Home | History | Annotate | Download | only in squashfs
      1 /*
      2  * Squashfs - a compressed read only filesystem for Linux
      3  *
      4  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
      5  * Phillip Lougher <phillip (at) lougher.demon.co.uk>
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License
      9  * as published by the Free Software Foundation; either version 2,
     10  * or (at your option) any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License
     18  * along with this program; if not, write to the Free Software
     19  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20  *
     21  * inode.c
     22  */
     23 
     24 /*
     25  * This file implements code to create and read inodes from disk.
     26  *
     27  * Inodes in Squashfs are identified by a 48-bit inode which encodes the
     28  * location of the compressed metadata block containing the inode, and the byte
     29  * offset into that block where the inode is placed (<block, offset>).
     30  *
     31  * To maximise compression there are different inodes for each file type
     32  * (regular file, directory, device, etc.), the inode contents and length
     33  * varying with the type.
     34  *
     35  * To further maximise compression, two types of regular file inode and
     36  * directory inode are defined: inodes optimised for frequently occurring
     37  * regular files and directories, and extended types where extra
     38  * information has to be stored.
     39  */
     40 
     41 #include <linux/fs.h>
     42 #include <linux/vfs.h>
     43 #include <linux/zlib.h>
     44 
     45 #include "squashfs_fs.h"
     46 #include "squashfs_fs_sb.h"
     47 #include "squashfs_fs_i.h"
     48 #include "squashfs.h"
     49 
     50 /*
     51  * Initialise VFS inode with the base inode information common to all
     52  * Squashfs inode types.  Sqsh_ino contains the unswapped base inode
     53  * off disk.
     54  */
     55 static int squashfs_new_inode(struct super_block *sb, struct inode *inode,
     56 				struct squashfs_base_inode *sqsh_ino)
     57 {
     58 	int err;
     59 
     60 	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->uid), &inode->i_uid);
     61 	if (err)
     62 		return err;
     63 
     64 	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &inode->i_gid);
     65 	if (err)
     66 		return err;
     67 
     68 	inode->i_ino = le32_to_cpu(sqsh_ino->inode_number);
     69 	inode->i_mtime.tv_sec = le32_to_cpu(sqsh_ino->mtime);
     70 	inode->i_atime.tv_sec = inode->i_mtime.tv_sec;
     71 	inode->i_ctime.tv_sec = inode->i_mtime.tv_sec;
     72 	inode->i_mode = le16_to_cpu(sqsh_ino->mode);
     73 	inode->i_size = 0;
     74 
     75 	return err;
     76 }
     77 
     78 
     79 struct inode *squashfs_iget(struct super_block *sb, long long ino,
     80 				unsigned int ino_number)
     81 {
     82 	struct inode *inode = iget_locked(sb, ino_number);
     83 	int err;
     84 
     85 	TRACE("Entered squashfs_iget\n");
     86 
     87 	if (!inode)
     88 		return ERR_PTR(-ENOMEM);
     89 	if (!(inode->i_state & I_NEW))
     90 		return inode;
     91 
     92 	err = squashfs_read_inode(inode, ino);
     93 	if (err) {
     94 		iget_failed(inode);
     95 		return ERR_PTR(err);
     96 	}
     97 
     98 	unlock_new_inode(inode);
     99 	return inode;
    100 }
    101 
    102 
    103 /*
    104  * Initialise VFS inode by reading inode from inode table (compressed
    105  * metadata).  The format and amount of data read depends on type.
    106  */
    107 int squashfs_read_inode(struct inode *inode, long long ino)
    108 {
    109 	struct super_block *sb = inode->i_sb;
    110 	struct squashfs_sb_info *msblk = sb->s_fs_info;
    111 	u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
    112 	int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
    113 	union squashfs_inode squashfs_ino;
    114 	struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
    115 
    116 	TRACE("Entered squashfs_read_inode\n");
    117 
    118 	/*
    119 	 * Read inode base common to all inode types.
    120 	 */
    121 	err = squashfs_read_metadata(sb, sqshb_ino, &block,
    122 				&offset, sizeof(*sqshb_ino));
    123 	if (err < 0)
    124 		goto failed_read;
    125 
    126 	err = squashfs_new_inode(sb, inode, sqshb_ino);
    127 	if (err)
    128 		goto failed_read;
    129 
    130 	block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
    131 	offset = SQUASHFS_INODE_OFFSET(ino);
    132 
    133 	type = le16_to_cpu(sqshb_ino->inode_type);
    134 	switch (type) {
    135 	case SQUASHFS_REG_TYPE: {
    136 		unsigned int frag_offset, frag_size, frag;
    137 		u64 frag_blk;
    138 		struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;
    139 
    140 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    141 							sizeof(*sqsh_ino));
    142 		if (err < 0)
    143 			goto failed_read;
    144 
    145 		frag = le32_to_cpu(sqsh_ino->fragment);
    146 		if (frag != SQUASHFS_INVALID_FRAG) {
    147 			frag_offset = le32_to_cpu(sqsh_ino->offset);
    148 			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
    149 			if (frag_size < 0) {
    150 				err = frag_size;
    151 				goto failed_read;
    152 			}
    153 		} else {
    154 			frag_blk = SQUASHFS_INVALID_BLK;
    155 			frag_size = 0;
    156 			frag_offset = 0;
    157 		}
    158 
    159 		inode->i_nlink = 1;
    160 		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
    161 		inode->i_fop = &generic_ro_fops;
    162 		inode->i_mode |= S_IFREG;
    163 		inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
    164 		squashfs_i(inode)->fragment_block = frag_blk;
    165 		squashfs_i(inode)->fragment_size = frag_size;
    166 		squashfs_i(inode)->fragment_offset = frag_offset;
    167 		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
    168 		squashfs_i(inode)->block_list_start = block;
    169 		squashfs_i(inode)->offset = offset;
    170 		inode->i_data.a_ops = &squashfs_aops;
    171 
    172 		TRACE("File inode %x:%x, start_block %llx, block_list_start "
    173 			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
    174 			offset, squashfs_i(inode)->start, block, offset);
    175 		break;
    176 	}
    177 	case SQUASHFS_LREG_TYPE: {
    178 		unsigned int frag_offset, frag_size, frag;
    179 		u64 frag_blk;
    180 		struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;
    181 
    182 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    183 							sizeof(*sqsh_ino));
    184 		if (err < 0)
    185 			goto failed_read;
    186 
    187 		frag = le32_to_cpu(sqsh_ino->fragment);
    188 		if (frag != SQUASHFS_INVALID_FRAG) {
    189 			frag_offset = le32_to_cpu(sqsh_ino->offset);
    190 			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
    191 			if (frag_size < 0) {
    192 				err = frag_size;
    193 				goto failed_read;
    194 			}
    195 		} else {
    196 			frag_blk = SQUASHFS_INVALID_BLK;
    197 			frag_size = 0;
    198 			frag_offset = 0;
    199 		}
    200 
    201 		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
    202 		inode->i_size = le64_to_cpu(sqsh_ino->file_size);
    203 		inode->i_fop = &generic_ro_fops;
    204 		inode->i_mode |= S_IFREG;
    205 		inode->i_blocks = ((inode->i_size -
    206 				le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
    207 
    208 		squashfs_i(inode)->fragment_block = frag_blk;
    209 		squashfs_i(inode)->fragment_size = frag_size;
    210 		squashfs_i(inode)->fragment_offset = frag_offset;
    211 		squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
    212 		squashfs_i(inode)->block_list_start = block;
    213 		squashfs_i(inode)->offset = offset;
    214 		inode->i_data.a_ops = &squashfs_aops;
    215 
    216 		TRACE("File inode %x:%x, start_block %llx, block_list_start "
    217 			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
    218 			offset, squashfs_i(inode)->start, block, offset);
    219 		break;
    220 	}
    221 	case SQUASHFS_DIR_TYPE: {
    222 		struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;
    223 
    224 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    225 				sizeof(*sqsh_ino));
    226 		if (err < 0)
    227 			goto failed_read;
    228 
    229 		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
    230 		inode->i_size = le16_to_cpu(sqsh_ino->file_size);
    231 		inode->i_op = &squashfs_dir_inode_ops;
    232 		inode->i_fop = &squashfs_dir_ops;
    233 		inode->i_mode |= S_IFDIR;
    234 		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
    235 		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
    236 		squashfs_i(inode)->dir_idx_cnt = 0;
    237 		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
    238 
    239 		TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
    240 				SQUASHFS_INODE_BLK(ino), offset,
    241 				squashfs_i(inode)->start,
    242 				le16_to_cpu(sqsh_ino->offset));
    243 		break;
    244 	}
    245 	case SQUASHFS_LDIR_TYPE: {
    246 		struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;
    247 
    248 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    249 				sizeof(*sqsh_ino));
    250 		if (err < 0)
    251 			goto failed_read;
    252 
    253 		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
    254 		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
    255 		inode->i_op = &squashfs_dir_inode_ops;
    256 		inode->i_fop = &squashfs_dir_ops;
    257 		inode->i_mode |= S_IFDIR;
    258 		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
    259 		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
    260 		squashfs_i(inode)->dir_idx_start = block;
    261 		squashfs_i(inode)->dir_idx_offset = offset;
    262 		squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);
    263 		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
    264 
    265 		TRACE("Long directory inode %x:%x, start_block %llx, offset "
    266 				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
    267 				squashfs_i(inode)->start,
    268 				le16_to_cpu(sqsh_ino->offset));
    269 		break;
    270 	}
    271 	case SQUASHFS_SYMLINK_TYPE:
    272 	case SQUASHFS_LSYMLINK_TYPE: {
    273 		struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;
    274 
    275 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    276 				sizeof(*sqsh_ino));
    277 		if (err < 0)
    278 			goto failed_read;
    279 
    280 		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
    281 		inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
    282 		inode->i_op = &page_symlink_inode_operations;
    283 		inode->i_data.a_ops = &squashfs_symlink_aops;
    284 		inode->i_mode |= S_IFLNK;
    285 		squashfs_i(inode)->start = block;
    286 		squashfs_i(inode)->offset = offset;
    287 
    288 		TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
    289 				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
    290 				block, offset);
    291 		break;
    292 	}
    293 	case SQUASHFS_BLKDEV_TYPE:
    294 	case SQUASHFS_CHRDEV_TYPE:
    295 	case SQUASHFS_LBLKDEV_TYPE:
    296 	case SQUASHFS_LCHRDEV_TYPE: {
    297 		struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
    298 		unsigned int rdev;
    299 
    300 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    301 				sizeof(*sqsh_ino));
    302 		if (err < 0)
    303 			goto failed_read;
    304 
    305 		if (type == SQUASHFS_CHRDEV_TYPE)
    306 			inode->i_mode |= S_IFCHR;
    307 		else
    308 			inode->i_mode |= S_IFBLK;
    309 		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
    310 		rdev = le32_to_cpu(sqsh_ino->rdev);
    311 		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
    312 
    313 		TRACE("Device inode %x:%x, rdev %x\n",
    314 				SQUASHFS_INODE_BLK(ino), offset, rdev);
    315 		break;
    316 	}
    317 	case SQUASHFS_FIFO_TYPE:
    318 	case SQUASHFS_SOCKET_TYPE:
    319 	case SQUASHFS_LFIFO_TYPE:
    320 	case SQUASHFS_LSOCKET_TYPE: {
    321 		struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
    322 
    323 		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
    324 				sizeof(*sqsh_ino));
    325 		if (err < 0)
    326 			goto failed_read;
    327 
    328 		if (type == SQUASHFS_FIFO_TYPE)
    329 			inode->i_mode |= S_IFIFO;
    330 		else
    331 			inode->i_mode |= S_IFSOCK;
    332 		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
    333 		init_special_inode(inode, inode->i_mode, 0);
    334 		break;
    335 	}
    336 	default:
    337 		ERROR("Unknown inode type %d in squashfs_iget!\n", type);
    338 		return -EINVAL;
    339 	}
    340 
    341 	return 0;
    342 
    343 failed_read:
    344 	ERROR("Unable to read inode 0x%llx\n", ino);
    345 	return err;
    346 }
    347