diff -ur linux-2.4.9-PRISTINE/fs/Makefile linux-my/fs/Makefile
--- linux-2.4.9-PRISTINE/fs/Makefile	Fri Aug 24 20:13:42 2001
+++ linux-my/fs/Makefile	Wed Aug 29 22:50:09 2001
@@ -32,6 +32,7 @@
 subdir-$(CONFIG_CODA_FS)	+= coda
 subdir-$(CONFIG_MINIX_FS)	+= minix
 subdir-$(CONFIG_FAT_FS)		+= fat
+subdir-$(CONFIG_UMSDOS_FS)	+= umsdos
 subdir-$(CONFIG_MSDOS_FS)	+= msdos
 subdir-$(CONFIG_VFAT_FS)	+= vfat
 subdir-$(CONFIG_BFS_FS)		+= bfs
@@ -43,7 +44,6 @@
 subdir-$(CONFIG_NFSD)		+= nfsd
 subdir-$(CONFIG_LOCKD)		+= lockd
 subdir-$(CONFIG_NLS)		+= nls
-subdir-$(CONFIG_UMSDOS_FS)	+= umsdos
 subdir-$(CONFIG_SYSV_FS)	+= sysv
 subdir-$(CONFIG_SMB_FS)		+= smbfs
 subdir-$(CONFIG_NCP_FS)		+= ncpfs
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/README-WIP.txt linux-my/fs/umsdos/README-WIP.txt
--- linux-2.4.9-PRISTINE/fs/umsdos/README-WIP.txt	Thu Dec  9 22:22:21 1999
+++ linux-my/fs/umsdos/README-WIP.txt	Wed Aug 29 22:46:47 2001
@@ -5,18 +5,11 @@
 There is no warning any more.
 Both read-only and read-write stuff is fixed, both in
 msdos-compatibile mode, and in umsdos EMD mode, and it seems stable.
-There are still few hardlink nuisances, but those are not fatal.
-
-I'd call it pre-release, and ask for as many people as possible to
-come and test it! See notes below for some more information, or if
-you are trying to use UMSDOS as root partition.
 
 Userland NOTE: new umsdos_progs (umssync, umssetup, udosctl & friends) that
-will compile and work on 2.2.x kernels and glibc based systems may be found
-at http://cvs.linux.hr/
-
-Also look at the quick-hack "homepage" for umsdos filesystem at 
-http://www.voyager.hr/~mnalis/umsdos
+will compile and work on 2.2.x+ kernels and glibc based systems, as well as
+kernel patches and other umsdos related information may be found at
+http://linux.voyager.hr/umsdos/
 
 Information below is getting outdated slowly -- I'll fix it one day when I
 get enough time - there are more important things to fix right now.
@@ -24,7 +17,7 @@
 Legend: those lines marked with '+' on the beggining of line indicates it
 passed all of my tests, and performed perfect in all of them.
 
-Current status (990202) - UMSDOS 0.85:
+Current status (010125) - UMSDOS 0.86j:
 
 (1) pure MSDOS (no --linux-.--- EMD file):
 
@@ -35,7 +28,7 @@
 
 WRITE:
 + creat file			- works
-+ delete file			- works
++ unlink file			- works
 + write file			- works
 + rename file (same dir)	- works
 + rename file (dif. dir)	- works
@@ -55,7 +48,7 @@
 + read file			- works
 + switching MSDOS/UMSDOS	- works
 + switching UMSDOS/MSDOS	- works
-- pseudo root things		- works mostly. See notes below.
+- pseudo root things		- works mostly. See notes below. BROKEN in 2.3.99pre4 COMPLETELY! FIXME!
 + resolve symlink		- works
 + dereference symlink		- works
 + dangling symlink		- works
@@ -66,21 +59,22 @@
 
 WRITE:
 + create symlink		- works
-- create hardlink		- works
++ create hardlink		- works
 + create file			- works
 + create special file		- works
 + write to file			- works
 + rename file (same dir)	- works
 + rename file (dif. dir)	- works
-- rename hardlink (same dir)	-
-- rename hardlink (dif. dir)	-
++ rename hardlink (same dir)	- works
+- rename hardlink (dif. dir)	- works, but see notes below.
 + rename symlink (same dir)	- works
 + rename symlink (dif. dir)	- works
 + rename dir (same dir)		- works
 + rename dir (dif. dir)		- works
-+ delete file			- works
++ unlink file			- works
 + notify_change (chown,perms)	- works
-+ delete hardlink		- works
++ notify_change for hardlinks	- works
++ unlink hardlink		- works
 + mkdir				- works
 + rmdir 			- works
 + umssyncing (many ioctls)	- works
@@ -99,24 +93,11 @@
 example is specs file about it. Specifically, moving directory which
 contains hardlinks will break them.
 
-Note: (about pseudoroot) If you are currently trying to use UMSDOS as root
-partition (with linux installed in c:\linux) it will boot, but there may be
-some problems. Volunteers ready to test pseudoroot are needed (preferably
-ones with working backups or unimportant data).  For example, '/DOS' pseudo
-directory is only partially re-implemented and buggy. It works most of the
-time, though. Update: should work ok in 0.84, although it still does not
-work correctly in combination with initrd featere. Working on this!
-
 Note: (about creating hardlinks in pseudoroot mode) - hardlinks created in
 pseudoroot mode are now again compatibile with 'normal' hardlinks, and vice
 versa. Thanks to Sorin Iordachescu <sorin@rodae.ro> for providing fix.
-
-Warning: (about hardlinks) - modifying hardlinks (esp. if they are in
-different directories) are currently somewhat broken, I'm working on it.
-Problem seems to be that code uses and updates EMD of directory where 'real
-hardlink' is stored, not EMD of directory where our pseudo-hardlink is
-located! I'm looking for ideas how to work around this in clean way, since
-without it modifying hardlinks in any but most simple ways is broken!
+See http://linux.voyager.hr/umsdos/hlbug.html for more info and upgrade
+procedure if you used broken versions...
 
 ------------------------------------------------------------------------------
 
@@ -130,6 +111,4 @@
 I'm unfortunately somewhat out of time to read linux-kernel@vger, but I do
 check for messages having "UMSDOS" in the subject, and read them.  I might
 miss some in all that volume, though.  I should reply to any direct e-mail
-in few days.  If I don't, probably I never got your message.  You can try
-mnalis-umsdos@voyager.hr; however mnalis@jagor.srce.hr is preferable.
-
+in few days.  If I don't, probably I never got your message.
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/dir.c linux-my/fs/umsdos/dir.c
--- linux-2.4.9-PRISTINE/fs/umsdos/dir.c	Fri Feb  9 20:29:44 2001
+++ linux-my/fs/umsdos/dir.c	Wed Aug 29 21:44:29 2001
@@ -67,7 +67,7 @@
 static int umsdos_dir_once (	void *buf,
 				const char *name,
 				int len,
-				off_t offset,
+				loff_t offset,
 				ino_t ino,
 				unsigned type)
 {
@@ -651,13 +651,13 @@
 	old_root = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
 	spin_lock(&dcache_lock);
-	path = __d_path(dentry, NULL, dentry->d_sb->s_root, NULL, buffer, len);
+	path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */
 	spin_unlock(&dcache_lock);
 
 	if (*path == '/')
 		path++; /* skip leading '/' */
 
-	if (old_root->d_inode == pseudo_root)
+	if (current->fs->root->d_inode == pseudo_root)
 	{
 		*(path-1) = '/';
 		path -= (UMSDOS_PSDROOT_LEN+1);
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/emd.c linux-my/fs/umsdos/emd.c
--- linux-2.4.9-PRISTINE/fs/umsdos/emd.c	Wed Mar  7 04:44:37 2001
+++ linux-my/fs/umsdos/emd.c	Mon Aug 27 12:43:55 2001
@@ -18,7 +18,21 @@
 #include <linux/pagemap.h>
 #include <linux/delay.h>
 
-static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
+void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q)
+{
+	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->atime = cpu_to_le32(q->atime);
+	p->mtime = cpu_to_le32(q->mtime);
+	p->ctime = cpu_to_le32(q->ctime);
+	p->rdev = cpu_to_le16(q->rdev);
+	p->mode = cpu_to_le16(q->mode);
+}
+
+static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
 {
 	p->name_len = q->name_len;
 	p->name[p->name_len]='\0';
@@ -136,6 +150,7 @@
 		printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len);
 		p->name_len = 0; 
 		ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */
+		/* FIXME: does not work if we did 'ls -l' before 'udosctl uls' ?! */
 	}
 
 	recsize = umsdos_evalrecsize(p->name_len);
@@ -163,7 +178,7 @@
 		page_cache_release(page2);
 	} else
 		memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare);
-	copy_entry(entry, p);
+	get_entry(entry, p);
 	kunmap(page);
 	page_cache_release(page);
 	*pos += recsize;
@@ -249,20 +264,11 @@
 					offs+info->recsize-PAGE_CACHE_SIZE);
 		if (ret)
 			goto out_unlock3;
-		p->name_len = entry->name_len;
-		p->flags = entry->flags;
-		p->nlink = cpu_to_le16(entry->nlink);
-		p->uid = cpu_to_le16(entry->uid);
-		p->gid = cpu_to_le16(entry->gid);
-		p->atime = cpu_to_le32(entry->atime);
-		p->mtime = cpu_to_le32(entry->mtime);
-		p->ctime = cpu_to_le32(entry->ctime);
-		p->rdev = cpu_to_le16(entry->rdev);
-		p->mode = cpu_to_le16(entry->mode);
-		memcpy(p->name,entry->name,
+		put_entry (p, entry);
+		memcpy(p->spare,entry->spare,
 			(char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);
 		memcpy(page_address(page2),
-				entry->spare+PAGE_CACHE_SIZE-offs,
+				((char*)entry)+PAGE_CACHE_SIZE-offs,
 				offs+info->recsize-PAGE_CACHE_SIZE);
 		ret = mapping->a_ops->commit_write(NULL,page2,0,
 					offs+info->recsize-PAGE_CACHE_SIZE);
@@ -279,16 +285,7 @@
 					offs + info->recsize);
 		if (ret)
 			goto out_unlock;
-		p->name_len = entry->name_len;
-		p->flags = entry->flags;
-		p->nlink = cpu_to_le16(entry->nlink);
-		p->uid = cpu_to_le16(entry->uid);
-		p->gid = cpu_to_le16(entry->gid);
-		p->atime = cpu_to_le32(entry->atime);
-		p->mtime = cpu_to_le32(entry->mtime);
-		p->ctime = cpu_to_le32(entry->ctime);
-		p->rdev = cpu_to_le16(entry->rdev);
-		p->mode = cpu_to_le16(entry->mode);
+		put_entry (p, entry);
 		memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare);
 		ret = mapping->a_ops->commit_write(NULL,page,offs,
 					offs + info->recsize);
@@ -463,7 +460,7 @@
 			goto skip_it;
 
 		info->f_pos = pos;
-		copy_entry(entry, rentry);
+		get_entry(entry, rentry);
 		ret = 0;
 		break;
 skip_it:
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/inode.c linux-my/fs/umsdos/inode.c
--- linux-2.4.9-PRISTINE/fs/umsdos/inode.c	Sun May 20 03:02:45 2001
+++ linux-my/fs/umsdos/inode.c	Wed Aug 29 21:49:10 2001
@@ -38,7 +38,7 @@
 		 ,atomic_read(&inode->i_count)));
 
 	if (inode == pseudo_root) {
-		printk (KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count));
+		Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)));
 	}
 
 	if (atomic_read(&inode->i_count) == 1)
@@ -49,7 +49,7 @@
 void UMSDOS_put_super (struct super_block *sb)
 {
 	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
-	if (saved_root) {
+	if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {
 		shrink_dcache_parent(saved_root);
 		dput(saved_root);
 		saved_root = NULL;
@@ -153,16 +153,56 @@
 }
 
 
-int umsdos_notify_change_locked(struct dentry *, struct iattr *);
 /*
  * lock the parent dir before starting ...
+ * also handles hardlink converting
  */
 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
-	struct inode *inode = dentry->d_inode;
+	struct inode *dir, *inode;
+	struct umsdos_info info;
+	struct dentry *temp, *old_dentry = NULL;
 	int ret;
 
+	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) {
+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;
+	}
+
+	if (info.entry.flags & UMSDOS_HLINK) {
+		/*
+		 * In order to get the correct (real) inode, we just drop
+		 * the original dentry.
+		 */ 
+		d_drop(dentry);
+Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n",
+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);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+	
+		/* now resolve the link ... */
+		temp = umsdos_solve_hlink(temp);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+		old_dentry = dentry;
+		dentry = temp;	/* so umsdos_notify_change_locked will operate on that */
+	}
+
+	dir = dentry->d_parent->d_inode;
+	inode = dentry->d_inode;
+
 	ret = inode_change_ok (inode, attr);
 	if (ret)
 		goto out;
@@ -173,9 +213,12 @@
 	if (ret == 0)
 		inode_setattr (inode, attr);
 out:
+	if (old_dentry)
+		dput (dentry);	/* if we had to use fake dentry for hardlinks, dput() it now */
 	return ret;
 }
 
+
 /*
  * Must be called with the parent lock held.
  */
@@ -316,16 +359,16 @@
 	struct super_block *res;
 	struct dentry *new_root;
 
-	MSDOS_SB(sb)->options.isvfat = 0;
 	/*
 	 * Call msdos-fs to mount the disk.
 	 * Note: this returns res == sb or NULL
 	 */
 	res = msdos_read_super (sb, data, silent);
+
 	if (!res)
 		goto out_fail;
 
-	printk (KERN_INFO "UMSDOS 0.86i "
+	printk (KERN_INFO "UMSDOS 0.86k "
 		"(compatibility level %d.%d, fast msdos)\n", 
 		UMSDOS_VERSION, UMSDOS_RELEASE);
 
@@ -333,22 +376,31 @@
 	MSDOS_SB(sb)->options.dotsOK = 0;	/* disable hidden==dotfile */
 
 	/* install our dentry operations ... */
-	sb->s_root->d_op = &umsdos_dentry_operations;
+	sb->s_root->d_op = &umsdos_dentry_operations;	/* FIXME! what about msdos_dentry_operations ? */
+
 	umsdos_patch_dentry_inode(sb->s_root, 0);
 
+#if 1
+printk( "/mn/ check_pseudo_root?\n");
+
 	/* Check whether to change to the /linux root */
 	new_root = check_pseudo_root(sb);
+#else
+	new_root = NULL;
+#endif
+
+printk( "/mn/ is_new_root?\n"); 
 
 	if (new_root) {
+printk( "/mn/. OK. we have new_root\n");
 		/* sanity check */
 		if (new_root->d_op != &umsdos_dentry_operations)
 			printk("umsdos_read_super: pseudo-root wrong ops!\n");
 
 		pseudo_root = new_root->d_inode;
-
 		saved_root = sb->s_root;
-		sb->s_root = new_root;
 		printk(KERN_INFO "UMSDOS: changed to alternate root\n");
+		dget (sb->s_root); sb->s_root = dget(new_root);
 	}
 	return sb;
 
@@ -379,22 +431,30 @@
 	 */
 	printk(KERN_INFO "check_pseudo_root: mounted as root\n");
 	root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN); 
+printk ("/mn/ after lookup_one\n");
 	if (IS_ERR(root))
 		goto out_noroot;
+		
+printk ("/mn/ Found c:\\linux\n");
 	if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
 		goto out_dput;
+printk ("/mn/ c:\\linux has inode and is directory\n");		
 
-	printk(KERN_INFO "check_pseudo_root: found %s/%s\n", root->d_parent->d_name.name, root->d_name.name);
+printk(KERN_INFO "check_pseudo_root: found %s/%s\n",
+root->d_parent->d_name.name, root->d_name.name);
 
 	/* look for /sbin/init */
 	sbin = lookup_one_len("sbin", root, 4);
 	if (IS_ERR(sbin))
 		goto out_dput;
+printk ("/mn/ has /sbin\n");		
 	if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))
 		goto out_dput_sbin;
+printk ("/mn/ /sbin has inode\n");		
 	init = lookup_one_len("init", sbin, 4);
 	if (IS_ERR(init))
 		goto out_dput_sbin;
+printk ("/mn/ has /sbin/init\n");		
 	if (!init->d_inode)
 		goto out_dput_init;
 	printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name);
@@ -410,6 +470,7 @@
 out_dput:
 	dput(root);
 out_noroot:
+printk ("/mn/ out_noroot\n");
 	return NULL;
 }
 
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/ioctl.c linux-my/fs/umsdos/ioctl.c
--- linux-2.4.9-PRISTINE/fs/umsdos/ioctl.c	Wed Apr 18 20:49:13 2001
+++ linux-my/fs/umsdos/ioctl.c	Mon Aug 27 12:43:55 2001
@@ -28,7 +28,7 @@
 				     void *buf,
 				     const char *name,
 				     int name_len,
-				     off_t offset,
+				     loff_t offset,
 				     ino_t ino,
 				     unsigned type)
 {
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/namei.c linux-my/fs/umsdos/namei.c
--- linux-2.4.9-PRISTINE/fs/umsdos/namei.c	Fri Aug 24 20:13:42 2001
+++ linux-my/fs/umsdos/namei.c	Wed Aug 29 21:50:52 2001
@@ -405,8 +405,15 @@
 		goto out_unlock;
 	/* make sure it's the same inode! */
 	ret = -ENOENT;
-	if (old->d_inode != old_inode)
-		goto out_dput;
+	/*
+	 * note: for hardlinks they will be different!
+	 *  old_inode will contain inode of .LINKxxx file containing data, and
+	 *  old->d_inode will contain inode of file containing path to .LINKxxx file
+	 */
+	if (!(old_info.entry.flags & UMSDOS_HLINK)) {
+	 	if (old->d_inode != old_inode)
+ 			goto out_dput;
+	}
 
 	new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 
 					new_info.fake.len);
@@ -531,7 +538,7 @@
 	struct umsdos_info hid_info;
 
 #ifdef UMSDOS_DEBUG_VERBOSE
-printk("umsdos_link: new %s%s -> %s/%s\n",
+printk("umsdos_link: new %s/%s -> %s/%s\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, 
 olddentry->d_parent->d_name.name, olddentry->d_name.name);
 #endif
@@ -698,17 +705,36 @@
 	if (ret == 0) {
 		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);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out_unlock2;
+
+		/* now resolve the link ... */
+		temp = umsdos_solve_hlink(temp);
+		ret = PTR_ERR(temp);
+		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);
 #endif
-		oldinode->i_nlink++;
+		temp->d_inode->i_nlink++;
 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
 olddentry->d_parent->d_name.name, olddentry->d_name.name,
 oldinode->i_ino, oldinode->i_nlink));
 		newattrs.ia_valid = 0;
-		ret = umsdos_notify_change_locked(olddentry, &newattrs);
+		ret = umsdos_notify_change_locked(temp, &newattrs);
+ 		if (ret == 0)
+			mark_inode_dirty(temp->d_inode);
+		dput(temp);
+out_unlock2:	
 		if (ret == 0)
 			mark_inode_dirty(olddentry->d_inode);
 	}
diff -ur linux-2.4.9-PRISTINE/fs/umsdos/rdir.c linux-my/fs/umsdos/rdir.c
--- linux-2.4.9-PRISTINE/fs/umsdos/rdir.c	Fri Feb  9 20:29:44 2001
+++ linux-my/fs/umsdos/rdir.c	Wed Aug 29 21:33:55 2001
@@ -32,7 +32,7 @@
 static int rdir_filldir (	void *buf,
 				const char *name,
 				int name_len,
-				off_t offset,
+				loff_t offset,
 				ino_t ino,
 				unsigned int d_type)
 {
@@ -111,6 +111,9 @@
 		 */
 Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n",
 dentry->d_parent->d_name.name, dentry->d_name.name));
+/* only patch if needed (because we get called even for lookup
+   (not only rlookup) stuff sometimes, like in umsdos_covered() */
+		if (dentry->d_inode->u.umsdos_i.i_patched == 0)	
 		umsdos_patch_dentry_inode(dentry, 0);
 
 	}
