inode.c revision a3e28ecaf227d2c03ec6724dd718e3c5a12b74ef
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@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#include <linux/squashfs_fs.h> 45#include <linux/squashfs_fs_sb.h> 46#include <linux/squashfs_fs_i.h> 47 48#include "squashfs.h" 49 50/* 51 * Initialise VFS inode with the base inode information common to all 52 * Squashfs inode types. Inodeb contains the unswapped base inode 53 * off disk. 54 */ 55static int squashfs_new_inode(struct super_block *s, struct inode *i, 56 struct squashfs_base_inode *inodeb) 57{ 58 if (squashfs_get_id(s, le16_to_cpu(inodeb->uid), &i->i_uid) == 0) 59 goto out; 60 if (squashfs_get_id(s, le16_to_cpu(inodeb->guid), &i->i_gid) == 0) 61 goto out; 62 63 i->i_ino = le32_to_cpu(inodeb->inode_number); 64 i->i_mtime.tv_sec = le32_to_cpu(inodeb->mtime); 65 i->i_atime.tv_sec = i->i_mtime.tv_sec; 66 i->i_ctime.tv_sec = i->i_mtime.tv_sec; 67 i->i_mode = le16_to_cpu(inodeb->mode); 68 i->i_size = 0; 69 70 return 1; 71 72out: 73 return 0; 74} 75 76 77struct inode *squashfs_iget(struct super_block *s, long long inode, 78 unsigned int inode_number) 79{ 80 struct inode *i = iget_locked(s, inode_number); 81 82 TRACE("Entered squashfs_iget\n"); 83 84 if (i && (i->i_state & I_NEW)) { 85 squashfs_read_inode(i, inode); 86 unlock_new_inode(i); 87 } 88 89 return i; 90} 91 92 93/* 94 * Initialise VFS inode by reading inode from inode table (compressed 95 * metadata). The format and amount of data read depends on type. 96 */ 97int squashfs_read_inode(struct inode *i, long long inode) 98{ 99 struct super_block *s = i->i_sb; 100 struct squashfs_sb_info *msblk = s->s_fs_info; 101 long long block = SQUASHFS_INODE_BLK(inode) + msblk->inode_table_start; 102 unsigned int offset = SQUASHFS_INODE_OFFSET(inode); 103 long long next_block; 104 unsigned int next_offset; 105 int type; 106 union squashfs_inode id; 107 struct squashfs_base_inode *inodeb = &id.base; 108 109 TRACE("Entered squashfs_read_inode\n"); 110 111 /* 112 * Read inode base common to all inode types. 113 */ 114 if (!squashfs_read_metadata(s, inodeb, block, offset, sizeof(*inodeb), 115 &next_block, &next_offset)) 116 goto failed_read; 117 118 if (squashfs_new_inode(s, i, inodeb) == 0) 119 goto failed_read; 120 121 type = le16_to_cpu(inodeb->inode_type); 122 switch (type) { 123 case SQUASHFS_FILE_TYPE: { 124 unsigned int frag_offset, frag_size, frag; 125 long long frag_blk; 126 struct squashfs_reg_inode *inodep = &id.reg; 127 128 if (!squashfs_read_metadata(s, inodep, block, offset, 129 sizeof(*inodep), &next_block, &next_offset)) 130 goto failed_read; 131 132 frag = le32_to_cpu(inodep->fragment); 133 if (frag != SQUASHFS_INVALID_FRAG) { 134 frag_offset = le32_to_cpu(inodep->offset); 135 frag_size = get_fragment_location(s, frag, &frag_blk); 136 if (frag_size == 0) 137 goto failed_read; 138 } else { 139 frag_blk = SQUASHFS_INVALID_BLK; 140 frag_size = 0; 141 frag_offset = 0; 142 } 143 144 i->i_nlink = 1; 145 i->i_size = le32_to_cpu(inodep->file_size); 146 i->i_fop = &generic_ro_fops; 147 i->i_mode |= S_IFREG; 148 i->i_blocks = ((i->i_size - 1) >> 9) + 1; 149 SQUASHFS_I(i)->fragment_block = frag_blk; 150 SQUASHFS_I(i)->fragment_size = frag_size; 151 SQUASHFS_I(i)->fragment_offset = frag_offset; 152 SQUASHFS_I(i)->start_block = le32_to_cpu(inodep->start_block); 153 SQUASHFS_I(i)->block_list_start = next_block; 154 SQUASHFS_I(i)->offset = next_offset; 155 i->i_data.a_ops = &squashfs_aops; 156 157 TRACE("File inode %x:%x, start_block %llx, block_list_start " 158 "%llx, offset %x\n", SQUASHFS_INODE_BLK(inode), 159 offset, SQUASHFS_I(i)->start_block, next_block, 160 next_offset); 161 break; 162 } 163 case SQUASHFS_LREG_TYPE: { 164 unsigned int frag_offset, frag_size, frag; 165 long long frag_blk; 166 struct squashfs_lreg_inode *inodep = &id.lreg; 167 168 if (!squashfs_read_metadata(s, inodep, block, offset, 169 sizeof(*inodep), &next_block, &next_offset)) 170 goto failed_read; 171 172 frag = le32_to_cpu(inodep->fragment); 173 if (frag != SQUASHFS_INVALID_FRAG) { 174 frag_offset = le32_to_cpu(inodep->offset); 175 frag_size = get_fragment_location(s, frag, &frag_blk); 176 if (frag_size == 0) 177 goto failed_read; 178 } else { 179 frag_blk = SQUASHFS_INVALID_BLK; 180 frag_size = 0; 181 frag_offset = 0; 182 } 183 184 i->i_nlink = le32_to_cpu(inodep->nlink); 185 i->i_size = le64_to_cpu(inodep->file_size); 186 i->i_fop = &generic_ro_fops; 187 i->i_mode |= S_IFREG; 188 i->i_blocks = ((i->i_size - le64_to_cpu(inodep->sparse) - 1) 189 >> 9) + 1; 190 191 SQUASHFS_I(i)->fragment_block = frag_blk; 192 SQUASHFS_I(i)->fragment_size = frag_size; 193 SQUASHFS_I(i)->fragment_offset = frag_offset; 194 SQUASHFS_I(i)->start_block = le64_to_cpu(inodep->start_block); 195 SQUASHFS_I(i)->block_list_start = next_block; 196 SQUASHFS_I(i)->offset = next_offset; 197 i->i_data.a_ops = &squashfs_aops; 198 199 TRACE("File inode %x:%x, start_block %llx, block_list_start " 200 "%llx, offset %x\n", SQUASHFS_INODE_BLK(inode), 201 offset, SQUASHFS_I(i)->start_block, next_block, 202 next_offset); 203 break; 204 } 205 case SQUASHFS_DIR_TYPE: { 206 struct squashfs_dir_inode *inodep = &id.dir; 207 208 if (!squashfs_read_metadata(s, inodep, block, offset, 209 sizeof(*inodep), &next_block, &next_offset)) 210 goto failed_read; 211 212 i->i_nlink = le32_to_cpu(inodep->nlink); 213 i->i_size = le16_to_cpu(inodep->file_size); 214 i->i_op = &squashfs_dir_inode_ops; 215 i->i_fop = &squashfs_dir_ops; 216 i->i_mode |= S_IFDIR; 217 SQUASHFS_I(i)->start_block = le32_to_cpu(inodep->start_block); 218 SQUASHFS_I(i)->offset = le16_to_cpu(inodep->offset); 219 SQUASHFS_I(i)->dir_index_count = 0; 220 SQUASHFS_I(i)->parent_inode = le32_to_cpu(inodep->parent_inode); 221 222 TRACE("Directory inode %x:%x, start_block %llx, offset %x\n", 223 SQUASHFS_INODE_BLK(inode), offset, 224 SQUASHFS_I(i)->start_block, 225 le16_to_cpu(inodep->offset)); 226 break; 227 } 228 case SQUASHFS_LDIR_TYPE: { 229 struct squashfs_ldir_inode *inodep = &id.ldir; 230 231 if (!squashfs_read_metadata(s, inodep, block, offset, 232 sizeof(*inodep), &next_block, &next_offset)) 233 goto failed_read; 234 235 i->i_nlink = le32_to_cpu(inodep->nlink); 236 i->i_size = le32_to_cpu(inodep->file_size); 237 i->i_op = &squashfs_dir_inode_ops; 238 i->i_fop = &squashfs_dir_ops; 239 i->i_mode |= S_IFDIR; 240 SQUASHFS_I(i)->start_block = le32_to_cpu(inodep->start_block); 241 SQUASHFS_I(i)->offset = le16_to_cpu(inodep->offset); 242 SQUASHFS_I(i)->dir_index_start = next_block; 243 SQUASHFS_I(i)->dir_index_offset = next_offset; 244 SQUASHFS_I(i)->dir_index_count = le16_to_cpu(inodep->i_count); 245 SQUASHFS_I(i)->parent_inode = le32_to_cpu(inodep->parent_inode); 246 247 TRACE("Long directory inode %x:%x, start_block %llx, offset " 248 "%x\n", SQUASHFS_INODE_BLK(inode), offset, 249 SQUASHFS_I(i)->start_block, 250 le16_to_cpu(inodep->offset)); 251 break; 252 } 253 case SQUASHFS_SYMLINK_TYPE: { 254 struct squashfs_symlink_inode *inodep = &id.symlink; 255 256 if (!squashfs_read_metadata(s, inodep, block, offset, 257 sizeof(*inodep), &next_block, &next_offset)) 258 goto failed_read; 259 260 i->i_nlink = le32_to_cpu(inodep->nlink); 261 i->i_size = le32_to_cpu(inodep->symlink_size); 262 i->i_op = &page_symlink_inode_operations; 263 i->i_data.a_ops = &squashfs_symlink_aops; 264 i->i_mode |= S_IFLNK; 265 SQUASHFS_I(i)->start_block = next_block; 266 SQUASHFS_I(i)->offset = next_offset; 267 268 TRACE("Symbolic link inode %x:%x, start_block %llx, offset " 269 "%x\n", SQUASHFS_INODE_BLK(inode), offset, 270 next_block, next_offset); 271 break; 272 } 273 case SQUASHFS_BLKDEV_TYPE: 274 case SQUASHFS_CHRDEV_TYPE: { 275 struct squashfs_dev_inode *inodep = &id.dev; 276 unsigned int rdev; 277 278 if (!squashfs_read_metadata(s, inodep, block, offset, 279 sizeof(*inodep), &next_block, &next_offset)) 280 goto failed_read; 281 282 i->i_nlink = le32_to_cpu(inodep->nlink); 283 i->i_mode |= (type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; 284 rdev = le32_to_cpu(inodep->rdev); 285 init_special_inode(i, le16_to_cpu(i->i_mode), 286 new_decode_dev(rdev)); 287 288 TRACE("Device inode %x:%x, rdev %x\n", 289 SQUASHFS_INODE_BLK(inode), offset, rdev); 290 break; 291 } 292 case SQUASHFS_FIFO_TYPE: 293 case SQUASHFS_SOCKET_TYPE: { 294 struct squashfs_ipc_inode *inodep = &id.ipc; 295 296 if (!squashfs_read_metadata(s, inodep, block, offset, 297 sizeof(*inodep), &next_block, &next_offset)) 298 goto failed_read; 299 300 i->i_nlink = le32_to_cpu(inodep->nlink); 301 i->i_mode |= (type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; 302 init_special_inode(i, le16_to_cpu(i->i_mode), 0); 303 break; 304 } 305 default: 306 ERROR("Unknown inode type %d in squashfs_iget!\n", type); 307 goto failed_read1; 308 } 309 310 return 1; 311 312failed_read: 313 ERROR("Unable to read inode [%llx:%x]\n", block, offset); 314 315failed_read1: 316 make_bad_inode(i); 317 return 0; 318} 319