--- /dev/null
+diff -Naur linux-2.6.0-test1-ac2/fs/Kconfig linux-2.6.0-test1-ac2-sfs/fs/Kconfig
+--- linux-2.6.0-test1-ac2/fs/Kconfig 2003-07-10 13:10:54.000000000 -0700
++++ linux-2.6.0-test1-ac2-sfs/fs/Kconfig 2003-07-20 01:36:53.000000000 -0700
+@@ -1114,6 +1114,26 @@
+
+ If unsure, say N.
+
++config SQUASHFS
++ tristate "Squashfs file system support"
++ help
++ Saying Y here includes support for Squashfs. 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 32K.
++
++ See <http://squashfs.sourceforge.net/> for further information.
++
++ 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 VXFS_FS
+ tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
+ help
+diff -Naur linux-2.6.0-test1-ac2/fs/Makefile linux-2.6.0-test1-ac2-sfs/fs/Makefile
+--- linux-2.6.0-test1-ac2/fs/Makefile 2003-07-10 13:10:55.000000000 -0700
++++ linux-2.6.0-test1-ac2-sfs/fs/Makefile 2003-07-16 13:45:34.000000000 -0700
+@@ -53,6 +53,7 @@
+ obj-$(CONFIG_JBD) += jbd/
+ obj-$(CONFIG_EXT2_FS) += ext2/
+ obj-$(CONFIG_CRAMFS) += cramfs/
++obj-$(CONFIG_SQUASHFS) += squashfs/
+ obj-$(CONFIG_RAMFS) += ramfs/
+ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
+ obj-$(CONFIG_CODA_FS) += coda/
+diff -Naur linux-2.6.0-test1-ac2/fs/squashfs/Makefile linux-2.6.0-test1-ac2-sfs/fs/squashfs/Makefile
+--- linux-2.6.0-test1-ac2/fs/squashfs/Makefile 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.6.0-test1-ac2-sfs/fs/squashfs/Makefile 2003-07-15 12:17:43.000000000 -0700
+@@ -0,0 +1,8 @@
++#
++# Makefile for the linux squashfs routines.
++#
++
++obj-$(CONFIG_SQUASHFS) += squashfs.o
++
++squashfs-objs := inode.o
++
+diff -Naur linux-2.6.0-test1-ac2/fs/squashfs/inode.c linux-2.6.0-test1-ac2-sfs/fs/squashfs/inode.c
+--- linux-2.6.0-test1-ac2/fs/squashfs/inode.c 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.6.0-test1-ac2-sfs/fs/squashfs/inode.c 2003-07-20 02:08:01.000000000 -0700
+@@ -0,0 +1,1045 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002 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 of the License, or (at your option) any later version.
++ *
++ * inode.c
++ */
++
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <asm/uaccess.h>
++#include <linux/wait.h>
++#include <asm/semaphore.h>
++#include <linux/zlib.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <linux/smp_lock.h>
++#include <linux/buffer_head.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/vfs.h>
++
++#ifdef SQUASHFS_TRACE
++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
++#else
++#define TRACE(s, args...) {}
++#endif
++
++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
++
++#define SERROR(s, args...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args)
++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
++
++typedef struct squashfs_inode_info {
++ unsigned int start_block;
++ unsigned int block_list_start;
++ unsigned int offset;
++
++ struct inode vfs_inode;
++} squashfs_inode_info;
++
++static inline struct squashfs_inode_info *SQUASH_I(struct inode *inode)
++{
++ return container_of(inode, struct squashfs_inode_info, vfs_inode);
++}
++
++static int squashfs_fill_super(struct super_block *, void *, int);
++static void squashfs_put_super(struct super_block *);
++static int squashfs_statfs(struct super_block *, struct kstatfs *);
++static int squashfs_symlink_readpage(struct file *file, struct page *page);
++static int squashfs_readpage(struct file *file, struct page *page);
++static int squashfs_readdir(struct file *, void *, filldir_t);
++static struct dentry *squashfs_lookup(struct inode *, struct dentry *, struct nameidata *);
++static unsigned int read_data(struct super_block *s, char *buffer,
++ unsigned int index, int length, unsigned int *next_index);
++static int squashfs_get_cached_block(struct super_block *s, char *buffer,
++ unsigned int block, unsigned int offset, int length,
++ unsigned int *next_block, unsigned int *next_offset);
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode);
++static void squashfs_put_super(struct super_block *s);
++static struct super_block *squashfs_get_sb(struct file_system_type *, int, const char *, void *);
++static struct inode *squashfs_alloc_inode(struct super_block *);
++static void squashfs_destroy_inode(struct inode *);
++
++DECLARE_MUTEX(read_data_mutex);
++
++static z_stream stream;
++
++static unsigned char squashfs_filetype_table[] = {
++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR
++};
++
++static struct super_operations squashfs_ops = {
++ .alloc_inode = squashfs_alloc_inode,
++ .destroy_inode = squashfs_destroy_inode,
++ .statfs = squashfs_statfs,
++ .put_super = squashfs_put_super,
++};
++
++static struct address_space_operations squashfs_symlink_aops = {
++ .readpage = squashfs_symlink_readpage
++};
++
++static struct address_space_operations squashfs_aops = {
++ .readpage = squashfs_readpage
++};
++
++static struct file_operations squashfs_dir_ops = {
++ .read = generic_read_dir,
++ .readdir = squashfs_readdir
++};
++
++static struct inode_operations squashfs_dir_inode_ops = {
++ .lookup = squashfs_lookup
++};
++
++static struct file_system_type squashfs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "squashfs",
++ .get_sb = squashfs_get_sb,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++
++static unsigned int read_data(struct super_block *s, char *buffer,
++ unsigned int index, int length, unsigned int *next_index)
++{
++ squashfs_sb_info *msBlk = s->s_fs_info;
++ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2];
++ unsigned short c_byte;
++ unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1);
++ unsigned int cur_index = index >> msBlk->devblksize_log2;
++ int bytes, avail_bytes, b, k;
++ char *c_buffer;
++ unsigned int compressed;
++
++ if(!(bh[0] = sb_bread(s, cur_index)))
++ goto read_failure;
++
++ if(length)
++ c_byte = length;
++ else {
++ if(msBlk->devblksize - offset == 1) {
++ if(msBlk->swap)
++ ((unsigned char *) &c_byte)[1] = *((unsigned char *) (bh[0]->b_data + offset));
++ else
++ ((unsigned char *) &c_byte)[0] = *((unsigned char *) (bh[0]->b_data + offset));
++ brelse(bh[0]);
++ if(!(bh[0] = sb_bread(s, ++cur_index)))
++ goto read_failure;
++ if(msBlk->swap)
++ ((unsigned char *) &c_byte)[0] = *((unsigned char *) bh[0]->b_data);
++ else
++ ((unsigned char *) &c_byte)[1] = *((unsigned char *) bh[0]->b_data);
++ offset = 1;
++ }
++ else {
++ if(msBlk->swap) {
++ ((unsigned char *) &c_byte)[1] = *((unsigned char *) (bh[0]->b_data + offset));
++ ((unsigned char *) &c_byte)[0] = *((unsigned char *) (bh[0]->b_data + offset + 1));
++ } else
++ c_byte = *((unsigned short *) (bh[0]->b_data + offset));
++ offset += 2;
++ }
++ if(SQUASHFS_CHECK_DATA(msBlk->sBlk.flags)) {
++ if(offset == msBlk->devblksize) {
++ brelse(bh[0]);
++ if(!(bh[0] = sb_bread(s, ++cur_index)))
++ goto read_failure;
++ offset = 0;
++ }
++ if(*((unsigned char *) (bh[0]->b_data + offset)) != SQUASHFS_MARKER_BYTE) {
++ ERROR("Metadata block marker corrupt @ %x\n", index);
++ brelse(bh[0]);
++ return 0;
++ }
++ offset ++;
++ }
++ }
++
++ bytes = msBlk->devblksize - offset;
++ c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer;
++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
++
++ TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte);
++
++ for(b = 1; bytes < c_byte; b++) {
++ if(!(bh[b] = sb_bread(s, ++cur_index)))
++ goto block_release;
++ bytes += msBlk->devblksize;
++ }
++
++ if(compressed)
++ down(&read_data_mutex);
++
++ for(bytes = 0, k = 0; k < b; k++) {
++ avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes;
++ memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
++ bytes += avail_bytes;
++ offset = 0;
++ brelse(bh[k]);
++ }
++
++ /*
++ * uncompress block
++ */
++ if(compressed) {
++ int zlib_err;
++
++ stream.next_in = c_buffer;
++ stream.avail_in = c_byte;
++ stream.next_out = buffer;
++ stream.avail_out = msBlk->read_size;
++ if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
++ ((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) ||
++ ((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) {
++ ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err);
++ bytes = 0;
++ } else
++ bytes = stream.total_out;
++ up(&read_data_mutex);
++ }
++
++ if(next_index)
++ *next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2));
++
++ return bytes;
++
++block_release:
++ while(--b >= 0) brelse(bh[b]);
++
++read_failure:
++ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
++ return 0;
++}
++
++
++static int squashfs_get_cached_block(struct super_block *s, char *buffer,
++ unsigned int block, unsigned int offset, int length,
++ unsigned int *next_block, unsigned int *next_offset)
++{
++ squashfs_sb_info *msBlk = s->s_fs_info;
++ int n, i, bytes, return_length = length;
++ unsigned int next_index;
++
++ TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset);
++
++ for(;;) {
++ for(i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ if(msBlk->block_cache[i].block == block)
++ break;
++
++ down(&msBlk->block_cache_mutex);
++ if(i == SQUASHFS_CACHED_BLKS) {
++ /* read inode header block */
++ for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS)
++ if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK)
++ break;
++ if(n == 0) {
++ up(&msBlk->block_cache_mutex);
++ sleep_on(&msBlk->waitq);
++ continue;
++ }
++ msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
++
++ if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) {
++ if(!(msBlk->block_cache[i].data = (unsigned char *)
++ kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) {
++ ERROR("Failed to allocate cache block\n");
++ up(&msBlk->block_cache_mutex);
++ return 0;
++ }
++ }
++
++ msBlk->block_cache[i].block = SQUASHFS_USED_BLK;
++ up(&msBlk->block_cache_mutex);
++ if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0,
++ &next_index))) {
++ ERROR("Unable to read cache block [%x:%x]\n", block, offset);
++ return 0;
++ }
++ down(&msBlk->block_cache_mutex);
++ wake_up(&msBlk->waitq);
++ msBlk->block_cache[i].block = block;
++ msBlk->block_cache[i].next_index = next_index;
++ TRACE("Read cache block [%x:%x]\n", block, offset);
++ }
++
++ if(msBlk->block_cache[i].block != block) {
++ up(&msBlk->block_cache_mutex);
++ continue;
++ }
++
++ if((bytes = msBlk->block_cache[i].length - offset) >= length) {
++ memcpy(buffer, msBlk->block_cache[i].data + offset, length);
++ if(msBlk->block_cache[i].length - offset == length) {
++ *next_block = msBlk->block_cache[i].next_index;
++ *next_offset = 0;
++ } else {
++ *next_block = block;
++ *next_offset = offset + length;
++ }
++
++ up(&msBlk->block_cache_mutex);
++ return return_length;
++ } else {
++ memcpy(buffer, msBlk->block_cache[i].data + offset, bytes);
++ block = msBlk->block_cache[i].next_index;
++ up(&msBlk->block_cache_mutex);
++ length -= bytes;
++ offset = 0;
++ buffer += bytes;
++ }
++ }
++}
++
++
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode)
++{
++ struct inode *i = new_inode(s);
++ struct squashfs_inode_info *sqi = SQUASH_I(i);
++ squashfs_sb_info *msBlk = s->s_fs_info;
++ squashfs_super_block *sBlk = &msBlk->sBlk;
++ unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start;
++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++ unsigned int next_block, next_offset;
++ squashfs_base_inode_header inodeb;
++
++ TRACE("Entered squashfs_iget\n");
++
++ if(msBlk->swap) {
++ squashfs_base_inode_header sinodeb;
++
++ if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset,
++ sizeof(sinodeb), &next_block, &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_BASE_INODE_HEADER(&inodeb, &sinodeb, sizeof(sinodeb));
++ } else
++ if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset,
++ sizeof(inodeb), &next_block, &next_offset))
++ goto failed_read;
++
++ i->i_nlink = 1;
++
++ i->i_mtime.tv_sec = sBlk->mkfs_time;
++ i->i_atime.tv_sec = sBlk->mkfs_time;
++ i->i_ctime.tv_sec = sBlk->mkfs_time;
++ i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
++ i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid];
++ i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset);
++
++ if(inodeb.guid == SQUASHFS_GUIDS)
++ i->i_gid = i->i_uid;
++ else
++ i->i_gid = msBlk->guid[inodeb.guid];
++
++ i->i_mode = inodeb.mode;
++
++ switch((inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) {
++ case SQUASHFS_FILE_TYPE: {
++ squashfs_reg_inode_header inodep;
++
++ if(msBlk->swap) {
++ squashfs_reg_inode_header sinodep;
++
++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
++ &next_block, &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_REG_INODE_HEADER(&inodep, &sinodep);
++ } else
++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ i->i_size = inodep.file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_data.a_ops = &squashfs_aops;
++ 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_mtime.tv_nsec = i->i_atime.tv_nsec =
++ i->i_ctime.tv_nsec = 0;
++ sqi->start_block = inodep.start_block;
++ sqi->block_list_start = next_block;
++ sqi->offset = next_offset;
++ TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset);
++ break;
++ }
++ case SQUASHFS_DIR_TYPE: {
++ squashfs_dir_inode_header inodep;
++
++ if(msBlk->swap) {
++ squashfs_dir_inode_header sinodep;
++
++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
++ &next_block, &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_INODE_HEADER(&inodep, &sinodep);
++ } else
++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ i->i_size = inodep.file_size;
++ i->i_op = &squashfs_dir_inode_ops;
++ i->i_fop = &squashfs_dir_ops;
++ i->i_mode |= S_IFDIR;
++ i->i_mtime.tv_sec = inodep.mtime;
++ i->i_atime.tv_sec = inodep.mtime;
++ i->i_ctime.tv_sec = inodep.mtime;
++ i->i_mtime.tv_nsec = i->i_atime.tv_nsec =
++ i->i_ctime.tv_nsec = 0;
++ sqi->start_block = inodep.start_block;
++ sqi->offset = inodep.offset;
++ TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset,
++ inodep.start_block, inodep.offset);
++ break;
++ }
++ case SQUASHFS_SYMLINK_TYPE: {
++ squashfs_symlink_inode_header inodep;
++
++ if(msBlk->swap) {
++ squashfs_symlink_inode_header sinodep;
++
++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
++ &next_block, &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep);
++ } else
++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ i->i_size = inodep.symlink_size;
++ i->i_op = &page_symlink_inode_operations;
++ i->i_data.a_ops = &squashfs_symlink_aops;
++ i->i_mode |= S_IFLNK;
++ sqi->start_block = next_block;
++ sqi->offset = next_offset;
++ TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset);
++ break;
++ }
++ case SQUASHFS_BLKDEV_TYPE:
++ case SQUASHFS_CHRDEV_TYPE: {
++ squashfs_dev_inode_header inodep;
++
++ if(msBlk->swap) {
++ squashfs_dev_inode_header sinodep;
++
++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
++ &next_block, &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DEV_INODE_HEADER(&inodep, &sinodep);
++ } else
++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ i->i_size = 0;
++ i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK;
++ init_special_inode(i, i->i_mode, inodep.rdev);
++ TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev);
++ break;
++ }
++ default:
++ ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type);
++ goto failed_read1;
++ }
++
++ return i;
++
++failed_read:
++ ERROR("Unable to read inode [%x:%x]\n", block, offset);
++
++failed_read1:
++ return NULL;
++}
++
++
++static int squashfs_fill_super(struct super_block *s, void *data, int silent)
++{
++ char bbuf[BDEVNAME_SIZE];
++ squashfs_sb_info *msBlk;
++ squashfs_super_block *sBlk;
++ int i;
++
++ TRACE("Entered squashfs_fill_super\n");
++
++ msBlk = kmalloc(sizeof(squashfs_sb_info), GFP_KERNEL);
++ if (!msBlk)
++ return -ENOMEM;
++ s->s_fs_info = msBlk;
++ sBlk = &(msBlk->sBlk);
++ memset(msBlk, 0, sizeof(squashfs_sb_info));
++
++ msBlk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
++ msBlk->devblksize_log2 = ffz(~msBlk->devblksize);
++
++ init_MUTEX(&msBlk->read_page_mutex);
++ init_MUTEX(&msBlk->block_cache_mutex);
++
++ init_waitqueue_head(&msBlk->waitq);
++
++ if(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(squashfs_super_block) | SQUASHFS_COMPRESSED_BIT, NULL)) {
++ SERROR("unable to read superblock\n");
++ goto failed_mount;
++ }
++
++ /* Check it is a SQUASHFS superblock */
++ msBlk->swap = 0;
++ if((s->s_magic = sBlk->s_magic) != SQUASHFS_MAGIC) {
++ if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) {
++ squashfs_super_block sblk;
++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", __bdevname(s->s_dev, bbuf));
++ SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk);
++ memcpy(sBlk, &sblk, sizeof(squashfs_super_block));
++ msBlk->swap = 1;
++ } else {
++ SERROR("Can't find a SQUASHFS superblock on %s\n", __bdevname(s->s_dev, bbuf));
++ goto failed_mount;
++ }
++ }
++
++ /* Check the MAJOR & MINOR versions */
++ if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
++ SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n",
++ sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR);
++ goto failed_mount;
++ }
++
++ TRACE("Found valid superblock on %s\n", __bdevname(s->s_dev, bbuf));
++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
++ TRACE("Check data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not");
++ TRACE("Filesystem size %d bytes\n", sBlk->bytes_used);
++ TRACE("Block size %d\n", sBlk->block_size);
++ TRACE("Number of inodes %d\n", sBlk->inodes);
++ TRACE("Number of uids %d\n", sBlk->no_uids);
++ TRACE("Number of gids %d\n", sBlk->no_guids);
++ TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start);
++ TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start);
++ TRACE("sBlk->uid_start %x\n", sBlk->uid_start);
++
++ s->s_flags |= MS_RDONLY;
++ s->s_op = &squashfs_ops;
++
++ /* Init inode_table block pointer array */
++ if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(squashfs_cache) * SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
++ ERROR("Failed to allocate block cache\n");
++ goto failed_mount;
++ }
++
++ for(i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ msBlk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++
++ msBlk->next_cache = 0;
++
++ /* Allocate read_data block */
++ msBlk->read_size = (sBlk->block_size < SQUASHFS_METADATA_SIZE) ? SQUASHFS_METADATA_SIZE : sBlk->block_size;
++ if(!(msBlk->read_data = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) {
++ ERROR("Failed to allocate read_data block\n");
++ goto failed_mount1;
++ }
++
++ /* Allocate read_page block */
++ if(sBlk->block_size > PAGE_CACHE_SIZE &&
++ !(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) {
++ ERROR("Failed to allocate read_page block\n");
++ goto failed_mount2;
++ }
++
++ /* Allocate uid and gid tables */
++ if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids +
++ sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ goto failed_mount3;
++ }
++ msBlk->guid = msBlk->uid + sBlk->no_uids;
++
++ if(msBlk->swap) {
++ squashfs_uid suid[sBlk->no_uids + sBlk->no_guids];
++
++ if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) *
++ sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, NULL)) {
++ SERROR("unable to read uid/gid table\n");
++ goto failed_mount4;
++ }
++ SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8));
++ } else
++ if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) *
++ sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, NULL)) {
++ SERROR("unable to read uid/gid table\n");
++ goto failed_mount4;
++ }
++
++ if(!(s->s_root = d_alloc_root(squashfs_iget(s, sBlk->root_inode)))) {
++ ERROR("Root inode create failed\n");
++ goto failed_mount4;
++ }
++
++ TRACE("Leaving squashfs_fill_super\n");
++ return 0;
++
++failed_mount4:
++ kfree(msBlk->uid);
++failed_mount3:
++ kfree(msBlk->read_page);
++failed_mount2:
++ kfree(msBlk->read_data);
++failed_mount1:
++ kfree(msBlk->block_cache);
++failed_mount:
++ kfree(msBlk);
++ s->s_fs_info = NULL;
++ return -EINVAL;
++}
++
++
++static int squashfs_statfs(struct super_block *s, struct kstatfs *buf)
++{
++ squashfs_super_block *sBlk = &((squashfs_sb_info*)(s->s_fs_info))->sBlk;
++
++ TRACE("Entered squashfs_statfs\n");
++ buf->f_type = SQUASHFS_MAGIC;
++ buf->f_bsize = sBlk->block_size;
++ buf->f_blocks = ((sBlk->bytes_used - 1) >> sBlk->block_log) + 1;
++ buf->f_bfree = buf->f_bavail = 0;
++ buf->f_files = sBlk->inodes;
++ buf->f_ffree = 0;
++ buf->f_namelen = SQUASHFS_NAME_LEN;
++ return 0;
++}
++
++
++static int squashfs_symlink_readpage(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ struct squashfs_inode_info *sqi = SQUASH_I(inode);
++ int index = page->index << PAGE_CACHE_SHIFT, length = 0, bytes;
++ int block = sqi->start_block;
++ int offset = sqi->offset;
++ char *buffer;
++
++ TRACE("Entered squashfs_symlink_readpage, page index %d, start block %x, offset %x\n",
++ page->index, sqi->start_block, sqi->offset);
++
++ if (! (buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL))) {
++ ERROR("Failed to allocate symblic link buffer\n");
++ return 0;
++ }
++
++ while(length < index) {
++ if(length += bytes = squashfs_get_cached_block(inode->i_sb, buffer, block, offset,
++ PAGE_CACHE_SIZE, &block, &offset), !bytes) {
++ ERROR("Unable to read symbolic link [%x:%x]\n", block, offset);
++ goto skip_read;
++ }
++ }
++
++ if(length != index) {
++ ERROR("(squashfs_symlink_readpage) length != index\n");
++ kfree(buffer);
++ return 0;
++ }
++
++ bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length;
++ if(!squashfs_get_cached_block(inode->i_sb, page_address(page), block, offset, bytes, &block, &offset))
++ ERROR("Unable to read symbolic link [%x:%x]\n", block, offset);
++
++skip_read:
++ kfree(buffer);
++ memset(page_address(page) + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++
++ return 0;
++}
++
++
++#define SIZE 1024
++static int squashfs_readpage(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ struct squashfs_inode_info *sqi = SQUASH_I(inode);
++ squashfs_sb_info *msBlk = inode->i_sb->s_fs_info;
++ squashfs_super_block *sBlk = &msBlk->sBlk;
++ unsigned short *block_listp;
++ int index = sBlk->block_log > PAGE_CACHE_SHIFT ?
++ page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT) :
++ page->index << (PAGE_CACHE_SHIFT - sBlk->block_log);
++ int block = sqi->start_block, i = 0;
++ int bytes = sqi->block_list_start;
++ int offset = sqi->offset;
++ int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1;
++ char *block_list;
++ char *sblock_list;
++
++ TRACE("Entered squashfs_readpage, page index %d, start block %x\n", page->index,
++ sqi->start_block);
++
++ if (msBlk->swap) {
++ block_list = kmalloc(SIZE, GFP_KERNEL);
++ sblock_list = kmalloc(SIZE, GFP_KERNEL);
++ if (! (block_list && sblock_list)) {
++ ERROR("Unable to allocate readpage buffer\n");
++ goto skip_read;
++ }
++ }
++ else {
++ sblock_list = 0;
++ if (! (block_list = kmalloc(SIZE, GFP_KERNEL))) {
++ ERROR("Unable to allocate readpage buffer\n");
++ goto skip_read;
++ }
++ }
++
++ if(index > file_blocks)
++ goto skip_read;
++
++ for(;;) {
++ int blocks = (index + 1 - i) > (SIZE >> 1) ? SIZE >> 1 : (index + 1 - i);
++ if(msBlk->swap) {
++ if(!squashfs_get_cached_block(inode->i_sb, sblock_list, bytes, offset, blocks << 1, &bytes, &offset)) {
++ ERROR("Unable to read block list [%d:%x]\n", bytes, offset);
++ goto skip_read;
++ }
++ SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks);
++ } else
++ if(!squashfs_get_cached_block(inode->i_sb, block_list, bytes, offset, blocks << 1, &bytes, &offset)) {
++ ERROR("Unable to read block list [%d:%x]\n", bytes, offset);
++ goto skip_read;
++ }
++ for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --)
++ block += SQUASHFS_COMPRESSED_SIZE(*block_listp);
++ if(blocks)
++ break;
++ }
++
++ if(sBlk->block_log > PAGE_CACHE_SHIFT) {
++ int mask = (1 << (sBlk->block_log - PAGE_CACHE_SHIFT)) - 1;
++ int start_index = page->index & ~mask;
++ int end_index = start_index | mask;
++ int byte_offset = 0;
++
++ down(&msBlk->read_page_mutex);
++ if(!(bytes = read_data(inode->i_sb, msBlk->read_page, block, *block_listp, NULL))) {
++ ERROR("Unable to read page, block %x, size %x\n", block, (int) *block_listp);
++ goto skip_read;
++ }
++
++ for(i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) {
++ int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset;
++
++ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", bytes, i, byte_offset, available_bytes);
++
++ if(i == page->index) {
++ memcpy(page_address(page), msBlk->read_page + byte_offset, available_bytes);
++ memset(page_address(page) + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++ } else {
++ struct page *push_page;
++
++ if((push_page = grab_cache_page_nowait(page->mapping, i))) {
++ memcpy(page_address(push_page), msBlk->read_page + byte_offset, available_bytes);
++ memset(page_address(push_page) + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes);
++ flush_dcache_page(push_page);
++ SetPageUptodate(push_page);
++ unlock_page(push_page);
++ page_cache_release(push_page);
++ }
++ }
++ }
++ up( &msBlk->read_page_mutex);
++ kfree(block_list);
++ kfree(sblock_list);
++ return 0;
++
++ } else if(sBlk->block_log == PAGE_CACHE_SHIFT) {
++ if(!(bytes = read_data(inode->i_sb, page_address(page), block, *block_listp, NULL)))
++ ERROR("Unable to read page, block %x, size %x\n", block, (int) *block_listp);
++
++ } else {
++ int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log));
++ char *p = (char *) page_address(page);
++ int byte;
++
++ if(i_end > file_blocks)
++ i_end = file_blocks;
++
++ while(index < i_end) {
++ if(!(byte = read_data(inode->i_sb, p, block, *block_listp, NULL))) {
++ ERROR("Unable to read page, block %x, size %x\n", block, (int) *block_listp);
++ goto skip_read;
++ }
++ block += SQUASHFS_COMPRESSED_SIZE(*block_listp);
++ p += byte;
++ bytes += byte;
++ index ++;
++ block_listp ++;
++ }
++ }
++
++skip_read:
++ kfree(block_list);
++ kfree(sblock_list);
++ memset(page_address(page) + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++
++ return 0;
++}
++
++
++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ struct inode *i = file->f_dentry->d_inode;
++ struct squashfs_inode_info *sqi = SQUASH_I(i);
++ squashfs_sb_info *msBlk = i->i_sb->s_fs_info;
++ squashfs_super_block *sBlk = &msBlk->sBlk;
++ int next_block = sqi->start_block + sBlk->directory_table_start, next_offset =
++ sqi->offset, length = 0, dirs_read = 0, dir_count, bytes;
++ squashfs_dir_header dirh;
++ char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
++ squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
++
++ TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset);
++
++ lock_kernel();
++
++ while(length < i->i_size) {
++ /* read directory header */
++ if(msBlk->swap) {
++ squashfs_dir_header sdirh;
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block,
++ next_offset, sizeof(sdirh), &next_block, &next_offset), !bytes)
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++ } else
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block,
++ next_offset, sizeof(dirh), &next_block, &next_offset), !bytes)
++ goto failed_read;
++
++ dir_count = dirh.count + 1;
++ while(dir_count--) {
++ if(msBlk->swap) {
++ squashfs_dir_entry sdire;
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block,
++ next_offset, sizeof(sdire), &next_block, &next_offset), !bytes)
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++ } else
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) dire, next_block,
++ next_offset, sizeof(*dire), &next_block, &next_offset), !bytes)
++ goto failed_read;
++
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, dire->name, next_block,
++ next_offset, dire->size + 1, &next_block, &next_offset), !bytes)
++ goto failed_read;
++
++ if(file->f_pos >= length)
++ continue;
++
++ dire->name[dire->size + 1] = '\0';
++
++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", dirent,
++ dire->name, dire->size + 1, (int) file->f_pos,
++ dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]);
++
++ if(filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE(dirh.start_block,
++ dire->offset), squashfs_filetype_table[dire->type]) < 0) {
++ TRACE("Filldir returned less than 0\n");
++ unlock_kernel();
++ return dirs_read;
++ }
++
++ file->f_pos = length;
++ dirs_read ++;
++ }
++ }
++ unlock_kernel();
++ return dirs_read;
++
++failed_read:
++ ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset);
++ unlock_kernel();
++ return 0;
++}
++
++
++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ const char *name =dentry->d_name.name;
++ int len = dentry->d_name.len;
++ struct inode *inode = NULL;
++ struct squashfs_inode_info *sqi = SQUASH_I(i);
++ squashfs_sb_info *msBlk = i->i_sb->s_fs_info;
++ squashfs_super_block *sBlk = &msBlk->sBlk;
++ int next_block = sqi->start_block + sBlk->directory_table_start, next_offset =
++ sqi->offset, length = 0, dir_count, bytes;
++ squashfs_dir_header dirh;
++ char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN];
++ squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
++
++ TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset);
++
++ while(length < i->i_size) {
++ /* read directory header */
++ if(msBlk->swap) {
++ squashfs_dir_header sdirh;
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset,
++ sizeof(sdirh), &next_block, &next_offset), !bytes)
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++ } else
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset,
++ sizeof(dirh), &next_block, &next_offset), !bytes)
++ goto failed_read;
++
++ dir_count = dirh.count + 1;
++ while(dir_count--) {
++ if(msBlk->swap) {
++ squashfs_dir_entry sdire;
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) &sdire,
++ next_block,next_offset, sizeof(sdire), &next_block, &next_offset), !bytes)
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++ } else
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, (char *) dire,
++ next_block,next_offset, sizeof(*dire), &next_block, &next_offset), !bytes)
++ goto failed_read;
++
++ if(length += bytes = squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset, dire->size + 1, &next_block, &next_offset), !bytes)
++ goto failed_read;
++
++ if((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
++ squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset);
++
++ TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n",
++ name, dirh.start_block, dire->offset);
++
++ inode = squashfs_iget(i->i_sb, ino);
++
++ goto exit_loop;
++ }
++ }
++ }
++
++exit_loop:
++ d_add(dentry, inode);
++ return ERR_PTR(0);
++
++failed_read:
++ ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset);
++ goto exit_loop;
++}
++
++
++static void squashfs_put_super(struct super_block *s)
++{
++ squashfs_sb_info *msBlk = s->s_fs_info;
++ kfree(msBlk->block_cache);
++ kfree(msBlk->read_data);
++ kfree(msBlk->read_page);
++ kfree(msBlk->uid);
++ kfree(msBlk);
++ s->s_fs_info = NULL;
++}
++
++static struct super_block *squashfs_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *data)
++{
++ return get_sb_bdev(fs_type, flags, dev_name, data,
++ squashfs_fill_super);
++}
++
++static kmem_cache_t * squashfs_inode_cachep;
++
++static struct inode *squashfs_alloc_inode(struct super_block *sb)
++{
++ struct squashfs_inode_info *ii;
++ ii = (struct squashfs_inode_info *)
++ kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL);
++ if (!ii)
++ return NULL;
++ ii->vfs_inode.i_version = 1;
++ return &ii->vfs_inode;
++}
++
++static void squashfs_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(squashfs_inode_cachep, SQUASH_I(inode));
++}
++
++static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
++{
++ struct squashfs_inode_info *sqi = (struct squashfs_inode_info *) foo;
++
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR) {
++ inode_init_once(&sqi->vfs_inode);
++ }
++}
++
++static int init_inodecache(void)
++{
++ squashfs_inode_cachep =
++ kmem_cache_create("squashfs_inode_cache",
++ sizeof(struct squashfs_inode_info),
++ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
++ init_once, NULL);
++ if (squashfs_inode_cachep == NULL)
++ return -ENOMEM;
++ return 0;
++}
++
++static void destroy_inodecache(void)
++{
++ kmem_cache_destroy(squashfs_inode_cachep);
++}
++
++static int __init init_squashfs_fs(void)
++{
++
++ if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) {
++ ERROR("Failed to allocate zlib workspace\n");
++ return -ENOMEM;
++ }
++ if (init_inodecache())
++ return -ENOMEM;
++ return register_filesystem(&squashfs_fs_type);
++}
++
++
++static void __exit exit_squashfs_fs(void)
++{
++ destroy_inodecache();
++ vfree(stream.workspace);
++ unregister_filesystem(&squashfs_fs_type);
++}
++
++
++module_init(init_squashfs_fs);
++module_exit(exit_squashfs_fs);
++MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem");
++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.0-test1-ac2/include/linux/squashfs_fs.h linux-2.6.0-test1-ac2-sfs/include/linux/squashfs_fs.h
+--- linux-2.6.0-test1-ac2/include/linux/squashfs_fs.h 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.6.0-test1-ac2-sfs/include/linux/squashfs_fs.h 2003-07-18 16:12:47.000000000 -0700
+@@ -0,0 +1,304 @@
++#ifndef SQUASHFS_FS
++#define SQUASHFS_FS
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002 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 of the License, or (at your option) any later version.
++ *
++ * squashfs_fs.h
++ */
++
++#define SQUASHFS_MAJOR 1
++#define SQUASHFS_MINOR 0
++#define SQUASHFS_MAGIC 0x73717368
++#define SQUASHFS_MAGIC_SWAP 0x68737173
++#define SQUASHFS_START 0
++
++/* size of metadata (inode and directory) blocks */
++#define SQUASHFS_METADATA_SIZE 8192
++#define SQUASHFS_METADATA_LOG 13
++
++/* default size of data blocks */
++#define SQUASHFS_FILE_SIZE 32768
++#define SQUASHFS_FILE_LOG 15
++
++#define SQUASHFS_FILE_MAX_SIZE 32768
++
++/* Max number of uids and gids */
++#define SQUASHFS_UIDS 48
++#define SQUASHFS_GUIDS 15
++
++/* Max length of filename (not 255) */
++#define SQUASHFS_NAME_LEN 256
++
++#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
++#define SQUASHFS_INVALID_BLK ((long long) 0xffffffff)
++#define SQUASHFS_USED_BLK ((long long) 0xfffffffe)
++
++/* Filesystem flags */
++#define SQUASHFS_NOI 1
++#define SQUASHFS_NOD 2
++#define SQUASHFS_CHECK 4
++#define SQUASHFS_UNCOMPRESSED_INODES(flags) (flags & SQUASHFS_NOI)
++#define SQUASHFS_UNCOMPRESSED_DATA(flags) (flags & SQUASHFS_NOD)
++#define SQUASHFS_CHECK_DATA(flags) (flags & SQUASHFS_CHECK)
++#define SQUASHFS_MKFLAGS(noi, nod, check_data) (noi | (nod << 1) | (check_data << 2))
++
++/* Max number of types and file types */
++#define SQUASHFS_TYPES 5
++#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
++
++/* 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))
++
++/*
++ * Inode number ops. Inodes consist of a compressed block number, and an uncompressed
++ * offset within that block
++ */
++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\
++ + (B)))
++
++/* Compute 32 bit VFS inode number from squashfs inode number */
++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1))
++
++/* Translate between VFS mode and squashfs mode */
++#define SQUASHFS_MODE(a) ((a) & 0xfff)
++
++/* cached data constants for filesystem */
++#define SQUASHFS_CACHED_BLKS 8
++
++#define SQUASHFS_MAX_FILE_SIZE_LOG 32
++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << SQUASHFS_MAX_FILE_SIZE_LOG - 1)
++
++#define SQUASHFS_MARKER_BYTE 0xff
++
++/*
++ * definitions for structures on disk
++ */
++
++typedef unsigned int squashfs_block;
++typedef long long squashfs_inode;
++
++typedef unsigned int squashfs_uid;
++
++typedef struct squashfs_super_block {
++ unsigned int s_magic __attribute__ ((packed));
++ unsigned int inodes __attribute__ ((packed));
++ unsigned int bytes_used __attribute__ ((packed));
++ unsigned int uid_start __attribute__ ((packed));
++ unsigned int guid_start __attribute__ ((packed));
++ unsigned int inode_table_start __attribute__ ((packed));
++ unsigned int directory_table_start __attribute__ ((packed));
++ unsigned int s_major:16 __attribute__ ((packed));
++ unsigned int s_minor:16 __attribute__ ((packed));
++ unsigned int block_size:16 __attribute__ ((packed));
++ unsigned int block_log:16 __attribute__ ((packed));
++ unsigned int flags:8 __attribute__ ((packed));
++ unsigned int no_uids:8 __attribute__ ((packed));
++ unsigned int no_guids:8 __attribute__ ((packed));
++ time_t mkfs_time /* time of filesystem creation */ __attribute__ ((packed));
++ squashfs_inode root_inode __attribute__ ((packed));
++} squashfs_super_block;
++
++typedef struct {
++ unsigned int inode_type:4 __attribute__ ((packed));
++ unsigned int mode:12 __attribute__ ((packed)); /* protection */
++ unsigned int uid:4 __attribute__ ((packed)); /* index into uid table */
++ unsigned int guid:4 __attribute__ ((packed)); /* index into guid table */
++} squashfs_base_inode_header;
++
++typedef struct {
++ unsigned int inode_type:4 __attribute__ ((packed));
++ unsigned int mode:12 __attribute__ ((packed)); /* protection */
++ unsigned int uid:4 __attribute__ ((packed)); /* index into uid table */
++ unsigned int guid:4 __attribute__ ((packed)); /* index into guid table */
++ unsigned short rdev __attribute__ ((packed));
++} squashfs_dev_inode_header;
++
++typedef struct {
++ unsigned int inode_type:4 __attribute__ ((packed));
++ unsigned int mode:12 __attribute__ ((packed)); /* protection */
++ unsigned int uid:4 __attribute__ ((packed)); /* index into uid table */
++ unsigned int guid:4 __attribute__ ((packed)); /* index into guid table */
++ unsigned short symlink_size __attribute__ ((packed));
++ char symlink[0] __attribute__ ((packed));
++} squashfs_symlink_inode_header;
++
++typedef struct {
++ unsigned int inode_type:4 __attribute__ ((packed));
++ unsigned int mode:12 __attribute__ ((packed)); /* protection */
++ unsigned int uid:4 __attribute__ ((packed)); /* index into uid table */
++ unsigned int guid:4 __attribute__ ((packed)); /* index into guid table */
++ time_t mtime __attribute__ ((packed));
++ squashfs_block start_block __attribute__ ((packed));
++ unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG __attribute__ ((packed));
++ unsigned short block_list[0] __attribute__ ((packed));
++} squashfs_reg_inode_header;
++
++typedef struct {
++ unsigned int inode_type:4 __attribute__ ((packed));
++ unsigned int mode:12 __attribute__ ((packed)); /* protection */
++ unsigned int uid:4 __attribute__ ((packed)); /* index into uid table */
++ unsigned int guid:4 __attribute__ ((packed)); /* index into guid table */
++ unsigned int file_size:19 __attribute__ ((packed));
++ unsigned int offset:13 __attribute__ ((packed));
++ time_t mtime __attribute__ ((packed));
++ unsigned int start_block:24 __attribute__ ((packed));
++} squashfs_dir_inode_header;
++
++typedef union {
++ squashfs_base_inode_header base;
++ squashfs_dev_inode_header dev;
++ squashfs_symlink_inode_header symlink;
++ squashfs_reg_inode_header reg;
++ squashfs_dir_inode_header dir;
++} squashfs_inode_header;
++
++typedef struct {
++ unsigned int offset:13 __attribute__ ((packed));
++ unsigned int type:3 __attribute__ ((packed));
++ unsigned int size:8 __attribute__ ((packed));
++ char name[0] __attribute__ ((packed));
++} squashfs_dir_entry;
++
++typedef struct {
++ unsigned int count:8 __attribute__ ((packed));
++ unsigned int start_block:24 __attribute__ ((packed));
++} squashfs_dir_header;
++
++
++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
++extern int squashfs_uncompress_init(void);
++extern int squashfs_uncompress_exit(void);
++
++/*
++ * macros to convert each packed bitfield structure from little endian to big
++ * endian and vice versa. These are needed when creating or using a filesystem on a
++ * machine with different byte ordering to the target architecture.
++ *
++ */
++
++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\
++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
++ SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\
++ SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\
++ SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\
++ SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\
++ SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\
++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
++ SQUASHFS_SWAP((s)->block_size, 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);\
++}
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\
++ SQUASHFS_SWAP((s)->guid, d, 20, 4);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\
++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\
++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\
++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\
++ 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);\
++}
++
++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\
++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\
++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
++}
++
++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_MEMSET(s, d, n * 2);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
++}
++
++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_MEMSET(s, d, n * bits / 8);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
++}
++
++#ifdef __KERNEL__
++/*
++ * macros used to swap each structure entry, taking into account
++ * bitfields and different bitfield placing conventions on differing architectures
++ */
++#include <asm/byteorder.h>
++#ifdef __BIG_ENDIAN
++ /* convert from little endian to big endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
++#else
++ /* convert from big endian to little endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
++#endif
++
++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
++ int bits;\
++ int b_pos = pos % 8;\
++ unsigned long long val = 0;\
++ unsigned char *s = (unsigned char *)p + (pos / 8);\
++ unsigned char *d = ((unsigned char *) &val) + 7;\
++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \
++ *d-- = *s++;\
++ value = val >> (SHIFT);\
++}
++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
++#endif
++#endif
+diff -Naur linux-2.6.0-test1-ac2/include/linux/squashfs_fs_sb.h linux-2.6.0-test1-ac2-sfs/include/linux/squashfs_fs_sb.h
+--- linux-2.6.0-test1-ac2/include/linux/squashfs_fs_sb.h 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.6.0-test1-ac2-sfs/include/linux/squashfs_fs_sb.h 2003-07-18 16:12:47.000000000 -0700
+@@ -0,0 +1,41 @@
++#ifndef SQUASHFS_FS_SB
++#define SQUASHFS_FS_SB
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002 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 of the License, or (at your option) any later version.
++ *
++ * squashfs_fs_sb.h
++ */
++
++#include <linux/squashfs_fs.h>
++
++typedef struct {
++ unsigned int block;
++ int length;
++ unsigned int next_index;
++ char *data;
++ } squashfs_cache;
++
++typedef struct squashfs_sb_info {
++ squashfs_super_block sBlk;
++ int devblksize;
++ int devblksize_log2;
++ int swap;
++ squashfs_cache *block_cache;
++ int next_cache;
++ squashfs_uid *uid;
++ squashfs_uid *guid;
++ unsigned int read_size;
++ char *read_data;
++ char *read_page;
++ struct semaphore read_page_mutex;
++ struct semaphore block_cache_mutex;
++ wait_queue_head_t waitq;
++ } squashfs_sb_info;
++#endif
+diff -Naur linux-2.6.0-test1-ac2/lib/Kconfig linux-2.6.0-test1-ac2-sfs/lib/Kconfig
+--- linux-2.6.0-test1-ac2/lib/Kconfig 2003-05-04 16:53:32.000000000 -0700
++++ linux-2.6.0-test1-ac2-sfs/lib/Kconfig 2003-07-16 16:40:44.000000000 -0700
+@@ -17,8 +17,8 @@
+ #
+ config ZLIB_INFLATE
+ tristate
+- default y if CRAMFS=y || PPP_DEFLATE=y || JFFS2_FS=y || ZISOFS_FS=y || BINFMT_ZFLAT=y || CRYPTO_DEFLATE=y
+- default m if CRAMFS=m || PPP_DEFLATE=m || JFFS2_FS=m || ZISOFS_FS=m || BINFMT_ZFLAT=m || CRYPTO_DEFLATE=m
++ default y if CRAMFS=y || SQUASHFS=y || PPP_DEFLATE=y || JFFS2_FS=y || ZISOFS_FS=y || BINFMT_ZFLAT=y || CRYPTO_DEFLATE=y
++ default m if CRAMFS=m || SQUASHFS=m || PPP_DEFLATE=m || JFFS2_FS=m || ZISOFS_FS=m || BINFMT_ZFLAT=m || CRYPTO_DEFLATE=m
+
+ config ZLIB_DEFLATE
+ tristate
--- /dev/null
+diff -Nur --exclude='*.orig' linux-2.6.0-test1.org/drivers/media/video/bttv-cards.c linux-2.6.0-test1/drivers/media/video/bttv-cards.c
+--- linux-2.6.0-test1.org/drivers/media/video/bttv-cards.c Mon Jul 14 03:34:03 2003
++++ linux-2.6.0-test1/drivers/media/video/bttv-cards.c Tue Jul 22 09:01:24 2003
+@@ -1630,12 +1630,8 @@
+ btv->type=card[btv->nr];
+
+ /* print which card config we are using */
+- sprintf(btv->video_dev.name,"BT%d%s(%.23s)",
+- btv->id,
+- (btv->id==848 && btv->revision==0x12) ? "A" : "",
+- bttv_tvcards[btv->type].name);
+ printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr,
+- btv->video_dev.name,btv->type,
++ bttv_tvcards[btv->type].name, btv->type,
+ (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
+ "insmod option" : "autodetected");
+
+diff -Nur --exclude='*.orig' linux-2.6.0-test1.org/drivers/media/video/bttv-driver.c linux-2.6.0-test1/drivers/media/video/bttv-driver.c
+--- linux-2.6.0-test1.org/drivers/media/video/bttv-driver.c Mon Jul 14 03:36:43 2003
++++ linux-2.6.0-test1/drivers/media/video/bttv-driver.c Tue Jul 22 09:02:57 2003
+@@ -33,6 +33,7 @@
+ #include <linux/sched.h>
+ #include <linux/interrupt.h>
+ #include <linux/kdev_t.h>
++#include <linux/device.h>
+
+ #include <asm/io.h>
+
+@@ -123,6 +124,17 @@
+ #endif
+
+ /* ----------------------------------------------------------------------- */
++/* sysfs */
++
++static ssize_t show_card(struct class_device *cd, char *buf)
++{
++ struct video_device *vfd = to_video_device(cd);
++ struct bttv *btv = dev_get_drvdata(vfd->dev);
++ return sprintf(buf, "%d\n", btv ? btv->type : UNSET);
++}
++static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
++
++/* ----------------------------------------------------------------------- */
+ /* static data */
+
+ /* special timing tables from conexant... */
+@@ -2007,7 +2019,7 @@
+ struct video_capability *cap = arg;
+
+ memset(cap,0,sizeof(*cap));
+- strcpy(cap->name,btv->video_dev.name);
++ strcpy(cap->name,btv->video_dev->name);
+ if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+ /* vbi */
+ cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
+@@ -2309,7 +2321,7 @@
+ if (0 == v4l2)
+ return -EINVAL;
+ strcpy(cap->driver,"bttv");
+- strlcpy(cap->card,btv->video_dev.name,sizeof(cap->card));
++ strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",btv->dev->slot_name);
+ cap->version = BTTV_VERSION_CODE;
+ cap->capabilities =
+@@ -2683,12 +2695,12 @@
+ dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
+
+ for (i = 0; i < bttv_num; i++) {
+- if (bttvs[i].video_dev.minor == minor) {
++ if (bttvs[i].video_dev->minor == minor) {
+ btv = &bttvs[i];
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ }
+- if (bttvs[i].vbi_dev.minor == minor) {
++ if (bttvs[i].vbi_dev->minor == minor) {
+ btv = &bttvs[i];
+ type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ break;
+@@ -2786,8 +2798,8 @@
+ static struct video_device bttv_video_template =
+ {
+ .name = "UNSET",
+- type: VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
+- VID_TYPE_CLIPPING|VID_TYPE_SCALES,
++ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
++ VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+ .hardware = VID_HARDWARE_BT848,
+ .fops = &bttv_fops,
+ .minor = -1,
+@@ -2815,7 +2827,7 @@
+ dprintk("bttv: open minor=%d\n",minor);
+
+ for (i = 0; i < bttv_num; i++) {
+- if (bttvs[i].radio_dev.minor == minor) {
++ if (bttvs[i].radio_dev->minor == minor) {
+ btv = &bttvs[i];
+ break;
+ }
+@@ -2860,7 +2872,7 @@
+ struct video_capability *cap = arg;
+
+ memset(cap,0,sizeof(*cap));
+- strcpy(cap->name,btv->radio_dev.name);
++ strcpy(cap->name,btv->radio_dev->name);
+ cap->type = VID_TYPE_TUNER;
+ cap->channels = 1;
+ cap->audios = 1;
+@@ -3239,30 +3251,83 @@
+ /* ----------------------------------------------------------------------- */
+ /* initialitation */
+
++static struct video_device *vdev_init(struct bttv *btv,
++ struct video_device *template,
++ char *type)
++{
++ struct video_device *vfd;
++
++ vfd = video_device_alloc();
++ if (NULL == vfd)
++ return NULL;
++ *vfd = *template;
++ vfd->minor = -1;
++ vfd->release = video_device_release;
++ vfd->dev = &btv->dev->dev;
++ snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
++ btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
++ type, bttv_tvcards[btv->type].name);
++ return vfd;
++}
++
+ /* register video4linux devices */
+ static int __devinit bttv_register_video(struct bttv *btv)
+ {
+- if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+- return -1;
++ /* video */
++ btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
++ if (NULL == btv->video_dev)
++ goto err;
++ if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
++ goto err;
+ printk(KERN_INFO "bttv%d: registered device video%d\n",
+- btv->nr,btv->video_dev.minor & 0x1f);
++ btv->nr,btv->video_dev->minor & 0x1f);
++ video_device_create_file(btv->video_dev, &class_device_attr_card);
+
+- if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) {
+- video_unregister_device(&btv->video_dev);
+- return -1;
+- }
++ /* vbi */
++ btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
++ if (NULL == btv->vbi_dev)
++ goto err;
++ if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
++ goto err;
+ printk(KERN_INFO "bttv%d: registered device vbi%d\n",
+- btv->nr,btv->vbi_dev.minor & 0x1f);
++ btv->nr,btv->vbi_dev->minor & 0x1f);
+
+ if (!btv->has_radio)
+ return 0;
+- if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) {
+- video_unregister_device(&btv->vbi_dev);
+- video_unregister_device(&btv->video_dev);
+- return -1;
+- }
++ /* radio */
++ btv->radio_dev = vdev_init(btv, &radio_template, "radio");
++ if (NULL == btv->radio_dev)
++ goto err;
++ if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
++ goto err;
+ printk(KERN_INFO "bttv%d: registered device radio%d\n",
+- btv->nr,btv->radio_dev.minor & 0x1f);
++ btv->nr,btv->radio_dev->minor & 0x1f);
++
++ /* all done */
++ return 0;
++
++ err:
++ if (btv->video_dev) {
++ if (-1 != btv->video_dev->minor)
++ video_unregister_device(btv->video_dev);
++ else
++ video_device_release(btv->video_dev);
++ btv->video_dev = NULL;
++ }
++ if (btv->vbi_dev) {
++ if (-1 != btv->vbi_dev->minor)
++ video_unregister_device(btv->vbi_dev);
++ else
++ video_device_release(btv->vbi_dev);
++ btv->vbi_dev = NULL;
++ }
++ if (btv->radio_dev) {
++ if (-1 != btv->radio_dev->minor)
++ video_unregister_device(btv->radio_dev);
++ else
++ video_device_release(btv->radio_dev);
++ btv->radio_dev = NULL;
++ }
+ return 0;
+ }
+
+@@ -3310,15 +3375,6 @@
+ btv->i2c_rc = -1;
+ btv->tuner_type = -1;
+
+- memcpy(&btv->video_dev, &bttv_video_template, sizeof(bttv_video_template));
+- memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template));
+- memcpy(&btv->vbi_dev, &bttv_vbi_template, sizeof(bttv_vbi_template));
+- btv->video_dev.minor = -1;
+- btv->video_dev.priv = btv;
+- btv->radio_dev.minor = -1;
+- btv->radio_dev.priv = btv;
+- btv->vbi_dev.minor = -1;
+- btv->vbi_dev.priv = btv;
+ btv->has_radio=radio[btv->nr];
+
+ /* pci stuff (init, get irq/mmip, ... */
+@@ -3477,12 +3533,18 @@
+ i2c_bit_del_bus(&btv->i2c_adap);
+
+ /* unregister video4linux */
+- if (btv->video_dev.minor!=-1)
+- video_unregister_device(&btv->video_dev);
+- if (btv->radio_dev.minor!=-1)
+- video_unregister_device(&btv->radio_dev);
+- if (btv->vbi_dev.minor!=-1)
+- video_unregister_device(&btv->vbi_dev);
++ if (btv->video_dev) {
++ video_unregister_device(btv->video_dev);
++ btv->video_dev = NULL;
++ }
++ if (btv->radio_dev) {
++ video_unregister_device(btv->radio_dev);
++ btv->radio_dev = NULL;
++ }
++ if (btv->vbi_dev) {
++ video_unregister_device(btv->vbi_dev);
++ btv->vbi_dev = NULL;
++ }
+
+ /* free allocated memory */
+ bttv_riscmem_free(btv->dev,&btv->main);
+diff -Nur --exclude='*.orig' linux-2.6.0-test1.org/drivers/media/video/bttvp.h linux-2.6.0-test1/drivers/media/video/bttvp.h
+--- linux-2.6.0-test1.org/drivers/media/video/bttvp.h Mon Jul 14 03:32:44 2003
++++ linux-2.6.0-test1/drivers/media/video/bttvp.h Tue Jul 22 08:57:59 2003
+@@ -280,9 +280,9 @@
+ int i2c_state, i2c_rc;
+
+ /* video4linux (1) */
+- struct video_device video_dev;
+- struct video_device radio_dev;
+- struct video_device vbi_dev;
++ struct video_device *video_dev;
++ struct video_device *radio_dev;
++ struct video_device *vbi_dev;
+
+ /* locking */
+ spinlock_t s_lock;
+diff -Nur --exclude='*.orig' linux-2.6.0-test1.org/drivers/media/video/videodev.c linux-2.6.0-test1/drivers/media/video/videodev.c
+--- linux-2.6.0-test1.org/drivers/media/video/videodev.c Mon Jul 14 03:30:42 2003
++++ linux-2.6.0-test1/drivers/media/video/videodev.c Tue Jul 22 08:57:54 2003
+@@ -15,7 +15,6 @@
+ * - Added procfs support
+ */
+
+-#include <linux/config.h>
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+@@ -28,6 +27,7 @@
+ #include <linux/init.h>
+ #include <linux/kmod.h>
+ #include <linux/slab.h>
++#include <linux/types.h>
+ #include <linux/devfs_fs_kernel.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -35,33 +35,67 @@
+
+ #include <linux/videodev.h>
+
+-#define VIDEO_NUM_DEVICES 256
++#define VIDEO_NUM_DEVICES 256
++#define VIDEO_NAME "video4linux"
+
+ /*
+- * Active devices
++ * sysfs stuff
+ */
+-
+-static struct video_device *video_device[VIDEO_NUM_DEVICES];
+-static DECLARE_MUTEX(videodev_lock);
+
++static ssize_t show_name(struct class_device *cd, char *buf)
++{
++ struct video_device *vfd = to_video_device(cd);
++ return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
++}
++
++static ssize_t show_dev(struct class_device *cd, char *buf)
++{
++ struct video_device *vfd = to_video_device(cd);
++ dev_t dev = MKDEV(VIDEO_MAJOR, vfd->minor);
++ return sprintf(buf,"%04x\n",(int)dev);
++}
+
+-#ifdef CONFIG_VIDEO_PROC_FS
++static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
++static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
+
+-#include <linux/proc_fs.h>
++struct video_device *video_device_alloc(void)
++{
++ struct video_device *vfd;
+
+-struct videodev_proc_data {
+- struct list_head proc_list;
+- char name[16];
+- struct video_device *vdev;
+- struct proc_dir_entry *proc_entry;
+-};
++ vfd = kmalloc(sizeof(*vfd),GFP_KERNEL);
++ if (NULL == vfd)
++ return NULL;
++ memset(vfd,0,sizeof(*vfd));
++ return vfd;
++}
++
++void video_device_release(struct video_device *vfd)
++{
++ kfree(vfd);
++}
++
++static void video_release(struct class_device *cd)
++{
++ struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+
+-static struct proc_dir_entry *video_dev_proc_entry = NULL;
+-struct proc_dir_entry *video_proc_entry = NULL;
+-EXPORT_SYMBOL(video_proc_entry);
+-LIST_HEAD(videodev_proc_list);
++#if 1 /* needed until all drivers are fixed */
++ if (!vfd->release)
++ return;
++#endif
++ vfd->release(vfd);
++}
+
+-#endif /* CONFIG_VIDEO_PROC_FS */
++static struct class video_class = {
++ .name = VIDEO_NAME,
++ .release = video_release,
++};
++
++/*
++ * Active devices
++ */
++
++static struct video_device *video_device[VIDEO_NUM_DEVICES];
++static DECLARE_MUTEX(videodev_lock);
+
+ struct video_device* video_devdata(struct file *file)
+ {
+@@ -192,156 +226,6 @@
+ return 0;
+ }
+
+-/*
+- * /proc support
+- */
+-
+-#ifdef CONFIG_VIDEO_PROC_FS
+-
+-/* Hmm... i'd like to see video_capability information here, but
+- * how can I access it (without changing the other drivers? -claudio
+- */
+-static int videodev_proc_read(char *page, char **start, off_t off,
+- int count, int *eof, void *data)
+-{
+- char *out = page;
+- struct video_device *vfd = data;
+- struct videodev_proc_data *d;
+- struct list_head *tmp;
+- int len;
+- char c = ' ';
+-
+- list_for_each (tmp, &videodev_proc_list) {
+- d = list_entry(tmp, struct videodev_proc_data, proc_list);
+- if (vfd == d->vdev)
+- break;
+- }
+-
+- /* Sanity check */
+- if (tmp == &videodev_proc_list)
+- goto skip;
+-
+-#define PRINT_VID_TYPE(x) do { if (vfd->type & x) \
+- out += sprintf (out, "%c%s", c, #x); c='|';} while (0)
+-
+- out += sprintf (out, "name : %s\n", vfd->name);
+- out += sprintf (out, "type :");
+- PRINT_VID_TYPE(VID_TYPE_CAPTURE);
+- PRINT_VID_TYPE(VID_TYPE_TUNER);
+- PRINT_VID_TYPE(VID_TYPE_TELETEXT);
+- PRINT_VID_TYPE(VID_TYPE_OVERLAY);
+- PRINT_VID_TYPE(VID_TYPE_CHROMAKEY);
+- PRINT_VID_TYPE(VID_TYPE_CLIPPING);
+- PRINT_VID_TYPE(VID_TYPE_FRAMERAM);
+- PRINT_VID_TYPE(VID_TYPE_SCALES);
+- PRINT_VID_TYPE(VID_TYPE_MONOCHROME);
+- PRINT_VID_TYPE(VID_TYPE_SUBCAPTURE);
+- PRINT_VID_TYPE(VID_TYPE_MPEG_DECODER);
+- PRINT_VID_TYPE(VID_TYPE_MPEG_ENCODER);
+- PRINT_VID_TYPE(VID_TYPE_MJPEG_DECODER);
+- PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER);
+- out += sprintf (out, "\n");
+- out += sprintf (out, "hardware : 0x%x\n", vfd->hardware);
+-#if 0
+- out += sprintf (out, "channels : %d\n", d->vcap.channels);
+- out += sprintf (out, "audios : %d\n", d->vcap.audios);
+- out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth);
+- out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight);
+- out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth);
+- out += sprintf (out, "minheight : %d\n", d->vcap.minheight);
+-#endif
+-
+-skip:
+- len = out - page;
+- len -= off;
+- if (len < count) {
+- *eof = 1;
+- if (len <= 0)
+- return 0;
+- } else
+- len = count;
+-
+- *start = page + off;
+-
+- return len;
+-}
+-
+-static void videodev_proc_create(void)
+-{
+- video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root);
+-
+- if (video_proc_entry == NULL) {
+- printk("video_dev: unable to initialise /proc/video\n");
+- return;
+- }
+-
+- video_proc_entry->owner = THIS_MODULE;
+- video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry);
+-
+- if (video_dev_proc_entry == NULL) {
+- printk("video_dev: unable to initialise /proc/video/dev\n");
+- return;
+- }
+-
+- video_dev_proc_entry->owner = THIS_MODULE;
+-}
+-
+-static void __exit videodev_proc_destroy(void)
+-{
+- if (video_dev_proc_entry != NULL)
+- remove_proc_entry("dev", video_proc_entry);
+-
+- if (video_proc_entry != NULL)
+- remove_proc_entry("video", &proc_root);
+-}
+-
+-static void videodev_proc_create_dev (struct video_device *vfd, char *name)
+-{
+- struct videodev_proc_data *d;
+- struct proc_dir_entry *p;
+-
+- if (video_dev_proc_entry == NULL)
+- return;
+-
+- d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL);
+- if (!d)
+- return;
+-
+- p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
+- if (!p) {
+- kfree(d);
+- return;
+- }
+- p->data = vfd;
+- p->read_proc = videodev_proc_read;
+-
+- d->proc_entry = p;
+- d->vdev = vfd;
+- strcpy (d->name, name);
+-
+- /* How can I get capability information ? */
+-
+- list_add (&d->proc_list, &videodev_proc_list);
+-}
+-
+-static void videodev_proc_destroy_dev (struct video_device *vfd)
+-{
+- struct list_head *tmp;
+- struct videodev_proc_data *d;
+-
+- list_for_each (tmp, &videodev_proc_list) {
+- d = list_entry(tmp, struct videodev_proc_data, proc_list);
+- if (vfd == d->vdev) {
+- remove_proc_entry(d->name, video_dev_proc_entry);
+- list_del (&d->proc_list);
+- kfree(d);
+- break;
+- }
+- }
+-}
+-
+-#endif /* CONFIG_VIDEO_PROC_FS */
+-
+ extern struct file_operations video_fops;
+
+ /**
+@@ -429,15 +313,23 @@
+ devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
+ S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
+ init_MUTEX(&vfd->lock);
+-
+-#ifdef CONFIG_VIDEO_PROC_FS
+-{
+- char name[16];
+- sprintf(name, "%s%d", name_base, i - base);
+- videodev_proc_create_dev(vfd, name);
+-}
+-#endif
+
++ /* sysfs class */
++ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
++ if (vfd->dev)
++ vfd->class_dev.dev = vfd->dev;
++ vfd->class_dev.class = &video_class;
++ strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
++ class_device_register(&vfd->class_dev);
++ video_device_create_file(vfd, &class_device_attr_name);
++ video_device_create_file(vfd, &class_device_attr_dev);
++
++#if 1 /* needed until all drivers are fixed */
++ if (!vfd->release)
++ printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
++ "Please fix your driver for proper sysfs support, see "
++ "http://lwn.net/Articles/36850/\n", vfd->name);
++#endif
+ return 0;
+ }
+
+@@ -455,10 +347,7 @@
+ if(video_device[vfd->minor]!=vfd)
+ panic("videodev: bad unregister");
+
+-#ifdef CONFIG_VIDEO_PROC_FS
+- videodev_proc_destroy_dev (vfd);
+-#endif
+-
++ class_device_unregister(&vfd->class_dev);
+ devfs_remove(vfd->devfs_name);
+ video_device[vfd->minor]=NULL;
+ up(&videodev_lock);
+@@ -479,24 +368,18 @@
+ static int __init videodev_init(void)
+ {
+ printk(KERN_INFO "Linux video capture interface: v1.00\n");
+- if (register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops)) {
++ if (register_chrdev(VIDEO_MAJOR,VIDEO_NAME, &video_fops)) {
+ printk("video_dev: unable to get major %d\n", VIDEO_MAJOR);
+ return -EIO;
+ }
+-
+-#ifdef CONFIG_VIDEO_PROC_FS
+- videodev_proc_create ();
+-#endif
+-
++ class_register(&video_class);
+ return 0;
+ }
+
+ static void __exit videodev_exit(void)
+ {
+-#ifdef CONFIG_VIDEO_PROC_FS
+- videodev_proc_destroy ();
+-#endif
+- unregister_chrdev(VIDEO_MAJOR, "video_capture");
++ class_unregister(&video_class);
++ unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
+ }
+
+ module_init(videodev_init)
+@@ -508,6 +391,8 @@
+ EXPORT_SYMBOL(video_usercopy);
+ EXPORT_SYMBOL(video_exclusive_open);
+ EXPORT_SYMBOL(video_exclusive_release);
++EXPORT_SYMBOL(video_device_alloc);
++EXPORT_SYMBOL(video_device_release);
+
+ MODULE_AUTHOR("Alan Cox");
+ MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+diff -Nur --exclude='*.orig' linux-2.6.0-test1.org/include/linux/videodev.h linux-2.6.0-test1/include/linux/videodev.h
+--- linux-2.6.0-test1.org/include/linux/videodev.h Mon Jul 14 03:39:37 2003
++++ linux-2.6.0-test1/include/linux/videodev.h Tue Jul 22 08:57:54 2003
+@@ -3,18 +3,10 @@
+
+ #include <linux/types.h>
+ #include <linux/version.h>
++#include <linux/device.h>
+
+-#if 1
+-/*
+- * v4l2 is still work-in-progress, integration planed for 2.5.x
+- * documentation: http://bytesex.org/v4l/
+- * patches available from: http://bytesex.org/patches/
+- */
+-# define HAVE_V4L2 1
+-# include <linux/videodev2.h>
+-#else
+-# undef HAVE_V4L2
+-#endif
++#define HAVE_V4L2 1
++#include <linux/videodev2.h>
+
+ #ifdef __KERNEL__
+
+@@ -23,35 +15,70 @@
+
+ struct video_device
+ {
+- struct module *owner;
++ /* device info */
++ struct device *dev;
+ char name[32];
+ int type; /* v4l1 */
+ int type2; /* v4l2 */
+ int hardware;
+ int minor;
+
+- /* new interface -- we will use file_operations directly
+- * like soundcore does. */
++ /* device ops + callbacks */
+ struct file_operations *fops;
+- void *priv; /* Used to be 'private' but that upsets C++ */
++ void (*release)(struct video_device *vfd);
+
+- /* for videodev.c intenal usage -- don't touch */
+- int users;
+- struct semaphore lock;
+- char devfs_name[64]; /* devfs */
++#if 1 /* to be removed in 2.7.x */
++ /* obsolete -- fops->owner is used instead */
++ struct module *owner;
++ /* dev->driver_data will be used instead some day.
++ * Use the video_{get|set}_drvdata() helper functions,
++ * so the switch over will be transparent for you.
++ * Or use {pci|usb|dev}_{get|set}_drvdata() directly. */
++ void *priv;
++#endif
++
++ /* for videodev.c intenal usage -- please don't touch */
++ int users; /* video_exclusive_{open|close} ... */
++ struct semaphore lock; /* ... helper function uses these */
++ char devfs_name[64]; /* devfs */
++ struct class_device class_dev; /* sysfs */
+ };
+
+ #define VIDEO_MAJOR 81
+-extern int video_register_device(struct video_device *, int type, int nr);
+
+ #define VFL_TYPE_GRABBER 0
+ #define VFL_TYPE_VBI 1
+ #define VFL_TYPE_RADIO 2
+ #define VFL_TYPE_VTX 3
+
++extern int video_register_device(struct video_device *, int type, int nr);
+ extern void video_unregister_device(struct video_device *);
+ extern struct video_device* video_devdata(struct file*);
+
++#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
++static inline void
++video_device_create_file(struct video_device *vfd,
++ struct class_device_attribute *attr)
++{
++ class_device_create_file(&vfd->class_dev, attr);
++}
++
++/* helper functions to alloc / release struct video_device, the
++ later can be used for video_device->release() */
++struct video_device *video_device_alloc(void);
++void video_device_release(struct video_device *vfd);
++
++/* helper functions to access driver private data. */
++static inline void *video_get_drvdata(struct video_device *dev)
++{
++ return dev->priv;
++}
++
++static inline void video_set_drvdata(struct video_device *dev, void *data)
++{
++ dev->priv = data;
++}
++
+ extern int video_exclusive_open(struct inode *inode, struct file *file);
+ extern int video_exclusive_release(struct inode *inode, struct file *file);
+ extern int video_usercopy(struct inode *inode, struct file *file,