diff options
author | wbx <wbx@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-08-28 22:19:09 +0000 |
---|---|---|
committer | wbx <wbx@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-08-28 22:19:09 +0000 |
commit | f8968501098182115a67b4d7bf664aec680cb356 (patch) | |
tree | 35bf45631fbfb49931cba9b140a91c2128044251 /target/linux/linux-2.6/patches/generic | |
parent | 8c1fd3fc2df82ae8290be58900f7bd7a4aeb6d0e (diff) |
add squashfs 2.2 for kernel 2.6, cleanup broadcom patch, remove .orig files
git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@1777 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/linux-2.6/patches/generic')
-rw-r--r-- | target/linux/linux-2.6/patches/generic/001-squashfs.patch | 2592 | ||||
-rw-r--r-- | target/linux/linux-2.6/patches/generic/002-squashfs_lzma.patch | 886 |
2 files changed, 3478 insertions, 0 deletions
diff --git a/target/linux/linux-2.6/patches/generic/001-squashfs.patch b/target/linux/linux-2.6/patches/generic/001-squashfs.patch new file mode 100644 index 0000000000..f51beaac66 --- /dev/null +++ b/target/linux/linux-2.6/patches/generic/001-squashfs.patch @@ -0,0 +1,2592 @@ +diff --new-file -urp linux-2.6.12/fs/Kconfig linux-2.6.12-squashfs2.2/fs/Kconfig +--- linux-2.6.12/fs/Kconfig 2005-06-17 20:48:29.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/fs/Kconfig 2005-07-04 02:35:35.000000000 +0100 +@@ -1171,6 +1171,69 @@ config CRAMFS + + If unsure, say N. + ++config SQUASHFS ++ tristate "SquashFS 2.0 - Squashed file system support" ++ select ZLIB_INFLATE ++ help ++ Saying Y here includes support for SquashFs 2.0 (Compressed Read-Only File ++ System). Squashfs is a highly compressed read-only filesystem for Linux. ++ It uses zlib compression to compress both files, inodes and directories. ++ Inodes in the system are very small and all blocks are packed to minimise ++ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. ++ ++ Squashfs is intended for general read-only filesystem use, for archival ++ use (i.e. in cases where a .tar.gz file may be used), and in embedded ++ systems where low overhead is needed. Further information and filesystem tools ++ are available from http://squashfs.sourceforge.net. ++ ++ If you want to compile this as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want), ++ say M here and read <file:Documentation/modules.txt>. The module ++ will be called squashfs. Note that the root file system (the one ++ containing the directory /) cannot be compiled as a module. ++ ++ If unsure, say N. ++ ++config SQUASHFS_EMBEDDED ++ ++ bool "Additional options for memory-constrained systems" ++ depends on SQUASHFS ++ default n ++ help ++ Saying Y here allows you to specify cache sizes and how Squashfs ++ allocates memory. This is only intended for memory constrained ++ systems. ++ ++ If unsure, say N. ++ ++config SQUASHFS_FRAGMENT_CACHE_SIZE ++ int "Number of fragments cached" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default "3" ++ help ++ By default SquashFS caches the last 3 fragments read from ++ the filesystem. Increasing this amount may mean SquashFS ++ has to re-read fragments less often from disk, at the expense ++ of extra system memory. Decreasing this amount will mean ++ SquashFS uses less memory at the expense of extra reads from disk. ++ ++ Note there must be at least one cached fragment. Anything ++ much more than three will probably not make much difference. ++ ++config SQUASHFS_VMALLOC ++ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default n ++ help ++ By default SquashFS uses kmalloc to obtain fragment cache memory. ++ Kmalloc memory is the standard kernel allocator, but it can fail ++ on memory constrained systems. Because of the way Vmalloc works, ++ Vmalloc can succeed when kmalloc fails. Specifying this option ++ will make SquashFS always use Vmalloc to allocate the ++ fragment cache memory. ++ ++ If unsure, say N. ++ + config VXFS_FS + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + help +diff --new-file -urp linux-2.6.12/fs/Makefile linux-2.6.12-squashfs2.2/fs/Makefile +--- linux-2.6.12/fs/Makefile 2005-06-17 20:48:29.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/fs/Makefile 2005-07-04 02:35:35.000000000 +0100 +@@ -52,6 +52,7 @@ obj-$(CONFIG_EXT3_FS) += ext3/ # Before + obj-$(CONFIG_JBD) += jbd/ + obj-$(CONFIG_EXT2_FS) += ext2/ + obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ + obj-$(CONFIG_RAMFS) += ramfs/ + obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ + obj-$(CONFIG_CODA_FS) += coda/ +diff --new-file -urp linux-2.6.12/fs/squashfs/inode.c linux-2.6.12-squashfs2.2/fs/squashfs/inode.c +--- linux-2.6.12/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/fs/squashfs/inode.c 2005-07-04 02:35:35.000000000 +0100 +@@ -0,0 +1,1803 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005 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. ++ * ++ * inode.c ++ */ ++ ++#define SQUASHFS_1_0_COMPATIBILITY ++ ++#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/slab.h> ++#include <linux/squashfs_fs_sb.h> ++#include <linux/squashfs_fs_i.h> ++#include <linux/buffer_head.h> ++#include <linux/vfs.h> ++#include <linux/init.h> ++#include <linux/dcache.h> ++#include <asm/uaccess.h> ++#include <linux/wait.h> ++#include <asm/semaphore.h> ++#include <linux/zlib.h> ++#include <linux/blkdev.h> ++#include <linux/vmalloc.h> ++ ++#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...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) ++ ++static void squashfs_put_super(struct super_block *); ++static int squashfs_statfs(struct super_block *, struct kstatfs *); ++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 *, struct nameidata *); ++static unsigned int read_data(struct super_block *s, char *buffer, ++ unsigned int index, unsigned int length, unsigned int *next_index); ++static int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ unsigned int block, unsigned int offset, int length, ++ unsigned int *next_block, unsigned int *next_offset); ++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode); ++static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, ++ char *block_list, unsigned short **block_p, unsigned int *bsize); ++static void squashfs_put_super(struct super_block *s); ++static struct super_block *squashfs_get_sb(struct file_system_type *, int, const char *, void *); ++static struct inode *squashfs_alloc_inode(struct super_block *sb); ++static void squashfs_destroy_inode(struct inode *inode); ++static int init_inodecache(void); ++static void destroy_inodecache(void); ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static int squashfs_readpage_lessthan4K(struct file *file, struct page *page); ++static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode); ++static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, ++ char *block_list, unsigned short **block_p, unsigned int *bsize); ++#endif ++ ++DECLARE_MUTEX(read_data_mutex); ++ ++static z_stream stream; ++ ++static struct file_system_type squashfs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "squashfs", ++ .get_sb = squashfs_get_sb, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV ++ }; ++ ++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 = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++}; ++ ++static struct address_space_operations squashfs_symlink_aops = { ++ .readpage = squashfs_symlink_readpage ++}; ++ ++static struct address_space_operations squashfs_aops = { ++ .readpage = squashfs_readpage ++}; ++ ++static struct address_space_operations squashfs_aops_4K = { ++ .readpage = squashfs_readpage4K ++}; ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static struct address_space_operations squashfs_aops_lessthan4K = { ++ .readpage = squashfs_readpage_lessthan4K ++}; ++#endif ++ ++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 inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) ++{ ++ return list_entry(inode, struct squashfs_inode_info, vfs_inode); ++} ++ ++ ++static struct buffer_head *get_block_length(struct super_block *s, ++ int *cur_index, int *offset, int *c_byte) ++{ ++ squashfs_sb_info *msblk = s->s_fs_info; ++ 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; ++} ++ ++ ++static unsigned int read_data(struct super_block *s, char *buffer, ++ unsigned int index, unsigned int length, unsigned int *next_index) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ 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%x, %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%x, %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(&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(&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; ++} ++ ++ ++static int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ unsigned int block, unsigned int offset, int length, ++ unsigned int *next_block, unsigned int *next_offset) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ int n, i, bytes, return_length = length; ++ unsigned int next_index; ++ ++ TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset); ++ ++ for(;;) { ++ 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); ++ up(&msBlk->block_cache_mutex); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ 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 = (unsigned char *) ++ kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate cache block\n"); ++ up(&msBlk->block_cache_mutex); ++ return 0; ++ } ++ } ++ ++ msBlk->block_cache[i].block = SQUASHFS_USED_BLK; ++ up(&msBlk->block_cache_mutex); ++ if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0, ++ &next_index))) { ++ ERROR("Unable to read cache block [%x:%x]\n", block, offset); ++ return 0; ++ } ++ 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 [%x:%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); ++ return return_length; ++ } 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; ++ } ++ } ++} ++ ++ ++static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); ++ squashfs_fragment_entry fragment_entry; ++ ++ if(msBlk->swap) { ++ squashfs_fragment_entry sfragment_entry; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset, ++ sizeof(sfragment_entry), &start_block, &offset)) ++ return 0; ++ 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)) ++ return 0; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++} ++ ++ ++void release_cached_fragment(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); ++} ++ ++ ++struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length) ++{ ++ int i, n; ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ ++ for(;;) { ++ 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); ++ up(&msBlk->fragment_mutex); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ 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 = (unsigned char *) ++ SQUASHFS_ALLOC(SQUASHFS_FILE_MAX_SIZE))) { ++ ERROR("Failed to allocate fragment cache block\n"); ++ up(&msBlk->fragment_mutex); ++ return NULL; ++ } ++ ++ msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msBlk->fragment[i].locked = 1; ++ up(&msBlk->fragment_mutex); ++ if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length, ++ NULL))) { ++ ERROR("Unable to read fragment cache block [%x]\n", start_block); ++ msBlk->fragment[i].locked = 0; ++ return NULL; ++ } ++ msBlk->fragment[i].block = start_block; ++ TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); ++ return &msBlk->fragment[i]; ++ } ++ ++ msBlk->fragment[i].locked ++; ++ up(&msBlk->fragment_mutex); ++ ++ TRACE("Got fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); ++ return &msBlk->fragment[i]; ++ } ++} ++ ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode) ++{ ++ struct inode *i = new_inode(s); ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ 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 next_block, next_offset; ++ squashfs_base_inode_header_1 inodeb; ++ ++ TRACE("Entered squashfs_iget_1\n"); ++ ++ if(msBlk->swap) { ++ squashfs_base_inode_header_1 sinodeb; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, ++ sizeof(sinodeb), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER_1(&inodeb, &sinodeb, sizeof(sinodeb)); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, ++ sizeof(inodeb), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ ++ i->i_mtime.tv_sec = sBlk->mkfs_time; ++ i->i_atime.tv_sec = sBlk->mkfs_time; ++ i->i_ctime.tv_sec = sBlk->mkfs_time; ++ ++ if(inodeb.inode_type != SQUASHFS_IPC_TYPE) ++ i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; ++ i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); ++ ++ i->i_mode = inodeb.mode; ++ ++ switch(inodeb.inode_type == SQUASHFS_IPC_TYPE ? SQUASHFS_IPC_TYPE : (inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) { ++ case SQUASHFS_FILE_TYPE: { ++ squashfs_reg_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_reg_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.file_size; ++ i->i_fop = &generic_ro_fops; ++ if(sBlk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else if(sBlk->block_size == 4096) ++ i->i_data.a_ops = &squashfs_aops_4K; ++ else ++ i->i_data.a_ops = &squashfs_aops_lessthan4K; ++ i->i_mode |= S_IFREG; ++ i->i_mtime.tv_sec = inodep.mtime; ++ i->i_atime.tv_sec = inodep.mtime; ++ i->i_ctime.tv_sec = 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 = SQUASHFS_INVALID_BLK; ++ SQUASHFS_I(i)->u.s1.fragment_offset = 0; ++ SQUASHFS_I(i)->start_block = inodep.start_block; ++ SQUASHFS_I(i)->block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ squashfs_dir_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dir_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep.mtime; ++ i->i_atime.tv_sec = inodep.mtime; ++ i->i_ctime.tv_sec = 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; ++ TRACE("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: { ++ squashfs_symlink_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_symlink_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ 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 %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ squashfs_dev_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dev_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = 0; ++ i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, old_decode_dev(inodep.rdev)); ++ TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); ++ break; ++ } ++ case SQUASHFS_IPC_TYPE: { ++ squashfs_ipc_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_ipc_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_IPC_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = 0; ++ i->i_mode |= (inodep.type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; ++ i->i_uid = msBlk->uid[inodep.offset * 16 + inodeb.uid]; ++ 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; ++ } ++ ++ if(inodeb.guid == 15) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msBlk->guid[inodeb.guid]; ++ ++ insert_inode_hash(i); ++ return i; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return NULL; ++} ++#endif ++ ++ ++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode) ++{ ++ struct inode *i = new_inode(s); ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ 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 next_block, next_offset; ++ squashfs_base_inode_header inodeb; ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if(msBlk->swap) { ++ squashfs_base_inode_header sinodeb; ++ ++ 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; ++ ++ i->i_nlink = 1; ++ ++ i->i_mtime.tv_sec = sBlk->mkfs_time; ++ i->i_atime.tv_sec = sBlk->mkfs_time; ++ i->i_ctime.tv_sec = sBlk->mkfs_time; ++ ++ i->i_uid = msBlk->uid[inodeb.uid]; ++ i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); ++ ++ i->i_mode = inodeb.mode; ++ ++ switch(inodeb.inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ squashfs_reg_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_reg_inode_header sinodep; ++ ++ 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; ++ ++ SQUASHFS_I(i)->u.s1.fragment_start_block = SQUASHFS_INVALID_BLK; ++ if(inodep.fragment != SQUASHFS_INVALID_BLK && !get_fragment_location(s, inodep.fragment, ++ &SQUASHFS_I(i)->u.s1.fragment_start_block, &SQUASHFS_I(i)->u.s1.fragment_size)) ++ goto failed_read; ++ ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep.offset; ++ i->i_size = inodep.file_size; ++ i->i_fop = &generic_ro_fops; ++ if(sBlk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ i->i_mode |= S_IFREG; ++ i->i_mtime.tv_sec = inodep.mtime; ++ i->i_atime.tv_sec = inodep.mtime; ++ i->i_ctime.tv_sec = inodep.mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ i->i_blksize = PAGE_CACHE_SIZE; ++ SQUASHFS_I(i)->start_block = inodep.start_block; ++ SQUASHFS_I(i)->block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ squashfs_dir_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dir_inode_header sinodep; ++ ++ 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; ++ ++ i->i_size = inodep.file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep.mtime; ++ i->i_atime.tv_sec = inodep.mtime; ++ i->i_ctime.tv_sec = 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; ++ 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: { ++ squashfs_ldir_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_ldir_inode_header sinodep; ++ ++ 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; ++ ++ i->i_size = inodep.file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep.mtime; ++ i->i_atime.tv_sec = inodep.mtime; ++ i->i_ctime.tv_sec = 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; ++ 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: { ++ squashfs_symlink_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_symlink_inode_header sinodep; ++ ++ 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; ++ ++ 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 %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ squashfs_dev_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dev_inode_header sinodep; ++ ++ 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; ++ ++ i->i_size = 0; ++ i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, old_decode_dev(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: { ++ i->i_size = 0; ++ 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; ++ } ++ ++ if(inodeb.guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msBlk->guid[inodeb.guid]; ++ ++ insert_inode_hash(i); ++ return i; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return NULL; ++} ++ ++ ++static int squashfs_fill_super(struct super_block *s, ++ void *data, int silent) ++{ ++ squashfs_sb_info *msBlk; ++ squashfs_super_block *sBlk; ++ int i; ++ char b[BDEVNAME_SIZE]; ++ ++ TRACE("Entered squashfs_read_superblock\n"); ++ ++ if(!(s->s_fs_info = (void *) kmalloc(sizeof(squashfs_sb_info), GFP_KERNEL))) { ++ ERROR("Failed to allocate superblock\n"); ++ return -ENOMEM; ++ } ++ msBlk = (squashfs_sb_info *) s->s_fs_info; ++ sBlk = &msBlk->sBlk; ++ ++ msBlk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); ++ msBlk->devblksize_log2 = ffz(~msBlk->devblksize); ++ ++ 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(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(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) { ++ squashfs_super_block sblk; ++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", bdevname(s->s_bdev, b)); ++ SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); ++ memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); ++ msBlk->swap = 1; ++ } else { ++ SERROR("Can't find a SQUASHFS superblock on %s\n", bdevname(s->s_bdev, b)); ++ goto failed_mount; ++ } ++ } ++ ++ /* Check the MAJOR & MINOR versions */ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++ if((sBlk->s_major != 1) && (sBlk->s_major != 2 || sBlk->s_minor > SQUASHFS_MINOR)) { ++ SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (1 : x) or (2 : <= %d)\n", ++ sBlk->s_major, sBlk->s_minor, SQUASHFS_MINOR); ++ goto failed_mount; ++ } ++ if(sBlk->s_major == 1) ++ sBlk->block_size = sBlk->block_size_1; ++#else ++ if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { ++ SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n", ++ sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); ++ goto failed_mount; ++ } ++#endif ++ ++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); ++ 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 %d 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 %x\n", sBlk->inode_table_start); ++ TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); ++ if(sBlk->s_major > 1) ++ TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); ++ TRACE("sBlk->uid_start %x\n", sBlk->uid_start); ++ ++ s->s_flags |= MS_RDONLY; ++ s->s_op = &squashfs_ops; ++ ++ /* Init inode_table block pointer array */ ++ if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(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 = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) { ++ ERROR("Failed to allocate read_data block\n"); ++ goto failed_mount1; ++ } ++ ++ /* Allocate read_page block */ ++ if(sBlk->block_size > PAGE_CACHE_SIZE) { ++ if(!(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) { ++ ERROR("Failed to allocate read_page block\n"); ++ goto failed_mount2; ++ } ++ } else ++ msBlk->read_page = NULL; ++ ++ /* Allocate uid and gid tables */ ++ if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids + ++ sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount3; ++ } ++ msBlk->guid = msBlk->uid + sBlk->no_uids; ++ ++ if(msBlk->swap) { ++ squashfs_uid suid[sBlk->no_uids + sBlk->no_guids]; ++ ++ if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * ++ sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { ++ SERROR("unable to read uid/gid table\n"); ++ goto failed_mount4; ++ } ++ SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8)); ++ } else ++ if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * ++ sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { ++ SERROR("unable to read uid/gid table\n"); ++ goto failed_mount4; ++ } ++ ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++ if(sBlk->s_major == 1) { ++ msBlk->iget = squashfs_iget_1; ++ msBlk->read_blocklist = read_blocklist_1; ++ msBlk->fragment = NULL; ++ msBlk->fragment_index = NULL; ++ goto allocate_root; ++ } ++#endif ++ msBlk->iget = squashfs_iget; ++ msBlk->read_blocklist = read_blocklist; ++ ++ if(!(msBlk->fragment = (struct squashfs_fragment_cache *) kmalloc(sizeof(struct squashfs_fragment_cache) * SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment block cache\n"); ++ goto failed_mount4; ++ } ++ ++ 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->fragment_index = (squashfs_fragment_index *) kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount5; ++ } ++ ++ if(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) && ++ !read_data(s, (char *) msBlk->fragment_index, sBlk->fragment_table_start, ++ SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { ++ SERROR("unable to read fragment index table\n"); ++ goto failed_mount6; ++ } ++ ++ if(msBlk->swap) { ++ int i; ++ squashfs_fragment_index 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; ++ } ++ } ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++allocate_root: ++#endif ++ if(!(s->s_root = d_alloc_root((msBlk->iget)(s, sBlk->root_inode)))) { ++ ERROR("Root inode create failed\n"); ++ goto failed_mount5; ++ } ++ ++ TRACE("Leaving squashfs_read_super\n"); ++ return 0; ++ ++failed_mount6: ++ kfree(msBlk->fragment_index); ++failed_mount5: ++ kfree(msBlk->fragment); ++failed_mount4: ++ kfree(msBlk->uid); ++failed_mount3: ++ kfree(msBlk->read_page); ++failed_mount2: ++ kfree(msBlk->read_data); ++failed_mount1: ++ kfree(msBlk->block_cache); ++failed_mount: ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ return -EINVAL; ++} ++ ++ ++static int squashfs_statfs(struct super_block *s, struct kstatfs *buf) ++{ ++ squashfs_super_block *sBlk = &((squashfs_sb_info *)s->s_fs_info)->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; ++ unsigned int block = SQUASHFS_I(inode)->start_block; ++ int offset = SQUASHFS_I(inode)->offset; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_symlink_readpage, page index %d, start block %x, 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 [%x:%x]\n", block, offset); ++ goto skip_read; ++ } ++ } ++ ++ if(length != index) { ++ ERROR("(squashfs_symlink_readpage) length != index\n"); ++ bytes = 0; ++ goto skip_read; ++ } ++ ++ bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length; ++ if(!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, bytes, &block, &offset))) ++ ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++#define SIZE 256 ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, ++ char *block_list, unsigned short **block_p, unsigned int *bsize) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; ++ unsigned short *block_listp; ++ int i = 0; ++ int block_ptr = SQUASHFS_I(inode)->block_list_start; ++ int offset = SQUASHFS_I(inode)->offset; ++ unsigned int block = SQUASHFS_I(inode)->start_block; ++ ++ for(;;) { ++ int blocks = (index + readahead_blks - i); ++ if(blocks > (SIZE >> 1)) { ++ if((index - i) <= (SIZE >> 1)) ++ blocks = index - i; ++ else ++ blocks = SIZE >> 1; ++ } ++ ++ if(msBlk->swap) { ++ unsigned char sblock_list[SIZE]; ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks); ++ } else ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE(*block_listp); ++ if(blocks >= readahead_blks) ++ break; ++ } ++ ++ if(bsize) ++ *bsize = SQUASHFS_COMPRESSED_SIZE(*block_listp) | (!SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_BIT_BLOCK : 0); ++ else ++ *block_p = block_listp; ++ return block; ++} ++#endif ++ ++ ++static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, ++ char *block_list, unsigned short **block_p, unsigned int *bsize) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; ++ unsigned int *block_listp; ++ int i = 0; ++ int block_ptr = SQUASHFS_I(inode)->block_list_start; ++ int offset = SQUASHFS_I(inode)->offset; ++ unsigned int block = SQUASHFS_I(inode)->start_block; ++ ++ for(;;) { ++ int blocks = (index + readahead_blks - i); ++ if(blocks > (SIZE >> 2)) { ++ if((index - i) <= (SIZE >> 2)) ++ blocks = index - i; ++ else ++ blocks = SIZE >> 2; ++ } ++ ++ if(msBlk->swap) { ++ unsigned char sblock_list[SIZE]; ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ((unsigned int *)sblock_list), blocks); ++ } else ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ for(block_listp = (unsigned int *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); ++ if(blocks >= readahead_blks) ++ break; ++ } ++ ++ *bsize = *block_listp; ++ return block; ++} ++ ++ ++static int squashfs_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned char block_list[SIZE]; ++ unsigned int bsize, block, i = 0, bytes = 0, byte_offset = 0; ++ int index = page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT); ++ void *pageaddr = kmap(page); ++ 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 %x, start block %x\n", (unsigned int) page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ if(page->index >= ((inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { ++ goto skip_read; ++ } ++ ++ if(SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> 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 = read_data(inode->i_sb, msBlk->read_page, block, bsize, NULL))) { ++ ERROR("Unable to read page, block %x, 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 %x, 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 + (inode->i_size & (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) { ++ memcpy(pageaddr, data_ptr + byte_offset, available_bytes); ++ memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ } else if((push_page = grab_cache_page_nowait(page->mapping, i))) { ++ void *pageaddr = kmap(push_page); ++ memcpy(pageaddr, data_ptr + byte_offset, available_bytes); ++ memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); ++ kunmap(push_page); ++ flush_dcache_page(push_page); ++ SetPageUptodate(push_page); ++ unlock_page(push_page); ++ page_cache_release(push_page); ++ } ++ } ++ ++ if(SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) ++ up(&msBlk->read_page_mutex); ++ else ++ release_cached_fragment(msBlk, fragment); ++ ++ return 0; ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++static int squashfs_readpage4K(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned char block_list[SIZE]; ++ unsigned int bsize, block, bytes = 0; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_readpage4K, page index %x, start block %x\n", (unsigned int) page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ if(page->index >= ((inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { ++ goto skip_read; ++ } ++ ++ if(SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK || page->index < (inode->i_size >> sBlk->block_log)) { ++ block = (msBlk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize); ++ ++ if(!(bytes = read_data(inode->i_sb, pageaddr, block, bsize, NULL))) ++ ERROR("Unable to read page, block %x, size %x\n", block, bsize); ++ } else { ++ struct squashfs_fragment_cache *fragment; ++ ++ 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 %x, size %x\n", SQUASHFS_I(inode)->u.s1.fragment_start_block, (int) SQUASHFS_I(inode)->u.s1.fragment_size); ++ else { ++ bytes = inode->i_size & (sBlk->block_size - 1); ++ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset, bytes); ++ release_cached_fragment(msBlk, fragment); ++ } ++ } ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static int squashfs_readpage_lessthan4K(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned char block_list[SIZE]; ++ unsigned short *block_listp, block, bytes = 0; ++ int index = page->index << (PAGE_CACHE_SHIFT - sBlk->block_log); ++ int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1; ++ int readahead_blks = 1 << (PAGE_CACHE_SHIFT - sBlk->block_log); ++ void *pageaddr = kmap(page); ++ ++ int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log)); ++ int byte; ++ ++ TRACE("Entered squashfs_readpage_lessthan4K, page index %x, start block %x\n", (unsigned int) page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ block = read_blocklist_1(inode, index, readahead_blks, block_list, &block_listp, NULL); ++ ++ if(i_end > file_blocks) ++ i_end = file_blocks; ++ ++ while(index < i_end) { ++ int c_byte = !SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_SIZE(*block_listp) | SQUASHFS_COMPRESSED_BIT_BLOCK : *block_listp; ++ if(!(byte = read_data(inode->i_sb, pageaddr, block, c_byte, NULL))) { ++ ERROR("Unable to read page, block %x, size %x\n", block, *block_listp); ++ goto skip_read; ++ } ++ block += SQUASHFS_COMPRESSED_SIZE(*block_listp); ++ pageaddr += byte; ++ bytes += byte; ++ index ++; ++ block_listp ++; ++ } ++ ++skip_read: ++ memset(pageaddr, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++#endif ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, unsigned int *next_block, ++ unsigned int *next_offset, unsigned int index_start, unsigned int index_offset, ++ int i_count, long long f_pos) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int i, length = 0; ++ squashfs_dir_index 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) ++ return 0; ++ ++ for(i = 0; i < i_count; i++) { ++ if(msBlk->swap) { ++ 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; ++ return length; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, unsigned int *next_block, ++ unsigned int *next_offset, unsigned int index_start, unsigned int index_offset, ++ int i_count, const char *name, int size) ++{ ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int i, length = 0; ++ char buffer[sizeof(squashfs_dir_index) + SQUASHFS_NAME_LEN + 1]; ++ squashfs_dir_index *index = (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) { ++ 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(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; ++} ++ ++ ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)i->i_sb->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int next_block = SQUASHFS_I(i)->start_block + sBlk->directory_table_start, next_offset = ++ SQUASHFS_I(i)->offset, length = 0, dirs_read = 0, dir_count; ++ squashfs_dir_header dirh; ++ char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; ++ squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; ++ ++ TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset); ++ ++ lock_kernel(); ++ ++ 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->i_size) { ++ /* read directory header */ ++ if(msBlk->swap) { ++ 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) { ++ 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)\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"); ++ unlock_kernel(); ++ return dirs_read; ++ } ++ ++ file->f_pos = length; ++ dirs_read ++; ++ } ++ } ++ ++ unlock_kernel(); ++ return dirs_read; ++ ++failed_read: ++ unlock_kernel(); ++ ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, struct nameidata *nd) ++{ ++ const unsigned char *name =dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ squashfs_sb_info *msBlk = (squashfs_sb_info *)i->i_sb->s_fs_info; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int next_block = SQUASHFS_I(i)->start_block + sBlk->directory_table_start, next_offset = ++ SQUASHFS_I(i)->offset, length = 0, dir_count; ++ squashfs_dir_header dirh; ++ char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN]; ++ squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; ++ int squashfs_2_1 = sBlk->s_major == 2 && sBlk->s_minor == 1; ++ ++ TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset); ++ ++ lock_kernel(); ++ ++ 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->i_size) { ++ /* read directory header */ ++ if(msBlk->swap) { ++ 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) { ++ 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(squashfs_2_1 && name[0] < dire->name[0]) ++ goto exit_loop; ++ ++ if((len == dire->size + 1) && !strncmp(name, dire->name, len)) { ++ squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); ++ ++ TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n", ++ name, dirh.start_block, dire->offset); ++ ++ inode = (msBlk->iget)(i->i_sb, ino); ++ ++ goto exit_loop; ++ } ++ } ++ } ++ ++exit_loop: ++ d_add(dentry, inode); ++ unlock_kernel(); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); ++ goto exit_loop; ++} ++ ++ ++static void squashfs_put_super(struct super_block *s) ++{ ++ int i; ++ ++ if(s->s_fs_info) { ++ squashfs_sb_info *sbi = (squashfs_sb_info *) s->s_fs_info; ++ 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); ++ kfree(sbi->block_cache); ++ } ++ if(sbi->read_data) kfree(sbi->read_data); ++ if(sbi->read_page) kfree(sbi->read_page); ++ if(sbi->uid) kfree(sbi->uid); ++ if(sbi->fragment) { ++ for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) ++ if(sbi->fragment[i].data != NULL) ++ SQUASHFS_FREE(sbi->fragment[i].data); ++ kfree(sbi->fragment); ++ } ++ if(sbi->fragment_index) kfree(sbi->fragment_index); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ } ++} ++ ++ ++static struct super_block *squashfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) ++{ ++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); ++} ++ ++ ++static int __init init_squashfs_fs(void) ++{ ++ int err = init_inodecache(); ++ if(err) ++ return err; ++ ++ printk(KERN_INFO "Squashfs 2.2 (released 2005/07/03) (C) 2002-2005 Phillip Lougher\n"); ++ ++ if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) { ++ ERROR("Failed to allocate zlib workspace\n"); ++ destroy_inodecache(); ++ return -ENOMEM; ++ } ++ ++ if((err = register_filesystem(&squashfs_fs_type))) { ++ vfree(stream.workspace); ++ destroy_inodecache(); ++ } ++ ++ return err; ++} ++ ++ ++static void __exit exit_squashfs_fs(void) ++{ ++ vfree(stream.workspace); ++ unregister_filesystem(&squashfs_fs_type); ++ destroy_inodecache(); ++} ++ ++ ++static kmem_cache_t * squashfs_inode_cachep; ++ ++ ++static struct inode *squashfs_alloc_inode(struct super_block *sb) ++{ ++ struct squashfs_inode_info *ei; ++ ei = (struct squashfs_inode_info *)kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL); ++ if (!ei) ++ return NULL; ++ return &ei->vfs_inode; ++} ++ ++ ++static void squashfs_destroy_inode(struct inode *inode) ++{ ++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); ++} ++ ++ ++static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) ++{ ++ struct squashfs_inode_info *ei = (struct squashfs_inode_info *) foo; ++ ++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == ++ SLAB_CTOR_CONSTRUCTOR) ++ inode_init_once(&ei->vfs_inode); ++} ++ ++ ++static int init_inodecache(void) ++{ ++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", ++ sizeof(struct squashfs_inode_info), ++ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, ++ init_once, NULL); ++ if (squashfs_inode_cachep == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++ ++static void destroy_inodecache(void) ++{ ++ if (kmem_cache_destroy(squashfs_inode_cachep)) ++ printk(KERN_INFO "squashfs_inode_cache: not all structures were freed\n"); ++} ++ ++ ++module_init(init_squashfs_fs); ++module_exit(exit_squashfs_fs); ++MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem"); ++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); ++MODULE_LICENSE("GPL"); +diff --new-file -urp linux-2.6.12/fs/squashfs/Makefile linux-2.6.12-squashfs2.2/fs/squashfs/Makefile +--- linux-2.6.12/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/fs/squashfs/Makefile 2005-07-04 02:35:35.000000000 +0100 +@@ -0,0 +1,7 @@ ++# ++# Makefile for the linux squashfs routines. ++# ++ ++obj-$(CONFIG_SQUASHFS) += squashfs.o ++ ++squashfs-objs := inode.o +diff --new-file -urp linux-2.6.12/include/linux/squashfs_fs.h linux-2.6.12-squashfs2.2/include/linux/squashfs_fs.h +--- linux-2.6.12/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/include/linux/squashfs_fs.h 2005-07-04 02:35:35.000000000 +0100 +@@ -0,0 +1,519 @@ ++#ifndef SQUASHFS_FS ++#define SQUASHFS_FS ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005 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. ++ * ++ * squashfs_fs.h ++ */ ++ ++#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 ++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE ++#define SQUASHFS_MAJOR 2 ++#define SQUASHFS_MINOR 1 ++#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_BLK ((long long) 0xffffffff) ++#define SQUASHFS_USED_BLK ((long long) 0xfffffffe) ++ ++/* 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 ++ ++/* 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)(((squashfs_inode) (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)) ++ ++/* Translate between VFS mode and squashfs mode */ ++#define SQUASHFS_MODE(a) ((a) & 0xfff) ++ ++/* fragment and fragment table defines */ ++typedef unsigned int squashfs_fragment_index; ++#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(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(squashfs_fragment_index)) ++ ++/* cached data constants for filesystem */ ++#define SQUASHFS_CACHED_BLKS 8 ++ ++#define SQUASHFS_MAX_FILE_SIZE_LOG 32 ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1)) ++ ++#define SQUASHFS_MARKER_BYTE 0xff ++ ++ ++/* ++ * definitions for structures on disk ++ */ ++ ++typedef unsigned int squashfs_block; ++typedef long long squashfs_inode; ++ ++typedef unsigned int squashfs_uid; ++ ++typedef struct squashfs_super_block { ++ unsigned int s_magic; ++ unsigned int inodes; ++ unsigned int bytes_used; ++ unsigned int uid_start; ++ unsigned int guid_start; ++ unsigned int inode_table_start; ++ unsigned int directory_table_start; ++ 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 root_inode; ++ unsigned int block_size; ++ unsigned int fragments; ++ unsigned int fragment_table_start; ++} __attribute__ ((packed)) squashfs_super_block; ++ ++typedef struct { ++ unsigned int index:27; ++ unsigned int start_block:29; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)) squashfs_dir_index; ++ ++typedef struct { ++ 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)) squashfs_base_inode_header; ++ ++typedef squashfs_base_inode_header squashfs_ipc_inode_header; ++ ++typedef struct { ++ 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)) squashfs_dev_inode_header; ++ ++typedef struct { ++ 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)) squashfs_symlink_inode_header; ++ ++typedef struct { ++ 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; ++ squashfs_block start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)) squashfs_reg_inode_header; ++ ++typedef struct { ++ 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)) squashfs_dir_inode_header; ++ ++typedef struct { ++ 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; ++ squashfs_dir_index index[0]; ++} __attribute__ ((packed)) squashfs_ldir_inode_header; ++ ++typedef union { ++ squashfs_base_inode_header base; ++ squashfs_dev_inode_header dev; ++ squashfs_symlink_inode_header symlink; ++ squashfs_reg_inode_header reg; ++ squashfs_dir_inode_header dir; ++ squashfs_ldir_inode_header ldir; ++ squashfs_ipc_inode_header ipc; ++} squashfs_inode_header; ++ ++typedef struct { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ char name[0]; ++} __attribute__ ((packed)) squashfs_dir_entry; ++ ++typedef struct { ++ unsigned int count:8; ++ unsigned int start_block:24; ++} __attribute__ ((packed)) squashfs_dir_header; ++ ++typedef struct { ++ unsigned int start_block; ++ unsigned int size; ++} __attribute__ ((packed)) squashfs_fragment_entry; ++ ++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_SUPER_BLOCK(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\ ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->directory_table_start, 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, d, 472, 32);\ ++} ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(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_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header)) ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\ ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\ ++ 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(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\ ++ 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(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ldir_inode_header));\ ++ 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(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_index));\ ++ 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(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\ ++ 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(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\ ++} ++ ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ 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_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_DATA(s, d, n, bits) {\ ++ int entry;\ ++ int bit_position;\ ++ 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_INTS(s, d, n) ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++typedef struct { ++ 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)) squashfs_base_inode_header_1; ++ ++typedef struct { ++ 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)) squashfs_ipc_inode_header_1; ++ ++typedef struct { ++ 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)) squashfs_dev_inode_header_1; ++ ++typedef struct { ++ 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)) squashfs_symlink_inode_header_1; ++ ++typedef struct { ++ 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; ++ squashfs_block start_block; ++ unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)) squashfs_reg_inode_header_1; ++ ++typedef struct { ++ 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)) squashfs_dir_inode_header_1; ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_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_IPC_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(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_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\ ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(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_BASE_INODE_HEADER(s, d, sizeof(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 __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) {\ ++ 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); ++#endif ++#endif +diff --new-file -urp linux-2.6.12/include/linux/squashfs_fs_i.h linux-2.6.12-squashfs2.2/include/linux/squashfs_fs_i.h +--- linux-2.6.12/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/include/linux/squashfs_fs_i.h 2005-07-04 02:35:35.000000000 +0100 +@@ -0,0 +1,43 @@ ++#ifndef SQUASHFS_FS_I ++#define SQUASHFS_FS_I ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005 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. ++ * ++ * squashfs_fs_i.h ++ */ ++ ++typedef struct squashfs_inode_info { ++ unsigned int start_block; ++ unsigned int block_list_start; ++ unsigned int offset; ++ union { ++ struct { ++ unsigned int fragment_start_block; ++ unsigned int fragment_size; ++ unsigned int fragment_offset; ++ } s1; ++ struct { ++ unsigned int directory_index_start; ++ unsigned int directory_index_offset; ++ unsigned int directory_index_count; ++ } s2; ++ } u; ++ struct inode vfs_inode; ++ } squashfs_inode_info; ++#endif +diff --new-file -urp linux-2.6.12/include/linux/squashfs_fs_sb.h linux-2.6.12-squashfs2.2/include/linux/squashfs_fs_sb.h +--- linux-2.6.12/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/include/linux/squashfs_fs_sb.h 2005-07-04 02:35:35.000000000 +0100 +@@ -0,0 +1,65 @@ ++#ifndef SQUASHFS_FS_SB ++#define SQUASHFS_FS_SB ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005 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. ++ * ++ * squashfs_fs_sb.h ++ */ ++ ++#include <linux/squashfs_fs.h> ++ ++typedef struct { ++ unsigned int block; ++ int length; ++ unsigned int next_index; ++ char *data; ++ } squashfs_cache; ++ ++struct squashfs_fragment_cache { ++ unsigned int block; ++ int length; ++ unsigned int locked; ++ char *data; ++ }; ++ ++typedef struct squashfs_sb_info { ++ squashfs_super_block sBlk; ++ int devblksize; ++ int devblksize_log2; ++ int swap; ++ squashfs_cache *block_cache; ++ struct squashfs_fragment_cache *fragment; ++ int next_cache; ++ int next_fragment; ++ squashfs_uid *uid; ++ squashfs_uid *guid; ++ squashfs_fragment_index *fragment_index; ++ unsigned int read_size; ++ char *read_data; ++ char *read_page; ++ struct semaphore read_page_mutex; ++ struct semaphore block_cache_mutex; ++ struct semaphore fragment_mutex; ++ wait_queue_head_t waitq; ++ wait_queue_head_t fragment_wait_queue; ++ struct inode *(*iget)(struct super_block *s, squashfs_inode inode); ++ unsigned int (*read_blocklist)(struct inode *inode, int index, int readahead_blks, ++ char *block_list, unsigned short **block_p, unsigned int *bsize); ++ } squashfs_sb_info; ++#endif +diff --new-file -urp linux-2.6.12/init/do_mounts_rd.c linux-2.6.12-squashfs2.2/init/do_mounts_rd.c +--- linux-2.6.12/init/do_mounts_rd.c 2005-06-17 20:48:29.000000000 +0100 ++++ linux-2.6.12-squashfs2.2/init/do_mounts_rd.c 2005-07-04 02:35:35.000000000 +0100 +@@ -5,6 +5,7 @@ + #include <linux/ext2_fs.h> + #include <linux/romfs_fs.h> + #include <linux/cramfs_fs.h> ++#include <linux/squashfs_fs.h> + #include <linux/initrd.h> + #include <linux/string.h> + +@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in + * numbers could not be found. + * + * We currently check for the following magic numbers: ++ * squashfs + * minix + * ext2 + * romfs +@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + memset(buf, 0xe5, size); + + /* +@@ -101,6 +105,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 --git a/target/linux/linux-2.6/patches/generic/002-squashfs_lzma.patch b/target/linux/linux-2.6/patches/generic/002-squashfs_lzma.patch new file mode 100644 index 0000000000..1db27eef0f --- /dev/null +++ b/target/linux/linux-2.6/patches/generic/002-squashfs_lzma.patch @@ -0,0 +1,886 @@ +diff -Nur linux-2.6.12.5-brcm-squashfs/fs/squashfs/LzmaDecode.c linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/LzmaDecode.c +--- linux-2.6.12.5-brcm-squashfs/fs/squashfs/LzmaDecode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/LzmaDecode.c 2005-08-29 00:02:44.099124176 +0200 +@@ -0,0 +1,663 @@ ++/* ++ LzmaDecode.c ++ LZMA Decoder ++ ++ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this code, expressly permits you to ++ statically or dynamically link your code (or bind by name) to the ++ interfaces of this file without subjecting your linked code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#include "LzmaDecode.h" ++ ++#ifndef Byte ++#define Byte unsigned char ++#endif ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++typedef struct _CRangeDecoder ++{ ++ Byte *Buffer; ++ Byte *BufferLim; ++ UInt32 Range; ++ UInt32 Code; ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *InCallback; ++ int Result; ++ #endif ++ int ExtraBytes; ++} CRangeDecoder; ++ ++Byte RangeDecoderReadByte(CRangeDecoder *rd) ++{ ++ if (rd->Buffer == rd->BufferLim) ++ { ++ #ifdef _LZMA_IN_CB ++ UInt32 size; ++ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size); ++ rd->BufferLim = rd->Buffer + size; ++ if (size == 0) ++ #endif ++ { ++ rd->ExtraBytes = 1; ++ return 0xFF; ++ } ++ } ++ return (*rd->Buffer++); ++} ++ ++/* #define ReadByte (*rd->Buffer++) */ ++#define ReadByte (RangeDecoderReadByte(rd)) ++ ++void RangeDecoderInit(CRangeDecoder *rd, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback ++ #else ++ Byte *stream, UInt32 bufferSize ++ #endif ++ ) ++{ ++ int i; ++ #ifdef _LZMA_IN_CB ++ rd->InCallback = inCallback; ++ rd->Buffer = rd->BufferLim = 0; ++ #else ++ rd->Buffer = stream; ++ rd->BufferLim = stream + bufferSize; ++ #endif ++ rd->ExtraBytes = 0; ++ rd->Code = 0; ++ rd->Range = (0xFFFFFFFF); ++ for(i = 0; i < 5; i++) ++ rd->Code = (rd->Code << 8) | ReadByte; ++} ++ ++#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code; ++#define RC_FLUSH_VAR rd->Range = range; rd->Code = code; ++#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; } ++ ++UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits) ++{ ++ RC_INIT_VAR ++ UInt32 result = 0; ++ int i; ++ for (i = numTotalBits; i > 0; i--) ++ { ++ /* UInt32 t; */ ++ range >>= 1; ++ ++ result <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ result |= 1; ++ } ++ /* ++ t = (code - range) >> 31; ++ t &= 1; ++ code -= range & (t - 1); ++ result = (result + result) | (1 - t); ++ */ ++ RC_NORMALIZE ++ } ++ RC_FLUSH_VAR ++ return result; ++} ++ ++int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd) ++{ ++ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob; ++ if (rd->Code < bound) ++ { ++ rd->Range = bound; ++ *prob += (kBitModelTotal - *prob) >> kNumMoveBits; ++ if (rd->Range < kTopValue) ++ { ++ rd->Code = (rd->Code << 8) | ReadByte; ++ rd->Range <<= 8; ++ } ++ return 0; ++ } ++ else ++ { ++ rd->Range -= bound; ++ rd->Code -= bound; ++ *prob -= (*prob) >> kNumMoveBits; ++ if (rd->Range < kTopValue) ++ { ++ rd->Code = (rd->Code << 8) | ReadByte; ++ rd->Range <<= 8; ++ } ++ return 1; ++ } ++} ++ ++#define RC_GET_BIT2(prob, mi, A0, A1) \ ++ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \ ++ if (code < bound) \ ++ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \ ++ else \ ++ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \ ++ RC_NORMALIZE ++ ++#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;) ++ ++int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) ++{ ++ int mi = 1; ++ int i; ++ #ifdef _LZMA_LOC_OPT ++ RC_INIT_VAR ++ #endif ++ for(i = numLevels; i > 0; i--) ++ { ++ #ifdef _LZMA_LOC_OPT ++ CProb *prob = probs + mi; ++ RC_GET_BIT(prob, mi) ++ #else ++ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd); ++ #endif ++ } ++ #ifdef _LZMA_LOC_OPT ++ RC_FLUSH_VAR ++ #endif ++ return mi - (1 << numLevels); ++} ++ ++int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) ++{ ++ int mi = 1; ++ int i; ++ int symbol = 0; ++ #ifdef _LZMA_LOC_OPT ++ RC_INIT_VAR ++ #endif ++ for(i = 0; i < numLevels; i++) ++ { ++ #ifdef _LZMA_LOC_OPT ++ CProb *prob = probs + mi; ++ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i)) ++ #else ++ int bit = RangeDecoderBitDecode(probs + mi, rd); ++ mi = mi + mi + bit; ++ symbol |= (bit << i); ++ #endif ++ } ++ #ifdef _LZMA_LOC_OPT ++ RC_FLUSH_VAR ++ #endif ++ return symbol; ++} ++ ++Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd) ++{ ++ int symbol = 1; ++ #ifdef _LZMA_LOC_OPT ++ RC_INIT_VAR ++ #endif ++ do ++ { ++ #ifdef _LZMA_LOC_OPT ++ CProb *prob = probs + symbol; ++ RC_GET_BIT(prob, symbol) ++ #else ++ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); ++ #endif ++ } ++ while (symbol < 0x100); ++ #ifdef _LZMA_LOC_OPT ++ RC_FLUSH_VAR ++ #endif ++ return symbol; ++} ++ ++Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte) ++{ ++ int symbol = 1; ++ #ifdef _LZMA_LOC_OPT ++ RC_INIT_VAR ++ #endif ++ do ++ { ++ int bit; ++ int matchBit = (matchByte >> 7) & 1; ++ matchByte <<= 1; ++ #ifdef _LZMA_LOC_OPT ++ { ++ CProb *prob = probs + ((1 + matchBit) << 8) + symbol; ++ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1) ++ } ++ #else ++ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd); ++ symbol = (symbol << 1) | bit; ++ #endif ++ if (matchBit != bit) ++ { ++ while (symbol < 0x100) ++ { ++ #ifdef _LZMA_LOC_OPT ++ CProb *prob = probs + symbol; ++ RC_GET_BIT(prob, symbol) ++ #else ++ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); ++ #endif ++ } ++ break; ++ } ++ } ++ while (symbol < 0x100); ++ #ifdef _LZMA_LOC_OPT ++ RC_FLUSH_VAR ++ #endif ++ return symbol; ++} ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState) ++{ ++ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0) ++ return RangeDecoderBitTreeDecode(p + LenLow + ++ (posState << kLenNumLowBits), kLenNumLowBits, rd); ++ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0) ++ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid + ++ (posState << kLenNumMidBits), kLenNumMidBits, rd); ++ return kLenNumLowSymbols + kLenNumMidSymbols + ++ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd); ++} ++ ++#define kNumStates 12 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#ifdef _LZMA_OUT_READ ++ ++typedef struct _LzmaVarState ++{ ++ CRangeDecoder RangeDecoder; ++ Byte *Dictionary; ++ UInt32 DictionarySize; ++ UInt32 DictionaryPos; ++ UInt32 GlobalPos; ++ UInt32 Reps[4]; ++ int lc; ++ int lp; ++ int pb; ++ int State; ++ int PreviousIsMatch; ++ int RemainLen; ++} LzmaVarState; ++ ++int LzmaDecoderInit( ++ unsigned char *buffer, UInt32 bufferSize, ++ int lc, int lp, int pb, ++ unsigned char *dictionary, UInt32 dictionarySize, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback ++ #else ++ unsigned char *inStream, UInt32 inSize ++ #endif ++ ) ++{ ++ LzmaVarState *vs = (LzmaVarState *)buffer; ++ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp)); ++ UInt32 i; ++ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState)) ++ return LZMA_RESULT_NOT_ENOUGH_MEM; ++ vs->Dictionary = dictionary; ++ vs->DictionarySize = dictionarySize; ++ vs->DictionaryPos = 0; ++ vs->GlobalPos = 0; ++ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1; ++ vs->lc = lc; ++ vs->lp = lp; ++ vs->pb = pb; ++ vs->State = 0; ++ vs->PreviousIsMatch = 0; ++ vs->RemainLen = 0; ++ dictionary[dictionarySize - 1] = 0; ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ RangeDecoderInit(&vs->RangeDecoder, ++ #ifdef _LZMA_IN_CB ++ inCallback ++ #else ++ inStream, inSize ++ #endif ++ ); ++ return LZMA_RESULT_OK; ++} ++ ++int LzmaDecode(unsigned char *buffer, ++ unsigned char *outStream, UInt32 outSize, ++ UInt32 *outSizeProcessed) ++{ ++ LzmaVarState *vs = (LzmaVarState *)buffer; ++ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); ++ CRangeDecoder rd = vs->RangeDecoder; ++ int state = vs->State; ++ int previousIsMatch = vs->PreviousIsMatch; ++ Byte previousByte; ++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; ++ UInt32 nowPos = 0; ++ UInt32 posStateMask = (1 << (vs->pb)) - 1; ++ UInt32 literalPosMask = (1 << (vs->lp)) - 1; ++ int lc = vs->lc; ++ int len = vs->RemainLen; ++ UInt32 globalPos = vs->GlobalPos; ++ ++ Byte *dictionary = vs->Dictionary; ++ UInt32 dictionarySize = vs->DictionarySize; ++ UInt32 dictionaryPos = vs->DictionaryPos; ++ ++ if (len == -1) ++ { ++ *outSizeProcessed = 0; ++ return LZMA_RESULT_OK; ++ } ++ ++ while(len > 0 && nowPos < outSize) ++ { ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ len--; ++ } ++ if (dictionaryPos == 0) ++ previousByte = dictionary[dictionarySize - 1]; ++ else ++ previousByte = dictionary[dictionaryPos - 1]; ++#else ++ ++int LzmaDecode( ++ Byte *buffer, UInt32 bufferSize, ++ int lc, int lp, int pb, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback, ++ #else ++ unsigned char *inStream, UInt32 inSize, ++ #endif ++ unsigned char *outStream, UInt32 outSize, ++ UInt32 *outSizeProcessed) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp)); ++ CProb *p = (CProb *)buffer; ++ CRangeDecoder rd; ++ UInt32 i; ++ int state = 0; ++ int previousIsMatch = 0; ++ Byte previousByte = 0; ++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; ++ UInt32 nowPos = 0; ++ UInt32 posStateMask = (1 << pb) - 1; ++ UInt32 literalPosMask = (1 << lp) - 1; ++ int len = 0; ++ if (bufferSize < numProbs * sizeof(CProb)) ++ return LZMA_RESULT_NOT_ENOUGH_MEM; ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ RangeDecoderInit(&rd, ++ #ifdef _LZMA_IN_CB ++ inCallback ++ #else ++ inStream, inSize ++ #endif ++ ); ++#endif ++ ++ *outSizeProcessed = 0; ++ while(nowPos < outSize) ++ { ++ int posState = (int)( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & posStateMask); ++ #ifdef _LZMA_IN_CB ++ if (rd.Result != LZMA_RESULT_OK) ++ return rd.Result; ++ #endif ++ if (rd.ExtraBytes != 0) ++ return LZMA_RESULT_DATA_ERROR; ++ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0) ++ { ++ CProb *probs = p + Literal + (LZMA_LIT_SIZE * ++ ((( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & literalPosMask) << lc) + (previousByte >> (8 - lc)))); ++ ++ if (state < 4) state = 0; ++ else if (state < 10) state -= 3; ++ else state -= 6; ++ if (previousIsMatch) ++ { ++ Byte matchByte; ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ matchByte = dictionary[pos]; ++ #else ++ matchByte = outStream[nowPos - rep0]; ++ #endif ++ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte); ++ previousIsMatch = 0; ++ } ++ else ++ previousByte = LzmaLiteralDecode(probs, &rd); ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #endif ++ } ++ else ++ { ++ previousIsMatch = 1; ++ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1) ++ { ++ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0) ++ { ++ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0) ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos; ++ #endif ++ if ( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ == 0) ++ return LZMA_RESULT_DATA_ERROR; ++ state = state < 7 ? 9 : 11; ++ #ifdef _LZMA_OUT_READ ++ pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ outStream[nowPos++] = previousByte; ++ continue; ++ } ++ } ++ else ++ { ++ UInt32 distance; ++ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0) ++ distance = rep1; ++ else ++ { ++ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0) ++ distance = rep2; ++ else ++ { ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ len = LzmaLenDecode(p + RepLenCoder, &rd, posState); ++ state = state < 7 ? 8 : 11; ++ } ++ else ++ { ++ int posSlot; ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ state = state < 7 ? 7 : 10; ++ len = LzmaLenDecode(p + LenCoder, &rd, posState); ++ posSlot = RangeDecoderBitTreeDecode(p + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits), kNumPosSlotBits, &rd); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits); ++ if (posSlot < kEndPosModelIndex) ++ { ++ rep0 += RangeDecoderReverseBitTreeDecode( ++ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd); ++ } ++ else ++ { ++ rep0 += RangeDecoderDecodeDirectBits(&rd, ++ numDirectBits - kNumAlignBits) << kNumAlignBits; ++ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd); ++ } ++ } ++ else ++ rep0 = posSlot; ++ rep0++; ++ } ++ if (rep0 == (UInt32)(0)) ++ { ++ /* it's for stream version */ ++ len = -1; ++ break; ++ } ++ if (rep0 > nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ { ++ return LZMA_RESULT_DATA_ERROR; ++ } ++ len += kMatchMinLen; ++ do ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ outStream[nowPos++] = previousByte; ++ len--; ++ } ++ while(len > 0 && nowPos < outSize); ++ } ++ } ++ ++ #ifdef _LZMA_OUT_READ ++ vs->RangeDecoder = rd; ++ vs->DictionaryPos = dictionaryPos; ++ vs->GlobalPos = globalPos + nowPos; ++ vs->Reps[0] = rep0; ++ vs->Reps[1] = rep1; ++ vs->Reps[2] = rep2; ++ vs->Reps[3] = rep3; ++ vs->State = state; ++ vs->PreviousIsMatch = previousIsMatch; ++ vs->RemainLen = len; ++ #endif ++ ++ *outSizeProcessed = nowPos; ++ return LZMA_RESULT_OK; ++} +diff -Nur linux-2.6.12.5-brcm-squashfs/fs/squashfs/LzmaDecode.h linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/LzmaDecode.h +--- linux-2.6.12.5-brcm-squashfs/fs/squashfs/LzmaDecode.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/LzmaDecode.h 2005-08-29 00:02:44.099124176 +0200 +@@ -0,0 +1,100 @@ ++/* ++ LzmaDecode.h ++ LZMA Decoder interface ++ ++ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this code, expressly permits you to ++ statically or dynamically link your code (or bind by name) to the ++ interfaces of this file without subjecting your linked code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#ifndef __LZMADECODE_H ++#define __LZMADECODE_H ++ ++/* #define _LZMA_IN_CB */ ++/* Use callback for input data */ ++ ++/* #define _LZMA_OUT_READ */ ++/* Use read function for output data */ ++ ++/* #define _LZMA_PROB32 */ ++/* It can increase speed on some 32-bit CPUs, ++ but memory usage will be doubled in that case */ ++ ++/* #define _LZMA_LOC_OPT */ ++/* Enable local speed optimizations inside code */ ++ ++#ifndef UInt32 ++#ifdef _LZMA_UINT32_IS_ULONG ++#define UInt32 unsigned long ++#else ++#define UInt32 unsigned int ++#endif ++#endif ++ ++#ifdef _LZMA_PROB32 ++#define CProb UInt32 ++#else ++#define CProb unsigned short ++#endif ++ ++#define LZMA_RESULT_OK 0 ++#define LZMA_RESULT_DATA_ERROR 1 ++#define LZMA_RESULT_NOT_ENOUGH_MEM 2 ++ ++#ifdef _LZMA_IN_CB ++typedef struct _ILzmaInCallback ++{ ++ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize); ++} ILzmaInCallback; ++#endif ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++/* ++bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb) ++bufferSize += 100 in case of _LZMA_OUT_READ ++by default CProb is unsigned short, ++but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int) ++*/ ++ ++#ifdef _LZMA_OUT_READ ++int LzmaDecoderInit( ++ unsigned char *buffer, UInt32 bufferSize, ++ int lc, int lp, int pb, ++ unsigned char *dictionary, UInt32 dictionarySize, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback ++ #else ++ unsigned char *inStream, UInt32 inSize ++ #endif ++); ++#endif ++ ++int LzmaDecode( ++ unsigned char *buffer, ++ #ifndef _LZMA_OUT_READ ++ UInt32 bufferSize, ++ int lc, int lp, int pb, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback, ++ #else ++ unsigned char *inStream, UInt32 inSize, ++ #endif ++ #endif ++ unsigned char *outStream, UInt32 outSize, ++ UInt32 *outSizeProcessed); ++ ++#endif +diff -Nur linux-2.6.12.5-brcm-squashfs/fs/squashfs/Makefile linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/Makefile +--- linux-2.6.12.5-brcm-squashfs/fs/squashfs/Makefile 2005-08-28 23:44:05.046246000 +0200 ++++ linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/Makefile 2005-08-29 00:06:21.872017664 +0200 +@@ -4,4 +4,4 @@ + + obj-$(CONFIG_SQUASHFS) += squashfs.o + +-squashfs-objs := inode.o ++squashfs-objs := inode.o LzmaDecode.o +diff -Nur linux-2.6.12.5-brcm-squashfs/fs/squashfs/inode.c linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/inode.c +--- linux-2.6.12.5-brcm-squashfs/fs/squashfs/inode.c 2005-08-28 23:44:05.045246000 +0200 ++++ linux-2.6.12.5-brcm-squashfs-lzma/fs/squashfs/inode.c 2005-08-29 00:05:51.534629648 +0200 +@@ -3,6 +3,9 @@ + * + * Copyright (c) 2002, 2003, 2004, 2005 Phillip Lougher <phillip@lougher.demon.co.uk> + * ++ * LZMA decompressor support added by Oleg I. Vdovikin ++ * Copyright (c) 2005 Oleg I.Vdovikin <oleg@cs.msu.su> ++ * + * 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, +@@ -20,7 +23,11 @@ + * inode.c + */ + ++#define SQUASHFS_LZMA ++ ++#ifndef SQUASHFS_LZMA + #define SQUASHFS_1_0_COMPATIBILITY ++#endif + + #include <linux/types.h> + #include <linux/squashfs_fs.h> +@@ -43,6 +50,19 @@ + #include <linux/blkdev.h> + #include <linux/vmalloc.h> + ++#ifdef SQUASHFS_LZMA ++#include "LzmaDecode.h" ++ ++/* default LZMA settings, should be in sync with mksquashfs */ ++#define LZMA_LC 3 ++#define LZMA_LP 0 ++#define LZMA_PB 2 ++ ++#define LZMA_WORKSPACE_SIZE ((LZMA_BASE_SIZE + \ ++ (LZMA_LIT_SIZE << (LZMA_LC + LZMA_LP))) * sizeof(CProb)) ++ ++#endif ++ + #ifdef SQUASHFS_TRACE + #define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) + #else +@@ -85,7 +105,11 @@ + + DECLARE_MUTEX(read_data_mutex); + ++#ifdef SQUASHFS_LZMA ++static unsigned char lzma_workspace[LZMA_WORKSPACE_SIZE]; ++#else + static z_stream stream; ++#endif + + static struct file_system_type squashfs_fs_type = { + .owner = THIS_MODULE, +@@ -274,6 +298,15 @@ + if(compressed) { + int zlib_err; + ++#ifdef SQUASHFS_LZMA ++ if ((zlib_err = LzmaDecode(lzma_workspace, ++ LZMA_WORKSPACE_SIZE, LZMA_LC, LZMA_LP, LZMA_PB, ++ c_buffer, c_byte, buffer, msBlk->read_size, &bytes)) != LZMA_RESULT_OK) ++ { ++ ERROR("lzma returned unexpected result 0x%x\n", zlib_err); ++ bytes = 0; ++ } ++#else + stream.next_in = c_buffer; + stream.avail_in = c_byte; + stream.next_out = buffer; +@@ -285,6 +318,7 @@ + bytes = 0; + } else + bytes = stream.total_out; ++#endif + up(&read_data_mutex); + } + +@@ -1725,12 +1759,13 @@ + + printk(KERN_INFO "Squashfs 2.2 (released 2005/07/03) (C) 2002-2005 Phillip Lougher\n"); + ++#ifndef SQUASHFS_LZMA + if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) { + ERROR("Failed to allocate zlib workspace\n"); + destroy_inodecache(); + return -ENOMEM; + } +- ++#endif + if((err = register_filesystem(&squashfs_fs_type))) { + vfree(stream.workspace); + destroy_inodecache(); +@@ -1742,7 +1777,9 @@ + + static void __exit exit_squashfs_fs(void) + { ++#ifndef SQUASHFS_LZMA + vfree(stream.workspace); ++#endif + unregister_filesystem(&squashfs_fs_type); + destroy_inodecache(); + } |