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