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