inode.c revision 1aef9e4f12365714fd95ac9a7a059ea4c7d6d846
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 *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		goto out;
63
64	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &inode->i_gid);
65	if (err)
66		goto out;
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
75out:
76	return err;
77}
78
79
80struct inode *squashfs_iget(struct super_block *sb, long long ino,
81				unsigned int ino_number)
82{
83	struct inode *inode = iget_locked(sb, ino_number);
84	int err;
85
86	TRACE("Entered squashfs_iget\n");
87
88	if (!inode)
89		return ERR_PTR(-ENOMEM);
90	if (!(inode->i_state & I_NEW))
91		return inode;
92
93	err = squashfs_read_inode(inode, ino);
94	if (err) {
95		iget_failed(inode);
96		return ERR_PTR(err);
97	}
98
99	unlock_new_inode(inode);
100	return inode;
101}
102
103
104/*
105 * Initialise VFS inode by reading inode from inode table (compressed
106 * metadata).  The format and amount of data read depends on type.
107 */
108int squashfs_read_inode(struct inode *inode, long long ino)
109{
110	struct super_block *sb = inode->i_sb;
111	struct squashfs_sb_info *msblk = sb->s_fs_info;
112	long long block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
113	unsigned int offset = SQUASHFS_INODE_OFFSET(ino);
114	int err, type;
115	union squashfs_inode squashfs_ino;
116	struct squashfs_base_inode *sqsh_ino = &squashfs_ino.base;
117
118	TRACE("Entered squashfs_read_inode\n");
119
120	/*
121	 * Read inode base common to all inode types.
122	 */
123	err = squashfs_read_metadata(sb, sqsh_ino, &block,
124						&offset, sizeof(*sqsh_ino));
125	if (err < 0)
126		goto failed_read;
127
128	err = squashfs_new_inode(sb, inode, sqsh_ino);
129	if (err)
130		goto failed_read;
131
132	block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
133	offset = SQUASHFS_INODE_OFFSET(ino);
134
135	type = le16_to_cpu(sqsh_ino->inode_type);
136	switch (type) {
137	case SQUASHFS_FILE_TYPE: {
138		unsigned int frag_offset, frag_size, frag;
139		long long frag_blk;
140		struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;
141
142		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
143							sizeof(*sqsh_ino));
144		if (err < 0)
145			goto failed_read;
146
147		frag = le32_to_cpu(sqsh_ino->fragment);
148		if (frag != SQUASHFS_INVALID_FRAG) {
149			frag_offset = le32_to_cpu(sqsh_ino->offset);
150			frag_size = get_fragment_location(sb, frag, &frag_blk);
151			if (frag_size < 0) {
152				err = frag_size;
153				goto failed_read;
154			}
155		} else {
156			frag_blk = SQUASHFS_INVALID_BLK;
157			frag_size = 0;
158			frag_offset = 0;
159		}
160
161		inode->i_nlink = 1;
162		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
163		inode->i_fop = &generic_ro_fops;
164		inode->i_mode |= S_IFREG;
165		inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
166		SQUASHFS_I(inode)->fragment_block = frag_blk;
167		SQUASHFS_I(inode)->fragment_size = frag_size;
168		SQUASHFS_I(inode)->fragment_offset = frag_offset;
169		SQUASHFS_I(inode)->start = le32_to_cpu(sqsh_ino->start_block);
170		SQUASHFS_I(inode)->block_list_start = block;
171		SQUASHFS_I(inode)->offset = offset;
172		inode->i_data.a_ops = &squashfs_aops;
173
174		TRACE("File inode %x:%x, start_block %llx, block_list_start "
175			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
176			offset, SQUASHFS_I(inode)->start, block, offset);
177		break;
178	}
179	case SQUASHFS_LREG_TYPE: {
180		unsigned int frag_offset, frag_size, frag;
181		long long frag_blk;
182		struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;
183
184		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
185							sizeof(*sqsh_ino));
186		if (err < 0)
187			goto failed_read;
188
189		frag = le32_to_cpu(sqsh_ino->fragment);
190		if (frag != SQUASHFS_INVALID_FRAG) {
191			frag_offset = le32_to_cpu(sqsh_ino->offset);
192			frag_size = get_fragment_location(sb, frag, &frag_blk);
193			if (frag_size < 0) {
194				err = frag_size;
195				goto failed_read;
196			}
197		} else {
198			frag_blk = SQUASHFS_INVALID_BLK;
199			frag_size = 0;
200			frag_offset = 0;
201		}
202
203		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
204		inode->i_size = le64_to_cpu(sqsh_ino->file_size);
205		inode->i_fop = &generic_ro_fops;
206		inode->i_mode |= S_IFREG;
207		inode->i_blocks = ((inode->i_size -
208				le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
209
210		SQUASHFS_I(inode)->fragment_block = frag_blk;
211		SQUASHFS_I(inode)->fragment_size = frag_size;
212		SQUASHFS_I(inode)->fragment_offset = frag_offset;
213		SQUASHFS_I(inode)->start = le64_to_cpu(sqsh_ino->start_block);
214		SQUASHFS_I(inode)->block_list_start = block;
215		SQUASHFS_I(inode)->offset = offset;
216		inode->i_data.a_ops = &squashfs_aops;
217
218		TRACE("File inode %x:%x, start_block %llx, block_list_start "
219			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
220			offset, SQUASHFS_I(inode)->start, block, offset);
221		break;
222	}
223	case SQUASHFS_DIR_TYPE: {
224		struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;
225
226		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
227				sizeof(*sqsh_ino));
228		if (err < 0)
229			goto failed_read;
230
231		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
232		inode->i_size = le16_to_cpu(sqsh_ino->file_size);
233		inode->i_op = &squashfs_dir_inode_ops;
234		inode->i_fop = &squashfs_dir_ops;
235		inode->i_mode |= S_IFDIR;
236		SQUASHFS_I(inode)->start = le32_to_cpu(sqsh_ino->start_block);
237		SQUASHFS_I(inode)->offset = le16_to_cpu(sqsh_ino->offset);
238		SQUASHFS_I(inode)->dir_idx_cnt = 0;
239		SQUASHFS_I(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
240
241		TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
242				SQUASHFS_INODE_BLK(inode), offset,
243				SQUASHFS_I(i)->start,
244				le16_to_cpu(sqsh_ino->offset));
245		break;
246	}
247	case SQUASHFS_LDIR_TYPE: {
248		struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;
249
250		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
251				sizeof(*sqsh_ino));
252		if (err < 0)
253			goto failed_read;
254
255		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
256		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
257		inode->i_op = &squashfs_dir_inode_ops;
258		inode->i_fop = &squashfs_dir_ops;
259		inode->i_mode |= S_IFDIR;
260		SQUASHFS_I(inode)->start = le32_to_cpu(sqsh_ino->start_block);
261		SQUASHFS_I(inode)->offset = le16_to_cpu(sqsh_ino->offset);
262		SQUASHFS_I(inode)->dir_idx_start = block;
263		SQUASHFS_I(inode)->dir_idx_offset = offset;
264		SQUASHFS_I(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);
265		SQUASHFS_I(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
266
267		TRACE("Long directory inode %x:%x, start_block %llx, offset "
268				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
269				SQUASHFS_I(inode)->start,
270				le16_to_cpu(sqsh_ino->offset));
271		break;
272	}
273	case SQUASHFS_SYMLINK_TYPE: {
274		struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;
275
276		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
277				sizeof(*sqsh_ino));
278		if (err < 0)
279			goto failed_read;
280
281		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
282		inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
283		inode->i_op = &page_symlink_inode_operations;
284		inode->i_data.a_ops = &squashfs_symlink_aops;
285		inode->i_mode |= S_IFLNK;
286		SQUASHFS_I(inode)->start = block;
287		SQUASHFS_I(inode)->offset = offset;
288
289		TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
290				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
291				block, offset);
292		break;
293	}
294	case SQUASHFS_BLKDEV_TYPE:
295	case SQUASHFS_CHRDEV_TYPE: {
296		struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
297		unsigned int rdev;
298
299		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
300				sizeof(*sqsh_ino));
301		if (err < 0)
302			goto failed_read;
303
304		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
305		inode->i_mode |= (type == SQUASHFS_CHRDEV_TYPE)
306						? S_IFCHR : S_IFBLK;
307		rdev = le32_to_cpu(sqsh_ino->rdev);
308		init_special_inode(inode, le16_to_cpu(inode->i_mode),
309					new_decode_dev(rdev));
310
311		TRACE("Device inode %x:%x, rdev %x\n",
312				SQUASHFS_INODE_BLK(ino), offset, rdev);
313		break;
314	}
315	case SQUASHFS_FIFO_TYPE:
316	case SQUASHFS_SOCKET_TYPE: {
317		struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
318
319		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
320				sizeof(*sqsh_ino));
321		if (err < 0)
322			goto failed_read;
323
324		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
325		inode->i_mode |= (type == SQUASHFS_FIFO_TYPE)
326						? S_IFIFO : S_IFSOCK;
327		init_special_inode(inode, le16_to_cpu(inode->i_mode), 0);
328		break;
329	}
330	default:
331		ERROR("Unknown inode type %d in squashfs_iget!\n", type);
332		err = -EINVAL;
333		goto failed_read1;
334	}
335
336	return 0;
337
338failed_read:
339	ERROR("Unable to read inode 0x%llx\n", ino);
340
341failed_read1:
342	return err;
343}
344