diff -ur linux-2.4.19-PRISTINE/CREDITS linux-mynew/CREDITS
--- linux-2.4.19-PRISTINE/CREDITS	Mon Aug 12 17:50:48 2002
+++ linux-mynew/CREDITS	Wed Aug 14 16:20:39 2002
@@ -2179,8 +2179,9 @@
 S: Finland
 
 N: Matija Nalis
-E: mnalis@jagor.srce.hr
-E: mnalis@voyager.hr
+E: mnalis-umsdos2@voyager.hr
+E: mnalis-umsdos2@net4u.hr
+E: umsdos@mnalis.com
 D: Maintainer of the Umsdos file system
 S: Listopadska 7
 S: 10000 Zagreb
diff -ur linux-2.4.19-PRISTINE/MAINTAINERS linux-mynew/MAINTAINERS
--- linux-2.4.19-PRISTINE/MAINTAINERS	Mon Aug 12 17:50:49 2002
+++ linux-mynew/MAINTAINERS	Wed Aug 14 16:20:39 2002
@@ -1614,7 +1614,7 @@
 
 UMSDOS FILESYSTEM
 P:	Matija Nalis
-M:	Matija Nalis <mnalis-umsdos@voyager.hr>
+M:	Matija Nalis <mnalis-umsdos2@voyager.hr>
 L:	linux-kernel@vger.kernel.org
 W:	http://linux.voyager.hr/umsdos/
 S:	Maintained
diff -ur linux-2.4.19-PRISTINE/fs/Config.in linux-mynew/fs/Config.in
--- linux-2.4.19-PRISTINE/fs/Config.in	Mon Aug 12 17:51:00 2002
+++ linux-mynew/fs/Config.in	Wed Aug 14 16:21:00 2002
@@ -31,8 +31,8 @@
 # msdos file systems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
 dep_tristate '  MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
 dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
+dep_tristate '    UMSDOS/VFAT: Unix-like file system on top of standard VFAT fs' CONFIG_UMSDOS_FS $CONFIG_VFAT_FS
 dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
 dep_tristate 'Journalling Flash File System (JFFS) support' CONFIG_JFFS_FS $CONFIG_MTD
 if [ "$CONFIG_JFFS_FS" = "y" -o "$CONFIG_JFFS_FS" = "m" ] ; then
diff -ur linux-2.4.19-PRISTINE/fs/fat/dir.c linux-mynew/fs/fat/dir.c
--- linux-2.4.19-PRISTINE/fs/fat/dir.c	Tue Oct 30 13:47:10 2001
+++ linux-mynew/fs/fat/dir.c	Sat Aug 17 19:13:20 2002
@@ -202,7 +202,7 @@
 	loff_t cpos = 0;
 
 	while(1) {
-		if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
+		if (fat_get_entry(inode,&cpos,&bh,&de,&ino,NULL) == -1)
 			goto EODir;
 parse_record:
 		long_slots = 0;
@@ -253,7 +253,7 @@
 				if (ds->id & 0x40) {
 					unicode[offset + 13] = 0;
 				}
-				if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
+				if (fat_get_entry(inode,&cpos,&bh,&de,&ino,NULL)<0)
 					goto EODir;
 				if (slot == 0)
 					break;
@@ -392,7 +392,7 @@
  	bh = NULL;
 GetNew:
 	long_slots = 0;
-	if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
+	if (fat_get_entry(inode,&cpos,&bh,&de,&ino,NULL) == -1)
 		goto EODir;
 	/* Check for long filename entry */
 	if (isvfat) {
@@ -449,7 +449,7 @@
 			if (ds->id & 0x40) {
 				unicode[offset + 13] = 0;
 			}
-			if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
+			if (fat_get_entry(inode,&cpos,&bh,&de,&ino,NULL) == -1)
 				goto EODir;
 			if (slot == 0)
 				break;
@@ -545,8 +545,10 @@
 		if (tmp) {
 			inum = tmp->i_ino;
 			iput(tmp);
-		} else
+		} else {
 			inum = iunique(sb, MSDOS_ROOT_INO);
+			PRINTK ((KERN_DEBUG "  FAT readdirx uncached. iunique generates %u\n", inum));
+		}
 	}
 
 	if (isvfat) {
@@ -697,7 +699,7 @@
 
 	pos = 0;
 	bh = NULL;
-	while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
+	while (fat_get_entry(dir,&pos,&bh,&de,&ino,NULL) > -1) {
 		/* Ignore vfat longname entries */
 		if (de->attr == ATTR_EXT)
 			continue;
@@ -727,7 +729,7 @@
 	offset = curr = 0;
 	*bh = NULL;
 	row = 0;
-	while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
+	while (fat_get_entry(dir,&curr,bh,de,ino,NULL) > -1) {
 		if (IS_FREE((*de)->name)) {
 			if (++row == slots)
 				return offset;
@@ -742,7 +744,7 @@
 	if (!new_bh)
 		return -ENOSPC;
 	fat_brelse(sb, new_bh);
-	do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
+	do fat_get_entry(dir,&curr,bh,de,ino,NULL); while (++row<slots);
 	return offset;
 }
 
diff -ur linux-2.4.19-PRISTINE/fs/fat/fatfs_syms.c linux-mynew/fs/fat/fatfs_syms.c
--- linux-2.4.19-PRISTINE/fs/fat/fatfs_syms.c	Tue Oct 30 13:47:10 2001
+++ linux-mynew/fs/fat/fatfs_syms.c	Sat Aug 17 19:13:20 2002
@@ -38,6 +38,9 @@
 EXPORT_SYMBOL(fat_dir_empty);
 EXPORT_SYMBOL(fat_truncate);
 EXPORT_SYMBOL(fat_brelse);
+EXPORT_SYMBOL(fat_bmap);
+EXPORT_SYMBOL(fat_iget);
+EXPORT_SYMBOL(fat_fill_inode);
 
 static int __init init_fat_fs(void)
 {
diff -ur linux-2.4.19-PRISTINE/fs/fat/inode.c linux-mynew/fs/fat/inode.c
--- linux-2.4.19-PRISTINE/fs/fat/inode.c	Mon Aug 12 17:51:01 2002
+++ linux-mynew/fs/fat/inode.c	Sat Aug 17 19:13:20 2002
@@ -32,7 +32,7 @@
 
 extern struct cvf_format default_cvf;
 
-/* #define FAT_PARANOIA 1 */
+#define FAT_PARANOIA 1
 #define DEBUG_LEVEL 0
 #ifdef FAT_DEBUG
 #  define PRINTK(x) printk x
@@ -103,6 +103,7 @@
 {
 	spin_lock(&fat_inode_lock);
 	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_old_loc = 0;
 	list_del(&MSDOS_I(inode)->i_fat_hash);
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&fat_inode_lock);
@@ -114,10 +115,29 @@
 	struct list_head *walk;
 	struct msdos_inode_info *i;
 	struct inode *inode = NULL;
+#ifdef DEBUG
+	int count = 0;
+#endif	
 
 	spin_lock(&fat_inode_lock);
 	list_for_each(walk, p) {
 		i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
+#ifdef DEBUG			
+		if (count++ > 100) {
+			printk (KERN_EMERG "COUNT BIGGER THAN 100 in fat_iget, debug listing & breaking out!\n");
+			printk (KERN_ERR "our sb=%p (%d,%d), our i_pos=%u\n\n", sb, MAJOR (sb->s_dev), MINOR (sb->s_dev), i_pos);
+			p = fat_inode_hashtable + fat_hash(sb, i_pos);
+			list_for_each(walk, p) {
+				i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
+				printk (KERN_ERR "   sb=%p (%d,%d) i_location=%u\n", i->i_fat_inode->i_sb, MAJOR (i->i_fat_inode->i_sb->s_dev), MINOR (i->i_fat_inode->i_sb->s_dev), i->i_location );
+				if (count-- == 0) {
+					printk (KERN_ERR "  ... breaking too long list...\n");
+					break;
+				}
+			}
+			break;
+		}
+#endif		
 		if (i->i_fat_inode->i_sb != sb)
 			continue;
 		if (i->i_location != i_pos)
@@ -126,29 +146,50 @@
 		if (inode)
 			break;
 	}
+#ifdef DEBUG
+	if (inode)	
+		PRINTK1 ((KERN_DEBUG "  FAT fat_iget cached! %u daje %lu (count = %d)\n", i_pos, inode->i_ino, count));
+	else
+		PRINTK1 ((KERN_DEBUG "  FAT fat_iget uncached for %u...\n", i_pos));
+#endif		
+	
 	spin_unlock(&fat_inode_lock);
 	return inode;
 }
 
-static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
+void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
 
 struct inode *fat_build_inode(struct super_block *sb,
 				struct msdos_dir_entry *de, int ino, int *res)
 {
 	struct inode *inode;
+	unsigned long new_ino = 0;
 	*res = 0;
 	inode = fat_iget(sb, ino);
-	if (inode)
-		goto out;
+	if (inode) {
+		if (inode->i_size != 0xdeadbeef)
+			goto out;
+		/* this is UVFAT readdir(2) faked inode, only inode->i_ino is valid! */
+		new_ino = inode->i_ino;
+
+		fat_detach(inode);
+//		remove_inode_hash(inode);	// hmmm, fixme ?
+		PRINTK1 ((KERN_DEBUG "**** fat_build_inode for fake inode before iput()\n"));
+		PRINTK1 ((KERN_DEBUG "*   inode is %lu (i_count=%d, umsdos_i.pos=%lu) (i_patched=%d)", inode->i_ino, atomic_read(&inode->i_count), inode->u.umsdos_i.pos, inode->u.umsdos_i.i_patched));
+		iput(inode);
+	}
 	inode = new_inode(sb);
 	*res = -ENOMEM;
 	if (!inode)
 		goto out;
 	*res = 0;
-	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
+	if (!new_ino) new_ino = iunique(sb, MSDOS_ROOT_INO);
+	inode->i_ino = new_ino;
+	PRINTK1 ((KERN_DEBUG "    fat_build_inode: ino seed=%u, new i_ino=%lu ", ino, inode->i_ino));
 	fat_fill_inode(inode, de);
 	fat_attach(inode, ino);
 	insert_inode_hash(inode);
+	PRINTK1 (("  b4 ret i_ino=%lu\n", inode->i_ino));
 out:
 	return inode;
 }
@@ -380,6 +421,8 @@
 
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_old_loc = 0;
+	MSDOS_I(inode)->i_fix_loc = 0;
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
@@ -883,7 +926,7 @@
 };
 
 /* doesn't deal with root inode */
-static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
+void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -891,6 +934,8 @@
 
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_old_loc = 0;
+	MSDOS_I(inode)->i_fix_loc = 0;
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
@@ -964,7 +1009,8 @@
 	MSDOS_I(inode)->i_ctime_ms = de->ctime_ms;
 }
 
-void fat_write_inode(struct inode *inode, int wait)
+
+void _fat_write_inode(struct inode *inode, int wait, unsigned int *loc)
 {
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh;
@@ -972,7 +1018,7 @@
 	unsigned int i_pos;
 
 retry:
-	i_pos = MSDOS_I(inode)->i_location;
+	i_pos = *loc;
 	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
 		return;
 	}
@@ -984,7 +1030,7 @@
 		return;
 	}
 	spin_lock(&fat_inode_lock);
-	if (i_pos != MSDOS_I(inode)->i_location) {
+	if (i_pos != *loc) {
 		spin_unlock(&fat_inode_lock);
 		fat_brelse(sb, bh);
 		unlock_kernel();
@@ -1020,6 +1066,18 @@
 	unlock_kernel();
 }
 
+void fat_write_inode(struct inode *inode, int wait)
+{
+	unsigned int *loc;
+	if (MSDOS_I(inode)->i_old_loc) {
+		loc = &(MSDOS_I(inode)->i_old_loc);
+		PRINTK1 ((KERN_DEBUG "fat_write_inode using i_old_loc=%u\n", *loc));
+	} else {
+		loc = &(MSDOS_I(inode)->i_location);
+		PRINTK1 ((KERN_DEBUG "fat_write_inode using i_location=%u\n", *loc));
+	}
+	_fat_write_inode (inode, wait, loc);
+}
 
 int fat_notify_change(struct dentry * dentry, struct iattr * attr)
 {
diff -ur linux-2.4.19-PRISTINE/fs/fat/misc.c linux-mynew/fs/fat/misc.c
--- linux-2.4.19-PRISTINE/fs/fat/misc.c	Tue Oct 30 13:47:10 2001
+++ linux-mynew/fs/fat/misc.c	Tue Aug 27 00:26:37 2002
@@ -315,7 +315,7 @@
  */
 
 int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
-    struct msdos_dir_entry **de, int *ino)
+    struct msdos_dir_entry **de, int *ino, int *fixloc)
 {
 	struct super_block *sb = dir->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -342,7 +342,28 @@
 
 		offset &= sb->s_blocksize - 1;
 		*de = (struct msdos_dir_entry *) ((*bh)->b_data + offset);
-		*ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+
+		/*
+		 * UVFAT patch: we use precalculated new_inode->i_location in 
+		 * dir->i_fix_loc (since struct inode *dir gets passed around)
+		 * we calculate it ourselves, the same way as below, but not 
+		 * using offset and sector of FAT DE, but offset and sector
+		 * in UVFAT EMD
+		 *
+		 * for normal msdos/vfat i_fix_loc will always be 0
+		 */
+		if (fixloc) {
+			*fixloc = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);	/* original position in FAT DE */
+			if (MSDOS_I(dir)->i_fix_loc) {
+				*ino = MSDOS_I(dir)->i_fix_loc;		/* our position to EMD DE */
+				PRINTK ((KERN_DEBUG "  fat__get_entry (dir=%lu, pos=%llu): patching inode seed = i_fix_loc = %u (orig=%u)\n", dir->i_ino, *pos, *ino, *fixloc));
+				MSDOS_I(dir)->i_fix_loc = 0;	/* did it, nuke it now... */
+			} else {
+				*ino = *fixloc;
+				*fixloc = 0;	/* notify no patch, original returned in &ino */
+				PRINTK ((KERN_DEBUG "  fat__get_entry (dir=%lu, pos=%llu): calculating (NO patch, blank i_fix_loc) inode seed = %u\n", dir->i_ino, *pos, *ino));
+			}
+		}
 
 		return 0;
 	}
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/Makefile linux-mynew/fs/umsdos/Makefile
--- linux-2.4.19-PRISTINE/fs/umsdos/Makefile	Fri Dec 29 23:07:23 2000
+++ linux-mynew/fs/umsdos/Makefile	Mon Jul 15 19:00:31 2002
@@ -8,7 +8,7 @@
 # Note 2:  the CFLAGS definitions are now in the main makefile.
 O_TARGET := umsdos.o
 
-obj-y   := dir.o  inode.o ioctl.o mangle.o namei.o rdir.o emd.o
+obj-y   := dir.o  inode.o ioctl.o mangle.o namei.o rdir.o emd.o check.o
 
 obj-m   := $(O_TARGET)
 
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/README-WIP.txt linux-mynew/fs/umsdos/README-WIP.txt
--- linux-2.4.19-PRISTINE/fs/umsdos/README-WIP.txt	Sat Oct 20 20:12:03 2001
+++ linux-mynew/fs/umsdos/README-WIP.txt	Fri Aug  2 17:07:45 2002
@@ -1,3 +1,31 @@
+UVFAT VERSION WIP -- this is not even alpha quality!!!! 2001-09-08
+
+usage:
+mount vfat partition as uvfat.
+create empty directory on vfat (for example, '/linux')
+run umssync on it ('umssync /linux')
+
+DO NOT USE UMSSYNC EVER AGAIN (until it is called uvfatsync, and umsdos
+compatibility version changes to 0.5 so umssync will refuse to run on it
+-- IT WILL DESTROY FILENAMES if you run it again.
+
+try making some long filenames in /linux, and when you remount as vfat (o
+reboot to windows) they should retain their names. 
+
+Renames and hardlinks are work in progress, please be gentle.
+Lookups and file/directory creation should work.
+
+NOTES:
+- there seems to be plenty of 
+  'umsdos_rlookup_x: xxx/yyyyy failed, ret=-852783680' on readdir(2)
+  calls, they appear not to be critical. I'm looking into them.
+
+E-mail me on mnalis-umsdos2@voyager.hr with bug reports and patches.
+Please not that this is pre-alpha, and surely contains bugs, some of which
+may prove fatal. Backup often.
+
+---------- documentation below is obsolete !!! -----------------
+
 Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing
 (started by Peter T. Waltenberg <peterw@karaka.chch.cri.nz>)
 (Final conversion to dentries Bill Hawes <whawes@star.net>)
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/check.c linux-mynew/fs/umsdos/check.c
--- linux-2.4.19-PRISTINE/fs/umsdos/check.c	Thu Aug  1 22:48:47 2002
+++ linux-mynew/fs/umsdos/check.c	Tue Aug 27 00:03:01 2002
@@ -0,0 +1,226 @@
+/*
+ * linux/fs/umsdos/check.c
+ *
+ * Sanity-checking code
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/msdos_fs.h>
+#include <linux/umsdos_fs.h>
+
+#include <asm/system.h>
+
+#define DEBUG_VERBOSITY KERN_DEBUG
+
+#ifdef CHECK_PAGE_TABLES
+static int check_one_table (struct pde *page_dir)
+{
+	if (pgd_none (*page_dir))
+		return 0;
+	if (pgd_bad (*page_dir))
+		return 1;
+	return 0;
+}
+
+/*
+ * This function checks all page tables of "current"
+ */
+void check_page_tables (void)
+{
+	struct pgd *pg_dir;
+	static int err = 0;
+
+	int stack_level = (long) (&pg_dir) - current->kernel_stack_page;
+
+	if (stack_level < 1500)
+		printk ("** %d ** ", stack_level);
+	pg_dir = PAGE_DIR_OFFSET (current, 0);
+	if (err == 0) {
+		int i;
+
+		for (i = 0; i < PTRS_PER_PAGE; i++, page_dir++) {
+			int notok = check_one_table (page_dir);
+
+			if (notok) {
+				err++;
+				printk ("|%d:%08lx| ", i, page_dir->pgd);
+			}
+		}
+		if (err)
+			printk ("\nError MM %d\n", err);
+	}
+}
+#endif
+
+
+#if UMS_DEBUG
+
+/*
+ * check a superblock
+ */
+
+void check_sb (struct super_block *sb, const char c)
+{
+	if (sb) {
+		printk (" (has %c_sb=%d, %d)", 
+			c, MAJOR (sb->s_dev), MINOR (sb->s_dev));
+	} else {
+		printk (" (%c_sb is NULL)", c);
+	}
+} 
+
+/*
+ * check an inode
+ */
+
+void check_inode (struct inode *inode)
+{
+	if (inode) {
+		printk (DEBUG_VERBOSITY "*   inode is %lu (i_count=%d, pos=%lu, i_size=%llu)",
+			 inode->i_ino, atomic_read(&inode->i_count), inode->u.umsdos_i.pos, inode->i_size);
+		check_sb (inode->i_sb, 'i');
+#if 0		
+		if (!list_empty(&inode->i_dentry)) {
+			printk (" (has i_dentry)");
+		} else {
+			printk (" (NO i_dentry)");
+		}
+#endif
+		printk (" (i_location=%u, i_old_loc=%u)", MSDOS_I(inode)->i_location, MSDOS_I(inode)->i_old_loc);
+		printk (" (i_patched=%d)\n", inode->u.umsdos_i.i_patched);
+
+	} else {
+		printk (DEBUG_VERBOSITY "*   inode is NULL\n");
+	}
+}
+
+/*
+ * checks all inode->i_dentry
+ *
+ */
+void checkd_inode (struct inode *inode)
+{
+	struct dentry *ret;
+	struct list_head *cur;
+	int count = 0;
+	if (!inode) {
+		printk (DEBUG_VERBOSITY "checkd_inode: inode is NULL!\n");
+		return;
+	}
+
+	printk (DEBUG_VERBOSITY "checkd_inode:  inode %lu\n", inode->i_ino);
+	cur = inode->i_dentry.prev;
+	while (count++ < 10) {
+		PRINTK (("1..."));
+		if (!cur) {
+			printk (DEBUG_VERBOSITY "checkd_inode: *** NULL reached. exit.\n");
+			return;
+		}
+		PRINTK (("2..."));
+		ret = list_entry (cur, struct dentry, d_alias);
+		PRINTK (("3..."));
+		if (cur == cur->next) {
+			printk (DEBUG_VERBOSITY "checkd_inode: *** cur=cur->next: normal exit.\n");
+			return;
+		}
+		PRINTK (("4..."));
+		if (!ret) {
+			printk (DEBUG_VERBOSITY "checkd_inode: *** ret dentry is NULL. exit.\n");
+			return;
+		}
+		PRINTK (("5... (ret=%p)...", ret));
+		PRINTK (("5.1.. (ret->d_dname=%p)...", &(ret->d_name)));
+		PRINTK (("5.1.1. (ret->d_dname.len=%d)...", (int) ret->d_name.len));
+		PRINTK (("5.1.2. (ret->d_dname.name=%c)...", ret->d_name.name));
+		printk (DEBUG_VERBOSITY "checkd_inode:   i_dentry is %.*s\n", (int) ret->d_name.len, ret->d_name.name);
+		PRINTK (("6..."));
+		cur = cur->next;
+		PRINTK (("7..."));
+#if 1
+		printk (KERN_ERR "checkd_inode: *** finished after count 1 (operator forced)\n");
+		return;
+#endif		
+	}
+	printk (KERN_ERR "checkd_inode: *** OVER LIMIT (loop?) !\n");
+	return;
+}
+
+/*
+ * internal part of check_dentry. does the real job.
+ *
+ */
+
+void check_dent_int (struct dentry *dentry, int parent)
+{
+	if (parent) {
+		printk (DEBUG_VERBOSITY "*  parent(%d) dentry: %.*s\n", 
+			parent, (int) dentry->d_name.len, dentry->d_name.name);
+	} else {
+		printk (DEBUG_VERBOSITY "*  checking dentry: %.*s\n",
+			 (int) dentry->d_name.len, dentry->d_name.name);
+	}
+	check_inode (dentry->d_inode);
+	printk (DEBUG_VERBOSITY "*   d_count=%d", atomic_read(&dentry->d_count));
+	check_sb (dentry->d_sb, 'd');
+	if (dentry->d_op == NULL) {
+		printk (" (d_op is NULL)\n");
+	} else {
+		printk (" (d_op is UNKNOWN: %p)\n", dentry->d_op);
+	}
+}
+
+/*
+ * checks dentry with full traceback to root and prints info. Limited to 10 recursive depths to avoid infinite loops.
+ *
+ */
+
+void check_dentry_path (struct dentry *dentry, const char *desc)
+{
+	int count=0;
+	printk (DEBUG_VERBOSITY "*** check_dentry_path: %.60s\n", desc);
+
+	if (!dentry) {
+		printk (DEBUG_VERBOSITY "*** checking dentry... it is NULL !\n");
+		return;
+	}
+	if (IS_ERR(dentry)) {
+		printk (DEBUG_VERBOSITY "*** checking dentry... it is ERR(%ld) !\n",
+			 PTR_ERR(dentry));
+		return;
+	}
+	
+	while (dentry && count < 10) {
+		check_dent_int (dentry, count++);
+		if (IS_ROOT(dentry)) {
+			printk (DEBUG_VERBOSITY "*** end checking dentry (root reached ok)\n");
+			break;
+		}
+		dentry = dentry->d_parent;
+	}
+
+	if (count >= 10) {	/* if infinite loop detected */
+		printk (KERN_ERR 
+			"*** WARNING ! INFINITE LOOP ! check_dentry_path aborted !\n");
+	}
+	
+	if (!dentry) {
+		printk (KERN_ERR 
+			"*** WARNING ! NULL dentry ! check_dentry_path aborted !\n");
+	}
+}
+#else
+inline void uq_log (char *txt, struct inode *inode) {};
+void check_sb (struct super_block *sb, const char c) {};
+void check_inode (struct inode *inode) {};
+void checkd_inode (struct inode *inode) {};
+void check_dentry_path (struct dentry *dentry, const char *desc) {};
+#endif	/* UMS_DEBUG */
+
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/dir.c linux-mynew/fs/umsdos/dir.c
--- linux-2.4.19-PRISTINE/fs/umsdos/dir.c	Sat Oct 20 20:12:03 2001
+++ linux-mynew/fs/umsdos/dir.c	Tue Aug 27 18:54:39 2002
@@ -64,7 +64,8 @@
  * NOTE: filldir DOES NOT use a dentry
  */
 
-static int umsdos_dir_once (	void *buf,
+static int umsdos_dir_once (
+				void *buf,
 				const char *name,
 				int len,
 				loff_t offset,
@@ -84,7 +85,6 @@
 	return ret;
 }
 
-
 /*
  * Read count directory entries from directory filp
  * Return a negative value from linux/errno.h.
@@ -94,13 +94,13 @@
  * and in order to get the directory entry from a file's dentry.
  * See umsdos_dentry_to_entry() below.
  */
- 
+
 static int umsdos_readdir_x (struct inode *dir, struct file *filp,
 				void *dirbuf, struct umsdos_dirent *u_entry,
 				filldir_t filldir)
 {
 	struct dentry *demd;
-	off_t start_fpos;
+	loff_t start_fpos;
 	int ret = 0;
 	loff_t pos;
 
@@ -169,7 +169,7 @@
 		pos = 0;
 	ret = 0;
 	while (pos < demd->d_inode->i_size) {
-		off_t cur_f_pos = pos;
+		loff_t cur_f_pos = pos;
 		struct dentry *dret;
 		struct inode *inode;
 		struct umsdos_dirent entry;
@@ -189,25 +189,60 @@
 		umsdos_parse (entry.name, entry.name_len, &info);
 		info.f_pos = cur_f_pos;
 		umsdos_manglename (&info);
+
 		/*
-		 * Do a real lookup on the short name.
-		 */
-		dret = umsdos_covered(filp->f_dentry, info.fake.fname,
-						 info.fake.len);
-		ret = PTR_ERR(dret);
-		if (IS_ERR(dret))
-			break;
-		/*
-		 * If the file wasn't found, remove it from the EMD.
+		 * we want inode number:
 		 */
-		inode = dret->d_inode;
-		if (!inode)
-			goto remove_name;
+
+#if 0		// FIXME: use old slow and safe way always if 1, not only for HLINK
+		if (1) {
+#else
+		if (entry.flags & UMSDOS_HLINK) {
+#endif		
+			/* for hardlinks, do slow and painfull version -- we need fully patched inode etc */
+			dret = umsdos_fake_or_lfn(filp->f_dentry, &info);
+			inode = dret->d_inode;
+			if (!inode) {
+				printk (KERN_WARNING "umsdos_readdir_x: hardlink broken %s/%s", dret->d_parent->d_name.name, dret->d_name.name);
+				break;
+			}
 #ifdef UMSDOS_DEBUG_VERBOSE
 if (inode->u.umsdos_i.i_is_hlink)
 printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
 dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
 #endif
+		} else {
+			/* FAST for all other: lookup FAT cache or generate new inode and put it in FAT cache */
+                        struct qstr qstr;
+
+                        qstr.name = info.entry.name;
+                        qstr.len  = info.entry.name_len;
+                        qstr.hash = full_name_hash(info.entry.name, info.entry.name_len);
+                        dret = d_alloc(filp->f_dentry, &qstr);
+                                                                                                                        			
+			ret = PTR_ERR(dret);
+			if (IS_ERR(dret))
+				break;
+				
+			inode = uvfat_build_inode (dir, demd, cur_f_pos, &info);
+			ret = PTR_ERR(inode);
+			if (IS_ERR(inode)) {
+				printk (KERN_WARNING "uvfat_build_inode failed with %d for %s/%s!", ret, dret->d_parent->d_name.name, dret->d_name.name);
+				break;
+			}
+
+        		// FIXME ? 
+			//  		atomic_inc(&inode->i_count);
+        		//d_add (dret, inode);
+        		d_instantiate (dret, inode);
+			//umsdos_lookup_patch_new(dret, &info);
+        		dret->d_op = &umsdos_dentry_operations;
+        		//check_dentry_path (dret, "umsdos_readdir_x calculated dret with faked inode");
+		}
+
+		ret = PTR_ERR(dret);
+		if (IS_ERR(dret))
+			break;
 
 Printk (("Found %s/%s, ino=%ld, flags=%x\n",
 dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
@@ -239,8 +274,8 @@
 				 cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {
 				pos = cur_f_pos;
 			}
-Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
-dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));
+Printk((KERN_DEBUG "umsdos_readdir_x: got %s/%s (%s), ino=%ld, pos=%lld\n",
+dret->d_parent->d_name.name, dret->d_name.name, entry.name, inode->i_ino, cur_f_pos));
 			if (u_entry != NULL)
 				*u_entry = entry;
 			dput(dret);
@@ -251,23 +286,6 @@
 		dput(dret);
 		continue;
 
-	remove_name:
-		/* #Specification:  umsdos / readdir / not in MSDOS
-		 * During a readdir operation, if the file is not
-		 * in the MS-DOS directory any more, the entry is
-		 * removed from the EMD file silently.
-		 */
-#ifdef UMSDOS_PARANOIA
-printk("umsdos_readdir_x: %s/%s out of sync, erasing\n",
-filp->f_dentry->d_name.name, info.entry.name);
-#endif
-		ret = umsdos_delentry(filp->f_dentry, &info, 
-					S_ISDIR(info.entry.mode));
-		if (ret)
-			printk(KERN_WARNING 
-				"umsdos_readdir_x: delentry %s, err=%d\n",
-				info.entry.name, ret);
-		goto clean_up;
 	}
 	/*
 	 * If the fillbuf has failed, f_pos is back to 0.
@@ -295,7 +313,7 @@
  * Return a negative value from linux/errno.h.
  * Return 0 or positive if successful.
  */
- 
+
 static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
 {
 	struct inode *dir = filp->f_dentry->d_inode;
@@ -316,8 +334,13 @@
 		if (bufk.count == 0)
 			break;
 		count += bufk.count;
+
+#ifdef UMSDOS_GETDENTS_MAX		
+		if (count > UMSDOS_GETDENTS_MAX)
+			break;
+#endif
 	}
-	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", 
+	Printk ((KERN_DEBUG "UMSDOS_readdir out %d count %d pos %Ld\n", 
 		ret, count, filp->f_pos));
 	return count ? : ret;
 }
@@ -371,8 +394,8 @@
 	inode->i_atime = entry->atime;
 	inode->i_ctime = entry->ctime;
 	inode->i_mtime = entry->mtime;
-	inode->i_uid = entry->uid;
-	inode->i_gid = entry->gid;
+	inode->i_uid = (uid_t) entry->uid;
+	inode->i_gid = (gid_t) entry->gid;
 
 	/* #Specification: umsdos / i_nlink
 	 * The nlink field of an inode is maintained by the MSDOS file system
@@ -452,6 +475,13 @@
 #endif
 
 	umsdos_startlookup (dir);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_lookup_x: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	if (umsdos_is_pseudodos (dir, dentry)) {
 		/* #Specification: pseudo root / lookup(DOS)
 		 * A lookup of DOS in the pseudo root will always succeed
@@ -479,8 +509,8 @@
 Printk (("lookup %.*s pos %lu ret %d len %d ", 
 info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
 
-	/* do a real lookup to get the short name ... */
-	dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+	/* do a real lookup to get the entry name ... */
+	dret = umsdos_fake_or_lfn(dentry->d_parent, &info);
 	ret = PTR_ERR(dret);
 	if (IS_ERR(dret)) {
 printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n", 
@@ -784,6 +814,44 @@
 }	
 
 
+/*
+ * First try to lookup mangled name, it that fails, try entry name
+ * returns dentry of found file, which you need to dput() later 
+ * (eg. behaves same as umsdos_covered())
+ */
+struct dentry *umsdos_fake_or_lfn (struct dentry *parent, struct umsdos_info *info)
+{
+	struct dentry *dret;
+
+//printk (" umsdos_fake_or_lfn 1st ide patch_fat_cache\n");
+	patch_fat_cache (parent, info);
+//printk (" umsdos_fake_or_lfn 1st ide umsdos_covered\n");
+	dret = umsdos_covered(parent, info->fake.fname,
+				        info->fake.len);
+//printk (" umsdos_fake_or_lfn 1st (%s) i_fix_loc=%u\n", info->fake.fname, MSDOS_I(parent->d_inode)->i_fix_loc);
+
+	if (IS_ERR(dret))	/* should not happen - ENOMEM, etc */
+		goto out;
+
+	if (dret->d_inode)	/* we've found mangled name, prefer that ! */
+		goto out;
+
+	/* negative cache, dput() it and try LFN */
+	dput (dret);
+
+//printk (" umsdos_fake_or_lfn 2nd ide patch_fat_cache\n");
+	patch_fat_cache (parent, info);
+//printk (" umsdos_fake_or_lfn 2nd ide umsdos_covered\n");
+	dret = umsdos_covered(parent, info->entry.name,
+				 info->entry.name_len);
+//printk (" umsdos_fake_or_lfn 2nd (%s) i_fix_loc=%u\n", info->entry.name, MSDOS_I(parent->d_inode)->i_fix_loc);
+
+out:
+	MSDOS_I(parent->d_inode)->i_fix_loc = 0;	/* cleanup */
+	return dret;
+}
+
+
 struct file_operations umsdos_dir_operations =
 {
 	read:		generic_read_dir,
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/emd.c linux-mynew/fs/umsdos/emd.c
--- linux-2.4.19-PRISTINE/fs/umsdos/emd.c	Sat Oct 20 20:12:03 2001
+++ linux-mynew/fs/umsdos/emd.c	Sun Aug 11 12:19:38 2002
@@ -23,8 +23,8 @@
 	p->name_len = q->name_len;
 	p->flags = q->flags;
 	p->nlink = cpu_to_le16(q->nlink);
-	p->uid = cpu_to_le16(q->uid);
-	p->gid = cpu_to_le16(q->gid);
+	p->uid = cpu_to_le32(q->uid);
+	p->gid = cpu_to_le32(q->gid);
 	p->atime = cpu_to_le32(q->atime);
 	p->mtime = cpu_to_le32(q->mtime);
 	p->ctime = cpu_to_le32(q->ctime);
@@ -38,9 +38,8 @@
 	p->name[p->name_len]='\0';
 	p->flags = q->flags;
 	p->nlink = le16_to_cpu (q->nlink);
-	/* FIXME -- 32bit UID/GID issues */
-	p->uid = le16_to_cpu (q->uid);
-	p->gid = le16_to_cpu (q->gid);
+	p->uid = le32_to_cpu (q->uid);
+	p->gid = le32_to_cpu (q->gid);
 	p->atime = le32_to_cpu (q->atime);
 	p->mtime = le32_to_cpu (q->mtime);
 	p->ctime = le32_to_cpu (q->ctime);
@@ -92,7 +91,7 @@
 	int err = PTR_ERR(demd);
 
 	if (IS_ERR(demd)) {
-		printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",
+		printk(KERN_WARNING "umsdos_make_emd: can't get dentry in %s, err=%d\n",
 			parent->d_name.name, err);
 		goto out;
 	}
@@ -105,7 +104,7 @@
 Printk(("umsdos_make_emd: creating EMD %s/%s\n",
 parent->d_name.name, demd->d_name.name));
 
-	err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
+	err = vfat_create(parent->d_inode, demd, S_IFREG | 0777);
 	if (err) {
 		printk (KERN_WARNING
 			"umsdos_make_emd: create %s/%s failed, err=%d\n",
@@ -145,7 +144,7 @@
 	p = (struct umsdos_dirent*)(kmap(page)+offs);
 
 	/* if this is an invalid entry (invalid name length), ignore it */
-	if( p->name_len > UMSDOS_MAXNAME )
+	if( p->name_len >= UMSDOS_MAXNAME )
 	{
 		printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len);
 		p->name_len = 0; 
@@ -209,6 +208,16 @@
 	struct page *page, *page2 = NULL;
 	int offs;
 
+	Printk ((KERN_DEBUG "/mn/ umsdos_writeentry in %s for %s (uid=%d, gid=%d, mode=%o) free=%d\n", parent->d_name.name, info->entry.name, info->entry.uid, info->entry.gid, info->entry.mode, free_entry));
+
+#ifdef UMSDOS_PARANOIA
+	ret = -ENAMETOOLONG;
+	if (info->entry.name_len >= UMSDOS_MAXNAME) {
+		printk (KERN_WARNING "umsdos_writeentry: Uh-oh, invalid EMD entry with size %d\n", info->entry.name_len);
+		goto out;
+	}
+#endif		
+
 	emd_dentry = umsdos_get_emd_dentry(parent);
 	ret = PTR_ERR(emd_dentry);
 	if (IS_ERR(emd_dentry))
@@ -312,7 +321,7 @@
 out_unlock:
 	UnlockPage(page);
 	page_cache_release(page);
-	printk ("UMSDOS:  problem with EMD file:  can't write\n");
+	printk (KERN_WARNING "UMSDOS:  problem with EMD file:  can't write\n");
 	goto out_dput;
 }
 
@@ -350,8 +359,8 @@
 	struct inode *emd_dir;
 	int ret = -ENOENT;
 	struct {
-		off_t posok;	/* Position available to store the entry */
-		off_t one;	/* One empty position -> maybe <- large enough */
+		loff_t posok;	/* Position available to store the entry */
+		loff_t one;	/* One empty position -> maybe <- large enough */
 	} empty;
 	int found = 0;
 	int empty_size = 0;
@@ -363,6 +372,14 @@
 	char *p = NULL;
 	loff_t pos = 0;
 
+#ifdef UMSDOS_PARANOIA
+	ret = -ENAMETOOLONG;
+	if (info->entry.name_len >= UMSDOS_MAXNAME) {
+		printk (KERN_WARNING "umsdos_find: Uh-oh, invalid EMD entry with size %d\n", info->entry.name_len);
+		goto out_dput;
+	}
+#endif		
+
 	/* make sure there's an EMD file ... */
 	ret = -ENOENT;
 	emd_dir = demd->d_inode;
@@ -640,6 +657,7 @@
 	ret = PTR_ERR(demd);
 	if (IS_ERR(demd))
 		goto out;
+		
 	ret = umsdos_find (demd, info);
 	if (ret)
 		goto out;
@@ -658,3 +676,107 @@
 	Printk (("umsdos_findentry: returning %d\n", ret));
 	return ret;
 }
+
+/*
+ * Must be called with the parent lock held.
+ */
+int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+	struct dentry *demd;
+	struct address_space *mapping;
+	struct page *page;
+	int ret = 0;
+	struct umsdos_dirent *entry;
+	int offs;
+
+Printk ((KERN_DEBUG "umsdos_notify_change_locked: entering for %s/%s (%d)\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
+
+#ifdef UMSDOS_DEBUG_VERBOSE
+	printk(KERN_DEBUG "UMSDOS_notify_change for %s/%s ", dentry->d_parent->d_name.name, dentry->d_name.name);
+	if (attr->ia_valid & ATTR_MODE) { printk ("MODE=%0o ", attr->ia_mode); }
+	if (attr->ia_valid & ATTR_UID) { printk ("UID=%u ", attr->ia_uid); }
+	if (attr->ia_valid & ATTR_GID) { printk ("GID=%u ",attr->ia_gid); }
+	if (attr->ia_valid & ATTR_SIZE) { printk ("SIZE=%llu ", attr->ia_size); }
+	if (attr->ia_valid & ATTR_ATIME) { printk ("ATIME=%lu ", attr->ia_atime); }
+	if (attr->ia_valid & ATTR_MTIME) { printk ("MTIME=%lu ", attr->ia_mtime); }
+	if (attr->ia_valid & ATTR_CTIME) { printk ("CTIME=%lu ", attr->ia_ctime); }
+	if (attr->ia_valid & ATTR_ATIME_SET) { printk ("ATTR_ATIME_SET "); }
+	if (attr->ia_valid & ATTR_MTIME_SET) { printk ("ATTR_MTIME_SET "); }
+	if (attr->ia_valid & ATTR_FORCE) { printk ("ATTR_FORCE "); }
+	if (attr->ia_valid & ATTR_ATTR_FLAG) { printk ("ATTR_ATTR_FLAG "); }
+	printk (".\n");
+#endif
+
+
+	if (inode->i_nlink == 0)
+		goto out;
+	if (inode->i_ino == UMSDOS_ROOT_INO)
+		goto out;
+
+	/* get the EMD file dentry */
+	demd = umsdos_get_emd_dentry(dentry->d_parent);
+	ret = PTR_ERR(demd);
+	if (IS_ERR(demd))
+		goto out;
+	ret = 0;
+	/* don't do anything if directory is not promoted to umsdos yet */
+	if (!demd->d_inode) { 
+		Printk((KERN_DEBUG
+			"UMSDOS_notify_change: no EMD file %s/%s\n",
+			demd->d_parent->d_name.name, demd->d_name.name));
+		goto out_dput;
+	}
+
+	/* don't do anything if this is the EMD itself */
+	if (inode == demd->d_inode)
+		goto out_dput;
+
+	/* This inode is not a EMD file nor an inode used internally
+	 * by MSDOS, so we can update its status.
+	 * See emd.c
+	 */
+
+	/* Read only the start of the entry since we don't touch the name */
+	mapping = demd->d_inode->i_mapping;
+	offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;
+	ret = -ENOMEM;
+	page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);
+	if (!page)
+		goto out_dput;
+	ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
+	if (ret)
+		goto out_unlock;
+	entry = (struct umsdos_dirent *) (page_address(page) + offs);
+	if (attr->ia_valid & ATTR_UID)
+		entry->uid = cpu_to_le32(attr->ia_uid);
+	if (attr->ia_valid & ATTR_GID)
+		entry->gid = cpu_to_le32(attr->ia_gid);
+	if (attr->ia_valid & ATTR_MODE)
+		entry->mode = cpu_to_le16(attr->ia_mode);
+	if (attr->ia_valid & ATTR_ATIME)
+		entry->atime = cpu_to_le32(attr->ia_atime);
+	if (attr->ia_valid & ATTR_MTIME)
+		entry->mtime = cpu_to_le32(attr->ia_mtime);
+	if (attr->ia_valid & ATTR_CTIME)
+		entry->ctime = cpu_to_le32(attr->ia_ctime);
+	entry->nlink = cpu_to_le16(inode->i_nlink);
+	ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
+	if (ret)
+		printk(KERN_WARNING
+			"umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
+			dentry->d_parent->d_name.name, dentry->d_name.name,ret);
+
+	/* #Specification: notify_change / msdos fs
+	 * notify_change operation are done only on the
+	 * EMD file. The msdos fs is not even called.
+	 */
+out_unlock:
+	UnlockPage(page);
+	page_cache_release(page);
+out_dput:
+	dput(demd);
+out:
+	return ret;
+}
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/inode.c linux-mynew/fs/umsdos/inode.c
--- linux-2.4.19-PRISTINE/fs/umsdos/inode.c	Sat Oct 20 20:14:28 2001
+++ linux-mynew/fs/umsdos/inode.c	Tue Aug 27 00:17:12 2002
@@ -24,20 +24,20 @@
 
 struct dentry *saved_root;	/* Original root if changed */
 struct inode *pseudo_root;	/* Useful to simulate the pseudo DOS */
-					/* directory. See UMSDOS_readdir_x() */
+				/* directory. See UMSDOS_readdir_x() */
 
 static struct dentry *check_pseudo_root(struct super_block *);
 
 
 void UMSDOS_put_inode (struct inode *inode)
 {
-	PRINTK ((KERN_DEBUG 
+	Printk ((KERN_DEBUG 
 		"put inode %p (%lu) pos %lu count=%d\n"
 		 ,inode, inode->i_ino
 		 ,inode->u.umsdos_i.pos
 		 ,atomic_read(&inode->i_count)));
 
-	if (inode == pseudo_root) {
+	if (pseudo_root && inode == pseudo_root) {
 		Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)));
 	}
 
@@ -55,11 +55,136 @@
 		saved_root = NULL;
 		pseudo_root = NULL;
 	}
-	msdos_put_super (sb);
+	fat_put_super (sb);
 }
 
 
 /*
+ * next call to vfat_* functions will use EMD-based inode seed
+ */
+int patch_fat_cache (struct dentry *parent, struct umsdos_info *info)
+{
+	int ino;
+	int ret=0;
+	struct dentry *demd;
+	
+	MSDOS_I(parent->d_inode)->i_fix_loc = 0;	/* find EMD file itself via normal lookup ! */
+	demd = umsdos_get_emd_dentry(parent);
+	
+	ret = get_fat_ino (demd, (loff_t) info->f_pos, &ino);
+	Printk ((KERN_DEBUG "patch_fat_cache in dir %s pos %lu gives inode seed %u.", parent->d_name.name, info->f_pos, ino));
+	if (ret) {
+		printk (" ERROR %d !\n", ret);
+	} else {
+		MSDOS_I(parent->d_inode)->i_fix_loc = ino;
+		Printk ((" patched.\n"));
+	}
+
+	dput(demd);
+	return ret;
+}
+
+
+/*
+ * calculates FAT ino "position seed" for fat_iget() and fat_attach()
+ */
+int get_fat_ino (struct dentry *demd, loff_t pos, int *ino)
+{
+	struct inode *dir;
+	struct super_block *sb;
+	struct msdos_sb_info *sbi;
+	int sector, offset;
+
+	if (!demd) { 
+		printk (KERN_ERR "get_fat_ino: no demd!");
+		return -EIO;
+	}
+	dir = demd->d_inode;
+	if (!dir) {
+		printk (KERN_ERR "get_fat_ino: no dir inode for %s/%s!", demd->d_parent->d_name.name, demd->d_name.name);
+		return -EIO;
+	}
+	sb = dir->i_sb;
+	sbi = MSDOS_SB(sb);
+
+	offset = pos;
+	if ((sector = fat_bmap(dir,offset >> sb->s_blocksize_bits)) == -1)
+		return -EIO;
+
+	offset &= sb->s_blocksize - 1;
+
+	/* MSDOS directory entry is 32 bytes, while UMSDOS_REC_SIZE is 64 bytes
+	 * so, to avoid recalculation, we might take exactly one bit more
+	 * using *ino = (sector << (sbi->dir_per_block_bits-1)) + (offset >> (MSDOS_DIR_BITS+1));
+	 *
+	 * however, we leave it at 32 bytes (same as MSDOS), in order to avoid heavy kludgery of FAT
+	 * shared code - it should just waste one bit of hash accuracy, but let us use same stuff and 
+	 * fast paths...
+	 */
+
+	if (!ino) {
+		printk (KERN_ERR "UMSDOS: get_fat_inode: ino pointer is NULL!!! Should never happen!\n");
+		return -EIO;
+	}
+	*ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+	Printk ((KERN_DEBUG "get_fat_ino: calculating for pos=%llu in %s/%s *** sector=%u, offset=%u ==> inode seed=%u\n", pos, demd->d_parent->d_name.name, demd->d_name.name, sector, offset, *ino));
+	return 0;
+}
+
+/*
+ * generates the pseudo-FAT_DE (directory entry) so the fat_fill_inode()
+ * has data to work on and fill our inode
+ */
+void fake_fat_de (struct msdos_dir_entry *de, struct umsdos_info *info)
+{
+	de->lcase = 0;
+	strcpy (de->name, "FAKEINFO.UMS");
+	de->ctime_ms = 0; de->ctime = 0; 
+	de->cdate = 0; de->adate = 0;
+	de->time = 0; de->date = 0;
+
+	de->starthi = 0;
+	de->start = 0;
+	de->size = 0xdeadbeef;	/* marker only -- says this DE needs to be refetched */
+	de->attr = S_ISDIR(info->entry.mode) ? ATTR_DIR : 0;
+}
+
+/*
+ * try to lookup current entry by demd disk sector and pos in FAT cache
+ * if it succeeds, great! if not, create new one using iunique() and put it
+ * in FAT cache */
+ 
+struct inode *uvfat_build_inode (struct inode *dir, struct dentry *demd, loff_t pos, struct umsdos_info *info)
+{
+	struct inode *inode = ERR_PTR(-EIO);
+	struct super_block *sb = dir->i_sb;
+	int ino;
+	struct msdos_dir_entry de;
+	                
+	if (get_fat_ino(demd, pos, &ino) < 0)
+		goto out;
+	
+	inode = fat_iget(sb, ino);
+	if (inode)
+		goto out;
+	inode = new_inode(sb);
+	if (!inode) {
+		inode = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
+	Printk ((KERN_DEBUG "uvfat_build_inode: ino seed=%d gives iunique() i_ino=%lu\n", ino, inode->i_ino));
+	fake_fat_de (&de, info);
+	fat_fill_inode(inode, &de);
+	
+	fat_attach(inode, ino);
+	insert_inode_hash(inode);
+out:
+	return inode;
+}
+
+ 
+/*
  * Complete the setup of a directory dentry based on its
  * EMD/non-EMD status.  If it has an EMD, then plug the
  * umsdos function table. If not, use the msdos one.
@@ -77,13 +202,14 @@
 	inode->u.umsdos_i.dir_info.creating = 0;
 	inode->u.umsdos_i.dir_info.pid = 0;
 
-	inode->i_op = &umsdos_rdir_inode_operations;
-	inode->i_fop = &umsdos_rdir_operations;
 	if (umsdos_have_emd(dir)) {
 Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
 dir->d_parent->d_name.name, dir->d_name.name));
 		inode->i_op = &umsdos_dir_inode_operations;
 		inode->i_fop = &umsdos_dir_operations;
+	} else {
+		inode->i_op = &umsdos_rdir_inode_operations;
+		inode->i_fop = &umsdos_rdir_operations;
 	}
 }
 
@@ -91,7 +217,7 @@
 /*
  * Add some info into an inode so it can find its owner quickly
  */
-void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
+void umsdos_set_dirinfo_new (struct dentry *dentry, loff_t f_pos)
 {
 	struct inode *inode = dentry->d_inode;
 	struct dentry *demd;
@@ -126,7 +252,7 @@
  * is tagged to this inode. It allows operations such as
  * notify_change to be handled.
  */
-void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
+void umsdos_patch_dentry_inode(struct dentry *dentry, loff_t f_pos)
 {
 	struct inode *inode = dentry->d_inode;
 
@@ -164,12 +290,21 @@
 	struct dentry *temp, *old_dentry = NULL;
 	int ret;
 
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_notify_change: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len,
 				&info);
 	if (ret)
 		goto out;
 	ret = umsdos_findentry (dentry->d_parent, &info, 0);
 	if (ret) {
+		if (ret == -ENOENT)
+			ret = fat_notify_change (dentry, attr);
+		else
 printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
 		goto out;
@@ -185,8 +320,7 @@
 dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname));
 	
 		/* Do a real lookup to get the short name dentry */
-		temp = umsdos_covered(dentry->d_parent, info.fake.fname,
-						info.fake.len);
+		temp = umsdos_fake_or_lfn(dentry->d_parent, &info);
 		ret = PTR_ERR(temp);
 		if (IS_ERR(temp))
 			goto out;
@@ -211,7 +345,7 @@
 	ret = umsdos_notify_change_locked(dentry, attr);
 	up(&dir->i_sem);
 	if (ret == 0)
-		ret = inode_setattr (inode, attr);
+		inode_setattr (inode, attr);
 out:
 	if (old_dentry)
 		dput (dentry);	/* if we had to use fake dentry for hardlinks, dput() it now */
@@ -219,92 +353,6 @@
 }
 
 
-/*
- * Must be called with the parent lock held.
- */
-int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
-{
-	struct inode *inode = dentry->d_inode;
-	struct dentry *demd;
-	struct address_space *mapping;
-	struct page *page;
-	int ret = 0;
-	struct umsdos_dirent *entry;
-	int offs;
-
-Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
-
-	if (inode->i_nlink == 0)
-		goto out;
-	if (inode->i_ino == UMSDOS_ROOT_INO)
-		goto out;
-
-	/* get the EMD file dentry */
-	demd = umsdos_get_emd_dentry(dentry->d_parent);
-	ret = PTR_ERR(demd);
-	if (IS_ERR(demd))
-		goto out;
-	ret = 0;
-	/* don't do anything if directory is not promoted to umsdos yet */
-	if (!demd->d_inode) { 
-		Printk((KERN_DEBUG
-			"UMSDOS_notify_change: no EMD file %s/%s\n",
-			demd->d_parent->d_name.name, demd->d_name.name));
-		goto out_dput;
-	}
-
-	/* don't do anything if this is the EMD itself */
-	if (inode == demd->d_inode)
-		goto out_dput;
-
-	/* This inode is not a EMD file nor an inode used internally
-	 * by MSDOS, so we can update its status.
-	 * See emd.c
-	 */
-
-	/* Read only the start of the entry since we don't touch the name */
-	mapping = demd->d_inode->i_mapping;
-	offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;
-	ret = -ENOMEM;
-	page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);
-	if (!page)
-		goto out_dput;
-	ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
-	if (ret)
-		goto out_unlock;
-	entry = (struct umsdos_dirent *) (page_address(page) + offs);
-	if (attr->ia_valid & ATTR_UID)
-		entry->uid = cpu_to_le16(attr->ia_uid);
-	if (attr->ia_valid & ATTR_GID)
-		entry->gid = cpu_to_le16(attr->ia_gid);
-	if (attr->ia_valid & ATTR_MODE)
-		entry->mode = cpu_to_le16(attr->ia_mode);
-	if (attr->ia_valid & ATTR_ATIME)
-		entry->atime = cpu_to_le32(attr->ia_atime);
-	if (attr->ia_valid & ATTR_MTIME)
-		entry->mtime = cpu_to_le32(attr->ia_mtime);
-	if (attr->ia_valid & ATTR_CTIME)
-		entry->ctime = cpu_to_le32(attr->ia_ctime);
-	entry->nlink = cpu_to_le16(inode->i_nlink);
-	ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
-	if (ret)
-		printk(KERN_WARNING
-			"umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name,ret);
-
-	/* #Specification: notify_change / msdos fs
-	 * notify_change operation are done only on the
-	 * EMD file. The msdos fs is not even called.
-	 */
-out_unlock:
-	UnlockPage(page);
-	page_cache_release(page);
-out_dput:
-	dput(demd);
-out:
-	return ret;
-}
 
 
 /*
@@ -312,22 +360,33 @@
  */
 void UMSDOS_write_inode (struct inode *inode, int wait)
 {
-	struct iattr newattrs;
+	Printk ((KERN_DEBUG "UMSDOS_write inode %lu xTIME update\n", inode->i_ino));
 
 	fat_write_inode (inode, wait);
-	newattrs.ia_mtime = inode->i_mtime;
-	newattrs.ia_atime = inode->i_atime;
-	newattrs.ia_ctime = inode->i_ctime;
-	newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
-	/*
-	 * UMSDOS_notify_change is convenient to call here
-	 * to update the EMD entry associated with this inode.
-	 * But it has the side effect to re"dirt" the inode.
-	 */
-/*      
- * UMSDOS_notify_change (inode, &newattrs);
-
- * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work.  We need to remove ourselves from list on dirty inodes. /mn/ */
+	
+#if 0
+	checkd_inode (inode);
+	/* unfortunately, inode->i_dentry is often empty, so we cannot update EMD */
+{
+	struct list_head *cur = inode->i_dentry.prev;
+	struct dentry *dentry = list_entry (cur, struct dentry, d_alias);
+	if (dentry && dentry->d_inode && dentry->d_parent && dentry->d_parent->d_inode) {
+		struct inode *dir = dentry->d_parent->d_inode;
+		struct iattr newattrs;
+
+		printk (KERN_DEBUG "UMSDOS_write_inode update EMD xTimes for %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name);
+
+		newattrs.ia_mtime = inode->i_mtime;
+		newattrs.ia_atime = inode->i_atime;
+		newattrs.ia_ctime = inode->i_ctime;
+		newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
+
+		down(&dir->i_sem);
+		umsdos_notify_change_locked(dentry, &newattrs);
+		up(&dir->i_sem);
+	}
+}
+#endif
 }
 
 
@@ -346,7 +405,7 @@
 	int ret;
 	ret = fat_statfs (sb, buf);
 	if (!ret)	
-		buf->f_namelen = UMSDOS_MAXNAME;
+		buf->f_namelen = UMSDOS_MAXNAME - 1;
 	return ret;
 }
 
@@ -363,17 +422,16 @@
 	 * Call msdos-fs to mount the disk.
 	 * Note: this returns res == sb or NULL
 	 */
-	res = msdos_read_super (sb, data, silent);
+	res = vfat_read_super (sb, data, silent);
 
 	if (!res)
 		goto out_fail;
 
-	printk (KERN_INFO "UMSDOS 0.86k "
+	printk (KERN_INFO "UMSDOS/UVFAT Alpha 0.95 "
 		"(compatibility level %d.%d, fast msdos)\n", 
 		UMSDOS_VERSION, UMSDOS_RELEASE);
 
 	sb->s_op = &umsdos_sops;
-	MSDOS_SB(sb)->options.dotsOK = 0;	/* disable hidden==dotfile */
 
 	/* install our dentry operations ... */
 	sb->s_root->d_op = &umsdos_dentry_operations;
@@ -396,7 +454,7 @@
 	return sb;
 
 out_fail:
-	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
+	printk(KERN_INFO "UMSDOS: vfat_read_super failed, mount aborted.\n");
 	return NULL;
 }
 
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/ioctl.c linux-mynew/fs/umsdos/ioctl.c
--- linux-2.4.19-PRISTINE/fs/umsdos/ioctl.c	Sat Oct 20 20:12:03 2001
+++ linux-mynew/fs/umsdos/ioctl.c	Sun Aug 11 12:18:14 2002
@@ -81,6 +81,12 @@
 Printk(("UMSDOS_ioctl_dir: %s/%s, cmd=%d, data=%08lx\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr));
 
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_ioctl_dir: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	/* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
 	if (cmd != UMSDOS_GETVERSION
 	    && cmd != UMSDOS_READDIR_DOS
@@ -92,7 +98,8 @@
 	    && cmd != UMSDOS_UNLINK_DOS
 	    && cmd != UMSDOS_RMDIR_DOS
 	    && cmd != UMSDOS_STAT_DOS
-	    && cmd != UMSDOS_DOS_SETUP)
+	    && cmd != UMSDOS_DOS_SETUP
+	    && cmd != VFAT_IOCTL_READDIR_BOTH)
 		return fat_dir_ioctl (dir, filp, cmd, data_ptr);
 
 	/* #Specification: ioctl / access
@@ -173,7 +180,7 @@
 			goto read_dput;
 
 		while (pos < demd->d_inode->i_size) {
-			off_t f_pos = pos;
+			loff_t f_pos = pos;
 			struct umsdos_dirent entry;
 			struct umsdos_info info;
 
@@ -260,7 +267,7 @@
 		goto out;
 	}
 	else if (cmd == UMSDOS_RENAME_DOS) {
-		struct dentry *old_dentry, *new_dentry;		/* FIXME */
+		struct dentry *old_dentry, *new_dentry;		/* FIXME? */
 
 		/* #Specification: ioctl / UMSDOS_RENAME_DOS
 		 * A file or directory is renamed in a DOS directory
@@ -285,7 +292,7 @@
 printk("umsdos_ioctl: renaming %s/%s to %s/%s\n",
 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
-			ret = msdos_rename (dir, old_dentry, dir, new_dentry);
+			ret = vfat_rename (dir, old_dentry, dir, new_dentry);
 			d_drop(new_dentry);
 			d_drop(old_dentry);
 			dput(new_dentry);
@@ -325,7 +332,7 @@
 
 		/* #Specification: ioctl / UMSDOS_UNLINK_DOS
 		 * The dos_dirent field of the struct umsdos_ioctl is used to
-		 * execute a msdos_unlink operation. The d_name and d_reclen
+		 * execute a vfat_unlink operation. The d_name and d_reclen
 		 * fields are used.
 		 * 
 		 * Return 0 if success.
@@ -339,7 +346,7 @@
 		if (temp->d_inode) {
 			ret = -EISDIR;
 			if (!S_ISDIR(temp->d_inode->i_mode))
-				ret = msdos_unlink (dir, temp);
+				ret = vfat_unlink (dir, temp);
 			if (!ret)
 				d_delete(temp);
 		}
@@ -351,7 +358,7 @@
 
 		/* #Specification: ioctl / UMSDOS_RMDIR_DOS
 		 * The dos_dirent field of the struct umsdos_ioctl is used to
-		 * execute a msdos_rmdir operation. The d_name and d_reclen
+		 * execute a vfat_rmdir operation. The d_name and d_reclen
 		 * fields are used.
 		 * 
 		 * Return 0 if success.
@@ -365,7 +372,7 @@
 		if (temp->d_inode) {
 			ret = -ENOTDIR;
 			if (S_ISDIR(temp->d_inode->i_mode))
-				ret = msdos_rmdir (dir, temp);
+				ret = vfat_rmdir (dir, temp);
 			if (!ret)
 				d_delete(temp);
 		}
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/mangle.c linux-mynew/fs/umsdos/mangle.c
--- linux-2.4.19-PRISTINE/fs/umsdos/mangle.c	Mon Jan  1 19:25:22 2001
+++ linux-mynew/fs/umsdos/mangle.c	Sat Aug 10 16:17:41 2002
@@ -15,8 +15,11 @@
 /* (This file is used outside of the kernel) */
 #ifndef __KERNEL__
 #define KERN_WARNING
+#include <string.h>
 #endif
 
+static int was_warned = 0;
+
 /*
  * Complete the mangling of the MSDOS fake name
  * based on the position of the entry in the EMD file.
@@ -88,10 +91,12 @@
 
 #define lookup12 (lookup3+9)
 		entry_num = info->f_pos / UMSDOS_REC_SIZE;
-		if (entry_num > (9* 32 * 32)){
+
+		if (!was_warned && (entry_num > (9* 32 * 32))){
 			printk (KERN_WARNING "UMSDOS: more than 9216 files in a directory.\n"
 				"This may break the mangling strategy.\n"
 				"Not a killer problem. See doc.\n");
+			was_warned = 1;
 		}
 		*pt++ = '.';
 		*pt++ = lookup3 [(entry_num >> 10) & 31];
@@ -150,7 +155,7 @@
 	 * truncated. This makes it conformant with the other file system
 	 * of Linux (minix and ext2 at least).
 	 */
-	if (len > UMSDOS_MAXNAME)
+	if (len >= UMSDOS_MAXNAME)
 		len = UMSDOS_MAXNAME;
 	{
 		const char *firstpt = NULL;	/* First place we saw a "." in fname */
@@ -210,6 +215,7 @@
 		 * This speeds up handling of long names.
 		 * The position of the last point is no more necessary anyway.
 		 */
+		ivldchar = 2; /* mangle all short or long names */
 		if (len <= (8 + 1 + 3)) {
 			const char *pt = fname;
 			const char *endpt = fname + len;
@@ -273,8 +279,6 @@
 				}
 				pt++;
 			}
-		} else {
-			ivldchar = 1;
 		}
 		if (ivldchar
 		    || (firstpt == NULL && len > 8)
@@ -317,7 +321,7 @@
 			for (i = 0; i < msdos_len; i++, pt++)
 				*pt = lkp[(unsigned char) (*pt)];
 			*pt = '\0';	/* GLU  We force null termination. */
-			info->msdos_reject = 1;
+			info->msdos_reject = ivldchar;
 			/*
 			 * The numeric extension is added only when we know
 			 * the position in the EMD file, in umsdos_newentry(),
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/namei.c linux-mynew/fs/umsdos/namei.c
--- linux-2.4.19-PRISTINE/fs/umsdos/namei.c	Sat Oct 20 20:12:03 2001
+++ linux-mynew/fs/umsdos/namei.c	Tue Aug 27 20:08:03 2002
@@ -242,8 +242,15 @@
 	struct dentry *fake;
 	struct inode *inode;
 	int ret;
+	int trymangle = 0;
 	struct umsdos_info info;
 
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_create_any: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	ret = umsdos_nevercreat (dir, dentry, -EEXIST);
 	if (ret)
 		goto out;
@@ -263,24 +270,59 @@
 	if (ret)
 		goto out;
 
-	/* do a real lookup to get the short name dentry */
-	fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+	/* do a real lookup to get the entry name dentry */
+	fake = umsdos_covered(dentry->d_parent, info.entry.name, info.entry.name_len);
 	ret = PTR_ERR(fake);
 	if (IS_ERR(fake))
 		goto out_remove;
+	
+	if (fake->d_inode) {	/* already used, we need to resort to mangling! */ 
+		trymangle = 1;	/* (probably filename only differs in case) */
+		Printk (("umsdos_create_any: filename %s/%s already used, trying to mangle\n",
+			fake->d_parent->d_name.name, fake->d_name.name));
+	}
+
+mangle:
+	if (trymangle) {
+		dput(fake);
+		fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+		ret = PTR_ERR(fake);
+		if (IS_ERR(fake))
+			goto out_remove;
+		Printk (("umsdos_create_any: using mangle %s/%s\n",
+			fake->d_parent->d_name.name, fake->d_name.name));
+	}
 
 	/* should not exist yet ... */
 	ret = -EEXIST;
 	if (fake->d_inode)
 		goto out_remove_dput;
 
-	ret = msdos_create (dir, fake, S_IFREG | 0777);
+	ret = patch_fat_cache (dentry->d_parent, &info);
+	if (ret)
+		goto out_remove_dput;
+		
+	ret = vfat_create (dir, fake, S_IFREG | 0777);
+//printk (KERN_DEBUG "i_patched on inode %lu aft=%d\n", fake->d_inode->i_ino, fake->d_inode->u.umsdos_i.i_patched);
+//check_dentry_path (fake, "umsdos_create_any fake after vfat_create");
+
+
+	if (ret && !trymangle) {	/* failed to create file -- maybe illegal 
+					 * chars like ":" ? Try mangling.
+					 */
+		trymangle = 1;
+		Printk (("umsdos_create_any: failed to create %s/%s, trying to mangle\n",
+			fake->d_parent->d_name.name, fake->d_name.name));
+		goto mangle;
+	}
+
 	if (ret)
 		goto out_remove_dput;
 
 	inode = fake->d_inode;
 	atomic_inc(&inode->i_count);
 	d_instantiate (dentry, inode);
+
 	dput(fake);
 	if (atomic_read(&inode->i_count) > 1) {
 		printk(KERN_WARNING
@@ -289,17 +331,19 @@
 			inode->i_ino, atomic_read(&inode->i_count));
 	}
 	umsdos_lookup_patch_new(dentry, &info);
+//check_dentry_path (dentry, "umsdos_create_any end dentry");
 
 out:
 	return ret;
 
 	/* Creation failed ... remove the EMD entry */
 out_remove_dput:
+	printk (KERN_WARNING "umsdos_create_any: error creating; fake is %s/%s\n", fake->d_parent->d_name.name, fake->d_name.name);
 	dput(fake);
 out_remove:
 	if (ret == -EEXIST)
-		printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
-			dentry->d_parent->d_name.name, info.fake.fname);
+		printk(KERN_WARNING "UMSDOS: out of sync (%d), deleting %s/%s\n", ret,
+			dentry->d_parent->d_name.name, info.entry.name);
 	umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
 	goto out;
 }
@@ -349,6 +393,16 @@
 	struct umsdos_info old_info;
 	struct umsdos_info new_info;
 
+	ret = -ENAMETOOLONG;
+	if (old_dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_rename_f: Uh-oh, vfat_rename on old entry %s with size %d\n", old_dentry->d_name.name, old_dentry->d_name.len));
+		goto out;
+	}
+	if (new_dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_rename_f: Uh-oh, vfat_rename on new entry %s with size %d\n", new_dentry->d_name.name, new_dentry->d_name.len));
+		goto out;
+	}
+
  	ret = -EPERM;
 	err = umsdos_parse (old_dentry->d_name.name,
 				old_dentry->d_name.len, &old_info);
@@ -371,21 +425,6 @@
 	if (ret)
 		goto out_unlock;
 
-	err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
-	if (err == 0) {
-		/* check whether it _really_ exists ... */
-		ret = -EEXIST;
-		if (new_dentry->d_inode)
-			goto out_unlock;
-
-		/* bogus lookup? complain and fix up the EMD ... */
-		printk(KERN_WARNING
-			"umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
-			new_dentry->d_parent->d_name.name, new_info.entry.name);
-		err = umsdos_delentry(new_dentry->d_parent, &new_info,
-					S_ISDIR(new_info.entry.mode));
-	}
-
 	umsdos_ren_init (&new_info, &old_info);
 	if (flags)
 		new_info.entry.flags = flags;
@@ -398,8 +437,7 @@
 		d_drop(old_dentry);
 	}
 
-	old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, 
-					old_info.fake.len);
+	old = umsdos_fake_or_lfn(old_dentry->d_parent, &old_info);
 	ret = PTR_ERR(old);
 	if (IS_ERR(old))
 		goto out_unlock;
@@ -415,17 +453,64 @@
  			goto out_dput;
 	}
 
-	new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 
-					new_info.fake.len);
+	new = umsdos_covered(new_dentry->d_parent, new_info.entry.name,
+					      new_info.entry.name_len);
+
+	ret = PTR_ERR(new);
+	if (IS_ERR(new))
+		goto out_dput;
+
+	if (new->d_inode) {	/* destination filename exists, but it shouldn't
+				   we have case collision -- use mangled name */
+		dput(new);
+		new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname,
+							    new_info.fake.len);
+	}
+
 	ret = PTR_ERR(new);
 	if (IS_ERR(new))
 		goto out_dput;
 
+	/* vfat_rename will use new_dir->i_fix_loc only for new destination file, even when new_dir == old_dir */
+	ret = patch_fat_cache (new->d_parent, &new_info);
+	if (ret) {
+		dput(new);
+		goto out_dput;
+	}
+
+	/* have to do fat_detach here, as vfat_rename will screw i_location in vfat_find (old_dir,...
+	   and we already use new_dir->i_fix_loc (which can be same as old_dir->i_fix_loc ! */
+	fat_detach(old->d_inode);
+//check_dentry_path (old, "umsdos_rename_f old b4 vfat_rename");
+//check_dentry_path (new, "umsdos_rename_f new b4 vfat_rename");
+
 	/* Do the msdos-level rename */
-	ret = msdos_rename (old_dir, old, new_dir, new);
+	ret = vfat_rename (old_dir, old, new_dir, new);
+//check_dentry_path (old, "umsdos_rename_f old aft vfat_rename");
+//check_dentry_path (new, "umsdos_rename_f new aft vfat_rename");
+	if (ret != 0) {		/* rename failed, possibly invalid destination filename? try with mangled name */
+		MSDOS_I(new->d_parent->d_inode)->i_fix_loc = 0;	/* clear old */
+		dput(new);
+		new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, new_info.fake.len);
+		ret = PTR_ERR(new);
+		if (IS_ERR(new))
+			goto out_dput;
+		Printk (("umsdos_rename_f: vfat_rename failed, using mangle %s/%s\n",
+			new->d_parent->d_name.name, new->d_name.name));
+
+		ret = patch_fat_cache (new->d_parent, &new_info);
+		if (ret) {
+			dput(new);
+			goto out_dput;
+		}
+		ret = vfat_rename (old_dir, old, new_dir, new);
+		if (ret)
+			MSDOS_I(new->d_parent->d_inode)->i_fix_loc = 0;	/* it failed, clear for future use */
+	}
 
 	dput(new);
 
+
 	/* If the rename failed, remove the new EMD entry */
 	if (ret != 0) {
 		umsdos_delentry (new_dentry->d_parent, &new_info,
@@ -491,6 +576,11 @@
 {
 	int ret, len;
 
+	len = strlen (symname) + 1;
+	ret = -ENAMETOOLONG;
+	if (len > 2048)
+		goto out;
+
 	ret = umsdos_create_any (dir, dentry, mode, 0, flags);
 	if (ret) {
 		printk(KERN_WARNING
@@ -498,10 +588,10 @@
 		goto out;
 	}
 
-	len = strlen (symname) + 1;
 	ret = block_symlink(dentry->d_inode, symname, len);
 	if (ret < 0)
 		goto out_unlink;
+//	d_drop(dentry);	/* FIXME: added as David's workaround 2002-08-07 /mn/ CHECK it. */
 out:
 	return ret;
 
@@ -519,6 +609,10 @@
 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
 		 const char *symname)
 {
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_symlink: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		return -ENAMETOOLONG;
+	}
 	return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
 }
 
@@ -542,10 +636,26 @@
 dentry->d_parent->d_name.name, dentry->d_name.name, 
 olddentry->d_parent->d_name.name, olddentry->d_name.name);
 #endif
+#ifdef UMSDOS_PARANOIA
+	if (!oldinode || !olddir) 
+		printk (KERN_ERR "UMSDOS_link - oldinode=%p, olddir=%p\n", oldinode, olddir);
+#endif
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_link new: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+	if (olddentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_link old: Uh-oh, dentry %s with size %d\n", olddentry->d_name.name, olddentry->d_name.len));
+		goto out;
+	}
  
 	ret = -EPERM;
 	if (S_ISDIR (oldinode->i_mode))
 		goto out;
+	if (S_ISLNK (oldinode->i_mode))
+		goto out;
 
 	ret = umsdos_nevercreat (dir, dentry, -EPERM);
 	if (ret)
@@ -575,7 +685,7 @@
 		goto out_unlock;
 	ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
 	if (ret) {
-printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
+printk(KERN_WARNING "UMSDOS_link: %s/%s not in EMD, ret=%d\n",
 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
 		goto out_unlock;
 	}
@@ -590,7 +700,7 @@
 		/* create a hidden link name */
 		ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
 		if (ret) {
-printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
+printk(KERN_WARNING "umsdos_link: can't make hidden %s/%s, ret=%d\n",
 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
 			goto out_unlock;
 		}
@@ -603,7 +713,7 @@
 						hid_info.entry.name_len, 0); 
 		ret = PTR_ERR(temp);
 		if (IS_ERR(temp)) {
-printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
+printk(KERN_WARNING "umsdos_link: lookup %s/%s failed, ret=%d\n",
 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
 			goto cleanup;
 		}
@@ -613,7 +723,7 @@
 		d_move(olddentry, temp);
 		dput(temp);
 		if (ret) {
-printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
+printk(KERN_WARNING "umsdos_link: rename to %s/%s failed, ret=%d\n",
 temp->d_parent->d_name.name, temp->d_name.name, ret);
 			goto cleanup;
 		}
@@ -647,6 +757,10 @@
 		/* This symlink increments i_nlink (see below.) */
 		err = umsdos_symlink_x (dir, dentry, path,
 					S_IFREG | 0777, UMSDOS_HLINK);
+
+		if (!err && !ret)	/* re-get new info->f_pos, needed for patch_fat_cache() in umsdos_fake_or_lfn calls below */
+			ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
+
 		/* fold the two errors */
 		if (!ret)
 			ret = err;
@@ -654,7 +768,7 @@
 
 		/* creation failed ... remove the link entry */
 	cleanup:
-printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
+printk(KERN_ERR "umsdos_link: link failed, ret=%d, removing %s/%s\n",
 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
 		err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
 		goto out_unlock;
@@ -678,11 +792,10 @@
 	 */ 
 	d_drop(olddentry);
 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
-olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
+olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.entry.name));
 
 	/* Do a real lookup to get the short name dentry */
-	temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
-					old_info.fake.len);
+	temp = umsdos_fake_or_lfn(olddentry->d_parent, &old_info);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out_unlock;
@@ -706,9 +819,8 @@
 		struct iattr newattrs;
 
 		/* Do a real lookup to get the short name dentry */
-		temp = umsdos_covered(olddentry->d_parent,
-					old_info.fake.fname,
-					old_info.fake.len);
+		temp = umsdos_fake_or_lfn(olddentry->d_parent,
+					&old_info);
 		ret = PTR_ERR(temp);
 		if (IS_ERR(temp))
 			goto out_unlock2;
@@ -719,11 +831,14 @@
 		if (IS_ERR(temp))
 			goto out_unlock2;
 
-
 #ifdef UMSDOS_PARANOIA
 if (!oldinode->u.umsdos_i.i_is_hlink)
 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
+if (!temp->d_inode) {
+	printk(KERN_ERR "UMSDOS_link: temp has NULL inode ? will OOPS... was %s/%s\n", olddentry->d_parent->d_name.name, old_info.entry.name);
+//	check_dentry_path(temp, "temp dentry: will OOPS now, working around");
+}
 #endif
 		temp->d_inode->i_nlink++;
 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
@@ -767,6 +882,7 @@
 	struct dentry *temp;
 	struct inode *inode;
 	int ret, err;
+	int trymangle = 0;
 	struct umsdos_info info;
 
 	ret = umsdos_nevercreat (dir, dentry, -EEXIST);
@@ -777,6 +893,12 @@
 	if (ret)
 		goto out;
 
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_mkdir: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	info.entry.mode = mode | S_IFDIR;
 	info.entry.rdev = 0;
 	info.entry.uid = current->fsuid;
@@ -788,21 +910,50 @@
 	if (ret)
 		goto out;
 
-	/* lookup the short name dentry */
-	temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+	/* lookup the lfn entry name dentry */
+	temp = umsdos_covered(dentry->d_parent, info.entry.name, info.entry.name_len);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out_remove;
+	
+	if (temp->d_inode) {	/* already used, we need to resort to mangling! */ 
+		trymangle = 1;	/* (probably filename only differs in case) */
+		Printk(("umsdos_mkdir: dirname %s/%s already used, trying to mangle\n",
+			temp->d_parent->d_name.name, temp->d_name.name));
+	}
+
+mangle:
+	if (trymangle) {
+		dput(temp);
+		temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out_remove;
+		printk (KERN_WARNING "umsdos_mkdir: using mangle %s/%s\n",
+			temp->d_parent->d_name.name, temp->d_name.name);
+	}
 
 	/* Make sure the short name doesn't exist */
 	ret = -EEXIST;
 	if (temp->d_inode) {
-printk("umsdos_mkdir: short name %s/%s exists\n",
-dentry->d_parent->d_name.name, info.fake.fname);
+printk("umsdos_mkdir: entry name %s/%s exists\n",
+dentry->d_parent->d_name.name, info.entry.name);
 		goto out_remove_dput;
 	}
 
-	ret = msdos_mkdir (dir, temp, mode);
+	ret = patch_fat_cache (dentry->d_parent, &info);
+	if (ret)
+		goto out_remove_dput;
+		
+	ret = vfat_mkdir (dir, temp, mode);
+	if (ret && !trymangle) {	/* failed to create dir -- maybe illegal 
+					 * chars like ":" ? Try mangling.
+					 */
+		trymangle = 1;
+		printk (KERN_WARNING "umsdos_mkdir: failed to create dir %s/%s, trying to mangle\n",
+			temp->d_parent->d_name.name, temp->d_name.name);
+		goto mangle;
+	}
 	if (ret)
 		goto out_remove_dput;
 
@@ -831,6 +982,7 @@
 	dput(temp);
 
 out:
+//check_dentry_path (dentry, "UMSDOS_mkdir end dentry");
 	Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name, ret));
 	return ret;
@@ -879,6 +1031,12 @@
 	if (ret)
 		goto out;
 
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_rmdir: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	ret = -EBUSY;
 	if (!d_unhashed(dentry))
 		goto out;
@@ -895,7 +1053,7 @@
 		if (!IS_ERR(demd)) {
 			err = -ENOENT;
 			if (demd->d_inode)
-				err = msdos_unlink (dentry->d_inode, demd);
+				err = vfat_unlink (dentry->d_inode, demd);
 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
 #ifdef UMSDOS_PARANOIA
 if (err)
@@ -916,14 +1074,14 @@
 	umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
 	/* Call findentry to complete the mangling */
 	umsdos_findentry (dentry->d_parent, &info, 2);
-	temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+	temp = umsdos_fake_or_lfn(dentry->d_parent, &info);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out;
 	/*
 	 * Attempt to remove the msdos name.
 	 */
-	ret = msdos_rmdir (dir, temp);
+	ret = vfat_rmdir (dir, temp);
 	if (ret && ret != -ENOENT)
 		goto out_dput;
 
@@ -974,6 +1132,12 @@
 	if (ret)
 		goto out;
 
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_unlink: Uh-oh, dentry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+
 	umsdos_lockcreate (dir);
 	ret = umsdos_findentry (dentry->d_parent, &info, 1);
 	if (ret) {
@@ -982,7 +1146,7 @@
 		goto out_unlock;
 	}
 
-Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
+Printk (("UMSDOS_unlink %.*s ", info.entry.name_len, info.entry.name));
 
 	/*
 	 * Note! If this is a hardlink and the names are aliased,
@@ -994,8 +1158,8 @@
 		d_drop(dentry);
 	}
 
-	/* Do a real lookup to get the short name dentry */
-	temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
+	/* Do a real lookup to get the entry name dentry */
+	temp = umsdos_fake_or_lfn(dentry->d_parent, &info);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out_unlock;
@@ -1015,7 +1179,7 @@
 		goto out_dput;
 	}
 
-	ret = msdos_unlink(dir, temp);
+	ret = vfat_unlink(dir, temp);
 	if (!ret)
 		d_delete(temp);
 #ifdef UMSDOS_PARANOIA
@@ -1104,6 +1268,10 @@
 	if (ret)
 		return ret;
 
+	/* Prohibit moves from a promoted to a non-promoted directory */
+	if (old_dir->i_op->rename != new_dir->i_op->rename)
+		return -EXDEV;
+
 		/*
 		 * If the target already exists, delete it first.
 		 */
diff -ur linux-2.4.19-PRISTINE/fs/umsdos/rdir.c linux-mynew/fs/umsdos/rdir.c
--- linux-2.4.19-PRISTINE/fs/umsdos/rdir.c	Sat Oct 20 20:12:03 2001
+++ linux-mynew/fs/umsdos/rdir.c	Sun Aug 11 12:17:47 2002
@@ -29,6 +29,7 @@
 	int real_root;
 };
 
+
 static int rdir_filldir (	void *buf,
 				const char *name,
 				int name_len,
@@ -95,9 +96,20 @@
 		ret = ERR_PTR(-ENOENT);
 		goto out;
 	}
+	
+#ifdef UMSDOS_PARANOIA	
+	if (strcmp(dentry->d_name.name, UMSDOS_EMD_FILE) != 0)
+		Printk ((KERN_DEBUG " ide vfat_lookup for %s/%s in dir %lu with inode seed %u\n", dentry->d_parent->d_name.name, dentry->d_name.name, dir->i_ino, MSDOS_I(dir)->i_fix_loc));
+#endif		
+	ret = ERR_PTR(-ENAMETOOLONG);
+	if (dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_rlookup_x: Uh-oh, vfat_lookup on entry %s with size %d\n", dentry->d_name.name, dentry->d_name.len));
+		goto out;
+	}
+	
+	ret = vfat_lookup (dir, dentry);
 
-	ret = msdos_lookup (dir, dentry);
-	if (ret) {
+	if (IS_ERR(ret)) {
 		printk(KERN_WARNING
 			"umsdos_rlookup_x: %s/%s failed, ret=%ld\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
@@ -164,7 +176,7 @@
 	if (!d_unhashed(dentry))
 		goto out;
 
-	ret = msdos_rmdir (dir, dentry);
+	ret = vfat_rmdir (dir, dentry);
 	if (ret != -ENOTEMPTY)
 		goto out;
 
@@ -177,7 +189,7 @@
 		if (!IS_ERR(demd)) {
 			ret = 0;
 			if (demd->d_inode)
-				ret = msdos_unlink (dentry->d_inode, demd);
+				ret = vfat_unlink (dentry->d_inode, demd);
 			if (!ret)
 				d_delete(demd);
 			dput(demd);
@@ -187,12 +199,31 @@
 		goto out;
 
 	/* now retry the original ... */
-	ret = msdos_rmdir (dir, dentry);
+	ret = vfat_rmdir (dir, dentry);
 
 out:
 	return ret;
 }
 
+int UMSDOS_rrename (struct inode *old_dir, struct dentry *old_dentry,
+		   struct inode *new_dir, struct dentry *new_dentry)
+{
+	/* Prohibit moves from a non-promoted to a promoted directory. */
+	if (old_dir->i_op->rename != new_dir->i_op->rename)
+		return -EXDEV;
+
+	if (old_dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_rrename: Uh-oh, vfat_rename on old entry %s with size %d\n", old_dentry->d_name.name, old_dentry->d_name.len));
+		return -ENAMETOOLONG;
+	}
+	if (new_dentry->d_name.len >= UMSDOS_MAXNAME) {
+		Printk ((KERN_WARNING "umsdos_rrename: Uh-oh, vfat_rename on new entry %s with size %d\n", new_dentry->d_name.name, new_dentry->d_name.len));
+		return -ENAMETOOLONG;
+	}
+
+	return vfat_rename(old_dir, old_dentry, new_dir, new_dentry);
+}
+
 /* #Specification: dual mode / introduction
  * One goal of UMSDOS is to allow a practical and simple coexistence
  * between MS-DOS and Linux in a single partition. Using the EMD file
@@ -233,11 +264,11 @@
 
 struct inode_operations umsdos_rdir_inode_operations =
 {
-	create:		msdos_create,
+	create:		vfat_create,
 	lookup:		UMSDOS_rlookup,
-	unlink:		msdos_unlink,
-	mkdir:		msdos_mkdir,
+	unlink:		vfat_unlink,
+	mkdir:		vfat_mkdir,
 	rmdir:		UMSDOS_rrmdir,
-	rename:		msdos_rename,
+	rename:		UMSDOS_rrename,
 	setattr:	UMSDOS_notify_change,
 };
diff -ur linux-2.4.19-PRISTINE/fs/vfat/namei.c linux-mynew/fs/vfat/namei.c
--- linux-2.4.19-PRISTINE/fs/vfat/namei.c	Mon Aug 12 17:51:01 2002
+++ linux-mynew/fs/vfat/namei.c	Tue Aug 27 00:26:18 2002
@@ -927,7 +927,12 @@
 	/* Now create the new entry */
 	*bh = NULL;
 	for (slot = 0; slot < slots; slot++) {
-		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) {
+		int *org_ino=NULL;
+		PRINTK2 ((KERN_DEBUG "vfat_add_entry currently %u/%u\n", slot, slots));
+		if (slot + 1 == slots) {	/* calculate/clean i_fix_loc only for LAST slot entry */
+			org_ino = &sinfo_out->org_ino;
+		}
+		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino, org_ino) < 0) {
 			res = -EIO;
 			goto cleanup;
 		}
@@ -972,7 +977,7 @@
 			&offset,&sinfo->longname_offset);
 	if (res>0) {
 		sinfo->long_slots = res-1;
-		if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0)
+		if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino,&sinfo->org_ino)>=0)
 			return 0;
 		res = -EIO;
 	} 
@@ -1002,6 +1007,8 @@
 		goto error;
 	}
 	inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res);
+	MSDOS_I(inode)->i_old_loc = sinfo.org_ino;
+
 	fat_brelse(dir->i_sb, bh);
 	if (res)
 		return ERR_PTR(res);
@@ -1034,7 +1041,9 @@
 	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
 	if (res < 0)
 		return res;
+	PRINTK2 ((KERN_DEBUG "  vfat_create ide fat_build_inode in dir %lu, ino=%u, org_ino=%u\n", dir->i_ino, sinfo.ino, sinfo.org_ino));
 	inode = fat_build_inode(sb, de, sinfo.ino, &res);
+	MSDOS_I(inode)->i_old_loc = sinfo.org_ino;
 	fat_brelse(sb, bh);
 	if (!inode)
 		return res;
@@ -1064,7 +1073,7 @@
 	/* remove the longname */
 	offset = sinfo->longname_offset; de = NULL;
 	for (i = sinfo->long_slots; i > 0; --i) {
-		if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0)
+		if (fat_get_entry(dir, &offset, &bh, &de, &ino, NULL) < 0)
 			continue;
 		de->name[0] = DELETED_FLAG;
 		de->attr = 0;
@@ -1133,7 +1142,9 @@
 	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
 	if (res < 0)
 		return res;
+	PRINTK2 ((KERN_DEBUG "  vfat_mkdir ide fat_build_inode in dir %lu, ino=%u, org_ino=%u\n", dir->i_ino, sinfo.ino, sinfo.org_ino));
 	inode = fat_build_inode(sb, de, sinfo.ino, &res);
+	MSDOS_I(inode)->i_old_loc = sinfo.org_ino;
 	if (!inode)
 		goto out;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -1163,7 +1174,28 @@
 	dir->i_nlink--;
 	return res;
 }
- 
+
+#if (DEBUG_LEVEL >= 2)
+void debugme (const char *txt, struct dentry *dentry, struct vfat_slot_info *sinfo)
+{
+	printk (KERN_DEBUG txt);
+	printk (" %s/%s ",dentry->d_parent->d_name.name, dentry->d_name.name);
+	if (sinfo) {
+		printk ("with sinfo.ino=%u, sinfo.old_ino=%u\n",
+			sinfo->ino, sinfo->org_ino);
+	}
+	if (dentry->d_inode) {
+		printk (" inode is %p, ino=%lu ", dentry->d_inode, dentry->d_inode->i_ino);
+		printk ("i_location=%u, i_old_loc=%u\n", MSDOS_I(dentry->d_inode)->i_location, MSDOS_I(dentry->d_inode)->i_old_loc);
+	} else {
+		printk (" inode is NULL\n");
+	}
+}
+#else
+void debugme (const char *txt, struct dentry *dentry, struct vfat_slot_info *sinfo) {}
+#endif
+
+  
 int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
 		struct inode *new_dir,struct dentry *new_dentry)
 {
@@ -1174,7 +1206,15 @@
 	struct inode *old_inode, *new_inode;
 	int res, is_dir;
 	struct vfat_slot_info old_sinfo,sinfo;
+	int new_loc;
+
+	PRINTK2 (KERN_DEBUG "vfat_rename: ENTER!\n");
 
+	new_loc = MSDOS_I(new_dir)->i_fix_loc;
+	MSDOS_I(new_dir)->i_fix_loc = 0;
+	/* save it for later, but nuke in case new_dir and old_dir are the same
+	   as that would screw vfat_find(old_dir, ....) below ! */
+	
 	old_bh = new_bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
@@ -1188,9 +1228,12 @@
 				&dotdot_de,&dotdot_ino)) < 0)
 		goto rename_done;
 
+	MSDOS_I(new_dir)->i_fix_loc = new_loc;	/* restore, we need it now */
+
 	if (new_dentry->d_inode) {
 		res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
 				&new_de);
+debugme ("vfat_rename new_dentry already exists", new_dentry, &sinfo);
 		if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) {
 			/* WTF??? Cry and fail. */
 			printk(KERN_WARNING "vfat_rename: fs corrupted\n");
@@ -1206,16 +1249,20 @@
 	} else {
 		res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo,
 					&new_bh,&new_de);
+debugme ("vfat_rename new_dentry does not yet exist, vfat_add_entry gives", new_dentry, &sinfo);
 		if (res < 0) goto rename_done;
 	}
 
 	new_dir->i_version = ++event;
 
 	/* releases old_bh */
+debugme("vfat_rename about to vfat_remove_entry and fat_detach old_dentry", old_dentry, &old_sinfo);
+
 	vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
 	old_bh=NULL;
 	fat_detach(old_inode);
 	fat_attach(old_inode, sinfo.ino);
+	MSDOS_I(old_inode)->i_old_loc = sinfo.org_ino;
 	mark_inode_dirty(old_inode);
 
 	old_dir->i_version = ++event;
@@ -1241,6 +1288,8 @@
 	}
 
 rename_done:
+debugme("vfat_rename after fat_detach old_dentry", old_dentry, NULL);
+debugme("vfat_rename after fat_detach new_dentry", new_dentry, NULL);
 	fat_brelse(sb, dotdot_bh);
 	fat_brelse(sb, old_bh);
 	fat_brelse(sb, new_bh);
diff -ur linux-2.4.19-PRISTINE/include/linux/msdos_fs.h linux-mynew/include/linux/msdos_fs.h
--- linux-2.4.19-PRISTINE/include/linux/msdos_fs.h	Tue Oct 30 13:47:12 2001
+++ linux-mynew/include/linux/msdos_fs.h	Sat Aug 17 16:16:52 2002
@@ -181,7 +181,8 @@
 	int total_slots;	       /* total slots (long and short) */
 	loff_t longname_offset;	       /* dir offset for longname start */
 	loff_t shortname_offset;       /* dir offset for shortname start */
-	int ino;		       /* ino for the file */
+	int ino;		       /* ino for the file (FAT DE position for vfat _or_ EMD DE position for uvfat) */
+	int org_ino;		       /* original ino (FAT DE position) [or 0 if ino is original FAT DE] */
 };
 
 /* Determine whether this FS has kB-aligned data. */
@@ -295,6 +296,8 @@
 extern int fat_statfs(struct super_block *sb, struct statfs *buf);
 extern void fat_write_inode(struct inode *inode, int wait);
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
+extern void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
+
 
 /* fat/misc.c */
 extern void fat_fs_panic(struct super_block *s, const char *msg);
@@ -308,11 +311,12 @@
 extern void fat_date_unix2dos(int unix_date, unsigned short *time,
 			      unsigned short *date);
 extern int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh,
-			  struct msdos_dir_entry **de, int *ino);
+			  struct msdos_dir_entry **de, int *ino, int *fixloc);
 static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
 				    struct buffer_head **bh,
-				    struct msdos_dir_entry **de, int *ino)
+				    struct msdos_dir_entry **de, int *ino, int *fixloc)
 {
+#if 0
 	/* Fast stuff first */
 	if (*bh && *de &&
 	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
@@ -321,7 +325,8 @@
 		(*ino)++;
 		return 0;
 	}
-	return fat__get_entry(dir,pos,bh,de,ino);
+#endif	
+	return fat__get_entry(dir,pos,bh,de,ino,fixloc);
 }
 extern int fat_subdirs(struct inode *dir);
 extern int fat_scan(struct inode *dir, const char *name,
diff -ur linux-2.4.19-PRISTINE/include/linux/msdos_fs_i.h linux-mynew/include/linux/msdos_fs_i.h
--- linux-2.4.19-PRISTINE/include/linux/msdos_fs_i.h	Thu Feb 10 21:17:00 2000
+++ linux-mynew/include/linux/msdos_fs_i.h	Thu Aug  1 22:12:57 2002
@@ -14,6 +14,8 @@
 	int i_location;	/* on-disk position of directory entry or 0 */
 	struct inode *i_fat_inode;	/* struct inode of this one */
 	struct list_head i_fat_hash;	/* hash by i_location */
+	int i_fix_loc;	/* used by uvfat on DIR, will be new i_location of FILE [EMD and not DE based] */
+	int i_old_loc;	/* on-disk position of directory entry or 0 -- original FAT DE i_location, needed for fat_write_inode() ! */
 };
 
 #endif
diff -ur linux-2.4.19-PRISTINE/include/linux/msdos_fs_sb.h linux-mynew/include/linux/msdos_fs_sb.h
--- linux-2.4.19-PRISTINE/include/linux/msdos_fs_sb.h	Tue Oct 30 13:47:12 2001
+++ linux-mynew/include/linux/msdos_fs_sb.h	Wed Aug  7 16:20:46 2002
@@ -27,6 +27,7 @@
 		 atari:1,         /* Use Atari GEMDOS variation of MS-DOS fs */
 		 fat32:1,	  /* Is this a FAT32 partition? */
 		 nocase:1;	  /* Does this need case conversion? 0=need case conversion*/
+
 };
 
 struct msdos_sb_info {
diff -ur linux-2.4.19-PRISTINE/include/linux/umsdos_fs.h linux-mynew/include/linux/umsdos_fs.h
--- linux-2.4.19-PRISTINE/include/linux/umsdos_fs.h	Mon Dec 11 22:26:12 2000
+++ linux-mynew/include/linux/umsdos_fs.h	Tue Aug 27 20:08:02 2002
@@ -2,20 +2,28 @@
 #define LINUX_UMSDOS_FS_H
 
 
-/*#define UMS_DEBUG 1	// define for check_* functions */
-/*#define UMSDOS_DEBUG 1*/
+/* #define UMS_DEBUG 1	// define for check_* functions */
+/* #define UMSDOS_DEBUG 1 */
 #define UMSDOS_PARANOIA 1
 
+/* limit max entries to be returned to sys_getdents* 
+ * at once - smaller is more interactive system, but bigger overhead 
+ * if undefined, unlimited (original behavior)
+ */
+#define UMSDOS_GETDENTS_MAX 8
+
 #define UMSDOS_VERSION	0
-#define UMSDOS_RELEASE	4
+#define UMSDOS_RELEASE	5
 
 #define UMSDOS_ROOT_INO 1
 
 /* This is the file acting as a directory extension */
-#define UMSDOS_EMD_FILE		"--linux-.---"
+#define UMSDOS_EMD_FILE		"--linux5.---"
 #define UMSDOS_EMD_NAMELEN	12
 #define UMSDOS_PSDROOT_NAME	"linux"
 #define UMSDOS_PSDROOT_LEN	5
+//#define UMSDOS_PSDROOT_NAME	"lindows"	// FIXME!!!!
+//#define UMSDOS_PSDROOT_LEN	7
 
 #ifndef _LINUX_TYPES_H
 #include <linux/types.h>
@@ -57,23 +65,24 @@
 	int len;
 };
 
+
 #define UMSDOS_MAXNAME	220
 /* This structure is 256 bytes large, depending on the name, only part */
 /* of it is written to disk */
 /* nice though it would be, I can't change this and preserve backward compatibility */
 struct umsdos_dirent {
-	unsigned char name_len;	/* if == 0, then this entry is not used */
-	unsigned char flags;	/* UMSDOS_xxxx */
-	unsigned short nlink;	/* How many hard links point to this entry */
-	__kernel_uid_t uid;	/* Owner user id */
-	__kernel_gid_t gid;	/* Group id */
-	time_t atime;		/* Access time */
-	time_t mtime;		/* Last modification time */
-	time_t ctime;		/* Creation time */
-	dev_t rdev;		/* major and minor number of a device */
+	__u8 name_len;		/* if == 0, then this entry is not used */
+	__u8 flags;		/* UMSDOS_xxxx */
+	__u16 nlink;		/* How many hard links point to this entry */
+	__u32 uid;		/* Owner user id (in 0.4 was __u16!) */
+	__u32 gid;		/* Group id (in 0.4 was __u16!) */
+	__u32 atime;		/* Access time */
+	__u32 mtime;		/* Last modification time */
+	__u32 ctime;		/* Creation time */
+	__u16 rdev;		/* major and minor number of a device */
 				/* special file */
-	umode_t mode;		/* Standard UNIX permissions bits + type of */
-	char spare[12];		/* unused bytes for future extensions */
+	__u16 mode;		/* Standard UNIX permissions bits + type of */
+	char spare[8];		/* unused bytes for future extensions */
 				/* file, see linux/stat.h */
 	char name[UMSDOS_MAXNAME];	/* Not '\0' terminated */
 				/* but '\0' padded, so it will allow */
diff -ur linux-2.4.19-PRISTINE/include/linux/umsdos_fs.p linux-mynew/include/linux/umsdos_fs.p
--- linux-2.4.19-PRISTINE/include/linux/umsdos_fs.p	Wed Aug  2 21:06:11 2000
+++ linux-mynew/include/linux/umsdos_fs.p	Sat Aug  3 17:13:51 2002
@@ -1,11 +1,11 @@
 /* check.c 23/01/95 03.38.30 */
 void check_page_tables (void);
+void check_sb(struct super_block *sb, const char c);
+void check_inode(struct inode *inode);
+void checkd_inode(struct inode *inode);
+void check_dentry_path(struct dentry *dentry, const char *desc);
 
 /* dir.c 22/06/95 00.22.12 */
-int  dummy_dir_read ( struct file *filp,
-	 char *buf,
-	 size_t size,
-	 loff_t *count);
 char * umsdos_d_path(struct dentry *, char *, int);
 void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *);
 int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry);
@@ -13,7 +13,7 @@
 struct dentry *UMSDOS_lookup(struct inode *, struct dentry *);
 struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int);
 struct dentry *umsdos_covered(struct dentry *, char *, int);
-
+struct dentry *umsdos_fake_or_lfn (struct dentry *, struct umsdos_info *);
 struct dentry *umsdos_solve_hlink (struct dentry *hlink);
 
 /* emd.c 22/06/95 00.22.04 */
@@ -27,6 +27,7 @@
 int umsdos_findentry (struct dentry *, struct umsdos_info *, int);
 int umsdos_isempty (struct dentry *);
 int umsdos_writeentry (struct dentry *, struct umsdos_info *, int);
+int umsdos_notify_change_locked(struct dentry *, struct iattr *attr);
 
 /* file.c 25/01/95 02.25.38 */
 
@@ -35,15 +36,18 @@
 void UMSDOS_read_inode (struct inode *);
 void UMSDOS_write_inode (struct inode *, int);
 int UMSDOS_notify_change (struct dentry *, struct iattr *attr);
-int umsdos_notify_change_locked(struct dentry *, struct iattr *attr);
 void UMSDOS_put_inode (struct inode *);
 int UMSDOS_statfs (struct super_block *, struct statfs *);
 struct super_block *UMSDOS_read_super (struct super_block *, void *, int);
 void UMSDOS_put_super (struct super_block *);
+int patch_fat_cache (struct dentry *parent, struct umsdos_info *info);
+int get_fat_ino (struct dentry *demd, loff_t pos, int *ino);
+struct inode *uvfat_build_inode (struct inode *dir, struct dentry *demd, loff_t pos, struct umsdos_info *info);
+
 
 void umsdos_setup_dir(struct dentry *);
-void umsdos_set_dirinfo_new(struct dentry *, off_t);
-void umsdos_patch_dentry_inode (struct dentry *, off_t);
+void umsdos_set_dirinfo_new(struct dentry *, loff_t);
+void umsdos_patch_dentry_inode (struct dentry *, loff_t);
 int umsdos_get_dirowner (struct inode *inode, struct inode **result);
 
 /* ioctl.c 22/06/95 00.22.08 */
