Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 150257 Details for
Bug 218169
sys-kernel/gentoo-sources-2.6.25 fails on squashfs compile
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch I'm using since some RCs
squashfs-bp3.patch (text/plain), 123.10 KB, created by
Bruno
on 2008-04-19 08:11:05 UTC
(
hide
)
Description:
Patch I'm using since some RCs
Filename:
MIME Type:
Creator:
Bruno
Created:
2008-04-19 08:11:05 UTC
Size:
123.10 KB
patch
obsolete
>unchanged: >--- linux-2.6.25-gentoo.orig/fs/Kconfig >+++ linux-2.6.25-gentoo/fs/Kconfig >@@ -1367,6 +1367,56 @@ config CRAMFS > > If unsure, say N. > >+config SQUASHFS >+ tristate "SquashFS 3.3 - Squashed file system support" >+ select ZLIB_INFLATE >+ help >+ Saying Y here includes support for SquashFS 3.3 (a 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 1 Mbytes (default >+ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files >+ (larger than 4GB), full uid/gid information, hard links and timestamps. >+ >+ 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 option for memory-constrained systems" >+ depends on SQUASHFS >+ default n >+ help >+ Saying Y here allows you to specify cache size. >+ >+ 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 VXFS_FS > tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" > depends on BLOCK >unchanged: >--- linux-2.6.25-gentoo.orig/fs/Makefile >+++ linux-2.6.25-gentoo/fs/Makefile >@@ -73,6 +73,7 @@ obj-$(CONFIG_JBD) += jbd/ > obj-$(CONFIG_JBD2) += jbd2/ > obj-$(CONFIG_EXT2_FS) += ext2/ > obj-$(CONFIG_CRAMFS) += cramfs/ >+obj-$(CONFIG_SQUASHFS) += squashfs/ > obj-y += ramfs/ > obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ > obj-$(CONFIG_CODA_FS) += coda/ >diff -u linux-2.6.25-gentoo/fs/squashfs/inode.c linux-2.6.25-gentoo/fs/squashfs/inode.c >--- linux-2.6.25-gentoo/fs/squashfs/inode.c >+++ linux-2.6.25-gentoo/fs/squashfs/inode.c >@@ -0,0 +1,2158 @@ >+/* >+ * Squashfs - a compressed read only filesystem for Linux >+ * >+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 >+ * 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 >+ */ >+ >+#include <linux/squashfs_fs.h> >+#include <linux/module.h> >+#include <linux/zlib.h> >+#include <linux/fs.h> >+#include <linux/squashfs_fs_sb.h> >+#include <linux/squashfs_fs_i.h> >+#include <linux/buffer_head.h> >+#include <linux/exportfs.h> >+#include <linux/sched.h> >+#include <linux/vfs.h> >+#include <linux/vmalloc.h> >+#include <linux/smp_lock.h> >+#include <linux/exportfs.h> >+ >+#include "squashfs.h" >+ >+static int squashfs_cached_blks; >+ >+static struct dentry *squashfs_get_parent(struct dentry *child); >+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); >+static int squashfs_statfs(struct dentry *, struct kstatfs *); >+static int squashfs_symlink_readpage(struct file *file, struct page *page); >+static long long read_blocklist(struct inode *inode, int index, >+ int readahead_blks, char *block_list, >+ unsigned short **block_p, unsigned int *bsize); >+static int squashfs_readpage(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 int squashfs_remount(struct super_block *s, int *flags, char *data); >+static void squashfs_put_super(struct super_block *); >+static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, >+ struct vfsmount *); >+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); >+ >+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 const 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_super_ops = { >+ .alloc_inode = squashfs_alloc_inode, >+ .destroy_inode = squashfs_destroy_inode, >+ .statfs = squashfs_statfs, >+ .put_super = squashfs_put_super, >+ .remount_fs = squashfs_remount >+}; >+ >+static struct super_operations squashfs_export_super_ops = { >+ .alloc_inode = squashfs_alloc_inode, >+ .destroy_inode = squashfs_destroy_inode, >+ .statfs = squashfs_statfs, >+ .put_super = squashfs_put_super, >+}; >+ >+static struct export_operations squashfs_export_ops = { >+ .get_parent = squashfs_get_parent >+}; >+ >+SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = { >+ .readpage = squashfs_symlink_readpage >+}; >+ >+SQSH_EXTERN const struct address_space_operations squashfs_aops = { >+ .readpage = squashfs_readpage >+}; >+ >+static const struct file_operations squashfs_dir_ops = { >+ .read = generic_read_dir, >+ .readdir = squashfs_readdir >+}; >+ >+SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = { >+ .lookup = squashfs_lookup >+}; >+ >+ >+static struct buffer_head *get_block_length(struct super_block *s, >+ int *cur_index, int *offset, int *c_byte) >+{ >+ struct squashfs_sb_info *msblk = s->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; >+} >+ >+ >+SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, >+ long long index, unsigned int length, >+ long long *next_index, int srclength) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ struct buffer_head **bh; >+ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); >+ unsigned int cur_index = index >> msblk->devblksize_log2; >+ int bytes, avail_bytes, b = 0, k = 0; >+ unsigned int compressed; >+ unsigned int c_byte = length; >+ >+ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) * >+ sizeof(struct buffer_head *), GFP_KERNEL); >+ if (bh == NULL) >+ goto read_failure; >+ >+ if (c_byte) { >+ bytes = msblk->devblksize - offset; >+ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); >+ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); >+ >+ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, >+ compressed ? "" : "un", (unsigned int) c_byte, srclength); >+ >+ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) >+ goto read_failure; >+ >+ bh[0] = sb_getblk(s, cur_index); >+ if (bh[0] == NULL) >+ goto block_release; >+ >+ for (b = 1; bytes < c_byte; b++) { >+ bh[b] = sb_getblk(s, ++cur_index); >+ if (bh[b] == NULL) >+ goto block_release; >+ bytes += msblk->devblksize; >+ } >+ ll_rw_block(READ, b, bh); >+ } else { >+ if (index < 0 || (index + 2) > sblk->bytes_used) >+ goto read_failure; >+ >+ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte); >+ if (bh[0] == NULL) >+ goto read_failure; >+ >+ bytes = msblk->devblksize - offset; >+ compressed = SQUASHFS_COMPRESSED(c_byte); >+ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); >+ >+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed >+ ? "" : "un", (unsigned int) c_byte); >+ >+ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) >+ goto read_failure; >+ >+ for (b = 1; bytes < c_byte; b++) { >+ bh[b] = sb_getblk(s, ++cur_index); >+ if (bh[b] == NULL) >+ goto block_release; >+ bytes += msblk->devblksize; >+ } >+ ll_rw_block(READ, b - 1, bh + 1); >+ } >+ >+ if (compressed) { >+ int zlib_err = 0; >+ >+ /* >+ * uncompress block >+ */ >+ >+ mutex_lock(&msblk->read_data_mutex); >+ >+ msblk->stream.next_out = buffer; >+ msblk->stream.avail_out = srclength; >+ >+ for (bytes = 0; k < b; k++) { >+ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); >+ >+ wait_on_buffer(bh[k]); >+ if (!buffer_uptodate(bh[k])) >+ goto release_mutex; >+ >+ msblk->stream.next_in = bh[k]->b_data + offset; >+ msblk->stream.avail_in = avail_bytes; >+ >+ if (k == 0) { >+ zlib_err = zlib_inflateInit(&msblk->stream); >+ if (zlib_err != Z_OK) { >+ ERROR("zlib_inflateInit returned unexpected result 0x%x," >+ " srclength %d\n", zlib_err, srclength); >+ goto release_mutex; >+ } >+ >+ if (avail_bytes == 0) { >+ offset = 0; >+ brelse(bh[k]); >+ continue; >+ } >+ } >+ >+ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); >+ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) { >+ ERROR("zlib_inflate returned unexpected result 0x%x," >+ " srclength %d, avail_in %d, avail_out %d\n", zlib_err, >+ srclength, msblk->stream.avail_in, msblk->stream.avail_out); >+ goto release_mutex; >+ } >+ >+ bytes += avail_bytes; >+ offset = 0; >+ brelse(bh[k]); >+ } >+ >+ if (zlib_err != Z_STREAM_END) >+ goto release_mutex; >+ >+ zlib_err = zlib_inflateEnd(&msblk->stream); >+ if (zlib_err != Z_OK) { >+ ERROR("zlib_inflateEnd returned unexpected result 0x%x," >+ " srclength %d\n", zlib_err, srclength); >+ goto release_mutex; >+ } >+ bytes = msblk->stream.total_out; >+ mutex_unlock(&msblk->read_data_mutex); >+ } else { >+ int i; >+ >+ for(i = 0; i < b; i++) { >+ wait_on_buffer(bh[i]); >+ if (!buffer_uptodate(bh[i])) >+ goto block_release; >+ } >+ >+ for (bytes = 0; k < b; k++) { >+ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); >+ >+ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); >+ bytes += avail_bytes; >+ offset = 0; >+ brelse(bh[k]); >+ } >+ } >+ >+ if (next_index) >+ *next_index = index + c_byte + (length ? 0 : >+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2)); >+ >+ kfree(bh); >+ return bytes; >+ >+release_mutex: >+ mutex_unlock(&msblk->read_data_mutex); >+ >+block_release: >+ for (; k < b; k++) >+ brelse(bh[k]); >+ >+read_failure: >+ ERROR("sb_bread failed reading block 0x%x\n", cur_index); >+ kfree(bh); >+ return 0; >+} >+ >+ >+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer, >+ long long block, unsigned int offset, >+ int length, long long *next_block, >+ unsigned int *next_offset) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ int n, i, bytes, return_length = length; >+ long long next_index; >+ >+ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); >+ >+ while (1) { >+ for (i = 0; i < squashfs_cached_blks; i++) >+ if (msblk->block_cache[i].block == block) >+ break; >+ >+ mutex_lock(&msblk->block_cache_mutex); >+ >+ if (i == squashfs_cached_blks) { >+ /* read inode header block */ >+ if (msblk->unused_cache_blks == 0) { >+ mutex_unlock(&msblk->block_cache_mutex); >+ wait_event(msblk->waitq, msblk->unused_cache_blks); >+ continue; >+ } >+ >+ i = msblk->next_cache; >+ for (n = 0; n < squashfs_cached_blks; n++) { >+ if (msblk->block_cache[i].block != SQUASHFS_USED_BLK) >+ break; >+ i = (i + 1) % squashfs_cached_blks; >+ } >+ >+ msblk->next_cache = (i + 1) % squashfs_cached_blks; >+ >+ if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) { >+ msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE); >+ if (msblk->block_cache[i].data == NULL) { >+ ERROR("Failed to allocate cache block\n"); >+ mutex_unlock(&msblk->block_cache_mutex); >+ goto out; >+ } >+ } >+ >+ msblk->block_cache[i].block = SQUASHFS_USED_BLK; >+ msblk->unused_cache_blks --; >+ mutex_unlock(&msblk->block_cache_mutex); >+ >+ msblk->block_cache[i].length = squashfs_read_data(s, >+ msblk->block_cache[i].data, block, 0, &next_index, >+ SQUASHFS_METADATA_SIZE); >+ >+ if (msblk->block_cache[i].length == 0) { >+ ERROR("Unable to read cache block [%llx:%x]\n", block, offset); >+ mutex_lock(&msblk->block_cache_mutex); >+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; >+ msblk->unused_cache_blks ++; >+ smp_mb(); >+ vfree(msblk->block_cache[i].data); >+ wake_up(&msblk->waitq); >+ mutex_unlock(&msblk->block_cache_mutex); >+ goto out; >+ } >+ >+ mutex_lock(&msblk->block_cache_mutex); >+ msblk->block_cache[i].block = block; >+ msblk->block_cache[i].next_index = next_index; >+ msblk->unused_cache_blks ++; >+ smp_mb(); >+ wake_up(&msblk->waitq); >+ TRACE("Read cache block [%llx:%x]\n", block, offset); >+ } >+ >+ if (msblk->block_cache[i].block != block) { >+ mutex_unlock(&msblk->block_cache_mutex); >+ continue; >+ } >+ >+ bytes = msblk->block_cache[i].length - offset; >+ >+ if (bytes < 1) { >+ mutex_unlock(&msblk->block_cache_mutex); >+ goto out; >+ } else if (bytes >= 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; >+ } >+ mutex_unlock(&msblk->block_cache_mutex); >+ goto finish; >+ } else { >+ if (buffer) { >+ memcpy(buffer, msblk->block_cache[i].data + offset, bytes); >+ buffer = (char *) buffer + bytes; >+ } >+ block = msblk->block_cache[i].next_index; >+ mutex_unlock(&msblk->block_cache_mutex); >+ length -= bytes; >+ offset = 0; >+ } >+ } >+ >+finish: >+ return return_length; >+out: >+ return 0; >+} >+ >+ >+static int get_fragment_location(struct super_block *s, unsigned int fragment, >+ long long *fragment_start_block, >+ unsigned int *fragment_size) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ long long start_block = >+ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; >+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); >+ struct squashfs_fragment_entry fragment_entry; >+ >+ if (msblk->swap) { >+ struct squashfs_fragment_entry sfragment_entry; >+ >+ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset, >+ sizeof(sfragment_entry), &start_block, &offset)) >+ goto out; >+ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); >+ } else >+ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset, >+ sizeof(fragment_entry), &start_block, &offset)) >+ goto out; >+ >+ *fragment_start_block = fragment_entry.start_block; >+ *fragment_size = fragment_entry.size; >+ >+ return 1; >+ >+out: >+ return 0; >+} >+ >+ >+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, >+ struct squashfs_fragment_cache *fragment) >+{ >+ mutex_lock(&msblk->fragment_mutex); >+ fragment->locked --; >+ if (fragment->locked == 0) { >+ msblk->unused_frag_blks ++; >+ smp_mb(); >+ wake_up(&msblk->fragment_wait_queue); >+ } >+ mutex_unlock(&msblk->fragment_mutex); >+} >+ >+ >+SQSH_EXTERN >+struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, >+ long long start_block, int length) >+{ >+ int i, n; >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ >+ while (1) { >+ mutex_lock(&msblk->fragment_mutex); >+ >+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && >+ msblk->fragment[i].block != start_block; i++); >+ >+ if (i == SQUASHFS_CACHED_FRAGMENTS) { >+ if (msblk->unused_frag_blks == 0) { >+ mutex_unlock(&msblk->fragment_mutex); >+ wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks); >+ continue; >+ } >+ >+ i = msblk->next_fragment; >+ for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) { >+ if (msblk->fragment[i].locked == 0) >+ break; >+ i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS; >+ } >+ >+ msblk->next_fragment = (msblk->next_fragment + 1) % >+ SQUASHFS_CACHED_FRAGMENTS; >+ >+ if (msblk->fragment[i].data == NULL) { >+ msblk->fragment[i].data = vmalloc(sblk->block_size); >+ if (msblk->fragment[i].data == NULL) { >+ ERROR("Failed to allocate fragment cache block\n"); >+ mutex_unlock(&msblk->fragment_mutex); >+ goto out; >+ } >+ } >+ >+ msblk->unused_frag_blks --; >+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; >+ msblk->fragment[i].locked = 1; >+ mutex_unlock(&msblk->fragment_mutex); >+ >+ msblk->fragment[i].length = squashfs_read_data(s, >+ msblk->fragment[i].data, start_block, length, NULL, >+ sblk->block_size); >+ >+ if (msblk->fragment[i].length == 0) { >+ ERROR("Unable to read fragment cache block [%llx]\n", start_block); >+ msblk->fragment[i].locked = 0; >+ msblk->unused_frag_blks ++; >+ smp_mb(); >+ wake_up(&msblk->fragment_wait_queue); >+ goto out; >+ } >+ >+ mutex_lock(&msblk->fragment_mutex); >+ msblk->fragment[i].block = start_block; >+ TRACE("New fragment %d, start block %lld, locked %d\n", >+ i, msblk->fragment[i].block, msblk->fragment[i].locked); >+ mutex_unlock(&msblk->fragment_mutex); >+ break; >+ } >+ >+ if (msblk->fragment[i].locked == 0) >+ msblk->unused_frag_blks --; >+ msblk->fragment[i].locked++; >+ mutex_unlock(&msblk->fragment_mutex); >+ TRACE("Got fragment %d, start block %lld, locked %d\n", i, >+ msblk->fragment[i].block, msblk->fragment[i].locked); >+ break; >+ } >+ >+ return &msblk->fragment[i]; >+ >+out: >+ return NULL; >+} >+ >+ >+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, >+ struct squashfs_base_inode_header *inodeb) >+{ >+ i->i_ino = inodeb->inode_number; >+ i->i_mtime.tv_sec = inodeb->mtime; >+ i->i_atime.tv_sec = inodeb->mtime; >+ i->i_ctime.tv_sec = inodeb->mtime; >+ i->i_uid = msblk->uid[inodeb->uid]; >+ i->i_mode = inodeb->mode; >+ i->i_size = 0; >+ >+ if (inodeb->guid == SQUASHFS_GUIDS) >+ i->i_gid = i->i_uid; >+ else >+ i->i_gid = msblk->guid[inodeb->guid]; >+} >+ >+ >+static struct dentry *squashfs_get_parent(struct dentry *child) >+{ >+ struct inode *i = child->d_inode; >+ struct inode *parent = iget_locked(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); >+ struct dentry *rv; >+ >+ TRACE("Entered squashfs_get_parent\n"); >+ >+ if(parent == NULL) { >+ rv = ERR_PTR(-EACCES); >+ goto out; >+ } >+ >+ rv = d_alloc_anon(parent); >+ if(parent->i_state & I_NEW) { >+ unlock_new_inode(parent); >+ } >+ >+ if(rv == NULL) >+ rv = ERR_PTR(-ENOMEM); >+ >+out: >+ return rv; >+} >+ >+ >+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, >+ squashfs_inode_t inode, unsigned int inode_number) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct inode *i = iget_locked(s, inode_number); >+ >+ TRACE("Entered squashfs_iget\n"); >+ >+ if(!i) >+ return ERR_PTR(-ENOMEM); >+ >+ if(i && (i->i_state & I_NEW)) { >+ (msblk->read_inode)(i, inode); >+ unlock_new_inode(i); >+ } >+ >+ return i; >+} >+ >+ >+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) >+{ >+ struct super_block *s = i->i_sb; >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; >+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); >+ long long next_block; >+ unsigned int next_offset; >+ union squashfs_inode_header id, sid; >+ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base; >+ >+ TRACE("Entered squashfs_read_inode\n"); >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, 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, inodeb, block, offset, >+ sizeof(*inodeb), &next_block, &next_offset)) >+ goto failed_read; >+ >+ squashfs_new_inode(msblk, i, inodeb); >+ >+ switch(inodeb->inode_type) { >+ case SQUASHFS_FILE_TYPE: { >+ unsigned int frag_size; >+ long long frag_blk; >+ struct squashfs_reg_inode_header *inodep = &id.reg; >+ struct squashfs_reg_inode_header *sinodep = &sid.reg; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, 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, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ frag_blk = SQUASHFS_INVALID_BLK; >+ >+ if (inodep->fragment != SQUASHFS_INVALID_FRAG) >+ if(!get_fragment_location(s, inodep->fragment, &frag_blk, >+ &frag_size)) >+ goto failed_read; >+ >+ i->i_nlink = 1; >+ i->i_size = inodep->file_size; >+ i->i_fop = &generic_ro_fops; >+ i->i_mode |= S_IFREG; >+ i->i_blocks = ((i->i_size - 1) >> 9) + 1; >+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; >+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; >+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; >+ SQUASHFS_I(i)->start_block = inodep->start_block; >+ SQUASHFS_I(i)->u.s1.block_list_start = next_block; >+ SQUASHFS_I(i)->offset = next_offset; >+ i->i_data.a_ops = &squashfs_aops; >+ >+ TRACE("File inode %x:%x, start_block %llx, " >+ "block_list_start %llx, offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ inodep->start_block, next_block, >+ next_offset); >+ break; >+ } >+ case SQUASHFS_LREG_TYPE: { >+ unsigned int frag_size; >+ long long frag_blk; >+ struct squashfs_lreg_inode_header *inodep = &id.lreg; >+ struct squashfs_lreg_inode_header *sinodep = &sid.lreg; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, sinodep, block, offset, >+ sizeof(*sinodep), &next_block, &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ frag_blk = SQUASHFS_INVALID_BLK; >+ >+ if (inodep->fragment != SQUASHFS_INVALID_FRAG) >+ if (!get_fragment_location(s, inodep->fragment, &frag_blk, >+ &frag_size)) >+ goto failed_read; >+ >+ i->i_nlink = inodep->nlink; >+ i->i_size = inodep->file_size; >+ i->i_fop = &generic_ro_fops; >+ i->i_mode |= S_IFREG; >+ i->i_blocks = ((i->i_size - 1) >> 9) + 1; >+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; >+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; >+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; >+ SQUASHFS_I(i)->start_block = inodep->start_block; >+ SQUASHFS_I(i)->u.s1.block_list_start = next_block; >+ SQUASHFS_I(i)->offset = next_offset; >+ i->i_data.a_ops = &squashfs_aops; >+ >+ TRACE("File inode %x:%x, start_block %llx, " >+ "block_list_start %llx, offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ inodep->start_block, next_block, >+ next_offset); >+ break; >+ } >+ case SQUASHFS_DIR_TYPE: { >+ struct squashfs_dir_inode_header *inodep = &id.dir; >+ struct squashfs_dir_inode_header *sinodep = &sid.dir; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, 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, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ i->i_nlink = inodep->nlink; >+ i->i_size = inodep->file_size; >+ i->i_op = &squashfs_dir_inode_ops; >+ i->i_fop = &squashfs_dir_ops; >+ i->i_mode |= S_IFDIR; >+ SQUASHFS_I(i)->start_block = inodep->start_block; >+ SQUASHFS_I(i)->offset = inodep->offset; >+ SQUASHFS_I(i)->u.s2.directory_index_count = 0; >+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; >+ >+ TRACE("Directory inode %x:%x, start_block %x, offset " >+ "%x\n", SQUASHFS_INODE_BLK(inode), >+ offset, inodep->start_block, >+ inodep->offset); >+ break; >+ } >+ case SQUASHFS_LDIR_TYPE: { >+ struct squashfs_ldir_inode_header *inodep = &id.ldir; >+ struct squashfs_ldir_inode_header *sinodep = &sid.ldir; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, 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, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ i->i_nlink = inodep->nlink; >+ i->i_size = inodep->file_size; >+ i->i_op = &squashfs_dir_inode_ops; >+ i->i_fop = &squashfs_dir_ops; >+ i->i_mode |= S_IFDIR; >+ SQUASHFS_I(i)->start_block = inodep->start_block; >+ SQUASHFS_I(i)->offset = inodep->offset; >+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; >+ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; >+ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; >+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; >+ >+ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ inodep->start_block, inodep->offset); >+ break; >+ } >+ case SQUASHFS_SYMLINK_TYPE: { >+ struct squashfs_symlink_inode_header *inodep = &id.symlink; >+ struct squashfs_symlink_inode_header *sinodep = &sid.symlink; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, 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, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ i->i_nlink = inodep->nlink; >+ i->i_size = inodep->symlink_size; >+ i->i_op = &page_symlink_inode_operations; >+ i->i_data.a_ops = &squashfs_symlink_aops; >+ i->i_mode |= S_IFLNK; >+ SQUASHFS_I(i)->start_block = next_block; >+ SQUASHFS_I(i)->offset = next_offset; >+ >+ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ next_block, next_offset); >+ break; >+ } >+ case SQUASHFS_BLKDEV_TYPE: >+ case SQUASHFS_CHRDEV_TYPE: { >+ struct squashfs_dev_inode_header *inodep = &id.dev; >+ struct squashfs_dev_inode_header *sinodep = &sid.dev; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, 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, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ i->i_nlink = inodep->nlink; >+ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? >+ S_IFCHR : S_IFBLK; >+ init_special_inode(i, i->i_mode, 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: { >+ struct squashfs_ipc_inode_header *inodep = &id.ipc; >+ struct squashfs_ipc_inode_header *sinodep = &sid.ipc; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, sinodep, block, offset, >+ sizeof(*sinodep), &next_block, &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, inodep, block, offset, >+ sizeof(*inodep), &next_block, &next_offset)) >+ goto failed_read; >+ >+ i->i_nlink = inodep->nlink; >+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) >+ ? S_IFIFO : S_IFSOCK; >+ init_special_inode(i, i->i_mode, 0); >+ break; >+ } >+ default: >+ ERROR("Unknown inode type %d in squashfs_iget!\n", >+ inodeb->inode_type); >+ goto failed_read1; >+ } >+ >+ return 1; >+ >+failed_read: >+ ERROR("Unable to read inode [%llx:%x]\n", block, offset); >+ >+failed_read1: >+ make_bad_inode(i); >+ return 0; >+} >+ >+ >+static int read_inode_lookup_table(struct super_block *s) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); >+ >+ TRACE("In read_inode_lookup_table, length %d\n", length); >+ >+ /* Allocate inode lookup table */ >+ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL); >+ if (msblk->inode_lookup_table == NULL) { >+ ERROR("Failed to allocate inode lookup table\n"); >+ return 0; >+ } >+ >+ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, >+ sblk->lookup_table_start, length | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { >+ ERROR("unable to read inode lookup table\n"); >+ return 0; >+ } >+ >+ if (msblk->swap) { >+ int i; >+ long long block; >+ >+ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { >+ /* XXX */ >+ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), >+ &msblk->inode_lookup_table[i], 1); >+ msblk->inode_lookup_table[i] = block; >+ } >+ } >+ >+ return 1; >+} >+ >+ >+static int read_fragment_index_table(struct super_block *s) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); >+ >+ if(length == 0) >+ return 1; >+ >+ /* Allocate fragment index table */ >+ msblk->fragment_index = kmalloc(length, GFP_KERNEL); >+ if (msblk->fragment_index == NULL) { >+ ERROR("Failed to allocate fragment index table\n"); >+ return 0; >+ } >+ >+ if (!squashfs_read_data(s, (char *) msblk->fragment_index, >+ sblk->fragment_table_start, length | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { >+ ERROR("unable to read fragment index table\n"); >+ return 0; >+ } >+ >+ if (msblk->swap) { >+ int i; >+ long long fragment; >+ >+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { >+ /* XXX */ >+ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), >+ &msblk->fragment_index[i], 1); >+ msblk->fragment_index[i] = fragment; >+ } >+ } >+ >+ return 1; >+} >+ >+ >+static int readahead_metadata(struct super_block *s) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ int i; >+ >+ squashfs_cached_blks = SQUASHFS_CACHED_BLKS; >+ >+ /* Init inode_table block pointer array */ >+ msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * >+ squashfs_cached_blks, GFP_KERNEL); >+ if (msblk->block_cache == NULL) { >+ ERROR("Failed to allocate block cache\n"); >+ goto failed; >+ } >+ >+ for (i = 0; i < squashfs_cached_blks; i++) >+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; >+ >+ msblk->next_cache = 0; >+ msblk->unused_cache_blks = squashfs_cached_blks; >+ >+ return 1; >+ >+failed: >+ return 0; >+} >+ >+ >+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) >+{ >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ >+ msblk->read_inode = squashfs_read_inode; >+ msblk->read_blocklist = read_blocklist; >+ msblk->read_fragment_index_table = read_fragment_index_table; >+ >+ if (sblk->s_major == 1) { >+ if (!squashfs_1_0_supported(msblk)) { >+ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " >+ "are unsupported\n"); >+ SERROR("Please recompile with Squashfs 1.0 support enabled\n"); >+ return 0; >+ } >+ } else if (sblk->s_major == 2) { >+ if (!squashfs_2_0_supported(msblk)) { >+ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " >+ "are unsupported\n"); >+ SERROR("Please recompile with Squashfs 2.0 support enabled\n"); >+ return 0; >+ } >+ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > >+ SQUASHFS_MINOR) { >+ SERROR("Major/Minor mismatch, trying to mount newer %d.%d " >+ "filesystem\n", sblk->s_major, sblk->s_minor); >+ SERROR("Please update your kernel\n"); >+ return 0; >+ } >+ >+ return 1; >+} >+ >+ >+static int squashfs_fill_super(struct super_block *s, void *data, int silent) >+{ >+ struct squashfs_sb_info *msblk; >+ struct squashfs_super_block *sblk; >+ int i; >+ char b[BDEVNAME_SIZE]; >+ struct inode *root; >+ >+ TRACE("Entered squashfs_fill_superblock\n"); >+ >+ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL); >+ if (s->s_fs_info == NULL) { >+ ERROR("Failed to allocate superblock\n"); >+ goto failure; >+ } >+ msblk = s->s_fs_info; >+ >+ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()); >+ if (msblk->stream.workspace == NULL) { >+ ERROR("Failed to allocate zlib workspace\n"); >+ goto failure; >+ } >+ sblk = &msblk->sblk; >+ >+ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); >+ msblk->devblksize_log2 = ffz(~msblk->devblksize); >+ >+ mutex_init(&msblk->read_data_mutex); >+ mutex_init(&msblk->read_page_mutex); >+ mutex_init(&msblk->block_cache_mutex); >+ mutex_init(&msblk->fragment_mutex); >+ mutex_init(&msblk->meta_index_mutex); >+ >+ init_waitqueue_head(&msblk->waitq); >+ init_waitqueue_head(&msblk->fragment_wait_queue); >+ >+ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not >+ * beyond filesystem end. As we're using squashfs_read_data to read sblk here, >+ * first set sblk->bytes_used to a useful value */ >+ sblk->bytes_used = sizeof(struct squashfs_super_block); >+ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, >+ sizeof(struct squashfs_super_block) | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { >+ SERROR("unable to read superblock\n"); >+ goto failed_mount; >+ } >+ >+ /* Check it is a SQUASHFS superblock */ >+ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { >+ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { >+ struct squashfs_super_block ssblk; >+ >+ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", >+ bdevname(s->s_bdev, b)); >+ >+ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); >+ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); >+ msblk->swap = 1; >+ } else { >+ SERROR("Can't find a SQUASHFS superblock on %s\n", >+ bdevname(s->s_bdev, b)); >+ goto failed_mount; >+ } >+ } >+ >+ /* Check the MAJOR & MINOR versions */ >+ if(!supported_squashfs_filesystem(msblk, silent)) >+ goto failed_mount; >+ >+ /* Check the filesystem does not extend beyond the end of the >+ block device */ >+ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) >+ goto failed_mount; >+ >+ /* Check the root inode for sanity */ >+ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) >+ goto failed_mount; >+ >+ 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 %spresent in the filesystem\n", >+ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not "); >+ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); >+ TRACE("Block size %d\n", sblk->block_size); >+ TRACE("Number of inodes %d\n", sblk->inodes); >+ if (sblk->s_major > 1) >+ TRACE("Number of fragments %d\n", sblk->fragments); >+ TRACE("Number of uids %d\n", sblk->no_uids); >+ TRACE("Number of gids %d\n", sblk->no_guids); >+ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); >+ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); >+ if (sblk->s_major > 1) >+ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start); >+ TRACE("sblk->uid_start %llx\n", sblk->uid_start); >+ >+ s->s_maxbytes = MAX_LFS_FILESIZE; >+ s->s_flags |= MS_RDONLY; >+ s->s_op = &squashfs_super_ops; >+ >+ if (readahead_metadata(s) == 0) >+ goto failed_mount; >+ >+ /* Allocate read_page block */ >+ msblk->read_page = vmalloc(sblk->block_size); >+ if (msblk->read_page == NULL) { >+ ERROR("Failed to allocate read_page block\n"); >+ goto failed_mount; >+ } >+ >+ /* Allocate uid and gid tables */ >+ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * >+ sizeof(unsigned int), GFP_KERNEL); >+ if (msblk->uid == NULL) { >+ ERROR("Failed to allocate uid/gid table\n"); >+ goto failed_mount; >+ } >+ msblk->guid = msblk->uid + sblk->no_uids; >+ >+ if (msblk->swap) { >+ unsigned int suid[sblk->no_uids + sblk->no_guids]; >+ >+ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, >+ ((sblk->no_uids + sblk->no_guids) * >+ sizeof(unsigned int)) | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { >+ ERROR("unable to read uid/gid table\n"); >+ goto failed_mount; >+ } >+ >+ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + >+ sblk->no_guids), (sizeof(unsigned int) * 8)); >+ } else >+ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, >+ ((sblk->no_uids + sblk->no_guids) * >+ sizeof(unsigned int)) | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { >+ ERROR("unable to read uid/gid table\n"); >+ goto failed_mount; >+ } >+ >+ >+ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) >+ goto allocate_root; >+ >+ msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) * >+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL); >+ if (msblk->fragment == NULL) { >+ ERROR("Failed to allocate fragment block cache\n"); >+ goto failed_mount; >+ } >+ >+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { >+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; >+ } >+ >+ msblk->next_fragment = 0; >+ msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS; >+ >+ /* Allocate and read fragment index table */ >+ if (msblk->read_fragment_index_table(s) == 0) >+ goto failed_mount; >+ >+ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK) >+ goto allocate_root; >+ >+ /* Allocate and read inode lookup table */ >+ if (read_inode_lookup_table(s) == 0) >+ goto failed_mount; >+ >+ s->s_op = &squashfs_export_super_ops; >+ s->s_export_op = &squashfs_export_ops; >+ >+allocate_root: >+ root = new_inode(s); >+ if ((msblk->read_inode)(root, sblk->root_inode) == 0) >+ goto failed_mount; >+ insert_inode_hash(root); >+ >+ s->s_root = d_alloc_root(root); >+ if (s->s_root == NULL) { >+ ERROR("Root inode create failed\n"); >+ iput(root); >+ goto failed_mount; >+ } >+ >+ TRACE("Leaving squashfs_fill_super\n"); >+ return 0; >+ >+failed_mount: >+ kfree(msblk->inode_lookup_table); >+ kfree(msblk->fragment_index); >+ kfree(msblk->fragment); >+ kfree(msblk->uid); >+ vfree(msblk->read_page); >+ kfree(msblk->block_cache); >+ kfree(msblk->fragment_index_2); >+ vfree(msblk->stream.workspace); >+ kfree(s->s_fs_info); >+ s->s_fs_info = NULL; >+ return -EINVAL; >+ >+failure: >+ return -ENOMEM; >+} >+ >+ >+static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) >+{ >+ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ >+ TRACE("Entered squashfs_statfs\n"); >+ >+ buf->f_type = SQUASHFS_MAGIC; >+ buf->f_bsize = sblk->block_size; >+ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; >+ buf->f_bfree = buf->f_bavail = 0; >+ buf->f_files = sblk->inodes; >+ buf->f_ffree = 0; >+ buf->f_namelen = SQUASHFS_NAME_LEN; >+ >+ return 0; >+} >+ >+ >+static int squashfs_symlink_readpage(struct file *file, struct page *page) >+{ >+ struct inode *inode = page->mapping->host; >+ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes; >+ long long block = SQUASHFS_I(inode)->start_block; >+ int offset = SQUASHFS_I(inode)->offset; >+ void *pageaddr = kmap(page); >+ >+ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " >+ "%llx, offset %x\n", page->index, >+ SQUASHFS_I(inode)->start_block, >+ SQUASHFS_I(inode)->offset); >+ >+ for (length = 0; length < index; length += bytes) { >+ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, >+ offset, PAGE_CACHE_SIZE, &block, &offset); >+ if (bytes == 0) { >+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); >+ goto skip_read; >+ } >+ } >+ >+ if (length != index) { >+ ERROR("(squashfs_symlink_readpage) length != index\n"); >+ bytes = 0; >+ goto skip_read; >+ } >+ >+ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE); >+ >+ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, >+ avail_bytes, &block, &offset); >+ if (bytes == 0) >+ ERROR("Unable to read symbolic link [%llx:%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; >+} >+ >+ >+struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) >+{ >+ struct meta_index *meta = NULL; >+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; >+ int i; >+ >+ mutex_lock(&msblk->meta_index_mutex); >+ >+ TRACE("locate_meta_index: index %d, offset %d\n", index, offset); >+ >+ if (msblk->meta_index == NULL) >+ goto not_allocated; >+ >+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) { >+ if (msblk->meta_index[i].inode_number == inode->i_ino && >+ msblk->meta_index[i].offset >= offset && >+ msblk->meta_index[i].offset <= index && >+ msblk->meta_index[i].locked == 0) { >+ TRACE("locate_meta_index: entry %d, offset %d\n", i, >+ msblk->meta_index[i].offset); >+ meta = &msblk->meta_index[i]; >+ offset = meta->offset; >+ } >+ } >+ >+ if (meta) >+ meta->locked = 1; >+ >+not_allocated: >+ mutex_unlock(&msblk->meta_index_mutex); >+ >+ return meta; >+} >+ >+ >+struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) >+{ >+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; >+ struct meta_index *meta = NULL; >+ int i; >+ >+ mutex_lock(&msblk->meta_index_mutex); >+ >+ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); >+ >+ if (msblk->meta_index == NULL) { >+ msblk->meta_index = kmalloc(sizeof(struct meta_index) * >+ SQUASHFS_META_NUMBER, GFP_KERNEL); >+ if (msblk->meta_index == NULL) { >+ ERROR("Failed to allocate meta_index\n"); >+ goto failed; >+ } >+ for (i = 0; i < SQUASHFS_META_NUMBER; i++) { >+ msblk->meta_index[i].inode_number = 0; >+ msblk->meta_index[i].locked = 0; >+ } >+ msblk->next_meta_index = 0; >+ } >+ >+ for (i = SQUASHFS_META_NUMBER; i && >+ msblk->meta_index[msblk->next_meta_index].locked; i --) >+ msblk->next_meta_index = (msblk->next_meta_index + 1) % >+ SQUASHFS_META_NUMBER; >+ >+ if (i == 0) { >+ TRACE("empty_meta_index: failed!\n"); >+ goto failed; >+ } >+ >+ TRACE("empty_meta_index: returned meta entry %d, %p\n", >+ msblk->next_meta_index, >+ &msblk->meta_index[msblk->next_meta_index]); >+ >+ meta = &msblk->meta_index[msblk->next_meta_index]; >+ msblk->next_meta_index = (msblk->next_meta_index + 1) % >+ SQUASHFS_META_NUMBER; >+ >+ meta->inode_number = inode->i_ino; >+ meta->offset = offset; >+ meta->skip = skip; >+ meta->entries = 0; >+ meta->locked = 1; >+ >+failed: >+ mutex_unlock(&msblk->meta_index_mutex); >+ return meta; >+} >+ >+ >+void release_meta_index(struct inode *inode, struct meta_index *meta) >+{ >+ meta->locked = 0; >+ smp_mb(); >+} >+ >+ >+static int read_block_index(struct super_block *s, int blocks, char *block_list, >+ long long *start_block, int *offset) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ unsigned int *block_listp; >+ int block = 0; >+ >+ if (msblk->swap) { >+ char sblock_list[blocks << 2]; >+ >+ if (!squashfs_get_cached_block(s, sblock_list, *start_block, >+ *offset, blocks << 2, start_block, offset)) { >+ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); >+ goto failure; >+ } >+ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), >+ ((unsigned int *)sblock_list), blocks); >+ } else { >+ if (!squashfs_get_cached_block(s, block_list, *start_block, >+ *offset, blocks << 2, start_block, offset)) { >+ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); >+ goto failure; >+ } >+ } >+ >+ for (block_listp = (unsigned int *) block_list; blocks; >+ block_listp++, blocks --) >+ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); >+ >+ return block; >+ >+failure: >+ return -1; >+} >+ >+ >+#define SIZE 256 >+ >+static inline int calculate_skip(int blocks) { >+ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); >+ return skip >= 7 ? 7 : skip + 1; >+} >+ >+ >+static int get_meta_index(struct inode *inode, int index, >+ long long *index_block, int *index_offset, >+ long long *data_block, char *block_list) >+{ >+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); >+ int offset = 0; >+ struct meta_index *meta; >+ struct meta_entry *meta_entry; >+ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; >+ int cur_offset = SQUASHFS_I(inode)->offset; >+ long long cur_data_block = SQUASHFS_I(inode)->start_block; >+ int i; >+ >+ index /= SQUASHFS_META_INDEXES * skip; >+ >+ while (offset < index) { >+ meta = locate_meta_index(inode, index, offset + 1); >+ >+ if (meta == NULL) { >+ meta = empty_meta_index(inode, offset + 1, skip); >+ if (meta == NULL) >+ goto all_done; >+ } else { >+ if(meta->entries == 0) >+ goto failed; >+ /* XXX */ >+ offset = index < meta->offset + meta->entries ? index : >+ meta->offset + meta->entries - 1; >+ /* XXX */ >+ meta_entry = &meta->meta_entry[offset - meta->offset]; >+ cur_index_block = meta_entry->index_block + sblk->inode_table_start; >+ cur_offset = meta_entry->offset; >+ cur_data_block = meta_entry->data_block; >+ TRACE("get_meta_index: offset %d, meta->offset %d, " >+ "meta->entries %d\n", offset, meta->offset, meta->entries); >+ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" >+ " data_block 0x%llx\n", cur_index_block, >+ cur_offset, cur_data_block); >+ } >+ >+ for (i = meta->offset + meta->entries; i <= index && >+ i < meta->offset + SQUASHFS_META_ENTRIES; i++) { >+ int blocks = skip * SQUASHFS_META_INDEXES; >+ >+ while (blocks) { >+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks; >+ int res = read_block_index(inode->i_sb, block, block_list, >+ &cur_index_block, &cur_offset); >+ >+ if (res == -1) >+ goto failed; >+ >+ cur_data_block += res; >+ blocks -= block; >+ } >+ >+ meta_entry = &meta->meta_entry[i - meta->offset]; >+ meta_entry->index_block = cur_index_block - sblk->inode_table_start; >+ meta_entry->offset = cur_offset; >+ meta_entry->data_block = cur_data_block; >+ meta->entries ++; >+ offset ++; >+ } >+ >+ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", >+ meta->offset, meta->entries); >+ >+ release_meta_index(inode, meta); >+ } >+ >+all_done: >+ *index_block = cur_index_block; >+ *index_offset = cur_offset; >+ *data_block = cur_data_block; >+ >+ return offset * SQUASHFS_META_INDEXES * skip; >+ >+failed: >+ release_meta_index(inode, meta); >+ return -1; >+} >+ >+ >+static long long read_blocklist(struct inode *inode, int index, >+ int readahead_blks, char *block_list, >+ unsigned short **block_p, unsigned int *bsize) >+{ >+ long long block_ptr; >+ int offset; >+ long long block; >+ int res = get_meta_index(inode, index, &block_ptr, &offset, &block, >+ block_list); >+ >+ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" >+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block); >+ >+ if(res == -1) >+ goto failure; >+ >+ index -= res; >+ >+ while (index) { >+ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; >+ int res = read_block_index(inode->i_sb, blocks, block_list, >+ &block_ptr, &offset); >+ if (res == -1) >+ goto failure; >+ block += res; >+ index -= blocks; >+ } >+ >+ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1) >+ goto failure; >+ *bsize = *((unsigned int *) block_list); >+ >+ return block; >+ >+failure: >+ return 0; >+} >+ >+ >+static int squashfs_readpage(struct file *file, struct page *page) >+{ >+ struct inode *inode = page->mapping->host; >+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ unsigned char *block_list = NULL; >+ long long block; >+ unsigned int bsize, i; >+ int bytes; >+ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); >+ void *pageaddr; >+ struct squashfs_fragment_cache *fragment = NULL; >+ char *data_ptr = msblk->read_page; >+ >+ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; >+ int start_index = page->index & ~mask; >+ int end_index = start_index | mask; >+ int file_end = i_size_read(inode) >> sblk->block_log; >+ int sparse = 0; >+ >+ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", >+ page->index, SQUASHFS_I(inode)->start_block); >+ >+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> >+ PAGE_CACHE_SHIFT)) >+ goto out; >+ >+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK >+ || index < file_end) { >+ block_list = kmalloc(SIZE, GFP_KERNEL); >+ if (block_list == NULL) { >+ ERROR("Failed to allocate block_list\n"); >+ goto error_out; >+ } >+ >+ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize); >+ if (block == 0) >+ goto error_out; >+ >+ if (bsize == 0) { /* hole */ >+ bytes = index == file_end ? >+ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size; >+ sparse = 1; >+ } else { >+ mutex_lock(&msblk->read_page_mutex); >+ >+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, >+ bsize, NULL, sblk->block_size); >+ >+ if (bytes == 0) { >+ ERROR("Unable to read page, block %llx, size %x\n", block, bsize); >+ mutex_unlock(&msblk->read_page_mutex); >+ goto error_out; >+ } >+ } >+ } else { >+ fragment = get_cached_fragment(inode->i_sb, >+ SQUASHFS_I(inode)-> u.s1.fragment_start_block, >+ SQUASHFS_I(inode)->u.s1.fragment_size); >+ >+ if (fragment == NULL) { >+ ERROR("Unable to read page, block %llx, size %x\n", >+ SQUASHFS_I(inode)->u.s1.fragment_start_block, >+ (int) SQUASHFS_I(inode)->u.s1.fragment_size); >+ goto error_out; >+ } >+ bytes = i_size_read(inode) & (sblk->block_size - 1); >+ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset; >+ } >+ >+ for (i = start_index; i <= end_index && bytes > 0; i++, >+ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) { >+ struct page *push_page; >+ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE); >+ >+ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); >+ >+ push_page = (i == page->index) ? page : >+ grab_cache_page_nowait(page->mapping, i); >+ >+ if (!push_page) >+ continue; >+ >+ if (PageUptodate(push_page)) >+ goto skip_page; >+ >+ pageaddr = kmap_atomic(push_page, KM_USER0); >+ memcpy(pageaddr, data_ptr, avail); >+ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); >+ kunmap_atomic(pageaddr, KM_USER0); >+ flush_dcache_page(push_page); >+ SetPageUptodate(push_page); >+skip_page: >+ unlock_page(push_page); >+ if(i != page->index) >+ page_cache_release(push_page); >+ } >+ >+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK >+ || index < file_end) { >+ if (!sparse) >+ mutex_unlock(&msblk->read_page_mutex); >+ kfree(block_list); >+ } else >+ release_cached_fragment(msblk, fragment); >+ >+ return 0; >+ >+error_out: >+ SetPageError(page); >+out: >+ pageaddr = kmap_atomic(page, KM_USER0); >+ memset(pageaddr, 0, PAGE_CACHE_SIZE); >+ kunmap_atomic(pageaddr, KM_USER0); >+ flush_dcache_page(page); >+ if (!PageError(page)) >+ SetPageUptodate(page); >+ unlock_page(page); >+ >+ kfree(block_list); >+ return 0; >+} >+ >+ >+static int get_dir_index_using_offset(struct super_block *s, >+ long long *next_block, unsigned int *next_offset, >+ long long index_start, unsigned int index_offset, int i_count, >+ long long f_pos) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ int i, length = 0; >+ struct squashfs_dir_index index; >+ >+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", >+ i_count, (unsigned int) f_pos); >+ >+ f_pos =- 3; >+ if (f_pos == 0) >+ goto finish; >+ >+ for (i = 0; i < i_count; i++) { >+ if (msblk->swap) { >+ struct squashfs_dir_index sindex; >+ squashfs_get_cached_block(s, &sindex, index_start, index_offset, >+ sizeof(sindex), &index_start, &index_offset); >+ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); >+ } else >+ squashfs_get_cached_block(s, &index, index_start, index_offset, >+ sizeof(index), &index_start, &index_offset); >+ >+ if (index.index > f_pos) >+ break; >+ >+ squashfs_get_cached_block(s, NULL, index_start, index_offset, >+ index.size + 1, &index_start, &index_offset); >+ >+ length = index.index; >+ *next_block = index.start_block + sblk->directory_table_start; >+ } >+ >+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; >+ >+finish: >+ return length + 3; >+} >+ >+ >+static int get_dir_index_using_name(struct super_block *s, >+ long long *next_block, unsigned int *next_offset, >+ long long index_start, unsigned int index_offset, int i_count, >+ const char *name, int size) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ int i, length = 0; >+ struct squashfs_dir_index *index; >+ char *str; >+ >+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); >+ >+ str = kmalloc(sizeof(struct squashfs_dir_index) + >+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL); >+ if (str == NULL) { >+ ERROR("Failed to allocate squashfs_dir_index\n"); >+ goto failure; >+ } >+ >+ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1); >+ strncpy(str, name, size); >+ str[size] = '\0'; >+ >+ for (i = 0; i < i_count; i++) { >+ if (msblk->swap) { >+ struct squashfs_dir_index sindex; >+ squashfs_get_cached_block(s, &sindex, index_start, index_offset, >+ sizeof(sindex), &index_start, &index_offset); >+ SQUASHFS_SWAP_DIR_INDEX(index, &sindex); >+ } else >+ squashfs_get_cached_block(s, index, index_start, index_offset, >+ sizeof(struct squashfs_dir_index), &index_start, &index_offset); >+ >+ squashfs_get_cached_block(s, index->name, index_start, index_offset, >+ index->size + 1, &index_start, &index_offset); >+ >+ index->name[index->size + 1] = '\0'; >+ >+ if (strcmp(index->name, str) > 0) >+ break; >+ >+ length = index->index; >+ *next_block = index->start_block + sblk->directory_table_start; >+ } >+ >+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; >+ kfree(str); >+ >+failure: >+ return length + 3; >+} >+ >+ >+static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) >+{ >+ struct inode *i = file->f_dentry->d_inode; >+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ long long next_block = SQUASHFS_I(i)->start_block + >+ sblk->directory_table_start; >+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; >+ struct squashfs_dir_header dirh; >+ struct squashfs_dir_entry *dire; >+ >+ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); >+ >+ dire = kmalloc(sizeof(struct squashfs_dir_entry) + >+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); >+ if (dire == NULL) { >+ ERROR("Failed to allocate squashfs_dir_entry\n"); >+ goto finish; >+ } >+ >+ while(file->f_pos < 3) { >+ char *name; >+ int size, i_ino; >+ >+ if(file->f_pos == 0) { >+ name = "."; >+ size = 1; >+ i_ino = i->i_ino; >+ } else { >+ name = ".."; >+ size = 2; >+ i_ino = SQUASHFS_I(i)->u.s2.parent_inode; >+ } >+ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", >+ (unsigned int) dirent, name, size, (int) >+ file->f_pos, i_ino, squashfs_filetype_table[1]); >+ >+ if (filldir(dirent, name, size, file->f_pos, i_ino, >+ squashfs_filetype_table[1]) < 0) { >+ TRACE("Filldir returned less than 0\n"); >+ goto finish; >+ } >+ file->f_pos += size; >+ } >+ >+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_start, >+ SQUASHFS_I(i)->u.s2.directory_index_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); >+ >+ while (length < i_size_read(i)) { >+ /* read directory header */ >+ if (msblk->swap) { >+ struct squashfs_dir_header sdirh; >+ >+ if (!squashfs_get_cached_block(i->i_sb, &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, &dirh, next_block, >+ next_offset, sizeof(dirh), &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(dirh); >+ } >+ >+ dir_count = dirh.count + 1; >+ while (dir_count--) { >+ if (msblk->swap) { >+ struct squashfs_dir_entry sdire; >+ if (!squashfs_get_cached_block(i->i_sb, &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, dire, next_block, >+ next_offset, sizeof(*dire), &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(*dire); >+ } >+ >+ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, >+ next_offset, dire->size + 1, &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += dire->size + 1; >+ >+ if (file->f_pos >= length) >+ continue; >+ >+ dire->name[dire->size + 1] = '\0'; >+ >+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", >+ (unsigned int) dirent, dire->name, dire->size + 1, >+ (int) file->f_pos, dirh.start_block, dire->offset, >+ dirh.inode_number + dire->inode_number, >+ squashfs_filetype_table[dire->type]); >+ >+ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos, >+ dirh.inode_number + dire->inode_number, >+ squashfs_filetype_table[dire->type]) < 0) { >+ TRACE("Filldir returned less than 0\n"); >+ goto finish; >+ } >+ file->f_pos = length; >+ } >+ } >+ >+finish: >+ kfree(dire); >+ return 0; >+ >+failed_read: >+ ERROR("Unable to read directory block [%llx:%x]\n", next_block, >+ next_offset); >+ kfree(dire); >+ 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; >+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ long long next_block = SQUASHFS_I(i)->start_block + >+ sblk->directory_table_start; >+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; >+ struct squashfs_dir_header dirh; >+ struct squashfs_dir_entry *dire; >+ >+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); >+ >+ dire = kmalloc(sizeof(struct squashfs_dir_entry) + >+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); >+ if (dire == NULL) { >+ ERROR("Failed to allocate squashfs_dir_entry\n"); >+ goto exit_lookup; >+ } >+ >+ if (len > SQUASHFS_NAME_LEN) >+ goto exit_lookup; >+ >+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_start, >+ SQUASHFS_I(i)->u.s2.directory_index_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_count, name, len); >+ >+ while (length < i_size_read(i)) { >+ /* read directory header */ >+ if (msblk->swap) { >+ struct squashfs_dir_header sdirh; >+ if (!squashfs_get_cached_block(i->i_sb, &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, &dirh, next_block, >+ next_offset, sizeof(dirh), &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(dirh); >+ } >+ >+ dir_count = dirh.count + 1; >+ while (dir_count--) { >+ if (msblk->swap) { >+ struct squashfs_dir_entry sdire; >+ if (!squashfs_get_cached_block(i->i_sb, &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, dire, next_block, >+ next_offset, sizeof(*dire), &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(*dire); >+ } >+ >+ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, >+ next_offset, dire->size + 1, &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += dire->size + 1; >+ >+ if (name[0] < dire->name[0]) >+ goto exit_lookup; >+ >+ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { >+ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, >+ dire->offset); >+ >+ TRACE("calling squashfs_iget for directory entry %s, inode" >+ " %x:%x, %d\n", name, dirh.start_block, dire->offset, >+ dirh.inode_number + dire->inode_number); >+ >+ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); >+ >+ goto exit_lookup; >+ } >+ } >+ } >+ >+exit_lookup: >+ kfree(dire); >+ if (inode) >+ return d_splice_alias(inode, dentry); >+ d_add(dentry, inode); >+ return ERR_PTR(0); >+ >+failed_read: >+ ERROR("Unable to read directory block [%llx:%x]\n", next_block, >+ next_offset); >+ goto exit_lookup; >+} >+ >+ >+static int squashfs_remount(struct super_block *s, int *flags, char *data) >+{ >+ *flags |= MS_RDONLY; >+ return 0; >+} >+ >+ >+static void squashfs_put_super(struct super_block *s) >+{ >+ int i; >+ >+ if (s->s_fs_info) { >+ struct squashfs_sb_info *sbi = 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) >+ vfree(sbi->block_cache[i].data); >+ if (sbi->fragment) >+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) >+ vfree(sbi->fragment[i].data); >+ kfree(sbi->fragment); >+ kfree(sbi->block_cache); >+ vfree(sbi->read_page); >+ kfree(sbi->uid); >+ kfree(sbi->fragment_index); >+ kfree(sbi->fragment_index_2); >+ kfree(sbi->meta_index); >+ vfree(sbi->stream.workspace); >+ kfree(s->s_fs_info); >+ s->s_fs_info = NULL; >+ } >+} >+ >+ >+static int squashfs_get_sb(struct file_system_type *fs_type, int flags, >+ const char *dev_name, void *data, struct vfsmount *mnt) >+{ >+ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, >+ mnt); >+} >+ >+ >+static int __init init_squashfs_fs(void) >+{ >+ int err = init_inodecache(); >+ if (err) >+ goto out; >+ >+ printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) " >+ "Phillip Lougher\n"); >+ >+ err = register_filesystem(&squashfs_fs_type); >+ if (err) >+ destroy_inodecache(); >+ >+out: >+ return err; >+} >+ >+ >+static void __exit exit_squashfs_fs(void) >+{ >+ unregister_filesystem(&squashfs_fs_type); >+ destroy_inodecache(); >+} >+ >+ >+static struct kmem_cache * squashfs_inode_cachep; >+ >+ >+static struct inode *squashfs_alloc_inode(struct super_block *sb) >+{ >+ struct squashfs_inode_info *ei; >+ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); >+ return ei ? &ei->vfs_inode : NULL; >+} >+ >+ >+static void squashfs_destroy_inode(struct inode *inode) >+{ >+ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); >+} >+ >+ >+static void init_once(struct kmem_cache *cachep, void *foo) >+{ >+ struct squashfs_inode_info *ei = foo; >+ >+ inode_init_once(&ei->vfs_inode); >+} >+ >+ >+static int __init 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); >+ if (squashfs_inode_cachep == NULL) >+ return -ENOMEM; >+ return 0; >+} >+ >+ >+static void destroy_inodecache(void) >+{ >+ kmem_cache_destroy(squashfs_inode_cachep); >+} >+ >+ >+module_init(init_squashfs_fs); >+module_exit(exit_squashfs_fs); >+MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem"); >+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); >+MODULE_LICENSE("GPL"); >unchanged: >--- /dev/null >+++ linux-2.6.25-gentoo/fs/squashfs/Makefile >@@ -0,0 +1,7 @@ >+# >+# Makefile for the linux squashfs routines. >+# >+ >+obj-$(CONFIG_SQUASHFS) += squashfs.o >+squashfs-y += inode.o >+squashfs-y += squashfs2_0.o >unchanged: >--- /dev/null >+++ linux-2.6.25-gentoo/fs/squashfs/squashfs2_0.c >@@ -0,0 +1,740 @@ >+/* >+ * Squashfs - a compressed read only filesystem for Linux >+ * >+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 >+ * 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. >+ * >+ * squashfs2_0.c >+ */ >+ >+#include <linux/squashfs_fs.h> >+#include <linux/module.h> >+#include <linux/zlib.h> >+#include <linux/fs.h> >+#include <linux/squashfs_fs_sb.h> >+#include <linux/squashfs_fs_i.h> >+ >+#include "squashfs.h" >+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); >+static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, >+ struct nameidata *); >+ >+static struct file_operations squashfs_dir_ops_2 = { >+ .read = generic_read_dir, >+ .readdir = squashfs_readdir_2 >+}; >+ >+static struct inode_operations squashfs_dir_inode_ops_2 = { >+ .lookup = squashfs_lookup_2 >+}; >+ >+static unsigned char squashfs_filetype_table[] = { >+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK >+}; >+ >+static int read_fragment_index_table_2(struct super_block *s) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ >+ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 >+ (sblk->fragments), GFP_KERNEL))) { >+ ERROR("Failed to allocate uid/gid table\n"); >+ return 0; >+ } >+ >+ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && >+ !squashfs_read_data(s, (char *) >+ msblk->fragment_index_2, >+ sblk->fragment_table_start, >+ SQUASHFS_FRAGMENT_INDEX_BYTES_2 >+ (sblk->fragments) | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { >+ ERROR("unable to read fragment index table\n"); >+ return 0; >+ } >+ >+ if (msblk->swap) { >+ int i; >+ unsigned int fragment; >+ >+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); >+ i++) { >+ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), >+ &msblk->fragment_index_2[i], 1); >+ msblk->fragment_index_2[i] = fragment; >+ } >+ } >+ >+ return 1; >+} >+ >+ >+static int get_fragment_location_2(struct super_block *s, unsigned int fragment, >+ long long *fragment_start_block, >+ unsigned int *fragment_size) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ long long start_block = >+ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; >+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); >+ struct squashfs_fragment_entry_2 fragment_entry; >+ >+ if (msblk->swap) { >+ struct squashfs_fragment_entry_2 sfragment_entry; >+ >+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, >+ start_block, offset, >+ sizeof(sfragment_entry), &start_block, >+ &offset)) >+ goto out; >+ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, >+ start_block, offset, >+ sizeof(fragment_entry), &start_block, >+ &offset)) >+ goto out; >+ >+ *fragment_start_block = fragment_entry.start_block; >+ *fragment_size = fragment_entry.size; >+ >+ return 1; >+ >+out: >+ return 0; >+} >+ >+ >+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, >+ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) >+{ >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ >+ i->i_ino = ino; >+ 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_mode = inodeb->mode; >+ i->i_nlink = 1; >+ i->i_size = 0; >+ if (inodeb->guid == SQUASHFS_GUIDS) >+ i->i_gid = i->i_uid; >+ else >+ i->i_gid = msblk->guid[inodeb->guid]; >+} >+ >+ >+static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) >+{ >+ struct super_block *s = i->i_sb; >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ unsigned int block = SQUASHFS_INODE_BLK(inode) + >+ sblk->inode_table_start; >+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); >+ unsigned int ino = SQUASHFS_MK_VFS_INODE(block - >+ sblk->inode_table_start, offset); >+ long long next_block; >+ unsigned int next_offset; >+ union squashfs_inode_header_2 id, sid; >+ struct squashfs_base_inode_header_2 *inodeb = &id.base, >+ *sinodeb = &sid.base; >+ >+ TRACE("Entered squashfs_read_inode_2\n"); >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, >+ offset, sizeof(*sinodeb), &next_block, >+ &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, >+ sizeof(*sinodeb)); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) inodeb, block, >+ offset, sizeof(*inodeb), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ squashfs_new_inode(msblk, i, inodeb, ino); >+ >+ switch(inodeb->inode_type) { >+ case SQUASHFS_FILE_TYPE: { >+ struct squashfs_reg_inode_header_2 *inodep = &id.reg; >+ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; >+ long long frag_blk; >+ unsigned int frag_size = 0; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, (char *) >+ sinodep, block, offset, >+ sizeof(*sinodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) >+ inodep, block, offset, >+ sizeof(*inodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ frag_blk = SQUASHFS_INVALID_BLK; >+ if (inodep->fragment != SQUASHFS_INVALID_FRAG && >+ !get_fragment_location_2(s, >+ inodep->fragment, &frag_blk, &frag_size)) >+ goto failed_read; >+ >+ i->i_size = inodep->file_size; >+ i->i_fop = &generic_ro_fops; >+ 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; >+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; >+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; >+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; >+ SQUASHFS_I(i)->start_block = inodep->start_block; >+ SQUASHFS_I(i)->u.s1.block_list_start = next_block; >+ SQUASHFS_I(i)->offset = next_offset; >+ i->i_data.a_ops = &squashfs_aops; >+ >+ TRACE("File inode %x:%x, start_block %x, " >+ "block_list_start %llx, offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ inodep->start_block, next_block, >+ next_offset); >+ break; >+ } >+ case SQUASHFS_DIR_TYPE: { >+ struct squashfs_dir_inode_header_2 *inodep = &id.dir; >+ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, (char *) >+ sinodep, block, offset, >+ sizeof(*sinodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) >+ inodep, block, offset, >+ sizeof(*inodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ i->i_size = inodep->file_size; >+ i->i_op = &squashfs_dir_inode_ops_2; >+ i->i_fop = &squashfs_dir_ops_2; >+ i->i_mode |= S_IFDIR; >+ i->i_mtime.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; >+ SQUASHFS_I(i)->u.s2.parent_inode = 0; >+ >+ TRACE("Directory inode %x:%x, start_block %x, offset " >+ "%x\n", SQUASHFS_INODE_BLK(inode), >+ offset, inodep->start_block, >+ inodep->offset); >+ break; >+ } >+ case SQUASHFS_LDIR_TYPE: { >+ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; >+ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, (char *) >+ sinodep, block, offset, >+ sizeof(*sinodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, >+ sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) >+ inodep, block, offset, >+ sizeof(*inodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ i->i_size = inodep->file_size; >+ i->i_op = &squashfs_dir_inode_ops_2; >+ i->i_fop = &squashfs_dir_ops_2; >+ i->i_mode |= S_IFDIR; >+ i->i_mtime.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; >+ SQUASHFS_I(i)->u.s2.parent_inode = 0; >+ >+ TRACE("Long directory inode %x:%x, start_block %x, " >+ "offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ inodep->start_block, inodep->offset); >+ break; >+ } >+ case SQUASHFS_SYMLINK_TYPE: { >+ struct squashfs_symlink_inode_header_2 *inodep = >+ &id.symlink; >+ struct squashfs_symlink_inode_header_2 *sinodep = >+ &sid.symlink; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, (char *) >+ sinodep, block, offset, >+ sizeof(*sinodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, >+ sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) >+ inodep, block, offset, >+ sizeof(*inodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ i->i_size = inodep->symlink_size; >+ i->i_op = &page_symlink_inode_operations; >+ i->i_data.a_ops = &squashfs_symlink_aops; >+ i->i_mode |= S_IFLNK; >+ SQUASHFS_I(i)->start_block = next_block; >+ SQUASHFS_I(i)->offset = next_offset; >+ >+ TRACE("Symbolic link inode %x:%x, start_block %llx, " >+ "offset %x\n", >+ SQUASHFS_INODE_BLK(inode), offset, >+ next_block, next_offset); >+ break; >+ } >+ case SQUASHFS_BLKDEV_TYPE: >+ case SQUASHFS_CHRDEV_TYPE: { >+ struct squashfs_dev_inode_header_2 *inodep = &id.dev; >+ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; >+ >+ if (msblk->swap) { >+ if (!squashfs_get_cached_block(s, (char *) >+ sinodep, block, offset, >+ sizeof(*sinodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); >+ } else >+ if (!squashfs_get_cached_block(s, (char *) >+ inodep, block, offset, >+ sizeof(*inodep), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ 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_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; >+ } >+ >+ return 1; >+ >+failed_read: >+ ERROR("Unable to read inode [%x:%x]\n", block, offset); >+ >+failed_read1: >+ return 0; >+} >+ >+ >+static int get_dir_index_using_offset(struct super_block *s, long long >+ *next_block, unsigned int *next_offset, >+ long long index_start, >+ unsigned int index_offset, int i_count, >+ long long f_pos) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ int i, length = 0; >+ struct squashfs_dir_index_2 index; >+ >+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", >+ i_count, (unsigned int) f_pos); >+ >+ if (f_pos == 0) >+ goto finish; >+ >+ for (i = 0; i < i_count; i++) { >+ if (msblk->swap) { >+ struct squashfs_dir_index_2 sindex; >+ squashfs_get_cached_block(s, (char *) &sindex, >+ index_start, index_offset, >+ sizeof(sindex), &index_start, >+ &index_offset); >+ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); >+ } else >+ squashfs_get_cached_block(s, (char *) &index, >+ index_start, index_offset, >+ sizeof(index), &index_start, >+ &index_offset); >+ >+ if (index.index > f_pos) >+ break; >+ >+ squashfs_get_cached_block(s, NULL, index_start, index_offset, >+ index.size + 1, &index_start, >+ &index_offset); >+ >+ length = index.index; >+ *next_block = index.start_block + sblk->directory_table_start; >+ } >+ >+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; >+ >+finish: >+ return length; >+} >+ >+ >+static int get_dir_index_using_name(struct super_block *s, long long >+ *next_block, unsigned int *next_offset, >+ long long index_start, >+ unsigned int index_offset, int i_count, >+ const char *name, int size) >+{ >+ struct squashfs_sb_info *msblk = s->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ int i, length = 0; >+ struct squashfs_dir_index_2 *index; >+ char *str; >+ >+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); >+ >+ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + >+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { >+ ERROR("Failed to allocate squashfs_dir_index\n"); >+ goto failure; >+ } >+ >+ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); >+ strncpy(str, name, size); >+ str[size] = '\0'; >+ >+ for (i = 0; i < i_count; i++) { >+ if (msblk->swap) { >+ struct squashfs_dir_index_2 sindex; >+ squashfs_get_cached_block(s, (char *) &sindex, >+ index_start, index_offset, >+ sizeof(sindex), &index_start, >+ &index_offset); >+ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); >+ } else >+ squashfs_get_cached_block(s, (char *) index, >+ index_start, index_offset, >+ sizeof(struct squashfs_dir_index_2), >+ &index_start, &index_offset); >+ >+ squashfs_get_cached_block(s, index->name, index_start, >+ index_offset, index->size + 1, >+ &index_start, &index_offset); >+ >+ index->name[index->size + 1] = '\0'; >+ >+ if (strcmp(index->name, str) > 0) >+ break; >+ >+ length = index->index; >+ *next_block = index->start_block + sblk->directory_table_start; >+ } >+ >+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; >+ kfree(str); >+failure: >+ return length; >+} >+ >+ >+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) >+{ >+ struct inode *i = file->f_dentry->d_inode; >+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ long long next_block = SQUASHFS_I(i)->start_block + >+ sblk->directory_table_start; >+ int next_offset = SQUASHFS_I(i)->offset, length = 0, >+ dir_count; >+ struct squashfs_dir_header_2 dirh; >+ struct squashfs_dir_entry_2 *dire; >+ >+ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); >+ >+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + >+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { >+ ERROR("Failed to allocate squashfs_dir_entry\n"); >+ goto finish; >+ } >+ >+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_start, >+ SQUASHFS_I(i)->u.s2.directory_index_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_count, >+ file->f_pos); >+ >+ while (length < i_size_read(i)) { >+ /* read directory header */ >+ if (msblk->swap) { >+ struct squashfs_dir_header_2 sdirh; >+ >+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, >+ next_block, next_offset, sizeof(sdirh), >+ &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(sdirh); >+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); >+ } else { >+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, >+ next_block, next_offset, sizeof(dirh), >+ &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(dirh); >+ } >+ >+ dir_count = dirh.count + 1; >+ while (dir_count--) { >+ if (msblk->swap) { >+ struct squashfs_dir_entry_2 sdire; >+ if (!squashfs_get_cached_block(i->i_sb, (char *) >+ &sdire, next_block, next_offset, >+ sizeof(sdire), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(sdire); >+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); >+ } else { >+ if (!squashfs_get_cached_block(i->i_sb, (char *) >+ dire, next_block, next_offset, >+ sizeof(*dire), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(*dire); >+ } >+ >+ if (!squashfs_get_cached_block(i->i_sb, dire->name, >+ next_block, next_offset, >+ dire->size + 1, &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ length += dire->size + 1; >+ >+ if (file->f_pos >= length) >+ continue; >+ >+ dire->name[dire->size + 1] = '\0'; >+ >+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", >+ (unsigned int) dirent, dire->name, >+ dire->size + 1, (int) file->f_pos, >+ dirh.start_block, dire->offset, >+ squashfs_filetype_table[dire->type]); >+ >+ if (filldir(dirent, dire->name, dire->size + 1, >+ file->f_pos, SQUASHFS_MK_VFS_INODE( >+ dirh.start_block, dire->offset), >+ squashfs_filetype_table[dire->type]) >+ < 0) { >+ TRACE("Filldir returned less than 0\n"); >+ goto finish; >+ } >+ file->f_pos = length; >+ } >+ } >+ >+finish: >+ kfree(dire); >+ return 0; >+ >+failed_read: >+ ERROR("Unable to read directory block [%llx:%x]\n", next_block, >+ next_offset); >+ kfree(dire); >+ return 0; >+} >+ >+ >+static struct dentry *squashfs_lookup_2(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; >+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ long long next_block = SQUASHFS_I(i)->start_block + >+ sblk->directory_table_start; >+ int next_offset = SQUASHFS_I(i)->offset, length = 0, >+ dir_count; >+ struct squashfs_dir_header_2 dirh; >+ struct squashfs_dir_entry_2 *dire; >+ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; >+ >+ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); >+ >+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + >+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { >+ ERROR("Failed to allocate squashfs_dir_entry\n"); >+ goto exit_loop; >+ } >+ >+ if (len > SQUASHFS_NAME_LEN) >+ goto exit_loop; >+ >+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_start, >+ SQUASHFS_I(i)->u.s2.directory_index_offset, >+ SQUASHFS_I(i)->u.s2.directory_index_count, name, >+ len); >+ >+ while (length < i_size_read(i)) { >+ /* read directory header */ >+ if (msblk->swap) { >+ struct squashfs_dir_header_2 sdirh; >+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, >+ next_block, next_offset, sizeof(sdirh), >+ &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(sdirh); >+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); >+ } else { >+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, >+ next_block, next_offset, sizeof(dirh), >+ &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(dirh); >+ } >+ >+ dir_count = dirh.count + 1; >+ while (dir_count--) { >+ if (msblk->swap) { >+ struct squashfs_dir_entry_2 sdire; >+ if (!squashfs_get_cached_block(i->i_sb, (char *) >+ &sdire, next_block,next_offset, >+ sizeof(sdire), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(sdire); >+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); >+ } else { >+ if (!squashfs_get_cached_block(i->i_sb, (char *) >+ dire, next_block,next_offset, >+ sizeof(*dire), &next_block, >+ &next_offset)) >+ goto failed_read; >+ >+ length += sizeof(*dire); >+ } >+ >+ if (!squashfs_get_cached_block(i->i_sb, dire->name, >+ next_block, next_offset, dire->size + 1, >+ &next_block, &next_offset)) >+ goto failed_read; >+ >+ length += dire->size + 1; >+ >+ if (sorted && name[0] < dire->name[0]) >+ goto exit_loop; >+ >+ if ((len == dire->size + 1) && !strncmp(name, >+ dire->name, len)) { >+ squashfs_inode_t ino = >+ SQUASHFS_MKINODE(dirh.start_block, >+ dire->offset); >+ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, >+ dire->offset); >+ >+ TRACE("calling squashfs_iget for directory " >+ "entry %s, inode %x:%x, %lld\n", name, >+ dirh.start_block, dire->offset, ino); >+ >+ inode = squashfs_iget(i->i_sb, ino, inode_number); >+ >+ goto exit_loop; >+ } >+ } >+ } >+ >+exit_loop: >+ kfree(dire); >+ d_add(dentry, inode); >+ return ERR_PTR(0); >+ >+failed_read: >+ ERROR("Unable to read directory block [%llx:%x]\n", next_block, >+ next_offset); >+ goto exit_loop; >+} >+ >+ >+int squashfs_2_0_supported(struct squashfs_sb_info *msblk) >+{ >+ struct squashfs_super_block *sblk = &msblk->sblk; >+ >+ msblk->read_inode = squashfs_read_inode_2; >+ msblk->read_fragment_index_table = read_fragment_index_table_2; >+ >+ sblk->bytes_used = sblk->bytes_used_2; >+ sblk->uid_start = sblk->uid_start_2; >+ sblk->guid_start = sblk->guid_start_2; >+ sblk->inode_table_start = sblk->inode_table_start_2; >+ sblk->directory_table_start = sblk->directory_table_start_2; >+ sblk->fragment_table_start = sblk->fragment_table_start_2; >+ >+ return 1; >+} >unchanged: >--- /dev/null >+++ linux-2.6.25-gentoo/fs/squashfs/squashfs.h >@@ -0,0 +1,86 @@ >+/* >+ * Squashfs - a compressed read only filesystem for Linux >+ * >+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 >+ * 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.h >+ */ >+ >+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY >+#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY >+#endif >+ >+#ifdef SQUASHFS_TRACE >+#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) >+#else >+#define TRACE(s, args...) {} >+#endif >+ >+#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) >+ >+#define SERROR(s, args...) do { \ >+ if (!silent) \ >+ printk(KERN_ERR "SQUASHFS error: "s, ## args);\ >+ } while(0) >+ >+#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) >+ >+static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) >+{ >+ return list_entry(inode, struct squashfs_inode_info, vfs_inode); >+} >+ >+#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) >+#define SQSH_EXTERN >+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, >+ long long index, unsigned int length, >+ long long *next_index, int srclength); >+extern int squashfs_get_cached_block(struct super_block *s, void *buffer, >+ long long block, unsigned int offset, >+ int length, long long *next_block, >+ unsigned int *next_offset); >+extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct >+ squashfs_fragment_cache *fragment); >+extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block >+ *s, long long start_block, >+ int length); >+extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); >+extern const struct address_space_operations squashfs_symlink_aops; >+extern const struct address_space_operations squashfs_aops; >+extern struct inode_operations squashfs_dir_inode_ops; >+#else >+#define SQSH_EXTERN static >+#endif >+ >+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY >+extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); >+#else >+static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) >+{ >+ return 0; >+} >+#endif >+ >+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY >+extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); >+#else >+static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) >+{ >+ return 0; >+} >+#endif >unchanged: >--- /dev/null >+++ linux-2.6.25-gentoo/include/linux/squashfs_fs.h >@@ -0,0 +1,935 @@ >+#ifndef SQUASHFS_FS >+#define SQUASHFS_FS >+ >+/* >+ * Squashfs >+ * >+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 >+ * 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 >+ */ >+ >+#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY >+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY >+#endif >+ >+#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE >+#define SQUASHFS_MAJOR 3 >+#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 131072 >+#define SQUASHFS_FILE_LOG 17 >+ >+#define SQUASHFS_FILE_MAX_SIZE 1048576 >+ >+/* Max number of uids and gids */ >+#define SQUASHFS_UIDS 256 >+#define SQUASHFS_GUIDS 255 >+ >+/* Max length of filename (not 255) */ >+#define SQUASHFS_NAME_LEN 256 >+ >+#define SQUASHFS_INVALID ((long long) 0xffffffffffff) >+#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) >+#define SQUASHFS_INVALID_BLK ((long long) -1) >+#define SQUASHFS_USED_BLK ((long long) -2) >+ >+/* Filesystem flags */ >+#define SQUASHFS_NOI 0 >+#define SQUASHFS_NOD 1 >+#define SQUASHFS_CHECK 2 >+#define SQUASHFS_NOF 3 >+#define SQUASHFS_NO_FRAG 4 >+#define SQUASHFS_ALWAYS_FRAG 5 >+#define SQUASHFS_DUPLICATE 6 >+#define SQUASHFS_EXPORT 7 >+ >+#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_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ >+ SQUASHFS_EXPORT) >+ >+#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ >+ SQUASHFS_CHECK) >+ >+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ >+ duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \ >+ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ >+ (duplicate_checking << 6) | (exportable << 7)) >+ >+/* Max number of types and file types */ >+#define SQUASHFS_DIR_TYPE 1 >+#define SQUASHFS_FILE_TYPE 2 >+#define SQUASHFS_SYMLINK_TYPE 3 >+#define SQUASHFS_BLKDEV_TYPE 4 >+#define SQUASHFS_CHRDEV_TYPE 5 >+#define SQUASHFS_FIFO_TYPE 6 >+#define SQUASHFS_SOCKET_TYPE 7 >+#define SQUASHFS_LDIR_TYPE 8 >+#define SQUASHFS_LREG_TYPE 9 >+ >+/* 1.0 filesystem type definitions */ >+#define SQUASHFS_TYPES 5 >+#define SQUASHFS_IPC_TYPE 0 >+ >+/* Flag whether block is compressed or uncompressed, bit is set if block is >+ * uncompressed */ >+#define SQUASHFS_COMPRESSED_BIT (1 << 15) >+ >+#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ >+ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) >+ >+#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) >+ >+#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) >+ >+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ >+ ~SQUASHFS_COMPRESSED_BIT_BLOCK) >+ >+#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) >+ >+/* >+ * Inode number ops. Inodes consist of a compressed block number, and an >+ * uncompressed offset within that block >+ */ >+#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) >+ >+#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) >+ >+#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ >+ << 16) + (B))) >+ >+/* Compute 32 bit VFS inode number from squashfs inode number */ >+#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ >+ ((b) >> 2) + 1)) >+/* XXX */ >+ >+/* Translate between VFS mode and squashfs mode */ >+#define SQUASHFS_MODE(a) ((a) & 0xfff) >+ >+/* fragment and fragment table defines */ >+#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) >+ >+#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ >+ SQUASHFS_METADATA_SIZE - 1) / \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ >+ sizeof(long long)) >+ >+/* inode lookup table defines */ >+#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) >+ >+#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ >+ SQUASHFS_METADATA_SIZE - 1) / \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ >+ sizeof(long long)) >+ >+/* cached data constants for filesystem */ >+#define SQUASHFS_CACHED_BLKS 8 >+ >+#define SQUASHFS_MAX_FILE_SIZE_LOG 64 >+ >+#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ >+ (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) >+ >+#define SQUASHFS_MARKER_BYTE 0xff >+ >+/* meta index cache */ >+#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) >+#define SQUASHFS_META_ENTRIES 31 >+#define SQUASHFS_META_NUMBER 8 >+#define SQUASHFS_SLOTS 4 >+ >+struct meta_entry { >+ long long data_block; >+ unsigned int index_block; >+ unsigned short offset; >+ unsigned short pad; >+}; >+ >+struct meta_index { >+ unsigned int inode_number; >+ unsigned int offset; >+ unsigned short entries; >+ unsigned short skip; >+ unsigned short locked; >+ unsigned short pad; >+ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; >+}; >+ >+ >+/* >+ * definitions for structures on disk >+ */ >+ >+typedef long long squashfs_block_t; >+typedef long long squashfs_inode_t; >+ >+struct squashfs_super_block { >+ unsigned int s_magic; >+ unsigned int inodes; >+ unsigned int bytes_used_2; >+ unsigned int uid_start_2; >+ unsigned int guid_start_2; >+ unsigned int inode_table_start_2; >+ unsigned int directory_table_start_2; >+ unsigned int s_major:16; >+ unsigned int s_minor:16; >+ unsigned int block_size_1:16; >+ unsigned int block_log:16; >+ unsigned int flags:8; >+ unsigned int no_uids:8; >+ unsigned int no_guids:8; >+ unsigned int mkfs_time /* time of filesystem creation */; >+ squashfs_inode_t root_inode; >+ unsigned int block_size; >+ unsigned int fragments; >+ unsigned int fragment_table_start_2; >+ long long bytes_used; >+ long long uid_start; >+ long long guid_start; >+ long long inode_table_start; >+ long long directory_table_start; >+ long long fragment_table_start; >+ long long lookup_table_start; >+} __attribute__ ((packed)); >+ >+struct squashfs_dir_index { >+ unsigned int index; >+ unsigned int start_block; >+ unsigned char size; >+ unsigned char name[0]; >+} __attribute__ ((packed)); >+ >+#define SQUASHFS_BASE_INODE_HEADER \ >+ unsigned int inode_type:4; \ >+ unsigned int mode:12; \ >+ unsigned int uid:8; \ >+ unsigned int guid:8; \ >+ unsigned int mtime; \ >+ unsigned int inode_number; >+ >+struct squashfs_base_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+} __attribute__ ((packed)); >+ >+struct squashfs_ipc_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ unsigned int nlink; >+} __attribute__ ((packed)); >+ >+struct squashfs_dev_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ unsigned int nlink; >+ unsigned short rdev; >+} __attribute__ ((packed)); >+ >+struct squashfs_symlink_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ unsigned int nlink; >+ unsigned short symlink_size; >+ char symlink[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_reg_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ squashfs_block_t start_block; >+ unsigned int fragment; >+ unsigned int offset; >+ unsigned int file_size; >+ unsigned short block_list[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_lreg_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ unsigned int nlink; >+ squashfs_block_t start_block; >+ unsigned int fragment; >+ unsigned int offset; >+ long long file_size; >+ unsigned short block_list[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_dir_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ unsigned int nlink; >+ unsigned int file_size:19; >+ unsigned int offset:13; >+ unsigned int start_block; >+ unsigned int parent_inode; >+} __attribute__ ((packed)); >+ >+struct squashfs_ldir_inode_header { >+ SQUASHFS_BASE_INODE_HEADER; >+ unsigned int nlink; >+ unsigned int file_size:27; >+ unsigned int offset:13; >+ unsigned int start_block; >+ unsigned int i_count:16; >+ unsigned int parent_inode; >+ struct squashfs_dir_index index[0]; >+} __attribute__ ((packed)); >+ >+union squashfs_inode_header { >+ struct squashfs_base_inode_header base; >+ struct squashfs_dev_inode_header dev; >+ struct squashfs_symlink_inode_header symlink; >+ struct squashfs_reg_inode_header reg; >+ struct squashfs_lreg_inode_header lreg; >+ struct squashfs_dir_inode_header dir; >+ struct squashfs_ldir_inode_header ldir; >+ struct squashfs_ipc_inode_header ipc; >+}; >+ >+struct squashfs_dir_entry { >+ unsigned int offset:13; >+ unsigned int type:3; >+ unsigned int size:8; >+ int inode_number:16; >+ char name[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_dir_header { >+ unsigned int count:8; >+ unsigned int start_block; >+ unsigned int inode_number; >+} __attribute__ ((packed)); >+ >+struct squashfs_fragment_entry { >+ long long start_block; >+ unsigned int size; >+ unsigned int pending; >+} __attribute__ ((packed)); >+ >+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); >+extern int squashfs_uncompress_init(void); >+extern int squashfs_uncompress_exit(void); >+ >+/* >+ * macros to convert each packed bitfield structure from little endian to big >+ * endian and vice versa. These are needed when creating or using a filesystem >+ * on a machine with different byte ordering to the target architecture. >+ * >+ */ >+ >+#define SQUASHFS_SWAP_START \ >+ int bits;\ >+ int b_pos;\ >+ unsigned long long val;\ >+ unsigned char *s;\ >+ unsigned char *d; >+ >+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ >+ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ >+ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ >+ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ >+ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ >+ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ >+ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ >+ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ >+ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ >+ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ >+ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ >+ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ >+ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ >+ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ >+ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ >+ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ >+ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ >+ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ >+ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ >+ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ >+ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ >+ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ >+ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ >+ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ >+ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ >+ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ >+} >+ >+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ >+ SQUASHFS_MEMSET(s, d, n);\ >+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ >+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ >+ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ >+ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ >+ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ >+ SQUASHFS_SWAP((s)->inode_number, d, 64, 32); >+ >+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ >+} >+ >+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_ipc_inode_header))\ >+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ >+} >+ >+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_dev_inode_header)); \ >+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ >+} >+ >+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_symlink_inode_header));\ >+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ >+} >+ >+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_reg_inode_header));\ >+ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ >+ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ >+ SQUASHFS_SWAP((s)->offset, d, 192, 32);\ >+ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ >+} >+ >+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_lreg_inode_header));\ >+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ >+ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ >+ SQUASHFS_SWAP((s)->offset, d, 224, 32);\ >+ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_dir_inode_header));\ >+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ >+ SQUASHFS_SWAP((s)->offset, d, 147, 13);\ >+ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ >+ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ >+} >+ >+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ >+ sizeof(struct squashfs_ldir_inode_header));\ >+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ >+ SQUASHFS_SWAP((s)->offset, d, 155, 13);\ >+ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ >+ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ >+ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ >+ SQUASHFS_SWAP((s)->index, d, 0, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ >+ SQUASHFS_SWAP((s)->size, d, 64, 8);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ >+ SQUASHFS_SWAP((s)->count, d, 0, 8);\ >+ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ >+ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ >+ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ >+ SQUASHFS_SWAP((s)->type, d, 13, 3);\ >+ SQUASHFS_SWAP((s)->size, d, 16, 8);\ >+ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ >+} >+ >+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ >+ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ >+ SQUASHFS_SWAP((s)->size, d, 64, 32);\ >+} >+ >+#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) >+ >+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ >+ int entry;\ >+ int bit_position;\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, n * 2);\ >+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ >+ 16)\ >+ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ >+} >+ >+#define SQUASHFS_SWAP_INTS(s, d, n) {\ >+ int entry;\ >+ int bit_position;\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, n * 4);\ >+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ >+ 32)\ >+ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ >+} >+ >+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ >+ int entry;\ >+ int bit_position;\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, n * 8);\ >+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ >+ 64)\ >+ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ >+} >+ >+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ >+ int entry;\ >+ int bit_position;\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, n * bits / 8);\ >+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ >+ bits)\ >+ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ >+} >+ >+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) >+#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) >+ >+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY >+ >+struct squashfs_base_inode_header_1 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:4; /* index into uid table */ >+ unsigned int guid:4; /* index into guid table */ >+} __attribute__ ((packed)); >+ >+struct squashfs_ipc_inode_header_1 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:4; /* index into uid table */ >+ unsigned int guid:4; /* index into guid table */ >+ unsigned int type:4; >+ unsigned int offset:4; >+} __attribute__ ((packed)); >+ >+struct squashfs_dev_inode_header_1 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:4; /* index into uid table */ >+ unsigned int guid:4; /* index into guid table */ >+ unsigned short rdev; >+} __attribute__ ((packed)); >+ >+struct squashfs_symlink_inode_header_1 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:4; /* index into uid table */ >+ unsigned int guid:4; /* index into guid table */ >+ unsigned short symlink_size; >+ char symlink[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_reg_inode_header_1 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:4; /* index into uid table */ >+ unsigned int guid:4; /* index into guid table */ >+ unsigned int mtime; >+ unsigned int start_block; >+ unsigned int file_size:32; >+ unsigned short block_list[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_dir_inode_header_1 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:4; /* index into uid table */ >+ unsigned int guid:4; /* index into guid table */ >+ unsigned int file_size:19; >+ unsigned int offset:13; >+ unsigned int mtime; >+ unsigned int start_block:24; >+} __attribute__ ((packed)); >+ >+union squashfs_inode_header_1 { >+ struct squashfs_base_inode_header_1 base; >+ struct squashfs_dev_inode_header_1 dev; >+ struct squashfs_symlink_inode_header_1 symlink; >+ struct squashfs_reg_inode_header_1 reg; >+ struct squashfs_dir_inode_header_1 dir; >+ struct squashfs_ipc_inode_header_1 ipc; >+}; >+ >+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ >+ SQUASHFS_MEMSET(s, d, n);\ >+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ >+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ >+ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ >+ SQUASHFS_SWAP((s)->guid, d, 20, 4); >+ >+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ >+} >+ >+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ >+ sizeof(struct squashfs_ipc_inode_header_1));\ >+ SQUASHFS_SWAP((s)->type, d, 24, 4);\ >+ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ >+} >+ >+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ >+ sizeof(struct squashfs_dev_inode_header_1));\ >+ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ >+} >+ >+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ >+ sizeof(struct squashfs_symlink_inode_header_1));\ >+ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ >+} >+ >+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ >+ sizeof(struct squashfs_reg_inode_header_1));\ >+ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ >+ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ >+ sizeof(struct squashfs_dir_inode_header_1));\ >+ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ >+ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ >+ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ >+} >+ >+#endif >+ >+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY >+ >+struct squashfs_dir_index_2 { >+ unsigned int index:27; >+ unsigned int start_block:29; >+ unsigned char size; >+ unsigned char name[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_base_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+} __attribute__ ((packed)); >+ >+struct squashfs_ipc_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+} __attribute__ ((packed)); >+ >+struct squashfs_dev_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+ unsigned short rdev; >+} __attribute__ ((packed)); >+ >+struct squashfs_symlink_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+ unsigned short symlink_size; >+ char symlink[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_reg_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+ unsigned int mtime; >+ unsigned int start_block; >+ unsigned int fragment; >+ unsigned int offset; >+ unsigned int file_size:32; >+ unsigned short block_list[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_dir_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+ unsigned int file_size:19; >+ unsigned int offset:13; >+ unsigned int mtime; >+ unsigned int start_block:24; >+} __attribute__ ((packed)); >+ >+struct squashfs_ldir_inode_header_2 { >+ unsigned int inode_type:4; >+ unsigned int mode:12; /* protection */ >+ unsigned int uid:8; /* index into uid table */ >+ unsigned int guid:8; /* index into guid table */ >+ unsigned int file_size:27; >+ unsigned int offset:13; >+ unsigned int mtime; >+ unsigned int start_block:24; >+ unsigned int i_count:16; >+ struct squashfs_dir_index_2 index[0]; >+} __attribute__ ((packed)); >+ >+union squashfs_inode_header_2 { >+ struct squashfs_base_inode_header_2 base; >+ struct squashfs_dev_inode_header_2 dev; >+ struct squashfs_symlink_inode_header_2 symlink; >+ struct squashfs_reg_inode_header_2 reg; >+ struct squashfs_dir_inode_header_2 dir; >+ struct squashfs_ldir_inode_header_2 ldir; >+ struct squashfs_ipc_inode_header_2 ipc; >+}; >+ >+struct squashfs_dir_header_2 { >+ unsigned int count:8; >+ unsigned int start_block:24; >+} __attribute__ ((packed)); >+ >+struct squashfs_dir_entry_2 { >+ unsigned int offset:13; >+ unsigned int type:3; >+ unsigned int size:8; >+ char name[0]; >+} __attribute__ ((packed)); >+ >+struct squashfs_fragment_entry_2 { >+ unsigned int start_block; >+ unsigned int size; >+} __attribute__ ((packed)); >+ >+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ >+ SQUASHFS_MEMSET(s, d, n);\ >+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ >+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ >+ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ >+ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ >+ >+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ >+} >+ >+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ >+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) >+ >+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ >+ sizeof(struct squashfs_dev_inode_header_2)); \ >+ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ >+} >+ >+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ >+ sizeof(struct squashfs_symlink_inode_header_2));\ >+ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ >+} >+ >+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ >+ sizeof(struct squashfs_reg_inode_header_2));\ >+ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ >+ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ >+ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ >+ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ >+ sizeof(struct squashfs_dir_inode_header_2));\ >+ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ >+ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ >+ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ >+} >+ >+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ >+ sizeof(struct squashfs_ldir_inode_header_2));\ >+ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ >+ SQUASHFS_SWAP((s)->offset, d, 59, 13);\ >+ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ >+ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ >+ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ >+ SQUASHFS_SWAP((s)->index, d, 0, 27);\ >+ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ >+ SQUASHFS_SWAP((s)->size, d, 56, 8);\ >+} >+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ >+ SQUASHFS_SWAP((s)->count, d, 0, 8);\ >+ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ >+} >+ >+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ >+ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ >+ SQUASHFS_SWAP((s)->type, d, 13, 3);\ >+ SQUASHFS_SWAP((s)->size, d, 16, 8);\ >+} >+ >+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ >+ SQUASHFS_SWAP_START\ >+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ >+ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ >+ SQUASHFS_SWAP((s)->size, d, 32, 32);\ >+} >+ >+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) >+ >+/* fragment and fragment table defines */ >+#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) >+ >+#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ >+ SQUASHFS_METADATA_SIZE - 1) / \ >+ SQUASHFS_METADATA_SIZE) >+ >+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ >+ sizeof(int)) >+ >+#endif >+ >+#ifdef __KERNEL__ >+ >+/* >+ * macros used to swap each structure entry, taking into account >+ * bitfields and different bitfield placing conventions on differing >+ * architectures >+ */ >+ >+#include <asm/byteorder.h> >+ >+#ifdef __BIG_ENDIAN >+ /* convert from little endian to big endian */ >+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ >+ tbits, b_pos) >+#else >+ /* convert from big endian to little endian */ >+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ >+ tbits, 64 - tbits - b_pos) >+#endif >+ >+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ >+ b_pos = pos % 8;\ >+ val = 0;\ >+ s = (unsigned char *)p + (pos / 8);\ >+ d = ((unsigned char *) &val) + 7;\ >+ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ >+ *d-- = *s++;\ >+ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ >+} >+ >+#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); >+ >+#endif >+#endif >unchanged: >--- /dev/null >+++ linux-2.6.25-gentoo/include/linux/squashfs_fs_i.h >@@ -0,0 +1,45 @@ >+#ifndef SQUASHFS_FS_I >+#define SQUASHFS_FS_I >+/* >+ * Squashfs >+ * >+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 >+ * 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 >+ */ >+ >+struct squashfs_inode_info { >+ long long start_block; >+ unsigned int offset; >+ union { >+ struct { >+ long long fragment_start_block; >+ unsigned int fragment_size; >+ unsigned int fragment_offset; >+ long long block_list_start; >+ } s1; >+ struct { >+ long long directory_index_start; >+ unsigned int directory_index_offset; >+ unsigned int directory_index_count; >+ unsigned int parent_inode; >+ } s2; >+ } u; >+ struct inode vfs_inode; >+}; >+#endif >unchanged: >--- /dev/null >+++ linux-2.6.25-gentoo/include/linux/squashfs_fs_sb.h >@@ -0,0 +1,76 @@ >+#ifndef SQUASHFS_FS_SB >+#define SQUASHFS_FS_SB >+/* >+ * Squashfs >+ * >+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 >+ * 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> >+ >+struct squashfs_cache { >+ long long block; >+ int length; >+ long long next_index; >+ char *data; >+}; >+ >+struct squashfs_fragment_cache { >+ long long block; >+ int length; >+ unsigned int locked; >+ char *data; >+}; >+ >+struct squashfs_sb_info { >+ struct squashfs_super_block sblk; >+ int devblksize; >+ int devblksize_log2; >+ int swap; >+ struct squashfs_cache *block_cache; >+ struct squashfs_fragment_cache *fragment; >+ int next_cache; >+ int next_fragment; >+ int next_meta_index; >+ unsigned int *uid; >+ unsigned int *guid; >+ long long *fragment_index; >+ unsigned int *fragment_index_2; >+ char *read_page; >+ struct mutex read_data_mutex; >+ struct mutex read_page_mutex; >+ struct mutex block_cache_mutex; >+ struct mutex fragment_mutex; >+ struct mutex meta_index_mutex; >+ wait_queue_head_t waitq; >+ wait_queue_head_t fragment_wait_queue; >+ struct meta_index *meta_index; >+ z_stream stream; >+ long long *inode_lookup_table; >+ int unused_cache_blks; >+ int unused_frag_blks; >+ int (*read_inode)(struct inode *i, squashfs_inode_t \ >+ inode); >+ long long (*read_blocklist)(struct inode *inode, int \ >+ index, int readahead_blks, char *block_list, \ >+ unsigned short **block_p, unsigned int *bsize); >+ int (*read_fragment_index_table)(struct super_block *s); >+}; >+#endif >unchanged: >--- linux-2.6.25-gentoo.orig/init/do_mounts_rd.c >+++ linux-2.6.25-gentoo/init/do_mounts_rd.c >@@ -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,18 @@ 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); >+ if (squashfsb->s_major < 3) >+ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; >+ else >+ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; >+ goto done; >+ } >+ > /* > * Read block 1 to test for minix and ext2 superblock > */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 218169
:
150160
| 150257