diff --new-file -urp linux-2.4.32/fs/Config.in linux-2.4.32-squashfs3.0/fs/Config.in
--- linux-2.4.32/fs/Config.in	2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.32-squashfs3.0/fs/Config.in	2006-03-07 21:12:36.000000000 +0000
@@ -51,6 +51,14 @@ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFI
    int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
 fi
 tristate 'Compressed ROM file system support' CONFIG_CRAMFS
+tristate 'Squashed file system support' CONFIG_SQUASHFS
+if [ "$CONFIG_SQUASHFS" = "y" -o "$CONFIG_SQUASHFS" = "m" ] ; then
+bool 'Additional options for memory constrained systems ' CONFIG_SQUASHFS_EMBEDDED
+fi
+if [ "$CONFIG_SQUASHFS_EMBEDDED" = "y" ] ; then
+int 'Number of fragments cached' CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE 3
+bool 'Use Vmalloc rather than Kmalloc'  CONFIG_SQUASHFS_VMALLOC
+fi
 bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
 define_bool CONFIG_RAMFS y
 
diff --new-file -urp linux-2.4.32/fs/Makefile linux-2.4.32-squashfs3.0/fs/Makefile
--- linux-2.4.32/fs/Makefile	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.32-squashfs3.0/fs/Makefile	2006-03-07 21:12:36.000000000 +0000
@@ -65,6 +65,7 @@ subdir-$(CONFIG_REISERFS_FS)	+= reiserfs
 subdir-$(CONFIG_DEVPTS_FS)	+= devpts
 subdir-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs
 subdir-$(CONFIG_BEFS_FS)	+= befs
+subdir-$(CONFIG_SQUASHFS)	+= squashfs
 subdir-$(CONFIG_JFS_FS)		+= jfs
 subdir-$(CONFIG_XFS_FS)		+= xfs
 
diff --new-file -urp linux-2.4.32/fs/squashfs/inode.c linux-2.4.32-squashfs3.0/fs/squashfs/inode.c
--- linux-2.4.32/fs/squashfs/inode.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/fs/squashfs/inode.c	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,2028 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * inode.c
+ */
+
+#include <linux/types.h>
+#include <linux/squashfs_fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/dcache.h>
+#include <linux/wait.h>
+#include <linux/zlib.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "squashfs.h"
+
+static struct super_block *squashfs_read_super(struct super_block *, void *, int);
+static void squashfs_put_super(struct super_block *);
+static int squashfs_statfs(struct super_block *, struct statfs *);
+static int squashfs_symlink_readpage(struct file *file, struct page *page);
+static int squashfs_readpage(struct file *file, struct page *page);
+static int squashfs_readpage4K(struct file *file, struct page *page);
+static int squashfs_readdir(struct file *, void *, filldir_t);
+static struct dentry *squashfs_lookup(struct inode *, struct dentry *);
+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
+static long long read_blocklist(struct inode *inode, int index,
+				int readahead_blks, char *block_list,
+				unsigned short **block_p, unsigned int *bsize);
+
+static z_stream stream;
+
+static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);
+
+static unsigned char squashfs_filetype_table[] = {
+	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
+};
+
+static struct super_operations squashfs_ops = {
+	.statfs = squashfs_statfs,
+	.put_super = squashfs_put_super,
+};
+
+SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
+	.readpage = squashfs_symlink_readpage
+};
+
+SQSH_EXTERN struct address_space_operations squashfs_aops = {
+	.readpage = squashfs_readpage
+};
+
+SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
+	.readpage = squashfs_readpage4K
+};
+
+static struct file_operations squashfs_dir_ops = {
+	.read = generic_read_dir,
+	.readdir = squashfs_readdir
+};
+
+static struct inode_operations squashfs_dir_inode_ops = {
+	.lookup = squashfs_lookup
+};
+
+static struct buffer_head *get_block_length(struct super_block *s,
+				int *cur_index, int *offset, int *c_byte)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	unsigned short temp;
+	struct buffer_head *bh;
+
+	if (!(bh = sb_bread(s, *cur_index)))
+		goto out;
+
+	if (msblk->devblksize - *offset == 1) {
+		if (msblk->swap)
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				(bh->b_data + *offset));
+		else
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				(bh->b_data + *offset));
+		brelse(bh);
+		if (!(bh = sb_bread(s, ++(*cur_index))))
+			goto out;
+		if (msblk->swap)
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				bh->b_data); 
+		else
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				bh->b_data); 
+		*c_byte = temp;
+		*offset = 1;
+	} else {
+		if (msblk->swap) {
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				(bh->b_data + *offset));
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				(bh->b_data + *offset + 1)); 
+		} else {
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				(bh->b_data + *offset));
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				(bh->b_data + *offset + 1)); 
+		}
+		*c_byte = temp;
+		*offset += 2;
+	}
+
+	if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
+		if (*offset == msblk->devblksize) {
+			brelse(bh);
+			if (!(bh = sb_bread(s, ++(*cur_index))))
+				goto out;
+			*offset = 0;
+		}
+		if (*((unsigned char *) (bh->b_data + *offset)) !=
+						SQUASHFS_MARKER_BYTE) {
+			ERROR("Metadata block marker corrupt @ %x\n",
+						*cur_index);
+			brelse(bh);
+			goto out;
+		}
+		(*offset)++;
+	}
+	return bh;
+
+out:
+	return NULL;
+}
+
+
+SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
+			long long index, unsigned int length,
+			long long *next_index)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
+			msblk->devblksize_log2) + 2];
+	unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
+	unsigned int cur_index = index >> msblk->devblksize_log2;
+	int bytes, avail_bytes, b = 0, k;
+	char *c_buffer;
+	unsigned int compressed;
+	unsigned int c_byte = length;
+
+	if (c_byte) {
+		bytes = msblk->devblksize - offset;
+		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
+		c_buffer = compressed ? msblk->read_data : buffer;
+		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
+
+		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
+					? "" : "un", (unsigned int) c_byte);
+
+		if (!(bh[0] = sb_getblk(s, cur_index)))
+			goto block_release;
+
+		for (b = 1; bytes < c_byte; b++) {
+			if (!(bh[b] = sb_getblk(s, ++cur_index)))
+				goto block_release;
+			bytes += msblk->devblksize;
+		}
+		ll_rw_block(READ, b, bh);
+	} else {
+		if (!(bh[0] = get_block_length(s, &cur_index, &offset,
+								&c_byte)))
+			goto read_failure;
+
+		bytes = msblk->devblksize - offset;
+		compressed = SQUASHFS_COMPRESSED(c_byte);
+		c_buffer = compressed ? msblk->read_data : buffer;
+		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+
+		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
+					? "" : "un", (unsigned int) c_byte);
+
+		for (b = 1; bytes < c_byte; b++) {
+			if (!(bh[b] = sb_getblk(s, ++cur_index)))
+				goto block_release;
+			bytes += msblk->devblksize;
+		}
+		ll_rw_block(READ, b - 1, bh + 1);
+	}
+
+	if (compressed)
+		down(&msblk->read_data_mutex);
+
+	for (bytes = 0, k = 0; k < b; k++) {
+		avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
+					msblk->devblksize - offset :
+					c_byte - bytes;
+		wait_on_buffer(bh[k]);
+		if (!buffer_uptodate(bh[k]))
+			goto block_release;
+		memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
+		bytes += avail_bytes;
+		offset = 0;
+		brelse(bh[k]);
+	}
+
+	/*
+	 * uncompress block
+	 */
+	if (compressed) {
+		int zlib_err;
+
+		stream.next_in = c_buffer;
+		stream.avail_in = c_byte;
+		stream.next_out = buffer;
+		stream.avail_out = msblk->read_size;
+
+		if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
+				((zlib_err = zlib_inflate(&stream, Z_FINISH))
+				 != Z_STREAM_END) || ((zlib_err =
+				zlib_inflateEnd(&stream)) != Z_OK)) {
+			ERROR("zlib_fs returned unexpected result 0x%x\n",
+				zlib_err);
+			bytes = 0;
+		} else
+			bytes = stream.total_out;
+		
+		up(&msblk->read_data_mutex);
+	}
+
+	if (next_index)
+		*next_index = index + c_byte + (length ? 0 :
+				(SQUASHFS_CHECK_DATA(msblk->sblk.flags)
+				 ? 3 : 2));
+	return bytes;
+
+block_release:
+	while (--b >= 0)
+		brelse(bh[b]);
+
+read_failure:
+	ERROR("sb_bread failed reading block 0x%x\n", cur_index);
+	return 0;
+}
+
+
+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
+				long long block, unsigned int offset,
+				int length, long long *next_block,
+				unsigned int *next_offset)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	int n, i, bytes, return_length = length;
+	long long next_index;
+
+	TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
+
+	while ( 1 ) {
+		for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 
+			if (msblk->block_cache[i].block == block)
+				break; 
+		
+		down(&msblk->block_cache_mutex);
+
+		if (i == SQUASHFS_CACHED_BLKS) {
+			/* read inode header block */
+			for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
+					n ; n --, i = (i + 1) %
+					SQUASHFS_CACHED_BLKS)
+				if (msblk->block_cache[i].block !=
+							SQUASHFS_USED_BLK)
+					break;
+
+			if (n == 0) {
+				wait_queue_t wait;
+
+				init_waitqueue_entry(&wait, current);
+				add_wait_queue(&msblk->waitq, &wait);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+ 				up(&msblk->block_cache_mutex);
+				schedule();
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&msblk->waitq, &wait);
+				continue;
+			}
+			msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
+
+			if (msblk->block_cache[i].block ==
+							SQUASHFS_INVALID_BLK) {
+				if (!(msblk->block_cache[i].data =
+						kmalloc(SQUASHFS_METADATA_SIZE,
+						GFP_KERNEL))) {
+					ERROR("Failed to allocate cache"
+							"block\n");
+					up(&msblk->block_cache_mutex);
+					goto out;
+				}
+			}
+	
+			msblk->block_cache[i].block = SQUASHFS_USED_BLK;
+			up(&msblk->block_cache_mutex);
+
+			if (!(msblk->block_cache[i].length =
+						squashfs_read_data(s,
+						msblk->block_cache[i].data,
+						block, 0, &next_index))) {
+				ERROR("Unable to read cache block [%llx:%x]\n",
+						block, offset);
+				goto out;
+			}
+
+			down(&msblk->block_cache_mutex);
+			wake_up(&msblk->waitq);
+			msblk->block_cache[i].block = block;
+			msblk->block_cache[i].next_index = next_index;
+			TRACE("Read cache block [%llx:%x]\n", block, offset);
+		}
+
+		if (msblk->block_cache[i].block != block) {
+			up(&msblk->block_cache_mutex);
+			continue;
+		}
+
+		if ((bytes = msblk->block_cache[i].length - offset) >= length) {
+			if (buffer)
+				memcpy(buffer, msblk->block_cache[i].data +
+						offset, length);
+			if (msblk->block_cache[i].length - offset == length) {
+				*next_block = msblk->block_cache[i].next_index;
+				*next_offset = 0;
+			} else {
+				*next_block = block;
+				*next_offset = offset + length;
+			}
+			up(&msblk->block_cache_mutex);
+			goto finish;
+		} else {
+			if (buffer) {
+				memcpy(buffer, msblk->block_cache[i].data +
+						offset, bytes);
+				buffer += bytes;
+			}
+			block = msblk->block_cache[i].next_index;
+			up(&msblk->block_cache_mutex);
+			length -= bytes;
+			offset = 0;
+		}
+	}
+
+finish:
+	return return_length;
+out:
+	return 0;
+}
+
+
+static int get_fragment_location(struct super_block *s, unsigned int fragment,
+				long long *fragment_start_block,
+				unsigned int *fragment_size)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	long long start_block =
+		msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
+	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
+	struct squashfs_fragment_entry fragment_entry;
+
+	if (msblk->swap) {
+		struct squashfs_fragment_entry sfragment_entry;
+
+		if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
+					start_block, offset,
+					sizeof(sfragment_entry), &start_block,
+					&offset))
+			goto out;
+		SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
+	} else
+		if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
+					start_block, offset,
+					sizeof(fragment_entry), &start_block,
+					&offset))
+			goto out;
+
+	*fragment_start_block = fragment_entry.start_block;
+	*fragment_size = fragment_entry.size;
+
+	return 1;
+
+out:
+	return 0;
+}
+
+
+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
+					squashfs_fragment_cache *fragment)
+{
+	down(&msblk->fragment_mutex);
+	fragment->locked --;
+	wake_up(&msblk->fragment_wait_queue);
+	up(&msblk->fragment_mutex);
+}
+
+
+SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
+					*s, long long start_block,
+					int length)
+{
+	int i, n;
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+
+	while ( 1 ) {
+		down(&msblk->fragment_mutex);
+
+		for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
+				msblk->fragment[i].block != start_block; i++);
+
+		if (i == SQUASHFS_CACHED_FRAGMENTS) {
+			for (i = msblk->next_fragment, n =
+				SQUASHFS_CACHED_FRAGMENTS; n &&
+				msblk->fragment[i].locked; n--, i = (i + 1) %
+				SQUASHFS_CACHED_FRAGMENTS);
+
+			if (n == 0) {
+				wait_queue_t wait;
+
+				init_waitqueue_entry(&wait, current);
+				add_wait_queue(&msblk->fragment_wait_queue,
+									&wait);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				up(&msblk->fragment_mutex);
+				schedule();
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&msblk->fragment_wait_queue,
+									&wait);
+				continue;
+			}
+			msblk->next_fragment = (msblk->next_fragment + 1) %
+				SQUASHFS_CACHED_FRAGMENTS;
+			
+			if (msblk->fragment[i].data == NULL)
+				if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
+						(SQUASHFS_FILE_MAX_SIZE))) {
+					ERROR("Failed to allocate fragment "
+							"cache block\n");
+					up(&msblk->fragment_mutex);
+					goto out;
+				}
+
+			msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
+			msblk->fragment[i].locked = 1;
+			up(&msblk->fragment_mutex);
+
+			if (!(msblk->fragment[i].length = squashfs_read_data(s,
+						msblk->fragment[i].data,
+						start_block, length, NULL))) {
+				ERROR("Unable to read fragment cache block "
+							"[%llx]\n", start_block);
+				msblk->fragment[i].locked = 0;
+				goto out;
+			}
+
+			msblk->fragment[i].block = start_block;
+			TRACE("New fragment %d, start block %lld, locked %d\n",
+						i, msblk->fragment[i].block,
+						msblk->fragment[i].locked);
+			break;
+		}
+
+		msblk->fragment[i].locked++;
+		up(&msblk->fragment_mutex);
+		TRACE("Got fragment %d, start block %lld, locked %d\n", i,
+						msblk->fragment[i].block,
+						msblk->fragment[i].locked);
+		break;
+	}
+
+	return &msblk->fragment[i];
+
+out:
+	return NULL;
+}
+
+
+static struct inode *squashfs_new_inode(struct super_block *s,
+		struct squashfs_base_inode_header *inodeb)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct inode *i = new_inode(s);
+
+	if (i) {
+		i->i_ino = inodeb->inode_number;
+		i->i_mtime = inodeb->mtime;
+		i->i_atime = inodeb->mtime;
+		i->i_ctime = inodeb->mtime;
+		i->i_uid = msblk->uid[inodeb->uid];
+		i->i_mode = inodeb->mode;
+		i->i_size = 0;
+		if (inodeb->guid == SQUASHFS_GUIDS)
+			i->i_gid = i->i_uid;
+		else
+			i->i_gid = msblk->guid[inodeb->guid];
+	}
+
+	return i;
+}
+
+
+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
+{
+	struct inode *i;
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long block = SQUASHFS_INODE_BLK(inode) +
+		sblk->inode_table_start;
+	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+	long long next_block;
+	unsigned int next_offset;
+	union squashfs_inode_header id, sid;
+	struct squashfs_base_inode_header *inodeb = &id.base,
+					  *sinodeb = &sid.base;
+
+	TRACE("Entered squashfs_iget\n");
+
+	if (msblk->swap) {
+		if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
+					offset, sizeof(*sinodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+		SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
+					sizeof(*sinodeb));
+	} else
+		if (!squashfs_get_cached_block(s, (char *) inodeb, block,
+					offset, sizeof(*inodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+
+	switch(inodeb->inode_type) {
+		case SQUASHFS_FILE_TYPE: {
+			unsigned int frag_size;
+			long long frag_blk;
+			struct squashfs_reg_inode_header *inodep = &id.reg;
+			struct squashfs_reg_inode_header *sinodep = &sid.reg;
+				
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			frag_blk = SQUASHFS_INVALID_BLK;
+			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+					!get_fragment_location(s,
+					inodep->fragment, &frag_blk, &frag_size))
+				goto failed_read;
+				
+			if((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = 1;
+			i->i_size = inodep->file_size;
+			i->i_fop = &generic_ro_fops;
+			i->i_mode |= S_IFREG;
+			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+			i->i_blksize = PAGE_CACHE_SIZE;
+			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+			if (sblk->block_size > 4096)
+				i->i_data.a_ops = &squashfs_aops;
+			else
+				i->i_data.a_ops = &squashfs_aops_4K;
+
+			TRACE("File inode %x:%x, start_block %llx, "
+					"block_list_start %llx, offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, next_block,
+					next_offset);
+			break;
+		}
+		case SQUASHFS_LREG_TYPE: {
+			unsigned int frag_size;
+			long long frag_blk;
+			struct squashfs_lreg_inode_header *inodep = &id.lreg;
+			struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
+				
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			frag_blk = SQUASHFS_INVALID_BLK;
+			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+					!get_fragment_location(s,
+					inodep->fragment, &frag_blk, &frag_size))
+				goto failed_read;
+				
+			if((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = inodep->file_size;
+			i->i_fop = &generic_ro_fops;
+			i->i_mode |= S_IFREG;
+			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+			i->i_blksize = PAGE_CACHE_SIZE;
+			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+			if (sblk->block_size > 4096)
+				i->i_data.a_ops = &squashfs_aops;
+			else
+				i->i_data.a_ops = &squashfs_aops_4K;
+
+			TRACE("File inode %x:%x, start_block %llx, "
+					"block_list_start %llx, offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, next_block,
+					next_offset);
+			break;
+		}
+		case SQUASHFS_DIR_TYPE: {
+			struct squashfs_dir_inode_header *inodep = &id.dir;
+			struct squashfs_dir_inode_header *sinodep = &sid.dir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = 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 = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count = 0;
+			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
+
+			TRACE("Directory inode %x:%x, start_block %x, offset "
+					"%x\n", SQUASHFS_INODE_BLK(inode),
+					offset, inodep->start_block,
+					inodep->offset);
+			break;
+		}
+		case SQUASHFS_LDIR_TYPE: {
+			struct squashfs_ldir_inode_header *inodep = &id.ldir;
+			struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
+						sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = 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 = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
+			SQUASHFS_I(i)->u.s2.directory_index_offset =
+								next_offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count =
+								inodep->i_count;
+			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
+
+			TRACE("Long directory inode %x:%x, start_block %x, "
+					"offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, inodep->offset);
+			break;
+		}
+		case SQUASHFS_SYMLINK_TYPE: {
+			struct squashfs_symlink_inode_header *inodep =
+								&id.symlink;
+			struct squashfs_symlink_inode_header *sinodep =
+								&sid.symlink;
+	
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
+								sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = 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_header *inodep = &id.dev;
+			struct squashfs_dev_inode_header *sinodep = &sid.dev;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
+			} else	
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if ((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = inodep->nlink;
+			i->i_mode |= (inodeb->inode_type ==
+					SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
+					S_IFBLK;
+			init_special_inode(i, i->i_mode, inodep->rdev);
+
+			TRACE("Device inode %x:%x, rdev %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->rdev);
+			break;
+		 }
+		 case SQUASHFS_FIFO_TYPE:
+		 case SQUASHFS_SOCKET_TYPE: {
+			struct squashfs_ipc_inode_header *inodep = &id.ipc;
+			struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
+			} else	
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if ((i = squashfs_new_inode(s, inodeb)) == NULL)
+				goto failed_read1;
+
+			i->i_nlink = inodep->nlink;
+			i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
+							? S_IFIFO : S_IFSOCK;
+			init_special_inode(i, i->i_mode, 0);
+			break;
+		 }
+		 default:
+			ERROR("Unknown inode type %d in squashfs_iget!\n",
+					inodeb->inode_type);
+			goto failed_read1;
+	}
+	
+	insert_inode_hash(i);
+	return i;
+
+failed_read:
+	ERROR("Unable to read inode [%llx:%x]\n", block, offset);
+
+failed_read1:
+	return NULL;
+}
+
+
+int read_fragment_index_table(struct super_block *s)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
+					(sblk->fragments), GFP_KERNEL))) {
+		ERROR("Failed to allocate uid/gid table\n");
+		return 0;
+	}
+   
+	if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
+					!squashfs_read_data(s, (char *)
+					msblk->fragment_index,
+					sblk->fragment_table_start,
+					SQUASHFS_FRAGMENT_INDEX_BYTES
+					(sblk->fragments) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+		ERROR("unable to read fragment index table\n");
+		return 0;
+	}
+
+	if (msblk->swap) {
+		int i;
+		long long fragment;
+
+		for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
+									i++) {
+			SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
+						&msblk->fragment_index[i], 1);
+			msblk->fragment_index[i] = fragment;
+		}
+	}
+
+	return 1;
+}
+
+
+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
+{
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	msblk->iget = squashfs_iget;
+	msblk->read_blocklist = read_blocklist;
+	msblk->read_fragment_index_table = read_fragment_index_table;
+
+	if (sblk->s_major == 1) {
+		if (!squashfs_1_0_supported(msblk)) {
+			SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
+				"are unsupported\n");
+			SERROR("Please recompile with "
+				"Squashfs 1.0 support enabled\n");
+			return 0;
+		}
+	} else if (sblk->s_major == 2) {
+		if (!squashfs_2_0_supported(msblk)) {
+			SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
+				"are unsupported\n");
+			SERROR("Please recompile with "
+				"Squashfs 2.0 support enabled\n");
+			return 0;
+		}
+	} else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
+			SQUASHFS_MINOR) {
+		SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
+				"filesystem\n", sblk->s_major, sblk->s_minor);
+		SERROR("Please update your kernel\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static struct super_block *squashfs_read_super(struct super_block *s,
+		void *data, int silent)
+{
+	kdev_t dev = s->s_dev;
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i;
+	struct inode *root;
+	
+	msblk->devblksize = get_hardsect_size(dev);
+	if(msblk->devblksize < BLOCK_SIZE)
+		msblk->devblksize = BLOCK_SIZE;
+	msblk->devblksize_log2 = ffz(~msblk->devblksize);
+        set_blocksize(dev, msblk->devblksize);
+	s->s_blocksize = msblk->devblksize;
+	s->s_blocksize_bits = msblk->devblksize_log2;
+	
+	init_MUTEX(&msblk->read_data_mutex);
+	init_MUTEX(&msblk->read_page_mutex);
+	init_MUTEX(&msblk->block_cache_mutex);
+	init_MUTEX(&msblk->fragment_mutex);
+	
+	init_waitqueue_head(&msblk->waitq);
+	init_waitqueue_head(&msblk->fragment_wait_queue);
+
+	if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
+					sizeof(struct squashfs_super_block) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+		SERROR("unable to read superblock\n");
+		goto failed_mount;
+	}
+
+	/* Check it is a SQUASHFS superblock */
+	msblk->swap = 0;
+	if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
+		if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
+			struct squashfs_super_block ssblk;
+
+			WARNING("Mounting a different endian SQUASHFS "
+				"filesystem on %s\n", bdevname(dev));
+
+			SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
+			memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
+			msblk->swap = 1;
+		} else  {
+			SERROR("Can't find a SQUASHFS superblock on %s\n",
+							bdevname(dev));
+			goto failed_mount;
+		}
+	}
+
+	/* Check the MAJOR & MINOR versions */
+	if(!supported_squashfs_filesystem(msblk, silent))
+		goto failed_mount;
+
+	TRACE("Found valid superblock on %s\n", bdevname(dev));
+	TRACE("Inodes are %scompressed\n",
+					SQUASHFS_UNCOMPRESSED_INODES
+					(sblk->flags) ? "un" : "");
+	TRACE("Data is %scompressed\n",
+					SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
+					? "un" : "");
+	TRACE("Check data is %s present in the filesystem\n",
+					SQUASHFS_CHECK_DATA(sblk->flags) ?
+					"" : "not");
+	TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
+	TRACE("Block size %d\n", sblk->block_size);
+	TRACE("Number of inodes %d\n", sblk->inodes);
+	if (sblk->s_major > 1)
+		TRACE("Number of fragments %d\n", sblk->fragments);
+	TRACE("Number of uids %d\n", sblk->no_uids);
+	TRACE("Number of gids %d\n", sblk->no_guids);
+	TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
+	TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
+	if (sblk->s_major > 1)
+		TRACE("sblk->fragment_table_start %llx\n",
+					sblk->fragment_table_start);
+	TRACE("sblk->uid_start %llx\n", sblk->uid_start);
+
+	s->s_flags |= MS_RDONLY;
+	s->s_op = &squashfs_ops;
+
+	/* Init inode_table block pointer array */
+	if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
+					SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
+		ERROR("Failed to allocate block cache\n");
+		goto failed_mount;
+	}
+
+	for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+		msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
+
+	msblk->next_cache = 0;
+
+	/* Allocate read_data block */
+	msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
+					SQUASHFS_METADATA_SIZE :
+					sblk->block_size;
+
+	if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
+		ERROR("Failed to allocate read_data block\n");
+		goto failed_mount;
+	}
+
+	/* Allocate read_page block */
+	if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
+		ERROR("Failed to allocate read_page block\n");
+		goto failed_mount;
+	}
+
+	/* Allocate uid and gid tables */
+	if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
+					sizeof(unsigned int), GFP_KERNEL))) {
+		ERROR("Failed to allocate uid/gid table\n");
+		goto failed_mount;
+	}
+	msblk->guid = msblk->uid + sblk->no_uids;
+   
+	if (msblk->swap) {
+		unsigned int suid[sblk->no_uids + sblk->no_guids];
+
+		if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
+					((sblk->no_uids + sblk->no_guids) *
+					 sizeof(unsigned int)) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+			ERROR("unable to read uid/gid table\n");
+			goto failed_mount;
+		}
+
+		SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
+			sblk->no_guids), (sizeof(unsigned int) * 8));
+	} else
+		if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
+					((sblk->no_uids + sblk->no_guids) *
+					 sizeof(unsigned int)) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+			ERROR("unable to read uid/gid table\n");
+			goto failed_mount;
+		}
+
+
+	if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
+		goto allocate_root;
+
+	if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
+				SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
+		ERROR("Failed to allocate fragment block cache\n");
+		goto failed_mount;
+	}
+
+	for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
+		msblk->fragment[i].locked = 0;
+		msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
+		msblk->fragment[i].data = NULL;
+	}
+
+	msblk->next_fragment = 0;
+
+	/* Allocate fragment index table */
+	if(msblk->read_fragment_index_table(s) == 0)
+		goto failed_mount;
+
+allocate_root:
+	if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
+		goto failed_mount;
+
+	if ((s->s_root = d_alloc_root(root)) == NULL) {
+		ERROR("Root inode create failed\n");
+		iput(root);
+		goto failed_mount;
+	}
+
+	TRACE("Leaving squashfs_read_super\n");
+	return s;
+
+failed_mount:
+	kfree(msblk->fragment_index);
+	kfree(msblk->fragment);
+	kfree(msblk->uid);
+	kfree(msblk->read_page);
+	kfree(msblk->read_data);
+	kfree(msblk->block_cache);
+	kfree(msblk->fragment_index_2);
+	return NULL;
+}
+
+
+static int squashfs_statfs(struct super_block *s, struct statfs *buf)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	TRACE("Entered squashfs_statfs\n");
+
+	buf->f_type = SQUASHFS_MAGIC;
+	buf->f_bsize = sblk->block_size;
+	buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
+	buf->f_bfree = buf->f_bavail = 0;
+	buf->f_files = sblk->inodes;
+	buf->f_ffree = 0;
+	buf->f_namelen = SQUASHFS_NAME_LEN;
+
+	return 0;
+}
+
+
+static int squashfs_symlink_readpage(struct file *file, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
+	long long block = SQUASHFS_I(inode)->start_block;
+	int offset = SQUASHFS_I(inode)->offset;
+	void *pageaddr = kmap(page);
+
+	TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
+				"%llx, offset %x\n", page->index,
+				SQUASHFS_I(inode)->start_block,
+				SQUASHFS_I(inode)->offset);
+
+	for (length = 0; length < index; length += bytes) {
+		if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
+				block, offset, PAGE_CACHE_SIZE, &block,
+				&offset))) {
+			ERROR("Unable to read symbolic link [%llx:%x]\n", block,
+					offset);
+			goto skip_read;
+		}
+	}
+
+	if (length != index) {
+		ERROR("(squashfs_symlink_readpage) length != index\n");
+		bytes = 0;
+		goto skip_read;
+	}
+
+	bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
+					i_size_read(inode) - length;
+
+	if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
+					offset, bytes, &block, &offset)))
+		ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
+
+skip_read:
+	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
+	kunmap(page);
+	SetPageUptodate(page);
+	UnlockPage(page);
+
+	return 0;
+}
+
+
+struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
+{
+	struct meta_index *meta = NULL;
+	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+	int i;
+
+	down(&msblk->meta_index_mutex);
+
+	TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
+
+	if(msblk->meta_index == NULL)
+		goto not_allocated;
+
+	for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
+		if (msblk->meta_index[i].inode_number == inode->i_ino &&
+				msblk->meta_index[i].offset >= offset &&
+				msblk->meta_index[i].offset <= index &&
+				msblk->meta_index[i].locked == 0) {
+			TRACE("locate_meta_index: entry %d, offset %d\n", i,
+					msblk->meta_index[i].offset);
+			meta = &msblk->meta_index[i];
+			offset = meta->offset;
+		}
+
+	if (meta)
+		meta->locked = 1;
+
+not_allocated:
+	up(&msblk->meta_index_mutex);
+
+	return meta;
+}
+
+
+struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
+{
+	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+	struct meta_index *meta = NULL;
+	int i;
+
+	down(&msblk->meta_index_mutex);
+
+	TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
+
+	if(msblk->meta_index == NULL) {
+		if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
+					SQUASHFS_META_NUMBER, GFP_KERNEL))) {
+			ERROR("Failed to allocate meta_index\n");
+			goto failed;
+		}
+		for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
+			msblk->meta_index[i].inode_number = 0;
+			msblk->meta_index[i].locked = 0;
+		}
+		msblk->next_meta_index = 0;
+	}
+
+	for(i = SQUASHFS_META_NUMBER; i &&
+			msblk->meta_index[msblk->next_meta_index].locked; i --)
+		msblk->next_meta_index = (msblk->next_meta_index + 1) %
+			SQUASHFS_META_NUMBER;
+
+	if(i == 0) {
+		TRACE("empty_meta_index: failed!\n");
+		goto failed;
+	}
+
+	TRACE("empty_meta_index: returned meta entry %d, %p\n",
+			msblk->next_meta_index,
+			&msblk->meta_index[msblk->next_meta_index]);
+
+	meta = &msblk->meta_index[msblk->next_meta_index];
+	msblk->next_meta_index = (msblk->next_meta_index + 1) %
+			SQUASHFS_META_NUMBER;
+
+	meta->inode_number = inode->i_ino;
+	meta->offset = offset;
+	meta->skip = skip;
+	meta->entries = 0;
+	meta->locked = 1;
+
+failed:
+	up(&msblk->meta_index_mutex);
+	return meta;
+}
+
+
+void release_meta_index(struct inode *inode, struct meta_index *meta)
+{
+	meta->locked = 0;
+}
+
+
+static int read_block_index(struct super_block *s, int blocks, char *block_list,
+		long long *start_block, int *offset)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	unsigned int *block_listp;
+	int block = 0;
+	
+	if (msblk->swap) {
+		char sblock_list[blocks << 2];
+
+		if (!squashfs_get_cached_block(s, sblock_list, *start_block,
+				*offset, blocks << 2, start_block, offset)) {
+			ERROR("Unable to read block list [%llx:%x]\n",
+				*start_block, *offset);
+			goto failure;
+		}
+		SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
+				((unsigned int *)sblock_list), blocks);
+	} else
+		if (!squashfs_get_cached_block(s, block_list, *start_block,
+				*offset, blocks << 2, start_block, offset)) {
+			ERROR("Unable to read block list [%llx:%x]\n",
+				*start_block, *offset);
+			goto failure;
+		}
+
+	for (block_listp = (unsigned int *) block_list; blocks;
+				block_listp++, blocks --)
+		block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
+
+	return block;
+
+failure:
+	return -1;
+}
+
+
+#define SIZE 256
+
+static inline int calculate_skip(int blocks) {
+	int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
+	return skip >= 7 ? 7 : skip + 1;
+}
+
+
+static int get_meta_index(struct inode *inode, int index,
+		long long *index_block, int *index_offset,
+		long long *data_block, char *block_list)
+{
+	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
+	int offset = 0;
+	struct meta_index *meta;
+	struct meta_entry *meta_entry;
+	long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
+	int cur_offset = SQUASHFS_I(inode)->offset;
+	long long cur_data_block = SQUASHFS_I(inode)->start_block;
+	int i;
+ 
+	index /= SQUASHFS_META_INDEXES * skip;
+
+	while ( offset < index ) {
+		meta = locate_meta_index(inode, index, offset + 1);
+
+		if (meta == NULL) {
+			if ((meta = empty_meta_index(inode, offset + 1,
+							skip)) == NULL)
+				goto all_done;
+		} else {
+			offset = index < meta->offset + meta->entries ? index :
+				meta->offset + meta->entries - 1;
+			meta_entry = &meta->meta_entry[offset - meta->offset];
+			cur_index_block = meta_entry->index_block + sblk->inode_table_start;
+			cur_offset = meta_entry->offset;
+			cur_data_block = meta_entry->data_block;
+			TRACE("get_meta_index: offset %d, meta->offset %d, "
+				"meta->entries %d\n", offset, meta->offset,
+				meta->entries);
+			TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
+				" data_block 0x%llx\n", cur_index_block,
+				cur_offset, cur_data_block);
+		}
+
+		for (i = meta->offset + meta->entries; i <= index &&
+				i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
+			int blocks = skip * SQUASHFS_META_INDEXES;
+
+			while (blocks) {
+				int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
+					blocks;
+				int res = read_block_index(inode->i_sb, block,
+					block_list, &cur_index_block,
+					&cur_offset);
+
+				if (res == -1)
+					goto failed;
+
+				cur_data_block += res;
+				blocks -= block;
+			}
+
+			meta_entry = &meta->meta_entry[i - meta->offset];
+			meta_entry->index_block = cur_index_block - sblk->inode_table_start;
+			meta_entry->offset = cur_offset;
+			meta_entry->data_block = cur_data_block;
+			meta->entries ++;
+			offset ++;
+		}
+
+		TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
+				meta->offset, meta->entries);
+
+		release_meta_index(inode, meta);
+	}
+
+all_done:
+	*index_block = cur_index_block;
+	*index_offset = cur_offset;
+	*data_block = cur_data_block;
+
+	return offset * SQUASHFS_META_INDEXES * skip;
+
+failed:
+	release_meta_index(inode, meta);
+	return -1;
+}
+
+
+static long long read_blocklist(struct inode *inode, int index,
+				int readahead_blks, char *block_list,
+				unsigned short **block_p, unsigned int *bsize)
+{
+	long long block_ptr;
+	int offset;
+	long long block;
+	int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
+		block_list);
+
+	TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
+		       " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
+		       block);
+
+	if(res == -1)
+		goto failure;
+
+	index -= res;
+
+	while ( index ) {
+		int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
+		int res = read_block_index(inode->i_sb, blocks, block_list,
+			&block_ptr, &offset);
+		if (res == -1)
+			goto failure;
+		block += res;
+		index -= blocks;
+	}
+
+	if (read_block_index(inode->i_sb, 1, block_list,
+			&block_ptr, &offset) == -1)
+		goto failure;
+	*bsize = *((unsigned int *) block_list);
+
+	return block;
+
+failure:
+	return 0;
+}
+
+
+static int squashfs_readpage(struct file *file, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned char block_list[SIZE];
+	long long block;
+	unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
+	int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
+ 	void *pageaddr;
+	struct squashfs_fragment_cache *fragment = NULL;
+	char *data_ptr = msblk->read_page;
+	
+	int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
+	int start_index = page->index & ~mask;
+	int end_index = start_index | mask;
+
+	TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
+					page->index,
+					SQUASHFS_I(inode)->start_block);
+
+	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+					PAGE_CACHE_SHIFT))
+		goto skip_read;
+
+	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+					|| index < (i_size_read(inode) >>
+					sblk->block_log)) {
+		if ((block = (msblk->read_blocklist)(inode, index, 1,
+					block_list, NULL, &bsize)) == 0)
+			goto skip_read;
+
+		down(&msblk->read_page_mutex);
+		
+		if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
+					block, bsize, NULL))) {
+			ERROR("Unable to read page, block %llx, size %x\n", block,
+					bsize);
+			up(&msblk->read_page_mutex);
+			goto skip_read;
+		}
+	} else {
+		if ((fragment = get_cached_fragment(inode->i_sb,
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block,
+					SQUASHFS_I(inode)->u.s1.fragment_size))
+					== NULL) {
+			ERROR("Unable to read page, block %llx, size %x\n",
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block,
+					(int) SQUASHFS_I(inode)->
+					u.s1.fragment_size);
+			goto skip_read;
+		}
+		bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
+					(i_size_read(inode) & (sblk->block_size
+					- 1));
+		byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
+		data_ptr = fragment->data;
+	}
+
+	for (i = start_index; i <= end_index && byte_offset < bytes;
+					i++, byte_offset += PAGE_CACHE_SIZE) {
+		struct page *push_page;
+		int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
+					PAGE_CACHE_SIZE : bytes - byte_offset;
+
+		TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
+					bytes, i, byte_offset, available_bytes);
+
+		if (i == page->index)  {
+			pageaddr = kmap_atomic(page, KM_USER0);
+			memcpy(pageaddr, data_ptr + byte_offset,
+					available_bytes);
+			memset(pageaddr + available_bytes, 0,
+					PAGE_CACHE_SIZE - available_bytes);
+			kunmap_atomic(pageaddr, KM_USER0);
+			flush_dcache_page(page);
+			SetPageUptodate(page);
+			UnlockPage(page);
+		} else if ((push_page =
+				grab_cache_page_nowait(page->mapping, i))) {
+ 			pageaddr = kmap_atomic(push_page, KM_USER0);
+
+			memcpy(pageaddr, data_ptr + byte_offset,
+					available_bytes);
+			memset(pageaddr + available_bytes, 0,
+					PAGE_CACHE_SIZE - available_bytes);
+			kunmap_atomic(pageaddr, KM_USER0);
+			flush_dcache_page(push_page);
+			SetPageUptodate(push_page);
+			UnlockPage(push_page);
+			page_cache_release(push_page);
+		}
+	}
+
+	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+					|| index < (i_size_read(inode) >>
+					sblk->block_log))
+		up(&msblk->read_page_mutex);
+	else
+		release_cached_fragment(msblk, fragment);
+
+	return 0;
+
+skip_read:
+	pageaddr = kmap_atomic(page, KM_USER0);
+	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
+	kunmap_atomic(pageaddr, KM_USER0);
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+	UnlockPage(page);
+
+	return 0;
+}
+
+
+static int squashfs_readpage4K(struct file *file, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned char block_list[SIZE];
+	long long block;
+	unsigned int bsize, bytes = 0;
+ 	void *pageaddr;
+	
+	TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
+					page->index,
+					SQUASHFS_I(inode)->start_block);
+
+	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+					PAGE_CACHE_SHIFT)) {
+		pageaddr = kmap_atomic(page, KM_USER0);
+		goto skip_read;
+	}
+
+	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+					|| page->index < (i_size_read(inode) >>
+					sblk->block_log)) {
+		block = (msblk->read_blocklist)(inode, page->index, 1,
+					block_list, NULL, &bsize);
+
+		down(&msblk->read_page_mutex);
+		bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
+					bsize, NULL);
+		pageaddr = kmap_atomic(page, KM_USER0);
+		if (bytes)
+			memcpy(pageaddr, msblk->read_page, bytes);
+		else
+			ERROR("Unable to read page, block %llx, size %x\n",
+					block, bsize);
+		up(&msblk->read_page_mutex);
+	} else {
+		struct squashfs_fragment_cache *fragment =
+			get_cached_fragment(inode->i_sb,
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block,
+					SQUASHFS_I(inode)-> u.s1.fragment_size);
+		pageaddr = kmap_atomic(page, KM_USER0);
+		if (fragment) {
+			bytes = i_size_read(inode) & (sblk->block_size - 1);
+			memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
+					u.s1.fragment_offset, bytes);
+			release_cached_fragment(msblk, fragment);
+		} else
+			ERROR("Unable to read page, block %llx, size %x\n",
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block, (int)
+					SQUASHFS_I(inode)-> u.s1.fragment_size);
+	}
+
+skip_read:
+	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
+	kunmap_atomic(pageaddr, KM_USER0);
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+	UnlockPage(page);
+
+	return 0;
+}
+
+
+static int get_dir_index_using_offset(struct super_block *s, long long 
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				long long f_pos)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	struct squashfs_dir_index index;
+
+	TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
+					i_count, (unsigned int) f_pos);
+
+	f_pos -= 3;
+	if (f_pos == 0)
+		goto finish;
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) &index,
+					index_start, index_offset,
+					sizeof(index), &index_start,
+					&index_offset);
+
+		if (index.index > f_pos)
+			break;
+
+		squashfs_get_cached_block(s, NULL, index_start, index_offset,
+					index.size + 1, &index_start,
+					&index_offset);
+
+		length = index.index;
+		*next_block = index.start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+
+finish:
+	return length + 3;
+}
+
+
+static int get_dir_index_using_name(struct super_block *s, long long
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				const char *name, int size)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
+	struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
+	char str[SQUASHFS_NAME_LEN + 1];
+
+	TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
+
+	strncpy(str, name, size);
+	str[size] = '\0';
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) index,
+					index_start, index_offset,
+					sizeof(struct squashfs_dir_index),
+					&index_start, &index_offset);
+
+		squashfs_get_cached_block(s, index->name, index_start,
+					index_offset, index->size + 1,
+					&index_start, &index_offset);
+
+		index->name[index->size + 1] = '\0';
+
+		if (strcmp(index->name, str) > 0)
+			break;
+
+		length = index->index;
+		*next_block = index->start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+	return length + 3;
+}
+
+		
+static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *i = file->f_dentry->d_inode;
+	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+		sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
+		dir_count;
+	struct squashfs_dir_header dirh;
+	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
+	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
+
+	TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
+
+	while(file->f_pos < 3) {
+		char *name;
+		int size, i_ino;
+
+		if(file->f_pos == 0) {
+			name = ".";
+			size = 1;
+			i_ino = i->i_ino;
+		} else {
+			name = "..";
+			size = 2;
+			i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
+		}
+		TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
+				(unsigned int) dirent, name, size, (int)
+				file->f_pos, i_ino,
+				squashfs_filetype_table[1]);
+
+		if (filldir(dirent, name, size,
+				file->f_pos, i_ino,
+				squashfs_filetype_table[1]) < 0) {
+				TRACE("Filldir returned less than 0\n");
+				goto finish;
+		}
+		file->f_pos += size;
+		dirs_read++;
+	}
+
+	length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count,
+				file->f_pos);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header sdirh;
+			
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block, next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block, next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+						next_block, next_offset,
+						dire->size + 1, &next_block,
+						&next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (file->f_pos >= length)
+				continue;
+
+			dire->name[dire->size + 1] = '\0';
+
+			TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
+					(unsigned int) dirent, dire->name,
+					dire->size + 1, (int) file->f_pos,
+					dirh.start_block, dire->offset,
+					dirh.inode_number + dire->inode_number,
+					squashfs_filetype_table[dire->type]);
+
+			if (filldir(dirent, dire->name, dire->size + 1,
+					file->f_pos,
+					dirh.inode_number + dire->inode_number,
+					squashfs_filetype_table[dire->type])
+					< 0) {
+				TRACE("Filldir returned less than 0\n");
+				goto finish;
+			}
+			file->f_pos = length;
+			dirs_read++;
+		}
+	}
+
+finish:
+	return dirs_read;
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	return 0;
+}
+
+
+static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry)
+{
+	const unsigned char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	struct inode *inode = NULL;
+	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+				sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0,
+				dir_count;
+	struct squashfs_dir_header dirh;
+	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
+	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
+
+	TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
+
+	if (len > SQUASHFS_NAME_LEN)
+		goto exit_loop;
+
+	length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count, name,
+				len);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header sdirh;
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block,next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block,next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+					next_block, next_offset, dire->size + 1,
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (name[0] < dire->name[0])
+				goto exit_loop;
+
+			if ((len == dire->size + 1) && !strncmp(name,
+						dire->name, len)) {
+				squashfs_inode_t ino =
+					SQUASHFS_MKINODE(dirh.start_block,
+					dire->offset);
+
+				TRACE("calling squashfs_iget for directory "
+					"entry %s, inode %x:%x, %d\n", name,
+					dirh.start_block, dire->offset,
+					dirh.inode_number + dire->inode_number);
+
+				inode = (msblk->iget)(i->i_sb, ino);
+
+				goto exit_loop;
+			}
+		}
+	}
+
+exit_loop:
+	d_add(dentry, inode);
+	return ERR_PTR(0);
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	goto exit_loop;
+}
+
+
+static void squashfs_put_super(struct super_block *s)
+{
+	int i;
+
+		struct squashfs_sb_info *sbi = &s->u.squashfs_sb;
+		if (sbi->block_cache)
+			for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+				if (sbi->block_cache[i].block !=
+							SQUASHFS_INVALID_BLK)
+					kfree(sbi->block_cache[i].data);
+		if (sbi->fragment)
+			for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) 
+				SQUASHFS_FREE(sbi->fragment[i].data);
+		kfree(sbi->fragment);
+		kfree(sbi->block_cache);
+		kfree(sbi->read_data);
+		kfree(sbi->read_page);
+		kfree(sbi->uid);
+		kfree(sbi->fragment_index);
+		kfree(sbi->fragment_index_2);
+		sbi->block_cache = NULL;
+		sbi->uid = NULL;
+		sbi->read_data = NULL;
+		sbi->read_page = NULL;
+		sbi->fragment = NULL;
+		sbi->fragment_index = NULL;
+		sbi->fragment_index_2 = NULL;
+}
+
+
+static int __init init_squashfs_fs(void)
+{
+
+	printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
+		"Phillip Lougher\n");
+
+	if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
+		ERROR("Failed to allocate zlib workspace\n");
+		return -ENOMEM;
+	}
+	return register_filesystem(&squashfs_fs_type);
+}
+
+
+static void __exit exit_squashfs_fs(void)
+{
+	vfree(stream.workspace);
+	unregister_filesystem(&squashfs_fs_type);
+}
+
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_squashfs_fs);
+module_exit(exit_squashfs_fs);
+MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem");
+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
+MODULE_LICENSE("GPL");
diff --new-file -urp linux-2.4.32/fs/squashfs/Makefile linux-2.4.32-squashfs3.0/fs/squashfs/Makefile
--- linux-2.4.32/fs/squashfs/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/fs/squashfs/Makefile	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux squashfs routines.
+#
+
+O_TARGET := squashfs.o
+
+obj-y  := inode.o squashfs2_0.o
+
+obj-m := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --new-file -urp linux-2.4.32/fs/squashfs/squashfs2_0.c linux-2.4.32-squashfs3.0/fs/squashfs/squashfs2_0.c
--- linux-2.4.32/fs/squashfs/squashfs2_0.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/fs/squashfs/squashfs2_0.c	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,751 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs2_0.c
+ */
+
+#include <linux/types.h>
+#include <linux/squashfs_fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/dcache.h>
+#include <linux/wait.h>
+#include <linux/zlib.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include "squashfs.h"
+
+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry);
+
+static struct file_operations squashfs_dir_ops_2 = {
+	.read = generic_read_dir,
+	.readdir = squashfs_readdir_2
+};
+
+static struct inode_operations squashfs_dir_inode_ops_2 = {
+	.lookup = squashfs_lookup_2
+};
+
+static unsigned char squashfs_filetype_table[] = {
+	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
+};
+
+static int read_fragment_index_table_2(struct super_block *s)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
+					(sblk->fragments), GFP_KERNEL))) {
+		ERROR("Failed to allocate uid/gid table\n");
+		return 0;
+	}
+   
+	if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
+					!squashfs_read_data(s, (char *)
+					msblk->fragment_index_2,
+					sblk->fragment_table_start,
+					SQUASHFS_FRAGMENT_INDEX_BYTES_2
+					(sblk->fragments) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+		ERROR("unable to read fragment index table\n");
+		return 0;
+	}
+
+	if (msblk->swap) {
+		int i;
+		unsigned int fragment;
+
+		for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
+									i++) {
+			SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
+						&msblk->fragment_index_2[i], 1);
+			msblk->fragment_index_2[i] = fragment;
+		}
+	}
+
+	return 1;
+}
+
+
+static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
+				long long *fragment_start_block,
+				unsigned int *fragment_size)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	long long start_block =
+		msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
+	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
+	struct squashfs_fragment_entry_2 fragment_entry;
+
+	if (msblk->swap) {
+		struct squashfs_fragment_entry_2 sfragment_entry;
+
+		if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
+					start_block, offset,
+					sizeof(sfragment_entry), &start_block,
+					&offset))
+			goto out;
+		SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
+	} else
+		if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
+					start_block, offset,
+					sizeof(fragment_entry), &start_block,
+					&offset))
+			goto out;
+
+	*fragment_start_block = fragment_entry.start_block;
+	*fragment_size = fragment_entry.size;
+
+	return 1;
+
+out:
+	return 0;
+}
+
+
+static struct inode *squashfs_new_inode(struct super_block *s,
+		struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	struct inode *i = new_inode(s);
+
+	if (i) {
+		i->i_ino = ino;
+		i->i_mtime = sblk->mkfs_time;
+		i->i_atime = sblk->mkfs_time;
+		i->i_ctime = sblk->mkfs_time;
+		i->i_uid = msblk->uid[inodeb->uid];
+		i->i_mode = inodeb->mode;
+		i->i_nlink = 1;
+		i->i_size = 0;
+		if (inodeb->guid == SQUASHFS_GUIDS)
+			i->i_gid = i->i_uid;
+		else
+			i->i_gid = msblk->guid[inodeb->guid];
+	}
+
+	return i;
+}
+
+
+static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
+{
+	struct inode *i;
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned int block = SQUASHFS_INODE_BLK(inode) +
+		sblk->inode_table_start;
+	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+	unsigned int ino = SQUASHFS_MK_VFS_INODE(block
+		- sblk->inode_table_start, offset);
+	long long next_block;
+	unsigned int next_offset;
+	union squashfs_inode_header_2 id, sid;
+	struct squashfs_base_inode_header_2 *inodeb = &id.base,
+					  *sinodeb = &sid.base;
+
+	TRACE("Entered squashfs_iget\n");
+
+	if (msblk->swap) {
+		if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
+					offset, sizeof(*sinodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+		SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
+					sizeof(*sinodeb));
+	} else
+		if (!squashfs_get_cached_block(s, (char *) inodeb, block,
+					offset, sizeof(*inodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+
+	switch(inodeb->inode_type) {
+		case SQUASHFS_FILE_TYPE: {
+			struct squashfs_reg_inode_header_2 *inodep = &id.reg;
+			struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
+			long long frag_blk;
+			unsigned int frag_size;
+				
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			frag_blk = SQUASHFS_INVALID_BLK;
+			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+					!get_fragment_location_2(s,
+					inodep->fragment, &frag_blk, &frag_size))
+				goto failed_read;
+				
+			if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+				goto failed_read1;
+
+			i->i_size = inodep->file_size;
+			i->i_fop = &generic_ro_fops;
+			i->i_mode |= S_IFREG;
+			i->i_mtime = inodep->mtime;
+			i->i_atime = inodep->mtime;
+			i->i_ctime = inodep->mtime;
+			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+			i->i_blksize = PAGE_CACHE_SIZE;
+			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+			if (sblk->block_size > 4096)
+				i->i_data.a_ops = &squashfs_aops;
+			else
+				i->i_data.a_ops = &squashfs_aops_4K;
+
+			TRACE("File inode %x:%x, start_block %x, "
+					"block_list_start %llx, offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, next_block,
+					next_offset);
+			break;
+		}
+		case SQUASHFS_DIR_TYPE: {
+			struct squashfs_dir_inode_header_2 *inodep = &id.dir;
+			struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+				goto failed_read1;
+
+			i->i_size = inodep->file_size;
+			i->i_op = &squashfs_dir_inode_ops_2;
+			i->i_fop = &squashfs_dir_ops_2;
+			i->i_mode |= S_IFDIR;
+			i->i_mtime = inodep->mtime;
+			i->i_atime = inodep->mtime;
+			i->i_ctime = inodep->mtime;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count = 0;
+			SQUASHFS_I(i)->u.s2.parent_inode = 0;
+
+			TRACE("Directory inode %x:%x, start_block %x, offset "
+					"%x\n", SQUASHFS_INODE_BLK(inode),
+					offset, inodep->start_block,
+					inodep->offset);
+			break;
+		}
+		case SQUASHFS_LDIR_TYPE: {
+			struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
+			struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
+						sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+				goto failed_read1;
+
+			i->i_size = inodep->file_size;
+			i->i_op = &squashfs_dir_inode_ops_2;
+			i->i_fop = &squashfs_dir_ops_2;
+			i->i_mode |= S_IFDIR;
+			i->i_mtime = inodep->mtime;
+			i->i_atime = inodep->mtime;
+			i->i_ctime = inodep->mtime;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
+			SQUASHFS_I(i)->u.s2.directory_index_offset =
+								next_offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count =
+								inodep->i_count;
+			SQUASHFS_I(i)->u.s2.parent_inode = 0;
+
+			TRACE("Long directory inode %x:%x, start_block %x, "
+					"offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, inodep->offset);
+			break;
+		}
+		case SQUASHFS_SYMLINK_TYPE: {
+			struct squashfs_symlink_inode_header_2 *inodep =
+								&id.symlink;
+			struct squashfs_symlink_inode_header_2 *sinodep =
+								&sid.symlink;
+	
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
+								sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+				goto failed_read1;
+
+			i->i_size = 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_header_2 *inodep = &id.dev;
+			struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
+			} else	
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+				goto failed_read1;
+
+			i->i_mode |= (inodeb->inode_type ==
+					SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
+					S_IFBLK;
+			init_special_inode(i, i->i_mode, inodep->rdev);
+
+			TRACE("Device inode %x:%x, rdev %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->rdev);
+			break;
+		 }
+		 case SQUASHFS_FIFO_TYPE:
+		 case SQUASHFS_SOCKET_TYPE: {
+			if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+				goto failed_read1;
+
+			i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
+							? S_IFIFO : S_IFSOCK;
+			init_special_inode(i, i->i_mode, 0);
+			break;
+		 }
+		 default:
+			ERROR("Unknown inode type %d in squashfs_iget!\n",
+					inodeb->inode_type);
+			goto failed_read1;
+	}
+	
+	insert_inode_hash(i);
+	return i;
+
+failed_read:
+	ERROR("Unable to read inode [%x:%x]\n", block, offset);
+
+failed_read1:
+	return NULL;
+}
+
+
+static int get_dir_index_using_offset(struct super_block *s, long long 
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				long long f_pos)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	struct squashfs_dir_index_2 index;
+
+	TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
+					i_count, (unsigned int) f_pos);
+
+	if (f_pos == 0)
+		goto finish;
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index_2 sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) &index,
+					index_start, index_offset,
+					sizeof(index), &index_start,
+					&index_offset);
+
+		if (index.index > f_pos)
+			break;
+
+		squashfs_get_cached_block(s, NULL, index_start, index_offset,
+					index.size + 1, &index_start,
+					&index_offset);
+
+		length = index.index;
+		*next_block = index.start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+
+finish:
+	return length;
+}
+
+
+static int get_dir_index_using_name(struct super_block *s, long long
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				const char *name, int size)
+{
+	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
+	struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
+	char str[SQUASHFS_NAME_LEN + 1];
+
+	TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
+
+	strncpy(str, name, size);
+	str[size] = '\0';
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index_2 sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) index,
+					index_start, index_offset,
+					sizeof(struct squashfs_dir_index_2),
+					&index_start, &index_offset);
+
+		squashfs_get_cached_block(s, index->name, index_start,
+					index_offset, index->size + 1,
+					&index_start, &index_offset);
+
+		index->name[index->size + 1] = '\0';
+
+		if (strcmp(index->name, str) > 0)
+			break;
+
+		length = index->index;
+		*next_block = index->start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+	return length;
+}
+
+		
+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *i = file->f_dentry->d_inode;
+	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+		sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
+		dir_count;
+	struct squashfs_dir_header_2 dirh;
+	char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
+	struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
+
+	TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
+
+	length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count,
+				file->f_pos);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header_2 sdirh;
+			
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry_2 sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block, next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block, next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+						next_block, next_offset,
+						dire->size + 1, &next_block,
+						&next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (file->f_pos >= length)
+				continue;
+
+			dire->name[dire->size + 1] = '\0';
+
+			TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
+					(unsigned int) dirent, dire->name,
+					dire->size + 1, (int) file->f_pos,
+					dirh.start_block, dire->offset,
+					squashfs_filetype_table[dire->type]);
+
+			if (filldir(dirent, dire->name, dire->size + 1,
+					file->f_pos, SQUASHFS_MK_VFS_INODE(
+					dirh.start_block, dire->offset),
+					squashfs_filetype_table[dire->type])
+					< 0) {
+				TRACE("Filldir returned less than 0\n");
+				goto finish;
+			}
+			file->f_pos = length;
+			dirs_read++;
+		}
+	}
+
+finish:
+	return dirs_read;
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	return 0;
+}
+
+
+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry)
+{
+	const unsigned char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	struct inode *inode = NULL;
+	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+				sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0,
+				dir_count;
+	struct squashfs_dir_header_2 dirh;
+	char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
+	struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
+	int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
+
+	TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
+
+	if (len > SQUASHFS_NAME_LEN)
+		goto exit_loop;
+
+	length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count, name,
+				len);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header_2 sdirh;
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry_2 sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block,next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block,next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+					next_block, next_offset, dire->size + 1,
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (sorted && name[0] < dire->name[0])
+				goto exit_loop;
+
+			if ((len == dire->size + 1) && !strncmp(name,
+						dire->name, len)) {
+				squashfs_inode_t ino =
+					SQUASHFS_MKINODE(dirh.start_block,
+					dire->offset);
+
+				TRACE("calling squashfs_iget for directory "
+					"entry %s, inode %x:%x, %d\n", name,
+					dirh.start_block, dire->offset, ino);
+
+				inode = (msblk->iget)(i->i_sb, ino);
+
+				goto exit_loop;
+			}
+		}
+	}
+
+exit_loop:
+	d_add(dentry, inode);
+	return ERR_PTR(0);
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	goto exit_loop;
+}
+
+
+int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
+{
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	msblk->iget = squashfs_iget_2;
+	msblk->read_fragment_index_table = read_fragment_index_table_2;
+
+	sblk->bytes_used = sblk->bytes_used_2;
+	sblk->uid_start = sblk->uid_start_2;
+	sblk->guid_start = sblk->guid_start_2;
+	sblk->inode_table_start = sblk->inode_table_start_2;
+	sblk->directory_table_start = sblk->directory_table_start_2;
+	sblk->fragment_table_start = sblk->fragment_table_start_2;
+
+	return 1;
+}
diff --new-file -urp linux-2.4.32/fs/squashfs/squashfs.h linux-2.4.32-squashfs3.0/fs/squashfs/squashfs.h
--- linux-2.4.32/fs/squashfs/squashfs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/fs/squashfs/squashfs.h	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,85 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs.h
+ */
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+#endif
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...)	printk(KERN_NOTICE "SQUASHFS: "s, ## args)
+#else
+#define TRACE(s, args...)	{}
+#endif
+
+#define ERROR(s, args...)	printk(KERN_ERR "SQUASHFS error: "s, ## args)
+
+#define SERROR(s, args...)	do { \
+				if (!silent) \
+				printk(KERN_ERR "SQUASHFS error: "s, ## args);\
+				} while(0)
+
+#define WARNING(s, args...)	printk(KERN_WARNING "SQUASHFS: "s, ## args)
+
+#define SQUASHFS_I(INO)			(&INO->u.squashfs_i)
+
+#define i_size_read(INO)		(INO->i_size)
+
+#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
+#define SQSH_EXTERN
+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
+				long long index, unsigned int length,
+				long long *next_index);
+extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
+				long long block, unsigned int offset,
+				int length, long long *next_block,
+				unsigned int *next_offset);
+extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
+					squashfs_fragment_cache *fragment);
+extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
+					*s, long long start_block,
+					int length);
+extern struct address_space_operations squashfs_symlink_aops;
+extern struct address_space_operations squashfs_aops;
+extern struct address_space_operations squashfs_aops_4K;
+extern struct file_operations squashfs_dir_ops;
+extern struct inode_operations squashfs_dir_inode_ops;
+#else
+#define SQSH_EXTERN static
+#endif
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
+#else
+static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
+#else
+static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
+{
+	return 0;
+}
+#endif
diff --new-file -urp linux-2.4.32/include/linux/fs.h linux-2.4.32-squashfs3.0/include/linux/fs.h
--- linux-2.4.32/include/linux/fs.h	2005-04-04 02:42:20.000000000 +0100
+++ linux-2.4.32-squashfs3.0/include/linux/fs.h	2006-03-07 21:12:36.000000000 +0000
@@ -324,6 +324,7 @@ extern void set_bh_page(struct buffer_he
 #include <linux/usbdev_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
+#include <linux/squashfs_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -519,6 +520,7 @@ struct inode {
 		struct socket			socket_i;
 		struct usbdev_inode_info        usbdev_i;
 		struct jffs2_inode_info		jffs2_i;
+		struct squashfs_inode_info	squashfs_i;
 		void				*generic_ip;
 	} u;
 };
@@ -734,6 +736,7 @@ struct nameidata {
 #include <linux/usbdev_fs_sb.h>
 #include <linux/cramfs_fs_sb.h>
 #include <linux/jffs2_fs_sb.h>
+#include <linux/squashfs_fs_sb.h>
 
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
@@ -793,6 +796,7 @@ struct super_block {
 		struct usbdev_sb_info   usbdevfs_sb;
 		struct jffs2_sb_info	jffs2_sb;
 		struct cramfs_sb_info	cramfs_sb;
+		struct squashfs_sb_info	squashfs_sb;
 		void			*generic_sbp;
 	} u;
 	/*
diff --new-file -urp linux-2.4.32/include/linux/squashfs_fs.h linux-2.4.32-squashfs3.0/include/linux/squashfs_fs.h
--- linux-2.4.32/include/linux/squashfs_fs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/include/linux/squashfs_fs.h	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,915 @@
+#ifndef SQUASHFS_FS
+#define SQUASHFS_FS
+
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs.h
+ */
+
+#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
+#endif
+
+#ifdef CONFIG_SQUASHFS_VMALLOC
+#define SQUASHFS_ALLOC(a)		vmalloc(a)
+#define SQUASHFS_FREE(a)		vfree(a)
+#else
+#define SQUASHFS_ALLOC(a)		kmalloc(a, GFP_KERNEL)
+#define SQUASHFS_FREE(a)		kfree(a)
+#endif
+#ifdef CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
+#define SQUASHFS_CACHED_FRAGMENTS	CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
+#else
+#define SQUASHFS_CACHED_FRAGMENTS	3
+#endif
+#define SQUASHFS_MAJOR			3
+#define SQUASHFS_MINOR			0
+#define SQUASHFS_MAGIC			0x73717368
+#define SQUASHFS_MAGIC_SWAP		0x68737173
+#define SQUASHFS_START			0
+
+/* size of metadata (inode and directory) blocks */
+#define SQUASHFS_METADATA_SIZE		8192
+#define SQUASHFS_METADATA_LOG		13
+
+/* default size of data blocks */
+#define SQUASHFS_FILE_SIZE		65536
+#define SQUASHFS_FILE_LOG		16
+
+#define SQUASHFS_FILE_MAX_SIZE		65536
+
+/* Max number of uids and gids */
+#define SQUASHFS_UIDS			256
+#define SQUASHFS_GUIDS			255
+
+/* Max length of filename (not 255) */
+#define SQUASHFS_NAME_LEN		256
+
+#define SQUASHFS_INVALID		((long long) 0xffffffffffff)
+#define SQUASHFS_INVALID_FRAG		((unsigned int) 0xffffffff)
+#define SQUASHFS_INVALID_BLK		((long long) -1)
+#define SQUASHFS_USED_BLK		((long long) -2)
+
+/* Filesystem flags */
+#define SQUASHFS_NOI			0
+#define SQUASHFS_NOD			1
+#define SQUASHFS_CHECK			2
+#define SQUASHFS_NOF			3
+#define SQUASHFS_NO_FRAG		4
+#define SQUASHFS_ALWAYS_FRAG		5
+#define SQUASHFS_DUPLICATE		6
+
+#define SQUASHFS_BIT(flag, bit)		((flag >> bit) & 1)
+
+#define SQUASHFS_UNCOMPRESSED_INODES(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOI)
+
+#define SQUASHFS_UNCOMPRESSED_DATA(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOD)
+
+#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOF)
+
+#define SQUASHFS_NO_FRAGMENTS(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_NO_FRAG)
+
+#define SQUASHFS_ALWAYS_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_ALWAYS_FRAG)
+
+#define SQUASHFS_DUPLICATES(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_DUPLICATE)
+
+#define SQUASHFS_CHECK_DATA(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_CHECK)
+
+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
+		duplicate_checking)	(noi | (nod << 1) | (check_data << 2) \
+		| (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
+		(duplicate_checking << 6))
+
+/* Max number of types and file types */
+#define SQUASHFS_DIR_TYPE		1
+#define SQUASHFS_FILE_TYPE		2
+#define SQUASHFS_SYMLINK_TYPE		3
+#define SQUASHFS_BLKDEV_TYPE		4
+#define SQUASHFS_CHRDEV_TYPE		5
+#define SQUASHFS_FIFO_TYPE		6
+#define SQUASHFS_SOCKET_TYPE		7
+#define SQUASHFS_LDIR_TYPE		8
+#define SQUASHFS_LREG_TYPE		9
+
+/* 1.0 filesystem type definitions */
+#define SQUASHFS_TYPES			5
+#define SQUASHFS_IPC_TYPE		0
+
+/* Flag whether block is compressed or uncompressed, bit is set if block is
+ * uncompressed */
+#define SQUASHFS_COMPRESSED_BIT		(1 << 15)
+
+#define SQUASHFS_COMPRESSED_SIZE(B)	(((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
+		(B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
+
+#define SQUASHFS_COMPRESSED(B)		(!((B) & SQUASHFS_COMPRESSED_BIT))
+
+#define SQUASHFS_COMPRESSED_BIT_BLOCK		(1 << 24)
+
+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)	(((B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
+
+#define SQUASHFS_COMPRESSED_BLOCK(B)	(!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
+
+/*
+ * Inode number ops.  Inodes consist of a compressed block number, and an
+ * uncompressed  offset within that block
+ */
+#define SQUASHFS_INODE_BLK(a)		((unsigned int) ((a) >> 16))
+
+#define SQUASHFS_INODE_OFFSET(a)	((unsigned int) ((a) & 0xffff))
+
+#define SQUASHFS_MKINODE(A, B)		((squashfs_inode_t)(((squashfs_inode_t) (A)\
+					<< 16) + (B)))
+
+/* Compute 32 bit VFS inode number from squashfs inode number */
+#define SQUASHFS_MK_VFS_INODE(a, b)	((unsigned int) (((a) << 8) + \
+					((b) >> 2) + 1))
+/* XXX */
+
+/* Translate between VFS mode and squashfs mode */
+#define SQUASHFS_MODE(a)		((a) & 0xfff)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES(A)	(A * sizeof(struct squashfs_fragment_entry))
+
+#define SQUASHFS_FRAGMENT_INDEX(A)	(SQUASHFS_FRAGMENT_BYTES(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)	(SQUASHFS_FRAGMENT_BYTES(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES(A)	((SQUASHFS_FRAGMENT_BYTES(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)	(SQUASHFS_FRAGMENT_INDEXES(A) *\
+						sizeof(long long))
+
+/* cached data constants for filesystem */
+#define SQUASHFS_CACHED_BLKS		8
+
+#define SQUASHFS_MAX_FILE_SIZE_LOG	64
+
+#define SQUASHFS_MAX_FILE_SIZE		((long long) 1 << \
+					(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
+
+#define SQUASHFS_MARKER_BYTE		0xff
+
+/* meta index cache */
+#define SQUASHFS_META_INDEXES	(SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
+#define SQUASHFS_META_ENTRIES	31
+#define SQUASHFS_META_NUMBER	8
+#define SQUASHFS_SLOTS		4
+
+struct meta_entry {
+	long long		data_block;
+	unsigned int		index_block;
+	unsigned short		offset;
+	unsigned short		pad;
+};
+
+struct meta_index {
+	unsigned int		inode_number;
+	unsigned int		offset;
+	unsigned short		entries;
+	unsigned short		skip;
+	unsigned short		locked;
+	unsigned short		pad;
+	struct meta_entry	meta_entry[SQUASHFS_META_ENTRIES];
+};
+
+
+/*
+ * definitions for structures on disk
+ */
+
+typedef long long		squashfs_block_t;
+typedef long long		squashfs_inode_t;
+
+struct squashfs_super_block {
+	unsigned int		s_magic;
+	unsigned int		inodes;
+	unsigned int		bytes_used_2;
+	unsigned int		uid_start_2;
+	unsigned int		guid_start_2;
+	unsigned int		inode_table_start_2;
+	unsigned int		directory_table_start_2;
+	unsigned int		s_major:16;
+	unsigned int		s_minor:16;
+	unsigned int		block_size_1:16;
+	unsigned int		block_log:16;
+	unsigned int		flags:8;
+	unsigned int		no_uids:8;
+	unsigned int		no_guids:8;
+	unsigned int		mkfs_time /* time of filesystem creation */;
+	squashfs_inode_t	root_inode;
+	unsigned int		block_size;
+	unsigned int		fragments;
+	unsigned int		fragment_table_start_2;
+	long long		bytes_used;
+	long long		uid_start;
+	long long		guid_start;
+	long long		inode_table_start;
+	long long		directory_table_start;
+	long long		fragment_table_start;
+	long long		unused;
+} __attribute__ ((packed));
+
+struct squashfs_dir_index {
+	unsigned int		index;
+	unsigned int		start_block;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+#define SQUASHFS_BASE_INODE_HEADER		\
+	unsigned int		inode_type:4;	\
+	unsigned int		mode:12;	\
+	unsigned int		uid:8;		\
+	unsigned int		guid:8;		\
+	unsigned int		mtime;		\
+	unsigned int 		inode_number;
+
+struct squashfs_base_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_lreg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	long long		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		parent_inode;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		i_count:16;
+	unsigned int		parent_inode;
+	struct squashfs_dir_index	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header {
+	struct squashfs_base_inode_header	base;
+	struct squashfs_dev_inode_header	dev;
+	struct squashfs_symlink_inode_header	symlink;
+	struct squashfs_reg_inode_header	reg;
+	struct squashfs_lreg_inode_header	lreg;
+	struct squashfs_dir_inode_header	dir;
+	struct squashfs_ldir_inode_header	ldir;
+	struct squashfs_ipc_inode_header	ipc;
+};
+	
+struct squashfs_dir_entry {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	int			inode_number:16;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_header {
+	unsigned int		count:8;
+	unsigned int		start_block;
+	unsigned int		inode_number;
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry {
+	long long		start_block;
+	unsigned int		size;
+	unsigned int		unused;
+} __attribute__ ((packed));
+
+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
+extern int squashfs_uncompress_init(void);
+extern int squashfs_uncompress_exit(void);
+
+/*
+ * macros to convert each packed bitfield structure from little endian to big
+ * endian and vice versa.  These are needed when creating or using a filesystem
+ * on a machine with different byte ordering to the target architecture.
+ *
+ */
+
+#define SQUASHFS_SWAP_START \
+	int bits;\
+	int b_pos;\
+	unsigned long long val;\
+	unsigned char *s;\
+	unsigned char *d;
+
+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
+	SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
+	SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
+	SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
+	SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
+	SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
+	SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
+	SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
+	SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
+	SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
+	SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
+	SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
+	SQUASHFS_SWAP((s)->flags, d, 288, 8);\
+	SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
+	SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
+	SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
+	SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
+	SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
+	SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
+	SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
+	SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
+	SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
+	SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
+	SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
+	SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
+	SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
+	SQUASHFS_SWAP((s)->unused, d, 888, 64);\
+}
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ipc_inode_header))\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dev_inode_header)); \
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_symlink_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_reg_inode_header));\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 192, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
+}
+
+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_lreg_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 224, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 147, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ldir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 155, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
+	SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
+	SQUASHFS_SWAP((s)->index, d, 0, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
+	SQUASHFS_SWAP((s)->size, d, 64, 8);\
+}
+
+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+	SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
+	SQUASHFS_SWAP((s)->size, d, 64, 32);\
+}
+
+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 2);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			16)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
+}
+
+#define SQUASHFS_SWAP_INTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 4);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			32)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
+}
+
+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			64)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
+}
+
+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * bits / 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			bits)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+
+struct squashfs_base_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		type:4;
+	unsigned int		offset:4;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 4);\
+	SQUASHFS_SWAP((s)->guid, d, 20, 4);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_ipc_inode_header_1));\
+	SQUASHFS_SWAP((s)->type, d, 24, 4);\
+	SQUASHFS_SWAP((s)->offset, d, 28, 4);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dev_inode_header_1));\
+	SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_1));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_reg_inode_header_1));\
+	SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dir_inode_header_1));\
+	SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 43, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
+}
+
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+
+struct squashfs_dir_index_2 {
+	unsigned int		index:27;
+	unsigned int		start_block:29;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+struct squashfs_base_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+	unsigned int		i_count:16;
+	struct squashfs_dir_index_2	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header_2 {
+	struct squashfs_base_inode_header_2	base;
+	struct squashfs_dev_inode_header_2	dev;
+	struct squashfs_symlink_inode_header_2	symlink;
+	struct squashfs_reg_inode_header_2	reg;
+	struct squashfs_dir_inode_header_2	dir;
+	struct squashfs_ldir_inode_header_2	ldir;
+	struct squashfs_ipc_inode_header_2	ipc;
+};
+	
+struct squashfs_dir_header_2 {
+	unsigned int		count:8;
+	unsigned int		start_block:24;
+} __attribute__ ((packed));
+
+struct squashfs_dir_entry_2 {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry_2 {
+	unsigned int		start_block;
+	unsigned int		size;
+} __attribute__ ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
+	SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dev_inode_header_2)); \
+	SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_2));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_reg_inode_header_2));\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
+	SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 128, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 51, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_ldir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 59, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
+	SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
+	SQUASHFS_SWAP((s)->index, d, 0, 27);\
+	SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
+	SQUASHFS_SWAP((s)->size, d, 56, 8);\
+}
+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
+	SQUASHFS_SWAP((s)->size, d, 32, 32);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES_2(A)	(A * sizeof(struct squashfs_fragment_entry_2))
+
+#define SQUASHFS_FRAGMENT_INDEX_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES_2(A)	((SQUASHFS_FRAGMENT_BYTES_2(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)	(SQUASHFS_FRAGMENT_INDEXES_2(A) *\
+						sizeof(int))
+
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing
+ * architectures
+ */
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+	/* convert from little endian to big endian */
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, b_pos)
+#else
+	/* convert from big endian to little endian */ 
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, 64 - tbits - b_pos)
+#endif
+
+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+	b_pos = pos % 8;\
+	val = 0;\
+	s = (unsigned char *)p + (pos / 8);\
+	d = ((unsigned char *) &val) + 7;\
+	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
+		*d-- = *s++;\
+	value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
+}
+
+#define SQUASHFS_MEMSET(s, d, n)	memset(s, 0, n);
+
+#endif
+#endif
diff --new-file -urp linux-2.4.32/include/linux/squashfs_fs_i.h linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_i.h
--- linux-2.4.32/include/linux/squashfs_fs_i.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_i.h	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,44 @@
+#ifndef SQUASHFS_FS_I
+#define SQUASHFS_FS_I
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs_i.h
+ */
+
+struct squashfs_inode_info {
+	long long	start_block;
+	unsigned int	offset;
+	union {
+		struct {
+			long long	fragment_start_block;
+			unsigned int	fragment_size;
+			unsigned int	fragment_offset;
+			long long	block_list_start;
+		} s1;
+		struct {
+			long long	directory_index_start;
+			unsigned int	directory_index_offset;
+			unsigned int	directory_index_count;
+			unsigned int	parent_inode;
+		} s2;
+	} u;
+};
+#endif
diff --new-file -urp linux-2.4.32/include/linux/squashfs_fs_sb.h linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_sb.h
--- linux-2.4.32/include/linux/squashfs_fs_sb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_sb.h	2006-03-07 21:12:36.000000000 +0000
@@ -0,0 +1,74 @@
+#ifndef SQUASHFS_FS_SB
+#define SQUASHFS_FS_SB
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs_sb.h
+ */
+
+#include <linux/squashfs_fs.h>
+
+struct squashfs_cache {
+	long long	block;
+	int		length;
+	long long	next_index;
+	char		*data;
+};
+
+struct squashfs_fragment_cache {
+	long long	block;
+	int		length;
+	unsigned int	locked;
+	char		*data;
+};
+
+struct squashfs_sb_info {
+	struct squashfs_super_block	sblk;
+	int			devblksize;
+	int			devblksize_log2;
+	int			swap;
+	struct squashfs_cache	*block_cache;
+	struct squashfs_fragment_cache	*fragment;
+	int			next_cache;
+	int			next_fragment;
+	int			next_meta_index;
+	unsigned int		*uid;
+	unsigned int		*guid;
+	long long		*fragment_index;
+	unsigned int		*fragment_index_2;
+	unsigned int		read_size;
+	char			*read_data;
+	char			*read_page;
+	struct semaphore	read_data_mutex;
+	struct semaphore	read_page_mutex;
+	struct semaphore	block_cache_mutex;
+	struct semaphore	fragment_mutex;
+	struct semaphore	meta_index_mutex;
+	wait_queue_head_t	waitq;
+	wait_queue_head_t	fragment_wait_queue;
+	struct meta_index	*meta_index;
+	struct inode		*(*iget)(struct super_block *s,  squashfs_inode_t \
+				inode);
+	long long		(*read_blocklist)(struct inode *inode, int \
+				index, int readahead_blks, char *block_list, \
+				unsigned short **block_p, unsigned int *bsize);
+	int			(*read_fragment_index_table)(struct super_block *s);
+};
+#endif
diff --new-file -urp linux-2.4.32/init/do_mounts.c linux-2.4.32-squashfs3.0/init/do_mounts.c
--- linux-2.4.32/init/do_mounts.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.32-squashfs3.0/init/do_mounts.c	2006-03-07 21:12:36.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/romfs_fs.h>
+#include <linux/squashfs_fs.h>
 #include <linux/cramfs_fs.h>
 
 #define BUILD_CRAMDISK
@@ -476,6 +477,7 @@ static int __init crd_load(int in_fd, in
  * 	minix
  * 	ext2
  *	romfs
+ * 	squashfs
  *	cramfs
  * 	gzip
  */
@@ -486,6 +488,7 @@ identify_ramdisk_image(int fd, int start
 	struct minix_super_block *minixsb;
 	struct ext2_super_block *ext2sb;
 	struct romfs_super_block *romfsb;
+ 	struct squashfs_super_block *squashfsb;
 	struct cramfs_super *cramfsb;
 	int nblocks = -1;
 	unsigned char *buf;
@@ -497,6 +500,7 @@ identify_ramdisk_image(int fd, int start
 	minixsb = (struct minix_super_block *) buf;
 	ext2sb = (struct ext2_super_block *) buf;
 	romfsb = (struct romfs_super_block *) buf;
+ 	squashfsb = (struct squashfs_super_block *) buf;
 	cramfsb = (struct cramfs_super *) buf;
 	memset(buf, 0xe5, size);
 
@@ -535,6 +539,15 @@ identify_ramdisk_image(int fd, int start
 		goto done;
 	}
 
+	/* squashfs is at block zero too */
+	if (squashfsb->s_magic == SQUASHFS_MAGIC) {
+		printk(KERN_NOTICE
+		       "RAMDISK: squashfs filesystem found at block %d\n",
+		       start_block);
+		nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
+		goto done;
+	}
+
 	/*
 	 * Read block 1 to test for minix and ext2 superblock
 	 */
diff --new-file -urp linux-2.4.32/lib/Config.in linux-2.4.32-squashfs3.0/lib/Config.in
--- linux-2.4.32/lib/Config.in	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.32-squashfs3.0/lib/Config.in	2006-03-07 21:12:36.000000000 +0000
@@ -10,6 +10,7 @@ tristate 'CRC32 functions' CONFIG_CRC32
 # Do we need the compression support?
 #
 if [ "$CONFIG_CRAMFS" = "y" -o \
+     "$CONFIG_SQUASHFS" = "y" -o \
      "$CONFIG_PPP_DEFLATE" = "y" -o \
      "$CONFIG_CRYPTO_DEFLATE" = "y" -o \
      "$CONFIG_JFFS2_FS" = "y" -o \
@@ -17,6 +18,7 @@ if [ "$CONFIG_CRAMFS" = "y" -o \
    define_tristate CONFIG_ZLIB_INFLATE y
 else
   if [ "$CONFIG_CRAMFS" = "m" -o \
+       "$CONFIG_SQUASHFS" = "m" -o \
        "$CONFIG_PPP_DEFLATE" = "m" -o \
        "$CONFIG_CRYPTO_DEFLATE" = "m" -o \
        "$CONFIG_JFFS2_FS" = "m" -o \
diff -ruN linux-2.4.20-nc/scripts/squashfs/global.h linux/scripts/squashfs/global.h
--- linux-2.4.20-nc/scripts/squashfs/global.h	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/global.h	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,46 @@
+#ifndef GLOBAL_H 
+#define GLOBAL_H
+
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * global.h
+ */
+
+typedef struct squashfs_super_block squashfs_super_block;
+typedef struct squashfs_dir_index squashfs_dir_index;
+typedef struct squashfs_base_inode_header squashfs_base_inode_header;
+typedef struct squashfs_ipc_inode_header squashfs_ipc_inode_header;
+typedef struct squashfs_dev_inode_header squashfs_dev_inode_header;
+typedef struct squashfs_symlink_inode_header squashfs_symlink_inode_header;
+typedef struct squashfs_reg_inode_header squashfs_reg_inode_header;
+typedef struct squashfs_lreg_inode_header squashfs_lreg_inode_header;
+typedef struct squashfs_dir_inode_header squashfs_dir_inode_header;
+typedef struct squashfs_ldir_inode_header squashfs_ldir_inode_header;
+typedef struct squashfs_dir_entry squashfs_dir_entry;
+typedef struct squashfs_dir_header squashfs_dir_header;
+typedef struct squashfs_fragment_entry squashfs_fragment_entry;
+
+typedef union squashfs_inode_header squashfs_inode_header;
+typedef unsigned int squashfs_uid;
+typedef long long squashfs_fragment_index;
+typedef squashfs_inode_t squashfs_inode;
+typedef squashfs_block_t squashfs_block;
+#endif
diff -ruN linux-2.4.20-nc/scripts/squashfs/Makefile linux/scripts/squashfs/Makefile
--- linux-2.4.20-nc/scripts/squashfs/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/Makefile	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,19 @@
+INCLUDEDIR = .
+
+CFLAGS := -I$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -O2
+
+all: mksquashfs unsquashfs
+
+mksquashfs: mksquashfs.o read_fs.o sort.o
+	$(CC) mksquashfs.o read_fs.o sort.o -lz -o $@
+
+mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h
+
+read_fs.o: read_fs.c squashfs_fs.h read_fs.h global.h
+
+sort.o: sort.c squashfs_fs.h global.h sort.h
+
+unsquashfs: unsquashfs.o
+	$(CC) unsquashfs.o -lz -o $@
+
+unsquashfs.o: unsquashfs.c squashfs_fs.h read_fs.h global.h
diff -ruN linux-2.4.20-nc/scripts/squashfs/mksquashfs.c linux/scripts/squashfs/mksquashfs.c
--- linux-2.4.20-nc/scripts/squashfs/mksquashfs.c	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/mksquashfs.c	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,2298 @@
+/*
+ * Create a squashfs filesystem.  This is a highly compressed read only filesystem.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * mksquashfs.c
+ */
+
+#define FALSE 0
+#define TRUE 1
+
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <string.h>
+#include <zlib.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/mman.h>
+
+#ifndef linux
+#define __BYTE_ORDER BYTE_ORDER
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#else
+#include <endian.h>
+#endif
+
+#include <squashfs_fs.h>
+#include "mksquashfs.h"
+#include "global.h"
+#include "sort.h"
+
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...)	do { \
+					printf("mksquashfs: "s, ## args); \
+				} while(0)
+#else
+#define TRACE(s, args...)
+#endif
+
+#define INFO(s, args...)	do {\
+					 if(!silent)\
+						printf("mksquashfs: "s, ## args);\
+				} while(0)
+#define ERROR(s, args...)	do {\
+					fprintf(stderr, s, ## args);\
+				} while(0)
+#define EXIT_MKSQUASHFS()	do {\
+					if(restore)\
+						restorefs();\
+					if(delete && destination_file && !block_device)\
+						unlink(destination_file);\
+					exit(1);\
+				} while(0)
+#define BAD_ERROR(s, args...)	do {\
+					fprintf(stderr, "FATAL ERROR:" s, ##args);\
+					EXIT_MKSQUASHFS();\
+				} while(0)
+
+int delete = FALSE;
+long long total_compressed = 0, total_uncompressed = 0;
+int fd;
+
+/* filesystem flags for building */
+int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
+int noI = 0, noD = 0, check_data = 0;
+int swap, silent = TRUE;
+long long global_uid = -1, global_gid = -1;
+
+/* superblock attributes */
+int block_size = SQUASHFS_FILE_SIZE, block_log;
+unsigned short uid_count = 0, guid_count = 0;
+squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS];
+int block_offset;
+int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0;
+
+/* write position within data section */
+long long bytes = 0, total_bytes = 0;
+
+/* in memory directory table - possibly compressed */
+char *directory_table = NULL;
+unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
+
+/* cached directory table */
+char *directory_data_cache = NULL;
+unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
+
+/* in memory inode table - possibly compressed */
+char *inode_table = NULL;
+unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
+
+/* cached inode table */
+char *data_cache = NULL;
+unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
+
+/* in memory directory data */
+#define I_COUNT_SIZE		128
+#define DIR_ENTRIES		32
+#define INODE_HASH_SIZE		65536
+#define INODE_HASH_MASK		(INODE_HASH_SIZE - 1)
+#define INODE_HASH(dev, ino)	(ino & INODE_HASH_MASK)
+
+struct cached_dir_index {
+	squashfs_dir_index	index;
+	char			*name;
+};
+
+struct directory {
+	unsigned int		start_block;
+	unsigned int		size;
+	unsigned char		*buff;
+	unsigned char		*p;
+	unsigned int		entry_count;
+	unsigned char		*entry_count_p;
+	unsigned int		i_count;
+	unsigned int		i_size;
+	struct cached_dir_index	*index;
+	unsigned char		*index_count_p;
+	unsigned int		inode_number;
+};
+
+struct inode_info *inode_info[INODE_HASH_SIZE];
+
+/* hash tables used to do fast duplicate searches in duplicate check */
+struct file_info *dupl[65536], *frag_dups[65536];
+int dup_files = 0;
+
+/* list of exclude dirs/files */
+struct exclude_info {
+	dev_t			st_dev;
+	ino_t			st_ino;
+};
+
+#define EXCLUDE_SIZE 8192
+int exclude = 0;
+struct exclude_info *exclude_paths = NULL;
+int excluded(char *filename, struct stat *buf);
+
+/* fragment block data structures */
+int fragments = 0;
+char fragment_data[SQUASHFS_FILE_SIZE];
+int fragment_size = 0;
+struct fragment {
+	unsigned int		index;
+	int			offset;
+	int			size;
+};
+#define FRAG_SIZE 32768
+squashfs_fragment_entry *fragment_table = NULL;
+
+
+/* current inode number for directories and non directories */
+unsigned int dir_inode_no = 1;
+unsigned int inode_no = 0;
+unsigned int root_inode_number = 0;
+
+/* list of source dirs/files */
+int source = 0;
+char **source_path;
+
+/* list of root directory entries read from original filesystem */
+int old_root_entries = 0;
+struct old_root_entry_info {
+	char			name[SQUASHFS_NAME_LEN + 1];
+	squashfs_inode		inode;
+	int			type;
+	int			inode_number;
+};
+struct old_root_entry_info *old_root_entry;
+
+/* in memory file info */
+struct file_info {
+	long long		bytes;
+	unsigned short		checksum;
+	long long		start;
+	unsigned int		*block_list;
+	struct file_info	*next;
+	struct fragment		*fragment;
+	unsigned short		fragment_checksum;
+};
+
+/* count of how many times SIGINT or SIGQUIT has been sent */
+int interrupted = 0;
+
+/* restore orignal filesystem state if appending to existing filesystem is cancelled */
+jmp_buf env;
+char *sdata_cache, *sdirectory_data_cache;
+
+long long sbytes, stotal_bytes;
+
+unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
+	sdirectory_cache_bytes, suid_count, sguid_count,
+	stotal_inode_bytes, stotal_directory_bytes,
+	sinode_count, sfile_count, ssym_count, sdev_count,
+	sdir_count, sfifo_count, ssock_count, sdup_files;
+int sfragments;
+int restore = 0;
+
+/* flag whether destination file is a block device */
+int block_device = 0;
+
+/* flag indicating whether files are sorted using sort list(s) */
+int sorted = 0;
+
+/* save destination file name for deleting on error */
+char *destination_file = NULL;
+
+/* structure to used to pass in a pointer or an integer
+ * to duplicate buffer read helper functions.
+ */
+struct duplicate_buffer_handle {
+	char	*ptr;
+	long long	start;
+};
+
+void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type);
+extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source);
+extern long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
+		char **data_cache, char **cdirectory_table, char **directory_data_cache,
+		unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
+		unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
+		int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
+		unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
+		long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
+		unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
+		void (push_directory_entry)(char *, squashfs_inode, int, int),
+		squashfs_fragment_entry **fragment_table);
+int get_sorted_inode(squashfs_inode *inode, struct stat *buf);
+int read_sort_file(char *filename, int source, char *source_path[]);
+void sort_files_and_write(struct dir_info *dir);
+struct file_info *duplicate(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, long long bytes, unsigned int **block_list, long long *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes);
+struct dir_info *dir_scan1(char *, int (_readdir)(char *, char *, struct dir_info *));
+
+#define MKINODE(A)	((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache)))
+
+
+void restorefs()
+{
+	ERROR("Exiting - restoring original filesystem!\n\n");
+	bytes = sbytes;
+	memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
+	memcpy(directory_data_cache, sdirectory_data_cache, directory_cache_bytes = sdirectory_cache_bytes);
+	inode_bytes = sinode_bytes;
+	directory_bytes = sdirectory_bytes;
+	uid_count = suid_count;
+	guid_count = sguid_count;
+	total_bytes = stotal_bytes;
+	total_inode_bytes = stotal_inode_bytes;
+	total_directory_bytes = stotal_directory_bytes;
+	inode_count = sinode_count;
+	file_count = sfile_count;
+	sym_count = ssym_count;
+	dev_count = sdev_count;
+	dir_count = sdir_count;
+	fifo_count = sfifo_count;
+	sock_count = ssock_count;
+	dup_files = sdup_files;
+	fragments = sfragments;
+	fragment_size = 0;
+	longjmp(env, 1);
+}
+
+
+void sighandler()
+{
+	if(interrupted == 1)
+		restorefs();
+	else {
+		ERROR("Interrupting will restore original filesystem!\n");
+		ERROR("Interrupt again to quit\n");
+		interrupted ++;
+	}
+}
+
+
+void sighandler2()
+{
+	EXIT_MKSQUASHFS();
+}
+
+
+unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block)
+{
+	unsigned long c_byte = block_size << 1;
+	unsigned int res;
+
+	if(!uncompressed && (res = compress2((unsigned char *) d, &c_byte, (unsigned char *) s, size, 9)) != Z_OK) {
+		if(res == Z_MEM_ERROR)
+			BAD_ERROR("zlib::compress failed, not enough memory\n");
+		else if(res == Z_BUF_ERROR)
+			BAD_ERROR("zlib::compress failed, not enough room in output buffer\n");
+		else
+			BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
+		return 0;
+	}
+
+	if(uncompressed || c_byte >= size) {
+		memcpy(d, s, size);
+		return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT);
+	}
+
+	return (unsigned int) c_byte;
+}
+
+
+squashfs_base_inode_header *get_inode(int req_size)
+{
+	int data_space;
+	unsigned short c_byte;
+
+	while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
+		if((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
+			if((inode_table = (char *) realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2))
+					== NULL) {
+				goto failed;
+			}
+			inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
+		}
+
+		c_byte = mangle(inode_table + inode_bytes + block_offset, data_cache,
+								SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
+		TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte);
+		if(!swap)
+			memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
+		else
+			SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
+		if(check_data)
+			*((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
+		inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
+		total_inode_bytes += SQUASHFS_METADATA_SIZE + block_offset;
+		memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE);
+		cache_bytes -= SQUASHFS_METADATA_SIZE;
+	}
+
+	data_space = (cache_size - cache_bytes);
+	if(data_space < req_size) {
+			int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space;
+
+			if((data_cache = (char *) realloc(data_cache, cache_size + realloc_size)) == NULL) {
+				goto failed;
+			}
+			cache_size += realloc_size;
+	}
+
+	cache_bytes += req_size;
+
+	return (squashfs_base_inode_header *)(data_cache + (cache_bytes - req_size));
+
+failed:
+	BAD_ERROR("Out of memory in inode table reallocation!\n");
+}
+
+
+void read_bytes(int fd, long long byte, int bytes, char *buff)
+{
+	off_t off = byte;
+
+	if(lseek(fd, off, SEEK_SET) == -1) {
+		perror("Lseek on destination failed");
+		EXIT_MKSQUASHFS();
+	}
+
+	if(read(fd, buff, bytes) == -1) {
+		perror("Read on destination failed");
+		EXIT_MKSQUASHFS();
+	}
+}
+
+
+void write_bytes(int fd, long long byte, int bytes, char *buff)
+{
+	off_t off = byte;
+
+	if(lseek(fd, off, SEEK_SET) == -1) {
+		perror("Lseek on destination failed");
+		EXIT_MKSQUASHFS();
+	}
+
+	if(write(fd, buff, bytes) == -1) {
+		perror("Write on destination failed");
+		EXIT_MKSQUASHFS();
+	}
+}
+
+
+long long write_inodes()
+{
+	unsigned short c_byte;
+	int avail_bytes;
+	char *datap = data_cache;
+	long long start_bytes = bytes;
+
+	while(cache_bytes) {
+		if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
+			if((inode_table = (char *) realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
+				BAD_ERROR("Out of memory in inode table reallocation!\n");
+			}
+			inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
+		}
+		avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes;
+		c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
+		TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte);
+		if(!swap)
+			memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
+		else
+			SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1); 
+		if(check_data)
+			*((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
+		inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
+		total_inode_bytes += avail_bytes + block_offset;
+		datap += avail_bytes;
+		cache_bytes -= avail_bytes;
+	}
+
+	write_bytes(fd, bytes, inode_bytes, (char *) inode_table);
+	bytes += inode_bytes;
+
+	return start_bytes;
+}
+
+
+long long write_directories()
+{
+	unsigned short c_byte;
+	int avail_bytes;
+	char *directoryp = directory_data_cache;
+	long long start_bytes = bytes;
+
+	while(directory_cache_bytes) {
+		if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
+			if((directory_table = (char *) realloc(directory_table, directory_size +
+					((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
+				BAD_ERROR("Out of memory in directory table reallocation!\n");
+			}
+			directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
+		}
+		avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes;
+		c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
+		TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte);
+		if(!swap)
+			memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
+		else
+			SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
+		if(check_data)
+			*((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
+		directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
+		total_directory_bytes += avail_bytes + block_offset;
+		directoryp += avail_bytes;
+		directory_cache_bytes -= avail_bytes;
+	}
+	write_bytes(fd, bytes, directory_bytes, (char *) directory_table);
+	bytes += directory_bytes;
+
+	return start_bytes;
+}
+
+
+unsigned int get_uid(squashfs_uid uid)
+{
+	int i;
+
+	for(i = 0; (i < uid_count) && uids[i] != uid; i++);
+	if(i == uid_count) {
+		if(uid_count == SQUASHFS_UIDS) {
+			ERROR("Out of uids! - using uid 0 - probably not what's wanted!\n");
+			i = 0;
+		} else
+			uids[uid_count++] = uid;
+	}
+
+	return i;
+}
+
+
+unsigned int get_guid(squashfs_uid uid, squashfs_uid guid)
+{
+	int i;
+
+	if(uid == guid)
+		return SQUASHFS_GUIDS;
+
+	for(i = 0; (i < guid_count) && guids[i] != guid; i++);
+	if(i == guid_count) {
+		if(guid_count == SQUASHFS_GUIDS) {
+			ERROR("Out of gids! - using gid 0 - probably not what's wanted!\n");
+			return SQUASHFS_GUIDS;
+		} else
+			guids[guid_count++] = guid;
+	}
+
+	return i;
+}
+
+
+int create_inode(squashfs_inode *i_no, struct dir_ent *dir_ent, int type, long long byte_size, long long start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment, struct directory *dir_in)
+{
+	struct stat *buf = &dir_ent->inode->buf;
+	squashfs_inode_header inode_header;
+	squashfs_base_inode_header *inode, *base = &inode_header.base;
+	char *filename = dir_ent->pathname;
+	int nlink = dir_ent->inode->nlink;
+	int inode_number = (type == SQUASHFS_LDIR_TYPE || type == SQUASHFS_DIR_TYPE) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
+
+	base->mode = SQUASHFS_MODE(buf->st_mode);
+	base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid);
+	base->inode_type = type;
+	base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf->st_gid : global_gid);
+	base->mtime = buf->st_mtime;
+	base->inode_number = inode_number;
+
+	if(type == SQUASHFS_FILE_TYPE) {
+		int i;
+		squashfs_reg_inode_header *reg = &inode_header.reg, *inodep;
+
+		inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
+		inodep = (squashfs_reg_inode_header *) inode;
+		reg->file_size = byte_size;
+		reg->start_block = start_block;
+		reg->fragment = fragment->index;
+		reg->offset = fragment->offset;
+		if(!swap) {
+			memcpy(inodep, reg, sizeof(*reg));
+			memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
+		} else {
+			SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep);
+			SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
+		}
+		TRACE("File inode, file_size %d, start_block %llx, blocks %d, fragment %d, offset %d, size %d\n", (int) byte_size,
+			start_block, offset, fragment->index, fragment->offset, fragment->size);
+		for(i = 0; i < offset; i++)
+			TRACE("Block %d, size %d\n", i, block_list[i]);
+	}
+	else if(type == SQUASHFS_LREG_TYPE) {
+		int i;
+		squashfs_lreg_inode_header *reg = &inode_header.lreg, *inodep;
+
+		inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
+		inodep = (squashfs_lreg_inode_header *) inode;
+		reg->nlink = nlink;
+		reg->file_size = byte_size;
+		reg->start_block = start_block;
+		reg->fragment = fragment->index;
+		reg->offset = fragment->offset;
+		if(!swap) {
+			memcpy(inodep, reg, sizeof(*reg));
+			memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
+		} else {
+			SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inodep);
+			SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
+		}
+		TRACE("Long file inode, file_size %lld, start_block %llx, blocks %d, fragment %d, offset %d, size %d, nlink %d\n", byte_size,
+			start_block, offset, fragment->index, fragment->offset, fragment->size, nlink);
+		for(i = 0; i < offset; i++)
+			TRACE("Block %d, size %d\n", i, block_list[i]);
+	}
+	else if(type == SQUASHFS_LDIR_TYPE) {
+		int i;
+		unsigned char *p;
+		squashfs_ldir_inode_header *dir = &inode_header.ldir, *inodep;
+		struct cached_dir_index *index = dir_in->index;
+		unsigned int i_count = dir_in->i_count;
+		unsigned int i_size = dir_in->i_size;
+
+		if(byte_size >= 1 << 27)
+			BAD_ERROR("directory greater than 2^27-1 bytes!\n");
+
+		inode = get_inode(sizeof(*dir) + i_size);
+		inodep = (squashfs_ldir_inode_header *) inode;
+		dir->inode_type = SQUASHFS_LDIR_TYPE;
+		dir->nlink = dir_ent->dir->directory_count + 2;
+		dir->file_size = byte_size;
+		dir->offset = offset;
+		dir->start_block = start_block;
+		dir->i_count = i_count;
+		dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
+
+		if(!swap)
+			memcpy(inode, dir, sizeof(*dir));
+		else
+			SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
+		p = (unsigned char *) inodep->index;
+		for(i = 0; i < i_count; i++) {
+			if(!swap)
+				memcpy(p, &index[i].index, sizeof(squashfs_dir_index));
+			else
+				SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
+			memcpy(((squashfs_dir_index *)p)->name, index[i].name, index[i].index.size + 1);
+			p += sizeof(squashfs_dir_index) + index[i].index.size + 1;
+		}
+		TRACE("Long directory inode, file_size %d, start_block %llx, offset %x, nlink %d\n", (int) byte_size,
+			start_block, offset, dir_ent->dir->directory_count + 2);
+	}
+	else if(type == SQUASHFS_DIR_TYPE) {
+		squashfs_dir_inode_header *dir = &inode_header.dir;
+
+		inode = get_inode(sizeof(*dir));
+		dir->nlink = dir_ent->dir->directory_count + 2;
+		dir->file_size = byte_size;
+		dir->offset = offset;
+		dir->start_block = start_block;
+		dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
+		if(!swap)
+			memcpy(inode, dir, sizeof(*dir));
+		else
+			SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
+		TRACE("Directory inode, file_size %d, start_block %llx, offset %x, nlink %d\n", (int) byte_size,
+			start_block, offset, dir_ent->dir->directory_count + 2);
+	}
+	else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
+		squashfs_dev_inode_header *dev = &inode_header.dev;
+
+		inode = get_inode(sizeof(*dev));
+		dev->nlink = nlink;
+		dev->rdev = (unsigned short) ((major(buf->st_rdev) << 8) |
+			(minor(buf->st_rdev) & 0xff));
+		if(!swap)
+			memcpy(inode, dev, sizeof(*dev));
+		else
+			SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
+		TRACE("Device inode, rdev %x, nlink %d\n", dev->rdev, nlink);
+	}
+	else if(type == SQUASHFS_SYMLINK_TYPE) {
+		squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep;
+		int byte;
+		char buff[65536];
+
+		if((byte = readlink(filename, buff, 65536)) == -1) {
+			perror("Error in reading symbolic link, skipping...");
+			return FALSE;
+		}
+
+		if(byte == 65536) {
+			ERROR("Symlink is greater than 65536 bytes! skipping...");
+			return FALSE;
+		}
+
+		inode = get_inode(sizeof(*symlink) + byte);
+		symlink->nlink = nlink;
+		inodep = (squashfs_symlink_inode_header *) inode;
+		symlink->symlink_size = byte;
+		if(!swap)
+			memcpy(inode, symlink, sizeof(*symlink));
+		else
+			SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
+		strncpy(inodep->symlink, buff, byte);
+		TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink);
+	}
+	else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
+		squashfs_ipc_inode_header *ipc = &inode_header.ipc;
+
+		inode = get_inode(sizeof(*ipc));
+		ipc->nlink = nlink;
+		if(!swap)
+			memcpy(inode, ipc, sizeof(*ipc));
+		else
+			SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
+		TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
+	} else
+		return FALSE;
+
+	*i_no = MKINODE(inode);
+	inode_count ++;
+
+	TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid);
+
+	return TRUE;
+}
+
+
+void scan2_init_dir(struct directory *dir)
+{
+	if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
+		BAD_ERROR("Out of memory allocating directory buffer\n");
+	}
+
+	dir->size = SQUASHFS_METADATA_SIZE;
+	dir->p = dir->index_count_p = dir->buff;
+	dir->entry_count = 256;
+	dir->entry_count_p = NULL;
+	dir->index = NULL;
+	dir->i_count = dir->i_size = 0;
+}
+
+
+void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir)
+{
+	unsigned char *buff;
+	squashfs_dir_entry idir, *idirp;
+	unsigned int start_block = inode >> 16;
+	unsigned int offset = inode & 0xffff;
+	unsigned int size;
+
+	if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
+		size = SQUASHFS_NAME_LEN;
+		ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN);
+	}
+
+	if(dir->p + sizeof(squashfs_dir_entry) + size + sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
+		if((buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL)  {
+			BAD_ERROR("Out of memory reallocating directory buffer\n");
+		}
+
+		dir->p = (dir->p - dir->buff) + buff;
+		if(dir->entry_count_p) 
+			dir->entry_count_p = (dir->entry_count_p - dir->buff + buff);
+		dir->index_count_p = dir->index_count_p - dir->buff + buff;
+		dir->buff = buff;
+	}
+
+	if(dir->entry_count == 256 || start_block != dir->start_block || ((dir->entry_count_p != NULL) && ((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || ((long long) inode_number - dir->inode_number) > 32767 || ((long long) inode_number - dir->inode_number) < - 32768) {
+		if(dir->entry_count_p) {
+			squashfs_dir_header dir_header;
+
+			if((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) {
+				if(dir->i_count % I_COUNT_SIZE == 0)
+					if((dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index))) == NULL)
+						BAD_ERROR("Out of memory in directory index table reallocation!\n");
+				dir->index[dir->i_count].index.index = dir->p - dir->buff;
+				dir->index[dir->i_count].index.size = size - 1;
+				dir->index[dir->i_count++].name = name;
+				dir->i_size += sizeof(squashfs_dir_index) + size;
+				dir->index_count_p = dir->p;
+			}
+
+			dir_header.count = dir->entry_count - 1;
+			dir_header.start_block = dir->start_block;
+			dir_header.inode_number = dir->inode_number;
+			if(!swap)
+				memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
+			else
+				SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
+
+		}
+
+
+		dir->entry_count_p = dir->p;
+		dir->start_block = start_block;
+		dir->entry_count = 0;
+		dir->inode_number = inode_number;
+		dir->p += sizeof(squashfs_dir_header);
+	}
+
+	idirp = (squashfs_dir_entry *) dir->p;
+	idir.offset = offset;
+	idir.type = type;
+	idir.size = size - 1;
+	idir.inode_number = ((long long) inode_number - dir->inode_number);
+	if(!swap)
+		memcpy(idirp, &idir, sizeof(idir));
+	else
+		SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp);
+	strncpy(idirp->name, name, size);
+	dir->p += sizeof(squashfs_dir_entry) + size;
+	dir->entry_count ++;
+}
+
+
+int write_dir(squashfs_inode *inode, struct dir_info *dir_info, struct directory *dir)
+{
+	unsigned int dir_size = dir->p - dir->buff;
+	int data_space = (directory_cache_size - directory_cache_bytes);
+	unsigned int directory_block, directory_offset, i_count, index;
+	unsigned short c_byte;
+
+	if(data_space < dir_size) {
+		int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
+
+		if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) {
+			goto failed;
+		}
+		directory_cache_size += realloc_size;
+	}
+
+	if(dir_size) {
+		squashfs_dir_header dir_header;
+
+		dir_header.count = dir->entry_count - 1;
+		dir_header.start_block = dir->start_block;
+		dir_header.inode_number = dir->inode_number;
+		if(!swap)
+			memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
+		else
+			SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
+		memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size);
+	}
+	directory_offset = directory_cache_bytes;
+	directory_block = directory_bytes;
+	directory_cache_bytes += dir_size;
+	i_count = 0;
+	index = SQUASHFS_METADATA_SIZE - directory_offset;
+
+	while(1) {
+		while(i_count < dir->i_count && dir->index[i_count].index.index < index)
+			dir->index[i_count++].index.start_block = directory_bytes;
+		index += SQUASHFS_METADATA_SIZE;
+
+		if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
+			break;
+
+		if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
+			if((directory_table = (char *) realloc(directory_table,
+							directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) {
+				goto failed;
+			}
+			directory_size += SQUASHFS_METADATA_SIZE << 1;
+		}
+
+		c_byte = mangle(directory_table + directory_bytes + block_offset, directory_data_cache,
+				SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
+		TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte);
+		if(!swap)
+			memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
+		else
+			SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
+		if(check_data)
+			*((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
+		directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
+		total_directory_bytes += SQUASHFS_METADATA_SIZE + block_offset;
+		memcpy(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE);
+		directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
+	}
+
+	if(dir_info->dir_is_ldir) {
+		if(create_inode(inode, dir_info->dir_ent, SQUASHFS_LDIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir) == FALSE)
+			return FALSE;
+	} else {
+		if(create_inode(inode, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, NULL) == FALSE)
+			return FALSE;
+	}
+
+#ifdef SQUASHFS_TRACE
+	if(!swap) {
+		unsigned char *dirp;
+		int count;
+
+		TRACE("Directory contents of inode 0x%llx\n", *inode);
+		dirp = dir->buff;
+		while(dirp < dir->p) {
+			char buffer[SQUASHFS_NAME_LEN + 1];
+			squashfs_dir_entry idir, *idirp;
+			squashfs_dir_header *dirh = (squashfs_dir_header *) dirp;
+			count = dirh->count + 1;
+			dirp += sizeof(squashfs_dir_header);
+
+			TRACE("\tStart block 0x%x, count %d\n", dirh->start_block, count);
+
+			while(count--) {
+				idirp = (squashfs_dir_entry *) dirp;
+				memcpy((char *) &idir, (char *) idirp, sizeof(idir));
+				strncpy(buffer, idirp->name, idir.size + 1);
+				buffer[idir.size + 1] = '\0';
+				TRACE("\t\tname %s, inode offset 0x%x, type %d\n", buffer,
+						  idir.offset, idir.type);
+				dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
+			}
+		}
+	}
+#endif
+	dir_count ++;
+
+	return TRUE;
+
+failed:
+	BAD_ERROR("Out of memory in directory table reallocation!\n");
+}
+
+
+char *get_fragment(char *buffer, struct fragment *fragment)
+{
+	squashfs_fragment_entry *disk_fragment = &fragment_table[fragment->index];
+	int size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
+
+	if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
+		int res;
+		unsigned long bytes = block_size;
+		char cbuffer[block_size];
+
+		read_bytes(fd, disk_fragment->start_block, size, cbuffer);
+
+		if((res = uncompress((unsigned char *) buffer, &bytes, (const unsigned char *) cbuffer, size)) != Z_OK) {
+			if(res == Z_MEM_ERROR)
+				BAD_ERROR("zlib::uncompress failed, not enough memory\n");
+			else if(res == Z_BUF_ERROR)
+				BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n");
+			else
+				BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res);
+		}
+	} else
+		read_bytes(fd, disk_fragment->start_block, size, buffer);
+
+	return buffer + fragment->offset;
+}
+
+	
+void write_fragment()
+{
+	int compressed_size;
+	char buffer[block_size << 1];
+
+	if(fragment_size == 0)
+		return;
+
+	if(fragments % FRAG_SIZE == 0)
+		if((fragment_table = (squashfs_fragment_entry *) realloc(fragment_table, (fragments + FRAG_SIZE) * sizeof(squashfs_fragment_entry))) == NULL)
+			BAD_ERROR("Out of memory in fragment table\n");
+	fragment_table[fragments].size = mangle(buffer, fragment_data, fragment_size, block_size, noF, 1);
+	fragment_table[fragments].start_block = bytes;
+	compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[fragments].size);
+	write_bytes(fd, bytes, compressed_size, buffer);
+	bytes += compressed_size;
+	total_uncompressed += fragment_size;
+	total_compressed += compressed_size;
+	TRACE("Writing fragment %d, uncompressed size %d, compressed size %d\n",fragments, fragment_size, compressed_size);
+	fragments ++;
+	fragment_size = 0;
+}
+
+
+static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
+struct fragment *get_and_fill_fragment(char *buff, int size)
+{
+	struct fragment *ffrg;
+
+	if(size == 0)
+		return &empty_fragment;
+
+	if(fragment_size + size > block_size)
+		write_fragment();
+
+	if((ffrg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
+		BAD_ERROR("Out of memory in fragment block allocation!\n");
+
+	ffrg->index = fragments;
+	ffrg->offset = fragment_size;
+	ffrg->size = size;
+	memcpy(fragment_data + fragment_size, buff, size);
+	fragment_size += size;
+
+	return ffrg;
+}
+
+
+long long write_fragment_table()
+{
+	long long start_bytes;
+	unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments),
+		meta_blocks = SQUASHFS_FRAGMENT_INDEXES(fragments);
+	char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2], buffer[frag_bytes];
+	squashfs_fragment_entry *p = (squashfs_fragment_entry *) buffer;
+	unsigned short c_byte;
+	int i, compressed_size;
+	squashfs_fragment_index list[meta_blocks];
+
+	TRACE("write_fragment_table: fragments %d, frag_bytes %d, meta_blocks %d\n", fragments, frag_bytes, meta_blocks);
+	for(i = 0; i < fragments; i++, p++) {
+		TRACE("write_fragment_table: fragment %d, start_block %llx, size %d\n", i, fragment_table[i].start_block, fragment_table[i].size);
+		if(!swap)
+			memcpy(p, &fragment_table[i], sizeof(squashfs_fragment_entry));
+		else
+			SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p);
+	}
+
+	for(i = 0; i < meta_blocks; i++) {
+		int avail_bytes = i == meta_blocks - 1 ? frag_bytes % SQUASHFS_METADATA_SIZE : SQUASHFS_METADATA_SIZE;
+		c_byte = mangle(cbuffer + block_offset, buffer + i * SQUASHFS_METADATA_SIZE , avail_bytes, SQUASHFS_METADATA_SIZE, noF, 0);
+		if(!swap)
+			memcpy(cbuffer, &c_byte, sizeof(unsigned short));
+		else
+			SQUASHFS_SWAP_SHORTS((&c_byte), cbuffer, 1);
+		if(check_data)
+			*((unsigned char *)(cbuffer + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
+		list[i] = bytes;
+		compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
+		write_bytes(fd, bytes, compressed_size, cbuffer);
+		bytes += compressed_size;
+	}
+
+	if(!swap)
+		write_bytes(fd, bytes, sizeof(list), (char *) list);
+	else {
+		squashfs_fragment_index slist[meta_blocks];
+		SQUASHFS_SWAP_FRAGMENT_INDEXES(list, slist, meta_blocks);
+		write_bytes(fd, bytes, sizeof(list), (char *) slist);
+	}
+
+	start_bytes = bytes;
+	bytes += sizeof(list);
+
+	return start_bytes;
+}
+
+
+char *read_from_buffer(struct duplicate_buffer_handle *handle, unsigned int avail_bytes)
+{
+	char *v = handle->ptr;
+	handle->ptr += avail_bytes;	
+	return v;
+}
+
+
+char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
+char *read_from_file(struct duplicate_buffer_handle *handle, unsigned int avail_bytes)
+{
+	read_bytes(fd, handle->start, avail_bytes, read_from_file_buffer);
+	handle->start += avail_bytes;
+	return read_from_file_buffer;
+}
+
+
+/*
+ * Compute 16 bit BSD checksum over the data
+ */
+unsigned short get_checksum(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *handle, long long l)
+{
+	unsigned short chksum = 0;
+	unsigned int bytes = 0;
+	unsigned char *b;
+	struct duplicate_buffer_handle position = *handle;
+
+	while(l) {
+		bytes = l > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : l;
+		l -= bytes;
+		b = (unsigned char *) get_next_file_block(&position, bytes);
+		while(bytes--) {
+			chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
+			chksum += *b++;
+		}
+	}
+
+	return chksum;
+}
+
+
+int cached_frag = -1;
+void add_file(long long start, long long file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes)
+{
+	struct fragment *frg;
+	struct file_info *dupl_ptr;
+	char *datap;
+	struct duplicate_buffer_handle handle;
+	unsigned int *block_list = block_listp;
+
+	if(!duplicate_checking)
+		return;
+
+	if((frg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
+		BAD_ERROR("Out of memory in fragment block allocation!\n");
+
+	frg->index = fragment;
+	frg->offset = offset;
+	frg->size = bytes;
+	if(fragment == cached_frag || fragment == SQUASHFS_INVALID_FRAG)
+		datap = fragment_data + offset;
+	else
+		datap = get_fragment(fragment_data, frg);
+	handle.start = start;
+	if((dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &frg, datap, bytes)) != NULL)
+		dupl_ptr->fragment = frg;
+	else
+		free(block_list);
+	cached_frag = fragment;
+}
+
+
+char cached_fragment[SQUASHFS_FILE_SIZE];
+int cached_frag1 = -1;
+
+struct file_info *duplicate(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, long long bytes, unsigned int **block_list, long long *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes)
+{
+	unsigned short checksum = get_checksum(get_next_file_block, file_start, bytes);
+	struct duplicate_buffer_handle handle = { frag_data, 0 };
+	unsigned short fragment_checksum = get_checksum(read_from_buffer, &handle, frag_bytes);
+	struct file_info *dupl_ptr = bytes ? dupl[checksum] : frag_dups[fragment_checksum];
+
+
+	for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
+		if(bytes == dupl_ptr->bytes && frag_bytes == dupl_ptr->fragment->size && fragment_checksum == dupl_ptr->fragment_checksum) {
+			char buffer1[SQUASHFS_FILE_MAX_SIZE];
+			long long dup_bytes = dupl_ptr->bytes;
+			long long dup_start = dupl_ptr->start;
+			struct duplicate_buffer_handle position = *file_start;
+			char *buffer;
+			while(dup_bytes) {
+				int avail_bytes = dup_bytes > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : dup_bytes;
+
+				buffer = get_next_file_block(&position, avail_bytes);
+				read_bytes(fd, dup_start, avail_bytes, buffer1);
+				if(memcmp(buffer, buffer1, avail_bytes) != 0)
+					break;
+				dup_bytes -= avail_bytes;
+				dup_start += avail_bytes;
+			}
+			if(dup_bytes == 0) {
+				char *fragment_buffer1;
+				
+				if(dupl_ptr->fragment->index == fragments || dupl_ptr->fragment->index == SQUASHFS_INVALID_FRAG)
+					fragment_buffer1 = fragment_data + dupl_ptr->fragment->offset;
+				else if(dupl_ptr->fragment->index == cached_frag1)
+					fragment_buffer1 = cached_fragment + dupl_ptr->fragment->offset;
+				else {
+					fragment_buffer1 = get_fragment(cached_fragment, dupl_ptr->fragment);
+					cached_frag1 = dupl_ptr->fragment->index;
+				}
+
+				if(frag_bytes == 0 || memcmp(frag_data, fragment_buffer1, frag_bytes) == 0) {
+					TRACE("Found duplicate file, start 0x%llx, size %lld, checksum 0x%x, fragment %d, size %d, offset %d, checksum 0x%x\n", dupl_ptr->start,
+						dupl_ptr->bytes, dupl_ptr->checksum, dupl_ptr->fragment->index, frag_bytes, dupl_ptr->fragment->offset, fragment_checksum);
+					*block_list = dupl_ptr->block_list;
+					*start = dupl_ptr->start;
+					*fragment = dupl_ptr->fragment;
+					return 0;
+				}
+			}
+		}
+
+
+	if((dupl_ptr = (struct file_info *) malloc(sizeof(struct file_info))) == NULL) {
+		BAD_ERROR("Out of memory in dup_files allocation!\n");
+	}
+
+	dupl_ptr->bytes = bytes;
+	dupl_ptr->checksum = checksum;
+	dupl_ptr->start = *start;
+	dupl_ptr->fragment_checksum = fragment_checksum;
+	dupl_ptr->block_list = *block_list;
+
+	dup_files ++;
+	if(bytes) {
+		dupl_ptr->next = dupl[checksum];
+		dupl[checksum] = dupl_ptr;
+	} else {
+		dupl_ptr->next = frag_dups[fragment_checksum];
+		frag_dups[fragment_checksum] = dupl_ptr;
+	}
+
+	return dupl_ptr;
+}
+
+
+#define MINALLOCBYTES (1024 * 1024)
+int write_file(squashfs_inode *inode, struct dir_ent *dir_ent, long long size, int *duplicate_file)
+{
+	int block = 0, i, file, whole_file = 1, status;
+	unsigned int c_byte, frag_bytes;
+	long long bbytes, file_bytes = 0, start;
+	char buff[block_size], *c_buffer = NULL, *filename = dir_ent->pathname;
+	struct fragment *fragment;
+	struct file_info *dupl_ptr = NULL;
+	struct duplicate_buffer_handle handle;
+	long long read_size = (size > SQUASHFS_MAX_FILE_SIZE) ? SQUASHFS_MAX_FILE_SIZE : size;
+	int blocks = (read_size + block_size - 1) >> block_log, allocated_blocks = blocks;
+	unsigned int *block_list, *block_listp;
+
+	if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL)
+		BAD_ERROR("Out of memory allocating block_list\n");
+	block_listp = block_list;
+
+	if(!no_fragments && (read_size < block_size || always_use_fragments)) {
+		allocated_blocks = blocks = read_size >> block_log;
+		frag_bytes = read_size % block_size;
+	} else
+		frag_bytes = 0;
+
+	if(size > read_size)
+		ERROR("file %s truncated to %lld bytes\n", filename, SQUASHFS_MAX_FILE_SIZE);
+
+	total_bytes += read_size;
+	if((file = open(filename, O_RDONLY)) == -1)
+		goto read_err;
+
+	do {
+		long long bytes = (((long long) allocated_blocks) + 1) << block_log;
+		if(bytes != ((size_t) bytes) || (c_buffer = (char *) malloc(bytes)) == NULL) {
+			TRACE("Out of memory allocating write_file buffer, allocated_blocks %ld, blocks %d\n", allocated_blocks, blocks);
+			whole_file = 0;
+			if(bytes < MINALLOCBYTES)
+				BAD_ERROR("Out of memory allocating write_file buffer, could not allocate %ld blocks (%d Kbytes)\n", allocated_blocks, allocated_blocks << (block_log - 10));
+			allocated_blocks >>= 1;
+		}
+	} while(!c_buffer);
+
+	for(start = bytes; block < blocks; file_bytes += bbytes) {
+		for(i = 0, bbytes = 0; (i < allocated_blocks) && (block < blocks); i++) {
+			int available_bytes = read_size - (block * block_size) > block_size ? block_size : read_size - (block * block_size);
+			if(read(file, buff, available_bytes) == -1)
+				goto read_err;
+			c_byte = mangle(c_buffer + bbytes, buff, available_bytes, block_size, noD, 1);
+			block_list[block ++] = c_byte;
+			bbytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
+		}
+		if(!whole_file) {
+			write_bytes(fd, bytes, bbytes, c_buffer);
+			bytes += bbytes;
+		}
+	}
+
+	if(frag_bytes != 0)
+		if(read(file, buff, frag_bytes) == -1)
+			goto read_err;
+
+	close(file);
+	if(whole_file) {
+		handle.ptr = c_buffer;
+		if(duplicate_checking && (dupl_ptr = duplicate(read_from_buffer, &handle, file_bytes, &block_listp, &start, blocks, &fragment, buff, frag_bytes)) == NULL) {
+			*duplicate_file = TRUE;
+			goto wr_inode;
+		}
+		write_bytes(fd, bytes, file_bytes, c_buffer);
+		bytes += file_bytes;
+	} else {
+		handle.start = start;
+		if(duplicate_checking && (dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &fragment, buff, frag_bytes)) == NULL) {
+			bytes = start;
+			if(!block_device)
+				ftruncate(fd, bytes);
+			*duplicate_file = TRUE;
+			goto wr_inode;
+		}
+	}
+
+	fragment = get_and_fill_fragment(buff, frag_bytes);
+	if(duplicate_checking)
+		dupl_ptr->fragment = fragment;
+
+	*duplicate_file = FALSE;
+
+wr_inode:
+	free(c_buffer);
+	file_count ++;
+	if(dir_ent->inode->nlink == 1 && read_size < ((long long) (1<<30) - 1))
+		status = create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_listp, fragment, NULL);
+	else
+		status = create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, read_size, start, blocks, block_listp, fragment, NULL);
+	if(duplicate_checking == FALSE || *duplicate_file == TRUE)
+		free(block_list);
+	return status;
+
+read_err:
+	perror("Error in reading file, skipping...");
+	free(c_buffer);
+	free(block_list);
+	return FALSE;
+}
+
+
+char b_buffer[8192];
+char *name;
+char *basename_r();
+
+char *getbase(char *pathname)
+{
+	char *result;
+
+	if(*pathname != '/') {
+		result = getenv("PWD");
+		strcat(strcat(strcpy(b_buffer, result), "/"), pathname);
+	} else
+		strcpy(b_buffer, pathname);
+	name = b_buffer;
+	if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
+		return NULL;
+	else
+		return result;
+}
+
+
+char *basename_r()
+{
+	char *s;
+	char *p;
+	int n = 1;
+
+	for(;;) {
+		s = name;
+		if(*name == '\0')
+			return NULL;
+		if(*name != '/') {
+			while(*name != '\0' && *name != '/') name++;
+			n = name - s;
+		}
+		while(*name == '/') name++;
+		if(strncmp(s, ".", n) == 0)
+			continue;
+		if((*name == '\0') || (strncmp(s, "..", n) == 0) || ((p = basename_r()) == NULL)) {
+			s[n] = '\0';
+			return s;
+		}
+		if(strcmp(p, "..") == 0)
+			continue;
+		return p;
+	}
+}
+
+
+struct inode_info *lookup_inode(struct stat *buf)
+{
+	int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino);
+	struct inode_info *inode = inode_info[inode_hash];
+
+	while(inode != NULL) {
+		if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
+			inode->nlink ++;
+			return inode;
+		}
+		inode = inode->next;
+	}
+
+	if((inode = malloc(sizeof(struct inode_info))) == NULL)
+		BAD_ERROR("Out of memory in inode hash table entry allocation\n");
+
+	memcpy(&inode->buf, buf, sizeof(struct stat));
+	inode->inode = SQUASHFS_INVALID_BLK;
+	inode->nlink = 1;
+	if((buf->st_mode & S_IFMT) == S_IFDIR)
+		inode->inode_number = dir_inode_no ++;
+	else
+		inode->inode_number = inode_no ++;
+
+	inode->next = inode_info[inode_hash];
+	inode_info[inode_hash] = inode;
+
+	return inode;
+}
+
+
+inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir, struct inode_info *inode_info, void *data, struct dir_info *dir)
+{
+	if((dir->count % DIR_ENTRIES) == 0)
+		if((dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) * sizeof(struct dir_ent *))) == NULL)
+			BAD_ERROR("Out of memory in add_dir_entry\n");
+
+	if((dir->list[dir->count] = malloc(sizeof(struct dir_ent))) == NULL)
+		BAD_ERROR("Out of memory in linux_opendir\n");
+
+	if(sub_dir)
+		sub_dir->dir_ent = dir->list[dir->count];
+	dir->list[dir->count]->name = strdup(name);
+	dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) : NULL;
+	dir->list[dir->count]->inode = inode_info;
+	dir->list[dir->count]->dir = sub_dir;
+	dir->list[dir->count]->our_dir = dir;
+	dir->list[dir->count++]->data = data;
+	dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry);
+}
+
+
+int compare_name(const void *ent1_ptr, const void *ent2_ptr)
+{
+	struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr);
+	struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr);
+
+	return strcmp(ent1->name, ent2->name);
+}
+
+
+void sort_directory(struct dir_info *dir)
+{
+	qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name);
+
+	if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE))
+		dir->dir_is_ldir = FALSE;
+}
+
+
+struct dir_info *scan1_opendir(char *pathname)
+{
+	DIR	*linuxdir;
+	struct dirent *d_name;
+	struct dir_info *dir;
+
+	if((dir = malloc(sizeof(struct dir_info))) == NULL)
+		return NULL;
+
+	if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
+		free(dir);
+		return NULL;
+	}
+	dir->pathname = strdup(pathname);
+	dir->count = dir->directory_count = dir->current_count = dir->byte_count = 0;
+	dir->dir_is_ldir = TRUE;
+	dir->list = NULL;
+
+	return dir;
+}
+
+
+int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir)
+{
+	int i, n, pass;
+	char *basename;
+	static int index = 0;
+
+	if(dir->count < old_root_entries)
+		for(i = 0; i < old_root_entries; i++) {
+			if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
+				dir->directory_count ++;
+			add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir);
+		}
+
+	while(index < source) {
+		if((basename = getbase(source_path[index])) == NULL) {
+			ERROR("Bad source directory %s - skipping ...\n", source_path[index]);
+			index ++;
+			continue;
+		}
+		strcpy(dir_name, basename);
+		pass = 1;
+		for(;;) {
+			for(n = 0; n < dir->count && strcmp(dir->list[n]->name, dir_name) != 0; n++);
+			if(n == dir->count)
+				break;
+			ERROR("Source directory entry %s already used! - trying ", dir_name);
+			sprintf(dir_name, "%s_%d", basename, pass++);
+			ERROR("%s\n", dir_name);
+		}
+		strcpy(pathname, source_path[index ++]);
+		return 1;
+	}
+	return 0;
+}
+
+
+int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir)
+{
+	struct dirent *d_name;
+	int i, pass;
+
+	if(dir->count < old_root_entries)
+		for(i = 0; i < old_root_entries; i++) {
+			if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
+				dir->directory_count ++;
+			add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir);
+		}
+
+	if((d_name = readdir(dir->linuxdir)) != NULL) {
+		strcpy(dir_name, d_name->d_name);
+		pass = 1;
+		for(;;) {
+			for(i = 0; i < dir->count && strcmp(dir->list[i]->name, dir_name) != 0; i++);
+			if(i == dir->count)
+				break;
+			ERROR("Source directory entry %s already used! - trying ", dir_name);
+			sprintf(dir_name, "%s_%d", d_name->d_name, pass++);
+			ERROR("%s\n", dir_name);
+		}
+		strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir)
+{
+	struct dirent *d_name;
+
+	if((d_name = readdir(dir->linuxdir)) != NULL) {
+		strcpy(dir_name, d_name->d_name);
+		strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+struct dir_ent *scan2_readdir(struct directory *dir, struct dir_info *dir_info)
+{
+	int current_count;
+
+	while((current_count = dir_info->current_count++) < dir_info->count)
+		if(dir_info->list[current_count]->data)
+			add_dir(dir_info->list[current_count]->data->inode, dir_info->list[current_count]->data->inode_number,
+				dir_info->list[current_count]->name, dir_info->list[current_count]->data->type, dir);
+		else 
+			return dir_info->list[current_count];
+	return FALSE;	
+}
+
+
+void scan1_freedir(struct dir_info *dir)
+{
+	if(dir->pathname[0] != '\0')
+		closedir(dir->linuxdir);
+}
+
+
+void scan2_freedir(struct directory *dir)
+{
+	if(dir->index)
+		free(dir->index);
+	free(dir->buff);
+}
+
+
+void dir_scan(squashfs_inode *inode, char *pathname, int (_readdir)(char *, char *, struct dir_info *))
+{
+	struct dir_info *dir_info = dir_scan1(pathname, _readdir);
+	struct dir_ent *dir_ent;
+	struct inode_info *inode_info;
+	
+	if(dir_info == NULL)
+		return;
+
+	if((dir_ent = malloc(sizeof(struct dir_ent))) == NULL)
+		BAD_ERROR("Out of memory in dir_scan\n");
+
+	if((inode_info = malloc(sizeof(struct inode_info))) == NULL)
+		BAD_ERROR("Out of memory in dir_scan\n");
+
+	dir_ent->name = dir_ent->pathname = strdup(pathname);
+	dir_ent->dir = dir_info;
+	dir_ent->inode = inode_info;
+	dir_ent->our_dir = NULL;
+	dir_ent->data = NULL;
+	inode_info->nlink = 1;
+	inode_info->inode_number = root_inode_number ? root_inode_number : dir_inode_no++;
+	dir_info->dir_ent = dir_ent;
+
+	if(pathname[0] == '\0') {
+		/* dummy top level directory, if multiple sources specified on command line */
+		inode_info->buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
+		inode_info->buf.st_uid = getuid();
+		inode_info->buf.st_gid = getgid();
+		inode_info->buf.st_mtime = time(NULL);
+	} else if(lstat(pathname, &inode_info->buf) == -1) {
+		char buffer[8192];
+		sprintf(buffer, "Cannot stat dir/file %s, ignoring", pathname);
+		perror(buffer);
+		return;
+	}
+	if(sorted)
+		sort_files_and_write(dir_info);
+	dir_scan2(inode, dir_info);
+}
+
+
+struct dir_info *dir_scan1(char *pathname, int (_readdir)(char *, char *, struct dir_info *))
+{
+	struct dir_info *dir, *sub_dir;
+	struct stat buf;
+	char filename[8192], dir_name[8192];
+
+	if((dir = scan1_opendir(pathname)) == NULL) {
+		ERROR("Could not open %s, skipping...\n", pathname);
+		goto error;
+	}
+
+	while(_readdir(filename, dir_name, dir) != FALSE) {
+
+		if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)
+			continue;
+
+		if(lstat(filename, &buf) == -1) {
+			char buffer[8192];
+			sprintf(buffer, "Cannot stat dir/file %s, ignoring", filename);
+			perror(buffer);
+			continue;
+		}
+		if(excluded(filename, &buf))
+			continue;
+
+		if((buf.st_mode & S_IFMT) == S_IFDIR) {
+			if((sub_dir = dir_scan1(filename, scan1_readdir)) == NULL)
+				continue;
+			dir->directory_count ++;
+		} else
+			sub_dir = NULL;
+
+		add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf), NULL, dir);
+	}
+
+	scan1_freedir(dir);
+	sort_directory(dir);
+
+error:
+	return dir;
+}
+
+
+int dir_scan2(squashfs_inode *inode, struct dir_info *dir_info)
+{
+	int squashfs_type;
+	int result = FALSE;
+	int duplicate_file;
+	char *pathname = dir_info->pathname;
+	struct directory dir;
+	struct dir_ent *dir_ent;
+	
+	scan2_init_dir(&dir);
+	
+	while((dir_ent = scan2_readdir(&dir, dir_info)) != NULL) {
+		struct inode_info *inode_info = dir_ent->inode;
+		struct stat *buf = &inode_info->buf;
+		char *filename = dir_ent->pathname;
+		char *dir_name = dir_ent->name;
+		unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
+
+		if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
+			switch(buf->st_mode & S_IFMT) {
+				case S_IFREG:
+					squashfs_type = SQUASHFS_FILE_TYPE;
+					result = write_file(inode, dir_ent, buf->st_size, &duplicate_file);
+					INFO("file %s, uncompressed size %lld bytes %s\n", filename, buf->st_size, duplicate_file ? "DUPLICATE" : "");
+					break;
+
+				case S_IFDIR:
+					squashfs_type = SQUASHFS_DIR_TYPE;
+					result = dir_scan2(inode, dir_ent->dir);
+					break;
+
+				case S_IFLNK:
+					squashfs_type = SQUASHFS_SYMLINK_TYPE;
+					result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
+					INFO("symbolic link %s inode 0x%llx\n", dir_name, *inode);
+					sym_count ++;
+					break;
+
+				case S_IFCHR:
+					squashfs_type = SQUASHFS_CHRDEV_TYPE;
+					result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
+					INFO("character device %s inode 0x%llx\n", dir_name, *inode);
+					dev_count ++;
+					break;
+
+				case S_IFBLK:
+					squashfs_type = SQUASHFS_BLKDEV_TYPE;
+					result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
+					INFO("block device %s inode 0x%llx\n", dir_name, *inode);
+					dev_count ++;
+					break;
+
+				case S_IFIFO:
+					squashfs_type = SQUASHFS_FIFO_TYPE;
+					result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
+					INFO("fifo %s inode 0x%llx\n", dir_name, *inode);
+					fifo_count ++;
+					break;
+
+				case S_IFSOCK:
+					squashfs_type = SQUASHFS_SOCKET_TYPE;
+					result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
+					INFO("unix domain socket %s inode 0x%llx\n", dir_name, *inode);
+					sock_count ++;
+					break;
+
+			 	default:
+					ERROR("%s unrecognised file type, mode is %x\n", filename, buf->st_mode);
+					result = FALSE;
+				}
+			if(result)
+				dir_ent->inode->inode = *inode;
+			dir_ent->inode->type = squashfs_type;
+		 } else {
+			*inode = dir_ent->inode->inode;
+			squashfs_type = dir_ent->inode->type;
+			switch(squashfs_type) {
+				case SQUASHFS_FILE_TYPE:
+					if(!sorted)
+						INFO("file %s, uncompressed size %lld bytes LINK\n", filename, buf->st_size);
+					break;
+				case SQUASHFS_SYMLINK_TYPE:
+					INFO("symbolic link %s inode 0x%llx LINK\n", dir_name, *inode);
+					break;
+				case SQUASHFS_CHRDEV_TYPE:
+					INFO("character device %s inode 0x%llx LINK\n", dir_name, *inode);
+					break;
+				caseSQUASHFS_BLKDEV_TYPE:
+					INFO("block device %s inode 0x%llx LINK\n", dir_name, *inode);
+					break;
+				case SQUASHFS_FIFO_TYPE:
+					INFO("fifo %s inode 0x%llx LINK\n", dir_name, *inode);
+					break;
+				case SQUASHFS_SOCKET_TYPE:
+					INFO("unix domain socket %s inode 0x%llx LINK\n", dir_name, *inode);
+					break;
+			}
+			result = TRUE;
+		}
+		
+
+		if(result)
+			add_dir(*inode, inode_number, dir_name, squashfs_type, &dir);
+	}
+
+	result = write_dir(inode, dir_info, &dir);
+	INFO("directory %s inode 0x%llx\n", pathname, *inode);
+
+	scan2_freedir(&dir);
+
+	return result;
+}
+
+
+unsigned int slog(unsigned int block)
+{
+	int i;
+
+	for(i = 12; i <= 16; i++)
+		if(block == (1 << i))
+			return i;
+	return 0;
+}
+
+
+int excluded(char *filename, struct stat *buf)
+{
+	int i;
+
+	for(i = 0; i < exclude; i++)
+		if((exclude_paths[i].st_dev == buf->st_dev) && (exclude_paths[i].st_ino == buf->st_ino))
+			return TRUE;
+	return FALSE;
+}
+
+
+#define ADD_ENTRY(buf) \
+	if(exclude % EXCLUDE_SIZE == 0) {\
+		if((exclude_paths = (struct exclude_info *) realloc(exclude_paths, (exclude + EXCLUDE_SIZE) * sizeof(struct exclude_info))) == NULL)\
+			BAD_ERROR("Out of memory in exclude dir/file table\n");\
+	}\
+	exclude_paths[exclude].st_dev = buf.st_dev;\
+	exclude_paths[exclude++].st_ino = buf.st_ino;
+int add_exclude(char *path)
+{
+	int i;
+	char buffer[4096], filename[4096];
+	struct stat buf;
+
+	if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
+		if(lstat(path, &buf) == -1) {
+			sprintf(buffer, "Cannot stat exclude dir/file %s, ignoring", path);
+			perror(buffer);
+			return TRUE;
+		}
+		ADD_ENTRY(buf);
+		return TRUE;
+	}
+
+	for(i = 0; i < source; i++) {
+		strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
+		if(lstat(filename, &buf) == -1) {
+			if(!(errno == ENOENT || errno == ENOTDIR)) {
+				sprintf(buffer, "Cannot stat exclude dir/file %s, ignoring", filename);
+				perror(buffer);
+			}
+			continue;
+		}
+		ADD_ENTRY(buf);
+	}
+	return TRUE;
+}
+
+
+void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type)
+{
+	if((old_root_entry = (struct old_root_entry_info *) realloc(old_root_entry, sizeof(struct old_root_entry_info)
+				* (old_root_entries + 1))) == NULL)
+		BAD_ERROR("Out of memory in old root directory entries reallocation\n");
+
+	strcpy(old_root_entry[old_root_entries].name, name);
+	old_root_entry[old_root_entries].inode = inode;
+	old_root_entry[old_root_entries].inode_number = inode_number;
+	old_root_entry[old_root_entries++].type = type;
+}
+
+
+#define VERSION() \
+	printf("mksquashfs version 3.0 (2006/03/15)\n");\
+	printf("copyright (C) 2006 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \
+    	printf("This program is free software; you can redistribute it and/or\n");\
+	printf("modify it under the terms of the GNU General Public License\n");\
+	printf("as published by the Free Software Foundation; either version 2,\n");\
+	printf("or (at your option) any later version.\n\n");\
+	printf("This program is distributed in the hope that it will be useful,\n");\
+	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
+	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");\
+	printf("GNU General Public License for more details.\n");
+int main(int argc, char *argv[])
+{
+	struct stat buf, source_buf;
+	int i;
+	squashfs_super_block sBlk;
+	char *b, *root_name = NULL;
+	int be, nopad = FALSE, keep_as_directory = FALSE, orig_be;
+	squashfs_inode inode;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	be = TRUE;
+#else
+	be = FALSE;
+#endif
+
+	block_log = slog(block_size);
+	if(argc > 1 && strcmp(argv[1], "-version") == 0) {
+		VERSION();
+		exit(0);
+	}
+        for(i = 1; i < argc && argv[i][0] != '-'; i++);
+	if(i < 3)
+		goto printOptions;
+	source_path = argv + 1;
+	source = i - 2;
+	for(; i < argc; i++) {
+		if(strcmp(argv[i], "-b") == 0) {
+			if((++i == argc) || (block_size = strtol(argv[i], &b, 10), *b !='\0')) {
+				ERROR("%s: -b missing or invalid block size\n", argv[0]);
+				exit(1);
+			}
+
+			if((block_log = slog(block_size)) == 0) {
+				ERROR("%s: -b block size not power of two or not between 4096 and 64K\n", argv[0]);
+				exit(1);
+			}
+		} else if(strcmp(argv[i], "-ef") == 0) {
+			if(++i == argc) {
+				ERROR("%s: -ef missing filename\n", argv[0]);
+				exit(1);
+			}
+		} else if(strcmp(argv[i], "-no-duplicates") == 0)
+			duplicate_checking = FALSE;
+
+		else if(strcmp(argv[i], "-no-fragments") == 0)
+			no_fragments = TRUE;
+
+		 else if(strcmp(argv[i], "-always-use-fragments") == 0)
+			always_use_fragments = TRUE;
+
+		 else if(strcmp(argv[i], "-sort") == 0) {
+			if(++i == argc) {
+				ERROR("%s: -sort missing filename\n", argv[0]);
+				exit(1);
+			}
+		} else if(strcmp(argv[i], "-all-root") == 0 ||
+				strcmp(argv[i], "-root-owned") == 0)
+			global_uid = global_gid = 0;
+
+		else if(strcmp(argv[i], "-force-uid") == 0) {
+			if(++i == argc) {
+				ERROR("%s: -force-uid missing uid or user\n", argv[0]);
+				exit(1);
+			}
+			if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
+				if(global_uid < 0 || global_uid > (((long long) 1 << 32) - 1)) {
+					ERROR("%s: -force-uid uid out of range\n", argv[0]);
+					exit(1);
+				}
+			} else {
+				struct passwd *uid = getpwnam(argv[i]);
+				if(uid)
+					global_uid = uid->pw_uid;
+				else {
+					ERROR("%s: -force-uid invalid uid or unknown user\n", argv[0]);
+					exit(1);
+				}
+			}
+		} else if(strcmp(argv[i], "-force-gid") == 0) {
+			if(++i == argc) {
+				ERROR("%s: -force-gid missing gid or group\n", argv[0]);
+				exit(1);
+			}
+			if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
+				if(global_gid < 0 || global_gid > (((long long) 1 << 32) - 1)) {
+					ERROR("%s: -force-gid gid out of range\n", argv[0]);
+					exit(1);
+				}
+			} else {
+				struct group *gid = getgrnam(argv[i]);
+				if(gid)
+					global_gid = gid->gr_gid;
+				else {
+					ERROR("%s: -force-gid invalid gid or unknown group\n", argv[0]);
+					exit(1);
+				}
+			}
+		} else if(strcmp(argv[i], "-noI") == 0 ||
+				strcmp(argv[i], "-noInodeCompression") == 0)
+			noI = TRUE;
+
+		else if(strcmp(argv[i], "-noD") == 0 ||
+				strcmp(argv[i], "-noDataCompression") == 0)
+			noD = TRUE;
+
+		else if(strcmp(argv[i], "-noF") == 0 ||
+				strcmp(argv[i], "-noFragmentCompression") == 0)
+			noF = TRUE;
+
+		else if(strcmp(argv[i], "-nopad") == 0)
+			nopad = TRUE;
+
+		else if(strcmp(argv[i], "-check_data") == 0)
+			check_data = TRUE;
+
+		else if(strcmp(argv[i], "-info") == 0)
+			silent = 0;
+
+		else if(strcmp(argv[i], "-be") == 0)
+			be = TRUE;
+
+		else if(strcmp(argv[i], "-le") == 0)
+			be = FALSE;
+
+		else if(strcmp(argv[i], "-e") == 0)
+			break;
+
+		else if(strcmp(argv[i], "-noappend") == 0)
+			delete = TRUE;
+
+		else if(strcmp(argv[i], "-keep-as-directory") == 0)
+			keep_as_directory = TRUE;
+
+		else if(strcmp(argv[i], "-root-becomes") == 0) {
+			if(++i == argc) {
+				ERROR("%s: -root-becomes: missing name\n", argv[0]);
+				exit(1);
+			}	
+			root_name = argv[i];
+		} else if(strcmp(argv[i], "-version") == 0) {
+			VERSION();
+		} else {
+			ERROR("%s: invalid option\n\n", argv[0]);
+printOptions:
+			ERROR("SYNTAX:%s source1 source2 ...  dest [options] [-e list of exclude\ndirs/files]\n", argv[0]);
+			ERROR("\nOptions are\n");
+			ERROR("-version\t\tprint version, licence and copyright message\n");
+			ERROR("-info\t\t\tprint files written to filesystem\n");
+			ERROR("-b <block_size>\t\tset data block to <block_size>.  Default %d bytes\n", SQUASHFS_FILE_SIZE);
+			ERROR("-noI\t\t\tdo not compress inode table\n");
+			ERROR("-noD\t\t\tdo not compress data blocks\n");
+			ERROR("-noF\t\t\tdo not compress fragment blocks\n");
+			ERROR("-no-fragments\t\tdo not use fragments\n");
+			ERROR("-always-use-fragments\tuse fragment blocks for files larger than block size\n");
+			ERROR("-no-duplicates\t\tdo not perform duplicate checking\n");
+			ERROR("-noappend\t\tdo not append to existing filesystem\n");
+			ERROR("-keep-as-directory\tif one source directory is specified, create a root\n");
+			ERROR("\t\t\tdirectory containing that directory, rather than the\n");
+			ERROR("\t\t\tcontents of the directory\n");
+			ERROR("-root-becomes <name>\twhen appending source files/directories, make the\n");
+			ERROR("\t\t\toriginal root become a subdirectory in the new root\n");
+			ERROR("\t\t\tcalled <name>, rather than adding the new source items\n");
+			ERROR("\t\t\tto the original root\n");
+			ERROR("-all-root\t\tmake all files owned by root\n");
+			ERROR("-force-uid uid\t\tset all file uids to uid\n");
+			ERROR("-force-gid gid\t\tset all file gids to gid\n");
+			ERROR("-le\t\t\tcreate a little endian filesystem\n");
+			ERROR("-be\t\t\tcreate a big endian filesystem\n");
+			ERROR("-nopad\t\t\tdo not pad filesystem to a multiple of 4K\n");
+			ERROR("-check_data\t\tadd checkdata for greater filesystem checks\n");
+			ERROR("-root-owned\t\talternative name for -all-root\n");
+			ERROR("-noInodeCompression\talternative name for -noI\n");
+			ERROR("-noDataCompression\talternative name for -noD\n");
+			ERROR("-noFragmentCompression\talternative name for -noF\n");
+			ERROR("-sort <sort_file>\tsort files according to priorities in <sort_file>.  One\n");
+			ERROR("\t\t\tfile or dir with priority per line.  Priority -32768 to\n");
+			ERROR("\t\t\t32767, default priority 0\n");
+			ERROR("-ef <exclude_file>\tlist of exclude dirs/files.  One per line\n");
+			exit(1);
+		}
+	}
+
+        for(i = 0; i < source; i++)
+                if(stat(source_path[i], &source_buf) == -1) {
+                        fprintf(stderr, "Cannot stat source directory \"%s\" because %s\n", source_path[i], strerror(errno));
+                        EXIT_MKSQUASHFS();
+                }
+
+	destination_file = argv[source + 1];
+	if(stat(argv[source + 1], &buf) == -1) {
+		if(errno == ENOENT) { /* Does not exist */
+			if((fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1) {
+				perror("Could not create destination file");
+				exit(1);
+			}
+			delete = TRUE;
+		} else {
+			perror("Could not stat destination file");
+			exit(1);
+		}
+
+	} else {
+		if(S_ISBLK(buf.st_mode)) {
+			if((fd = open(argv[source + 1], O_RDWR)) == -1) {
+				perror("Could not open block device as destination");
+				exit(1);
+			}
+			block_device = 1;
+
+		} else if(S_ISREG(buf.st_mode))	 {
+			if((fd = open(argv[source + 1], (delete ? O_TRUNC : 0) | O_RDWR)) == -1) {
+				perror("Could not open regular file for writing as destination");
+				exit(1);
+			}
+		}
+		else {
+			ERROR("Destination not block device or regular file\n");
+			exit(1);
+		}
+
+	}
+
+	if(!delete) {
+	        if(read_super(fd, &sBlk, &orig_be, argv[source + 1]) == 0) {
+			ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n");
+			EXIT_MKSQUASHFS();
+		}
+	} else  {
+		signal(SIGTERM, sighandler2);
+		signal(SIGINT, sighandler2);
+	}
+
+	/* process the exclude files - must be done afer destination file has been possibly created */
+	for(i = source + 2; i < argc; i++)
+		if(strcmp(argv[i], "-ef") == 0) {
+			FILE *fd;
+			char filename[16385];
+			if((fd = fopen(argv[++i], "r")) == NULL) {
+				perror("Could not open exclude file...");
+				EXIT_MKSQUASHFS();
+			}
+			while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
+				add_exclude(filename);
+			fclose(fd);
+		} else if(strcmp(argv[i], "-e") == 0)
+			break;
+		else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-sort") == 0)
+			i++;
+
+	if(i != argc) {
+		if(++i == argc) {
+			ERROR("%s: -e missing arguments\n", argv[0]);
+			EXIT_MKSQUASHFS();
+		}
+		while(i < argc && add_exclude(argv[i++]));
+	}
+
+	/* process the sort files - must be done afer the exclude files  */
+	for(i = source + 2; i < argc; i++)
+		if(strcmp(argv[i], "-sort") == 0) {
+			read_sort_file(argv[++i], source, source_path);
+			sorted ++;
+		} else if(strcmp(argv[i], "-e") == 0)
+			break;
+		else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0)
+			i++;
+
+	if(delete) {
+		printf("Creating %s %d.%d filesystem on %s, block size %d.\n",
+				be ? "big endian" : "little endian", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
+		bytes = sizeof(squashfs_super_block);
+	} else {
+		unsigned int last_directory_block, inode_dir_offset, inode_dir_file_size, root_inode_size,
+		inode_dir_start_block, uncompressed_data, compressed_data, inode_dir_inode_number,
+		inode_dir_parent_inode;
+		unsigned int root_inode_start = SQUASHFS_INODE_BLK(sBlk.root_inode), root_inode_offset =
+		SQUASHFS_INODE_OFFSET(sBlk.root_inode);
+
+		be = orig_be;
+		block_log = slog(block_size = sBlk.block_size);
+		noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
+		noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
+		noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
+		check_data = SQUASHFS_CHECK_DATA(sBlk.flags);
+		no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
+		always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
+		duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
+		
+		if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &data_cache,
+				&directory_table, &directory_data_cache, &last_directory_block, &inode_dir_offset,
+				&inode_dir_file_size, &root_inode_size, &inode_dir_start_block,
+				&file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count,
+				(squashfs_uid *) uids, &uid_count, (squashfs_uid *) guids, &guid_count,
+				&total_bytes, &total_inode_bytes, &total_directory_bytes, &inode_dir_inode_number,
+				&inode_dir_parent_inode, add_old_root_entry, &fragment_table)) == 0) {
+			ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n");
+			EXIT_MKSQUASHFS();
+		}
+		if((fragments = sBlk.fragments))
+			fragment_table = (squashfs_fragment_entry *) realloc((char *) fragment_table, ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) * sizeof(squashfs_fragment_entry)); 
+
+		printf("Appending to existing %s %d.%d filesystem on %s, block size %d\n", be ? "big endian" :
+			"little endian", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
+		printf("All -be, -le, -b, -noI, -noD, -noF, -check_data, no-duplicates, no-fragments, -always-use-fragments and -2.0 options ignored\n");
+		printf("\nIf appending is not wanted, please re-run with -noappend specified!\n\n");
+
+		compressed_data = inode_dir_offset + inode_dir_file_size & ~(SQUASHFS_METADATA_SIZE - 1);
+		uncompressed_data = inode_dir_offset + inode_dir_file_size & (SQUASHFS_METADATA_SIZE - 1);
+		
+		/* save original filesystem state for restoring ... */
+		sfragments = fragments;
+		sbytes = bytes;
+		sinode_count = sBlk.inodes;
+		sdata_cache = (char *)malloc(scache_bytes = root_inode_offset + root_inode_size);
+		sdirectory_data_cache = (char *)malloc(sdirectory_cache_bytes = uncompressed_data);
+		memcpy(sdata_cache, data_cache, scache_bytes);
+		memcpy(sdirectory_data_cache, directory_data_cache + compressed_data, sdirectory_cache_bytes);
+		sinode_bytes = root_inode_start;
+		sdirectory_bytes = last_directory_block;
+		suid_count = uid_count;
+		sguid_count = guid_count;
+		stotal_bytes = total_bytes;
+		stotal_inode_bytes = total_inode_bytes;
+		stotal_directory_bytes = total_directory_bytes + compressed_data;
+		sfile_count = file_count;
+		ssym_count = sym_count;
+		sdev_count = dev_count;
+		sdir_count = dir_count + 1;
+		sfifo_count = fifo_count;
+		ssock_count = sock_count;
+		sdup_files = dup_files;
+		restore = TRUE;
+		if(setjmp(env))
+			goto restore_filesystem;
+		signal(SIGTERM, sighandler);
+		signal(SIGINT, sighandler);
+		write_bytes(fd, SQUASHFS_START, 4, "\0\0\0\0");
+
+		/* set the filesystem state up to be able to append to the original filesystem.  The filesystem state
+		 * differs depending on whether we're appending to the original root directory, or if the original
+		 * root directory becomes a sub-directory (root-becomes specified on command line, here root_name != NULL)
+		 */
+		inode_bytes = inode_size = root_inode_start;
+		directory_size = last_directory_block;
+		cache_size = root_inode_offset + root_inode_size;
+		directory_cache_size = inode_dir_offset + inode_dir_file_size;
+		if(root_name) {
+			root_inode_number = inode_dir_parent_inode;
+			dir_inode_no = sBlk.inodes + 2;
+			directory_bytes = last_directory_block;
+			directory_cache_bytes = uncompressed_data;
+			memmove(directory_data_cache, directory_data_cache + compressed_data, uncompressed_data);
+			cache_bytes = root_inode_offset + root_inode_size;
+			add_old_root_entry(root_name, sBlk.root_inode, inode_dir_inode_number, SQUASHFS_DIR_TYPE);
+			total_directory_bytes += compressed_data;
+			dir_count ++;
+		} else {
+			root_inode_number = inode_dir_inode_number;
+			dir_inode_no = sBlk.inodes + 1;
+			directory_bytes = inode_dir_start_block;
+			directory_cache_bytes = inode_dir_offset;
+			cache_bytes = root_inode_offset;
+		}
+
+		inode_count = file_count + dir_count + sym_count + dev_count + fifo_count + sock_count;
+	}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	swap = !be;
+#else
+	swap = be;
+#endif
+
+	block_offset = check_data ? 3 : 2;
+
+	if(delete && !keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode))
+		dir_scan(&inode, source_path[0], scan1_readdir);
+	else if(!keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode))
+		dir_scan(&inode, source_path[0], scan1_single_readdir);
+	else
+		dir_scan(&inode, "", scan1_encomp_readdir);
+	sBlk.root_inode = inode;
+	sBlk.inodes = inode_count;
+	sBlk.s_magic = SQUASHFS_MAGIC;
+	sBlk.s_major = SQUASHFS_MAJOR;
+	sBlk.s_minor = SQUASHFS_MINOR;
+	sBlk.block_size = block_size;
+	sBlk.block_log = block_log;
+	sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, check_data, noF, no_fragments, always_use_fragments, duplicate_checking);
+	sBlk.mkfs_time = time(NULL);
+
+restore_filesystem:
+	write_fragment();
+	sBlk.fragments = fragments;
+	sBlk.inode_table_start = write_inodes();
+	sBlk.directory_table_start = write_directories();
+	sBlk.fragment_table_start = write_fragment_table();
+
+	TRACE("sBlk->inode_table_start 0x%x\n", sBlk.inode_table_start);
+	TRACE("sBlk->directory_table_start 0x%x\n", sBlk.directory_table_start);
+	TRACE("sBlk->fragment_table_start 0x%x\n", sBlk.fragment_table_start);
+
+	if(sBlk.no_uids = uid_count) {
+		if(!swap)
+			write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids);
+		else {
+			squashfs_uid uids_copy[uid_count];
+
+			SQUASHFS_SWAP_DATA(uids, uids_copy, uid_count, sizeof(squashfs_uid) * 8);
+			write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids_copy);
+		}
+		sBlk.uid_start = bytes;
+		bytes += uid_count * sizeof(squashfs_uid);
+	} else
+		sBlk.uid_start = 0;
+
+	if(sBlk.no_guids = guid_count) {
+		if(!swap)
+			write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids);
+		else {
+			squashfs_uid guids_copy[guid_count];
+
+			SQUASHFS_SWAP_DATA(guids, guids_copy, guid_count, sizeof(squashfs_uid) * 8);
+			write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids_copy);
+		}
+		sBlk.guid_start = bytes;
+		bytes += guid_count * sizeof(squashfs_uid);
+	} else
+		sBlk.guid_start = 0;
+
+	sBlk.bytes_used = bytes;
+
+	sBlk.unused = SQUASHFS_INVALID_BLK;
+
+	if(!swap)
+		write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk);
+	else {
+		squashfs_super_block sBlk_copy;
+
+		SQUASHFS_SWAP_SUPER_BLOCK((&sBlk), &sBlk_copy); 
+		write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk_copy);
+	}
+
+	if(!nopad && (i = bytes & (4096 - 1))) {
+		char temp[4096] = {0};
+		write_bytes(fd, bytes, 4096 - i, temp);
+	}
+
+	total_bytes += total_inode_bytes + total_directory_bytes + uid_count
+		* sizeof(unsigned short) + guid_count * sizeof(unsigned short) +
+		sizeof(squashfs_super_block);
+
+	printf("\n%s filesystem, data block size %d, %s data, %s metadata, %s fragments\n", be ?
+		"Big endian" : "Little endian", block_size, noD ? "uncompressed" : "compressed", noI ?
+	"uncompressed" : "compressed", no_fragments ? "no" : noF ? "uncompressed" : "compressed");
+	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, bytes / (1024.0 * 1024.0));
+	printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
+		((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
+	printf("Inode table size %d bytes (%.2f Kbytes)\n",
+		inode_bytes, inode_bytes / 1024.0);
+	printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
+		((float) inode_bytes / total_inode_bytes) * 100.0, total_inode_bytes);
+	printf("Directory table size %d bytes (%.2f Kbytes)\n",
+		directory_bytes, directory_bytes / 1024.0);
+	printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
+		((float) directory_bytes / total_directory_bytes) * 100.0, total_directory_bytes);
+	if(duplicate_checking)
+		printf("Number of duplicate files found %d\n", file_count - dup_files);
+	else
+		printf("No duplicate files removed\n");
+	printf("Number of inodes %d\n", inode_count);
+	printf("Number of files %d\n", file_count);
+	if(!no_fragments)
+		printf("Number of fragments %d\n", fragments);
+	printf("Number of symbolic links  %d\n", sym_count);
+	printf("Number of device nodes %d\n", dev_count);
+	printf("Number of fifo nodes %d\n", fifo_count);
+	printf("Number of socket nodes %d\n", sock_count);
+	printf("Number of directories %d\n", dir_count);
+	printf("Number of uids %d\n", uid_count);
+
+	for(i = 0; i < uid_count; i++) {
+		struct passwd *user = getpwuid(uids[i]);
+		printf("\t%s (%d)\n", user == NULL ? "unknown" : user->pw_name, uids[i]);
+	}
+
+	printf("Number of gids %d\n", guid_count);
+
+	for(i = 0; i < guid_count; i++) {
+		struct group *group = getgrgid(guids[i]);
+		printf("\t%s (%d)\n", group == NULL ? "unknown" : group->gr_name, guids[i]);
+	}
+	close(fd);
+	return 0;
+}
diff -ruN linux-2.4.20-nc/scripts/squashfs/mksquashfs.h linux/scripts/squashfs/mksquashfs.h
--- linux-2.4.20-nc/scripts/squashfs/mksquashfs.h	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/mksquashfs.h	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,48 @@
+/*
+ * macros to convert each packed bitfield structure from little endian to big
+ * endian and vice versa.  These are needed when creating a filesystem on a
+ * machine with different byte ordering to the target architecture.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.demon.co.uK>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * mksquashfs.h
+ *
+ */
+
+/*
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing architectures
+ */
+#if __BYTE_ORDER == __BIG_ENDIAN
+	/* convert from big endian to little endian */
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
+#else
+	/* convert from little endian to big endian */ 
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
+#endif
+
+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+	int bits;\
+	int b_pos = pos % 8;\
+	unsigned long long val = (long long) value << (SHIFT);\
+	unsigned char *s = ((unsigned char *) &val) + 7;\
+	unsigned char *d = ((unsigned char *)p) + (pos / 8);\
+	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
+		*d++ |= *s--;\
+}
+#define SQUASHFS_MEMSET(s, d, n)	memset(d, 0, n);
diff -ruN linux-2.4.20-nc/scripts/squashfs/read_fs.c linux/scripts/squashfs/read_fs.c
--- linux-2.4.20-nc/scripts/squashfs/read_fs.c	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/read_fs.c	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,614 @@
+/*
+ * Read a squashfs filesystem.  This is a highly compressed read only filesystem.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * read_fs.c
+ */
+
+extern void read_bytes(int, long long, int, char *);
+extern int add_file(long long, long long, unsigned int *, int, unsigned int, int, int);
+
+#define TRUE 1
+#define FALSE 0
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <zlib.h>
+#include <sys/mman.h>
+
+#ifndef linux
+#define __BYTE_ORDER BYTE_ORDER
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#else
+#include <endian.h>
+#endif
+
+#include <squashfs_fs.h>
+#include "read_fs.h"
+#include "global.h"
+
+#include <stdlib.h>
+
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...)		do { \
+						printf("mksquashfs: "s, ## args); \
+					} while(0)
+#else
+#define TRACE(s, args...)
+#endif
+
+#define ERROR(s, args...)		do { \
+						fprintf(stderr, s, ## args); \
+					} while(0)
+
+int swap;
+
+int read_block(int fd, long long start, long long *next, unsigned char *block, squashfs_super_block *sBlk)
+{
+	unsigned short c_byte;
+	int offset = 2;
+	
+	if(swap) {
+		read_bytes(fd, start, 2, (char *) block);
+		((unsigned char *) &c_byte)[1] = block[0];
+		((unsigned char *) &c_byte)[0] = block[1]; 
+	} else 
+		read_bytes(fd, start, 2, (char *)&c_byte);
+
+	if(SQUASHFS_CHECK_DATA(sBlk->flags))
+		offset = 3;
+	if(SQUASHFS_COMPRESSED(c_byte)) {
+		char buffer[SQUASHFS_METADATA_SIZE];
+		int res;
+		unsigned long bytes = SQUASHFS_METADATA_SIZE;
+
+		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+		read_bytes(fd, start + offset, c_byte, buffer);
+
+		if((res = uncompress(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) {
+			if(res == Z_MEM_ERROR)
+				ERROR("zlib::uncompress failed, not enough memory\n");
+			else if(res == Z_BUF_ERROR)
+				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
+			else
+				ERROR("zlib::uncompress failed, unknown error %d\n", res);
+			return 0;
+		}
+		if(next)
+			*next = start + offset + c_byte;
+		return bytes;
+	} else {
+		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+		read_bytes(fd, start + offset, c_byte, (char *) block);
+		if(next)
+			*next = start + offset + c_byte;
+		return c_byte;
+	}
+}
+
+
+int scan_inode_table(int fd, long long start, long long end, long long root_inode_start, int root_inode_offset,
+		squashfs_super_block *sBlk,
+		squashfs_inode_header *dir_inode, unsigned char **inode_table, unsigned int *root_inode_block,
+		unsigned int *root_inode_size, long long *uncompressed_file, unsigned int *uncompressed_directory,
+		int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count)
+{
+	unsigned char *cur_ptr;
+	int byte, bytes = 0, size = 0, files = 0;
+	squashfs_reg_inode_header inode;
+	unsigned int directory_start_block;
+
+	TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start 0x%llx\n", start, end, root_inode_start);
+	while(start < end) {
+		if(start == root_inode_start) {
+			TRACE("scan_inode_table: read compressed block 0x%llx containing root inode\n", start);
+			*root_inode_block = bytes;
+		}
+		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
+				((*inode_table = realloc(*inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL))
+			return FALSE;
+		TRACE("scan_inode_table: reading block 0x%llx\n", start);
+		if((byte = read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) {
+			free(*inode_table);
+			return FALSE;
+		}
+		bytes += byte;
+	}
+
+	/*
+	 * Read last inode entry which is the root directory inode, and obtain the last
+	 * directory start block index.  This is used when calculating the total uncompressed
+	 * directory size.  The directory bytes in the last block will be counted as normal.
+	 *
+	 * The root inode is ignored in the inode scan.  This ensures there is
+	 * always enough bytes left to read a regular file inode entry
+	 */
+	*root_inode_size = bytes - (*root_inode_block + root_inode_offset);
+	bytes = *root_inode_block + root_inode_offset;
+	if(swap) {
+		squashfs_base_inode_header sinode;
+		memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->base));
+		SQUASHFS_SWAP_BASE_INODE_HEADER(&dir_inode->base, &sinode, sizeof(squashfs_base_inode_header));
+	} else
+		memcpy(&dir_inode->base, *inode_table + bytes, sizeof(dir_inode->base));
+	if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE) {
+		if(swap) {
+			squashfs_dir_inode_header sinode;
+			memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->dir));
+			SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode->dir, &sinode);
+		} else
+			memcpy(&dir_inode->dir, *inode_table + bytes, sizeof(dir_inode->dir));
+		directory_start_block = dir_inode->dir.start_block;
+	} else {
+		if(swap) {
+			squashfs_ldir_inode_header sinode;
+			memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->ldir));
+			SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode->ldir, &sinode);
+		} else
+			memcpy(&dir_inode->ldir, *inode_table + bytes, sizeof(dir_inode->ldir));
+		directory_start_block = dir_inode->ldir.start_block;
+	}
+
+	for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) {
+		if(swap) {
+			squashfs_reg_inode_header sinode;
+			memcpy(&sinode, cur_ptr, sizeof(inode));
+			SQUASHFS_SWAP_REG_INODE_HEADER(&inode, &sinode);
+		} else
+			memcpy(&inode, cur_ptr, sizeof(inode));
+
+		TRACE("scan_inode_table: processing inode @ byte position 0x%x, type 0x%x\n", cur_ptr - *inode_table,
+				inode.inode_type);
+		switch(inode.inode_type) {
+			case SQUASHFS_FILE_TYPE: {
+				int frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size;
+				int blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size
+					+ sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >>
+					sBlk->block_log;
+				long long file_bytes = 0;
+				int i, start = inode.start_block;
+				unsigned int *block_list;
+
+				TRACE("scan_inode_table: regular file, file_size %lld, blocks %d\n", inode.file_size, blocks);
+
+				if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) {
+					ERROR("Out of memory in block list malloc\n");
+					goto failed;
+				}
+
+				cur_ptr += sizeof(inode);
+				if(swap) {
+					unsigned int sblock_list[blocks];
+					memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int));
+					SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
+				} else
+					memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int));
+
+				*uncompressed_file += inode.file_size;
+				(*file_count) ++;
+
+				for(i = 0; i < blocks; i++)
+					file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
+
+	                        add_file(start, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes);
+				cur_ptr += blocks * sizeof(unsigned int);
+				break;
+			}	
+			case SQUASHFS_LREG_TYPE: {
+				squashfs_lreg_inode_header inode;
+				int frag_bytes;
+				int blocks;
+				long long file_bytes = 0;
+				int i, start;
+				unsigned int *block_list;
+
+				if(swap) {
+					squashfs_lreg_inode_header sinodep;
+					memcpy(&sinodep, cur_ptr, sizeof(sinodep));
+					SQUASHFS_SWAP_LREG_INODE_HEADER(&inode, &sinodep);
+				} else
+					memcpy(&inode, cur_ptr, sizeof(inode));
+
+				TRACE("scan_inode_table: extended regular file, file_size %lld, blocks %d\n", inode.file_size, blocks);
+
+				cur_ptr += sizeof(inode);
+				frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size;
+				blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size
+					+ sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >>
+					sBlk->block_log;
+				start = inode.start_block;
+
+				if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) {
+					ERROR("Out of memory in block list malloc\n");
+					goto failed;
+				}
+
+				if(swap) {
+					unsigned int sblock_list[blocks];
+					memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int));
+					SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
+				} else
+					memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int));
+
+				*uncompressed_file += inode.file_size;
+				(*file_count) ++;
+
+				for(i = 0; i < blocks; i++)
+					file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
+
+	                        add_file(start, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes);
+				cur_ptr += blocks * sizeof(unsigned int);
+				break;
+			}	
+			case SQUASHFS_SYMLINK_TYPE: {
+				squashfs_symlink_inode_header inodep;
+	
+				if(swap) {
+					squashfs_symlink_inode_header sinodep;
+					memcpy(&sinodep, cur_ptr, sizeof(sinodep));
+					SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep);
+				} else
+					memcpy(&inodep, cur_ptr, sizeof(inodep));
+				(*sym_count) ++;
+				cur_ptr += sizeof(inodep) + inodep.symlink_size;
+				break;
+			}
+			case SQUASHFS_DIR_TYPE: {
+				squashfs_dir_inode_header dir_inode;
+
+				if(swap) {
+					squashfs_dir_inode_header sinode;
+					memcpy(&sinode, cur_ptr, sizeof(dir_inode));
+					SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode, &sinode);
+				} else
+					memcpy(&dir_inode, cur_ptr, sizeof(dir_inode));
+				if(dir_inode.start_block < directory_start_block)
+					*uncompressed_directory += dir_inode.file_size;
+				(*dir_count) ++;
+				cur_ptr += sizeof(squashfs_dir_inode_header);
+				break;
+			}
+			case SQUASHFS_LDIR_TYPE: {
+				squashfs_ldir_inode_header dir_inode;
+				int i;
+
+				if(swap) {
+					squashfs_ldir_inode_header sinode;
+					memcpy(&sinode, cur_ptr, sizeof(dir_inode));
+					SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode, &sinode);
+				} else
+					memcpy(&dir_inode, cur_ptr, sizeof(dir_inode));
+				if(dir_inode.start_block < directory_start_block)
+					*uncompressed_directory += dir_inode.file_size;
+				(*dir_count) ++;
+				cur_ptr += sizeof(squashfs_ldir_inode_header);
+				for(i = 0; i < dir_inode.i_count; i++) {
+					squashfs_dir_index index;
+					if(swap) {
+						squashfs_dir_index sindex;
+						memcpy(&sindex, cur_ptr, sizeof(squashfs_dir_index));
+						SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
+					} else
+						memcpy(&index, cur_ptr, sizeof(squashfs_dir_index));
+					cur_ptr += sizeof(squashfs_dir_index) + index.size + 1;
+				}
+				break;
+			}
+		 	case SQUASHFS_BLKDEV_TYPE:
+		 	case SQUASHFS_CHRDEV_TYPE:
+				(*dev_count) ++;
+				cur_ptr += sizeof(squashfs_dev_inode_header);
+				break;
+
+			case SQUASHFS_FIFO_TYPE:
+				(*fifo_count) ++;
+				cur_ptr += sizeof(squashfs_ipc_inode_header);
+				break;
+			case SQUASHFS_SOCKET_TYPE:
+				(*sock_count) ++;
+				cur_ptr += sizeof(squashfs_ipc_inode_header);
+				break;
+		 	default:
+				ERROR("Unknown inode type %d in scan_inode_table!\n", inode.inode_type);
+				goto failed;
+		}
+	}
+	
+	return files;
+
+
+failed:
+	free(*inode_table);
+	return FALSE;
+}
+
+
+int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source)
+{
+	read_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) sBlk);
+
+	/* Check it is a SQUASHFS superblock */
+	swap = 0;
+	if(sBlk->s_magic != SQUASHFS_MAGIC) {
+		if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) {
+			squashfs_super_block sblk;
+			ERROR("Reading a different endian SQUASHFS filesystem on %s - ignoring -le/-be options\n", source);
+			SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk);
+			memcpy(sBlk, &sblk, sizeof(squashfs_super_block));
+			swap = 1;
+		} else  {
+			ERROR("Can't find a SQUASHFS superblock on %s\n", source);
+			goto failed_mount;
+		}
+	}
+
+	/* Check the MAJOR & MINOR versions */
+	if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
+		if(sBlk->s_major < 3)
+			ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem.  Appending\nto SQUASHFS %d.%d filesystems is not supported.  Please convert it to a SQUASHFS 3.0 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
+		else
+			ERROR("Major/Minor mismatch, filesystem on %s is %d.%d, I support 3.0\n",
+				source, sBlk->s_major, sBlk->s_minor);
+		goto failed_mount;
+	}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	*be = !swap;
+#else
+	*be = swap;
+#endif
+
+	printf("Found a valid SQUASHFS superblock on %s.\n", source);
+	printf("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
+	printf("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
+	printf("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
+	printf("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not");
+	printf("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : "");
+	printf("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not");
+	printf("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not");
+	printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0));
+	printf("\tBlock size %d\n", sBlk->block_size);
+	printf("\tNumber of fragments %d\n", sBlk->fragments);
+	printf("\tNumber of inodes %d\n", sBlk->inodes);
+	printf("\tNumber of uids %d\n", sBlk->no_uids);
+	printf("\tNumber of gids %d\n", sBlk->no_guids);
+	TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start);
+	TRACE("sBlk->directory_table_start %llx\n", sBlk->directory_table_start);
+	TRACE("sBlk->uid_start %llx\n", sBlk->uid_start);
+	TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start);
+	printf("\n");
+
+	return TRUE;
+
+failed_mount:
+	return FALSE;
+}
+
+
+unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size,
+		unsigned int *last_directory_block, squashfs_super_block *sBlk, void (push_directory_entry)(char *, squashfs_inode, int, int))
+{
+	squashfs_dir_header dirh;
+	char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
+	squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
+	unsigned char *directory_table = NULL;
+	int byte, bytes = 0, dir_count;
+	long long start = sBlk->directory_table_start + directory_start_block, last_start_block; 
+
+	size += offset;
+	if((directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1))) == NULL)
+		return NULL;
+	while(bytes < size) {
+		TRACE("squashfs_readdir: reading block 0x%llx, bytes read so far %d\n", start, bytes);
+		last_start_block = start;
+		if((byte = read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) {
+			free(directory_table);
+			return NULL;
+		}
+		bytes += byte;
+	}
+
+	if(!root_entries)
+		goto all_done;
+
+	bytes = offset;
+ 	while(bytes < size) {			
+		if(swap) {
+			squashfs_dir_header sdirh;
+			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
+			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
+		} else
+			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
+
+		dir_count = dirh.count + 1;
+		TRACE("squashfs_readdir: Read directory header @ byte position 0x%x, 0x%x directory entries\n", bytes, dir_count);
+		bytes += sizeof(dirh);
+
+		while(dir_count--) {
+			if(swap) {
+				squashfs_dir_entry sdire;
+				memcpy(&sdire, directory_table + bytes, sizeof(sdire));
+				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
+			} else
+				memcpy(dire, directory_table + bytes, sizeof(dire));
+			bytes += sizeof(*dire);
+
+			memcpy(dire->name, directory_table + bytes, dire->size + 1);
+			dire->name[dire->size + 1] = '\0';
+			TRACE("squashfs_readdir: pushing directory entry %s, inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type);
+			push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dire->inode_number, dire->type);
+			bytes += dire->size + 1;
+		}
+	}
+
+all_done:
+	*last_directory_block = (unsigned int) last_start_block - sBlk->directory_table_start;
+	return directory_table;
+}
+
+
+int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_entry **fragment_table)
+{
+	int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
+	squashfs_fragment_index fragment_table_index[indexes];
+
+	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start);
+	if(sBlk->fragments == 0)
+		return 1;
+
+	if((*fragment_table = (squashfs_fragment_entry *) malloc(sBlk->fragments * sizeof(squashfs_fragment_entry))) == NULL) {
+		ERROR("Failed to allocate fragment table\n");
+		return 0;
+	}
+
+	if(swap) {
+		squashfs_fragment_index sfragment_table_index[indexes];
+
+		read_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) sfragment_table_index);
+		SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes);
+	} else
+		read_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index);
+
+	for(i = 0; i < indexes; i++) {
+		int length = read_block(fd, fragment_table_index[i], NULL, ((unsigned char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk);
+		TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length);
+	}
+
+	if(swap) {
+		squashfs_fragment_entry sfragment;
+		for(i = 0; i < sBlk->fragments; i++) {
+			SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&(*fragment_table)[i]));
+			memcpy((char *) &(*fragment_table)[i], (char *) &sfragment, sizeof(squashfs_fragment_entry));
+		}
+	}
+
+	return 1;
+}
+
+
+long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
+		char **data_cache, char **cdirectory_table, char **directory_data_cache,
+		unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
+		unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
+		int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
+		unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
+		long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
+		unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
+		void (push_directory_entry)(char *, squashfs_inode, int, int), squashfs_fragment_entry **fragment_table)
+{
+	unsigned char *inode_table = NULL, *directory_table;
+	long long start = sBlk->inode_table_start, end = sBlk->directory_table_start, root_inode_start = start +
+		SQUASHFS_INODE_BLK(sBlk->root_inode);
+	unsigned int root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode), root_inode_block, files;
+	squashfs_inode_header inode;
+
+	printf("Scanning existing filesystem...\n");
+
+	if(read_fragment_table(fd, sBlk, fragment_table) == 0)
+		goto error;
+
+	if((files = scan_inode_table(fd, start, end, root_inode_start, root_inode_offset, sBlk, &inode, &inode_table,
+			&root_inode_block, root_inode_size, uncompressed_file, uncompressed_directory, file_count, sym_count,
+			dev_count, dir_count, fifo_count, sock_count)) == 0) {
+		ERROR("read_filesystem: inode table read failed\n");
+		goto error;
+	}
+
+	*uncompressed_inode = root_inode_block;
+
+	printf("Read existing filesystem, %d inodes scanned\n", files);
+
+	if(inode.base.inode_type == SQUASHFS_DIR_TYPE || inode.base.inode_type == SQUASHFS_LDIR_TYPE) {
+		if(inode.base.inode_type == SQUASHFS_DIR_TYPE) {
+			*inode_dir_start_block = inode.dir.start_block;
+			*inode_dir_offset = inode.dir.offset;
+			*inode_dir_file_size = inode.dir.file_size - 3;
+			*inode_dir_inode_number = inode.dir.inode_number;
+			*inode_dir_parent_inode = inode.dir.parent_inode;
+		} else {
+			*inode_dir_start_block = inode.ldir.start_block;
+			*inode_dir_offset = inode.ldir.offset;
+			*inode_dir_file_size = inode.ldir.file_size - 3;
+			*inode_dir_inode_number = inode.ldir.inode_number;
+			*inode_dir_parent_inode = inode.ldir.parent_inode;
+		}
+
+		if((directory_table = squashfs_readdir(fd, !root_name, *inode_dir_start_block, *inode_dir_offset,
+				*inode_dir_file_size, last_directory_block, sBlk, push_directory_entry)) == NULL) {
+			ERROR("read_filesystem: Could not read root directory\n");
+			goto error;
+		}
+
+		root_inode_start -= start;
+		if((*cinode_table = (char *) malloc(root_inode_start)) == NULL) {
+			ERROR("read_filesystem: failed to alloc space for existing filesystem inode table\n");
+			goto error;
+		}
+	       	read_bytes(fd, start, root_inode_start, *cinode_table);
+
+		if((*cdirectory_table = (char *) malloc(*last_directory_block)) == NULL) {
+			ERROR("read_filesystem: failed to alloc space for existing filesystem directory table\n");
+			goto error;
+		}
+		read_bytes(fd, sBlk->directory_table_start, *last_directory_block, *cdirectory_table);
+
+		if((*data_cache = (char *) malloc(root_inode_offset + *root_inode_size)) == NULL) {
+			ERROR("read_filesystem: failed to alloc inode cache\n");
+			goto error;
+		}
+		memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset + *root_inode_size);
+
+		if((*directory_data_cache = (char *) malloc(*inode_dir_offset + *inode_dir_file_size)) == NULL) {
+			ERROR("read_filesystem: failed to alloc directory cache\n");
+			goto error;
+		}
+		memcpy(*directory_data_cache, directory_table, *inode_dir_offset + *inode_dir_file_size);
+
+		if(!swap)
+			read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids);
+		else {
+			squashfs_uid uids_copy[sBlk->no_uids];
+
+			read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids_copy);
+			SQUASHFS_SWAP_DATA(uids, uids_copy, sBlk->no_uids, sizeof(squashfs_uid) * 8);
+		}
+
+		if(!swap)
+			read_bytes(fd, sBlk->guid_start, sBlk->no_guids * sizeof(squashfs_uid), (char *) guids);
+		else {
+			squashfs_uid guids_copy[sBlk->no_guids];
+
+			read_bytes(fd, sBlk->guid_start, sBlk->no_guids * sizeof(squashfs_uid), (char *) guids_copy);
+			SQUASHFS_SWAP_DATA(guids, guids_copy, sBlk->no_guids, sizeof(squashfs_uid) * 8);
+		}
+		*uid_count = sBlk->no_uids;
+		*guid_count = sBlk->no_guids;
+
+		free(inode_table);
+		free(directory_table);
+		return sBlk->inode_table_start;
+	}
+
+error:
+	return 0;
+}
diff -ruN linux-2.4.20-nc/scripts/squashfs/read_fs.h linux/scripts/squashfs/read_fs.h
--- linux-2.4.20-nc/scripts/squashfs/read_fs.h	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/read_fs.h	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,49 @@
+/*
+ * macros to convert each packed bitfield structure from little endian to big
+ * endian and vice versa.  These are needed when creating a filesystem on a
+ * machine with different byte ordering to the target architecture.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * mksquashfs.h
+ *
+ */
+
+/*
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing architectures
+ */
+#if __BYTE_ORDER == __BIG_ENDIAN
+	/* convert from big endian to little endian */
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
+#else
+	/* convert from little endian to big endian */ 
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
+#endif
+
+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+	int bits;\
+	int b_pos = pos % 8;\
+	unsigned long long val = 0;\
+	unsigned char *s = (unsigned char *)p + (pos / 8);\
+	unsigned char *d = ((unsigned char *) &val) + 7;\
+	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
+		*d-- = *s++;\
+	value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
+}
+#define SQUASHFS_MEMSET(s, d, n)	memset(s, 0, n);
diff -ruN linux-2.4.20-nc/scripts/squashfs/sort.c linux/scripts/squashfs/sort.c
--- linux-2.4.20-nc/scripts/squashfs/sort.c	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/sort.c	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,257 @@
+/*
+ * Create a squashfs filesystem.  This is a highly compressed read only filesystem.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * sort.c
+ */
+
+#define TRUE 1
+#define FALSE 0
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <squashfs_fs.h>
+#include "global.h"
+#include "sort.h"
+
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...)		do { \
+						printf("mksquashfs: "s, ## args); \
+					} while(0)
+#else
+#define TRACE(s, args...)
+#endif
+
+#define INFO(s, args...)		do { \
+						if(!silent) printf("mksquashfs: "s, ## args); \
+					} while(0)
+#define ERROR(s, args...)		do { \
+						fprintf(stderr, s, ## args); \
+					} while(0)
+#define EXIT_MKSQUASHFS()		do { \
+						exit(1); \
+					} while(0)
+#define BAD_ERROR(s, args...)		do {\
+						fprintf(stderr, "FATAL ERROR:" s, ##args);\
+						EXIT_MKSQUASHFS();\
+					} while(0);
+
+int mkisofs_style = -1;
+
+struct sort_info {
+	dev_t			st_dev;
+	ino_t			st_ino;
+	int			priority;
+	struct sort_info	*next;
+};
+
+struct sort_info *sort_info_list[65536];
+
+struct priority_entry {
+	struct dir_ent *dir;
+	struct priority_entry *next;
+};
+
+struct priority_entry *priority_list[65536];
+
+extern int silent;
+extern squashfs_inode write_file(squashfs_inode *inode, struct dir_ent *dir_ent, long long size, int *c_size);
+
+
+int add_priority_list(struct dir_ent *dir, int priority)
+{
+	struct priority_entry *new_priority_entry;
+
+	priority += 32768;
+	if((new_priority_entry = malloc(sizeof(struct priority_entry))) == NULL) {
+		ERROR("Out of memory allocating priority entry\n");
+		return FALSE;
+	}
+
+	new_priority_entry->dir = dir;;
+	new_priority_entry->next = priority_list[priority];
+	priority_list[priority] = new_priority_entry;
+	return TRUE;
+}
+
+
+int get_priority(char *filename, struct stat *buf, int priority)
+{
+	int hash = buf->st_ino & 0xffff;
+	struct sort_info *s;
+
+	for(s = sort_info_list[hash]; s; s = s->next)
+		if((s->st_dev == buf->st_dev) && (s->st_ino == buf->st_ino)) {
+			TRACE("returning priority %d (%s)\n", s->priority, filename);
+			return s->priority;
+		}
+	TRACE("returning priority %d (%s)\n", priority, filename);
+	return priority;
+}
+
+
+#define ADD_ENTRY(buf, priority) {\
+	int hash = buf.st_ino & 0xffff;\
+	struct sort_info *s;\
+	if((s = malloc(sizeof(struct sort_info))) == NULL) {\
+		ERROR("Out of memory allocating sort list entry\n");\
+		return FALSE;\
+	}\
+	s->st_dev = buf.st_dev;\
+	s->st_ino = buf.st_ino;\
+	s->priority = priority;\
+	s->next = sort_info_list[hash];\
+	sort_info_list[hash] = s;\
+	}
+int add_sort_list(char *path, int priority, int source, char *source_path[])
+{
+	int i, n;
+	char filename[4096];
+	struct stat buf;
+
+	TRACE("add_sort_list: filename %s, priority %d\n", path, priority);
+	if(strlen(path) > 1 && strcmp(path + strlen(path) - 2, "/*") == 0)
+		path[strlen(path) - 2] = '\0';
+
+	TRACE("add_sort_list: filename %s, priority %d\n", path, priority);
+re_read:
+	if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0 || mkisofs_style == 1) {
+		if(lstat(path, &buf) == -1)
+			goto error;
+		TRACE("adding filename %s, priority %d, st_dev %llx, st_ino %llx\n", path, priority, buf.st_dev, buf.st_ino);
+		ADD_ENTRY(buf, priority);
+		return TRUE;
+	}
+
+	for(i = 0, n = 0; i < source; i++) {
+		strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
+		if(lstat(filename, &buf) == -1) {
+			if(!(errno == ENOENT || errno == ENOTDIR))
+				goto error;
+			continue;
+		}
+		ADD_ENTRY(buf, priority);
+		n ++;
+	}
+
+	if(n == 0 && mkisofs_style == -1 && lstat(path, &buf) != -1) {
+		ERROR("WARNING: Mkisofs style sortlist detected! This is supported but please\n");
+		ERROR("convert to mksquashfs style sortlist! A sortlist entry ");
+	        ERROR("should be\neither absolute (starting with ");
+		ERROR("'/') start with './' or '../' (taken to be\nrelative to $PWD), otherwise it ");
+		ERROR("is assumed the entry is relative to one\nof the source directories, i.e. with ");
+		ERROR("\"mksquashfs test test.sqsh\",\nthe sortlist ");
+		ERROR("entry \"file\" is assumed to be inside the directory test.\n\n");
+		mkisofs_style = 1;
+		goto re_read;
+	}
+
+	mkisofs_style = 0;
+
+	if(n == 1)
+		return TRUE;
+	if(n > 1)
+		BAD_ERROR(" Ambiguous sortlist entry \"%s\"\n\nIt maps to more than one source entry!  Please use an absolute path.\n", path);
+
+error:
+        fprintf(stderr, "Cannot stat sortlist entry \"%s\"\n", path);
+        fprintf(stderr, "This is probably because you're using the wrong file\n");
+        fprintf(stderr, "path relative to the source directories\n");
+        return FALSE;
+}
+
+
+void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf)
+{
+	priority = get_priority(dir->pathname, buf, priority);
+
+	while(dir->current_count < dir->count) {
+		struct dir_ent *dir_ent = dir->list[dir->current_count++];
+		struct stat *buf = &dir_ent->inode->buf;
+		if(dir_ent->data)
+			continue;
+
+		switch(buf->st_mode & S_IFMT) {
+			case S_IFREG:
+				add_priority_list(dir_ent, get_priority(dir_ent->pathname, buf, priority));
+				break;
+			case S_IFDIR:
+				generate_file_priorities(dir_ent->dir, priority, buf);
+				break;
+		}
+	}
+	dir->current_count = 0;
+}
+
+
+int read_sort_file(char *filename, int source, char *source_path[])
+{
+	FILE *fd;
+	char sort_filename[16385];
+	int priority;
+
+	if((fd = fopen(filename, "r")) == NULL) {
+		perror("Could not open sort_list file...");
+		return FALSE;
+	}
+	while(fscanf(fd, "%s %d", sort_filename, &priority) != EOF)
+		if(priority >= -32768 && priority <= 32767)
+			add_sort_list(sort_filename, priority, source, source_path);
+		else
+			ERROR("Sort file %s, priority %d outside range of -32767:32768 - skipping...\n", sort_filename, priority);
+	fclose(fd);
+	return TRUE;
+}
+
+
+void sort_files_and_write(struct dir_info *dir)
+{
+	int i;
+	struct priority_entry *entry;
+	squashfs_inode inode;
+	int duplicate_file;
+
+	generate_file_priorities(dir, 0, &dir->dir_ent->inode->buf);
+
+	for(i = 65535; i >= 0; i--)
+		for(entry = priority_list[i]; entry; entry = entry->next) {
+			TRACE("%d: %s\n", i - 32768, entry->dir->pathname);
+			if(entry->dir->inode->inode == SQUASHFS_INVALID_BLK) {
+				if(write_file(&inode, entry->dir, entry->dir->inode->buf.st_size,
+							&duplicate_file)) {
+					INFO("file %s, uncompressed size %lld bytes %s\n",
+						entry->dir->pathname,
+						entry->dir->inode->buf.st_size,
+						duplicate_file ? "DUPLICATE" : "");
+					entry->dir->inode->inode = inode;
+					entry->dir->inode->type = SQUASHFS_FILE_TYPE;
+				}
+			} else
+				INFO("file %s, uncompressed size %lld bytes LINK\n",
+					entry->dir->pathname, entry->dir->inode->buf.st_size);
+		}
+}
diff -ruN linux-2.4.20-nc/scripts/squashfs/sort.h linux/scripts/squashfs/sort.h
--- linux-2.4.20-nc/scripts/squashfs/sort.h	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/sort.h	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,56 @@
+#ifndef SORT_H 
+#define SORT_H
+
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * sort.h
+ */
+
+struct dir_info {
+	char			*pathname;
+	unsigned int		count;
+	unsigned int		directory_count;
+	unsigned int		current_count;
+	unsigned int		byte_count;
+	char			dir_is_ldir;
+	struct dir_ent		*dir_ent;
+	struct dir_ent		**list;
+	DIR			*linuxdir;
+};
+
+struct dir_ent {
+	char			*name;
+	char			*pathname;
+	struct inode_info	*inode;
+	struct dir_info		*dir;
+	struct dir_info		*our_dir;
+	struct old_root_entry_info *data;
+};
+
+struct inode_info {
+	unsigned int		nlink;
+	struct stat		buf;
+	squashfs_inode		inode;
+	unsigned int		type;
+	unsigned int		inode_number;
+	struct inode_info	*next;
+};
+#endif
diff -ruN linux-2.4.20-nc/scripts/squashfs/squashfs_fs.h linux/scripts/squashfs/squashfs_fs.h
--- linux-2.4.20-nc/scripts/squashfs/squashfs_fs.h	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/squashfs_fs.h	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,877 @@
+#ifndef SQUASHFS_FS
+#define SQUASHFS_FS
+
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs.h
+ */
+
+#define SQUASHFS_MAJOR			3
+#define SQUASHFS_MINOR			0
+#define SQUASHFS_MAGIC			0x73717368
+#define SQUASHFS_MAGIC_SWAP		0x68737173
+#define SQUASHFS_START			0
+
+/* size of metadata (inode and directory) blocks */
+#define SQUASHFS_METADATA_SIZE		8192
+#define SQUASHFS_METADATA_LOG		13
+
+/* default size of data blocks */
+#define SQUASHFS_FILE_SIZE		65536
+#define SQUASHFS_FILE_LOG		16
+
+#define SQUASHFS_FILE_MAX_SIZE		65536
+
+/* Max number of uids and gids */
+#define SQUASHFS_UIDS			256
+#define SQUASHFS_GUIDS			255
+
+/* Max length of filename (not 255) */
+#define SQUASHFS_NAME_LEN		256
+
+#define SQUASHFS_INVALID		((long long) 0xffffffffffff)
+#define SQUASHFS_INVALID_FRAG		((unsigned int) 0xffffffff)
+#define SQUASHFS_INVALID_BLK		((long long) -1)
+#define SQUASHFS_USED_BLK		((long long) -2)
+
+/* Filesystem flags */
+#define SQUASHFS_NOI			0
+#define SQUASHFS_NOD			1
+#define SQUASHFS_CHECK			2
+#define SQUASHFS_NOF			3
+#define SQUASHFS_NO_FRAG		4
+#define SQUASHFS_ALWAYS_FRAG		5
+#define SQUASHFS_DUPLICATE		6
+
+#define SQUASHFS_BIT(flag, bit)		((flag >> bit) & 1)
+
+#define SQUASHFS_UNCOMPRESSED_INODES(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOI)
+
+#define SQUASHFS_UNCOMPRESSED_DATA(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOD)
+
+#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOF)
+
+#define SQUASHFS_NO_FRAGMENTS(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_NO_FRAG)
+
+#define SQUASHFS_ALWAYS_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_ALWAYS_FRAG)
+
+#define SQUASHFS_DUPLICATES(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_DUPLICATE)
+
+#define SQUASHFS_CHECK_DATA(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_CHECK)
+
+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
+		duplicate_checking)	(noi | (nod << 1) | (check_data << 2) \
+		| (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
+		(duplicate_checking << 6))
+
+/* Max number of types and file types */
+#define SQUASHFS_DIR_TYPE		1
+#define SQUASHFS_FILE_TYPE		2
+#define SQUASHFS_SYMLINK_TYPE		3
+#define SQUASHFS_BLKDEV_TYPE		4
+#define SQUASHFS_CHRDEV_TYPE		5
+#define SQUASHFS_FIFO_TYPE		6
+#define SQUASHFS_SOCKET_TYPE		7
+#define SQUASHFS_LDIR_TYPE		8
+#define SQUASHFS_LREG_TYPE		9
+
+/* 1.0 filesystem type definitions */
+#define SQUASHFS_TYPES			5
+#define SQUASHFS_IPC_TYPE		0
+
+/* Flag whether block is compressed or uncompressed, bit is set if block is
+ * uncompressed */
+#define SQUASHFS_COMPRESSED_BIT		(1 << 15)
+
+#define SQUASHFS_COMPRESSED_SIZE(B)	(((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
+		(B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
+
+#define SQUASHFS_COMPRESSED(B)		(!((B) & SQUASHFS_COMPRESSED_BIT))
+
+#define SQUASHFS_COMPRESSED_BIT_BLOCK		(1 << 24)
+
+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)	(((B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
+
+#define SQUASHFS_COMPRESSED_BLOCK(B)	(!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
+
+/*
+ * Inode number ops.  Inodes consist of a compressed block number, and an
+ * uncompressed  offset within that block
+ */
+#define SQUASHFS_INODE_BLK(a)		((unsigned int) ((a) >> 16))
+
+#define SQUASHFS_INODE_OFFSET(a)	((unsigned int) ((a) & 0xffff))
+
+#define SQUASHFS_MKINODE(A, B)		((squashfs_inode_t)(((squashfs_inode_t) (A)\
+					<< 16) + (B)))
+
+/* Compute 32 bit VFS inode number from squashfs inode number */
+#define SQUASHFS_MK_VFS_INODE(a, b)	((unsigned int) (((a) << 8) + \
+					((b) >> 2) + 1))
+/* XXX */
+
+/* Translate between VFS mode and squashfs mode */
+#define SQUASHFS_MODE(a)		((a) & 0xfff)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES(A)	(A * sizeof(struct squashfs_fragment_entry))
+
+#define SQUASHFS_FRAGMENT_INDEX(A)	(SQUASHFS_FRAGMENT_BYTES(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)	(SQUASHFS_FRAGMENT_BYTES(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES(A)	((SQUASHFS_FRAGMENT_BYTES(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)	(SQUASHFS_FRAGMENT_INDEXES(A) *\
+						sizeof(long long))
+
+#define SQUASHFS_CACHED_FRAGMENTS	3
+
+/* cached data constants for filesystem */
+#define SQUASHFS_CACHED_BLKS		8
+
+#define SQUASHFS_MAX_FILE_SIZE_LOG	64
+
+#define SQUASHFS_MAX_FILE_SIZE		((long long) 1 << \
+					(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
+
+#define SQUASHFS_MARKER_BYTE		0xff
+
+/*
+ * definitions for structures on disk
+ */
+
+typedef long long		squashfs_block_t;
+typedef long long		squashfs_inode_t;
+
+struct squashfs_super_block {
+	unsigned int		s_magic;
+	unsigned int		inodes;
+	unsigned int		bytes_used_2;
+	unsigned int		uid_start_2;
+	unsigned int		guid_start_2;
+	unsigned int		inode_table_start_2;
+	unsigned int		directory_table_start_2;
+	unsigned int		s_major:16;
+	unsigned int		s_minor:16;
+	unsigned int		block_size_1:16;
+	unsigned int		block_log:16;
+	unsigned int		flags:8;
+	unsigned int		no_uids:8;
+	unsigned int		no_guids:8;
+	unsigned int		mkfs_time /* time of filesystem creation */;
+	squashfs_inode_t	root_inode;
+	unsigned int		block_size;
+	unsigned int		fragments;
+	unsigned int		fragment_table_start_2;
+	long long		bytes_used;
+	long long		uid_start;
+	long long		guid_start;
+	long long		inode_table_start;
+	long long		directory_table_start;
+	long long		fragment_table_start;
+	long long		unused;
+} __attribute__ ((packed));
+
+struct squashfs_dir_index {
+	unsigned int		index;
+	unsigned int		start_block;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+#define SQUASHFS_BASE_INODE_HEADER		\
+	unsigned int		inode_type:4;	\
+	unsigned int		mode:12;	\
+	unsigned int		uid:8;		\
+	unsigned int		guid:8;		\
+	unsigned int		mtime;		\
+	unsigned int 		inode_number;
+
+struct squashfs_base_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_lreg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	long long		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		parent_inode;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		i_count:16;
+	unsigned int		parent_inode;
+	struct squashfs_dir_index	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header {
+	struct squashfs_base_inode_header	base;
+	struct squashfs_dev_inode_header	dev;
+	struct squashfs_symlink_inode_header	symlink;
+	struct squashfs_reg_inode_header	reg;
+	struct squashfs_lreg_inode_header	lreg;
+	struct squashfs_dir_inode_header	dir;
+	struct squashfs_ldir_inode_header	ldir;
+	struct squashfs_ipc_inode_header	ipc;
+};
+	
+struct squashfs_dir_entry {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	int			inode_number:16;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_header {
+	unsigned int		count:8;
+	unsigned int		start_block;
+	unsigned int		inode_number;
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry {
+	long long		start_block;
+	unsigned int		size;
+	unsigned int		unused;
+} __attribute__ ((packed));
+
+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
+extern int squashfs_uncompress_init(void);
+extern int squashfs_uncompress_exit(void);
+
+/*
+ * macros to convert each packed bitfield structure from little endian to big
+ * endian and vice versa.  These are needed when creating or using a filesystem
+ * on a machine with different byte ordering to the target architecture.
+ *
+ */
+
+#define SQUASHFS_SWAP_START \
+	int bits;\
+	int b_pos;\
+	unsigned long long val;\
+	unsigned char *s;\
+	unsigned char *d;
+
+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
+	SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
+	SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
+	SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
+	SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
+	SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
+	SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
+	SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
+	SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
+	SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
+	SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
+	SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
+	SQUASHFS_SWAP((s)->flags, d, 288, 8);\
+	SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
+	SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
+	SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
+	SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
+	SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
+	SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
+	SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
+	SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
+	SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
+	SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
+	SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
+	SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
+	SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
+	SQUASHFS_SWAP((s)->unused, d, 888, 64);\
+}
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ipc_inode_header))\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dev_inode_header)); \
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_symlink_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_reg_inode_header));\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 192, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
+}
+
+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_lreg_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 224, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 147, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ldir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 155, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
+	SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
+	SQUASHFS_SWAP((s)->index, d, 0, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
+	SQUASHFS_SWAP((s)->size, d, 64, 8);\
+}
+
+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+	SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
+	SQUASHFS_SWAP((s)->size, d, 64, 32);\
+}
+
+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 2);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			16)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
+}
+
+#define SQUASHFS_SWAP_INTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 4);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			32)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
+}
+
+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			64)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
+}
+
+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * bits / 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			bits)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+
+struct squashfs_base_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		type:4;
+	unsigned int		offset:4;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 4);\
+	SQUASHFS_SWAP((s)->guid, d, 20, 4);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_ipc_inode_header_1));\
+	SQUASHFS_SWAP((s)->type, d, 24, 4);\
+	SQUASHFS_SWAP((s)->offset, d, 28, 4);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dev_inode_header_1));\
+	SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_1));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_reg_inode_header_1));\
+	SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dir_inode_header_1));\
+	SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 43, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
+}
+
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+
+struct squashfs_dir_index_2 {
+	unsigned int		index:27;
+	unsigned int		start_block:29;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+struct squashfs_base_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+	unsigned int		i_count:16;
+	struct squashfs_dir_index_2	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header_2 {
+	struct squashfs_base_inode_header_2	base;
+	struct squashfs_dev_inode_header_2	dev;
+	struct squashfs_symlink_inode_header_2	symlink;
+	struct squashfs_reg_inode_header_2	reg;
+	struct squashfs_dir_inode_header_2	dir;
+	struct squashfs_ldir_inode_header_2	ldir;
+	struct squashfs_ipc_inode_header_2	ipc;
+};
+	
+struct squashfs_dir_header_2 {
+	unsigned int		count:8;
+	unsigned int		start_block:24;
+} __attribute__ ((packed));
+
+struct squashfs_dir_entry_2 {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry_2 {
+	unsigned int		start_block;
+	unsigned int		size;
+} __attribute__ ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
+	SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dev_inode_header_2)); \
+	SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_2));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_reg_inode_header_2));\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
+	SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 128, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 51, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_ldir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 59, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
+	SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
+	SQUASHFS_SWAP((s)->index, d, 0, 27);\
+	SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
+	SQUASHFS_SWAP((s)->size, d, 56, 8);\
+}
+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
+	SQUASHFS_SWAP((s)->size, d, 32, 32);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES_2(A)	(A * sizeof(struct squashfs_fragment_entry_2))
+
+#define SQUASHFS_FRAGMENT_INDEX_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES_2(A)	((SQUASHFS_FRAGMENT_BYTES_2(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)	(SQUASHFS_FRAGMENT_INDEXES_2(A) *\
+						sizeof(int))
+
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing
+ * architectures
+ */
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+	/* convert from little endian to big endian */
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, b_pos)
+#else
+	/* convert from big endian to little endian */ 
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, 64 - tbits - b_pos)
+#endif
+
+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+	b_pos = pos % 8;\
+	val = 0;\
+	s = (unsigned char *)p + (pos / 8);\
+	d = ((unsigned char *) &val) + 7;\
+	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
+		*d-- = *s++;\
+	value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
+}
+
+#define SQUASHFS_MEMSET(s, d, n)	memset(s, 0, n);
+
+#endif
+#endif
diff -ruN linux-2.4.20-nc/scripts/squashfs/unsquashfs.c linux/scripts/squashfs/unsquashfs.c
--- linux-2.4.20-nc/scripts/squashfs/unsquashfs.c	1969-12-31 16:00:00.000000000 -0800
+++ linux/scripts/squashfs/unsquashfs.c	2006-06-19 15:25:16.000000000 -0700
@@ -0,0 +1,946 @@
+/*
+ * Unsquash a squashfs filesystem.  This is a highly compressed read only filesystem.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ *  Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * unsquash.c
+ */
+
+#define TRUE 1
+#define FALSE 0
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <zlib.h>
+#include <sys/mman.h>
+#include <utime.h>
+
+#ifndef linux
+#define __BYTE_ORDER BYTE_ORDER
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#else
+#include <endian.h>
+#endif
+
+#include <squashfs_fs.h>
+#include "read_fs.h"
+#include "global.h"
+
+#include <stdlib.h>
+
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...)		do { \
+						printf("mksquashfs: "s, ## args); \
+					} while(0)
+#else
+#define TRACE(s, args...)
+#endif
+
+#define ERROR(s, args...)		do { \
+						fprintf(stderr, s, ## args); \
+					} while(0)
+
+#define EXIT_UNSQUASH(s, args...)	do { \
+						fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \
+					} while(0)
+
+struct hash_table_entry {
+	int	start;
+	int	bytes;
+	struct hash_table_entry *next;
+};
+
+int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, dev_count = 0, fifo_count = 0;
+char *inode_table = NULL, *directory_table = NULL;
+struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
+int fd;
+squashfs_fragment_entry *fragment_table;
+unsigned int *uid_table, *guid_table;
+unsigned int cached_frag = SQUASHFS_INVALID_FRAG;
+char *fragment_data;
+char *file_data;
+char *data;
+unsigned int block_size;
+int lsonly = FALSE, info = FALSE;
+char **created_inode;
+
+#define CALCULATE_HASH(start)	(start & 0xffff)
+
+int add_entry(struct hash_table_entry *hash_table[], int start, int bytes)
+{
+	int hash = CALCULATE_HASH(start);
+	struct hash_table_entry *hash_table_entry;
+
+	if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) {
+		ERROR("add_hash: out of memory in malloc\n");
+		return FALSE;
+	}
+
+	hash_table_entry->start = start;
+	hash_table_entry->bytes = bytes;
+	hash_table_entry->next = hash_table[hash];
+	hash_table[hash] = hash_table_entry;
+
+	return TRUE;
+}
+
+
+int lookup_entry(struct hash_table_entry *hash_table[], int start)
+{
+	int hash = CALCULATE_HASH(start);
+	struct hash_table_entry *hash_table_entry;
+
+	for(hash_table_entry = hash_table[hash]; hash_table_entry; hash_table_entry = hash_table_entry->next)
+		if(hash_table_entry->start == start)
+			return hash_table_entry->bytes;
+
+	return -1;
+}
+
+
+int read_bytes(long long byte, int bytes, char *buff)
+{
+	off_t off = byte;
+
+	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes);
+
+	if(lseek(fd, off, SEEK_SET) == -1) {
+		ERROR("Lseek failed because %s\b", strerror(errno));
+		return FALSE;
+	}
+
+	if(read(fd, buff, bytes) == -1) {
+		ERROR("Read on destination failed because %s\n", strerror(errno));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+int read_block(long long start, long long *next, char *block, squashfs_super_block *sBlk)
+{
+	unsigned short c_byte;
+	int offset = 2;
+	
+	if(swap) {
+		if(read_bytes(start, 2, block) == FALSE)
+			goto failed;
+		((unsigned char *) &c_byte)[1] = block[0];
+		((unsigned char *) &c_byte)[0] = block[1]; 
+	} else 
+		if(read_bytes(start, 2, (char *)&c_byte) == FALSE)
+			goto failed;
+
+	TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed");
+
+	if(SQUASHFS_CHECK_DATA(sBlk->flags))
+		offset = 3;
+	if(SQUASHFS_COMPRESSED(c_byte)) {
+		char buffer[SQUASHFS_METADATA_SIZE];
+		int res;
+		unsigned long bytes = SQUASHFS_METADATA_SIZE;
+
+		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+		if(read_bytes(start + offset, c_byte, buffer) == FALSE)
+			goto failed;
+
+		if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) {
+			if(res == Z_MEM_ERROR)
+				ERROR("zlib::uncompress failed, not enough memory\n");
+			else if(res == Z_BUF_ERROR)
+				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
+			else
+				ERROR("zlib::uncompress failed, unknown error %d\n", res);
+			goto failed;
+		}
+		if(next)
+			*next = start + offset + c_byte;
+		return bytes;
+	} else {
+		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+		if(read_bytes(start + offset, c_byte, block) == FALSE)
+			goto failed;
+		if(next)
+			*next = start + offset + c_byte;
+		return c_byte;
+	}
+
+failed:
+	return FALSE;
+}
+
+
+int read_data_block(long long start, unsigned int size, char *block)
+{
+	int res;
+	unsigned long bytes = block_size;
+	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
+
+	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte), SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed");
+
+	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
+		if(read_bytes(start, c_byte, data) == FALSE)
+			return 0;
+
+		if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte)) != Z_OK) {
+			if(res == Z_MEM_ERROR)
+				ERROR("zlib::uncompress failed, not enough memory\n");
+			else if(res == Z_BUF_ERROR)
+				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
+			else
+				ERROR("zlib::uncompress failed, unknown error %d\n", res);
+			return 0;
+		}
+
+		return bytes;
+	} else {
+		if(read_bytes(start, c_byte, block) == FALSE)
+			return 0;
+
+		return c_byte;
+	}
+}
+
+
+void uncompress_inode_table(long long start, long long end, squashfs_super_block *sBlk)
+{
+	int size = 0, bytes = 0, res;
+
+	while(start < end) {
+		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
+				((inode_table = realloc(inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL))
+			EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n");
+		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
+		add_entry(inode_table_hash, start, bytes);
+		if((res = read_block(start, &start, inode_table + bytes, sBlk)) == 0) {
+			free(inode_table);
+			EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n");
+		}
+		bytes += res;
+	}
+}
+
+
+int set_attributes(char *pathname, unsigned int mode, unsigned int uid, unsigned int guid,
+unsigned int mtime, unsigned int set_mode)
+{
+	struct utimbuf times = { (time_t) mtime, (time_t) mtime };
+
+	if(utime(pathname, &times) == -1) {
+		ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno));
+		return FALSE;
+	}
+
+	if(set_mode && chmod(pathname, (mode_t) mode) == -1) {
+		ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno));
+		return FALSE;
+	}
+
+	if(geteuid() == 0) {
+		uid_t uid_value = (uid_t) uid_table[uid];
+		uid_t guid_value = guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[guid];
+
+		if(chown(pathname, uid_value, guid_value) == -1) {
+			ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+
+void read_uids_guids(squashfs_super_block *sBlk)
+{
+	if((uid_table = malloc((sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int))) == NULL)
+		EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n");
+
+	guid_table = uid_table + sBlk->no_uids;
+
+	if(read_bytes(sBlk->uid_start, (sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int), (char *) uid_table) ==
+			FALSE)
+		EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n");
+}
+
+
+void read_fragment_table(squashfs_super_block *sBlk)
+{
+	int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
+	squashfs_fragment_index fragment_table_index[indexes];
+
+	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start);
+	if(sBlk->fragments == 0)
+		return;
+
+	if((fragment_table = (squashfs_fragment_entry *) malloc(sBlk->fragments * sizeof(squashfs_fragment_entry))) == NULL)
+		EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n");
+
+	if(swap) {
+		squashfs_fragment_index sfragment_table_index[indexes];
+
+		read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) sfragment_table_index);
+		SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes);
+	} else
+		read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index);
+
+	for(i = 0; i < indexes; i++) {
+		int length = read_block(fragment_table_index[i], NULL, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk);
+		TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length);
+	}
+
+	if(swap) {
+		squashfs_fragment_entry sfragment;
+		for(i = 0; i < sBlk->fragments; i++) {
+			SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&fragment_table[i]));
+			memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry));
+		}
+	}
+}
+
+
+char *read_fragment(unsigned int fragment)
+{
+	TRACE("read_fragment: reading fragment %d\n", fragment);
+
+	if(cached_frag == SQUASHFS_INVALID_FRAG || fragment != cached_frag) {
+		squashfs_fragment_entry *fragment_entry = &fragment_table[fragment];
+		if(read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data) == 0) {
+			ERROR("read_fragment: failed to read fragment %d\n", fragment);
+			cached_frag = SQUASHFS_INVALID_FRAG;
+			return NULL;
+		}
+		cached_frag = fragment;
+	}
+
+	return fragment_data;
+}
+
+
+int write_file(char *pathname, unsigned int fragment, unsigned int frag_bytes, unsigned int offset,
+unsigned int blocks, long long start, char *block_ptr, unsigned int mode)
+{
+	unsigned int file_fd, bytes, i;
+	unsigned int *block_list;
+
+	TRACE("write_file: regular file, blocks %d\n", blocks);
+
+	if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) {
+		ERROR("write_file: unable to malloc block list\n");
+		return FALSE;
+	}
+
+	if(swap) {
+		unsigned int sblock_list[blocks];
+		memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int));
+		SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
+	} else
+		memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
+
+	if((file_fd = open(pathname, O_CREAT | O_WRONLY, (mode_t) mode)) == -1) {
+		ERROR("write_file: failed to create file %s, because %s\n", pathname,
+			strerror(errno));
+		free(block_list);
+		return FALSE;
+	}
+
+	for(i = 0; i < blocks; i++) {
+		if((bytes = read_data_block(start, block_list[i], file_data)) == 0) {
+			ERROR("write_file: failed to read data block 0x%llx\n", start);
+			goto failure;
+		}
+
+		if(write(file_fd, file_data, bytes) < bytes) {
+			ERROR("write_file: failed to write data block 0x%llx\n", start);
+			goto failure;
+		}
+
+		start += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
+	}
+
+	if(frag_bytes != 0) {
+		char *fragment_data = read_fragment(fragment);
+
+		if(fragment_data == NULL)
+			goto failure;
+
+		if(write(file_fd, fragment_data + offset, frag_bytes) < frag_bytes) {
+			ERROR("write_file: failed to write fragment %d\n", fragment);
+			goto failure;
+		}
+	}
+
+	close(file_fd);
+	return TRUE;
+
+failure:
+	close(file_fd);
+	free(block_list);
+	return FALSE;
+}
+		
+
+int create_inode(char *pathname, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk)
+{
+	long long start = sBlk->inode_table_start + start_block;
+	squashfs_inode_header header;
+	char *block_ptr;
+	int bytes = lookup_entry(inode_table_hash, start), file_fd;
+
+	TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset);
+
+	if(bytes == -1) {
+		ERROR("create_inode: inode block 0x%llx out of range!\n", start);
+		return FALSE;
+	}
+	block_ptr = inode_table + bytes + offset;
+
+	if(swap) {
+		squashfs_base_inode_header sinode;
+		memcpy(&sinode, block_ptr, sizeof(header.base));
+		SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header));
+	} else
+		memcpy(&header.base, block_ptr, sizeof(header.base));
+
+	if(created_inode[header.base.inode_number - 1]) {
+		TRACE("create_inode: hard link\n");
+		if(link(created_inode[header.base.inode_number - 1], pathname) == -1) {
+			ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno));
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	switch(header.base.inode_type) {
+		case SQUASHFS_FILE_TYPE: {
+			unsigned int frag_bytes;
+			unsigned int blocks;
+			unsigned int offset;
+			long long start;
+			squashfs_reg_inode_header *inode = &header.reg;
+
+			if(swap) {
+				squashfs_reg_inode_header sinode;
+				memcpy(&sinode, block_ptr, sizeof(sinode));
+				SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode);
+			} else
+				memcpy(inode, block_ptr, sizeof(*inode));
+
+			frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size;
+			offset = inode->offset;
+			blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size
+				+ sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >>
+				sBlk->block_log;
+			start = inode->start_block;
+
+			TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks);
+
+			if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start,
+					block_ptr + sizeof(*inode), inode->mode)) {
+				set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE);
+				file_count ++;
+			}
+			break;
+		}	
+		case SQUASHFS_LREG_TYPE: {
+			unsigned int frag_bytes;
+			unsigned int blocks;
+			unsigned int offset;
+			long long start;
+			squashfs_lreg_inode_header *inode = &header.lreg;
+
+			if(swap) {
+				squashfs_lreg_inode_header sinode;
+				memcpy(&sinode, block_ptr, sizeof(sinode));
+				SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode);
+			} else
+				memcpy(inode, block_ptr, sizeof(*inode));
+
+			frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size;
+			offset = inode->offset;
+			blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size
+				+ sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >>
+				sBlk->block_log;
+			start = inode->start_block;
+
+			TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks);
+
+			if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start,
+					block_ptr + sizeof(*inode), inode->mode)) {
+				set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE);
+				file_count ++;
+			}
+			break;
+		}	
+		case SQUASHFS_SYMLINK_TYPE: {
+			squashfs_symlink_inode_header *inodep = &header.symlink;
+			char name[65536];
+
+			if(swap) {
+				squashfs_symlink_inode_header sinodep;
+				memcpy(&sinodep, block_ptr, sizeof(sinodep));
+				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep);
+			} else
+				memcpy(inodep, block_ptr, sizeof(*inodep));
+
+			TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size);
+
+			strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size);
+			name[inodep->symlink_size] = '\0';
+
+			if(symlink(name, pathname) == -1) {
+				ERROR("create_inode: failed to create symlink %s, because %s\n", pathname,
+					strerror(errno));
+				break;
+			}
+
+			if(geteuid() == 0) {
+				uid_t uid_value = (uid_t) uid_table[inodep->uid];
+				uid_t guid_value = inodep->guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[inodep->guid];
+
+				if(lchown(pathname, uid_value, guid_value) == -1)
+					ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
+			}
+
+			sym_count ++;
+			break;
+		}
+ 		case SQUASHFS_BLKDEV_TYPE:
+	 	case SQUASHFS_CHRDEV_TYPE: {
+			squashfs_dev_inode_header *inodep = &header.dev;
+
+			if(swap) {
+				squashfs_dev_inode_header sinodep;
+				memcpy(&sinodep, block_ptr, sizeof(sinodep));
+				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep);
+			} else
+				memcpy(inodep, block_ptr, sizeof(*inodep));
+
+			TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev);
+
+			if(geteuid() == 0) {
+				if(mknod(pathname, inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? S_IFCHR : S_IFBLK,
+							makedev((inodep->rdev >> 8) & 0xff, inodep->rdev & 0xff))
+							== -1) {
+					ERROR("create_inode: failed to create %s device %s, because %s\n",
+						inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block",
+						pathname, strerror(errno));
+					break;
+				}
+				set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, inodep->mtime, TRUE);
+				dev_count ++;
+			} else
+				ERROR("create_inode: could not create %s device %s, because you're not superuser!\n",
+					inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block",
+					pathname, strerror(errno));
+			break;
+			}
+		case SQUASHFS_FIFO_TYPE:
+			TRACE("create_inode: fifo\n");
+
+			if(mknod(pathname, S_IFIFO, 0) == -1) {
+				ERROR("create_inode: failed to create fifo %s, because %s\n",
+					pathname, strerror(errno));
+				break;
+			}
+			set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid,
+				header.base.mtime, TRUE);
+			fifo_count ++;
+			break;
+		case SQUASHFS_SOCKET_TYPE:
+			TRACE("create_inode: socket\n");
+			ERROR("create_inode: socket %s ignored\n", pathname);
+			break;
+		default:
+			ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type);
+			return FALSE;
+	}
+
+	created_inode[header.base.inode_number - 1] = strdup(pathname);
+
+	return TRUE;
+}
+
+
+void uncompress_directory_table(long long start, long long end, squashfs_super_block *sBlk)
+{
+	int bytes = 0, size = 0, res;
+
+	while(start < end) {
+		if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table = realloc(directory_table, size += SQUASHFS_METADATA_SIZE)) == NULL)
+			EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n");
+		TRACE("uncompress_directory_table: reading block 0x%llx\n", start);
+		add_entry(directory_table_hash, start, bytes);
+		if((res = read_block(start, &start, directory_table + bytes, sBlk)) == 0)
+			EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n");
+		bytes += res;
+	}
+}
+
+
+#define DIR_ENT_SIZE	16
+
+struct dir_ent	{
+	char		name[SQUASHFS_NAME_LEN + 1];
+	unsigned int	start_block;
+	unsigned int	offset;
+	unsigned int	type;
+};
+
+struct dir {
+	int		dir_count;
+	int 		cur_entry;
+	unsigned int	mode;
+	unsigned int	uid;
+	unsigned int	guid;
+	unsigned int	mtime;
+	struct dir_ent	*dirs;
+};
+
+
+struct dir *squashfs_openddir(unsigned int block_start, unsigned int offset, squashfs_super_block *sBlk)
+{
+	squashfs_dir_header dirh;
+	char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
+	squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
+	long long start = sBlk->inode_table_start + block_start;
+	char *block_ptr;
+	int bytes = lookup_entry(inode_table_hash, start);
+	squashfs_inode_header header;
+	int dir_count, size;
+	struct dir_ent *new_dir;
+	struct dir *dir;
+
+	TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset);
+
+	if(bytes == -1) {
+		ERROR("squashfs_opendir: inode block %d not found!\n", block_start);
+		return NULL;
+	}
+	block_ptr = inode_table + bytes + offset;
+
+	if(swap) {
+		squashfs_dir_inode_header sinode;
+		memcpy(&sinode, block_ptr, sizeof(header.dir));
+		SQUASHFS_SWAP_DIR_INODE_HEADER(&header.dir, &sinode);
+	} else
+		memcpy(&header.dir, block_ptr, sizeof(header.dir));
+
+	switch(header.dir.inode_type) {
+		case SQUASHFS_DIR_TYPE:
+			block_start = header.dir.start_block;
+			offset = header.dir.offset;
+			size = header.dir.file_size;
+			break;
+		case SQUASHFS_LDIR_TYPE:
+			if(swap) {
+				squashfs_ldir_inode_header sinode;
+				memcpy(&sinode, block_ptr, sizeof(header.ldir));
+				SQUASHFS_SWAP_LDIR_INODE_HEADER(&header.ldir, &sinode);
+			} else
+				memcpy(&header.ldir, block_ptr, sizeof(header.ldir));
+			block_start = header.ldir.start_block;
+			offset = header.ldir.offset;
+			size = header.ldir.file_size;
+			break;
+		default:
+			ERROR("squashfs_opendir: inode not a directory\n");
+			return NULL;
+	}
+
+	start = sBlk->directory_table_start + block_start;
+	bytes = lookup_entry(directory_table_hash, start);
+
+	if(bytes == -1) {
+		ERROR("squashfs_opendir: directory block %d not found!\n", block_start);
+		return NULL;
+	}
+	bytes += offset;
+	size += bytes - 3;
+
+	if((dir = malloc(sizeof(struct dir))) == NULL) {
+		ERROR("squashfs_opendir: malloc failed!\n");
+		return NULL;
+	}
+
+	dir->dir_count = 0;
+	dir->cur_entry = 0;
+	dir->mode = header.dir.mode;
+	dir->uid = header.dir.uid;
+	dir->guid = header.dir.guid;
+	dir->mtime = header.dir.mtime;
+	dir->dirs = NULL;
+
+	while(bytes < size) {			
+		if(swap) {
+			squashfs_dir_header sdirh;
+			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
+			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
+		} else
+			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
+	
+		dir_count = dirh.count + 1;
+		TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count);
+		bytes += sizeof(dirh);
+
+		while(dir_count--) {
+			if(swap) {
+				squashfs_dir_entry sdire;
+				memcpy(&sdire, directory_table + bytes, sizeof(sdire));
+				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
+			} else
+				memcpy(dire, directory_table + bytes, sizeof(dire));
+			bytes += sizeof(*dire);
+
+			memcpy(dire->name, directory_table + bytes, dire->size + 1);
+			dire->name[dire->size + 1] = '\0';
+			TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type);
+			if((dir->dir_count % DIR_ENT_SIZE) == 0) {
+				if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) {
+					ERROR("squashfs_opendir: realloc failed!\n");
+					free(dir->dirs);
+					free(dir);
+					return NULL;
+				}
+				dir->dirs = new_dir;
+			}
+			strcpy(dir->dirs[dir->dir_count].name, dire->name);
+			dir->dirs[dir->dir_count].start_block = dirh.start_block;
+			dir->dirs[dir->dir_count].offset = dire->offset;
+			dir->dirs[dir->dir_count].type = dire->type;
+			dir->dir_count ++;
+			bytes += dire->size + 1;
+		}
+	}
+
+	return dir;
+}
+
+
+int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, unsigned int *offset, unsigned int *type)
+{
+	if(dir->cur_entry == dir->dir_count)
+		return FALSE;
+
+	*name = dir->dirs[dir->cur_entry].name;
+	*start_block = dir->dirs[dir->cur_entry].start_block;
+	*offset = dir->dirs[dir->cur_entry].offset;
+	*type = dir->dirs[dir->cur_entry].type;
+	dir->cur_entry ++;
+
+	return TRUE;
+}
+
+
+void squashfs_closedir(struct dir *dir)
+{
+	free(dir->dirs);
+	free(dir);
+}
+
+
+int dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk)
+{
+	struct dir *dir = squashfs_openddir(start_block, offset, sBlk);
+	unsigned int type;
+	char *name, pathname[1024];
+
+	if(dir == NULL) {
+		ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset);
+		return FALSE;
+	}
+
+	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1) {
+		ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno));
+		return FALSE;
+	}
+
+	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
+		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type);
+
+		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
+
+		if(lsonly || info)
+			printf("%s\n", pathname);
+
+		if(type == SQUASHFS_DIR_TYPE)
+			dir_scan(pathname, start_block, offset, sBlk);
+		else
+			if(!lsonly)
+				create_inode(pathname, start_block, offset, sBlk);
+	}
+
+	!lsonly && set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, TRUE);
+
+	squashfs_closedir(dir);
+	dir_count ++;
+
+	return TRUE;
+}
+
+
+int read_super(squashfs_super_block *sBlk, char *source)
+{
+	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) sBlk);
+
+	/* Check it is a SQUASHFS superblock */
+	swap = 0;
+	if(sBlk->s_magic != SQUASHFS_MAGIC) {
+		if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) {
+			squashfs_super_block sblk;
+			ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source);
+			SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk);
+			memcpy(sBlk, &sblk, sizeof(squashfs_super_block));
+			swap = 1;
+		} else  {
+			ERROR("Can't find a SQUASHFS superblock on %s\n", source);
+			goto failed_mount;
+		}
+	}
+
+	/* Check the MAJOR & MINOR versions */
+	if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
+		ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d)\n",
+				source, sBlk->s_major, sBlk->s_minor);
+		ERROR("I only support Squashfs 3.0 filesystems!  Later releases will support older Squashfs filesystems\n");
+		goto failed_mount;
+	}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "little" : "big", source);
+#else
+	TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "big" : "little", source);
+#endif
+
+	TRACE("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
+	TRACE("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
+	TRACE("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
+	TRACE("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not");
+	TRACE("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : "");
+	TRACE("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not");
+	TRACE("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not");
+	TRACE("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0));
+	TRACE("\tBlock size %d\n", sBlk->block_size);
+	TRACE("\tNumber of fragments %d\n", sBlk->fragments);
+	TRACE("\tNumber of inodes %d\n", sBlk->inodes);
+	TRACE("\tNumber of uids %d\n", sBlk->no_uids);
+	TRACE("\tNumber of gids %d\n", sBlk->no_guids);
+	TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start);
+	TRACE("sBlk->directory_table_start 0x%llx\n", sBlk->directory_table_start);
+	TRACE("sBlk->uid_start 0x%llx\n", sBlk->uid_start);
+	TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start);
+	TRACE("\n");
+
+	return TRUE;
+
+failed_mount:
+	return FALSE;
+}
+
+
+#define VERSION() \
+	printf("unsquashfs version 1.0 (2006/03/15)\n");\
+	printf("copyright (C) 2006 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \
+    	printf("This program is free software; you can redistribute it and/or\n");\
+	printf("modify it under the terms of the GNU General Public License\n");\
+	printf("as published by the Free Software Foundation; either version 2,\n");\
+	printf("or (at your option) any later version.\n\n");\
+	printf("This program is distributed in the hope that it will be useful,\n");\
+	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
+	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");\
+	printf("GNU General Public License for more details.\n");
+int main(int argc, char *argv[])
+{
+	squashfs_super_block sBlk;
+	char *dest = "squashfs-root";
+	int i, version = FALSE;
+
+	for(i = 1; i < argc; i++) {
+		if(*argv[i] != '-')
+			break;
+		if(strcmp(argv[i], "-version") == 0) {
+			VERSION();
+			version = TRUE;
+		} else if(strcmp(argv[i], "-info") == 0)
+			info = TRUE;
+		else if(strcmp(argv[i], "-ls") == 0)
+			lsonly = TRUE;
+		else if(strcmp(argv[i], "-dest") == 0) {
+			if(++i == argc)
+				goto options;
+			dest = argv[i];
+		}
+	}
+
+	if(i == argc) {
+		if(!version) {
+options:
+			ERROR("SYNTAX: %s [-ls | -dest] filesystem\n", argv[0]);
+			ERROR("\t-version\t\tprint version, licence and copyright information\n");
+			ERROR("\t-info\t\t\tprint files as they are unsquashed\n");
+			ERROR("\t-ls\t\t\tlist filesystem only\n");
+			ERROR("\t-dest <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n");
+		}
+		exit(1);
+	}
+
+	if((fd = open(argv[i], O_RDONLY)) == -1) {
+		ERROR("Could not open %s, because %s\n", argv[i], strerror(errno));
+		exit(1);
+	}
+
+	if(read_super(&sBlk, argv[i]) == FALSE)
+		exit(1);
+
+	block_size = sBlk.block_size;
+	if((fragment_data = malloc(block_size)) == NULL)
+		EXIT_UNSQUASH("failed to allocate fragment_data\n");
+
+	if((file_data = malloc(block_size)) == NULL)
+		EXIT_UNSQUASH("failed to allocate file_data");
+
+	if((data = malloc(block_size)) == NULL)
+		EXIT_UNSQUASH("failed to allocate datan\n");
+
+	if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL)
+		EXIT_UNSQUASH("failed to allocate created_inode\n");
+
+	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
+
+	read_uids_guids(&sBlk);
+	read_fragment_table(&sBlk);
+	uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start, &sBlk);
+	uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start, &sBlk);
+
+	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), &sBlk);
+
+	if(!lsonly) {
+		printf("\n");
+		printf("created %d files\n", file_count);
+		printf("created %d directories\n", dir_count);
+		printf("created %d symlinks\n", sym_count);
+		printf("created %d devices\n", dev_count);
+		printf("created %d fifos\n", fifo_count);
+	}
+
+}
