Subject: [PATCH 01/16] Squashfs: inode operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Phillip Lougher <phillip@xxxxxxxxxxxxxxxxxxx>
---
 fs/squashfs/inode.c |  318 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 318 insertions(+), 0 deletions(-)

diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
new file mode 100644
index 0000000..4782e1d
--- /dev/null
+++ b/fs/squashfs/inode.c
@@ -0,0 +1,318 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ * Phillip Lougher <phillip@xxxxxxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * inode.c
+ */
+
+/*
+ * This file implements code to create and read inodes from disk.
+ *
+ * Inodes in Squashfs are identified by a 48-bit inode which encodes the
+ * location of the compressed metadata block containing the inode, and the byte
+ * offset into that block where the inode is placed (<block, offset>).
+ *
+ * To maximise compression there are different inodes for each file type
+ * (regular file, directory, device, etc.), the inode contents and length
+ * varying with the type.
+ *
+ * To further maximise compression, two types of regular file inode and
+ * directory inode are defined: inodes optimised for frequently occurring
+ * regular files and directories, and extended types where extra
+ * information has to be stored.
+ */
+
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/zlib.h>
+#include <linux/squashfs_fs.h>
+#include <linux/squashfs_fs_sb.h>
+#include <linux/squashfs_fs_i.h>
+
+#include "squashfs.h"
+
+/*
+ * Initialise VFS inode with the base inode information common to all
+ * Squashfs inode types.  Inodeb contains the unswapped base inode
+ * off disk.
+ */
+static int squashfs_new_inode(struct super_block *s, struct inode *i,
+				struct squashfs_base_inode *inodeb)
+{
+	if (squashfs_get_id(s, le16_to_cpu(inodeb->uid), &i->i_uid) == 0)
+		goto out;
+	if (squashfs_get_id(s, le16_to_cpu(inodeb->guid), &i->i_gid) == 0)
+		goto out;
+
+	i->i_ino = le32_to_cpu(inodeb->inode_number);
+	i->i_mtime.tv_sec = le32_to_cpu(inodeb->mtime);
+	i->i_atime.tv_sec = i->i_mtime.tv_sec;
+	i->i_ctime.tv_sec = i->i_mtime.tv_sec;
+	i->i_mode = le16_to_cpu(inodeb->mode);
+	i->i_size = 0;
+
+	return 1;
+
+out:
+	return 0;
+}
+
+
+struct inode *squashfs_iget(struct super_block *s, long long inode,
+				unsigned int inode_number)
+{
+	struct inode *i = iget_locked(s, inode_number);
+
+	TRACE("Entered squashfs_iget\n");
+
+	if (i && (i->i_state & I_NEW)) {
+		squashfs_read_inode(i, inode);
+		unlock_new_inode(i);
+	}
+
+	return i;
+}
+
+
+/*
+ * Initialise VFS inode by reading inode from inode table (compressed
+ * metadata).  The format and amount of data read depends on type.
+ */
+int squashfs_read_inode(struct inode *i, long long inode)
+{
+	struct super_block *s = i->i_sb;
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	long long block = SQUASHFS_INODE_BLK(inode) + msblk->inode_table_start;
+	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+	long long next_block;
+	unsigned int next_offset;
+	int type;
+	union squashfs_inode id;
+	struct squashfs_base_inode *inodeb = &id.base;
+
+	TRACE("Entered squashfs_read_inode\n");
+
+	/*
+	 * Read inode base common to all inode types.
+	 */
+	if (!squashfs_read_metadata(s, inodeb, block, offset, sizeof(*inodeb),
+			&next_block, &next_offset))
+		goto failed_read;
+
+	if (squashfs_new_inode(s, i, inodeb) == 0)
+			goto failed_read;
+
+	type = le16_to_cpu(inodeb->inode_type);
+	switch (type) {
+	case SQUASHFS_FILE_TYPE: {
+		unsigned int frag_offset, frag_size, frag;
+		long long frag_blk;
+		struct squashfs_reg_inode *inodep = &id.reg;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		frag = le32_to_cpu(inodep->fragment);
+		if (frag != SQUASHFS_INVALID_FRAG) {
+			frag_offset = le32_to_cpu(inodep->offset);
+			frag_size = get_fragment_location(s, frag, &frag_blk);
+			if (frag_size == 0)
+				goto failed_read;
+		} else {
+			frag_blk = SQUASHFS_INVALID_BLK;
+			frag_size = 0;
+			frag_offset = 0;
+		}
+
+		i->i_nlink = 1;
+		i->i_size = le32_to_cpu(inodep->file_size);
+		i->i_fop = &generic_ro_fops;
+		i->i_mode |= S_IFREG;
+		i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+		SQUASHFS_I(i)->fragment_block = frag_blk;
+		SQUASHFS_I(i)->fragment_size = frag_size;
+		SQUASHFS_I(i)->fragment_offset = frag_offset;
+		SQUASHFS_I(i)->start_block = le32_to_cpu(inodep->start_block);
+		SQUASHFS_I(i)->block_list_start = next_block;
+		SQUASHFS_I(i)->offset = next_offset;
+		i->i_data.a_ops = &squashfs_aops;
+
+		TRACE("File inode %x:%x, start_block %llx, block_list_start "
+				"%llx, offset %x\n", SQUASHFS_INODE_BLK(inode),
+				offset, SQUASHFS_I(i)->start_block, next_block,
+				next_offset);
+		break;
+	}
+	case SQUASHFS_LREG_TYPE: {
+		unsigned int frag_offset, frag_size, frag;
+		long long frag_blk;
+		struct squashfs_lreg_inode *inodep = &id.lreg;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		frag = le32_to_cpu(inodep->fragment);
+		if (frag != SQUASHFS_INVALID_FRAG) {
+			frag_offset = le32_to_cpu(inodep->offset);
+			frag_size = get_fragment_location(s, frag, &frag_blk);
+			if (frag_size == 0)
+				goto failed_read;
+		} else {
+			frag_blk = SQUASHFS_INVALID_BLK;
+			frag_size = 0;
+			frag_offset = 0;
+		}
+
+		i->i_nlink = le32_to_cpu(inodep->nlink);
+		i->i_size = le64_to_cpu(inodep->file_size);
+		i->i_fop = &generic_ro_fops;
+		i->i_mode |= S_IFREG;
+		i->i_blocks = ((i->i_size - le64_to_cpu(inodep->sparse) - 1)
+				>> 9) + 1;
+
+		SQUASHFS_I(i)->fragment_block = frag_blk;
+		SQUASHFS_I(i)->fragment_size = frag_size;
+		SQUASHFS_I(i)->fragment_offset = frag_offset;
+		SQUASHFS_I(i)->start_block = le64_to_cpu(inodep->start_block);
+		SQUASHFS_I(i)->block_list_start = next_block;
+		SQUASHFS_I(i)->offset = next_offset;
+		i->i_data.a_ops = &squashfs_aops;
+
+		TRACE("File inode %x:%x, start_block %llx, block_list_start "
+				"%llx, offset %x\n", SQUASHFS_INODE_BLK(inode),
+				offset, SQUASHFS_I(i)->start_block, next_block,
+				next_offset);
+		break;
+	}
+	case SQUASHFS_DIR_TYPE: {
+		struct squashfs_dir_inode *inodep = &id.dir;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		i->i_nlink = le32_to_cpu(inodep->nlink);
+		i->i_size = le16_to_cpu(inodep->file_size);
+		i->i_op = &squashfs_dir_inode_ops;
+		i->i_fop = &squashfs_dir_ops;
+		i->i_mode |= S_IFDIR;
+		SQUASHFS_I(i)->start_block = le32_to_cpu(inodep->start_block);
+		SQUASHFS_I(i)->offset = le16_to_cpu(inodep->offset);
+		SQUASHFS_I(i)->dir_index_count = 0;
+		SQUASHFS_I(i)->parent_inode = le32_to_cpu(inodep->parent_inode);
+
+		TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
+				SQUASHFS_INODE_BLK(inode), offset,
+				SQUASHFS_I(i)->start_block,
+				le16_to_cpu(inodep->offset));
+		break;
+	}
+	case SQUASHFS_LDIR_TYPE: {
+		struct squashfs_ldir_inode *inodep = &id.ldir;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		i->i_nlink = le32_to_cpu(inodep->nlink);
+		i->i_size = le32_to_cpu(inodep->file_size);
+		i->i_op = &squashfs_dir_inode_ops;
+		i->i_fop = &squashfs_dir_ops;
+		i->i_mode |= S_IFDIR;
+		SQUASHFS_I(i)->start_block = le32_to_cpu(inodep->start_block);
+		SQUASHFS_I(i)->offset = le16_to_cpu(inodep->offset);
+		SQUASHFS_I(i)->dir_index_start = next_block;
+		SQUASHFS_I(i)->dir_index_offset = next_offset;
+		SQUASHFS_I(i)->dir_index_count = le16_to_cpu(inodep->i_count);
+		SQUASHFS_I(i)->parent_inode = le32_to_cpu(inodep->parent_inode);
+
+		TRACE("Long directory inode %x:%x, start_block %llx, offset "
+				"%x\n", SQUASHFS_INODE_BLK(inode), offset,
+				SQUASHFS_I(i)->start_block,
+				le16_to_cpu(inodep->offset));
+		break;
+	}
+	case SQUASHFS_SYMLINK_TYPE: {
+		struct squashfs_symlink_inode *inodep = &id.symlink;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		i->i_nlink = le32_to_cpu(inodep->nlink);
+		i->i_size = le32_to_cpu(inodep->symlink_size);
+		i->i_op = &page_symlink_inode_operations;
+		i->i_data.a_ops = &squashfs_symlink_aops;
+		i->i_mode |= S_IFLNK;
+		SQUASHFS_I(i)->start_block = next_block;
+		SQUASHFS_I(i)->offset = next_offset;
+
+		TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
+				"%x\n", SQUASHFS_INODE_BLK(inode), offset,
+				next_block, next_offset);
+		break;
+	}
+	case SQUASHFS_BLKDEV_TYPE:
+	case SQUASHFS_CHRDEV_TYPE: {
+		struct squashfs_dev_inode *inodep = &id.dev;
+		unsigned int rdev;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		i->i_nlink = le32_to_cpu(inodep->nlink);
+		i->i_mode |= (type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK;
+		rdev = le32_to_cpu(inodep->rdev);
+		init_special_inode(i, le16_to_cpu(i->i_mode),
+					new_decode_dev(rdev));
+
+		TRACE("Device inode %x:%x, rdev %x\n",
+				SQUASHFS_INODE_BLK(inode), offset, rdev);
+		break;
+	}
+	case SQUASHFS_FIFO_TYPE:
+	case SQUASHFS_SOCKET_TYPE: {
+		struct squashfs_ipc_inode *inodep = &id.ipc;
+
+		if (!squashfs_read_metadata(s, inodep, block, offset,
+				sizeof(*inodep), &next_block, &next_offset))
+			goto failed_read;
+
+		i->i_nlink = le32_to_cpu(inodep->nlink);
+		i->i_mode |= (type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK;
+		init_special_inode(i, le16_to_cpu(i->i_mode), 0);
+		break;
+	}
+	default:
+		ERROR("Unknown inode type %d in squashfs_iget!\n", type);
+		goto failed_read1;
+	}
+
+	return 1;
+
+failed_read:
+	ERROR("Unable to read inode [%llx:%x]\n", block, offset);
+
+failed_read1:
+	make_bad_inode(i);
+	return 0;
+}
-- 
1.5.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux