summaryrefslogtreecommitdiffstats
path: root/patches
diff options
context:
space:
mode:
authorcc4b05f61e2d8f77114750386c9f9a60 <cc4b05f61e2d8f7@7114750386c9f9a60>2023-05-11 14:38:47 +0000
committercc4b05f61e2d8f77114750386c9f9a60 <cc4b05f61e2d8f7@7114750386c9f9a60>2023-05-11 14:38:47 +0000
commitf5450bfd35a6410528d124f534c2b1a958cafe51 (patch)
treea808b12d6ad5343fabdec7b8918df6b4d844e03f /patches
parent5ad2bb7a6ac7e97c031908d2439808a00fff6214 (diff)
dmsdos-0.9.2.2 addeddmsdos-0.9.2.2
Diffstat (limited to 'patches')
-rw-r--r--patches/DIFFS.TXT260
-rw-r--r--patches/cvf-uvfat.diff-2.0.33110
-rw-r--r--patches/cvf.c147
-rw-r--r--patches/cvf.c-2.1.128147
-rw-r--r--patches/cvf.c.README70
-rw-r--r--patches/cvf.diff-2.0.331056
-rw-r--r--patches/cvf.diff-2.0.33+fat32-0.2.81074
-rw-r--r--patches/cvf.diff-2.0.341074
-rw-r--r--patches/fat-truncate-bugfix.diff13
-rw-r--r--patches/fat_cvf.txt210
-rw-r--r--patches/fat_cvf.txt-2.1.128210
-rw-r--r--patches/in-kernel-2.0.35.diff62
-rw-r--r--patches/linux-2.2.13-dmsdos.patch-116
-rw-r--r--patches/linux-2.3.30-pre6-dmsdos.patch-1284
-rw-r--r--patches/magic16
-rw-r--r--patches/msdos-rmdir-bugfix.diff19
-rw-r--r--patches/vfat-brelse-bugfix.diff15
17 files changed, 4783 insertions, 0 deletions
diff --git a/patches/DIFFS.TXT b/patches/DIFFS.TXT
new file mode 100644
index 0000000..6ad1e6f
--- /dev/null
+++ b/patches/DIFFS.TXT
@@ -0,0 +1,260 @@
+
+The list of CVF-FAT diffs is actually some lines below.
+
+Some notes about applying patches
+---------------------------------
+
+This section is for people not familiar with kernel patches. Feel free to
+skip it if you are an experienced patch hacker :)
+
+Well, as always be careful with diffs. Nobody knows whether they always
+apply correctly. Praise yourself lucky if you see errors on the screen -
+then at least you know that the patch failed. :)
+
+However, I've seen patches applying without errors, but changing code at
+the wrong place, even creating syntactically correct but senseless
+and not well working code. (For example, this happens for a small part of
+the patches if you use the plain 2.0.33 diff here for a fat32 patched
+2.0.33 kernel or a 2.1.76 kernel. Argh. It's almost impossible to find
+and repair such an error if you haven't written the code yourself.)
+
+From the patch manual:
+
+ Patch usually produces the correct results, even when it
+ has to do a lot of guessing. However, the results are
+ guaranteed to be correct only when the patch is applied to
+ exactly the same version of the file that the patch was
+ generated from.
+
+So do at least the usual security steps. It's best to get a fresh kernel
+from the net (*not* upgrading by patches). But sometimes you need patches.
+Ensure:
+
+ A. Before applying a patch:
+
+ 1. Copy your complete kernel sources to another place, and operate
+ only on this test copy, e.g.
+
+ cp -a /usr/src/linux-x.y.z /usr/src/linux-x.y.z-test
+ cd /usr/src/linux-x.y.z-test
+
+ 2. Remove all patch related files in the kernel sources, e.g.
+
+ find . -name "*.orig" -exec rm {} \;
+ find . -name "*.rej" -exec rm {} \;
+
+ B. Apply the patches you need. Order is important.
+
+ 1. Look at the first lines of the diff. There's very likely a complete
+ path in the filenames. If it begins with "linux..." you need the
+ option -p1, if it begins with "/usr/src/linux..." you need -p4 or
+ -p0 (you'll see). If the option is wrong or the number behind -p is
+ wrong, patch will display a prompt like "file to patch?" and wait
+ for your answer, which should be CTRL-C in that case :-). Okay:
+
+ patch -p1 < your-favorite-diff
+
+ 2. After applying each patch, watch for reject files, e.g.
+
+ find . -name "*.rej" -print
+
+ If there are any, then the patch failed. You must repair it manually
+ now or you can give up completely. If you dare to repair it, take
+ a look at the *.rej files and try to find out what should have been
+ changed in the sources but couldn't be changed for some reasons.
+
+ Just note, you *cannot* continue if any "*.rej" file is present and
+ the problem is not fixed manually. You will have messed up kernel
+ sources that won't work or won't even compile.
+
+ 3. After applying the patch and eventually fixing problems manually
+ remove all patch related files in the kernel sources, e.g.
+
+ find . -name "*.orig" -exec rm {} \;
+ find . -name "*.rej" -exec rm {} \;
+
+ 4. Then apply the next patch (if you need), and so on.
+
+ C. Recompile the kernel from scratch. Don't install it yet. Watch for
+ errors and warnings that were not present before:
+
+ make mrproper (this is not always needed, but if problems arise
+ without it, try again starting here)
+ make config (this is also not always needed)
+ make dep
+ make clean
+ make zImage
+ make modules
+
+ Okay, if everything succeeded, you might want to give it a try.
+ It's best to use a boot disk for the first test ('make zdisk'), but
+ if your configuration is highly modular this won't be enough,
+ so you might not have another choice than doing 'make zlilo' and
+ 'make modules_install'.
+
+ Be sure to have a rescue boot and root floppy (a simple boot disk is
+ not always sufficient). I know most people are lazy and ignore this
+ until "it" happens. I've been lazy too :-) Also be sure to have
+ your old kernel and your old modules handy (if you only operated on
+ your test copy of the kernel, as I recommended above, you have them
+ still somewhere in the original source tree).
+
+
+Good luck and happy hacking. :)
+
+
+----------------------------------------------------------------------------
+
+List of CVF-FAT related diffs
+-----------------------------
+
+cvf.diff-2.0.33
+
+ This is a diff was generated against a cyrix-patched 2.0.33 kernel (I need
+ cyrix support, so don't ask me to leave it out). This shouldn't matter as
+ the cyrix patches don't affect filesystem code. So just don't wonder why
+ the paths in that patch include the name 'cyrix-patched'. Of course, the
+ diff does not contain the cyrix patches itself :)
+
+ This diff has been tested thoroughly and found to work with a plain 2.0.33
+ kernel.
+
+ If you are using the uvfat patches, uvfat will not work correctly on CVFs
+ (it cannot since some wrappers must be patched in). You must additionally
+ apply the cvf-uvfat.diff-2.0.33 patch.
+
+ This patch does not work for fat32 support. Try the next one instead :)
+ This patch also fails for Linux 2.0.34 and newer. Try the next one in this
+ case.
+
+cvf.diff-2.0.33+fat32-0.2.8
+cvf.diff-2.0.34 (link to same file)
+
+ This diff was generated against a cyrix-patched and fat32-patched 2.0.33
+ kernel. It works also with a 2.0.33 kernel that is only fat32-patched.
+ The fat32 version used is 0.2.8.
+
+ Please don't misunderstand. This diff does *not* include fat32 support
+ itself. It only works against a kernel that has already been patched for
+ fat32 support.
+
+ This patch has also been tested against the new 2.0.34, 2.0.35 and 2.0.36
+ kernels and found to work without problems :)
+
+cvf-uvfat.diff-2.0.33
+
+ This diff changes the uvfat filesystem so it works properly on CVFs.
+ Changes are minimal. This diff does not contain the uvfat patches itself.
+
+ What uvfat is? Look:
+ uvfat : umsdos == vfat : msdos
+ Search the net for more information. There's a uvfat homepage:
+ http://lab1.psy.univie.ac.at/~michael/uvfat.html
+
+ This diff must be applied *after* the uvfat patch and *after* the
+ cvf.diff-2.0.33 patch (or cvf.diff-2.0.33+fat32-0.2.8 - depending on what
+ you need). Note that the uvfat patches caused a reject file when I tried
+ (fs/Makefile.rej), so be sure to check. The problem was because there was
+ autofs added in Linux 2.0.31, and plain uvfat is against kernel 2.0.28.
+ Just add the text uvfat to the list in Makefile, and it works. As far as
+ I know, there's no uvfat update for newer (2.1.xx with xx>80) kernels.
+
+ Okay, step by step, this is what I have done, and it worked for me:
+
+ 1. Get linux 2.0.33 sources and unpack.
+ 2. Patch in linux-2.0.28-uvfat-0.1.diff.
+ 3. Repair the rejected file fs/Makefile.
+ 4. Patch in cvf.diff-2.0.33.
+ 5. Patch in this patch.
+
+kerneld-autoload.diff
+
+ This diff has been removed because it is obsolete. Use the updated cvf.c
+ files instead (see file cvf.c.README).
+
+in-kernel-2.0.35.diff
+
+ This diff can be used to compile dmsdos as a fix part of the kernel.
+ It hangs dmsdos into some of the kernel initialization files. If you want
+ to compile dmsdos as a fix part of the kernel, apply this patch, then
+ create a directory linux/fs/dmsdos, copy the dmsdos sources from src into
+ that directory, replace the Makefile with 'Makefile.kernel', and create a
+ link 'dmsdos-config.h' pointing to the generic kernel config include file
+ 'linux/include/linux/config.h' If you want a working help subsystem just
+ append the dmsdos Configure.help file to that one in the kernel. All of
+ that should be done automatically by the script 'in-kernel.sh' so just take
+ a look at it for details :) The script additionally avoids copying
+ unnecessary files.
+
+ NOTE: This patch may not work for kernels other than 2.0.35. But changes
+ are small and easy to understand. I expect that patching the fs/Makefile
+ fails just in the same way as it fails for the UVFAT patches :) Fix that
+ by manually adding the word 'dmsdos' to the subdirectory list in that
+ file.
+
+msdos-rmdir-bugfix.diff
+
+ This is indeed an excerpt from Alan Cox' pre-2.0.36 patches. It fixes
+ the msdos rmdir bug that can cause filesystem corruption in a msdos
+ filesystem (and therefore also in a compressed msdos filesystem).
+ Affected kernels are 2.0.34 and 2.0.35 and all earlier kernels that have
+ been patched for FAT32 support version 0.2.8. The bug is fixed in 2.0.36.
+
+ The diff just adds two missing braces to the msdos fs source code ...
+
+ I do not know whether 2.1.xx kernels are affected too. Maybe you take a
+ look at what where the diff adds the two missing braces and verify that
+ they are there in your kernel sources :)
+
+ In 2.2.x kernels this bug is not present.
+
+fat-truncate-bugfix.diff
+
+ There's a design flaw somewhere in the kernel or in the FAT driver (I
+ really cannot say where) that can write to a disk though the device is
+ mounted read-only. It is triggered at least by damaged directory entries
+ on a FAT partition. Such damaged directory entries are a rare condition,
+ but the dmsdos driver may leave them around when finding another problem
+ and setting the filesystem to read-only mode. This bug can destroy any
+ FAT based filesystem that has damaged directory entries.
+
+ The bug is at least present in kernels up to 2.0.36 from the 2.0 series
+ and in all kernels in the 2.1 series. Also it is in 2.2.x up to 2.2.2. For
+ newer kernels I don't know. As always with bugfixes: take a look at the
+ diff and the kernel sources ... :)
+
+ This bug has not yet been fixed in official kernels (kernel 2.2.2).
+
+vfat-brelse-bugfix.diff
+
+ There is a serious bug in the vfat driver (calls to brelse instead of
+ fat_brelse) that makes the system corrupt internal filesystem buffer
+ lists. (The bug bypasses the CVF-FAT interface and also causes problems
+ with filesystems that use a non-512 byte sector size [very rare condition
+ today].) It has only been reported to affect 2.2.x kernels, but late 2.1.x
+ kernels may have this bug too. Check the source code. As of kernel 2.2.2,
+ it has not yet been fixed in official kernels.
+
+ The bug is not present in 2.0.x kernels.
+
+linux-2.2.13-dmsdos.patch-1
+
+ Simple fix to fat_add_cluster1 to return non-NULL pointer to
+ first buffer-head of newly allocated cluster.
+
+linux-2.3.30-pre6-dmsdos.patch-1
+
+ Many changes needed to enable basic DMSDOS functionality
+ without MMAP support for 2.3.30-pre6
+ It contains
+ - simple fix to fat_extend_dir to return non-NULL
+ pointer to first buffer-head of newly allocated cluster
+ - fixes to fat read super - cvf_format must be set before
+ cvf_mount is called.
+ - cvf struct type fixes
+
+
+--------------------------------------------------------------------------
+
+Well, are there other useful extensions for the fat based filesystems
+that should be checked whether they work with CVF-FAT ? Just let me know.
diff --git a/patches/cvf-uvfat.diff-2.0.33 b/patches/cvf-uvfat.diff-2.0.33
new file mode 100644
index 0000000..e778111
--- /dev/null
+++ b/patches/cvf-uvfat.diff-2.0.33
@@ -0,0 +1,110 @@
+diff -u -r -N linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/emd.c linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/emd.c
+--- linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/emd.c Sun Jan 4 15:01:56 1998
++++ linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/emd.c Sun Jan 4 15:15:23 1998
+@@ -34,6 +34,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_read(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+@@ -50,6 +51,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_write(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+diff -u -r -N linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/file.c linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/file.c
+--- linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/file.c Sun Jan 4 15:01:56 1998
++++ linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/file.c Sun Jan 4 15:18:16 1998
+@@ -131,3 +131,38 @@
+ NULL, /* smap */
+ };
+
++/* For other with larger and unaligned file system with readpage */
++struct file_operations uvfat_file_operations_readpage = {
++ NULL, /* lseek - default */
++ UVFAT_file_read, /* read */
++ UVFAT_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations uvfat_file_inode_operations_readpage = {
++ &uvfat_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ UVFAT_truncate,/* truncate */
++ NULL, /* permission */
++ NULL, /* smap */
++};
++
+diff -u -r -N linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/inode.c linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/inode.c
+--- linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/inode.c Sun Jan 4 15:01:56 1998
++++ linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/inode.c Sun Jan 4 15:22:33 1998
+@@ -165,11 +165,20 @@
+ if (!uvfat_isinit(inode)){
+ inode->u.uvfat_i.i_emd_dir = 0;
+ if (S_ISREG(inode->i_mode)){
++ if (MSDOS_SB(inode->i_sb)->cvf_format){
++ if (MSDOS_SB(inode->i_sb)->cvf_format->flags
++ &CVF_USE_READPAGE){
++ inode->i_op = &uvfat_file_inode_operations_readpage;
++ }else{
++ inode->i_op = &uvfat_file_inode_operations_no_bmap;
++ }
++ }else{
+ if (inode->i_op->bmap != NULL){
+ inode->i_op = &uvfat_file_inode_operations;
+ }else{
+ inode->i_op = &uvfat_file_inode_operations_no_bmap;
+ }
++ }
+ }else if (S_ISDIR(inode->i_mode)){
+ if (dir != NULL){
+ uvfat_setup_dir_inode(inode);
+diff -u -r -N linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/ioctl.c linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/ioctl.c
+--- linux-2.0.33-cyrix-patched-uvfat/fs/uvfat/ioctl.c Sun Jan 4 15:01:56 1998
++++ linux-2.0.33-cyrix-patched-uvfat-test/fs/uvfat/ioctl.c Sun Jan 4 15:24:41 1998
+@@ -62,6 +62,21 @@
+ {
+ int ret = -EPERM;
+ int err;
++
++ /* forward non-uvfat ioctls - this hopefully doesn't cause conflicts */
++ if(cmd!=UVFAT_GETVERSION
++ &&cmd!=UVFAT_READDIR_DOS
++ &&cmd!=UVFAT_READDIR_EMD
++ &&cmd!=UVFAT_INIT_EMD
++ &&cmd!=UVFAT_CREAT_EMD
++ &&cmd!=UVFAT_RENAME_DOS
++ &&cmd!=UVFAT_UNLINK_EMD
++ &&cmd!=UVFAT_UNLINK_DOS
++ &&cmd!=UVFAT_RMDIR_DOS
++ &&cmd!=UVFAT_STAT_DOS
++ &&cmd!=UVFAT_DOS_SETUP)
++ return fat_dir_ioctl(dir,filp,cmd,data);
++
+ /* #Specification: ioctl / acces
+ Only root (effective id) is allowed to do IOCTL on directory
+ in UVFAT. EPERM is returned for other user.
diff --git a/patches/cvf.c b/patches/cvf.c
new file mode 100644
index 0000000..62c85c8
--- /dev/null
+++ b/patches/cvf.c
@@ -0,0 +1,147 @@
+/*
+ * CVF extensions for fat-based filesystems
+ *
+ * written 1997,1998 by Frank Gockel <[email protected]>
+ *
+ * please do not remove the next line, dmsdos needs it for verifying patches
+ * CVF-FAT-VERSION-ID: 1.1.0
+ *
+ */
+
+#include<linux/sched.h>
+#include<linux/fs.h>
+#include<linux/msdos_fs.h>
+#include<linux/msdos_fs_sb.h>
+#include<linux/string.h>
+#include<linux/fat_cvf.h>
+#include<linux/config.h>
+#ifdef CONFIG_KERNELD
+#include<linux/kerneld.h>
+#endif
+
+#define MAX_CVF_FORMATS 3
+
+struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
+int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
+
+int register_cvf_format(struct cvf_format*cvf_format)
+{ int i,j;
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i]==NULL)
+ { /* free slot found, now check version */
+ for(j=0;j<MAX_CVF_FORMATS;++j)
+ { if(cvf_formats[j])
+ { if(cvf_formats[j]->cvf_version==cvf_format->cvf_version)
+ { printk("register_cvf_format: version %d already registered\n",
+ cvf_format->cvf_version);
+ return -1;
+ }
+ }
+ }
+ cvf_formats[i]=cvf_format;
+ cvf_format_use_count[i]=0;
+ printk("CVF format %s (version id %d) successfully registered.\n",
+ cvf_format->cvf_version_text,cvf_format->cvf_version);
+ return 0;
+ }
+ }
+
+ printk("register_cvf_format: too many formats\n");
+ return -1;
+}
+
+int unregister_cvf_format(struct cvf_format*cvf_format)
+{ int i;
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->cvf_version==cvf_format->cvf_version)
+ { if(cvf_format_use_count[i])
+ { printk("unregister_cvf_format: format %d in use, cannot remove!\n",
+ cvf_formats[i]->cvf_version);
+ return -1;
+ }
+
+ printk("CVF format %s (version id %d) successfully unregistered.\n",
+ cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version);
+ cvf_formats[i]=NULL;
+ return 0;
+ }
+ }
+ }
+
+ printk("unregister_cvf_format: format %d is not registered\n",
+ cvf_format->cvf_version);
+ return -1;
+}
+
+void dec_cvf_format_use_count_by_version(int version)
+{ int i;
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->cvf_version==version)
+ { --cvf_format_use_count[i];
+ if(cvf_format_use_count[i]<0)
+ { cvf_format_use_count[i]=0;
+ printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n");
+ }
+ return;
+ }
+ }
+ }
+
+ printk("dec_cvf_format_use_count_by_version: version %d not found ???\n",
+ version);
+}
+
+int detect_cvf(struct super_block*sb,char*force)
+{ int i;
+ int found=0;
+ int found_i=-1;
+
+ if(force)
+ if(strcmp(force,"autoload")==0)
+ {
+#ifdef CONFIG_KERNELD
+ request_module("cvf_autoload");
+ force=NULL;
+#else
+ printk("cannot autoload CVF modules: kerneld support is not compiled into kernel\n");
+ return -1;
+#endif
+ }
+
+#ifdef CONFIG_KERNELD
+ if(force)
+ if(*force)
+ request_module(force);
+#endif
+
+ if(force)
+ { if(*force)
+ { for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
+ return i;
+ }
+ }
+ printk("CVF format %s unknown (module not loaded?)\n",force);
+ return -1;
+ }
+ }
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->detect_cvf(sb))
+ { ++found;
+ found_i=i;
+ }
+ }
+ }
+
+ if(found==1)return found_i;
+ if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
+ return -1;
+}
diff --git a/patches/cvf.c-2.1.128 b/patches/cvf.c-2.1.128
new file mode 100644
index 0000000..9dd70f8
--- /dev/null
+++ b/patches/cvf.c-2.1.128
@@ -0,0 +1,147 @@
+/*
+ * CVF extensions for fat-based filesystems
+ *
+ * written 1997,1998 by Frank Gockel <[email protected]>
+ *
+ * please do not remove the next line, dmsdos needs it for verifying patches
+ * CVF-FAT-VERSION-ID: 1.2.0
+ *
+ */
+
+#include<linux/sched.h>
+#include<linux/fs.h>
+#include<linux/msdos_fs.h>
+#include<linux/msdos_fs_sb.h>
+#include<linux/string.h>
+#include<linux/fat_cvf.h>
+#include<linux/config.h>
+#ifdef CONFIG_KMOD
+#include<linux/kmod.h>
+#endif
+
+#define MAX_CVF_FORMATS 3
+
+struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
+int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
+
+int register_cvf_format(struct cvf_format*cvf_format)
+{ int i,j;
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i]==NULL)
+ { /* free slot found, now check version */
+ for(j=0;j<MAX_CVF_FORMATS;++j)
+ { if(cvf_formats[j])
+ { if(cvf_formats[j]->cvf_version==cvf_format->cvf_version)
+ { printk("register_cvf_format: version %d already registered\n",
+ cvf_format->cvf_version);
+ return -1;
+ }
+ }
+ }
+ cvf_formats[i]=cvf_format;
+ cvf_format_use_count[i]=0;
+ printk("CVF format %s (version id %d) successfully registered.\n",
+ cvf_format->cvf_version_text,cvf_format->cvf_version);
+ return 0;
+ }
+ }
+
+ printk("register_cvf_format: too many formats\n");
+ return -1;
+}
+
+int unregister_cvf_format(struct cvf_format*cvf_format)
+{ int i;
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->cvf_version==cvf_format->cvf_version)
+ { if(cvf_format_use_count[i])
+ { printk("unregister_cvf_format: format %d in use, cannot remove!\n",
+ cvf_formats[i]->cvf_version);
+ return -1;
+ }
+
+ printk("CVF format %s (version id %d) successfully unregistered.\n",
+ cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version);
+ cvf_formats[i]=NULL;
+ return 0;
+ }
+ }
+ }
+
+ printk("unregister_cvf_format: format %d is not registered\n",
+ cvf_format->cvf_version);
+ return -1;
+}
+
+void dec_cvf_format_use_count_by_version(int version)
+{ int i;
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->cvf_version==version)
+ { --cvf_format_use_count[i];
+ if(cvf_format_use_count[i]<0)
+ { cvf_format_use_count[i]=0;
+ printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n");
+ }
+ return;
+ }
+ }
+ }
+
+ printk("dec_cvf_format_use_count_by_version: version %d not found ???\n",
+ version);
+}
+
+int detect_cvf(struct super_block*sb,char*force)
+{ int i;
+ int found=0;
+ int found_i=-1;
+
+ if(force)
+ if(strcmp(force,"autoload")==0)
+ {
+#ifdef CONFIG_KMOD
+ request_module("cvf_autoload");
+ force=NULL;
+#else
+ printk("cannot autoload CVF modules: kmod support is not compiled into kernel\n");
+ return -1;
+#endif
+ }
+
+#ifdef CONFIG_KMOD
+ if(force)
+ if(*force)
+ request_module(force);
+#endif
+
+ if(force)
+ { if(*force)
+ { for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
+ return i;
+ }
+ }
+ printk("CVF format %s unknown (module not loaded?)\n",force);
+ return -1;
+ }
+ }
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->detect_cvf(sb))
+ { ++found;
+ found_i=i;
+ }
+ }
+ }
+
+ if(found==1)return found_i;
+ if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
+ return -1;
+}
diff --git a/patches/cvf.c.README b/patches/cvf.c.README
new file mode 100644
index 0000000..9d5561c
--- /dev/null
+++ b/patches/cvf.c.README
@@ -0,0 +1,70 @@
+
+Update to CVF-FAT 1.1.0 or 1.2.0
+--------------------------------
+
+Today's kernels (currently means in time of Linux 2.2.2) use still CVF-FAT
+interface version 1.0.0. That is a bit outdated (and known to have one minor
+bug and some missing features).
+
+Latest versions are:
+ * CVF-FAT version 1.1.0 for 2.0.xx kernels
+ * CVF-FAT version 1.2.0 for kernels 2.1.128 or newer (also 2.2.x)
+ (The break between those two is somewhere between 2.1.94 and 2.1.128,
+ exactly it should be when kerneld was replaced by kmod, but I have never
+ verified that. Better use 2.0 or 2.2 kernels. :) )
+
+Files:
+
+ cvf.c: CVF-FAT 1.1.0. For kernels that support kerneld.
+ fat_cvf.txt: Documentation for CVF-FAT 1.1.0 (in file cvf.c).
+
+ cvf.c-2.1.128: CVF-FAT 1.2.0. For newer kernels that support kmod
+ instead of kerneld (including 2.2.x kernels).
+ fat_cvf.txt-2.1.128: Documentation for CVF-FAT 1.2.0 (in file
+ cvf.c-2.1.128).
+
+These files _replace_ the respective files in the kernel sources:
+
+ linux/fs/fat/cvf.c
+ linux/fs/Documentation/filesystems/fat_cvf.txt
+
+The only difference between CVF-FAT 1.1.0 and 1.2.0 is that 1.2.0 has
+been rewritten for kmod support which replaces kerneld in latest 2.1.xx
+kernels (and also 2.2.x kernels).
+*** Be sure to use the right file for your kernel! You must check the
+ kernel source or kernel documentation in order to find out whether
+ your kernel supports kerneld or kmod. At least, I know that all 2.0.xx
+ kernels support kerneld. Also, I checked that 2.1.128 uses kmod. Newer
+ kernels also should support kmod. That's all I know. You're on your
+ own here to find that out. A kernel that supports kmod should have a
+ file linux/Documentation/kmod.txt or similar, but I'm not 100% sure :)
+
+Who should update
+-----------------
+
+If you are using CVF-FAT 1.0.0 or older you may want to update. Watch for a
+version number in file linux/fs/fat/cvf.c. There should be a line somewhere
+at the beginning of the file that reads "CVF-FAT-VERSION-ID: x.y.z" where
+"x.y.z" is the version number. If this line is missing you are using version
+1.0.0 or older.
+
+Why update
+----------
+
+It fixes a bug that lets the mount command silently succeed if there is a
+special kind of error. This bug sometimes caused the plain FAT driver to
+mount a CVF in case of error with CVF-FAT support, which is surely not a
+good idea :)
+
+Now 'mount' fails with an error message in that case.
+
+Also the kerneld/kmod-autoload feature is now permanently in that file so you
+do not have to apply it as a seperate patch. For latest 2.1.xx kernels,
+where kerneld has been replaced by kmod, the kerneld-autoload support has
+been rewritten to use kmod instead.
+
+How to update
+-------------
+
+You can simply replace the old files with the new ones as listed above.
+Then recompile your modules (or your kernel if fat support is not modular).
diff --git a/patches/cvf.diff-2.0.33 b/patches/cvf.diff-2.0.33
new file mode 100644
index 0000000..84b3154
--- /dev/null
+++ b/patches/cvf.diff-2.0.33
@@ -0,0 +1,1056 @@
+diff -u -r -N linux-2.0.33-cyrix-patched/Documentation/filesystems/fat_cvf.txt linux-2.0.33-cyrix-patched-test/Documentation/filesystems/fat_cvf.txt
+--- linux-2.0.33-cyrix-patched/Documentation/filesystems/fat_cvf.txt Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-test/Documentation/filesystems/fat_cvf.txt Wed Nov 18 20:40:50 1998
+@@ -0,0 +1,210 @@
++This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998
++
++
++Table of Contents:
++
++1. The idea of CVF-FAT
++2. Restrictions
++3. Mount options
++4. Description of the CVF-FAT interface
++5. CVF Modules
++
++------------------------------------------------------------------------------
++
++
++1. The idea of CVF-FAT
++------------------------------------------------------------------------------
++
++CVF-FAT is a FAT filesystem extension that provides a generic interface for
++Compressed Volume Files in FAT partitions. Popular CVF software, for
++example, are Microsoft's Doublespace/Drivespace and Stac's Stacker.
++Using the CVF-FAT interface, it is possible to load a module that handles
++all the low-level disk access that has to do with on-the-fly compression
++and decompression. Any other part of FAT filesystem access is still handled
++by the FAT, MSDOS or VFAT or even UMSDOS driver.
++
++CVF access works by redirecting certain low-level routines from the FAT
++driver to a loadable, CVF-format specific module. This module must fake
++a normal FAT filesystem to the FAT driver while doing all the extra stuff
++like compression and decompression silently.
++
++
++2. Restrictions
++------------------------------------------------------------------------------
++
++- BMAP problems
++
++ CVF filesystems cannot do bmap. It's impossible in principle. Thus
++ all actions that require bmap do not work (swapping, writable mmapping).
++ Read-only mmapping works because the FAT driver has a hack for this
++ situation :) Well, writable mmapping should now work using the readpage
++ interface function which has been hacked into the FAT driver just for
++ CVF-FAT :)
++
++- attention, DOSEmu users
++
++ You may have to unmount all CVF partitions before running DOSEmu depending
++ on your configuration. If DOSEmu is configured to use wholedisk or
++ partition access (this is often the case to let DOSEmu access
++ compressed partitions) there's a risk of destroying your compressed
++ partitions or crashing your system because of confused drivers.
++
++ Note that it is always safe to redirect the compressed partitions with
++ lredir or emufs.sys. Refer to the DOSEmu documentation for details.
++
++
++3. Mount options
++------------------------------------------------------------------------------
++
++The CVF-FAT extension currently adds the following options to the FAT
++driver's standard options:
++
++ cvf_format=xxx
++ Forces the driver to use the CVF module "xxx" instead of auto-detection.
++ Without this option, the CVF-FAT interface asks all currently loaded
++ CVF modules whether they recognize the CVF. Therefore, this option is
++ only necessary if the CVF format is not recognized correctly
++ because of bugs or incompatibilities in the CVF modules. (It skips
++ the detect_cvf call.) "xxx" may be the text "none" (without the quotes)
++ to inhibit using any of the loaded CVF modules, just in case a CVF
++ module insists on mounting plain FAT filesystems by misunderstanding.
++ "xxx" may also be the text "autoload", which has a special meaning for
++ kerneld, but does not skip auto-detection.
++
++ If the kernel supports kerneld, the cvf_format=xxx option also controls
++ on-demand CVF module loading. Without this option, nothing is loaded
++ on demand. With cvf_format=xxx, a module "xxx" is requested automatically
++ before mounting the compressed filesystem (unless "xxx" is "none"). In
++ case there is a difference between the CVF format name and the module
++ name, setup aliases in your kerneld configuration. If the string "xxx"
++ is "autoload", a non-existent module "cvf_autoload" is requested which
++ can be used together with a special kerneld configuration (alias and
++ pre-install statements) in order to load more than one CVF module, let
++ them detect automatically which kind of CVF is to be mounted, and only
++ keep the "right" module in memory. For examples please refer to the
++ dmsdos documentation (ftp and http addresses see below).
++
++ cvf_options=yyy
++ Option string passed to the CVF module. I.e. only the "yyy" is passed
++ (without the quotes). The documentation for each CVF module should
++ explain it since it is interpreted only by the CVF module. Note that
++ the string must not contain a comma (",") - this would lead to
++ misinterpretation by the FAT driver, which would recognize the text
++ after a comma as a FAT driver option and might get confused or print
++ strange error messages. The documentation for the CVF module should
++ offer a different separation symbol, for example the dot "." or the
++ plus sign "+", which is only valid inside the string "yyy".
++
++
++4. Description of the CVF-FAT interface
++------------------------------------------------------------------------------
++
++Assuming you want to write your own CVF module, you need to write a lot of
++interface functions. Most of them are covered in the kernel documentation
++you can find on the net, and thus won't be described here. They have been
++marked with "[...]" :-) Take a look at include/linux/fat_cvf.h.
++
++struct cvf_format
++{ int cvf_version;
++ char* cvf_version_text;
++ unsigned long int flags;
++ int (*detect_cvf) (struct super_block*sb);
++ int (*mount_cvf) (struct super_block*sb,char*options);
++ int (*unmount_cvf) (struct super_block*sb);
++ [...]
++ void (*cvf_zero_cluster) (struct inode*inode,int clusternr);
++}
++
++This structure defines the capabilities of a CVF module. It must be filled
++out completely by a CVF module. Consider it as a kind of form that is used
++to introduce the module to the FAT/CVF-FAT driver.
++
++It contains...
++ - cvf_version:
++ A version id which must be unique. Choose one.
++ - cvf_version_text:
++ A human readable version string that should be one short word
++ describing the CVF format the module implements. This text is used
++ for the cvf_format option. This name must also be unique.
++ - flags:
++ Bit coded flags, currently only used for a readpage/mmap hack that
++ provides both mmap and readpage functionality. If CVF_USE_READPAGE
++ is set, mmap is set to generic_file_mmap and readpage is caught
++ and redirected to the cvf_readpage function. If it is not set,
++ readpage is set to generic_readpage and mmap is caught and redirected
++ to cvf_mmap. (If you want writable mmap use the readpage interface.)
++ - detect_cvf:
++ A function that is called to decide whether the filesystem is a CVF of
++ the type the module supports. The detect_cvf function must return 0
++ for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS
++ THE KIND OF CVF I SUPPORT". The function must maintain the module
++ usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
++ and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
++ successful recongition would lead to a call of the mount_cvf function
++ later.
++ - mount_cvf:
++ A function that sets up some values or initializes something additional
++ to what has to be done when a CVF is mounted. This is called at the
++ end of fat_read_super and must return 0 on success. Definitely, this
++ function must increment the module usage counter by MOD_INC_USE_COUNT.
++ This mount_cvf function is also responsible for interpreting a CVF
++ module specific option string (the "yyy" from the FAT mount option
++ "cvf_options=yyy") which cannot contain a comma (use for example the
++ dot "." as option separator symbol).
++ - unmount_cvf:
++ A function that is called when the filesystem is unmounted. Most likely
++ it only frees up some memory and calls MOD_DEC_USE_COUNT. The return
++ value might be ignored (it currently is ignored).
++ - [...]:
++ All other interface functions are "caught" FAT driver functions, i.e.
++ are executed by the FAT driver *instead* of the original FAT driver
++ functions. NULL means use the original FAT driver functions instead.
++ If you really want "no action", write a function that does nothing and
++ hang it in instead.
++ - cvf_zero_cluster:
++ The cvf_zero_cluster function is called when the fat driver wants to
++ zero out a (new) cluster. This is important for directories (mkdir).
++ If it is NULL, the FAT driver defaults to overwriting the whole
++ cluster with zeros. Note that clusternr is absolute, not relative
++ to the provided inode.
++
++Notes:
++ 1. The cvf_bmap function should be ignored. It really should never
++ get called from somewhere. I recommend redirecting it to a panic
++ or fatal error message so bugs show up immediately.
++ 2. The cvf_writepage function is ignored. This is because the fat
++ driver doesn't support it. This might change in future. I recommend
++ setting it to NULL (i.e use default).
++
++int register_cvf_format(struct cvf_format*cvf_format);
++ If you have just set up a variable containing the above structure,
++ call this function to introduce your CVF format to the FAT/CVF-FAT
++ driver. This is usually done in init_module. Be sure to check the
++ return value. Zero means success, everything else causes a kernel
++ message printed in the syslog describing the error that occurred.
++ Typical errors are:
++ - a module with the same version id is already registered or
++ - too many CVF formats. Hack fs/fat/cvf.c if you need more.
++
++int unregister_cvf_format(struct cvf_format*cvf_format);
++ This is usually called in cleanup_module. Return value =0 means
++ success. An error only occurs if you try to unregister a CVF format
++ that has not been previously registered. The code uses the version id
++ to distinguish the modules, so be sure to keep it unique.
++
++5. CVF Modules
++------------------------------------------------------------------------------
++
++Refer to the dmsdos module (the successor of the dmsdos filesystem) for a
++sample implementation. It can currently be found at
++
++ ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz
++ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz
++ ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz
++
++(where x.y.z is to be replaced with the actual version number). Full
++documentation about dmsdos is included in the dmsdos package, but can also
++be found at
++
++ http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html
++ http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese).
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/Makefile linux-2.0.33-cyrix-patched-test/fs/fat/Makefile
+--- linux-2.0.33-cyrix-patched/fs/fat/Makefile Wed Feb 7 08:39:27 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/Makefile Sat Dec 27 21:34:20 1997
+@@ -8,7 +8,7 @@
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+
+ O_TARGET := fat.o
+-O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o
++O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o cvf.o
+ OX_OBJS := fatfs_syms.o
+ M_OBJS := $(O_TARGET)
+
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/buffer.c linux-2.0.33-cyrix-patched-test/fs/fat/buffer.c
+--- linux-2.0.33-cyrix-patched/fs/fat/buffer.c Fri May 10 06:54:52 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/buffer.c Sat Dec 27 21:46:10 1997
+@@ -9,6 +9,7 @@
+ #include <linux/string.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
++#include <linux/fat_cvf.h>
+
+ struct buffer_head *fat_bread (
+ struct super_block *sb,
+@@ -16,6 +17,10 @@
+ {
+ struct buffer_head *ret = NULL;
+
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_bread)
++ return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
++
+ /* Note that the blocksize is 512 or 1024, but the first read
+ is always of size 1024. Doing readahead may be counterproductive
+ or just plain wrong. */
+@@ -73,6 +78,11 @@
+ int block)
+ {
+ struct buffer_head *ret = NULL;
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_getblk)
++ return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
++
+ if (sb->s_blocksize == 512){
+ ret = getblk (sb->s_dev,block,512);
+ }else{
+@@ -92,6 +102,10 @@
+ struct buffer_head *bh)
+ {
+ if (bh != NULL){
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_brelse)
++ return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
++
+ if (sb->s_blocksize == 512){
+ brelse (bh);
+ }else{
+@@ -109,6 +123,12 @@
+ struct buffer_head *bh,
+ int dirty_val)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty)
++ { MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty_val);
++ return;
++ }
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -120,6 +140,12 @@
+ struct buffer_head *bh,
+ int val)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_set_uptodate)
++ { MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
++ return;
++ }
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -129,6 +155,10 @@
+ struct super_block *sb,
+ struct buffer_head *bh)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
++ return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -141,6 +171,12 @@
+ int nbreq,
+ struct buffer_head *bh[32])
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block)
++ { MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
++ return;
++ }
++
+ if (sb->s_blocksize == 512){
+ ll_rw_block(opr,nbreq,bh);
+ }else{
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/cache.c linux-2.0.33-cyrix-patched-test/fs/fat/cache.c
+--- linux-2.0.33-cyrix-patched/fs/fat/cache.c Fri May 10 06:54:52 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/cache.c Sun Dec 28 12:16:08 1997
+@@ -9,6 +9,7 @@
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/stat.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -24,6 +25,10 @@
+ unsigned char *p_first,*p_last;
+ int first,last,next,copy,b;
+
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->fat_access)
++ return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
++
+ if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
+ return 0;
+ if (MSDOS_SB(sb)->fat_bits == 16) {
+@@ -246,6 +251,10 @@
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
++ if(sb->cvf_format)
++ if(sb->cvf_format->cvf_smap)
++ return sb->cvf_format->cvf_smap(inode,sector);
++
+ if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
+ !MSDOS_I(inode)->i_start)) {
+ if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0;
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/cvf.c linux-2.0.33-cyrix-patched-test/fs/fat/cvf.c
+--- linux-2.0.33-cyrix-patched/fs/fat/cvf.c Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-test/fs/fat/cvf.c Tue Nov 17 20:10:41 1998
+@@ -0,0 +1,147 @@
++/*
++ * CVF extensions for fat-based filesystems
++ *
++ * written 1997,1998 by Frank Gockel <[email protected]>
++ *
++ * please do not remove the next line, dmsdos needs it for verifying patches
++ * CVF-FAT-VERSION-ID: 1.1.0
++ *
++ */
++
++#include<linux/sched.h>
++#include<linux/fs.h>
++#include<linux/msdos_fs.h>
++#include<linux/msdos_fs_sb.h>
++#include<linux/string.h>
++#include<linux/fat_cvf.h>
++#include<linux/config.h>
++#ifdef CONFIG_KERNELD
++#include<linux/kerneld.h>
++#endif
++
++#define MAX_CVF_FORMATS 3
++
++struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
++int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
++
++int register_cvf_format(struct cvf_format*cvf_format)
++{ int i,j;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i]==NULL)
++ { /* free slot found, now check version */
++ for(j=0;j<MAX_CVF_FORMATS;++j)
++ { if(cvf_formats[j])
++ { if(cvf_formats[j]->cvf_version==cvf_format->cvf_version)
++ { printk("register_cvf_format: version %d already registered\n",
++ cvf_format->cvf_version);
++ return -1;
++ }
++ }
++ }
++ cvf_formats[i]=cvf_format;
++ cvf_format_use_count[i]=0;
++ printk("CVF format %s (version id %d) successfully registered.\n",
++ cvf_format->cvf_version_text,cvf_format->cvf_version);
++ return 0;
++ }
++ }
++
++ printk("register_cvf_format: too many formats\n");
++ return -1;
++}
++
++int unregister_cvf_format(struct cvf_format*cvf_format)
++{ int i;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->cvf_version==cvf_format->cvf_version)
++ { if(cvf_format_use_count[i])
++ { printk("unregister_cvf_format: format %d in use, cannot remove!\n",
++ cvf_formats[i]->cvf_version);
++ return -1;
++ }
++
++ printk("CVF format %s (version id %d) successfully unregistered.\n",
++ cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version);
++ cvf_formats[i]=NULL;
++ return 0;
++ }
++ }
++ }
++
++ printk("unregister_cvf_format: format %d is not registered\n",
++ cvf_format->cvf_version);
++ return -1;
++}
++
++void dec_cvf_format_use_count_by_version(int version)
++{ int i;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->cvf_version==version)
++ { --cvf_format_use_count[i];
++ if(cvf_format_use_count[i]<0)
++ { cvf_format_use_count[i]=0;
++ printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n");
++ }
++ return;
++ }
++ }
++ }
++
++ printk("dec_cvf_format_use_count_by_version: version %d not found ???\n",
++ version);
++}
++
++int detect_cvf(struct super_block*sb,char*force)
++{ int i;
++ int found=0;
++ int found_i=-1;
++
++ if(force)
++ if(strcmp(force,"autoload")==0)
++ {
++#ifdef CONFIG_KERNELD
++ request_module("cvf_autoload");
++ force=NULL;
++#else
++ printk("cannot autoload CVF modules: kerneld support is not compiled into kernel\n");
++ return -1;
++#endif
++ }
++
++#ifdef CONFIG_KERNELD
++ if(force)
++ if(*force)
++ request_module(force);
++#endif
++
++ if(force)
++ { if(*force)
++ { for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
++ return i;
++ }
++ }
++ printk("CVF format %s unknown (module not loaded?)\n",force);
++ return -1;
++ }
++ }
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->detect_cvf(sb))
++ { ++found;
++ found_i=i;
++ }
++ }
++ }
++
++ if(found==1)return found_i;
++ if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
++ return -1;
++}
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/dir.c linux-2.0.33-cyrix-patched-test/fs/fat/dir.c
+--- linux-2.0.33-cyrix-patched/fs/fat/dir.c Fri May 10 06:54:52 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/dir.c Sat Jan 3 12:41:00 1998
+@@ -382,6 +382,7 @@
+ unsigned int cmd, unsigned long arg)
+ {
+ int err;
++
+ /*
+ * We want to provide an interface for Samba to be able
+ * to get the short filename for a given long filename.
+@@ -408,6 +409,11 @@
+ vfat_ioctl_fill, NULL, 1, 0, 1);
+ }
+ default:
++ /* forward ioctl to CVF extension */
++ if(MSDOS_SB(inode->i_sb)->cvf_format
++ &&MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
++ return MSDOS_SB(inode->i_sb)->cvf_format->
++ cvf_dir_ioctl(inode,filp,cmd,arg);
+ return -EINVAL;
+ }
+
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/fatfs_syms.c linux-2.0.33-cyrix-patched-test/fs/fat/fatfs_syms.c
+--- linux-2.0.33-cyrix-patched/fs/fat/fatfs_syms.c Tue Mar 5 12:03:26 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/fatfs_syms.c Sat Jan 3 10:41:33 1998
+@@ -8,6 +8,7 @@
+
+ #include <linux/mm.h>
+ #include <linux/msdos_fs.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+ #include "tables.h"
+@@ -48,6 +49,13 @@
+ X(fat_uni2code),
+ X(fat_unlock_creation),
+ X(fat_write_inode),
++ X(register_cvf_format),
++ X(unregister_cvf_format),
++ X(get_cluster),
++ X(lock_fat),
++ X(unlock_fat),
++ X(fat_readpage),
++ X(fat_dir_ioctl),
+ #include <linux/symtab_end.h>
+ };
+
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/file.c linux-2.0.33-cyrix-patched-test/fs/fat/file.c
+--- linux-2.0.33-cyrix-patched/fs/fat/file.c Fri May 10 06:54:52 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/file.c Fri Jan 2 20:24:15 1998
+@@ -15,6 +15,7 @@
+ #include <linux/stat.h>
+ #include <linux/string.h>
+ #include <linux/pagemap.h>
++#include <linux/fat_cvf.h>
+
+ #include <asm/segment.h>
+ #include <asm/system.h>
+@@ -109,6 +110,40 @@
+ NULL /* smap */
+ };
+
++static struct file_operations fat_file_operations_readpage = {
++ NULL, /* lseek - default */
++ fat_file_read, /* read */
++ fat_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations fat_file_inode_operations_readpage = {
++ &fat_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ fat_truncate, /* truncate */
++ NULL, /* permission */
++ NULL /* smap */
++};
++
+ #define MSDOS_PREFETCH 32
+ struct fat_pre {
+ int file_sector;/* Next sector to read in the prefetch table */
+@@ -170,6 +205,10 @@
+ printk("fat_file_read: inode = NULL\n");
+ return -EINVAL;
+ }
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_file_read)
++ return MSDOS_SB(sb)->cvf_format->cvf_file_read(inode,filp,buf,count);
++
+ /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
+ printk("fat_file_read: mode = %07o\n",inode->i_mode);
+@@ -287,6 +326,10 @@
+ printk("fat_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_file_write)
++ return MSDOS_SB(sb)->cvf_format->cvf_file_write(inode,filp,buf,count);
++
+ /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
+ printk("fat_file_write: mode = %07o\n",inode->i_mode);
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/inode.c linux-2.0.33-cyrix-patched-test/fs/fat/inode.c
+--- linux-2.0.33-cyrix-patched/fs/fat/inode.c Sat Nov 30 11:27:38 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/inode.c Sat Jan 3 10:46:27 1998
+@@ -18,6 +18,8 @@
+ #include <linux/fs.h>
+ #include <linux/stat.h>
+ #include <linux/locks.h>
++#include <linux/fat_cvf.h>
++#include <linux/malloc.h>
+
+ #include "msbuffer.h"
+ #include "tables.h"
+@@ -75,6 +77,10 @@
+
+ void fat_put_super(struct super_block *sb)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ { dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
++ MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
++ }
+ fat_cache_inval_dev(sb->s_dev);
+ set_blocksize (sb->s_dev,BLOCK_SIZE);
+ lock_super(sb);
+@@ -86,7 +92,8 @@
+
+
+ static int parse_options(char *options,int *fat, int *blksize, int *debug,
+- struct fat_mount_options *opts)
++ struct fat_mount_options *opts,
++ char* cvf_format, char*cvf_options)
+ {
+ char *this_char,*value;
+
+@@ -181,6 +188,17 @@
+ return 0;
+ opts->sys_immutable = 1;
+ }
++ else if (!strcmp(this_char,"cvf_format")) {
++ if (!value)
++ return 0;
++ strncpy(cvf_format,value,20);
++ }
++ else if (!strcmp(this_char,"cvf_options")) {
++ if (!value)
++ return 0;
++ strncpy(cvf_options,value,100);
++ }
++
+ }
+ return 1;
+ }
+@@ -196,6 +214,14 @@
+ int debug,error,fat;
+ int blksize = 512;
+ struct fat_mount_options opts;
++ int i;
++ char cvf_format[21];
++ char cvf_options[101];
++
++ cvf_format[0]='\0';
++ cvf_options[0]='\0';
++ MSDOS_SB(sb)->cvf_format=NULL;
++ MSDOS_SB(sb)->private_data=NULL;
+
+ MOD_INC_USE_COUNT;
+ if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
+@@ -204,7 +230,7 @@
+ printk ("MSDOS: Hardware sector size is %d\n",blksize);
+ }
+ }
+- if (!parse_options((char *) data, &fat, &blksize, &debug, &opts)
++ if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, cvf_format, cvf_options)
+ || (blksize != 512 && blksize != 1024)) {
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+@@ -286,6 +312,9 @@
+ /* because clusters (DOS) are often aligned */
+ /* on odd sectors. */
+ sb->s_blocksize_bits = blksize == 512 ? 9 : 10;
++ if(!strcmp(cvf_format,"none"))i=-1;
++ else i=detect_cvf(sb,cvf_format);
++ if(i>=0)error=cvf_formats[i]->mount_cvf(sb,cvf_options);
+ if (error || debug) {
+ /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
+ printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
+@@ -302,13 +331,15 @@
+ (unsigned long)b->total_sect,logical_sector_size);
+ printk ("Transaction block size = %d\n",blksize);
+ }
+- if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
++ if(i<0) if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
+ MSDOS_SB(sb)->clusters = fat_clusters-2;
+ if (error) {
+ if (!silent)
+ printk("VFS: Can't find a valid MSDOS filesystem on dev "
+ "%s.\n", kdevname(sb->s_dev));
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+@@ -321,10 +352,16 @@
+ memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
+ if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ printk("get root inode failed\n");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
++ if(i>=0)
++ { MSDOS_SB(sb)->cvf_format=cvf_formats[i];
++ ++cvf_format_use_count[i];
++ }
+ return sb;
+ }
+
+@@ -333,7 +370,13 @@
+ {
+ int free,nr;
+ struct statfs tmp;
+-
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_statfs)
++ { MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz);
++ return;
++ }
++
+ lock_fat(sb);
+ if (MSDOS_SB(sb)->free_clusters != -1)
+ free = MSDOS_SB(sb)->free_clusters;
+@@ -362,6 +405,10 @@
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
++ if(sb->cvf_format)
++ if(sb->cvf_format->cvf_bmap)
++ return sb->cvf_format->cvf_bmap(inode,block);
++
+ if (inode->i_ino == MSDOS_ROOT_INO) {
+ return sb->dir_start + block;
+ }
+@@ -451,7 +498,12 @@
+ !is_exec(raw_entry->ext)))
+ ? S_IRUGO|S_IWUGO : S_IRWXUGO)
+ & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
+- inode->i_op = (sb->s_blocksize == 1024)
++ if(MSDOS_SB(sb)->cvf_format)
++ inode->i_op = (MSDOS_SB(sb)->cvf_format->flags&CVF_USE_READPAGE)
++ ? &fat_file_inode_operations_readpage
++ : &fat_file_inode_operations_1024;
++ else
++ inode->i_op = (sb->s_blocksize == 1024)
+ ? &fat_file_inode_operations_1024
+ : &fat_file_inode_operations;
+ MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/misc.c linux-2.0.33-cyrix-patched-test/fs/fat/misc.c
+--- linux-2.0.33-cyrix-patched/fs/fat/misc.c Fri May 10 06:54:52 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/misc.c Fri Jan 2 22:35:54 1998
+@@ -186,6 +186,10 @@
+ #endif
+ sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size;
+ last_sector = sector + cluster_size;
++ if(MSDOS_SB(sb)->cvf_format&&
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster)
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr);
++ else
+ for ( ; sector < last_sector; sector++) {
+ #ifdef DEBUG
+ printk("zeroing sector %d\n",sector);
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/fat/mmap.c linux-2.0.33-cyrix-patched-test/fs/fat/mmap.c
+--- linux-2.0.33-cyrix-patched/fs/fat/mmap.c Fri Feb 9 06:47:16 1996
++++ linux-2.0.33-cyrix-patched-test/fs/fat/mmap.c Fri Jan 2 20:15:29 1998
+@@ -93,6 +93,9 @@
+ */
+ int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+ {
++ if(MSDOS_SB(inode->i_sb)->cvf_format)
++ if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap)
++ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap(inode,file,vma);
+ if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
+ return -EINVAL;
+ if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+@@ -110,4 +113,12 @@
+ return 0;
+ }
+
++int fat_readpage(struct inode * inode, struct page * page)
++{
++ if(MSDOS_SB(inode->i_sb)->cvf_format)
++ if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage)
++ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page);
+
++ printk("fat_readpage called with no handler (shouldn't happen)\n");
++ return -1;
++}
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/umsdos/emd.c linux-2.0.33-cyrix-patched-test/fs/umsdos/emd.c
+--- linux-2.0.33-cyrix-patched/fs/umsdos/emd.c Wed Feb 7 08:39:29 1996
++++ linux-2.0.33-cyrix-patched-test/fs/umsdos/emd.c Sat Jan 3 19:13:43 1998
+@@ -32,6 +32,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_read(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+@@ -48,6 +49,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_write(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/umsdos/file.c linux-2.0.33-cyrix-patched-test/fs/umsdos/file.c
+--- linux-2.0.33-cyrix-patched/fs/umsdos/file.c Tue Feb 20 09:28:13 1996
++++ linux-2.0.33-cyrix-patched-test/fs/umsdos/file.c Fri Jan 2 23:50:57 1998
+@@ -129,3 +129,38 @@
+ NULL, /* smap */
+ };
+
++/* For other with larger and unaligned file system with readpage */
++struct file_operations umsdos_file_operations_readpage = {
++ NULL, /* lseek - default */
++ UMSDOS_file_read, /* read */
++ UMSDOS_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations umsdos_file_inode_operations_readpage = {
++ &umsdos_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ UMSDOS_truncate,/* truncate */
++ NULL, /* permission */
++ NULL, /* smap */
++};
++
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/umsdos/inode.c linux-2.0.33-cyrix-patched-test/fs/umsdos/inode.c
+--- linux-2.0.33-cyrix-patched/fs/umsdos/inode.c Sat Nov 30 11:21:22 1996
++++ linux-2.0.33-cyrix-patched-test/fs/umsdos/inode.c Fri Jan 2 23:55:34 1998
+@@ -149,11 +149,20 @@
+ if (!umsdos_isinit(inode)){
+ inode->u.umsdos_i.i_emd_dir = 0;
+ if (S_ISREG(inode->i_mode)){
++ if (MSDOS_SB(inode->i_sb)->cvf_format){
++ if (MSDOS_SB(inode->i_sb)->cvf_format->flags
++ &CVF_USE_READPAGE){
++ inode->i_op = &umsdos_file_inode_operations_readpage;
++ }else{
++ inode->i_op = &umsdos_file_inode_operations_no_bmap;
++ }
++ } else {
+ if (inode->i_op->bmap != NULL){
+ inode->i_op = &umsdos_file_inode_operations;
+ }else{
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
+ }
++ }
+ }else if (S_ISDIR(inode->i_mode)){
+ if (dir != NULL){
+ umsdos_setup_dir_inode(inode);
+diff -u -r -N linux-2.0.33-cyrix-patched/fs/umsdos/ioctl.c linux-2.0.33-cyrix-patched-test/fs/umsdos/ioctl.c
+--- linux-2.0.33-cyrix-patched/fs/umsdos/ioctl.c Wed Jul 3 15:39:48 1996
++++ linux-2.0.33-cyrix-patched-test/fs/umsdos/ioctl.c Sat Jan 3 13:01:52 1998
+@@ -60,6 +60,21 @@
+ {
+ int ret = -EPERM;
+ int err;
++
++ /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
++ if(cmd!=UMSDOS_GETVERSION
++ &&cmd!=UMSDOS_READDIR_DOS
++ &&cmd!=UMSDOS_READDIR_EMD
++ &&cmd!=UMSDOS_INIT_EMD
++ &&cmd!=UMSDOS_CREAT_EMD
++ &&cmd!=UMSDOS_RENAME_DOS
++ &&cmd!=UMSDOS_UNLINK_EMD
++ &&cmd!=UMSDOS_UNLINK_DOS
++ &&cmd!=UMSDOS_RMDIR_DOS
++ &&cmd!=UMSDOS_STAT_DOS
++ &&cmd!=UMSDOS_DOS_SETUP)
++ return fat_dir_ioctl(dir,filp,cmd,data);
++
+ /* #Specification: ioctl / acces
+ Only root (effective id) is allowed to do IOCTL on directory
+ in UMSDOS. EPERM is returned for other user.
+diff -u -r -N linux-2.0.33-cyrix-patched/include/linux/fat_cvf.h linux-2.0.33-cyrix-patched-test/include/linux/fat_cvf.h
+--- linux-2.0.33-cyrix-patched/include/linux/fat_cvf.h Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-test/include/linux/fat_cvf.h Sat Jan 3 12:42:28 1998
+@@ -0,0 +1,55 @@
++#ifndef _FAT_CVF
++#define _FAT_CVF
++
++#define CVF_USE_READPAGE 0x0001
++
++struct cvf_format
++{ int cvf_version;
++ char* cvf_version_text;
++ unsigned long flags;
++ int (*detect_cvf) (struct super_block*sb);
++ int (*mount_cvf) (struct super_block*sb,char*options);
++ int (*unmount_cvf) (struct super_block*sb);
++ struct buffer_head* (*cvf_bread) (struct super_block*sb,int block);
++ struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block);
++ void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh);
++ void (*cvf_mark_buffer_dirty) (struct super_block *sb,
++ struct buffer_head *bh,
++ int dirty_val);
++ void (*cvf_set_uptodate) (struct super_block *sb,
++ struct buffer_head *bh,
++ int val);
++ int (*cvf_is_uptodate) (struct super_block *sb,struct buffer_head *bh);
++ void (*cvf_ll_rw_block) (struct super_block *sb,
++ int opr,
++ int nbreq,
++ struct buffer_head *bh[32]);
++ int (*fat_access) (struct super_block *sb,int nr,int new_value);
++ void (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
++ int (*cvf_bmap) (struct inode *inode,int block);
++ int (*cvf_smap) (struct inode *inode,int sector);
++ int (*cvf_file_read) ( struct inode *inode,
++ struct file *filp,
++ char *buf,
++ int count);
++ int (*cvf_file_write) ( struct inode *inode,
++ struct file *filp,
++ const char *buf,
++ int count);
++ int (*cvf_mmap) (struct inode*, struct file *, struct vm_area_struct *);
++ int (*cvf_readpage) (struct inode *, struct page *);
++ int (*cvf_writepage) (struct inode *, struct page *);
++ int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp,
++ unsigned int cmd, unsigned long arg);
++ void (*zero_out_cluster) (struct inode*, int clusternr);
++};
++
++int register_cvf_format(struct cvf_format*cvf_format);
++int unregister_cvf_format(struct cvf_format*cvf_format);
++void dec_cvf_format_use_count_by_version(int version);
++int detect_cvf(struct super_block*sb,char*force);
++
++extern struct cvf_format *cvf_formats[];
++extern int cvf_format_use_count[];
++
++#endif
+diff -u -r -N linux-2.0.33-cyrix-patched/include/linux/msdos_fs.h linux-2.0.33-cyrix-patched-test/include/linux/msdos_fs.h
+--- linux-2.0.33-cyrix-patched/include/linux/msdos_fs.h Tue Dec 23 22:50:14 1997
++++ linux-2.0.33-cyrix-patched-test/include/linux/msdos_fs.h Sat Jan 3 13:03:16 1998
+@@ -221,12 +221,14 @@
+ /* file.c */
+ extern struct inode_operations fat_file_inode_operations;
+ extern struct inode_operations fat_file_inode_operations_1024;
++extern struct inode_operations fat_file_inode_operations_readpage;
+ extern int fat_file_read(struct inode *, struct file *, char *, int);
+ extern int fat_file_write(struct inode *, struct file *, const char *, int);
+ extern void fat_truncate(struct inode *inode);
+
+ /* mmap.c */
+ extern int fat_mmap(struct inode *, struct file *, struct vm_area_struct *);
++extern int fat_readpage(struct inode *, struct page *);
+
+
+ /* vfat.c */
+diff -u -r -N linux-2.0.33-cyrix-patched/include/linux/msdos_fs_sb.h linux-2.0.33-cyrix-patched-test/include/linux/msdos_fs_sb.h
+--- linux-2.0.33-cyrix-patched/include/linux/msdos_fs_sb.h Mon Mar 11 10:25:58 1996
++++ linux-2.0.33-cyrix-patched-test/include/linux/msdos_fs_sb.h Sat Jan 3 13:02:03 1998
+@@ -1,5 +1,6 @@
+ #ifndef _MSDOS_FS_SB
+ #define _MSDOS_FS_SB
++#include<linux/fat_cvf.h>
+
+ /*
+ * MS-DOS file system in-core superblock data
+@@ -34,6 +35,8 @@
+ int prev_free; /* previously returned free cluster number */
+ int free_clusters; /* -1 if undefined */
+ struct fat_mount_options options;
++ struct cvf_format* cvf_format;
++ void* private_data;
+ };
+
+ #endif
+diff -u -r -N linux-2.0.33-cyrix-patched/include/linux/umsdos_fs.h linux-2.0.33-cyrix-patched-test/include/linux/umsdos_fs.h
+--- linux-2.0.33-cyrix-patched/include/linux/umsdos_fs.h Tue Dec 23 22:50:14 1997
++++ linux-2.0.33-cyrix-patched-test/include/linux/umsdos_fs.h Sat Jan 3 13:04:02 1998
+@@ -135,6 +135,7 @@
+ extern struct file_operations umsdos_file_operations;
+ extern struct inode_operations umsdos_file_inode_operations;
+ extern struct inode_operations umsdos_file_inode_operations_no_bmap;
++extern struct inode_operations umsdos_file_inode_operations_readpage;
+ extern struct inode_operations umsdos_symlink_inode_operations;
+ extern int init_umsdos_fs(void);
+
+diff -u -r -N linux-2.0.33-cyrix-patched/kernel/ksyms.c linux-2.0.33-cyrix-patched-test/kernel/ksyms.c
+--- linux-2.0.33-cyrix-patched/kernel/ksyms.c Sat Nov 22 18:26:32 1997
++++ linux-2.0.33-cyrix-patched-test/kernel/ksyms.c Sat Jan 3 14:03:39 1998
+@@ -123,6 +123,9 @@
+ X(do_mmap),
+ X(do_munmap),
+ X(exit_mm),
++ X(exit_sighand),
++ X(exit_fs),
++ X(exit_files),
+
+ /* internal kernel memory management */
+ X(__get_free_pages),
diff --git a/patches/cvf.diff-2.0.33+fat32-0.2.8 b/patches/cvf.diff-2.0.33+fat32-0.2.8
new file mode 100644
index 0000000..4963301
--- /dev/null
+++ b/patches/cvf.diff-2.0.33+fat32-0.2.8
@@ -0,0 +1,1074 @@
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/Documentation/filesystems/fat_cvf.txt linux-2.0.33-cyrix-patched-fat32-test/Documentation/filesystems/fat_cvf.txt
+--- linux-2.0.33-cyrix-patched-fat32/Documentation/filesystems/fat_cvf.txt Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-fat32-test/Documentation/filesystems/fat_cvf.txt Wed Nov 18 20:40:50 1998
+@@ -0,0 +1,210 @@
++This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998
++
++
++Table of Contents:
++
++1. The idea of CVF-FAT
++2. Restrictions
++3. Mount options
++4. Description of the CVF-FAT interface
++5. CVF Modules
++
++------------------------------------------------------------------------------
++
++
++1. The idea of CVF-FAT
++------------------------------------------------------------------------------
++
++CVF-FAT is a FAT filesystem extension that provides a generic interface for
++Compressed Volume Files in FAT partitions. Popular CVF software, for
++example, are Microsoft's Doublespace/Drivespace and Stac's Stacker.
++Using the CVF-FAT interface, it is possible to load a module that handles
++all the low-level disk access that has to do with on-the-fly compression
++and decompression. Any other part of FAT filesystem access is still handled
++by the FAT, MSDOS or VFAT or even UMSDOS driver.
++
++CVF access works by redirecting certain low-level routines from the FAT
++driver to a loadable, CVF-format specific module. This module must fake
++a normal FAT filesystem to the FAT driver while doing all the extra stuff
++like compression and decompression silently.
++
++
++2. Restrictions
++------------------------------------------------------------------------------
++
++- BMAP problems
++
++ CVF filesystems cannot do bmap. It's impossible in principle. Thus
++ all actions that require bmap do not work (swapping, writable mmapping).
++ Read-only mmapping works because the FAT driver has a hack for this
++ situation :) Well, writable mmapping should now work using the readpage
++ interface function which has been hacked into the FAT driver just for
++ CVF-FAT :)
++
++- attention, DOSEmu users
++
++ You may have to unmount all CVF partitions before running DOSEmu depending
++ on your configuration. If DOSEmu is configured to use wholedisk or
++ partition access (this is often the case to let DOSEmu access
++ compressed partitions) there's a risk of destroying your compressed
++ partitions or crashing your system because of confused drivers.
++
++ Note that it is always safe to redirect the compressed partitions with
++ lredir or emufs.sys. Refer to the DOSEmu documentation for details.
++
++
++3. Mount options
++------------------------------------------------------------------------------
++
++The CVF-FAT extension currently adds the following options to the FAT
++driver's standard options:
++
++ cvf_format=xxx
++ Forces the driver to use the CVF module "xxx" instead of auto-detection.
++ Without this option, the CVF-FAT interface asks all currently loaded
++ CVF modules whether they recognize the CVF. Therefore, this option is
++ only necessary if the CVF format is not recognized correctly
++ because of bugs or incompatibilities in the CVF modules. (It skips
++ the detect_cvf call.) "xxx" may be the text "none" (without the quotes)
++ to inhibit using any of the loaded CVF modules, just in case a CVF
++ module insists on mounting plain FAT filesystems by misunderstanding.
++ "xxx" may also be the text "autoload", which has a special meaning for
++ kerneld, but does not skip auto-detection.
++
++ If the kernel supports kerneld, the cvf_format=xxx option also controls
++ on-demand CVF module loading. Without this option, nothing is loaded
++ on demand. With cvf_format=xxx, a module "xxx" is requested automatically
++ before mounting the compressed filesystem (unless "xxx" is "none"). In
++ case there is a difference between the CVF format name and the module
++ name, setup aliases in your kerneld configuration. If the string "xxx"
++ is "autoload", a non-existent module "cvf_autoload" is requested which
++ can be used together with a special kerneld configuration (alias and
++ pre-install statements) in order to load more than one CVF module, let
++ them detect automatically which kind of CVF is to be mounted, and only
++ keep the "right" module in memory. For examples please refer to the
++ dmsdos documentation (ftp and http addresses see below).
++
++ cvf_options=yyy
++ Option string passed to the CVF module. I.e. only the "yyy" is passed
++ (without the quotes). The documentation for each CVF module should
++ explain it since it is interpreted only by the CVF module. Note that
++ the string must not contain a comma (",") - this would lead to
++ misinterpretation by the FAT driver, which would recognize the text
++ after a comma as a FAT driver option and might get confused or print
++ strange error messages. The documentation for the CVF module should
++ offer a different separation symbol, for example the dot "." or the
++ plus sign "+", which is only valid inside the string "yyy".
++
++
++4. Description of the CVF-FAT interface
++------------------------------------------------------------------------------
++
++Assuming you want to write your own CVF module, you need to write a lot of
++interface functions. Most of them are covered in the kernel documentation
++you can find on the net, and thus won't be described here. They have been
++marked with "[...]" :-) Take a look at include/linux/fat_cvf.h.
++
++struct cvf_format
++{ int cvf_version;
++ char* cvf_version_text;
++ unsigned long int flags;
++ int (*detect_cvf) (struct super_block*sb);
++ int (*mount_cvf) (struct super_block*sb,char*options);
++ int (*unmount_cvf) (struct super_block*sb);
++ [...]
++ void (*cvf_zero_cluster) (struct inode*inode,int clusternr);
++}
++
++This structure defines the capabilities of a CVF module. It must be filled
++out completely by a CVF module. Consider it as a kind of form that is used
++to introduce the module to the FAT/CVF-FAT driver.
++
++It contains...
++ - cvf_version:
++ A version id which must be unique. Choose one.
++ - cvf_version_text:
++ A human readable version string that should be one short word
++ describing the CVF format the module implements. This text is used
++ for the cvf_format option. This name must also be unique.
++ - flags:
++ Bit coded flags, currently only used for a readpage/mmap hack that
++ provides both mmap and readpage functionality. If CVF_USE_READPAGE
++ is set, mmap is set to generic_file_mmap and readpage is caught
++ and redirected to the cvf_readpage function. If it is not set,
++ readpage is set to generic_readpage and mmap is caught and redirected
++ to cvf_mmap. (If you want writable mmap use the readpage interface.)
++ - detect_cvf:
++ A function that is called to decide whether the filesystem is a CVF of
++ the type the module supports. The detect_cvf function must return 0
++ for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS
++ THE KIND OF CVF I SUPPORT". The function must maintain the module
++ usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
++ and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
++ successful recongition would lead to a call of the mount_cvf function
++ later.
++ - mount_cvf:
++ A function that sets up some values or initializes something additional
++ to what has to be done when a CVF is mounted. This is called at the
++ end of fat_read_super and must return 0 on success. Definitely, this
++ function must increment the module usage counter by MOD_INC_USE_COUNT.
++ This mount_cvf function is also responsible for interpreting a CVF
++ module specific option string (the "yyy" from the FAT mount option
++ "cvf_options=yyy") which cannot contain a comma (use for example the
++ dot "." as option separator symbol).
++ - unmount_cvf:
++ A function that is called when the filesystem is unmounted. Most likely
++ it only frees up some memory and calls MOD_DEC_USE_COUNT. The return
++ value might be ignored (it currently is ignored).
++ - [...]:
++ All other interface functions are "caught" FAT driver functions, i.e.
++ are executed by the FAT driver *instead* of the original FAT driver
++ functions. NULL means use the original FAT driver functions instead.
++ If you really want "no action", write a function that does nothing and
++ hang it in instead.
++ - cvf_zero_cluster:
++ The cvf_zero_cluster function is called when the fat driver wants to
++ zero out a (new) cluster. This is important for directories (mkdir).
++ If it is NULL, the FAT driver defaults to overwriting the whole
++ cluster with zeros. Note that clusternr is absolute, not relative
++ to the provided inode.
++
++Notes:
++ 1. The cvf_bmap function should be ignored. It really should never
++ get called from somewhere. I recommend redirecting it to a panic
++ or fatal error message so bugs show up immediately.
++ 2. The cvf_writepage function is ignored. This is because the fat
++ driver doesn't support it. This might change in future. I recommend
++ setting it to NULL (i.e use default).
++
++int register_cvf_format(struct cvf_format*cvf_format);
++ If you have just set up a variable containing the above structure,
++ call this function to introduce your CVF format to the FAT/CVF-FAT
++ driver. This is usually done in init_module. Be sure to check the
++ return value. Zero means success, everything else causes a kernel
++ message printed in the syslog describing the error that occurred.
++ Typical errors are:
++ - a module with the same version id is already registered or
++ - too many CVF formats. Hack fs/fat/cvf.c if you need more.
++
++int unregister_cvf_format(struct cvf_format*cvf_format);
++ This is usually called in cleanup_module. Return value =0 means
++ success. An error only occurs if you try to unregister a CVF format
++ that has not been previously registered. The code uses the version id
++ to distinguish the modules, so be sure to keep it unique.
++
++5. CVF Modules
++------------------------------------------------------------------------------
++
++Refer to the dmsdos module (the successor of the dmsdos filesystem) for a
++sample implementation. It can currently be found at
++
++ ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz
++ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz
++ ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz
++
++(where x.y.z is to be replaced with the actual version number). Full
++documentation about dmsdos is included in the dmsdos package, but can also
++be found at
++
++ http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html
++ http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese).
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/Makefile linux-2.0.33-cyrix-patched-fat32-test/fs/fat/Makefile
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/Makefile Wed Feb 7 08:39:27 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/Makefile Sun Jan 4 11:59:56 1998
+@@ -8,7 +8,7 @@
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+
+ O_TARGET := fat.o
+-O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o
++O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o cvf.o
+ OX_OBJS := fatfs_syms.o
+ M_OBJS := $(O_TARGET)
+
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/buffer.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/buffer.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/buffer.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/buffer.c Sun Jan 4 12:07:19 1998
+@@ -9,6 +9,7 @@
+ #include <linux/string.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
++#include <linux/fat_cvf.h>
+
+ #if 0
+ # define PRINTK(x) printk x
+@@ -26,6 +27,11 @@
+ /* Note that the blocksize is 512 or 1024, but the first read
+ is always of size 1024. Doing readahead may be counterproductive
+ or just plain wrong. */
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_bread)
++ return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
++
+ if (sb->s_blocksize == 512) {
+ ret = bread (sb->s_dev,block,512);
+ } else {
+@@ -81,6 +87,11 @@
+ {
+ struct buffer_head *ret = NULL;
+ PRINTK(("fat_getblk: block=0x%x\n", block));
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_getblk)
++ return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
++
+ if (sb->s_blocksize == 512){
+ ret = getblk (sb->s_dev,block,512);
+ }else{
+@@ -100,6 +111,10 @@
+ struct buffer_head *bh)
+ {
+ if (bh != NULL){
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_brelse)
++ return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
++
+ if (sb->s_blocksize == 512){
+ brelse (bh);
+ }else{
+@@ -117,6 +132,12 @@
+ struct buffer_head *bh,
+ int dirty_val)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty)
++ { MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty_val);
++ return;
++ }
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -128,6 +149,12 @@
+ struct buffer_head *bh,
+ int val)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_set_uptodate)
++ { MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
++ return;
++ }
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -137,6 +164,10 @@
+ struct super_block *sb,
+ struct buffer_head *bh)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
++ return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -149,6 +180,12 @@
+ int nbreq,
+ struct buffer_head *bh[32])
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block)
++ { MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
++ return;
++ }
++
+ if (sb->s_blocksize == 512){
+ ll_rw_block(opr,nbreq,bh);
+ }else{
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/cache.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cache.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/cache.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cache.c Sun Jan 4 12:08:48 1998
+@@ -9,6 +9,7 @@
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/stat.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -29,6 +30,10 @@
+ unsigned char *p_first,*p_last;
+ int copy,first,last,next,b;
+
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->fat_access)
++ return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
++
+ if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
+ return 0;
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+@@ -261,6 +266,10 @@
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
++ if(sb->cvf_format)
++ if(sb->cvf_format->cvf_smap)
++ return sb->cvf_format->cvf_smap(inode,sector);
++
+ if ((sb->fat_bits != 32) &&
+ (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
+ !MSDOS_I(inode)->i_start))) {
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/cvf.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cvf.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/cvf.c Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cvf.c Tue Nov 17 20:10:41 1998
+@@ -0,0 +1,147 @@
++/*
++ * CVF extensions for fat-based filesystems
++ *
++ * written 1997,1998 by Frank Gockel <[email protected]>
++ *
++ * please do not remove the next line, dmsdos needs it for verifying patches
++ * CVF-FAT-VERSION-ID: 1.1.0
++ *
++ */
++
++#include<linux/sched.h>
++#include<linux/fs.h>
++#include<linux/msdos_fs.h>
++#include<linux/msdos_fs_sb.h>
++#include<linux/string.h>
++#include<linux/fat_cvf.h>
++#include<linux/config.h>
++#ifdef CONFIG_KERNELD
++#include<linux/kerneld.h>
++#endif
++
++#define MAX_CVF_FORMATS 3
++
++struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
++int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
++
++int register_cvf_format(struct cvf_format*cvf_format)
++{ int i,j;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i]==NULL)
++ { /* free slot found, now check version */
++ for(j=0;j<MAX_CVF_FORMATS;++j)
++ { if(cvf_formats[j])
++ { if(cvf_formats[j]->cvf_version==cvf_format->cvf_version)
++ { printk("register_cvf_format: version %d already registered\n",
++ cvf_format->cvf_version);
++ return -1;
++ }
++ }
++ }
++ cvf_formats[i]=cvf_format;
++ cvf_format_use_count[i]=0;
++ printk("CVF format %s (version id %d) successfully registered.\n",
++ cvf_format->cvf_version_text,cvf_format->cvf_version);
++ return 0;
++ }
++ }
++
++ printk("register_cvf_format: too many formats\n");
++ return -1;
++}
++
++int unregister_cvf_format(struct cvf_format*cvf_format)
++{ int i;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->cvf_version==cvf_format->cvf_version)
++ { if(cvf_format_use_count[i])
++ { printk("unregister_cvf_format: format %d in use, cannot remove!\n",
++ cvf_formats[i]->cvf_version);
++ return -1;
++ }
++
++ printk("CVF format %s (version id %d) successfully unregistered.\n",
++ cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version);
++ cvf_formats[i]=NULL;
++ return 0;
++ }
++ }
++ }
++
++ printk("unregister_cvf_format: format %d is not registered\n",
++ cvf_format->cvf_version);
++ return -1;
++}
++
++void dec_cvf_format_use_count_by_version(int version)
++{ int i;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->cvf_version==version)
++ { --cvf_format_use_count[i];
++ if(cvf_format_use_count[i]<0)
++ { cvf_format_use_count[i]=0;
++ printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n");
++ }
++ return;
++ }
++ }
++ }
++
++ printk("dec_cvf_format_use_count_by_version: version %d not found ???\n",
++ version);
++}
++
++int detect_cvf(struct super_block*sb,char*force)
++{ int i;
++ int found=0;
++ int found_i=-1;
++
++ if(force)
++ if(strcmp(force,"autoload")==0)
++ {
++#ifdef CONFIG_KERNELD
++ request_module("cvf_autoload");
++ force=NULL;
++#else
++ printk("cannot autoload CVF modules: kerneld support is not compiled into kernel\n");
++ return -1;
++#endif
++ }
++
++#ifdef CONFIG_KERNELD
++ if(force)
++ if(*force)
++ request_module(force);
++#endif
++
++ if(force)
++ { if(*force)
++ { for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
++ return i;
++ }
++ }
++ printk("CVF format %s unknown (module not loaded?)\n",force);
++ return -1;
++ }
++ }
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->detect_cvf(sb))
++ { ++found;
++ found_i=i;
++ }
++ }
++ }
++
++ if(found==1)return found_i;
++ if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
++ return -1;
++}
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/dir.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/dir.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/dir.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/dir.c Sun Jan 4 11:59:56 1998
+@@ -425,6 +425,7 @@
+ unsigned int cmd, unsigned long arg)
+ {
+ int err;
++
+ /*
+ * We want to provide an interface for Samba to be able
+ * to get the short filename for a given long filename.
+@@ -451,6 +452,11 @@
+ vfat_ioctl_fill, NULL, 1, 0, 1);
+ }
+ default:
++ /* forward ioctl to CVF extension */
++ if(MSDOS_SB(inode->i_sb)->cvf_format
++ &&MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
++ return MSDOS_SB(inode->i_sb)->cvf_format->
++ cvf_dir_ioctl(inode,filp,cmd,arg);
+ return -EINVAL;
+ }
+
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/fatfs_syms.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/fatfs_syms.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/fatfs_syms.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/fatfs_syms.c Sun Jan 4 12:11:10 1998
+@@ -11,6 +11,7 @@
+
+ #include <linux/mm.h>
+ #include <linux/msdos_fs.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -53,6 +54,13 @@
+ X(fat_uni2esc) X_PUNCT
+ X(fat_unlock_creation) X_PUNCT
+ X(fat_write_inode) X_PUNCT
++X(register_cvf_format) X_PUNCT
++X(unregister_cvf_format) X_PUNCT
++X(get_cluster) X_PUNCT
++X(lock_fat) X_PUNCT
++X(unlock_fat) X_PUNCT
++X(fat_readpage) X_PUNCT
++X(fat_dir_ioctl) X_PUNCT
+ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+ #include <linux/symtab_end.h>
+ };
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/file.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/file.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/file.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/file.c Sun Jan 4 11:59:56 1998
+@@ -17,6 +17,7 @@
+ #include <linux/stat.h>
+ #include <linux/string.h>
+ #include <linux/pagemap.h>
++#include <linux/fat_cvf.h>
+
+ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+ #include <asm/uaccess.h>
+@@ -121,6 +122,40 @@
+ NULL /* smap */
+ };
+
++static struct file_operations fat_file_operations_readpage = {
++ NULL, /* lseek - default */
++ fat_file_read, /* read */
++ fat_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations fat_file_inode_operations_readpage = {
++ &fat_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ fat_truncate, /* truncate */
++ NULL, /* permission */
++ NULL /* smap */
++};
++
+ #define MSDOS_PREFETCH 32
+ struct fat_pre {
+ int file_sector;/* Next sector to read in the prefetch table */
+@@ -183,6 +218,10 @@
+ printk("fat_file_read: inode = NULL\n");
+ return -EINVAL;
+ }
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_file_read)
++ return MSDOS_SB(sb)->cvf_format->cvf_file_read(inode,filp,buf,count);
++
+ /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
+ printk("fat_file_read: mode = %07o\n",inode->i_mode);
+@@ -305,6 +344,10 @@
+ printk("fat_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_file_write)
++ return MSDOS_SB(sb)->cvf_format->cvf_file_write(inode,filp,buf,count);
++
+ /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
+ printk("fat_file_write: mode = %07o\n",inode->i_mode);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/inode.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/inode.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/inode.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/inode.c Sun Jan 4 12:31:18 1998
+@@ -22,6 +22,7 @@
+ #include <linux/stat.h>
+ #include <linux/locks.h>
+ #include <linux/malloc.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -88,6 +89,10 @@
+
+ void fat_put_super(struct super_block *sb)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ { dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
++ MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
++ }
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ fat_clusters_flush(sb);
+ }
+@@ -113,7 +118,8 @@
+
+
+ static int parse_options(char *options,int *fat, int *blksize, int *debug,
+- struct fat_mount_options *opts)
++ struct fat_mount_options *opts,
++ char* cvf_format, char*cvf_options)
+ {
+ char *this_char,*value,save,*savep;
+ char *p;
+@@ -239,6 +245,16 @@
+ ret = 0;
+ }
+ }
++ else if (!strcmp(this_char,"cvf_format")) {
++ if (!value)
++ return 0;
++ strncpy(cvf_format,value,20);
++ }
++ else if (!strcmp(this_char,"cvf_options")) {
++ if (!value)
++ return 0;
++ strncpy(cvf_options,value,100);
++ }
+
+ if (this_char != options) *(this_char-1) = ',';
+ if (value) *savep = save;
+@@ -261,6 +277,14 @@
+ struct fat_mount_options opts;
+ char buf[50];
+ char *p;
++ int i;
++ char cvf_format[21];
++ char cvf_options[101];
++
++ cvf_format[0]='\0';
++ cvf_options[0]='\0';
++ MSDOS_SB(sb)->cvf_format=NULL;
++ MSDOS_SB(sb)->private_data=NULL;
+
+ MOD_INC_USE_COUNT;
+ if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
+@@ -270,7 +294,8 @@
+ }
+ }
+ opts.isvfat = MSDOS_SB(sb)->options.isvfat;
+- if (!parse_options((char *) data, &fat, &blksize, &debug, &opts)
++ if (!parse_options((char *) data, &fat, &blksize, &debug, &opts,
++ cvf_format, cvf_options)
+ || (blksize != 512 && blksize != 1024)) {
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+@@ -375,6 +400,9 @@
+ /* because clusters (DOS) are often aligned */
+ /* on odd sectors. */
+ sb->s_blocksize_bits = blksize == 512 ? 9 : 10;
++ if(!strcmp(cvf_format,"none"))i=-1;
++ else i=detect_cvf(sb,cvf_format);
++ if(i>=0)error=cvf_formats[i]->mount_cvf(sb,cvf_options);
+ if (error || debug) {
+ /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
+ printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
+@@ -392,13 +420,15 @@
+ MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters);
+ printk ("Transaction block size = %d\n",blksize);
+ }
+- if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
++ if(i<0) if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
+ MSDOS_SB(sb)->clusters = fat_clusters-2;
+ if (error) {
+ if (!silent)
+ printk("VFS: Can't find a valid MSDOS filesystem on dev "
+ "%s.\n", kdevname(sb->s_dev));
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+@@ -419,6 +449,8 @@
+ MSDOS_SB(sb)->nls_disk = load_nls_default();
+ } else {
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+@@ -433,6 +465,8 @@
+ kfree(opts.iocharset);
+ unload_nls(MSDOS_SB(sb)->nls_disk);
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ } else {
+@@ -447,9 +481,16 @@
+ unload_nls(MSDOS_SB(sb)->nls_disk);
+ if (MSDOS_SB(sb)->nls_io) unload_nls(MSDOS_SB(sb)->nls_io);
+ if (opts.iocharset) kfree(opts.iocharset);
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
++
++ if(i>=0)
++ { MSDOS_SB(sb)->cvf_format=cvf_formats[i];
++ ++cvf_format_use_count[i];
++ }
+
+ return sb;
+ }
+@@ -459,7 +500,13 @@
+ {
+ int free,nr;
+ struct statfs tmp;
+-
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_statfs)
++ { MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz);
++ return;
++ }
++
+ lock_fat(sb);
+ if (MSDOS_SB(sb)->free_clusters != -1)
+ free = MSDOS_SB(sb)->free_clusters;
+@@ -488,6 +535,10 @@
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
++ if(sb->cvf_format)
++ if(sb->cvf_format->cvf_bmap)
++ return sb->cvf_format->cvf_bmap(inode,block);
++
+ if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
+ return sb->dir_start + block;
+ }
+@@ -600,7 +651,12 @@
+ !is_exec(raw_entry->ext)))
+ ? S_IRUGO|S_IWUGO : S_IRWXUGO)
+ & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
+- inode->i_op = (sb->s_blocksize == 1024)
++ if(MSDOS_SB(sb)->cvf_format)
++ inode->i_op = (MSDOS_SB(sb)->cvf_format->flags&CVF_USE_READPAGE)
++ ? &fat_file_inode_operations_readpage
++ : &fat_file_inode_operations_1024;
++ else
++ inode->i_op = (sb->s_blocksize == 1024)
+ ? &fat_file_inode_operations_1024
+ : &fat_file_inode_operations;
+ MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/misc.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/misc.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/misc.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/misc.c Sun Jan 4 11:59:56 1998
+@@ -225,6 +225,10 @@
+ #endif
+ sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size;
+ last_sector = sector + cluster_size;
++ if(MSDOS_SB(sb)->cvf_format&&
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster)
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr);
++ else
+ for ( ; sector < last_sector; sector++) {
+ #ifdef DEBUG
+ printk("zeroing sector %d\n",sector);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/mmap.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/mmap.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/mmap.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/mmap.c Sun Jan 4 11:59:56 1998
+@@ -100,6 +100,9 @@
+ */
+ int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+ {
++ if(MSDOS_SB(inode->i_sb)->cvf_format)
++ if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap)
++ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap(inode,file,vma);
+ if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
+ return -EINVAL;
+ if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+@@ -117,4 +120,12 @@
+ return 0;
+ }
+
++int fat_readpage(struct inode * inode, struct page * page)
++{
++ if(MSDOS_SB(inode->i_sb)->cvf_format)
++ if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage)
++ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page);
+
++ printk("fat_readpage called with no handler (shouldn't happen)\n");
++ return -1;
++}
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/emd.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/emd.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/emd.c Wed Feb 7 08:39:29 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/emd.c Sun Jan 4 11:59:56 1998
+@@ -32,6 +32,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_read(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+@@ -48,6 +49,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_write(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/file.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/file.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/file.c Tue Feb 20 09:28:13 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/file.c Sun Jan 4 11:59:56 1998
+@@ -129,3 +129,38 @@
+ NULL, /* smap */
+ };
+
++/* For other with larger and unaligned file system with readpage */
++struct file_operations umsdos_file_operations_readpage = {
++ NULL, /* lseek - default */
++ UMSDOS_file_read, /* read */
++ UMSDOS_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations umsdos_file_inode_operations_readpage = {
++ &umsdos_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ UMSDOS_truncate,/* truncate */
++ NULL, /* permission */
++ NULL, /* smap */
++};
++
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/inode.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/inode.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/inode.c Sat Nov 30 11:21:22 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/inode.c Sun Jan 4 11:59:56 1998
+@@ -149,11 +149,20 @@
+ if (!umsdos_isinit(inode)){
+ inode->u.umsdos_i.i_emd_dir = 0;
+ if (S_ISREG(inode->i_mode)){
++ if (MSDOS_SB(inode->i_sb)->cvf_format){
++ if (MSDOS_SB(inode->i_sb)->cvf_format->flags
++ &CVF_USE_READPAGE){
++ inode->i_op = &umsdos_file_inode_operations_readpage;
++ }else{
++ inode->i_op = &umsdos_file_inode_operations_no_bmap;
++ }
++ } else {
+ if (inode->i_op->bmap != NULL){
+ inode->i_op = &umsdos_file_inode_operations;
+ }else{
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
+ }
++ }
+ }else if (S_ISDIR(inode->i_mode)){
+ if (dir != NULL){
+ umsdos_setup_dir_inode(inode);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/ioctl.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/ioctl.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/ioctl.c Wed Jul 3 15:39:48 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/ioctl.c Sun Jan 4 11:59:56 1998
+@@ -60,6 +60,21 @@
+ {
+ int ret = -EPERM;
+ int err;
++
++ /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
++ if(cmd!=UMSDOS_GETVERSION
++ &&cmd!=UMSDOS_READDIR_DOS
++ &&cmd!=UMSDOS_READDIR_EMD
++ &&cmd!=UMSDOS_INIT_EMD
++ &&cmd!=UMSDOS_CREAT_EMD
++ &&cmd!=UMSDOS_RENAME_DOS
++ &&cmd!=UMSDOS_UNLINK_EMD
++ &&cmd!=UMSDOS_UNLINK_DOS
++ &&cmd!=UMSDOS_RMDIR_DOS
++ &&cmd!=UMSDOS_STAT_DOS
++ &&cmd!=UMSDOS_DOS_SETUP)
++ return fat_dir_ioctl(dir,filp,cmd,data);
++
+ /* #Specification: ioctl / acces
+ Only root (effective id) is allowed to do IOCTL on directory
+ in UMSDOS. EPERM is returned for other user.
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/fat_cvf.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/fat_cvf.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/fat_cvf.h Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/fat_cvf.h Sun Jan 4 11:59:56 1998
+@@ -0,0 +1,55 @@
++#ifndef _FAT_CVF
++#define _FAT_CVF
++
++#define CVF_USE_READPAGE 0x0001
++
++struct cvf_format
++{ int cvf_version;
++ char* cvf_version_text;
++ unsigned long flags;
++ int (*detect_cvf) (struct super_block*sb);
++ int (*mount_cvf) (struct super_block*sb,char*options);
++ int (*unmount_cvf) (struct super_block*sb);
++ struct buffer_head* (*cvf_bread) (struct super_block*sb,int block);
++ struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block);
++ void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh);
++ void (*cvf_mark_buffer_dirty) (struct super_block *sb,
++ struct buffer_head *bh,
++ int dirty_val);
++ void (*cvf_set_uptodate) (struct super_block *sb,
++ struct buffer_head *bh,
++ int val);
++ int (*cvf_is_uptodate) (struct super_block *sb,struct buffer_head *bh);
++ void (*cvf_ll_rw_block) (struct super_block *sb,
++ int opr,
++ int nbreq,
++ struct buffer_head *bh[32]);
++ int (*fat_access) (struct super_block *sb,int nr,int new_value);
++ void (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
++ int (*cvf_bmap) (struct inode *inode,int block);
++ int (*cvf_smap) (struct inode *inode,int sector);
++ int (*cvf_file_read) ( struct inode *inode,
++ struct file *filp,
++ char *buf,
++ int count);
++ int (*cvf_file_write) ( struct inode *inode,
++ struct file *filp,
++ const char *buf,
++ int count);
++ int (*cvf_mmap) (struct inode*, struct file *, struct vm_area_struct *);
++ int (*cvf_readpage) (struct inode *, struct page *);
++ int (*cvf_writepage) (struct inode *, struct page *);
++ int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp,
++ unsigned int cmd, unsigned long arg);
++ void (*zero_out_cluster) (struct inode*, int clusternr);
++};
++
++int register_cvf_format(struct cvf_format*cvf_format);
++int unregister_cvf_format(struct cvf_format*cvf_format);
++void dec_cvf_format_use_count_by_version(int version);
++int detect_cvf(struct super_block*sb,char*force);
++
++extern struct cvf_format *cvf_formats[];
++extern int cvf_format_use_count[];
++
++#endif
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs.h Sun Jan 4 11:55:33 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs.h Sun Jan 4 12:40:48 1998
+@@ -246,12 +246,14 @@
+ /* file.c */
+ extern struct inode_operations fat_file_inode_operations;
+ extern struct inode_operations fat_file_inode_operations_1024;
++extern struct inode_operations fat_file_inode_operations_readpage;
+ extern int fat_file_read(struct inode *, struct file *, char *, int);
+ extern int fat_file_write(struct inode *, struct file *, const char *, int);
+ extern void fat_truncate(struct inode *inode);
+
+ /* mmap.c */
+ extern int fat_mmap(struct inode *, struct file *, struct vm_area_struct *);
++extern int fat_readpage(struct inode *, struct page *);
+
+
+ /* vfat.c */
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs_sb.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs_sb.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs_sb.h Sun Jan 4 11:55:33 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs_sb.h Sun Jan 4 12:02:05 1998
+@@ -1,5 +1,6 @@
+ #ifndef _MSDOS_FS_SB
+ #define _MSDOS_FS_SB
++#include<linux/fat_cvf.h>
+
+ /*
+ * MS-DOS file system in-core superblock data
+@@ -46,6 +47,8 @@
+ struct fat_mount_options options;
+ struct nls_table *nls_disk; /* Codepage used on disk */
+ struct nls_table *nls_io; /* Charset used for input and display */
++ struct cvf_format* cvf_format;
++ void* private_data;
+ };
+
+ #endif
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/umsdos_fs.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/umsdos_fs.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/umsdos_fs.h Tue Dec 23 22:50:14 1997
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/umsdos_fs.h Sun Jan 4 12:40:48 1998
+@@ -135,6 +135,7 @@
+ extern struct file_operations umsdos_file_operations;
+ extern struct inode_operations umsdos_file_inode_operations;
+ extern struct inode_operations umsdos_file_inode_operations_no_bmap;
++extern struct inode_operations umsdos_file_inode_operations_readpage;
+ extern struct inode_operations umsdos_symlink_inode_operations;
+ extern int init_umsdos_fs(void);
+
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/kernel/ksyms.c linux-2.0.33-cyrix-patched-fat32-test/kernel/ksyms.c
+--- linux-2.0.33-cyrix-patched-fat32/kernel/ksyms.c Sun Jan 4 11:55:33 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/kernel/ksyms.c Sun Jan 4 11:59:56 1998
+@@ -124,6 +124,9 @@
+ X(do_mmap),
+ X(do_munmap),
+ X(exit_mm),
++ X(exit_sighand),
++ X(exit_fs),
++ X(exit_files),
+
+ /* internal kernel memory management */
+ X(__get_free_pages),
diff --git a/patches/cvf.diff-2.0.34 b/patches/cvf.diff-2.0.34
new file mode 100644
index 0000000..4963301
--- /dev/null
+++ b/patches/cvf.diff-2.0.34
@@ -0,0 +1,1074 @@
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/Documentation/filesystems/fat_cvf.txt linux-2.0.33-cyrix-patched-fat32-test/Documentation/filesystems/fat_cvf.txt
+--- linux-2.0.33-cyrix-patched-fat32/Documentation/filesystems/fat_cvf.txt Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-fat32-test/Documentation/filesystems/fat_cvf.txt Wed Nov 18 20:40:50 1998
+@@ -0,0 +1,210 @@
++This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998
++
++
++Table of Contents:
++
++1. The idea of CVF-FAT
++2. Restrictions
++3. Mount options
++4. Description of the CVF-FAT interface
++5. CVF Modules
++
++------------------------------------------------------------------------------
++
++
++1. The idea of CVF-FAT
++------------------------------------------------------------------------------
++
++CVF-FAT is a FAT filesystem extension that provides a generic interface for
++Compressed Volume Files in FAT partitions. Popular CVF software, for
++example, are Microsoft's Doublespace/Drivespace and Stac's Stacker.
++Using the CVF-FAT interface, it is possible to load a module that handles
++all the low-level disk access that has to do with on-the-fly compression
++and decompression. Any other part of FAT filesystem access is still handled
++by the FAT, MSDOS or VFAT or even UMSDOS driver.
++
++CVF access works by redirecting certain low-level routines from the FAT
++driver to a loadable, CVF-format specific module. This module must fake
++a normal FAT filesystem to the FAT driver while doing all the extra stuff
++like compression and decompression silently.
++
++
++2. Restrictions
++------------------------------------------------------------------------------
++
++- BMAP problems
++
++ CVF filesystems cannot do bmap. It's impossible in principle. Thus
++ all actions that require bmap do not work (swapping, writable mmapping).
++ Read-only mmapping works because the FAT driver has a hack for this
++ situation :) Well, writable mmapping should now work using the readpage
++ interface function which has been hacked into the FAT driver just for
++ CVF-FAT :)
++
++- attention, DOSEmu users
++
++ You may have to unmount all CVF partitions before running DOSEmu depending
++ on your configuration. If DOSEmu is configured to use wholedisk or
++ partition access (this is often the case to let DOSEmu access
++ compressed partitions) there's a risk of destroying your compressed
++ partitions or crashing your system because of confused drivers.
++
++ Note that it is always safe to redirect the compressed partitions with
++ lredir or emufs.sys. Refer to the DOSEmu documentation for details.
++
++
++3. Mount options
++------------------------------------------------------------------------------
++
++The CVF-FAT extension currently adds the following options to the FAT
++driver's standard options:
++
++ cvf_format=xxx
++ Forces the driver to use the CVF module "xxx" instead of auto-detection.
++ Without this option, the CVF-FAT interface asks all currently loaded
++ CVF modules whether they recognize the CVF. Therefore, this option is
++ only necessary if the CVF format is not recognized correctly
++ because of bugs or incompatibilities in the CVF modules. (It skips
++ the detect_cvf call.) "xxx" may be the text "none" (without the quotes)
++ to inhibit using any of the loaded CVF modules, just in case a CVF
++ module insists on mounting plain FAT filesystems by misunderstanding.
++ "xxx" may also be the text "autoload", which has a special meaning for
++ kerneld, but does not skip auto-detection.
++
++ If the kernel supports kerneld, the cvf_format=xxx option also controls
++ on-demand CVF module loading. Without this option, nothing is loaded
++ on demand. With cvf_format=xxx, a module "xxx" is requested automatically
++ before mounting the compressed filesystem (unless "xxx" is "none"). In
++ case there is a difference between the CVF format name and the module
++ name, setup aliases in your kerneld configuration. If the string "xxx"
++ is "autoload", a non-existent module "cvf_autoload" is requested which
++ can be used together with a special kerneld configuration (alias and
++ pre-install statements) in order to load more than one CVF module, let
++ them detect automatically which kind of CVF is to be mounted, and only
++ keep the "right" module in memory. For examples please refer to the
++ dmsdos documentation (ftp and http addresses see below).
++
++ cvf_options=yyy
++ Option string passed to the CVF module. I.e. only the "yyy" is passed
++ (without the quotes). The documentation for each CVF module should
++ explain it since it is interpreted only by the CVF module. Note that
++ the string must not contain a comma (",") - this would lead to
++ misinterpretation by the FAT driver, which would recognize the text
++ after a comma as a FAT driver option and might get confused or print
++ strange error messages. The documentation for the CVF module should
++ offer a different separation symbol, for example the dot "." or the
++ plus sign "+", which is only valid inside the string "yyy".
++
++
++4. Description of the CVF-FAT interface
++------------------------------------------------------------------------------
++
++Assuming you want to write your own CVF module, you need to write a lot of
++interface functions. Most of them are covered in the kernel documentation
++you can find on the net, and thus won't be described here. They have been
++marked with "[...]" :-) Take a look at include/linux/fat_cvf.h.
++
++struct cvf_format
++{ int cvf_version;
++ char* cvf_version_text;
++ unsigned long int flags;
++ int (*detect_cvf) (struct super_block*sb);
++ int (*mount_cvf) (struct super_block*sb,char*options);
++ int (*unmount_cvf) (struct super_block*sb);
++ [...]
++ void (*cvf_zero_cluster) (struct inode*inode,int clusternr);
++}
++
++This structure defines the capabilities of a CVF module. It must be filled
++out completely by a CVF module. Consider it as a kind of form that is used
++to introduce the module to the FAT/CVF-FAT driver.
++
++It contains...
++ - cvf_version:
++ A version id which must be unique. Choose one.
++ - cvf_version_text:
++ A human readable version string that should be one short word
++ describing the CVF format the module implements. This text is used
++ for the cvf_format option. This name must also be unique.
++ - flags:
++ Bit coded flags, currently only used for a readpage/mmap hack that
++ provides both mmap and readpage functionality. If CVF_USE_READPAGE
++ is set, mmap is set to generic_file_mmap and readpage is caught
++ and redirected to the cvf_readpage function. If it is not set,
++ readpage is set to generic_readpage and mmap is caught and redirected
++ to cvf_mmap. (If you want writable mmap use the readpage interface.)
++ - detect_cvf:
++ A function that is called to decide whether the filesystem is a CVF of
++ the type the module supports. The detect_cvf function must return 0
++ for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS
++ THE KIND OF CVF I SUPPORT". The function must maintain the module
++ usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
++ and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
++ successful recongition would lead to a call of the mount_cvf function
++ later.
++ - mount_cvf:
++ A function that sets up some values or initializes something additional
++ to what has to be done when a CVF is mounted. This is called at the
++ end of fat_read_super and must return 0 on success. Definitely, this
++ function must increment the module usage counter by MOD_INC_USE_COUNT.
++ This mount_cvf function is also responsible for interpreting a CVF
++ module specific option string (the "yyy" from the FAT mount option
++ "cvf_options=yyy") which cannot contain a comma (use for example the
++ dot "." as option separator symbol).
++ - unmount_cvf:
++ A function that is called when the filesystem is unmounted. Most likely
++ it only frees up some memory and calls MOD_DEC_USE_COUNT. The return
++ value might be ignored (it currently is ignored).
++ - [...]:
++ All other interface functions are "caught" FAT driver functions, i.e.
++ are executed by the FAT driver *instead* of the original FAT driver
++ functions. NULL means use the original FAT driver functions instead.
++ If you really want "no action", write a function that does nothing and
++ hang it in instead.
++ - cvf_zero_cluster:
++ The cvf_zero_cluster function is called when the fat driver wants to
++ zero out a (new) cluster. This is important for directories (mkdir).
++ If it is NULL, the FAT driver defaults to overwriting the whole
++ cluster with zeros. Note that clusternr is absolute, not relative
++ to the provided inode.
++
++Notes:
++ 1. The cvf_bmap function should be ignored. It really should never
++ get called from somewhere. I recommend redirecting it to a panic
++ or fatal error message so bugs show up immediately.
++ 2. The cvf_writepage function is ignored. This is because the fat
++ driver doesn't support it. This might change in future. I recommend
++ setting it to NULL (i.e use default).
++
++int register_cvf_format(struct cvf_format*cvf_format);
++ If you have just set up a variable containing the above structure,
++ call this function to introduce your CVF format to the FAT/CVF-FAT
++ driver. This is usually done in init_module. Be sure to check the
++ return value. Zero means success, everything else causes a kernel
++ message printed in the syslog describing the error that occurred.
++ Typical errors are:
++ - a module with the same version id is already registered or
++ - too many CVF formats. Hack fs/fat/cvf.c if you need more.
++
++int unregister_cvf_format(struct cvf_format*cvf_format);
++ This is usually called in cleanup_module. Return value =0 means
++ success. An error only occurs if you try to unregister a CVF format
++ that has not been previously registered. The code uses the version id
++ to distinguish the modules, so be sure to keep it unique.
++
++5. CVF Modules
++------------------------------------------------------------------------------
++
++Refer to the dmsdos module (the successor of the dmsdos filesystem) for a
++sample implementation. It can currently be found at
++
++ ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz
++ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz
++ ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz
++
++(where x.y.z is to be replaced with the actual version number). Full
++documentation about dmsdos is included in the dmsdos package, but can also
++be found at
++
++ http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html
++ http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese).
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/Makefile linux-2.0.33-cyrix-patched-fat32-test/fs/fat/Makefile
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/Makefile Wed Feb 7 08:39:27 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/Makefile Sun Jan 4 11:59:56 1998
+@@ -8,7 +8,7 @@
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+
+ O_TARGET := fat.o
+-O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o
++O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o cvf.o
+ OX_OBJS := fatfs_syms.o
+ M_OBJS := $(O_TARGET)
+
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/buffer.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/buffer.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/buffer.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/buffer.c Sun Jan 4 12:07:19 1998
+@@ -9,6 +9,7 @@
+ #include <linux/string.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
++#include <linux/fat_cvf.h>
+
+ #if 0
+ # define PRINTK(x) printk x
+@@ -26,6 +27,11 @@
+ /* Note that the blocksize is 512 or 1024, but the first read
+ is always of size 1024. Doing readahead may be counterproductive
+ or just plain wrong. */
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_bread)
++ return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
++
+ if (sb->s_blocksize == 512) {
+ ret = bread (sb->s_dev,block,512);
+ } else {
+@@ -81,6 +87,11 @@
+ {
+ struct buffer_head *ret = NULL;
+ PRINTK(("fat_getblk: block=0x%x\n", block));
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_getblk)
++ return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
++
+ if (sb->s_blocksize == 512){
+ ret = getblk (sb->s_dev,block,512);
+ }else{
+@@ -100,6 +111,10 @@
+ struct buffer_head *bh)
+ {
+ if (bh != NULL){
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_brelse)
++ return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
++
+ if (sb->s_blocksize == 512){
+ brelse (bh);
+ }else{
+@@ -117,6 +132,12 @@
+ struct buffer_head *bh,
+ int dirty_val)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty)
++ { MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty_val);
++ return;
++ }
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -128,6 +149,12 @@
+ struct buffer_head *bh,
+ int val)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_set_uptodate)
++ { MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
++ return;
++ }
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -137,6 +164,10 @@
+ struct super_block *sb,
+ struct buffer_head *bh)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
++ return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
++
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+@@ -149,6 +180,12 @@
+ int nbreq,
+ struct buffer_head *bh[32])
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block)
++ { MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
++ return;
++ }
++
+ if (sb->s_blocksize == 512){
+ ll_rw_block(opr,nbreq,bh);
+ }else{
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/cache.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cache.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/cache.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cache.c Sun Jan 4 12:08:48 1998
+@@ -9,6 +9,7 @@
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/stat.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -29,6 +30,10 @@
+ unsigned char *p_first,*p_last;
+ int copy,first,last,next,b;
+
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->fat_access)
++ return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
++
+ if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
+ return 0;
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+@@ -261,6 +266,10 @@
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
++ if(sb->cvf_format)
++ if(sb->cvf_format->cvf_smap)
++ return sb->cvf_format->cvf_smap(inode,sector);
++
+ if ((sb->fat_bits != 32) &&
+ (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
+ !MSDOS_I(inode)->i_start))) {
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/cvf.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cvf.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/cvf.c Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/cvf.c Tue Nov 17 20:10:41 1998
+@@ -0,0 +1,147 @@
++/*
++ * CVF extensions for fat-based filesystems
++ *
++ * written 1997,1998 by Frank Gockel <[email protected]>
++ *
++ * please do not remove the next line, dmsdos needs it for verifying patches
++ * CVF-FAT-VERSION-ID: 1.1.0
++ *
++ */
++
++#include<linux/sched.h>
++#include<linux/fs.h>
++#include<linux/msdos_fs.h>
++#include<linux/msdos_fs_sb.h>
++#include<linux/string.h>
++#include<linux/fat_cvf.h>
++#include<linux/config.h>
++#ifdef CONFIG_KERNELD
++#include<linux/kerneld.h>
++#endif
++
++#define MAX_CVF_FORMATS 3
++
++struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
++int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
++
++int register_cvf_format(struct cvf_format*cvf_format)
++{ int i,j;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i]==NULL)
++ { /* free slot found, now check version */
++ for(j=0;j<MAX_CVF_FORMATS;++j)
++ { if(cvf_formats[j])
++ { if(cvf_formats[j]->cvf_version==cvf_format->cvf_version)
++ { printk("register_cvf_format: version %d already registered\n",
++ cvf_format->cvf_version);
++ return -1;
++ }
++ }
++ }
++ cvf_formats[i]=cvf_format;
++ cvf_format_use_count[i]=0;
++ printk("CVF format %s (version id %d) successfully registered.\n",
++ cvf_format->cvf_version_text,cvf_format->cvf_version);
++ return 0;
++ }
++ }
++
++ printk("register_cvf_format: too many formats\n");
++ return -1;
++}
++
++int unregister_cvf_format(struct cvf_format*cvf_format)
++{ int i;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->cvf_version==cvf_format->cvf_version)
++ { if(cvf_format_use_count[i])
++ { printk("unregister_cvf_format: format %d in use, cannot remove!\n",
++ cvf_formats[i]->cvf_version);
++ return -1;
++ }
++
++ printk("CVF format %s (version id %d) successfully unregistered.\n",
++ cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version);
++ cvf_formats[i]=NULL;
++ return 0;
++ }
++ }
++ }
++
++ printk("unregister_cvf_format: format %d is not registered\n",
++ cvf_format->cvf_version);
++ return -1;
++}
++
++void dec_cvf_format_use_count_by_version(int version)
++{ int i;
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->cvf_version==version)
++ { --cvf_format_use_count[i];
++ if(cvf_format_use_count[i]<0)
++ { cvf_format_use_count[i]=0;
++ printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n");
++ }
++ return;
++ }
++ }
++ }
++
++ printk("dec_cvf_format_use_count_by_version: version %d not found ???\n",
++ version);
++}
++
++int detect_cvf(struct super_block*sb,char*force)
++{ int i;
++ int found=0;
++ int found_i=-1;
++
++ if(force)
++ if(strcmp(force,"autoload")==0)
++ {
++#ifdef CONFIG_KERNELD
++ request_module("cvf_autoload");
++ force=NULL;
++#else
++ printk("cannot autoload CVF modules: kerneld support is not compiled into kernel\n");
++ return -1;
++#endif
++ }
++
++#ifdef CONFIG_KERNELD
++ if(force)
++ if(*force)
++ request_module(force);
++#endif
++
++ if(force)
++ { if(*force)
++ { for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
++ return i;
++ }
++ }
++ printk("CVF format %s unknown (module not loaded?)\n",force);
++ return -1;
++ }
++ }
++
++ for(i=0;i<MAX_CVF_FORMATS;++i)
++ { if(cvf_formats[i])
++ { if(cvf_formats[i]->detect_cvf(sb))
++ { ++found;
++ found_i=i;
++ }
++ }
++ }
++
++ if(found==1)return found_i;
++ if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
++ return -1;
++}
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/dir.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/dir.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/dir.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/dir.c Sun Jan 4 11:59:56 1998
+@@ -425,6 +425,7 @@
+ unsigned int cmd, unsigned long arg)
+ {
+ int err;
++
+ /*
+ * We want to provide an interface for Samba to be able
+ * to get the short filename for a given long filename.
+@@ -451,6 +452,11 @@
+ vfat_ioctl_fill, NULL, 1, 0, 1);
+ }
+ default:
++ /* forward ioctl to CVF extension */
++ if(MSDOS_SB(inode->i_sb)->cvf_format
++ &&MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
++ return MSDOS_SB(inode->i_sb)->cvf_format->
++ cvf_dir_ioctl(inode,filp,cmd,arg);
+ return -EINVAL;
+ }
+
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/fatfs_syms.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/fatfs_syms.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/fatfs_syms.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/fatfs_syms.c Sun Jan 4 12:11:10 1998
+@@ -11,6 +11,7 @@
+
+ #include <linux/mm.h>
+ #include <linux/msdos_fs.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -53,6 +54,13 @@
+ X(fat_uni2esc) X_PUNCT
+ X(fat_unlock_creation) X_PUNCT
+ X(fat_write_inode) X_PUNCT
++X(register_cvf_format) X_PUNCT
++X(unregister_cvf_format) X_PUNCT
++X(get_cluster) X_PUNCT
++X(lock_fat) X_PUNCT
++X(unlock_fat) X_PUNCT
++X(fat_readpage) X_PUNCT
++X(fat_dir_ioctl) X_PUNCT
+ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+ #include <linux/symtab_end.h>
+ };
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/file.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/file.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/file.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/file.c Sun Jan 4 11:59:56 1998
+@@ -17,6 +17,7 @@
+ #include <linux/stat.h>
+ #include <linux/string.h>
+ #include <linux/pagemap.h>
++#include <linux/fat_cvf.h>
+
+ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
+ #include <asm/uaccess.h>
+@@ -121,6 +122,40 @@
+ NULL /* smap */
+ };
+
++static struct file_operations fat_file_operations_readpage = {
++ NULL, /* lseek - default */
++ fat_file_read, /* read */
++ fat_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations fat_file_inode_operations_readpage = {
++ &fat_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ fat_truncate, /* truncate */
++ NULL, /* permission */
++ NULL /* smap */
++};
++
+ #define MSDOS_PREFETCH 32
+ struct fat_pre {
+ int file_sector;/* Next sector to read in the prefetch table */
+@@ -183,6 +218,10 @@
+ printk("fat_file_read: inode = NULL\n");
+ return -EINVAL;
+ }
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_file_read)
++ return MSDOS_SB(sb)->cvf_format->cvf_file_read(inode,filp,buf,count);
++
+ /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
+ printk("fat_file_read: mode = %07o\n",inode->i_mode);
+@@ -305,6 +344,10 @@
+ printk("fat_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_file_write)
++ return MSDOS_SB(sb)->cvf_format->cvf_file_write(inode,filp,buf,count);
++
+ /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
+ printk("fat_file_write: mode = %07o\n",inode->i_mode);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/inode.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/inode.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/inode.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/inode.c Sun Jan 4 12:31:18 1998
+@@ -22,6 +22,7 @@
+ #include <linux/stat.h>
+ #include <linux/locks.h>
+ #include <linux/malloc.h>
++#include <linux/fat_cvf.h>
+
+ #include "msbuffer.h"
+
+@@ -88,6 +89,10 @@
+
+ void fat_put_super(struct super_block *sb)
+ {
++ if(MSDOS_SB(sb)->cvf_format)
++ { dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
++ MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
++ }
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ fat_clusters_flush(sb);
+ }
+@@ -113,7 +118,8 @@
+
+
+ static int parse_options(char *options,int *fat, int *blksize, int *debug,
+- struct fat_mount_options *opts)
++ struct fat_mount_options *opts,
++ char* cvf_format, char*cvf_options)
+ {
+ char *this_char,*value,save,*savep;
+ char *p;
+@@ -239,6 +245,16 @@
+ ret = 0;
+ }
+ }
++ else if (!strcmp(this_char,"cvf_format")) {
++ if (!value)
++ return 0;
++ strncpy(cvf_format,value,20);
++ }
++ else if (!strcmp(this_char,"cvf_options")) {
++ if (!value)
++ return 0;
++ strncpy(cvf_options,value,100);
++ }
+
+ if (this_char != options) *(this_char-1) = ',';
+ if (value) *savep = save;
+@@ -261,6 +277,14 @@
+ struct fat_mount_options opts;
+ char buf[50];
+ char *p;
++ int i;
++ char cvf_format[21];
++ char cvf_options[101];
++
++ cvf_format[0]='\0';
++ cvf_options[0]='\0';
++ MSDOS_SB(sb)->cvf_format=NULL;
++ MSDOS_SB(sb)->private_data=NULL;
+
+ MOD_INC_USE_COUNT;
+ if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
+@@ -270,7 +294,8 @@
+ }
+ }
+ opts.isvfat = MSDOS_SB(sb)->options.isvfat;
+- if (!parse_options((char *) data, &fat, &blksize, &debug, &opts)
++ if (!parse_options((char *) data, &fat, &blksize, &debug, &opts,
++ cvf_format, cvf_options)
+ || (blksize != 512 && blksize != 1024)) {
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+@@ -375,6 +400,9 @@
+ /* because clusters (DOS) are often aligned */
+ /* on odd sectors. */
+ sb->s_blocksize_bits = blksize == 512 ? 9 : 10;
++ if(!strcmp(cvf_format,"none"))i=-1;
++ else i=detect_cvf(sb,cvf_format);
++ if(i>=0)error=cvf_formats[i]->mount_cvf(sb,cvf_options);
+ if (error || debug) {
+ /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
+ printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
+@@ -392,13 +420,15 @@
+ MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters);
+ printk ("Transaction block size = %d\n",blksize);
+ }
+- if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
++ if(i<0) if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
+ MSDOS_SB(sb)->clusters = fat_clusters-2;
+ if (error) {
+ if (!silent)
+ printk("VFS: Can't find a valid MSDOS filesystem on dev "
+ "%s.\n", kdevname(sb->s_dev));
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+@@ -419,6 +449,8 @@
+ MSDOS_SB(sb)->nls_disk = load_nls_default();
+ } else {
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+@@ -433,6 +465,8 @@
+ kfree(opts.iocharset);
+ unload_nls(MSDOS_SB(sb)->nls_disk);
+ sb->s_dev = 0;
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ } else {
+@@ -447,9 +481,16 @@
+ unload_nls(MSDOS_SB(sb)->nls_disk);
+ if (MSDOS_SB(sb)->nls_io) unload_nls(MSDOS_SB(sb)->nls_io);
+ if (opts.iocharset) kfree(opts.iocharset);
++ if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
++ MSDOS_SB(sb)->private_data=NULL;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
++
++ if(i>=0)
++ { MSDOS_SB(sb)->cvf_format=cvf_formats[i];
++ ++cvf_format_use_count[i];
++ }
+
+ return sb;
+ }
+@@ -459,7 +500,13 @@
+ {
+ int free,nr;
+ struct statfs tmp;
+-
++
++ if(MSDOS_SB(sb)->cvf_format)
++ if(MSDOS_SB(sb)->cvf_format->cvf_statfs)
++ { MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz);
++ return;
++ }
++
+ lock_fat(sb);
+ if (MSDOS_SB(sb)->free_clusters != -1)
+ free = MSDOS_SB(sb)->free_clusters;
+@@ -488,6 +535,10 @@
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
++ if(sb->cvf_format)
++ if(sb->cvf_format->cvf_bmap)
++ return sb->cvf_format->cvf_bmap(inode,block);
++
+ if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
+ return sb->dir_start + block;
+ }
+@@ -600,7 +651,12 @@
+ !is_exec(raw_entry->ext)))
+ ? S_IRUGO|S_IWUGO : S_IRWXUGO)
+ & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
+- inode->i_op = (sb->s_blocksize == 1024)
++ if(MSDOS_SB(sb)->cvf_format)
++ inode->i_op = (MSDOS_SB(sb)->cvf_format->flags&CVF_USE_READPAGE)
++ ? &fat_file_inode_operations_readpage
++ : &fat_file_inode_operations_1024;
++ else
++ inode->i_op = (sb->s_blocksize == 1024)
+ ? &fat_file_inode_operations_1024
+ : &fat_file_inode_operations;
+ MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/misc.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/misc.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/misc.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/misc.c Sun Jan 4 11:59:56 1998
+@@ -225,6 +225,10 @@
+ #endif
+ sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size;
+ last_sector = sector + cluster_size;
++ if(MSDOS_SB(sb)->cvf_format&&
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster)
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr);
++ else
+ for ( ; sector < last_sector; sector++) {
+ #ifdef DEBUG
+ printk("zeroing sector %d\n",sector);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/fat/mmap.c linux-2.0.33-cyrix-patched-fat32-test/fs/fat/mmap.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/fat/mmap.c Sun Jan 4 11:55:32 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/fat/mmap.c Sun Jan 4 11:59:56 1998
+@@ -100,6 +100,9 @@
+ */
+ int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+ {
++ if(MSDOS_SB(inode->i_sb)->cvf_format)
++ if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap)
++ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap(inode,file,vma);
+ if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
+ return -EINVAL;
+ if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+@@ -117,4 +120,12 @@
+ return 0;
+ }
+
++int fat_readpage(struct inode * inode, struct page * page)
++{
++ if(MSDOS_SB(inode->i_sb)->cvf_format)
++ if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage)
++ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page);
+
++ printk("fat_readpage called with no handler (shouldn't happen)\n");
++ return -1;
++}
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/emd.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/emd.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/emd.c Wed Feb 7 08:39:29 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/emd.c Sun Jan 4 11:59:56 1998
+@@ -32,6 +32,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_read(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+@@ -48,6 +49,7 @@
+ int ret;
+ int old_fs = get_fs();
+ set_fs (KERNEL_DS);
++ MSDOS_I(inode)->i_binary=2;
+ ret = fat_file_write(inode,filp,buf,count);
+ set_fs (old_fs);
+ return ret;
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/file.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/file.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/file.c Tue Feb 20 09:28:13 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/file.c Sun Jan 4 11:59:56 1998
+@@ -129,3 +129,38 @@
+ NULL, /* smap */
+ };
+
++/* For other with larger and unaligned file system with readpage */
++struct file_operations umsdos_file_operations_readpage = {
++ NULL, /* lseek - default */
++ UMSDOS_file_read, /* read */
++ UMSDOS_file_write, /* write */
++ NULL, /* readdir - bad */
++ NULL, /* select - default */
++ NULL, /* ioctl - default */
++ generic_file_mmap, /* mmap */
++ NULL, /* no special open is needed */
++ NULL, /* release */
++ file_fsync /* fsync */
++};
++
++struct inode_operations umsdos_file_inode_operations_readpage = {
++ &umsdos_file_operations_readpage, /* default file operations */
++ NULL, /* create */
++ NULL, /* lookup */
++ NULL, /* link */
++ NULL, /* unlink */
++ NULL, /* symlink */
++ NULL, /* mkdir */
++ NULL, /* rmdir */
++ NULL, /* mknod */
++ NULL, /* rename */
++ NULL, /* readlink */
++ NULL, /* follow_link */
++ fat_readpage, /* readpage */
++ NULL, /* writepage */
++ NULL, /* bmap */
++ UMSDOS_truncate,/* truncate */
++ NULL, /* permission */
++ NULL, /* smap */
++};
++
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/inode.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/inode.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/inode.c Sat Nov 30 11:21:22 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/inode.c Sun Jan 4 11:59:56 1998
+@@ -149,11 +149,20 @@
+ if (!umsdos_isinit(inode)){
+ inode->u.umsdos_i.i_emd_dir = 0;
+ if (S_ISREG(inode->i_mode)){
++ if (MSDOS_SB(inode->i_sb)->cvf_format){
++ if (MSDOS_SB(inode->i_sb)->cvf_format->flags
++ &CVF_USE_READPAGE){
++ inode->i_op = &umsdos_file_inode_operations_readpage;
++ }else{
++ inode->i_op = &umsdos_file_inode_operations_no_bmap;
++ }
++ } else {
+ if (inode->i_op->bmap != NULL){
+ inode->i_op = &umsdos_file_inode_operations;
+ }else{
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
+ }
++ }
+ }else if (S_ISDIR(inode->i_mode)){
+ if (dir != NULL){
+ umsdos_setup_dir_inode(inode);
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/fs/umsdos/ioctl.c linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/ioctl.c
+--- linux-2.0.33-cyrix-patched-fat32/fs/umsdos/ioctl.c Wed Jul 3 15:39:48 1996
++++ linux-2.0.33-cyrix-patched-fat32-test/fs/umsdos/ioctl.c Sun Jan 4 11:59:56 1998
+@@ -60,6 +60,21 @@
+ {
+ int ret = -EPERM;
+ int err;
++
++ /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
++ if(cmd!=UMSDOS_GETVERSION
++ &&cmd!=UMSDOS_READDIR_DOS
++ &&cmd!=UMSDOS_READDIR_EMD
++ &&cmd!=UMSDOS_INIT_EMD
++ &&cmd!=UMSDOS_CREAT_EMD
++ &&cmd!=UMSDOS_RENAME_DOS
++ &&cmd!=UMSDOS_UNLINK_EMD
++ &&cmd!=UMSDOS_UNLINK_DOS
++ &&cmd!=UMSDOS_RMDIR_DOS
++ &&cmd!=UMSDOS_STAT_DOS
++ &&cmd!=UMSDOS_DOS_SETUP)
++ return fat_dir_ioctl(dir,filp,cmd,data);
++
+ /* #Specification: ioctl / acces
+ Only root (effective id) is allowed to do IOCTL on directory
+ in UMSDOS. EPERM is returned for other user.
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/fat_cvf.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/fat_cvf.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/fat_cvf.h Thu Jan 1 01:00:00 1970
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/fat_cvf.h Sun Jan 4 11:59:56 1998
+@@ -0,0 +1,55 @@
++#ifndef _FAT_CVF
++#define _FAT_CVF
++
++#define CVF_USE_READPAGE 0x0001
++
++struct cvf_format
++{ int cvf_version;
++ char* cvf_version_text;
++ unsigned long flags;
++ int (*detect_cvf) (struct super_block*sb);
++ int (*mount_cvf) (struct super_block*sb,char*options);
++ int (*unmount_cvf) (struct super_block*sb);
++ struct buffer_head* (*cvf_bread) (struct super_block*sb,int block);
++ struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block);
++ void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh);
++ void (*cvf_mark_buffer_dirty) (struct super_block *sb,
++ struct buffer_head *bh,
++ int dirty_val);
++ void (*cvf_set_uptodate) (struct super_block *sb,
++ struct buffer_head *bh,
++ int val);
++ int (*cvf_is_uptodate) (struct super_block *sb,struct buffer_head *bh);
++ void (*cvf_ll_rw_block) (struct super_block *sb,
++ int opr,
++ int nbreq,
++ struct buffer_head *bh[32]);
++ int (*fat_access) (struct super_block *sb,int nr,int new_value);
++ void (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
++ int (*cvf_bmap) (struct inode *inode,int block);
++ int (*cvf_smap) (struct inode *inode,int sector);
++ int (*cvf_file_read) ( struct inode *inode,
++ struct file *filp,
++ char *buf,
++ int count);
++ int (*cvf_file_write) ( struct inode *inode,
++ struct file *filp,
++ const char *buf,
++ int count);
++ int (*cvf_mmap) (struct inode*, struct file *, struct vm_area_struct *);
++ int (*cvf_readpage) (struct inode *, struct page *);
++ int (*cvf_writepage) (struct inode *, struct page *);
++ int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp,
++ unsigned int cmd, unsigned long arg);
++ void (*zero_out_cluster) (struct inode*, int clusternr);
++};
++
++int register_cvf_format(struct cvf_format*cvf_format);
++int unregister_cvf_format(struct cvf_format*cvf_format);
++void dec_cvf_format_use_count_by_version(int version);
++int detect_cvf(struct super_block*sb,char*force);
++
++extern struct cvf_format *cvf_formats[];
++extern int cvf_format_use_count[];
++
++#endif
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs.h Sun Jan 4 11:55:33 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs.h Sun Jan 4 12:40:48 1998
+@@ -246,12 +246,14 @@
+ /* file.c */
+ extern struct inode_operations fat_file_inode_operations;
+ extern struct inode_operations fat_file_inode_operations_1024;
++extern struct inode_operations fat_file_inode_operations_readpage;
+ extern int fat_file_read(struct inode *, struct file *, char *, int);
+ extern int fat_file_write(struct inode *, struct file *, const char *, int);
+ extern void fat_truncate(struct inode *inode);
+
+ /* mmap.c */
+ extern int fat_mmap(struct inode *, struct file *, struct vm_area_struct *);
++extern int fat_readpage(struct inode *, struct page *);
+
+
+ /* vfat.c */
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs_sb.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs_sb.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/msdos_fs_sb.h Sun Jan 4 11:55:33 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/msdos_fs_sb.h Sun Jan 4 12:02:05 1998
+@@ -1,5 +1,6 @@
+ #ifndef _MSDOS_FS_SB
+ #define _MSDOS_FS_SB
++#include<linux/fat_cvf.h>
+
+ /*
+ * MS-DOS file system in-core superblock data
+@@ -46,6 +47,8 @@
+ struct fat_mount_options options;
+ struct nls_table *nls_disk; /* Codepage used on disk */
+ struct nls_table *nls_io; /* Charset used for input and display */
++ struct cvf_format* cvf_format;
++ void* private_data;
+ };
+
+ #endif
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/include/linux/umsdos_fs.h linux-2.0.33-cyrix-patched-fat32-test/include/linux/umsdos_fs.h
+--- linux-2.0.33-cyrix-patched-fat32/include/linux/umsdos_fs.h Tue Dec 23 22:50:14 1997
++++ linux-2.0.33-cyrix-patched-fat32-test/include/linux/umsdos_fs.h Sun Jan 4 12:40:48 1998
+@@ -135,6 +135,7 @@
+ extern struct file_operations umsdos_file_operations;
+ extern struct inode_operations umsdos_file_inode_operations;
+ extern struct inode_operations umsdos_file_inode_operations_no_bmap;
++extern struct inode_operations umsdos_file_inode_operations_readpage;
+ extern struct inode_operations umsdos_symlink_inode_operations;
+ extern int init_umsdos_fs(void);
+
+diff -u -r -N linux-2.0.33-cyrix-patched-fat32/kernel/ksyms.c linux-2.0.33-cyrix-patched-fat32-test/kernel/ksyms.c
+--- linux-2.0.33-cyrix-patched-fat32/kernel/ksyms.c Sun Jan 4 11:55:33 1998
++++ linux-2.0.33-cyrix-patched-fat32-test/kernel/ksyms.c Sun Jan 4 11:59:56 1998
+@@ -124,6 +124,9 @@
+ X(do_mmap),
+ X(do_munmap),
+ X(exit_mm),
++ X(exit_sighand),
++ X(exit_fs),
++ X(exit_files),
+
+ /* internal kernel memory management */
+ X(__get_free_pages),
diff --git a/patches/fat-truncate-bugfix.diff b/patches/fat-truncate-bugfix.diff
new file mode 100644
index 0000000..f4967d9
--- /dev/null
+++ b/patches/fat-truncate-bugfix.diff
@@ -0,0 +1,13 @@
+--- linux/fs/fat/file.c.orig Thu Jan 7 18:38:59 1999
++++ linux/fs/fat/file.c Thu Jan 7 19:17:40 1999
+@@ -442,6 +442,10 @@
+ /* Why no return value? Surely the disk could fail... */
+ if (IS_IMMUTABLE(inode))
+ return /* -EPERM */;
++ if(inode->i_sb->s_flags&MS_RDONLY) {
++ printk("FAT: fat_truncate called though fs is read-only, uhh...\n");
++ return /* -EROFS */;
++ }
+ cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+ (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
diff --git a/patches/fat_cvf.txt b/patches/fat_cvf.txt
new file mode 100644
index 0000000..4ddcf3e
--- /dev/null
+++ b/patches/fat_cvf.txt
@@ -0,0 +1,210 @@
+This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998
+
+
+Table of Contents:
+
+1. The idea of CVF-FAT
+2. Restrictions
+3. Mount options
+4. Description of the CVF-FAT interface
+5. CVF Modules
+
+------------------------------------------------------------------------------
+
+
+1. The idea of CVF-FAT
+------------------------------------------------------------------------------
+
+CVF-FAT is a FAT filesystem extension that provides a generic interface for
+Compressed Volume Files in FAT partitions. Popular CVF software, for
+example, are Microsoft's Doublespace/Drivespace and Stac's Stacker.
+Using the CVF-FAT interface, it is possible to load a module that handles
+all the low-level disk access that has to do with on-the-fly compression
+and decompression. Any other part of FAT filesystem access is still handled
+by the FAT, MSDOS or VFAT or even UMSDOS driver.
+
+CVF access works by redirecting certain low-level routines from the FAT
+driver to a loadable, CVF-format specific module. This module must fake
+a normal FAT filesystem to the FAT driver while doing all the extra stuff
+like compression and decompression silently.
+
+
+2. Restrictions
+------------------------------------------------------------------------------
+
+- BMAP problems
+
+ CVF filesystems cannot do bmap. It's impossible in principle. Thus
+ all actions that require bmap do not work (swapping, writable mmapping).
+ Read-only mmapping works because the FAT driver has a hack for this
+ situation :) Well, writable mmapping should now work using the readpage
+ interface function which has been hacked into the FAT driver just for
+ CVF-FAT :)
+
+- attention, DOSEmu users
+
+ You may have to unmount all CVF partitions before running DOSEmu depending
+ on your configuration. If DOSEmu is configured to use wholedisk or
+ partition access (this is often the case to let DOSEmu access
+ compressed partitions) there's a risk of destroying your compressed
+ partitions or crashing your system because of confused drivers.
+
+ Note that it is always safe to redirect the compressed partitions with
+ lredir or emufs.sys. Refer to the DOSEmu documentation for details.
+
+
+3. Mount options
+------------------------------------------------------------------------------
+
+The CVF-FAT extension currently adds the following options to the FAT
+driver's standard options:
+
+ cvf_format=xxx
+ Forces the driver to use the CVF module "xxx" instead of auto-detection.
+ Without this option, the CVF-FAT interface asks all currently loaded
+ CVF modules whether they recognize the CVF. Therefore, this option is
+ only necessary if the CVF format is not recognized correctly
+ because of bugs or incompatibilities in the CVF modules. (It skips
+ the detect_cvf call.) "xxx" may be the text "none" (without the quotes)
+ to inhibit using any of the loaded CVF modules, just in case a CVF
+ module insists on mounting plain FAT filesystems by misunderstanding.
+ "xxx" may also be the text "autoload", which has a special meaning for
+ kerneld, but does not skip auto-detection.
+
+ If the kernel supports kerneld, the cvf_format=xxx option also controls
+ on-demand CVF module loading. Without this option, nothing is loaded
+ on demand. With cvf_format=xxx, a module "xxx" is requested automatically
+ before mounting the compressed filesystem (unless "xxx" is "none"). In
+ case there is a difference between the CVF format name and the module
+ name, setup aliases in your kerneld configuration. If the string "xxx"
+ is "autoload", a non-existent module "cvf_autoload" is requested which
+ can be used together with a special kerneld configuration (alias and
+ pre-install statements) in order to load more than one CVF module, let
+ them detect automatically which kind of CVF is to be mounted, and only
+ keep the "right" module in memory. For examples please refer to the
+ dmsdos documentation (ftp and http addresses see below).
+
+ cvf_options=yyy
+ Option string passed to the CVF module. I.e. only the "yyy" is passed
+ (without the quotes). The documentation for each CVF module should
+ explain it since it is interpreted only by the CVF module. Note that
+ the string must not contain a comma (",") - this would lead to
+ misinterpretation by the FAT driver, which would recognize the text
+ after a comma as a FAT driver option and might get confused or print
+ strange error messages. The documentation for the CVF module should
+ offer a different separation symbol, for example the dot "." or the
+ plus sign "+", which is only valid inside the string "yyy".
+
+
+4. Description of the CVF-FAT interface
+------------------------------------------------------------------------------
+
+Assuming you want to write your own CVF module, you need to write a lot of
+interface functions. Most of them are covered in the kernel documentation
+you can find on the net, and thus won't be described here. They have been
+marked with "[...]" :-) Take a look at include/linux/fat_cvf.h.
+
+struct cvf_format
+{ int cvf_version;
+ char* cvf_version_text;
+ unsigned long int flags;
+ int (*detect_cvf) (struct super_block*sb);
+ int (*mount_cvf) (struct super_block*sb,char*options);
+ int (*unmount_cvf) (struct super_block*sb);
+ [...]
+ void (*cvf_zero_cluster) (struct inode*inode,int clusternr);
+}
+
+This structure defines the capabilities of a CVF module. It must be filled
+out completely by a CVF module. Consider it as a kind of form that is used
+to introduce the module to the FAT/CVF-FAT driver.
+
+It contains...
+ - cvf_version:
+ A version id which must be unique. Choose one.
+ - cvf_version_text:
+ A human readable version string that should be one short word
+ describing the CVF format the module implements. This text is used
+ for the cvf_format option. This name must also be unique.
+ - flags:
+ Bit coded flags, currently only used for a readpage/mmap hack that
+ provides both mmap and readpage functionality. If CVF_USE_READPAGE
+ is set, mmap is set to generic_file_mmap and readpage is caught
+ and redirected to the cvf_readpage function. If it is not set,
+ readpage is set to generic_readpage and mmap is caught and redirected
+ to cvf_mmap. (If you want writable mmap use the readpage interface.)
+ - detect_cvf:
+ A function that is called to decide whether the filesystem is a CVF of
+ the type the module supports. The detect_cvf function must return 0
+ for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS
+ THE KIND OF CVF I SUPPORT". The function must maintain the module
+ usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
+ and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
+ successful recongition would lead to a call of the mount_cvf function
+ later.
+ - mount_cvf:
+ A function that sets up some values or initializes something additional
+ to what has to be done when a CVF is mounted. This is called at the
+ end of fat_read_super and must return 0 on success. Definitely, this
+ function must increment the module usage counter by MOD_INC_USE_COUNT.
+ This mount_cvf function is also responsible for interpreting a CVF
+ module specific option string (the "yyy" from the FAT mount option
+ "cvf_options=yyy") which cannot contain a comma (use for example the
+ dot "." as option separator symbol).
+ - unmount_cvf:
+ A function that is called when the filesystem is unmounted. Most likely
+ it only frees up some memory and calls MOD_DEC_USE_COUNT. The return
+ value might be ignored (it currently is ignored).
+ - [...]:
+ All other interface functions are "caught" FAT driver functions, i.e.
+ are executed by the FAT driver *instead* of the original FAT driver
+ functions. NULL means use the original FAT driver functions instead.
+ If you really want "no action", write a function that does nothing and
+ hang it in instead.
+ - cvf_zero_cluster:
+ The cvf_zero_cluster function is called when the fat driver wants to
+ zero out a (new) cluster. This is important for directories (mkdir).
+ If it is NULL, the FAT driver defaults to overwriting the whole
+ cluster with zeros. Note that clusternr is absolute, not relative
+ to the provided inode.
+
+Notes:
+ 1. The cvf_bmap function should be ignored. It really should never
+ get called from somewhere. I recommend redirecting it to a panic
+ or fatal error message so bugs show up immediately.
+ 2. The cvf_writepage function is ignored. This is because the fat
+ driver doesn't support it. This might change in future. I recommend
+ setting it to NULL (i.e use default).
+
+int register_cvf_format(struct cvf_format*cvf_format);
+ If you have just set up a variable containing the above structure,
+ call this function to introduce your CVF format to the FAT/CVF-FAT
+ driver. This is usually done in init_module. Be sure to check the
+ return value. Zero means success, everything else causes a kernel
+ message printed in the syslog describing the error that occurred.
+ Typical errors are:
+ - a module with the same version id is already registered or
+ - too many CVF formats. Hack fs/fat/cvf.c if you need more.
+
+int unregister_cvf_format(struct cvf_format*cvf_format);
+ This is usually called in cleanup_module. Return value =0 means
+ success. An error only occurs if you try to unregister a CVF format
+ that has not been previously registered. The code uses the version id
+ to distinguish the modules, so be sure to keep it unique.
+
+5. CVF Modules
+------------------------------------------------------------------------------
+
+Refer to the dmsdos module (the successor of the dmsdos filesystem) for a
+sample implementation. It can currently be found at
+
+ ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz
+ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz
+ ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz
+
+(where x.y.z is to be replaced with the actual version number). Full
+documentation about dmsdos is included in the dmsdos package, but can also
+be found at
+
+ http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html
+ http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese).
diff --git a/patches/fat_cvf.txt-2.1.128 b/patches/fat_cvf.txt-2.1.128
new file mode 100644
index 0000000..c1cf27b
--- /dev/null
+++ b/patches/fat_cvf.txt-2.1.128
@@ -0,0 +1,210 @@
+This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998
+
+
+Table of Contents:
+
+1. The idea of CVF-FAT
+2. Restrictions
+3. Mount options
+4. Description of the CVF-FAT interface
+5. CVF Modules
+
+------------------------------------------------------------------------------
+
+
+1. The idea of CVF-FAT
+------------------------------------------------------------------------------
+
+CVF-FAT is a FAT filesystem extension that provides a generic interface for
+Compressed Volume Files in FAT partitions. Popular CVF software, for
+example, are Microsoft's Doublespace/Drivespace and Stac's Stacker.
+Using the CVF-FAT interface, it is possible to load a module that handles
+all the low-level disk access that has to do with on-the-fly compression
+and decompression. Any other part of FAT filesystem access is still handled
+by the FAT, MSDOS or VFAT or even UMSDOS driver.
+
+CVF access works by redirecting certain low-level routines from the FAT
+driver to a loadable, CVF-format specific module. This module must fake
+a normal FAT filesystem to the FAT driver while doing all the extra stuff
+like compression and decompression silently.
+
+
+2. Restrictions
+------------------------------------------------------------------------------
+
+- BMAP problems
+
+ CVF filesystems cannot do bmap. It's impossible in principle. Thus
+ all actions that require bmap do not work (swapping, writable mmapping).
+ Read-only mmapping works because the FAT driver has a hack for this
+ situation :) Well, writable mmapping should now work using the readpage
+ interface function which has been hacked into the FAT driver just for
+ CVF-FAT :)
+
+- attention, DOSEmu users
+
+ You may have to unmount all CVF partitions before running DOSEmu depending
+ on your configuration. If DOSEmu is configured to use wholedisk or
+ partition access (this is often the case to let DOSEmu access
+ compressed partitions) there's a risk of destroying your compressed
+ partitions or crashing your system because of confused drivers.
+
+ Note that it is always safe to redirect the compressed partitions with
+ lredir or emufs.sys. Refer to the DOSEmu documentation for details.
+
+
+3. Mount options
+------------------------------------------------------------------------------
+
+The CVF-FAT extension currently adds the following options to the FAT
+driver's standard options:
+
+ cvf_format=xxx
+ Forces the driver to use the CVF module "xxx" instead of auto-detection.
+ Without this option, the CVF-FAT interface asks all currently loaded
+ CVF modules whether they recognize the CVF. Therefore, this option is
+ only necessary if the CVF format is not recognized correctly
+ because of bugs or incompatibilities in the CVF modules. (It skips
+ the detect_cvf call.) "xxx" may be the text "none" (without the quotes)
+ to inhibit using any of the loaded CVF modules, just in case a CVF
+ module insists on mounting plain FAT filesystems by misunderstanding.
+ "xxx" may also be the text "autoload", which has a special meaning for
+ a module loader, but does not skip auto-detection.
+
+ If the kernel supports kmod, the cvf_format=xxx option also controls
+ on-demand CVF module loading. Without this option, nothing is loaded
+ on demand. With cvf_format=xxx, a module "xxx" is requested automatically
+ before mounting the compressed filesystem (unless "xxx" is "none"). In
+ case there is a difference between the CVF format name and the module
+ name, setup aliases in your modules configuration. If the string "xxx"
+ is "autoload", a non-existent module "cvf_autoload" is requested which
+ can be used together with a special modules configuration (alias and
+ pre-install statements) in order to load more than one CVF module, let
+ them detect automatically which kind of CVF is to be mounted, and only
+ keep the "right" module in memory. For examples please refer to the
+ dmsdos documentation (ftp and http addresses see below).
+
+ cvf_options=yyy
+ Option string passed to the CVF module. I.e. only the "yyy" is passed
+ (without the quotes). The documentation for each CVF module should
+ explain it since it is interpreted only by the CVF module. Note that
+ the string must not contain a comma (",") - this would lead to
+ misinterpretation by the FAT driver, which would recognize the text
+ after a comma as a FAT driver option and might get confused or print
+ strange error messages. The documentation for the CVF module should
+ offer a different separation symbol, for example the dot "." or the
+ plus sign "+", which is only valid inside the string "yyy".
+
+
+4. Description of the CVF-FAT interface
+------------------------------------------------------------------------------
+
+Assuming you want to write your own CVF module, you need to write a lot of
+interface functions. Most of them are covered in the kernel documentation
+you can find on the net, and thus won't be described here. They have been
+marked with "[...]" :-) Take a look at include/linux/fat_cvf.h.
+
+struct cvf_format
+{ int cvf_version;
+ char* cvf_version_text;
+ unsigned long int flags;
+ int (*detect_cvf) (struct super_block*sb);
+ int (*mount_cvf) (struct super_block*sb,char*options);
+ int (*unmount_cvf) (struct super_block*sb);
+ [...]
+ void (*cvf_zero_cluster) (struct inode*inode,int clusternr);
+}
+
+This structure defines the capabilities of a CVF module. It must be filled
+out completely by a CVF module. Consider it as a kind of form that is used
+to introduce the module to the FAT/CVF-FAT driver.
+
+It contains...
+ - cvf_version:
+ A version id which must be unique. Choose one.
+ - cvf_version_text:
+ A human readable version string that should be one short word
+ describing the CVF format the module implements. This text is used
+ for the cvf_format option. This name must also be unique.
+ - flags:
+ Bit coded flags, currently only used for a readpage/mmap hack that
+ provides both mmap and readpage functionality. If CVF_USE_READPAGE
+ is set, mmap is set to generic_file_mmap and readpage is caught
+ and redirected to the cvf_readpage function. If it is not set,
+ readpage is set to generic_readpage and mmap is caught and redirected
+ to cvf_mmap. (If you want writable mmap use the readpage interface.)
+ - detect_cvf:
+ A function that is called to decide whether the filesystem is a CVF of
+ the type the module supports. The detect_cvf function must return 0
+ for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS
+ THE KIND OF CVF I SUPPORT". The function must maintain the module
+ usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
+ and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
+ successful recongition would lead to a call of the mount_cvf function
+ later.
+ - mount_cvf:
+ A function that sets up some values or initializes something additional
+ to what has to be done when a CVF is mounted. This is called at the
+ end of fat_read_super and must return 0 on success. Definitely, this
+ function must increment the module usage counter by MOD_INC_USE_COUNT.
+ This mount_cvf function is also responsible for interpreting a CVF
+ module specific option string (the "yyy" from the FAT mount option
+ "cvf_options=yyy") which cannot contain a comma (use for example the
+ dot "." as option separator symbol).
+ - unmount_cvf:
+ A function that is called when the filesystem is unmounted. Most likely
+ it only frees up some memory and calls MOD_DEC_USE_COUNT. The return
+ value might be ignored (it currently is ignored).
+ - [...]:
+ All other interface functions are "caught" FAT driver functions, i.e.
+ are executed by the FAT driver *instead* of the original FAT driver
+ functions. NULL means use the original FAT driver functions instead.
+ If you really want "no action", write a function that does nothing and
+ hang it in instead.
+ - cvf_zero_cluster:
+ The cvf_zero_cluster function is called when the fat driver wants to
+ zero out a (new) cluster. This is important for directories (mkdir).
+ If it is NULL, the FAT driver defaults to overwriting the whole
+ cluster with zeros. Note that clusternr is absolute, not relative
+ to the provided inode.
+
+Notes:
+ 1. The cvf_bmap function should be ignored. It really should never
+ get called from somewhere. I recommend redirecting it to a panic
+ or fatal error message so bugs show up immediately.
+ 2. The cvf_writepage function is ignored. This is because the fat
+ driver doesn't support it. This might change in future. I recommend
+ setting it to NULL (i.e use default).
+
+int register_cvf_format(struct cvf_format*cvf_format);
+ If you have just set up a variable containing the above structure,
+ call this function to introduce your CVF format to the FAT/CVF-FAT
+ driver. This is usually done in init_module. Be sure to check the
+ return value. Zero means success, everything else causes a kernel
+ message printed in the syslog describing the error that occurred.
+ Typical errors are:
+ - a module with the same version id is already registered or
+ - too many CVF formats. Hack fs/fat/cvf.c if you need more.
+
+int unregister_cvf_format(struct cvf_format*cvf_format);
+ This is usually called in cleanup_module. Return value =0 means
+ success. An error only occurs if you try to unregister a CVF format
+ that has not been previously registered. The code uses the version id
+ to distinguish the modules, so be sure to keep it unique.
+
+5. CVF Modules
+------------------------------------------------------------------------------
+
+Refer to the dmsdos module (the successor of the dmsdos filesystem) for a
+sample implementation. It can currently be found at
+
+ ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz
+ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz
+ ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz
+
+(where x.y.z is to be replaced with the actual version number). Full
+documentation about dmsdos is included in the dmsdos package, but can also
+be found at
+
+ http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html
+ http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese).
diff --git a/patches/in-kernel-2.0.35.diff b/patches/in-kernel-2.0.35.diff
new file mode 100644
index 0000000..5bfbee2
--- /dev/null
+++ b/patches/in-kernel-2.0.35.diff
@@ -0,0 +1,62 @@
+--- linux-orig/fs/Makefile Thu Jun 11 14:23:31 1998
++++ linux/fs/Makefile Sun Aug 23 14:23:39 1998
+@@ -18,7 +18,7 @@
+
+ MOD_LIST_NAME := FS_MODULES
+ ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \
+- hpfs sysv smbfs ncpfs ufs affs autofs
++ hpfs sysv smbfs ncpfs ufs affs autofs dmsdos
+
+ ifeq ($(CONFIG_QUOTA),y)
+ O_OBJS += dquot.o
+@@ -55,6 +55,14 @@
+ else
+ ifeq ($(CONFIG_FAT_FS),m)
+ MOD_SUB_DIRS += fat
++ endif
++endif
++
++ifeq ($(CONFIG_DMSDOS_FS),y)
++SUB_DIRS += dmsdos
++else
++ ifeq ($(CONFIG_DMSDOS_FS),m)
++ MOD_SUB_DIRS += dmsdos
+ endif
+ endif
+
+--- linux-orig/fs/Config.in Sat Jul 18 00:31:37 1998
++++ linux/fs/Config.in Sun Aug 23 14:33:10 1998
+@@ -16,6 +16,10 @@
+
+ # msdos filesystems
+ dep_tristate 'DOS FAT fs support' CONFIG_FAT_FS $CONFIG_NLS
++ dep_tristate 'DMSDOS (dblspace/drvspace/stacker) support' CONFIG_DMSDOS_FS $CONFIG_FAT_FS
++ if [ "$CONFIG_DMSDOS_FS" = "y" -o "$CONFIG_DMSDOS_FS" = "m" ]; then
++ source fs/dmsdos/Config.in
++ fi
+ dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
+ dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+ dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
+--- linux-orig/fs/filesystems.c Thu Jun 11 14:23:32 1998
++++ linux/fs/filesystems.c Sun Aug 23 14:54:27 1998
+@@ -32,6 +32,9 @@
+
+ extern void device_setup(void);
+ extern void binfmt_setup(void);
++#ifdef CONFIG_DMSDOS_FS
++extern int init_dmsdos(void);
++#endif
+
+ /* This may be used only once, enforced by 'static int callable' */
+ asmlinkage int sys_setup(void)
+@@ -72,6 +75,10 @@
+
+ #ifdef CONFIG_FAT_FS
+ init_fat_fs();
++#endif
++
++#ifdef CONFIG_DMSDOS_FS
++ init_dmsdos();
+ #endif
+
+ #ifdef CONFIG_MSDOS_FS
diff --git a/patches/linux-2.2.13-dmsdos.patch-1 b/patches/linux-2.2.13-dmsdos.patch-1
new file mode 100644
index 0000000..e126359
--- /dev/null
+++ b/patches/linux-2.2.13-dmsdos.patch-1
@@ -0,0 +1,16 @@
+diff -u -r -r linux-2.2.13-orig/fs/fat/misc.c linux-2.2.13-new1/fs/fat/misc.c
+--- linux-2.2.13-orig/fs/fat/misc.c Mon Aug 9 19:04:41 1999
++++ linux-2.2.13-new1/fs/fat/misc.c Sun Dec 5 11:43:02 1999
+@@ -222,9 +222,10 @@
+ sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size;
+ last_sector = sector + cluster_size;
+ if (MSDOS_SB(sb)->cvf_format &&
+- MSDOS_SB(sb)->cvf_format->zero_out_cluster)
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster) {
+ MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr);
+- else
++ res=fat_bread(sb,fat_smap(inode,inode->i_blocks));
++ }else
+ for ( ; sector < last_sector; sector++) {
+ #ifdef DEBUG
+ printk("zeroing sector %d\n",sector);
diff --git a/patches/linux-2.3.30-pre6-dmsdos.patch-1 b/patches/linux-2.3.30-pre6-dmsdos.patch-1
new file mode 100644
index 0000000..bc4757b
--- /dev/null
+++ b/patches/linux-2.3.30-pre6-dmsdos.patch-1
@@ -0,0 +1,284 @@
+diff -u -r linux-2.3.30-6-orig/fs/fat/cvf.c linux-2.3.30-6-new1/fs/fat/cvf.c
+--- linux-2.3.30-6-orig/fs/fat/cvf.c Mon Aug 9 18:43:49 1999
++++ linux-2.3.30-6-new1/fs/fat/cvf.c Wed Nov 3 00:28:53 1999
+@@ -53,49 +53,55 @@
+ loff_t *ppos);
+
+ struct cvf_format default_cvf = {
+- 0, /* version - who cares? */
+- "plain",
+- 0, /* flags - who cares? */
+- NULL,
+- NULL,
+- NULL,
+- default_fat_bread,
+- default_fat_getblk,
+- default_fat_brelse,
+- default_fat_mark_buffer_dirty,
+- default_fat_set_uptodate,
+- default_fat_is_uptodate,
+- default_fat_ll_rw_block,
+- default_fat_access,
+- NULL,
+- default_fat_bmap,
+- generic_file_read,
+- default_fat_file_write,
+- NULL,
+- NULL
++ 0, /* cvf unique version number - 0 for fat internal CVF */
++ "plain", /* cvf version name */
++ 0, /* flags - capabilities, ex. CVF_USE_READPAGE */
++ NULL, /* detect_cvf */
++ NULL, /* mount_cvf */
++ NULL, /* unmount_cvf */
++ default_fat_bread, /* cvf_bread */
++ default_fat_getblk, /* cvf_getblk */
++ default_fat_brelse, /* cvf_brelse */
++ default_fat_mark_buffer_dirty, /* cvf_mark_buffer_dirty */
++ default_fat_set_uptodate, /* cvf_set_uptodate */
++ default_fat_is_uptodate, /* cvf_is_uptodate */
++ default_fat_ll_rw_block, /* cvf_ll_rw_block */
++ default_fat_access, /* fat_access */
++ NULL, /* cvf_statfs */
++ default_fat_bmap, /* cvf_bmap */
++ generic_file_read, /* cvf_file_read */
++ default_fat_file_write, /* cvf_file_write */
++ NULL, /* cvf_mmap */
++ block_read_full_page, /* cvf_readpage */
++ NULL, /* cvf_writepage */
++ NULL, /* cvf_dir_ioctl */
++ NULL /* zero_out_cluster */
+ };
+
+ struct cvf_format bigblock_cvf = {
+- 0, /* version - who cares? */
+- "big_blocks",
+- 0, /* flags - who cares? */
+- NULL,
+- NULL,
+- NULL,
+- bigblock_fat_bread,
+- bigblock_fat_bread,
+- bigblock_fat_brelse,
+- bigblock_fat_mark_buffer_dirty,
+- bigblock_fat_set_uptodate,
+- bigblock_fat_is_uptodate,
+- bigblock_fat_ll_rw_block,
+- default_fat_access,
+- NULL,
+- default_fat_bmap,
+- NULL,
+- default_fat_file_write,
+- NULL,
+- NULL
++ 0, /* cvf unique version number - 0 for fat internal CVF */
++ "big_blocks", /* cvf version name */
++ 0, /* flags - capabilities, ex. CVF_USE_READPAGE */
++ NULL, /* detect_cvf */
++ NULL, /* mount_cvf */
++ NULL, /* unmount_cvf */
++ bigblock_fat_bread, /* cvf_bread */
++ bigblock_fat_bread, /* cvf_getblk */
++ bigblock_fat_brelse, /* cvf_brelse */
++ bigblock_fat_mark_buffer_dirty, /* cvf_mark_buffer_dirty */
++ bigblock_fat_set_uptodate, /* cvf_set_uptodate */
++ bigblock_fat_is_uptodate, /* cvf_is_uptodate */
++ bigblock_fat_ll_rw_block, /* cvf_ll_rw_block */
++ default_fat_access, /* fat_access */
++ NULL, /* cvf_statfs */
++ default_fat_bmap, /* cvf_bmap */
++ NULL, /* ?????? */ /* cvf_file_read */
++ default_fat_file_write, /* cvf_file_write */
++ NULL, /* cvf_mmap */
++ block_read_full_page, /* cvf_readpage */
++ NULL, /* cvf_writepage */
++ NULL, /* cvf_dir_ioctl */
++ NULL /* zero_out_cluster */
+ };
+
+ struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
+diff -u -r linux-2.3.30-6-orig/fs/fat/fatfs_syms.c linux-2.3.30-6-new1/fs/fat/fatfs_syms.c
+--- linux-2.3.30-6-orig/fs/fat/fatfs_syms.c Tue Oct 26 18:21:46 1999
++++ linux-2.3.30-6-new1/fs/fat/fatfs_syms.c Mon Nov 1 22:29:25 1999
+@@ -17,6 +17,7 @@
+
+ extern struct file_operations fat_dir_operations;
+
++EXPORT_SYMBOL(fat_add_cluster);
+ EXPORT_SYMBOL(fat_new_dir);
+ EXPORT_SYMBOL(fat_bmap);
+ EXPORT_SYMBOL(fat_get_block);
+@@ -55,6 +56,12 @@
+ EXPORT_SYMBOL(fat_dir_ioctl);
+ EXPORT_SYMBOL(fat_add_entries);
+ EXPORT_SYMBOL(fat_dir_empty);
++
++#if 0 /* will be reenabled again for CVF mmap support */
++EXPORT_SYMBOL(fat_mmap);
++EXPORT_SYMBOL(fat_readpage);
++EXPORT_SYMBOL(fat_writepage);
++#endif
+
+ int init_fat_fs(void)
+ {
+diff -u -r linux-2.3.30-6-orig/fs/fat/inode.c linux-2.3.30-6-new1/fs/fat/inode.c
+--- linux-2.3.30-6-orig/fs/fat/inode.c Sat Nov 6 00:27:28 1999
++++ linux-2.3.30-6-new1/fs/fat/inode.c Sun Dec 5 01:16:44 1999
+@@ -434,12 +434,15 @@
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ char *p;
+ int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;
+- int debug,error,fat,cp;
++ int debug;
++ int error = 0;
++ int fat,cp;
+ int blksize = 512;
+ int fat32;
+ struct fat_mount_options opts;
+ char buf[50];
+- int i;
++ int cvf_index=-1;
++ /* int i; */
+ char cvf_format[21];
+ char cvf_options[101];
+
+@@ -514,14 +517,15 @@
+ sbi->cluster_size = b->cluster_size*sector_mult;
+ if (!sbi->cluster_size || (sbi->cluster_size & (sbi->cluster_size-1))) {
+ printk("fatfs: bogus cluster size\n");
+- brelse(bh);
+- goto out_invalid;
++ error = 1;
++ /* brelse(bh);goto out_invalid; */
++ }else{
++ for (sbi->cluster_bits=0;
++ 1<<sbi->cluster_bits<sbi->cluster_size;
++ sbi->cluster_bits++)
++ ;
++ sbi->cluster_bits += SECTOR_BITS;
+ }
+- for (sbi->cluster_bits=0;
+- 1<<sbi->cluster_bits<sbi->cluster_size;
+- sbi->cluster_bits++)
+- ;
+- sbi->cluster_bits += SECTOR_BITS;
+ sbi->fats = b->fats;
+ sbi->fat_start = CF_LE_W(b->reserved)*sector_mult;
+ if (!b->fat_length && b->fat32_length) {
+@@ -573,7 +577,7 @@
+ data_sectors = CF_LE_L(b->total_sect);
+ }
+ data_sectors = data_sectors * sector_mult - sbi->data_start;
+- error = !b->cluster_size || !sector_mult;
++ error |= !sector_mult;
+ if (!error) {
+ sbi->clusters = b->cluster_size ? data_sectors/
+ b->cluster_size/sector_mult : 0;
+@@ -599,11 +603,14 @@
+ /* on odd sectors. */
+ sb->s_blocksize_bits = blksize == 512 ? 9 : (blksize == 1024 ? 10 : 11);
+ if (!strcmp(cvf_format,"none"))
+- i = -1;
++ cvf_index = -1;
+ else
+- i = detect_cvf(sb,cvf_format);
+- if (i >= 0)
+- error = cvf_formats[i]->mount_cvf(sb,cvf_options);
++ cvf_index = detect_cvf(sb,cvf_format);
++ if (cvf_index >= 0) {
++ ++cvf_format_use_count[cvf_index];
++ sbi->cvf_format = cvf_formats[cvf_index];
++ error = cvf_formats[cvf_index]->mount_cvf(sb,cvf_options);
++ }
+ else if (sb->s_blocksize == 512)
+ sbi->cvf_format = &default_cvf;
+ else
+@@ -627,7 +634,7 @@
+ sbi->root_cluster,sbi->free_clusters);
+ printk ("Transaction block size = %d\n",blksize);
+ }
+- if (i<0) if (sbi->clusters+2 > fat_clusters)
++ if (cvf_index<0) if (sbi->clusters+2 > fat_clusters)
+ sbi->clusters = fat_clusters-2;
+ if (error)
+ goto out_invalid;
+@@ -672,10 +679,6 @@
+ sb->s_root = d_alloc_root(root_inode);
+ if (!sb->s_root)
+ goto out_no_root;
+- if(i>=0) {
+- sbi->cvf_format = cvf_formats[i];
+- ++cvf_format_use_count[i];
+- }
+ return sb;
+
+ out_no_root:
+@@ -687,6 +690,8 @@
+ unload_nls(sbi->nls_disk);
+ goto out_fail;
+ out_invalid:
++ if(cvf_index>=0)
++ --cvf_format_use_count[cvf_index];
+ if (!silent)
+ printk("VFS: Can't find a valid MSDOS filesystem on dev %s.\n",
+ kdevname(sb->s_dev));
+diff -u -r linux-2.3.30-6-orig/fs/fat/misc.c linux-2.3.30-6-new1/fs/fat/misc.c
+--- linux-2.3.30-6-orig/fs/fat/misc.c Mon Aug 30 17:23:14 1999
++++ linux-2.3.30-6-new1/fs/fat/misc.c Sun Dec 5 03:11:47 1999
+@@ -209,8 +209,16 @@
+ int cluster_size = MSDOS_SB(sb)->cluster_size;
+
+ if (MSDOS_SB(sb)->fat_bits != 32) {
+- if (inode->i_ino == MSDOS_ROOT_INO) return res;
++ if (inode->i_ino == MSDOS_ROOT_INO){
++#ifdef DEBUG
++printk("FAT extend dir called for root\n");
++#endif
++ return res;
++ }
+ }
++#ifdef DEBUG
++printk("FAT extend dir called for NON-root\n");
++#endif
+ if (!MSDOS_SB(sb)->free_clusters) return res;
+ lock_fat(sb);
+ limit = MSDOS_SB(sb)->clusters;
+@@ -279,9 +287,11 @@
+ sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size;
+ last_sector = sector + cluster_size;
+ if (MSDOS_SB(sb)->cvf_format &&
+- MSDOS_SB(sb)->cvf_format->zero_out_cluster)
++ MSDOS_SB(sb)->cvf_format->zero_out_cluster){
++ /* CVF zeroes full cluster only */
+ MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr);
+- else
++ res=fat_bread(sb,fat_bmap(inode,inode->i_blocks));
++ }else
+ for ( ; sector < last_sector; sector++) {
+ #ifdef DEBUG
+ printk("zeroing sector %d\n",sector);
+diff -u -r linux-2.3.30-6-orig/include/linux/fat_cvf.h linux-2.3.30-6-new1/include/linux/fat_cvf.h
+--- linux-2.3.30-6-orig/include/linux/fat_cvf.h Mon Aug 9 18:43:49 1999
++++ linux-2.3.30-6-new1/include/linux/fat_cvf.h Sat Dec 4 23:25:26 1999
+@@ -30,8 +30,8 @@
+ ssize_t (*cvf_file_read) ( struct file *, char *, size_t, loff_t *);
+ ssize_t (*cvf_file_write) ( struct file *, const char *, size_t, loff_t *);
+ int (*cvf_mmap) (struct file *, struct vm_area_struct *);
+- int (*cvf_readpage) (struct inode *, struct page *);
+- int (*cvf_writepage) (struct inode *, struct page *);
++ int (*cvf_readpage) (struct dentry *, struct page *);
++ int (*cvf_writepage) (struct dentry *, struct page *);
+ int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp,
+ unsigned int cmd, unsigned long arg);
+ void (*zero_out_cluster) (struct inode*, int clusternr);
+diff -u -r linux-2.3.30-6-orig/include/linux/msdos_fs.h linux-2.3.30-6-new1/include/linux/msdos_fs.h
+--- linux-2.3.30-6-orig/include/linux/msdos_fs.h Wed Oct 27 23:19:11 1999
++++ linux-2.3.30-6-new1/include/linux/msdos_fs.h Wed Nov 24 22:25:31 1999
+@@ -274,6 +274,7 @@
+ /* mmap.c */
+ extern int fat_mmap(struct file *, struct vm_area_struct *);
+ extern int fat_readpage(struct file *, struct page *);
++extern int fat_writepage(struct file *, struct page *);
+
+
+ /* vfat.c */
diff --git a/patches/magic b/patches/magic
new file mode 100644
index 0000000..9ee8ebb
--- /dev/null
+++ b/patches/magic
@@ -0,0 +1,16 @@
+#------------------------------------------------------------------------------
+#
+# dmsdos: file(1) magic for the CVF formats supported by dmsdos
+#
+
+3 string MSDBL6.0
+>51 byte 0
+>>13 byte 16 Doublespace CVF (version 1)
+>>13 byte 64 Drivespace 3 CVF
+>51 byte 2 Drivespace CVF (version 2)
+3 string MSDSP6.0
+>51 byte 0
+>>13 byte 16 Doublespace CVF (version 1)
+>>13 byte 64 Drivespace 3 CVF
+>51 byte 2 Drivespace CVF (version 2)
+0 string STACKER Stacker CVF
diff --git a/patches/msdos-rmdir-bugfix.diff b/patches/msdos-rmdir-bugfix.diff
new file mode 100644
index 0000000..cd8305f
--- /dev/null
+++ b/patches/msdos-rmdir-bugfix.diff
@@ -0,0 +1,19 @@
+--- linux.vanilla/fs/msdos/namei.c Sun Jun 21 18:40:55 1998
++++ linux/fs/msdos/namei.c Fri Sep 11 04:07:28 1998
+@@ -369,7 +369,7 @@
+ if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
+ pos = 0;
+ bh = NULL;
+- while (fat_get_entry(dir,&pos,&bh,&de) > -1)
++ while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
+ /* Ignore vfat longname entries */
+ if (de->attr == ATTR_EXT)
+ continue;
+@@ -379,6 +379,7 @@
+ fat_brelse(sb, bh);
+ return -ENOTEMPTY;
+ }
++ }
+ if (bh)
+ fat_brelse(sb, bh);
+ }
diff --git a/patches/vfat-brelse-bugfix.diff b/patches/vfat-brelse-bugfix.diff
new file mode 100644
index 0000000..ec9e750
--- /dev/null
+++ b/patches/vfat-brelse-bugfix.diff
@@ -0,0 +1,15 @@
+--- linux/fs/vfat/namei.c.orig Fri Feb 26 14:42:54 1999
++++ linux/fs/vfat/namei.c Fri Feb 26 14:43:28 1999
+@@ -506,10 +506,10 @@
+ continue;
+ if (memcmp(de->name,name,MSDOS_NAME))
+ continue;
+- brelse(bh);
++ fat_brelse(dir->i_sb,bh);
+ return 0;
+ }
+- brelse(bh);
++ fat_brelse(dir->i_sb,bh);
+ return -ENOENT;
+ }
+