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