diff -rc2P linux.1.1.12/config.in linux/config.in
*** linux.1.1.12/config.in	Fri May 20 23:49:24 1994
--- linux/config.in	Mon May 16 22:12:53 1994
***************
*** 113,116 ****
--- 113,117 ----
  bool 'xiafs filesystem support' CONFIG_XIA_FS n
  bool 'msdos fs support' CONFIG_MSDOS_FS y
+ bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS y
  bool '/proc filesystem support' CONFIG_PROC_FS y
  bool 'NFS filesystem support' CONFIG_NFS_FS y
diff -rc2P linux.1.1.12/fs/Makefile linux/fs/Makefile
*** linux.1.1.12/fs/Makefile	Tue Dec 21 05:30:23 1993
--- linux/fs/Makefile	Wed May 11 23:38:29 1994
***************
*** 34,37 ****
--- 34,40 ----
  FS_SUBDIRS := $(FS_SUBDIRS) xiafs
  endif
+ ifdef CONFIG_UMSDOS_FS
+ FS_SUBDIRS := $(FS_SUBDIRS) umsdos
+ endif
  ifdef CONFIG_SYSV_FS
  FS_SUBDIRS := $(FS_SUBDIRS) sysv
diff -rc2P linux.1.1.12/fs/filesystems.c linux/fs/filesystems.c
*** linux.1.1.12/fs/filesystems.c	Fri May 20 23:49:07 1994
--- linux/fs/filesystems.c	Wed May 11 23:38:29 1994
***************
*** 27,30 ****
--- 27,33 ----
  {
  	static int callable = 1;
+ #ifdef CONFIG_UMSDOS_FS
+ #include <linux/umsdos_fs.h>
+ #endif
  
  	if (!callable)
***************
*** 52,55 ****
--- 55,62 ----
  	register_filesystem(&(struct file_system_type)
  		{xiafs_read_super, "xiafs", 1, NULL});
+ #endif
+ #ifdef CONFIG_UMSDOS_FS
+ 	register_filesystem(&(struct file_system_type)
+ 	{UMSDOS_read_super,	"umsdos",	1, NULL});
  #endif
  
diff -rc2P linux.1.1.12/fs/msdos/Makefile linux/fs/msdos/Makefile
*** linux.1.1.12/fs/msdos/Makefile	Wed Dec  1 07:44:15 1993
--- linux/fs/msdos/Makefile	Wed May 11 23:48:19 1994
***************
*** 15,19 ****
  	$(AS) -o $*.o $<
  
! OBJS=	namei.o inode.o file.o dir.o misc.o fat.o
  
  msdos.o: $(OBJS)
--- 15,19 ----
  	$(AS) -o $*.o $<
  
! OBJS=	namei.o inode.o file.o dir.o misc.o fat.o mmap.o
  
  msdos.o: $(OBJS)
diff -rc2P linux.1.1.12/fs/msdos/dir.c linux/fs/msdos/dir.c
*** linux.1.1.12/fs/msdos/dir.c	Wed Dec  1 07:44:15 1993
--- linux/fs/msdos/dir.c	Wed May 11 23:48:19 1994
***************
*** 13,16 ****
--- 13,17 ----
  #include <linux/errno.h>
  #include <linux/stat.h>
+ #include <linux/string.h>
  
  
***************
*** 20,24 ****
  }
  
! static int msdos_readdir(struct inode *inode,struct file *filp,
      struct dirent *dirent,int count);
  
--- 21,25 ----
  }
  
! int msdos_readdir(struct inode *inode,struct file *filp,
      struct dirent *dirent,int count);
  
***************
*** 55,60 ****
  };
  
! static int msdos_readdir(struct inode *inode,struct file *filp,
!     struct dirent *dirent,int count)
  {
  	int ino,i,i2,last;
--- 56,65 ----
  };
  
! static int msdos_readdir_x(
! 	struct inode *inode,
! 	struct file *filp,
! 	struct dirent *dirent,
! 	int count,
! 	int dirent_in_fs)
  {
  	int ino,i,i2,last;
***************
*** 69,78 ****
  		else if (filp->f_pos < 2) {
  				walk = filp->f_pos++ ? ".." : ".";
! 				for (i = 0; *walk; walk++)
! 					put_fs_byte(*walk,dirent->d_name+i++);
! 				put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino);
! 				put_fs_byte(0,dirent->d_name+i);
! 				put_fs_word(i,&dirent->d_reclen);
! 				return i;
  			}
  	}
--- 74,90 ----
  		else if (filp->f_pos < 2) {
  				walk = filp->f_pos++ ? ".." : ".";
! 				if (dirent_in_fs){
! 					for (i = 0; *walk; walk++)
! 						put_fs_byte(*walk,dirent->d_name+i++);
! 					put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino);
! 					put_fs_byte(0,dirent->d_name+i);
! 					put_fs_word(i,&dirent->d_reclen);
! 					return i;
! 				}else{
! 					dirent->d_ino = MSDOS_ROOT_INO;
! 					strcpy (dirent->d_name,walk);
! 					dirent->d_reclen = filp->f_pos;
! 					return dirent->d_reclen;
! 				}
  			}
  	}
***************
*** 81,92 ****
  	while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
  		if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
  			for (i = last = 0; i < 8; i++) {
  				if (!(c = de->name[i])) break;
  				if (c >= 'A' && c <= 'Z') c += 32;
! 				if (c != ' ') last = i+1;
! 				put_fs_byte(c,i+dirent->d_name);
  			}
  			i = last;
! 			put_fs_byte('.',i+dirent->d_name);
  			i++;
  			for (i2 = 0; i2 < 3; i2++) {
--- 93,108 ----
  	while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
  		if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
+ 			char bufname[13];
+ 			char *ptname = bufname;
  			for (i = last = 0; i < 8; i++) {
  				if (!(c = de->name[i])) break;
  				if (c >= 'A' && c <= 'Z') c += 32;
! 				if (c != ' '){
! 					last = i+1;
! 					*ptname++ = c;
! 				}
  			}
  			i = last;
! 			*ptname++ = '.';
  			i++;
  			for (i2 = 0; i2 < 3; i2++) {
***************
*** 93,98 ****
  				if (!(c = de->ext[i2])) break;
  				if (c >= 'A' && c <= 'Z') c += 32;
! 				if (c != ' ') last = i+1;
! 				put_fs_byte(c,i+dirent->d_name);
  				i++;
  			}
--- 109,116 ----
  				if (!(c = de->ext[i2])) break;
  				if (c >= 'A' && c <= 'Z') c += 32;
! 				if (c != ' '){
! 					last = i+1;
! 					*ptname++ = c;
! 				}
  				i++;
  			}
***************
*** 102,108 ****
  				else if (!strcmp(de->name,MSDOS_DOTDOT))
  						ino = msdos_parent_ino(inode,0);
! 				put_fs_long(ino,&dirent->d_ino);
! 				put_fs_byte(0,i+dirent->d_name);
! 				put_fs_word(i,&dirent->d_reclen);
  				brelse(bh);
  				return i;
--- 120,133 ----
  				else if (!strcmp(de->name,MSDOS_DOTDOT))
  						ino = msdos_parent_ino(inode,0);
! 				bufname[i] = '\0';
! 				if (dirent_in_fs){
! 					put_fs_long(ino,&dirent->d_ino);
! 					memcpy_tofs(dirent->d_name,bufname,i+1);
! 					put_fs_word(i,&dirent->d_reclen);
! 				}else{
! 					dirent->d_ino = ino;
! 					memcpy (dirent->d_name,bufname,i+1);
! 					dirent->d_reclen = i;
! 				}
  				brelse(bh);
  				return i;
***************
*** 112,114 ****
--- 137,149 ----
  	if (bh) brelse(bh);
  	return 0;
+ }
+ int msdos_readdir(struct inode *inode,struct file *filp,
+     struct dirent *dirent,int count)
+ {
+ 	return msdos_readdir_x(inode,filp,dirent,count,1);
+ }
+ int msdos_readdir_kmem(struct inode *inode,struct file *filp,
+     struct dirent *dirent,int count)
+ {
+ 	return msdos_readdir_x(inode,filp,dirent,count,0);
  }
diff -rc2P linux.1.1.12/fs/msdos/file.c linux/fs/msdos/file.c
*** linux.1.1.12/fs/msdos/file.c	Fri May 20 23:48:37 1994
--- linux/fs/msdos/file.c	Wed May 11 23:48:20 1994
***************
*** 16,19 ****
--- 16,20 ----
  #include <linux/fcntl.h>
  #include <linux/stat.h>
+ #include <linux/string.h>
  
  #define MIN(a,b) (((a) < (b)) ? (a) : (b))
***************
*** 20,29 ****
  #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  
- static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
-     int count);
- static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
-     int count);
- 
- 
  static struct file_operations msdos_file_operations = {
  	NULL,			/* lseek - default */
--- 21,24 ----
***************
*** 33,37 ****
  	NULL,			/* select - default */
  	NULL,			/* ioctl - default */
! 	NULL,			/* mmap */
  	NULL,			/* no special open is needed */
  	NULL,			/* release */
--- 28,32 ----
  	NULL,			/* select - default */
  	NULL,			/* ioctl - default */
! 	msdos_mmap,		/* mmap */
  	NULL,			/* no special open is needed */
  	NULL,			/* release */
***************
*** 54,58 ****
  	msdos_bmap,		/* bmap */
  	msdos_truncate,		/* truncate */
! 	NULL			/* permission */
  };
  
--- 49,54 ----
  	msdos_bmap,		/* bmap */
  	msdos_truncate,		/* truncate */
! 	NULL,			/* permission */
! 	msdos_smap		/* smap */
  };
  
***************
*** 74,83 ****
  	NULL,			/* bmap */
  	msdos_truncate,		/* truncate */
! 	NULL			/* permission */
  };
  
  
! static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
!     int count)
  {
  	char *start;
--- 70,87 ----
  	NULL,			/* bmap */
  	msdos_truncate,		/* truncate */
! 	NULL,			/* permission */
! 	msdos_smap		/* smap */
  };
  
  
! /*
! 	Read a file into user space or kernel space
! */
! static int msdos_file_readx(
! 	struct inode *inode,
! 	struct file *filp,
! 	char *buf,
!     int count,
! 	int from_fs)
  {
  	char *start;
***************
*** 92,96 ****
  		return -EINVAL;
  	}
! 	if (!S_ISREG(inode->i_mode)) {
  		printk("msdos_file_read: mode = %07o\n",inode->i_mode);
  		return -EINVAL;
--- 96,101 ----
  		return -EINVAL;
  	}
! 	/* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
! 	if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
  		printk("msdos_file_read: mode = %07o\n",inode->i_mode);
  		return -EINVAL;
***************
*** 104,108 ****
  		if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
  		filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
! 		if (MSDOS_I(inode)->i_binary) {
  			memcpy_tofs(buf,data+offset,size);
  			buf += size;
--- 109,116 ----
  		if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
  		filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
! 		if (!from_fs){
! 			memcpy (buf,data+offset,size);
! 			buf += size;
! 		}else if (MSDOS_I(inode)->i_binary) {
  			memcpy_tofs(buf,data+offset,size);
  			buf += size;
***************
*** 132,139 ****
  }
  
! 
! static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
      int count)
  {
  	int sector,offset,size,left,written;
  	int error,carry;
--- 140,176 ----
  }
  
! /*
! 	Read a file into user space memory
! */
! int msdos_file_read(
! 	struct inode *inode,
! 	struct file *filp,
! 	char *buf,
      int count)
  {
+ 	return msdos_file_readx(inode,filp,buf,count,1);
+ }
+ /*
+ 	Read a file into kernel space memory
+ */
+ int msdos_file_read_kmem(
+ 	struct inode *inode,
+ 	struct file *filp,
+ 	char *buf,
+     int count)
+ {
+ 	return msdos_file_readx(inode,filp,buf,count,0);
+ }
+ 
+ /*
+ 	Write to a file either from kernel memory or user space
+ */
+ static int msdos_file_writex(
+ 	struct inode *inode,
+ 	struct file *filp,
+ 	char *buf,
+     int count,
+ 	int from_fs)
+ {
  	int sector,offset,size,left,written;
  	int error,carry;
***************
*** 146,150 ****
  		return -EINVAL;
  	}
! 	if (!S_ISREG(inode->i_mode)) {
  		printk("msdos_file_write: mode = %07o\n",inode->i_mode);
  		return -EINVAL;
--- 183,188 ----
  		return -EINVAL;
  	}
! 	/* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
! 	if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
  		printk("msdos_file_write: mode = %07o\n",inode->i_mode);
  		return -EINVAL;
***************
*** 170,174 ****
  			break;
  		}
! 		if (MSDOS_I(inode)->i_binary) {
  			memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
  			    buf,written = size);
--- 208,217 ----
  			break;
  		}
! 		if (!from_fs){
! 			/* Assume binary data when from kernel memory */
! 			memcpy(data+(filp->f_pos & (SECTOR_SIZE-1)),
! 			    buf,written = size);
! 			buf += size;
! 		}else if (MSDOS_I(inode)->i_binary) {
  			memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
  			    buf,written = size);
***************
*** 212,216 ****
  }
  
! 
  void msdos_truncate(struct inode *inode)
  {
--- 255,274 ----
  }
  
! /*
! 	Write to a file from user space
! */
! int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
!     int count)
! {
! 	return msdos_file_writex(inode,filp,buf,count,1);
! }
! /*
! 	Write to a file from kernel space
! */
! int msdos_file_write_kmem(struct inode *inode,struct file *filp,char *buf,
!     int count)
! {
! 	return msdos_file_writex(inode,filp,buf,count,0);
! }
  void msdos_truncate(struct inode *inode)
  {
diff -rc2P linux.1.1.12/fs/msdos/mmap.c linux/fs/msdos/mmap.c
*** linux.1.1.12/fs/msdos/mmap.c
--- linux/fs/msdos/mmap.c	Wed May 11 23:48:23 1994
***************
*** 0 ****
--- 1,156 ----
+ /*
+  *	fs/msdos/mmap.c
+  *
+  *	Written by Jacques Gelinas (jacques@solucorp.qc.ca)
+  *	Inspired by fs/nfs/mmap.c (Jaon Tombs 15 Aug 1993)
+  *
+  *	msdos mmap handling
+  */
+ #include <linux/stat.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+ #include <linux/shm.h>
+ #include <linux/errno.h>
+ #include <linux/mman.h>
+ #include <linux/string.h>
+ #include <linux/malloc.h>
+ #include <asm/segment.h>
+ #include <asm/system.h>
+ #include <linux/msdos_fs.h>
+ 
+ extern int share_page(struct vm_area_struct * area, struct task_struct * tsk,
+ 	struct inode * inode, unsigned long address, unsigned long error_code,
+ 	unsigned long newpage);
+ 
+ extern unsigned long put_page(struct task_struct * tsk,unsigned long page,
+ 	unsigned long address,int prot);
+ 
+ extern void file_mmap_free(struct vm_area_struct * area);
+ extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
+ 				unsigned long address);
+ 
+ /*
+ 	Perform the mapping of an adresse in memory
+ */
+ static void msdos_file_mmap_nopage(
+ 	int error_code,
+ 	struct vm_area_struct * area,
+ 	unsigned long address)
+ {
+ 	struct inode * inode = area->vm_inode;
+ 	unsigned int clear;
+ 	unsigned long page;
+ 	int pos;
+ 	long gap;	/* distance from eof to pos */
+ 
+ 	address &= PAGE_MASK;
+ 	pos = address - area->vm_start + area->vm_offset;
+ 
+ 	page = __get_free_page(GFP_KERNEL);
+ 	if (share_page(area, area->vm_task, inode, address, error_code, page)) {
+ 		++area->vm_task->mm->min_flt;
+ 		return;
+ 	}
+ 
+ 	++area->vm_task->mm->maj_flt;
+ 	if (!page) {
+ 		oom(current);
+ 		put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+ 		return;
+ 	}
+ 
+ 	clear = 0;
+ 	gap = inode->i_size - pos;
+ 	if (gap <= 0){
+ 		/* mmaping beyong end of file */
+ 		clear = PAGE_SIZE;
+ 	}else{
+ 		int cur_read;
+ 		int need_read;
+ 		struct file filp;
+ 		if (gap < PAGE_SIZE){
+ 			clear = PAGE_SIZE - gap;
+ 		}
+ 		filp.f_pos = pos;
+ 		need_read = PAGE_SIZE - clear;
+ 		cur_read = msdos_file_read_kmem (inode,&filp,(char*)page,need_read);
+ 		if (cur_read != need_read){
+ 			printk ("MSDOS: Error while reading an mmap file %d <> %d\n"
+ 				,cur_read,need_read);
+ 			free_page (page);
+ 			oom(current);
+ 			put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+ 			return;
+ 		}
+ 	}
+ 	if (!(error_code & PAGE_RW)) {
+ 		if (share_page(area, area->vm_task, inode, address, error_code, page))
+ 			return;
+ 	}
+ 	if (clear > 0){
+ 		#if 1
+ 			memset ((char*)page+PAGE_SIZE-clear,0,clear);
+ 		#else
+ 			unsigned long tmp = page + PAGE_SIZE;
+ 			while (clear--) {
+ 				*(char *)--tmp = 0;
+ 			}
+ 		#endif
+ 	}
+ 	if (put_page(area->vm_task,page,address,area->vm_page_prot))
+ 		return;
+ 	free_page(page);
+ 	oom(current);
+ }
+ struct vm_operations_struct msdos_file_mmap = {
+ 	NULL,			/* open */
+ 	file_mmap_free,		/* close */
+ 	msdos_file_mmap_nopage,/* nopage */
+ 	NULL,			/* wppage */
+ 	file_mmap_share,	/* share */
+ 	NULL,			/* unmap */
+ };
+ /*
+ 	Initialise a mmap operation on a file.	
+ 	Return 0 if ok, or a negative error code if not.
+ */
+ int msdos_mmap(
+ 	struct inode * inode,
+ 	struct file * file,
+ 	unsigned long addr,
+ 	size_t len,
+ 	int prot,
+ 	unsigned long off)
+ {
+ 	struct vm_area_struct * mpnt;
+ 
+ 	if (prot & PAGE_RW)	/* only PAGE_COW or read-only supported now */
+ 		return -EINVAL;
+ 	if (off & (inode->i_sb->s_blocksize - 1))
+ 		return -EINVAL;
+ 	if (!inode->i_sb || !S_ISREG(inode->i_mode))
+ 		return -EACCES;
+ 	if (!IS_RDONLY(inode)) {
+ 		inode->i_atime = CURRENT_TIME;
+ 		inode->i_dirt = 1;
+ 	}
+ 
+ 	mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ 	if (!mpnt)
+ 		return -ENOMEM;
+ 
+ 	unmap_page_range(addr, len);
+ 	mpnt->vm_task = current;
+ 	mpnt->vm_start = addr;
+ 	mpnt->vm_end = addr + len;
+ 	mpnt->vm_page_prot = prot;
+ 	mpnt->vm_share = NULL;
+ 	mpnt->vm_inode = inode;
+ 	inode->i_count++;
+ 	mpnt->vm_offset = off;
+ 	mpnt->vm_ops = &msdos_file_mmap;
+ 	insert_vm_struct (current,mpnt);
+ 	merge_segments (current->mm->mmap,NULL,NULL);
+ 	return 0;
+ }
diff -rc2P linux.1.1.12/fs/msdos/namei.c linux/fs/msdos/namei.c
*** linux.1.1.12/fs/msdos/namei.c	Fri May 20 23:48:37 1994
--- linux/fs/msdos/namei.c	Wed May 11 23:48:24 1994
***************
*** 361,365 ****
  
  
! int msdos_unlink(struct inode *dir,const char *name,int len)
  {
  	int res,ino;
--- 361,369 ----
  
  
! static int msdos_unlinkx(
! 	struct inode *dir,
! 	const char *name,
! 	int len,
! 	int nospc)	/* Flag special file ? */
  {
  	int res,ino;
***************
*** 376,380 ****
  		goto unlink_done;
  	}
! 	if (!S_ISREG(inode->i_mode)) {
  		res = -EPERM;
  		goto unlink_done;
--- 380,384 ----
  		goto unlink_done;
  	}
! 	if (!S_ISREG(inode->i_mode) && nospc){
  		res = -EPERM;
  		goto unlink_done;
***************
*** 393,396 ****
--- 397,411 ----
  }
  
+ int msdos_unlink(struct inode *dir,const char *name,int len)
+ {
+ 	return msdos_unlinkx (dir,name,len,1);
+ }
+ /*
+ 	Special entry for umsdos
+ */
+ int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
+ {
+ 	return msdos_unlinkx (dir,name,len,0);
+ }
  
  static int rename_same_dir(struct inode *old_dir,char *old_name,
diff -rc2P linux.1.1.12/fs/umsdos/Makefile linux/fs/umsdos/Makefile
*** linux.1.1.12/fs/umsdos/Makefile
--- linux/fs/umsdos/Makefile	Wed May 11 23:47:27 1994
***************
*** 0 ****
--- 1,40 ----
+ #
+ # Makefile for the umsdos unix-like filesystem routines.
+ #
+ # Note! Dependencies are done automagically by 'make dep', which also
+ # removes any old dependencies. DON'T put your own dependencies here
+ # unless it's something special (ie not a .c file).
+ #
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+ 
+ .c.s:
+ 	$(CC) $(CFLAGS) -S $<
+ .c.o:
+ 	$(CC) $(CFLAGS) -c $<
+ .s.o:
+ 	$(AS) -o $*.o $<
+ 
+ OBJS=	dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o\
+ 	rdir.o symlink.o #check.o
+ 
+ umsdos.o: $(OBJS)
+ 	$(LD) -r -o umsdos.o $(OBJS)
+ 
+ clean:
+ 	rm -f core *.o *.a *.s
+ 
+ dep:
+ 	$(CPP) -M *.c > .depend
+ 
+ p:
+ 	proto *.c >/usr/include/linux/umsdos_fs.p
+ 
+ doc:
+ 	nadoc -i -p umsdos.doc - /tmp/umsdos.mpg
+ 
+ #
+ # include a dependency file if one exists
+ #
+ ifeq (.depend,$(wildcard .depend))
+ include .depend
+ endif
diff -rc2P linux.1.1.12/fs/umsdos/check.c linux/fs/umsdos/check.c
*** linux.1.1.12/fs/umsdos/check.c
--- linux/fs/umsdos/check.c	Wed May 11 23:47:27 1994
***************
*** 0 ****
--- 1,55 ----
+ #include <asm/system.h>
+ 
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+ #include <linux/head.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>
+ 
+ extern unsigned long high_memory;
+ 
+ static int check_one_table(unsigned long * page_dir)
+ {
+ 	unsigned long pg_table = *page_dir;
+ 
+ 	if (!pg_table)
+ 		return 0;
+ 	if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) {
+ 		return 1;
+ 	}
+ 	return 0;
+ }
+ 
+ /*
+  * This function frees up all page tables of a process when it exits.
+  */
+ void check_page_tables(void)
+ {
+ 	unsigned long 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 = current->tss.cr3;
+ 	if (mem_map[MAP_NR(pg_dir)] > 1) {
+ 		return;
+ 	}
+ 	if (err == 0){
+ 		unsigned long *page_dir = (unsigned long *) pg_dir;
+ 		unsigned long *base = page_dir;
+ 		int i;
+ 		for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++){
+ 			int notok = check_one_table(page_dir);
+ 			if (notok){
+ 				err++;
+ 				printk ("|%d| ",page_dir-base);
+ 			}
+ 		}
+ 		if (err) printk ("Erreur MM %d\n",err);
+ 	}
+ }
+ 
diff -rc2P linux.1.1.12/fs/umsdos/dir.c linux/fs/umsdos/dir.c
*** linux.1.1.12/fs/umsdos/dir.c
--- linux/fs/umsdos/dir.c	Thu May 12 00:29:23 1994
***************
*** 0 ****
--- 1,703 ----
+ /*
+  *  linux/fs/umsdos/dir.c
+  *
+  *  Written 1993 by Jacques Gelinas
+  *	Inspired from linux/fs/msdos/... : Werner Almesberger
+  *
+  *  Extended MS-DOS directory handling functions
+  */
+ 
+ #include <asm/segment.h>
+ 
+ #include <linux/sched.h>
+ #include <linux/string.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/errno.h>
+ #include <linux/stat.h>
+ #include <linux/limits.h>
+ #include <linux/umsdos_fs.h>
+ #include <linux/malloc.h>
+ 
+ #define PRINTK(x)
+ #define Printk(x) printk x
+ 
+ #define UMSDOS_SPECIAL_DIRFPOS	3
+ extern struct inode *pseudo_root;
+ /*
+ 	So  grep *  doesn't complain in the presence of directories.
+ */
+ int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
+     int count)
+ {
+ 	return -EISDIR;
+ }
+ /*
+ 	Read count directory entries from directory filp
+ 	Return a negative value from linux/errno.h.
+ 	Return > 0 if success (the length of the file name).
+ 
+ 	This function is used by the normal readdir VFS entry point and by
+ 	some function who try to find out info on a file from a pure MSDOS
+ 	inode. See umsdos_locate_ancestor() below.
+ */
+ static int umsdos_readdir_x(
+ 	struct inode *dir,		/* Point to a description of the super block */
+ 	struct file *filp,		/* Point to a directory which is read */
+     struct dirent *dirent,	/* Will hold count directory entry */
+ 	int dirent_in_fs,		/* dirent point in user's space ? */
+ 	int count,
+ 	struct umsdos_dirent *u_entry,	/* Optionnal umsdos entry */
+ 	int follow_hlink,
+ 	off_t *pt_f_pos)		/* will hold the offset of the entry in EMD */
+ {
+ 	int ret = 0;
+ 	
+ 	umsdos_startlookup(dir);	
+ 	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
+ 		&& dir == pseudo_root
+ 		&& dirent_in_fs){
+ 		/*
+ 			We don't need to simulate this pseudo directory
+ 			when umsdos_readdir_x is called for internal operation
+ 			of umsdos. This is why dirent_in_fs is tested
+ 		*/
+ 		/* #Specification: pseudo root / directory /DOS
+ 			When umsdos operates in pseudo root mode (C:\linux is the
+ 			linux root), it simulate a directory /DOS which points to
+ 			the real root of the file system.
+ 		*/
+ 		put_fs_long(dir->i_sb->s_mounted->i_ino,&dirent->d_ino);
+ 		memcpy_tofs (dirent->d_name,"DOS",3);
+ 		put_fs_byte(0,dirent->d_name+3);
+ 		put_fs_word (3,&dirent->d_reclen);
+ 		if (u_entry != NULL) u_entry->flags = 0;
+ 		ret = 3;
+ 		filp->f_pos++;
+ 	}else if (filp->f_pos < 2
+ 		|| (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
+ 		/* #Specification: readdir / . and ..
+ 			The msdos filesystem manage the . and .. entry properly
+ 			so the EMD file won't hold any info about it.
+ 
+ 			In readdir, we assume that for the root directory
+ 			the read position will be 0 for ".", 1 for "..". For
+ 			a non root directory, the read position will be 0 for "."
+ 			and 32 for "..".
+ 		*/
+ 		/*
+ 			This is a trick used by the msdos file system (fs/msdos/dir.c)
+ 			to manage . and .. for the root directory of a file system.
+ 			Since there is no such entry in the root, fs/msdos/dir.c
+ 			use the following:
+ 
+ 			if f_pos == 0, return ".".
+ 			if f_pos == 1, return "..".
+ 
+ 			So let msdos handle it
+ 
+ 			Since umsdos entries are much larger, we share the same f_pos.
+ 			if f_pos is 0 or 1 or 32, we are clearly looking at . and
+ 			..
+ 
+ 			As soon as we get f_pos == 2 or f_pos == 64, then back to
+ 			0, but this time we are reading the EMD file.
+ 
+ 			Well, not so true. The problem, is that UMSDOS_REC_SIZE is
+ 			also 64, so as soon as we read the first record in the
+ 			EMD, we are back at offset 64. So we set the offset
+ 			to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
+ 			.. entry from msdos.
+ 		*/
+ 		ret = msdos_readdir(dir,filp,dirent,count);
+ 		if (filp->f_pos == 64) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
+ 		if (u_entry != NULL) u_entry->flags = 0;
+ 	}else{
+ 		struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
+ 		if (emd_dir != NULL){
+ 			if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
+ 			PRINTK (("f_pos %ld i_size %d\n",filp->f_pos,emd_dir->i_size));
+ 			ret = 0;
+ 			while (filp->f_pos < emd_dir->i_size){
+ 				struct umsdos_dirent entry;
+ 				off_t cur_f_pos = filp->f_pos;
+ 				if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
+ 					ret = -EIO;
+ 					break;
+ 				}else if (entry.name_len != 0){
+ 					/* #Specification: umsdos / readdir
+ 						umsdos_readdir() should fill a struct dirent with
+ 						an inode number. The cheap way to get it is to
+ 						do a lookup in the MSDOS directory for each
+ 						entry processed by the readdir() function.
+ 						This is not very efficient, but very simple. The
+ 						other way around is to maintain a copy of the inode
+ 						number in the EMD file. This is a problem because
+ 						this has to be maintained in sync using tricks.
+ 						Remember that MSDOS (the OS) does not update the
+ 						modification time (mtime) of a directory. There is
+ 						no easy way to tell that a directory was modified
+ 						during a DOS session and synchronise the EMD file.
+ 
+ 						Suggestion welcome.
+ 
+ 						So the easy way is used!
+ 					*/
+ 					struct umsdos_info info;
+ 					struct inode *inode;
+ 					int lret;
+ 					umsdos_parse (entry.name,entry.name_len,&info);
+ 					info.f_pos = cur_f_pos;
+ 					*pt_f_pos = cur_f_pos;
+ 					umsdos_manglename (&info);
+ 					lret = umsdos_real_lookup (dir,info.fake.fname
+ 						,info.fake.len,&inode);
+ 					PRINTK (("Cherche inode de %s lret %d flags %d\n"
+ 						,info.fake.fname,lret,entry.flags));
+ 					if (lret == 0
+ 						&& (entry.flags & UMSDOS_HLINK)
+ 						&& follow_hlink){
+ 						struct inode *rinode;
+ 						lret = umsdos_hlink2inode (inode,&rinode);
+ 						inode = rinode;
+ 					}
+ 					if (lret == 0){
+ 						/* #Specification: pseudo root / reading real root
+ 							The pseudo root (/linux) is logically
+ 							erased from the real root. This mean that
+ 							ls /DOS, won't show "linux". This avoids
+ 							infinite recursion /DOS/linux/DOS/linux while
+ 							walking the file system.
+ 						*/
+ 						if (inode != pseudo_root){
+ 							PRINTK (("Trouve ino %d ",inode->i_ino));
+ 							if (dirent_in_fs){
+ 								put_fs_long(inode->i_ino,&dirent->d_ino);
+ 								memcpy_tofs (dirent->d_name,entry.name
+ 									,entry.name_len);
+ 								put_fs_byte(0,dirent->d_name+entry.name_len);
+ 								put_fs_word (entry.name_len
+ 									,&dirent->d_reclen);
+ 								/* In this case, the caller only needs */
+ 								/* flags */
+ 								if (u_entry != NULL){
+ 									u_entry->flags = entry.flags;
+ 								}
+ 							}else{
+ 								dirent->d_ino = inode->i_ino;
+ 								memcpy (dirent->d_name,entry.name
+ 									,entry.name_len);
+ 								dirent->d_name[entry.name_len] = '\0';
+ 								dirent->d_reclen = entry.name_len;
+ 								if (u_entry != NULL) *u_entry = entry;
+ 							}
+ 							ret = entry.name_len;
+ 							iput (inode);
+ 							break;
+ 						}
+ 						iput (inode);
+ 					}else{
+ 						/* #Specification: umsdos / readdir / not in MSDOS
+ 							During a readdir operation, if the file is not
+ 							in the MSDOS directory anymore, the entry is
+ 							removed from the EMD file silently.
+ 						*/
+ 						ret = umsdos_writeentry (dir,emd_dir,&info,1);
+ 						if (ret != 0){
+ 							break;
+ 						}
+ 					}
+ 				}
+ 			}
+ 			iput(emd_dir);
+ 		}
+ 	}
+ 	umsdos_endlookup(dir);	
+ 	PRINTK (("read dir %p pos %d ret %d\n",dir,filp->f_pos,ret));
+ 	return ret;
+ }
+ /*
+ 	Read count directory entries from directory filp
+ 	Return a negative value from linux/errno.h.
+ 	Return > 0 if success (the length of the file name).
+ */
+ static int UMSDOS_readdir(
+ 	struct inode *dir,		/* Point to a description of the super block */
+ 	struct file *filp,		/* Point to a directory which is read */
+     struct dirent *dirent,	/* Will hold count directory entry */
+ 	int count)
+ {
+ 	int ret = -ENOENT;
+ 	while (1){
+ 		struct umsdos_dirent entry;
+ 		off_t f_pos;
+ 		ret = umsdos_readdir_x (dir,filp,dirent,1,count,&entry,1,&f_pos);
+ 		if (ret <= 0 || !(entry.flags & UMSDOS_HIDDEN)) break;
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Complete the inode content with info from the EMD file
+ */
+ void umsdos_lookup_patch (
+ 	struct inode *dir,
+ 	struct inode *inode,
+ 	struct umsdos_dirent *entry,
+ 	off_t  emd_pos)
+ {
+ 	/*
+ 		This function modify the state of a dir inode. It decides
+ 		if the dir is a umsdos dir or a dos dir. This is done
+ 		deeper in umsdos_patch_inode() called at the end of this function.
+ 
+ 		umsdos_patch_inode() may block because it is doing disk access.
+ 		At the same time, another process may get here to initialise
+ 		the same dir inode. There is 3 cases.
+ 
+ 		1-The inode is already initialised. We do nothing.
+ 		2-The inode is not initialised. We lock access and do it.
+ 		3-Like 2 but another process has lock the inode, so we try
+ 		  to lock it and right after check if initialisation is still
+ 		  needed.
+ 
+ 
+ 		Thanks to the mem option of the kernel command line, it was
+ 		possible to consistently reproduce this problem by limiting
+ 		my mem to 4 meg and running X.
+ 	*/
+ 	/*
+ 		Do this only if the inode is freshly read, because we will lose
+ 		the current (updated) content.
+ 	*/
+ 	/*
+ 		A lookup of a mount point directory yield the inode into
+ 		the other fs, so we don't care about initialising it. iget()
+ 		does this automaticly.
+ 	*/
+ 	if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
+ 		if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
+ 		if (!umsdos_isinit(inode)){
+ 			/* #Specification: umsdos / lookup / inode info
+ 				After successfully reading an inode from the MSDOS
+ 				filesystem, we use the EMD file to complete it.
+ 				We update the following field.
+ 
+ 				uid, gid, atime, ctime, mtime, mode.
+ 
+ 				We rely on MSDOS for mtime. If the file
+ 				was modified during an MSDOS session, at least
+ 				mtime will be meaningful. We do this only for regular
+ 				file.
+ 				
+ 				We don't rely on MSDOS for mtime for directory because
+ 				the MSDOS directory date is creation time (strange
+ 				MSDOS behavior) which fit nowhere in the three UNIX
+ 				time stamp.
+ 			*/
+ 			if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
+ 			inode->i_mode  = entry->mode;
+ 			inode->i_rdev  = entry->rdev;
+ 			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;
+ 			/* #Specification: umsdos / i_nlink
+ 				The nlink field of an inode is maintain by the MSDOS file system
+ 				for directory and by UMSDOS for other file. The logic is that
+ 				MSDOS is already figuring out what to do for directories and
+ 				does nothing for other files. For MSDOS, there are no hard link
+ 				so all file carry nlink==1. UMSDOS use some info in the
+ 				EMD file to plug the correct value.
+ 			*/
+ 			if (!S_ISDIR(entry->mode)){
+ 				if (entry->nlink > 0){
+ 					inode->i_nlink = entry->nlink;
+ 				}else{
+ 					printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n");
+ 				}
+ 			}
+ 			umsdos_patch_inode(inode,dir,emd_pos);
+ 		}
+ 		if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
+ if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
+ 	}
+ }
+ /*
+ 	Locate entry of an inode in a directory.
+ 	Return 0 or a negative error code.
+ 
+ 	Normally, this function must succeed. It means a strange corruption
+ 	in the file system if not.
+ */
+ int umsdos_inode2entry (
+ 	struct inode *dir,
+ 	struct inode *inode,
+ 	struct umsdos_dirent *entry)	/* Will hold the entry */
+ {
+ 	int ret = -ENOENT;
+ 	if (inode == pseudo_root){
+ 		/*
+ 			Quick way to find the name.
+ 			Also umsdos_readdir_x won't show /linux anyway
+ 		*/
+ 		memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
+ 		entry->name_len = UMSDOS_PSDROOT_LEN;
+ 		ret = 0;
+ 	}else{
+ 		struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
+ 		iput (emddir);
+ 		if (emddir == NULL){
+ 			/* This is a DOS directory */
+ 			struct file filp;
+ 			filp.f_pos = 0;
+ 			while (1){
+ 				struct dirent dirent;
+ 				if (msdos_readdir_kmem (dir,&filp,&dirent,1) <= 0){
+ 					printk ("UMSDOS: can't locate inode %ld in DOS directory???\n"
+ 						,inode->i_ino);
+ 				}else if (dirent.d_ino == inode->i_ino){
+ 					ret = 0;
+ 					memcpy (entry->name,dirent.d_name,dirent.d_reclen);
+ 					entry->name[dirent.d_reclen] = '\0';
+ 					entry->name_len = dirent.d_reclen;
+ 					inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+ 					inode->u.umsdos_i.i_emd_owner = 0;
+ 					umsdos_setup_dir_inode(inode);
+ 					break;
+ 				}
+ 			}
+ 		}else{
+ 			/* skip . and .. see umsdos_readdir_x() */
+ 			struct file filp;
+ 			filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+ 			while (1){
+ 				struct dirent dirent;
+ 				off_t f_pos;
+ 				if (umsdos_readdir_x(dir,&filp,&dirent
+ 					,0,1,entry,0,&f_pos) <= 0){
+ 					printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
+ 						,inode->i_ino);
+ 					break;
+ 				}else if (dirent.d_ino == inode->i_ino){
+ 					ret = 0;
+ 					umsdos_lookup_patch (dir,inode,entry,f_pos);
+ 					break;
+ 				}
+ 			}
+ 		}
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Locate the parent of a directory and the info on that directory
+ 	Return 0 or a negative error code.
+ */
+ static int umsdos_locate_ancestor (
+ 	struct inode *dir,
+ 	struct inode **result,
+ 	struct umsdos_dirent *entry)
+ {
+ 	int ret;
+ 	umsdos_patch_inode (dir,NULL,0);
+ 	ret = umsdos_real_lookup (dir,"..",2,result);
+ 	PRINTK (("result %d %x ",ret,*result));
+ 	if (ret == 0){
+ 		struct inode *adir = *result;
+ 		ret = umsdos_inode2entry (adir,dir,entry);
+ 	}
+ 	PRINTK (("\n"));
+ 	return ret;
+ }
+ /*
+ 	Build the path name of an inode (relative to the file system.
+ 	This function is need to set (pseudo) hard link.
+ 
+ 	It uses the same strategy as the standard getcwd().
+ */
+ int umsdos_locate_path (
+ 	struct inode *inode,
+ 	char *path)
+ {
+ 	int ret = 0;
+ 	struct inode *dir = inode;
+ 	char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+ 	if (bpath == NULL){
+ 		ret = -ENOMEM;
+ 	}else{
+ 		struct umsdos_dirent entry;
+ 		char *ptbpath = bpath+PATH_MAX-1;
+ 		*ptbpath = '\0';
+ 		PRINTK (("locate_path mode %x ",inode->i_mode));
+ 		if (!S_ISDIR(inode->i_mode)){
+ 			ret = umsdos_get_dirowner (inode,&dir);
+ 			PRINTK (("locate_path ret %d ",ret));
+ 			if (ret == 0){
+ 				ret = umsdos_inode2entry (dir,inode,&entry);
+ 				if (ret == 0){
+ 					ptbpath -= entry.name_len;
+ 					memcpy (ptbpath,entry.name,entry.name_len);
+ 					PRINTK (("ptbpath :%s: ",ptbpath));
+ 				}
+ 			}
+ 		}else{
+ 			dir->i_count++;
+ 		}
+ 		if (ret == 0){
+ 			while (dir != dir->i_sb->s_mounted){
+ 				struct inode *adir;
+ 				ret = umsdos_locate_ancestor (dir,&adir,&entry);
+ 				iput (dir);
+ 				dir = NULL;
+ 				PRINTK (("ancestor %d ",ret));
+ 				if (ret == 0){
+ 					*--ptbpath = '/';
+ 					ptbpath -= entry.name_len;
+ 					memcpy (ptbpath,entry.name,entry.name_len);
+ 					dir = adir;
+ 					PRINTK (("ptbpath :%s: ",ptbpath));
+ 				}else{
+ 					break;
+ 				}
+ 			}
+ 		}
+ 		strcpy (path,ptbpath);
+ 		kfree (bpath);
+ 	}
+ 	PRINTK (("\n"));
+ 	iput (dir);
+ 	return ret;
+ }
+ 
+ /*
+ 	Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
+ */
+ int umsdos_is_pseudodos (
+ 	struct inode *dir,
+ 	const char *name,
+ 	int len)
+ {
+ 	/* #Specification: pseudo root / DOS hard coded
+ 		The pseudo sub-directory DOS in the pseudo root is hard coded.
+ 		The name is DOS. This is done this way to help standardised
+ 		the umsdos layout. The idea is that from now on /DOS is
+ 		a reserved path and nobody will think of using such a path
+ 		for a package.
+ 	*/
+ 	return dir == pseudo_root
+ 		&& len == 3
+ 		&& name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
+ }
+ /*
+ 	Check if a file exist in the current directory.
+ 	Return 0 if ok, negative error code if not (ex: -ENOENT).
+ */
+ static int umsdos_lookup_x (
+ 	struct inode *dir,
+ 	const char *name,
+ 	int len,
+ 	struct inode **result,	/* Will hold inode of the file, if successful */
+ 	int nopseudo)			/* Don't care about pseudo root mode */
+ {
+ 	int ret = -ENOENT;
+ 	*result = NULL;
+ 	umsdos_startlookup(dir);	
+ 	if (len == 1 && name[0] == '.'){
+ 		*result = dir;
+ 		dir->i_count++;
+ 		ret = 0;
+ 	}else if (len == 2 && name[0] == '.' && name[1] == '.'){
+ 		if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
+ 			/* #Specification: pseudo root / .. in real root
+ 				Whenever a lookup is those in the real root for
+ 				the directory .., and pseudo root is active, the
+ 				pseudo root is returned.
+ 			*/
+ 			ret = 0;
+ 			*result = pseudo_root;
+ 			pseudo_root->i_count++;
+ 		}else{
+ 			/* #Specification: locating .. / strategy
+ 				We use the msdos filesystem to locate the parent directory.
+ 				But it is more complicated than that.
+ 				
+ 				We have to step back even further to
+ 				get the parent of the parent, so we can get the EMD
+ 				of the parent of the parent. Using the EMD file, we can
+ 				locate all the info on the parent, such a permissions
+ 				and owner.
+ 			*/
+ 			ret = umsdos_real_lookup (dir,"..",2,result);
+ 			PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
+ 			if (ret == 0
+ 				&& *result != dir->i_sb->s_mounted
+ 				&& *result != pseudo_root){
+ 				struct inode *aadir;
+ 				struct umsdos_dirent entry;
+ 				ret = umsdos_locate_ancestor (*result,&aadir,&entry);
+ 				iput (aadir);
+ 			}
+ 		}
+ 	}else if (umsdos_is_pseudodos(dir,name,len)){
+ 		/* #Specification: pseudo root / lookup(DOS)
+ 			A lookup of DOS in the pseudo root will always succeed
+ 			and return the inode of the real root.
+ 		*/
+ 		*result = dir->i_sb->s_mounted;
+ 		(*result)->i_count++;
+ 		ret = 0;
+ 	}else{
+ 		struct umsdos_info info;
+ 		ret = umsdos_parse (name,len,&info);
+ 		if (ret == 0) ret = umsdos_findentry (dir,&info,0);
+ 		PRINTK (("lookup %s pos %d ret %d len %d ",info.fake.fname,info.f_pos,ret
+ 			,info.fake.len));
+ 		if (ret == 0){
+ 			/* #Specification: umsdos / lookup
+ 				A lookup for a file is done in two step. First, we locate
+ 				the file in the EMD file. If not present, we return
+ 				an error code (-ENOENT). If it is there, we repeat the
+ 				operation on the msdos file system. If this fails, it means
+ 				that the file system is not in sync with the emd file.
+ 				We silently remove this entry from the emd file,
+ 				and return ENOENT.
+ 			*/
+ 			struct inode *inode;
+ 			ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
+ 			inode = *result;
+ 			if (inode == NULL){
+ 				printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
+ 					,info.fake.fname);
+ 				umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
+ 			}else{
+ 				umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
+ 				PRINTK (("lookup ino %d flags %d\n",inode->i_ino
+ 					,info.entry.flags));
+ 				if (info.entry.flags & UMSDOS_HLINK){
+ 					ret = umsdos_hlink2inode (inode,result);
+ 				}
+ 				if (*result == pseudo_root && !nopseudo){
+ 					/* #Specification: pseudo root / dir lookup
+ 						For the same reason as readdir, a lookup in /DOS for
+ 						the pseudo root directory (linux) will fail.
+ 					*/
+ 					/*
+ 						This has to be allowed for resolving hard link
+ 						which are recorded independantly of the pseudo-root
+ 						mode.
+ 					*/
+ 					iput (pseudo_root);
+ 					*result = NULL;
+ 					ret = -ENOENT;
+ 				}
+ 			}
+ 		}
+ 	}
+ 	umsdos_endlookup(dir);	
+ 	iput (dir);
+ 	return ret;
+ }
+ /*
+ 	Check if a file exist in the current directory.
+ 	Return 0 if ok, negative error code if not (ex: -ENOENT).
+ */
+ int UMSDOS_lookup (
+ 	struct inode *dir,
+ 	const char *name,
+ 	int len,
+ 	struct inode **result)	/* Will hold inode of the file, if successful */
+ {
+ 	return umsdos_lookup_x(dir,name,len,result,0);
+ }
+ /*
+ 	Locate the inode pointed by a (pseudo) hard link
+ 	Return 0 if ok, a negative error code if not.
+ */
+ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
+ {
+ 	int ret = -EIO;
+ 	char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+ 	*result = NULL;
+ 	if (path == NULL){
+ 		ret = -ENOMEM;
+ 		iput (hlink);
+ 	}else{
+ 		struct file filp;
+ 		filp.f_pos = 0;
+ 		PRINTK (("hlink2inode "));
+ 		if (msdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
+ 			==hlink->i_size){
+ 			struct inode *dir;
+ 			char *pt = path;
+ 			dir = hlink->i_sb->s_mounted;
+ 			path[hlink->i_size] = '\0';
+ 			iput (hlink);
+ 			dir->i_count++;
+ 			while (1){
+ 				char *start = pt;
+ 				int len;
+ 				while (*pt != '\0' && *pt != '/') pt++;
+ 				len = (int)(pt - start);
+ 				if (*pt == '/') *pt++ = '\0';
+ 				if (dir->u.umsdos_i.i_emd_dir == 0){
+ 					/* This is a DOS directory */
+ 					ret = msdos_lookup(dir,start,len,result);
+ 				}else{
+ 					ret = umsdos_lookup_x(dir,start,len,result,1);
+ 				}
+ 				PRINTK (("h2n lookup :%s: -> %d ",start,ret));
+ 				if (ret == 0 && *pt != '\0'){
+ 					dir = *result;
+ 				}else{
+ 					break;
+ 				}
+ 			}
+ 		}else{
+ 			iput (hlink);
+ 		}
+ 		PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
+ 		kfree (path);
+ 	}
+ 	return ret;
+ }
+ 
+ static struct file_operations umsdos_dir_operations = {
+ 	NULL,				/* lseek - default */
+ 	UMSDOS_dir_read,	/* read */
+ 	NULL,				/* write - bad */
+ 	UMSDOS_readdir,		/* readdir */
+ 	NULL,				/* select - default */
+ 	UMSDOS_ioctl_dir,	/* ioctl - default */
+ 	NULL,				/* mmap */
+ 	NULL,				/* no special open code */
+ 	NULL,				/* no special release code */
+ 	NULL				/* fsync */
+ };
+ 
+ struct inode_operations umsdos_dir_inode_operations = {
+ 	&umsdos_dir_operations,	/* default directory file-ops */
+ 	UMSDOS_create,		/* create */
+ 	UMSDOS_lookup,		/* lookup */
+ 	UMSDOS_link,		/* link */
+ 	UMSDOS_unlink,		/* unlink */
+ 	UMSDOS_symlink,		/* symlink */
+ 	UMSDOS_mkdir,		/* mkdir */
+ 	UMSDOS_rmdir,		/* rmdir */
+ 	UMSDOS_mknod,		/* mknod */
+ 	UMSDOS_rename,		/* rename */
+ 	NULL,			/* readlink */
+ 	NULL,			/* follow_link */
+ 	NULL,			/* bmap */
+ 	NULL,			/* truncate */
+ 	NULL			/* permission */
+ };
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
diff -rc2P linux.1.1.12/fs/umsdos/emd.c linux/fs/umsdos/emd.c
*** linux.1.1.12/fs/umsdos/emd.c
--- linux/fs/umsdos/emd.c	Wed May 11 23:47:28 1994
***************
*** 0 ****
--- 1,454 ----
+ /*
+  *  linux/fs/umsdos/emd.c
+  *
+  *  Written 1993 by Jacques Gelinas
+  *
+  *  Extended MS-DOS directory handling functions
+  */
+ #include <linux/types.h>
+ #include <linux/fcntl.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/umsdos_fs.h>
+ 
+ #define PRINTK(x)
+ #define Printk(x) printk x
+ 
+ /*
+ 	Write a block of bytes into one EMD file.
+ 	The block of data is NOT in user space.
+ 
+ 	Return 0 if ok, a negative error code if not.
+ */
+ int umsdos_emd_dir_write (
+ 	struct inode *emd_dir,
+ 	struct file *filp,
+ 	char *buf,	/* buffer in kernel memory, not in user space */
+ 	int count)
+ {
+ 	int written;
+ 	filp->f_flags = 0;
+ 	written = msdos_file_write_kmem (emd_dir,filp,buf,count);
+ 	return written != count ? -EIO : 0;
+ }
+ /*
+ 	Read a block of bytes from one EMD file.
+ 	The block of data is NOT in user space.
+ 	Retourne 0 if ok, -EIO if any error.
+ */
+ int umsdos_emd_dir_read (
+ 	struct inode *emd_dir,
+ 	struct file *filp,
+ 	char *buf,	/* buffer in kernel memory, not in user space */
+ 	int count)
+ {
+ 	int ret = 0;
+ 	int sizeread;
+ 	filp->f_flags = 0;
+ 	sizeread = msdos_file_read_kmem (emd_dir,filp,buf,count);
+ 	if (sizeread != count){
+ 		printk ("UMSDOS: problem with EMD file. Can't read\n");
+ 		ret = -EIO;
+ 	}
+ 	return ret;
+ 
+ }
+ /*
+ 	Locate the EMD file in a directory and optionnally, creates it.
+ 
+ 	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
+ */
+ struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat)
+ {
+ 	struct inode *ret = NULL;
+ 	if (dir->u.umsdos_i.i_emd_dir != 0){
+ 		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
+ 		PRINTK (("deja trouve %d %x [%d] "
+ 			,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));
+ 	}else{
+ 		umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
+ 		PRINTK (("emd_dir_lookup "));
+ 		if (ret != NULL){
+ 			PRINTK (("Find --linux "));
+ 			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+ 		}else if (creat){
+ 			int code;
+ 			PRINTK (("avant create "));
+ 			dir->i_count++;
+ 			code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
+ 				,S_IFREG|0777,&ret);
+ 			PRINTK (("Creat EMD code %d ret %x ",code,ret));
+ 			if (ret != NULL){
+ 				dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+ 			}else{
+ 				printk ("UMSDOS: Can't create EMD file\n");
+ 			}
+ 		}
+ 	}
+ 	if (ret != NULL){
+ 		/* Disable UMSDOS_notify_change() for EMD file */
+ 		ret->u.umsdos_i.i_emd_owner = 0xffffffff;
+ 	}
+ 	return ret;
+ }
+ 
+ /*
+ 	Read an entry from the EMD file.
+ 	Support variable length record.
+ 	Return -EIO if error, 0 if ok.
+ */
+ int umsdos_emd_dir_readentry (
+ 	struct inode *emd_dir,
+ 	struct file *filp,
+ 	struct umsdos_dirent *entry)
+ {
+ 	int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE);
+ 	if (ret == 0){
+ 		/* Variable size record. Maybe, we have to read some more */
+ 		int recsize = umsdos_evalrecsize (entry->name_len);
+ 		if (recsize > UMSDOS_REC_SIZE){
+ 			ret = umsdos_emd_dir_read(emd_dir,filp
+ 				,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE);
+ 			
+ 		}
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Write an entry in the EMD file.
+ 	Return 0 if ok, -EIO if some error.
+ */
+ int umsdos_writeentry (
+ 	struct inode *dir,
+ 	struct inode *emd_dir,
+ 	struct umsdos_info *info,
+ 	int free_entry)		/* This entry is deleted, so Write all 0's */
+ {
+ 	int ret = 0;
+ 	struct file filp;
+ 	struct umsdos_dirent *entry = &info->entry;
+ 	struct umsdos_dirent entry0;
+ 	if (free_entry){
+ 		/* #Specification: EMD file / empty entries
+ 			Unused entry in the EMD file are identify
+ 			by the name_len field equal to 0. However to
+ 			help future extension (or bug corretion :-( ),
+ 			empty entries are filled with 0.
+ 		*/
+ 		memset (&entry0,0,sizeof(entry0));
+ 		entry = &entry0;
+ 	}else if (entry->name_len > 0){
+ 		memset (entry->name+entry->name_len,'\0'
+ 			,sizeof(entry->name)-entry->name_len);
+ 		/* #Specification: EMD file / spare bytes
+ 			10 bytes are unused in each record of the EMD. They
+ 			are set to 0 all the time. So it will be possible
+ 			to do new stuff and rely on the state of those
+ 			bytes in old EMD file around.
+ 		*/
+ 		memset (entry->spare,0,sizeof(entry->spare));
+ 	}
+ 	filp.f_pos = info->f_pos;
+ 	ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize);
+ 	if (ret != 0){
+ 		printk ("UMSDOS: problem with EMD file. Can't write\n");
+ 	}else{
+ 		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ 		dir->i_dirt = 1;
+ 	}
+ 	return ret;
+ }
+ 
+ #define CHUNK_SIZE (16*UMSDOS_REC_SIZE)
+ struct find_buffer{
+ 	char buffer[CHUNK_SIZE];
+ 	int pos;	/* read offset in buffer */
+ 	int size;	/* Current size of buffer */
+ 	struct file filp;
+ };
+ 
+ /*
+ 	Fill the read buffer and take care of the byte remaining inside.
+ 	Unread bytes are simply move to the beginning.
+ 
+ 	Return -ENOENT if EOF, 0 if ok, a negativ error code if any problem.
+ */
+ static int umsdos_fillbuf (
+ 	struct inode *inode,
+ 	struct find_buffer *buf)
+ {
+ 	int ret = -ENOENT;
+ 	int mustmove = buf->size - buf->pos;
+ 	int mustread;
+ 	int remain;
+ 	if (mustmove > 0){
+ 		memcpy (buf->buffer,buf->buffer+buf->pos,mustmove);
+ 	}
+ 	buf->pos = 0;
+ 	mustread = CHUNK_SIZE - mustmove;
+ 	remain = inode->i_size - buf->filp.f_pos;
+ 	if (remain < mustread) mustread = remain;
+ 	if (mustread > 0){
+ 		ret = umsdos_emd_dir_read (inode,&buf->filp,buf->buffer+mustmove
+ 			,mustread);
+ 		if (ret == 0) buf->size = mustmove + mustread;		
+ 	}else if (mustmove){
+ 		buf->size = mustmove;
+ 		ret = 0;
+ 	}
+ 	return ret;
+ }
+ 
+ /*
+ 	General search, locate a name in the EMD file or an empty slot to
+ 	store it. if info->entry.name_len == 0, search the first empty
+ 	slot (of the proper size).
+ 
+ 	Caller must do iput on *pt_emd_dir.
+ 
+ 	Return 0 if found, -ENOENT if not found, another error code if
+ 	other problem.
+ 
+ 	So this routine is used to either find an existing entry or to
+ 	create a new one, while making sure it is a new one. After you
+ 	get -ENOENT, you make sure the entry is stuffed correctly and
+ 	call umsdos_writeentry().
+ 
+ 	To delete an entry, you find it, zero out the entry (memset)
+ 	and call umsdos_writeentry().
+ 
+ 	All this to say that umsdos_writeentry must be call after this
+ 	function since it rely on the f_pos field of info.
+ */
+ static int umsdos_find (
+ 	struct inode *dir,
+ 	struct umsdos_info *info,		/* Hold name and name_len */
+ 									/* Will hold the entry found */
+ 	struct inode **pt_emd_dir)		/* Will hold the emd_dir inode */
+ 									/* or NULL if not found */
+ {
+ 	/* #Specification: EMD file structure
+ 		The EMD file uses a fairly simple layout. It is made of records
+ 		(UMSDOS_REC_SIZE == 64). When a name can't be written is a single
+ 		record, multiple contiguous record are allocated.
+ 	*/
+ 	int ret = -ENOENT;
+ 	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1);
+ 	if (emd_dir != NULL){
+ 		struct umsdos_dirent *entry = &info->entry;
+ 		int recsize = info->recsize;
+ 		struct {
+ 			off_t posok;	/* Position available to store the entry */
+ 			int found;		/* A valid empty position has been found */
+ 			off_t one;		/* One empty position -> maybe <- large enough */
+ 			int onesize;	/* size of empty region starting at one */
+ 		}empty;
+ 		/* Read several entries at a time to speed up the search */
+ 		struct find_buffer buf;
+ 		buf.pos = 0;
+ 		buf.size = 0;
+ 		buf.filp.f_pos = 0;
+ 		empty.found = 0;
+ 		empty.posok = emd_dir->i_size;
+ 		empty.onesize = 0;
+ 		while (1){
+ 			struct umsdos_dirent *rentry = (struct umsdos_dirent*)
+ 				(buf.buffer + buf.pos);
+ 			int file_pos = buf.filp.f_pos - buf.size + buf.pos;
+ 			if (buf.pos == buf.size){
+ 				ret = umsdos_fillbuf (emd_dir,&buf);
+ 				if (ret < 0){
+ 					/* Not found, so note where it can be added */
+ 					info->f_pos = empty.posok;
+ 					break;
+ 				}
+ 			}else if (rentry->name_len == 0){
+ 				/* We are looking for an empty section at least */
+ 				/* recsize large */
+ 				if (entry->name_len == 0){
+ 					info->f_pos = file_pos;
+ 					ret = 0;
+ 					break;
+ 				}else if (!empty.found){
+ 					if (empty.onesize == 0){
+ 						/* This is the first empty record of a section */
+ 						empty.one = file_pos;
+ 					}
+ 					/* grow the empty section */
+ 					empty.onesize += UMSDOS_REC_SIZE;
+ 					if (empty.onesize == recsize){
+ 						/* here is a large enough section */
+ 						empty.posok = empty.one;
+ 						empty.found = 1;
+ 					}
+ 				}
+ 				buf.pos += UMSDOS_REC_SIZE;
+ 			}else{
+ 				int entry_size = umsdos_evalrecsize(rentry->name_len);
+ 				if (buf.pos+entry_size > buf.size){
+ 					ret = umsdos_fillbuf (emd_dir,&buf);
+ 					if (ret < 0){
+ 						/* Not found, so note where it can be added */
+ 						info->f_pos = empty.posok;
+ 						break;
+ 					}
+ 				}else{
+ 					empty.onesize = 0;	/* Reset the free slot search */
+ 					if (entry->name_len == rentry->name_len
+ 						&& memcmp(entry->name,rentry->name,rentry->name_len)
+ 							==0){
+ 						info->f_pos = file_pos;
+ 						*entry = *rentry;
+ 						ret = 0;
+ 						break;
+ 					}else{
+ 						buf.pos += entry_size;
+ 					}
+ 				}
+ 			}	
+ 		}
+ 		umsdos_manglename(info);
+ 	}
+ 	*pt_emd_dir = emd_dir;
+ 	return ret;
+ }
+ /*
+ 	Add a new entry in the emd file
+ 	Return 0 if ok or a negative error code.
+ 	Return -EEXIST if the entry already exist.
+ 
+ 	Complete the information missing in info.
+ */
+ int umsdos_newentry (
+ 	struct inode *dir,
+ 	struct umsdos_info *info)
+ {
+ 	struct inode *emd_dir;
+ 	int ret = umsdos_find (dir,info,&emd_dir);
+ 	if (ret == 0){
+ 		ret = -EEXIST;
+ 	}else if (ret == -ENOENT){
+ 		ret = umsdos_writeentry(dir,emd_dir,info,0);
+ 		PRINTK (("umsdos_newentry EDM ret = %d\n",ret));
+ 	}
+ 	iput (emd_dir);
+ 	return ret;
+ }
+ /*
+ 	Create a new hidden link.
+ 	Return 0 if ok, an error code if not.
+ */
+ int umsdos_newhidden (
+ 	struct inode *dir,
+ 	struct umsdos_info *info)
+ {
+ 	struct inode *emd_dir;
+ 	int ret;
+ 	umsdos_parse ("..LINK",6,info);
+ 	info->entry.name_len = 0;
+ 	ret = umsdos_find (dir,info,&emd_dir);
+ 	iput (emd_dir);
+ 	if (ret == -ENOENT || ret == 0){
+ 		/* #Specification: hard link / hidden name
+ 			When a hard link is created, the original file is renamed
+ 			to a hidden name. The name is "..LINKNNN" where NNN is a
+ 			number define from the entry offset in the EMD file.
+ 		*/
+ 		info->entry.name_len = sprintf (info->entry.name,"..LINK%ld"
+ 			,info->f_pos);
+ 		ret = 0;
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Remove an entry from the emd file
+ 	Return 0 if ok, a negative error code otherwise.
+ 
+ 	Complete the information missing in info.
+ */
+ int umsdos_delentry (
+ 	struct inode *dir,
+ 	struct umsdos_info *info,
+ 	int isdir)
+ {
+ 	struct inode *emd_dir;
+ 	int ret = umsdos_find (dir,info,&emd_dir);
+ 	if (ret == 0){
+ 		if (info->entry.name_len != 0){
+ 			if ((isdir != 0) != (S_ISDIR(info->entry.mode) != 0)){
+ 				if (S_ISDIR(info->entry.mode)){
+ 					ret = -EISDIR;
+ 				}else{
+ 					ret = -ENOTDIR;
+ 				}
+ 			}else{
+ 				ret = umsdos_writeentry(dir,emd_dir,info,1);
+ 			}
+ 		}
+ 	}
+ 	iput(emd_dir);
+ 	return ret;
+ }
+ 
+ 
+ /*
+ 	Verify is a EMD directory is empty.
+ 	Return 0 if not empty
+ 		   1 if empty
+ 		   2 if empty, no EMD file.
+ */
+ int umsdos_isempty (struct inode *dir)
+ {
+ 	int ret = 2;
+ 	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
+ 	/* If the EMD file does not exist, it is certainly empty :-) */
+ 	if (emd_dir != NULL){
+ 		struct file filp;
+ 		/* Find an empty slot */
+ 		filp.f_pos = 0;
+ 		filp.f_flags = O_RDONLY;
+ 		ret = 1;
+ 		while (filp.f_pos < emd_dir->i_size){
+ 			struct umsdos_dirent entry;
+ 			if (umsdos_emd_dir_readentry(emd_dir,&filp,&entry)!=0){
+ 				ret = 0;
+ 				break;
+ 			}else if (entry.name_len != 0){
+ 				ret = 0;
+ 				break;
+ 			}	
+ 		}
+ 		iput (emd_dir);
+ 	}
+ 	return ret;
+ }
+ 
+ /*
+ 	Locate an entry in a EMD directory.
+ 	Return 0 if ok, errcod if not, generally -ENOENT.
+ */
+ int umsdos_findentry (
+ 	struct inode *dir,
+ 	struct umsdos_info *info,
+ 	int expect)		/* 0: anything */
+ 					/* 1: file */
+ 					/* 2: directory */
+ {
+ 	struct inode *emd_dir;
+ 	int ret = umsdos_find (dir,info,&emd_dir);
+ 	if (ret == 0){
+ 		if (expect != 0){
+ 			if (S_ISDIR(info->entry.mode)){
+ 				if (expect != 2) ret = -EISDIR;
+ 			}else if (expect == 2){
+ 				ret = -ENOTDIR;
+ 			}
+ 		}
+ 	}
+ 	iput (emd_dir);
+ 	return ret;
+ }
+ 
diff -rc2P linux.1.1.12/fs/umsdos/file.c linux/fs/umsdos/file.c
*** linux.1.1.12/fs/umsdos/file.c
--- linux/fs/umsdos/file.c	Wed May 11 23:47:28 1994
***************
*** 0 ****
--- 1,103 ----
+ /*
+  *  linux/fs/umsdos/file.c
+  *
+  *  Written 1993 by Jacques Gelinas
+  *	inpired from linux/fs/msdos/file.c Werner Almesberger
+  *
+  *  Extended MS-DOS regular file handling primitives
+  */
+ 
+ #include <asm/segment.h>
+ #include <asm/system.h>
+ 
+ #include <linux/sched.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/errno.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/umsdos_fs.h>
+ 
+ 
+ #define PRINTK(x)
+ #define Printk(x)	printk x
+ /*
+ 	Read a file into user space memory
+ */
+ static int UMSDOS_file_read(
+ 	struct inode *inode,
+ 	struct file *filp,
+ 	char *buf,
+     int count)
+ {
+ 	/* We have to set the access time because msdos don't care */
+ 	int ret = msdos_file_read(inode,filp,buf,count);
+ 	inode->i_atime = CURRENT_TIME;
+ 	inode->i_dirt = 1;
+ 	return ret;
+ }
+ /*
+ 	Write a file from user space memory
+ */
+ static int UMSDOS_file_write(
+ 	struct inode *inode,
+ 	struct file *filp,
+ 	char *buf,
+     int count)
+ {
+ 	return msdos_file_write(inode,filp,buf,count);
+ }
+ /*
+ 	Truncate a file to 0 length.
+ */
+ static void UMSDOS_truncate(struct inode *inode)
+ {
+ 	PRINTK (("UMSDOS_truncate\n"));
+ 	msdos_truncate (inode);
+ 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ 	inode->i_dirt = 1;
+ }
+ /*
+ 	See inode.c
+ 	
+ 	Some entry point are filled dynamicly with function pointers
+ 	from the msdos file_operations and file_inode_operations.
+ 	
+ 	The idea is to have the code as independant as possible from
+ 	the msdos file system.
+ */
+ 
+ struct file_operations umsdos_file_operations = {
+ 	NULL,				/* lseek - default */
+ 	UMSDOS_file_read,	/* read */
+ 	UMSDOS_file_write,	/* write */
+ 	NULL,				/* readdir - bad */
+ 	NULL,				/* select - default */
+ 	NULL,				/* ioctl - default */
+ 	msdos_mmap,			/* mmap */
+ 	NULL,				/* no special open is needed */
+ 	NULL,				/* release */
+ 	NULL				/* fsync */
+ };
+ 
+ struct inode_operations umsdos_file_inode_operations = {
+ 	&umsdos_file_operations,	/* default file operations */
+ 	NULL,			/* create */
+ 	NULL,			/* lookup */
+ 	NULL,			/* link */
+ 	NULL,			/* unlink */
+ 	NULL,			/* symlink */
+ 	NULL,			/* mkdir */
+ 	NULL,			/* rmdir */
+ 	NULL,			/* mknod */
+ 	NULL,			/* rename */
+ 	NULL,			/* readlink */
+ 	NULL,			/* follow_link */
+ 	NULL,			/* bmap */
+ 	UMSDOS_truncate,/* truncate */
+ 	NULL,			/* permission */
+ 	msdos_smap		/* smap */
+ };
+ 
+ 
diff -rc2P linux.1.1.12/fs/umsdos/inode.c linux/fs/umsdos/inode.c
*** linux.1.1.12/fs/umsdos/inode.c
--- linux/fs/umsdos/inode.c	Thu May 12 09:44:21 1994
***************
*** 0 ****
--- 1,465 ----
+ /*
+  *  linux/fs/umsdos/inode.c
+  *
+  *	Written 1993 by Jacques Gelinas 
+  *	Inspired from linux/fs/msdos/... by Werner Almesberger
+  *
+  */
+ 
+ #include <stdlib.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/errno.h>
+ #include <asm/segment.h>
+ #include <linux/string.h>
+ #include <linux/ctype.h>
+ #include <linux/stat.h>
+ #include <linux/umsdos_fs.h>
+ 
+ struct inode *pseudo_root=NULL;		/* Useful to simulate the pseudo DOS */
+ 									/* directory. See UMSDOS_readdir_x() */
+ 
+ /* #Specification: convention / PRINTK Printk and printk
+ 	Here is the convention for the use of printk inside fs/umsdos
+ 
+ 	printk carry important message (error or status).
+ 	Printk is for debugging (it is a macro defined at the beginning of
+ 		   most source.
+ 	PRINTK is a nulled Printk macro.
+ 
+ 	This convention makes the source easier to read, and Printk easier
+ 	to shut off.
+ */
+ #define PRINTK(x)
+ #define Printk(x) printk x
+ 
+ 
+ void UMSDOS_put_inode(struct inode *inode)
+ {
+ 	PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
+ 		,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
+ 		,inode->u.umsdos_i.i_emd_dir));
+ 	msdos_put_inode(inode);
+ }
+ 
+ 
+ void UMSDOS_put_super(struct super_block *sb)
+ {
+ 	msdos_put_super(sb);
+ }
+ 
+ 
+ void UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
+ {
+ 	msdos_statfs(sb,buf);
+ }
+ 
+ 
+ /*
+ 	Call msdos_lookup, but set back the original msdos function table.
+ 	Retourne 0 if ok, or a negative error code if not.
+ */
+ int umsdos_real_lookup (
+ 	struct inode *dir,
+ 	const char *name,
+ 	int len,
+ 	struct inode **result)	/* Will hold inode of the file, if successful */
+ {
+ 	int ret;
+ 	dir->i_count++;
+ 	ret = msdos_lookup (dir,name,len,result);
+ 	return ret;
+ }
+ /*
+ 	Complete the setup of an directory inode.
+ 	First, it completes the function pointers, then
+ 	it locates the EMD file. If the EMD is there, then plug the
+ 	umsdos function table. If not, use the msdos one.
+ */
+ void umsdos_setup_dir_inode (struct inode *inode)
+ {
+ 	inode->u.umsdos_i.i_emd_dir = 0;
+ 	{
+ 		struct inode *emd_dir = umsdos_emd_dir_lookup (inode,0);
+ 		extern struct inode_operations umsdos_rdir_inode_operations;
+ 		inode->i_op = emd_dir != NULL
+ 			? &umsdos_dir_inode_operations
+ 			: &umsdos_rdir_inode_operations;
+ 		iput (emd_dir);
+ 	}
+ }
+ /*
+ 	Add some info into an inode so it can find its owner quickly
+ */
+ void umsdos_set_dirinfo(
+ 	struct inode *inode,
+ 	struct inode *dir,
+ 	off_t f_pos)
+ {
+ 	struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
+ 	inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+ 	inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
+ 	iput (emd_owner);
+ 	inode->u.umsdos_i.pos = f_pos;
+ }
+ /*
+ 	Tells if an Umsdos inode has been "patched" once.
+ 	Returne != 0 if so.
+ */
+ int umsdos_isinit (struct inode *inode)
+ {
+ #if	1
+ 	return inode->u.umsdos_i.i_emd_owner != 0;
+ #elif 0
+ 	return inode->i_atime != 0;
+ #else
+ 	return inode->i_count > 1;
+ #endif
+ }
+ /*
+ 	Connect the proper tables in the inode and add some info.
+ */
+ void umsdos_patch_inode (
+ 	struct inode *inode,
+ 	struct inode *dir,		/* May be NULL */
+ 	off_t f_pos)
+ {
+ 	/*
+ 		This function is called very early to setup the inode, somewhat
+ 		too early (called by UMSDOS_read_inode). At this point, we can't
+ 		do to much, such as lookup up EMD files and so on. This causes
+ 		confusion in the kernel. This is why some initialisation
+ 		will be done when dir != NULL only.
+ 
+ 		UMSDOS do run piggy back on top of msdos fs. It looks like something
+ 		is missing in the VFS to accomodate stacked fs. Still unclear what
+ 		(quite honestly).
+ 
+ 		Well, maybe one! A new entry "may_unmount" which would allow
+ 		the stacked fs to allocate some inode permanently and release
+ 		them at the end. Doing that now introduce a problem. unmount
+ 		always fail because some inodes are in use.
+ 	*/
+ 	if (!umsdos_isinit(inode)){
+ 		inode->u.umsdos_i.i_emd_dir = 0;
+ 		if (S_ISREG(inode->i_mode)){
+ 			static char is_init = 0;
+ 			if (!is_init){
+ 				/*
+ 					I don't want to change the msdos file system code
+ 					so I get the adress of some subroutine dynamicly
+ 					once.
+ 				*/
+ 				umsdos_file_inode_operations.bmap = inode->i_op->bmap;
+ 				inode->i_op = &umsdos_file_inode_operations;
+ 				is_init = 1;
+ 			}
+ 			inode->i_op = &umsdos_file_inode_operations;
+ 		}else if (S_ISDIR(inode->i_mode)){
+ 			if (dir != NULL){
+ 				umsdos_setup_dir_inode(inode);
+ 			}
+ 		}else if (S_ISLNK(inode->i_mode)){
+ 			inode->i_op = &umsdos_symlink_inode_operations;
+ 		}else if (S_ISCHR(inode->i_mode)){
+ 			inode->i_op = &chrdev_inode_operations;
+ 		}else if (S_ISBLK(inode->i_mode)){
+ 			inode->i_op = &blkdev_inode_operations;
+ 		}else if (S_ISFIFO(inode->i_mode)){
+ 			init_fifo(inode);
+ 		}
+ 		if (dir != NULL){
+ 			/* #Specification: inode / umsdos info
+ 				The first time an inode is seen (inode->i_count == 1),
+ 				the inode number of the EMD file which control this inode
+ 				is tagged to this inode. It allows operation such
+ 				as notify_change to be handled.
+ 			*/
+ 			/*
+ 				This is done last because it also control the
+ 				status of umsdos_isinit()
+ 			*/
+ 			umsdos_set_dirinfo (inode,dir,f_pos);
+ 		}
+ 	}else if (dir != NULL){
+ 		/*
+ 			Test to see if the info is maintained.
+ 			This should be removed when the file system will be proven.
+ 		*/
+ 		struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
+ 		iput (emd_owner);
+ 		if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
+ 			printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
+ 				,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
+ 		}
+ 	}
+ }
+ /*
+ 	Get the inode of the directory which owns this inode.
+ 	Return 0 if ok, -EIO if error.
+ */
+ int umsdos_get_dirowner(
+ 	struct inode *inode,
+ 	struct inode **result)	/* Hold NULL if any error */
+ 							/* else, the inode of the directory */
+ {
+ 	int ret = -EIO;
+ 	unsigned long ino = inode->u.umsdos_i.i_dir_owner;
+ 	*result = NULL;
+ 	if (ino == 0){
+ 		printk ("UMSDOS: umsdos_get_dirowner ino == 0\n");
+ 	}else{
+ 		struct inode *dir = *result = iget(inode->i_sb,ino);
+ 		if (dir != NULL){
+ 			umsdos_patch_inode (dir,NULL,0);
+ 			ret = 0;
+ 		}
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Load an inode from disk.
+ */
+ void UMSDOS_read_inode(struct inode *inode)
+ {
+ 	PRINTK (("read inode %x ino = %d ",inode,inode->i_ino));
+ 	msdos_read_inode(inode);
+ 	PRINTK (("ino = %d %d\n",inode->i_ino,inode->i_count));
+ 	if (S_ISDIR(inode->i_mode)
+ 		&& (inode->u.umsdos_i.u.dir_info.creating != 0
+ 			|| inode->u.umsdos_i.u.dir_info.looking != 0
+ 			|| inode->u.umsdos_i.u.dir_info.p != NULL)){
+ 		Printk (("read inode %d %d %p\n"
+ 			,inode->u.umsdos_i.u.dir_info.creating
+ 			,inode->u.umsdos_i.u.dir_info.looking
+ 			,inode->u.umsdos_i.u.dir_info.p));
+ 	}
+ 	/* #Specification: Inode / post initialisation
+ 		To completly initialise an inode, we need access to the owner
+ 		directory, so we can locate more info in the EMD file. This is
+ 		not available the first time the inode is access, we use
+ 		a value in the inode to tell if it has been finally initialised.
+ 
+ 		At first, we have tried testing i_count but it was causing
+ 		problem. It is possible that two or more process use the
+ 		newly accessed inode. While the first one block during
+ 		the initialisation (probably while reading the EMD file), the
+ 		others believe all is well because i_count > 1. They go banana
+ 		with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
+ 	*/
+ 	umsdos_patch_inode(inode,NULL,0);
+ }
+ 
+ /*
+ 	Update the disk with the inode content
+ */
+ void UMSDOS_write_inode(struct inode *inode)
+ {
+ 	PRINTK (("UMSDOS_write_inode emd %d\n",inode->u.umsdos_i.i_emd_owner));
+ 	msdos_write_inode(inode);
+ 	UMSDOS_notify_change (NOTIFY_TIME,inode);
+ }
+ int UMSDOS_notify_change (int flags, struct inode *inode)
+ {
+ 	int ret = 0;
+ 	if (inode->i_nlink > 0){
+ 		/* #Specification: notify_change / i_nlink > 0
+ 			notify change is only done for inode with nlink > 0. An inode
+ 			with nlink == 0 is no longer associated with any entry in
+ 			the EMD file, so there is nothing to update.
+ 		*/
+ 		unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
+ 		if (inode == inode->i_sb->s_mounted){
+ 			/* #Specification: root inode / attributes
+ 				I don't know yet how this should work. Normally
+ 				the attributes (permissions bits, owner, times) of
+ 				a directory are stored in the EMD file of its parent.
+ 
+ 				One thing we could do is store the attributes of the root
+ 				inode in its own EMD file. A simple entry named "." could
+ 				be used for this special case. It would be read once
+ 				when the file system is mounted and update in
+ 				UMSDOS_notify_change() (right here).
+ 
+ 				I am not sure of the behavior of the root inode for
+ 				a real UNIX file system. For now, this is a nop.
+ 			*/
+ 		}else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){
+ 			/* This inode is not a EMD file nor an inode used internally
+ 				by MSDOS, so we can update its status.
+ 				See emd.c
+ 			*/
+ 			struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
+ 			PRINTK (("notify change %p ",inode));
+ 			if (emd_owner == NULL){
+ 				printk ("UMSDOS: emd_owner = NULL ???");
+ 				ret = -EPERM;
+ 			}else{
+ 				struct file filp;
+ 				struct umsdos_dirent entry;
+ 				filp.f_pos = inode->u.umsdos_i.pos;
+ 				PRINTK (("pos = %d ",filp.f_pos));
+ 				/* Read only the start of the entry since we don't touch */
+ 				/* the name */
+ 				ret = umsdos_emd_dir_read (emd_owner,&filp,(char*)&entry
+ 					,UMSDOS_REC_SIZE);
+ 				if (ret == 0){
+ 					if (flags & NOTIFY_UIDGID){
+ 						entry.uid = inode->i_uid;
+ 						entry.gid = inode->i_gid;
+ 						/* Remove those flags msdos don't like */
+ 						flags &= ~NOTIFY_UIDGID;
+ 					}
+ 					if (flags & NOTIFY_MODE){
+ 						entry.mode = inode->i_mode;
+ 						flags &= ~NOTIFY_MODE;
+ 					}
+ 					if (flags & NOTIFY_TIME){
+ 						entry.atime = inode->i_atime;
+ 						entry.mtime = inode->i_mtime;
+ 						entry.ctime = inode->i_ctime;
+ 					}
+ 					entry.nlink = inode->i_nlink;
+ 					filp.f_pos = inode->u.umsdos_i.pos;
+ 					ret = umsdos_emd_dir_write (emd_owner,&filp,(char*)&entry
+ 						,UMSDOS_REC_SIZE);
+ 					PRINTK (("notify pos %d ret %d nlink %d "
+ 						,inode->u.umsdos_i.pos
+ 						,ret,entry.nlink));
+ 					/* #Specification: notify_change / msdos fs
+ 						notify_change operation are done only on the
+ 						EMD file. The msdos fs is not even called.
+ 					*/
+ 					#if 0
+ 					if (ret == 0
+ 						&& (S_ISDIR(inode->i_mode)
+ 							|| S_ISREG(inode->i_mode))){
+ 						ret = msdos_notify_change(flags, inode);
+ 						printk ("msdos_notify %x %d",inode,ret);
+ 					}
+ 					#endif
+ 				}
+ 				iput (emd_owner);
+ 			}
+ 			PRINTK (("\n"));
+ 		}
+ 	}
+ 	return ret;
+ }
+ 
+ /* #Specification: function name / convention
+ 	A simple convention for function name has been used in
+ 	the UMSDOS file system. First all function use the prefix
+ 	umsdos_ to avoid name clash with other part of the kernel.
+ 
+ 	And standard VFS entry point use the prefix UMSDOS (upper case)
+ 	so it's easier to tell them apart.
+ */
+ 
+ static struct super_operations umsdos_sops = { 
+ 	UMSDOS_read_inode,
+ 	UMSDOS_notify_change,
+ 	UMSDOS_write_inode,
+ 	UMSDOS_put_inode,
+ 	UMSDOS_put_super,
+ 	NULL, /* added in 0.96c */
+ 	UMSDOS_statfs,
+ 	NULL
+ };
+ 
+ /*
+ 	Read the super block of an Extended MS-DOS FS.
+ */
+ struct super_block *UMSDOS_read_super(
+ 	struct super_block *s,
+ 	void *data,
+ 	int silent)
+ {
+ 	/* #Specification: mount / options
+ 		Umsdos run on top of msdos. Currently, it supports no
+ 		mount option, but happily pass all option received to
+ 		the msdos driver. I am not sure if all msdos mount option
+ 		make sens with Umsdos. Here are at least those who
+ 		are useful.
+ 			uid=
+ 			gid=
+ 
+ 		These options affect the operation of umsdos in directories
+ 		which do not have an EMD file. They behave like normal
+ 		msdos directory, with all limitation of msdos.
+ 	*/
+ 	struct super_block *sb = msdos_read_super(s,data,silent);
+ 	printk ("UMSDOS Alpha %d.%d\n",UMSDOS_VERSION,UMSDOS_RELEASE);
+ 	if (sb != NULL){
+ 		sb->s_op = &umsdos_sops;
+ 		PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
+ 		umsdos_setup_dir_inode (sb->s_mounted);
+ 		PRINTK (("End umsdos_read_super\n"));
+ 		if (s == super_blocks){
+ 			/* #Specification: pseudo root / mount
+ 				When a umsdos fs is mounted, a special handling is done
+ 				if it is the root partition. We check for the presence
+ 				of the file /linux/etc/init or /linux/etc/rc.
+ 				If one is there, we do a chroot("/linux").
+ 
+ 				We check both because (see init/main.c) the kernel
+ 				try to exec init at different place and if it fails
+ 				it tries /bin/sh /etc/rc. To be consistent with
+ 				init/main.c, many more test would have to be done
+ 				to locate init. Any complain ?
+ 
+ 				The chroot is done manually in init/main.c but the
+ 				info (the inode) is located at mount time and store
+ 				in a global variable (pseudo_root) which is used at
+ 				different place in the umsdos driver. There is no
+ 				need to store this variable elsewhere because it
+ 				will always be one, not one per mount.
+ 
+ 				This feature allows the installation
+ 				of a linux system within a DOS system in a subdirectory.
+ 	
+ 				A user may install its linux stuff in c:\linux
+ 				avoiding any clash with existing DOS file and subdirectory.
+ 				When linux boots, it hides this fact, showing a normal
+ 				root directory with /etc /bin /tmp ...
+ 
+ 				The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
+ 				in the macro UMSDOS_PSDROOT_NAME.
+ 			*/
+ 
+ 			struct inode *pseudo;
+ 			Printk (("Mounting root\n"));
+ 			if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME
+ 					,UMSDOS_PSDROOT_LEN,&pseudo)==0
+ 				&& S_ISDIR(pseudo->i_mode)){
+ 				struct inode *etc = NULL;
+ 				struct inode *rc = NULL;
+ 				Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
+ 				if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
+ 					&& S_ISDIR(etc->i_mode)){
+ 					struct inode *init;
+ 					Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
+ 					if ((umsdos_real_lookup (etc,"init",4,&init)==0
+ 							&& S_ISREG(init->i_mode))
+ 						|| (umsdos_real_lookup (etc,"rc",2,&rc)==0
+ 							&& S_ISREG(rc->i_mode))){
+ 						umsdos_setup_dir_inode (pseudo);
+ 						Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
+ 						pseudo_root = pseudo;
+ 						pseudo->i_count++;
+ 						pseudo = NULL;
+ 					}
+ 					iput (init);
+ 					iput (rc);
+ 				}
+ 				iput (etc);
+ 			}
+ 			iput (pseudo);
+ 		}
+ 	}
+ 	return sb;
+ }
+ 
+ 
diff -rc2P linux.1.1.12/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
*** linux.1.1.12/fs/umsdos/ioctl.c
--- linux/fs/umsdos/ioctl.c	Wed May 11 23:47:30 1994
***************
*** 0 ****
--- 1,259 ----
+ /*
+  *  linux/fs/umsdos/ioctl.c
+  *
+  *  Written 1993 by Jacques Gelinas
+  *
+  *  Extended MS-DOS ioctl directory handling functions
+  */
+ #include <asm/segment.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/umsdos_fs.h>
+ 
+ #define PRINTK(x)
+ #define Printk(x) printk x
+ 
+ /*
+ 	Perform special function on a directory
+ */
+ int UMSDOS_ioctl_dir (
+ 	struct inode *dir,
+ 	struct file *filp,
+ 	unsigned int cmd,
+ 	unsigned long data)
+ {
+ 	int ret = -EPERM;
+ 	/* #Specification: ioctl / acces
+ 		Only root (effective id) is allowed to do IOCTL on directory
+ 		in UMSDOS. EPERM is returned for other user.
+ 	*/
+ 	if (current->euid == 0
+ 		|| cmd == UMSDOS_GETVERSION){
+ 		struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data;
+ 		ret = -EINVAL;
+ 		/* #Specification: ioctl / prototypes
+ 			The official prototype for the umsdos ioctl on directory
+ 			is:
+ 
+ 			int ioctl (
+ 				int fd,		// File handle of the directory
+ 				int cmd,	// command
+ 				struct umsdos_ioctl *data)
+ 
+ 			The struct and the commands are defined in linux/umsdos_fs.h.
+ 
+ 			umsdos_progs/umsdosio.c provide an interface in C++ to all
+ 			these ioctl. umsdos_progs/udosctl is a small utility showing
+ 			all this.
+ 
+ 			These ioctl generally allow one to work on the EMD or the
+ 			DOS directory independantly. These are essential to implement
+ 			the synchroniser.
+ 		*/
+ 		PRINTK (("ioctl %d ",cmd));
+ 		if (cmd == UMSDOS_GETVERSION){
+ 			/* #Specification: ioctl / UMSDOS_GETVERSION
+ 				The field version and release of the structure
+ 				umsdos_ioctl are filled with the version and release
+ 				number of the fs code in the kernel. This will allow
+ 				some form of checking. Users won't be able to run
+ 				incompatible utility such as the synchroniser (umssync).
+ 				umsdos_progs/umsdosio.c enforce this checking.
+ 
+ 				Return always 0.
+ 			*/
+ 			put_fs_byte (UMSDOS_VERSION,&idata->version);
+ 			put_fs_byte (UMSDOS_RELEASE,&idata->release);
+ 			ret = 0;
+ 		}else if (cmd == UMSDOS_READDIR_DOS){
+ 			/* #Specification: ioctl / UMSDOS_READDIR_DOS
+ 				One entry is read from the DOS directory at the current
+ 				file position. The entry is put as is in the dos_dirent
+ 				field of struct umsdos_ioctl.
+ 
+ 				Return > 0 if success.
+ 			*/
+ 			ret = msdos_readdir(dir,filp,&idata->dos_dirent,1);
+ 		}else if (cmd == UMSDOS_READDIR_EMD){
+ 			/* #Specification: ioctl / UMSDOS_READDIR_EMD
+ 				One entry is read from the EMD at the current
+ 				file position. The entry is put as is in the umsdos_dirent
+ 				field of struct umsdos_ioctl. The corresponding mangled
+ 				DOS entry name is put in the dos_dirent field.
+ 
+ 				All entries are read including hidden links. Blank
+ 				entries are skipped.
+ 
+ 				Return > 0 if success.
+ 			*/
+ 			struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
+ 			if (emd_dir != NULL){
+ 				while (1){
+ 					if (filp->f_pos >= emd_dir->i_size){
+ 						ret = 0;
+ 						break;
+ 					}else{
+ 						struct umsdos_dirent entry;
+ 						off_t f_pos = filp->f_pos;
+ 						ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry);
+ 						if (ret < 0){
+ 							break;
+ 						}else if (entry.name_len > 0){
+ 							struct umsdos_info info;
+ 							ret = entry.name_len;
+ 							umsdos_parse (entry.name,entry.name_len,&info);
+ 							info.f_pos = f_pos;
+ 							umsdos_manglename(&info);
+ 							memcpy_tofs(&idata->umsdos_dirent,&entry
+ 								,sizeof(entry));
+ 							memcpy_tofs(&idata->dos_dirent.d_name
+ 								,info.fake.fname,info.fake.len+1);
+ 							break;
+ 						}
+ 					}
+ 				}
+ 				iput (emd_dir);
+ 			}else{
+ 				/* The absence of the EMD is simply seen as an EOF */
+ 				ret = 0;
+ 			}
+ 		}else if (cmd == UMSDOS_INIT_EMD){
+ 			/* #Specification: ioctl / UMSDOS_INIT_EMD
+ 				The UMSDOS_INIT_EMD command make sure the EMD
+ 				exist for a directory. If it does not, it is
+ 				created. Also, it makes sure the directory functions
+ 				table (struct inode_operations) is set to the UMSDOS
+ 				semantic. This mean that umssync may be applied to
+ 				an "opened" msdos directory, and it will change behavior
+ 				on the fly.
+ 
+ 				Return 0 if success.
+ 			*/
+ 			extern struct inode_operations umsdos_rdir_inode_operations;
+ 			struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
+ 			ret = emd_dir != NULL;
+ 			iput (emd_dir);
+ 					
+ 			dir->i_op = ret
+ 				? &umsdos_dir_inode_operations
+ 				: &umsdos_rdir_inode_operations;
+ 		}else{
+ 			struct umsdos_ioctl data;
+ 			memcpy_fromfs (&data,idata,sizeof(data));
+ 			if (cmd == UMSDOS_CREAT_EMD){
+ 				/* #Specification: ioctl / UMSDOS_CREAT_EMD
+ 					The umsdos_dirent field of the struct umsdos_ioctl is used
+ 					as is to create a new entry in the EMD of the directory.
+ 					The DOS directory is not modified.
+ 					No validation is done (yet).
+ 
+ 					Return 0 if success.
+ 				*/
+ 				struct umsdos_info info;
+ 				/* This makes sure info.entry and info in general is correctly */
+ 				/* initialised */
+ 				memcpy (&info.entry,&data.umsdos_dirent
+ 					,sizeof(data.umsdos_dirent));
+ 				umsdos_parse (data.umsdos_dirent.name
+ 					,data.umsdos_dirent.name_len,&info);
+ 				ret = umsdos_newentry (dir,&info);
+ 			}else if (cmd == UMSDOS_UNLINK_EMD){
+ 				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
+ 					The umsdos_dirent field of the struct umsdos_ioctl is used
+ 					as is to remove an entry from the EMD of the directory.
+ 					No validation is done (yet). The mode field is used
+ 					to validate S_ISDIR or S_ISREG.
+ 
+ 					Return 0 if success.
+ 				*/
+ 				struct umsdos_info info;
+ 				/* This makes sure info.entry and info in general is correctly */
+ 				/* initialised */
+ 				memcpy (&info.entry,&data.umsdos_dirent
+ 					,sizeof(data.umsdos_dirent));
+ 				umsdos_parse (data.umsdos_dirent.name
+ 					,data.umsdos_dirent.name_len,&info);
+ 				ret = umsdos_delentry (dir,&info
+ 					,S_ISDIR(data.umsdos_dirent.mode));
+ 			}else if (cmd == UMSDOS_UNLINK_DOS){
+ 				/* #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
+ 					fields are used.
+ 
+ 					Return 0 if success.
+ 				*/
+ 				dir->i_count++;
+ 				ret = msdos_unlink (dir,data.dos_dirent.d_name
+ 					,data.dos_dirent.d_reclen);
+ 			}else if (cmd == UMSDOS_RMDIR_DOS){
+ 				/* #Specification: ioctl / UMSDOS_RMDIR_DOS
+ 					The dos_dirent field of the struct umsdos_ioctl is used to
+ 					execute a msdos_unlink operation. The d_name and d_reclen
+ 					fields are used.
+ 
+ 					Return 0 if success.
+ 				*/
+ 				dir->i_count++;
+ 				ret = msdos_rmdir (dir,data.dos_dirent.d_name
+ 					,data.dos_dirent.d_reclen);
+ 			}else if (cmd == UMSDOS_STAT_DOS){
+ 				/* #Specification: ioctl / UMSDOS_STAT_DOS
+ 					The dos_dirent field of the struct umsdos_ioctl is
+ 					used to execute a stat operation in the DOS directory.
+ 					The d_name and d_reclen fields are used.
+ 
+ 					The following field of umsdos_ioctl.stat are filled.
+ 
+ 					st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
+ 					Return 0 if success.
+ 				*/
+ 				struct inode *inode;
+ 				ret = umsdos_real_lookup (dir,data.dos_dirent.d_name
+ 					,data.dos_dirent.d_reclen,&inode);
+ 				if (ret == 0){
+ 					data.stat.st_ino = inode->i_ino;
+ 					data.stat.st_mode = inode->i_mode;
+ 					data.stat.st_size = inode->i_size;
+ 					data.stat.st_atime = inode->i_atime;
+ 					data.stat.st_ctime = inode->i_ctime;
+ 					data.stat.st_mtime = inode->i_mtime;
+ 					memcpy_tofs (&idata->stat,&data.stat,sizeof(data.stat));
+ 					iput (inode);
+ 				}
+ 			}else if (cmd == UMSDOS_DOS_SETUP){
+ 				/* #Specification: ioctl / UMSDOS_DOS_SETUP
+ 					The UMSDOS_DOS_SETUP ioctl allow changing the
+ 					default permission of the MsDOS file system driver
+ 					on the fly. The MsDOS driver apply global permission
+ 					to every file and directory. Normally these permissions
+ 					are controlled by a mount option. This is not
+ 					available for root partition, so a special utility
+ 					(umssetup) is provided to do this, normally in
+ 					/etc/rc.local.
+ 
+ 					Be aware that this apply ONLY to MsDOS directory
+ 					(those without EMD --linux-.---). Umsdos directory
+ 					have independant (standard) permission for each
+ 					and every file.
+ 
+ 					The field umsdos_dirent provide the information needed.
+ 					umsdos_dirent.uid and gid sets the owner and group.
+ 					umsdos_dirent.mode set the permissions flags.
+ 				*/
+ 				dir->i_sb->u.msdos_sb.fs_uid = data.umsdos_dirent.uid;
+ 				dir->i_sb->u.msdos_sb.fs_gid = data.umsdos_dirent.gid;
+ 				dir->i_sb->u.msdos_sb.fs_umask = data.umsdos_dirent.mode;
+ 				ret = 0;
+ 			}
+ 		}
+ 	}
+ 	PRINTK (("ioctl return %d\n",ret));
+ 	return ret;
+ }
+ 
+ 
+ 
diff -rc2P linux.1.1.12/fs/umsdos/mangle.c linux/fs/umsdos/mangle.c
*** linux.1.1.12/fs/umsdos/mangle.c
--- linux/fs/umsdos/mangle.c	Thu May 12 07:10:16 1994
***************
*** 0 ****
--- 1,478 ----
+ /*
+  *  linux/fs/umsdos/mangle.c
+  *
+  *	Written 1993 by Jacques Gelinas 
+  *
+  * Control the mangling of file name to fit msdos name space.
+  * Many optimisation by GLU == dglaude@is1.vub.ac.be (GLAUDE DAVID)
+ */
+ #include <linux/errno.h>
+ #include <linux/ctype.h>
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+ #include <linux/umsdos_fs.h>
+ 
+ /*
+ 	Complete the mangling of the MSDOS fake name
+ 	based on the position of the entry in the EMD file.
+ 
+ 	Simply complete the job of umsdos_parse; fill the extension.
+ 
+ 	Beware that info->f_pos must be set.
+ */
+ void umsdos_manglename (struct umsdos_info *info)
+ {
+ 	if (info->msdos_reject){
+ 		/* #Specification: file name / non MSDOS conforming / mangling
+ 			Each non MSDOS conforming file has a special extension
+ 			build from the entry position in the EMD file.
+ 
+ 			This number is then transform in a base 32 number, where
+ 			each digit is expressed like hexadecimal number, using
+ 			digit and letter, except it uses 22 letters from 'a' to 'v'.
+ 			The number 32 comes from 2**5. It is faster to split a binary
+ 			number using a base which is a power of two. And I was 32
+ 			when I started this project. Pick your answer :-) .
+ 
+ 			If the result is '0', it is replace with '_', simply
+ 			to make it odd.
+ 
+ 			This is true for the first two character of the extension.
+ 			The last one is taken from a list of odd character, which
+ 			are:
+ 
+ 				{ } ( ) ! ` ^ & @
+ 
+ 			With this scheme, we can produce 9216 ( 9* 32 * 32)
+ 			different extensions which should not clash with any useful
+ 			extension already popular or meaningful. Since most directory
+ 			have much less than 32 * 32 files in it, the first character
+ 			of the extension of any mangle name will be {.
+ 
+ 			Here are the reason to do this (this kind of mangling).
+ 
+ 			-The mangling is deterministic. Just by the extension, we
+ 			 are able to locate the entry in the EMD file.
+ 
+ 			-By keeping to beginning of the file name almost unchange,
+ 			 we are helping the MSDOS user.
+ 
+ 			-The mangling produces names not too ugly, so an msdos user
+ 			 may live with it (remember it, type it, etc...).
+ 
+ 			-The mangling produces names ugly enough so no one will
+ 			 ever think of using such a name in real life. This is not
+ 			 fool proof. I don't think there is a total solution to this.
+ 		*/
+ 		union {
+ 			int entry_num;
+ 			struct {
+ 				unsigned num1:5,num2:5,num3:5;
+ 			}num;
+ 		} u;
+ 		char *pt = info->fake.fname + info->fake.len;
+ 		/* lookup for encoding the last character of the extension */
+ 		/* It contain valid character after the ugly one to make sure */
+ 		/* even if someone overflow the 32 * 32 * 9 limit, it still do */
+ 		/* something */
+ 		#define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@'
+ 		static char lookup3[]={
+ 			SPECIAL_MANGLING,
+ 			/* This is the start of lookup12 */
+ 			'_','1','2','3','4','5','6','7','8','9',
+ 			'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
+ 			'p','q','r','s','t','u','v' 
+ 		};
+ 		#define lookup12 (lookup3+9)
+ 		u.entry_num = info->f_pos / UMSDOS_REC_SIZE;
+ 		if (u.entry_num > (9* 32 * 32)){
+ 			printk ("UMSDOS: More than 9216 file in a directory.\n"
+ 				"This may break the mangling strategy.\n"
+ 				"Not a killer problem. See doc.\n");
+ 		}
+ 		*pt++ = '.';
+ 		*pt++ = lookup3 [u.num.num3];
+ 		*pt++ = lookup12[u.num.num2];
+ 		*pt++ = lookup12[u.num.num1];
+ 		*pt = '\0';		/* help doing printk */	
+ 		info->fake.len += 4;
+ 		info->msdos_reject = 0;		/* Avoid mangling twice */
+ 	}
+ }
+ 
+ /*
+ 	Evaluate the record size needed to store of name of len character.
+ 	The value returned is a multiple of UMSDOS_REC_SIZE.
+ */
+ int umsdos_evalrecsize (int len)
+ {
+ 	struct umsdos_dirent dirent;
+ 	int nbrec = 1+((len-1+(dirent.name-(char*)&dirent))
+                    / UMSDOS_REC_SIZE);
+ 	return nbrec * UMSDOS_REC_SIZE;
+ 	/*
+ 	GLU	This should be inlined or something to speed it up to the max.
+ 	GLU	nbrec is absolutely not needed to return the value.
+ 	*/
+ }
+ #ifdef TEST
+ int umsdos_evalrecsize_old (int len)
+ {
+ 	struct umsdos_dirent dirent;
+ 	int size = len + (dirent.name-(char*)&dirent);
+ 	int nbrec = size / UMSDOS_REC_SIZE;
+ 	int extra = size % UMSDOS_REC_SIZE;
+ 	if (extra > 0) nbrec++;
+ 	return nbrec * UMSDOS_REC_SIZE;
+ }
+ #endif
+ /*
+ 	Fill the struct info with the full and msdos name of a file
+ 	Return 0 if all is ok, a negative error code otherwise.
+ */
+ int umsdos_parse (
+ 	const char *fname,
+ 	int len,
+ 	struct umsdos_info *info)
+ {
+ 	int ret = -ENAMETOOLONG;
+ 	/* #Specification: file name / too long
+ 		If a file name exceed UMSDOS maxima, the file name is silently
+ 		truncated. This makes it conformant with the other file system
+ 		of Linux (minix and ext2 at least).
+ 	*/
+ 	if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME;
+ 	{
+ 		const char *firstpt=NULL;	/* First place we saw a . in fname */
+ 		/* #Specification: file name / non MSDOS conforming / base length 0
+ 			file name beginning with a period '.' are invalid for MsDOS.
+ 			It needs absolutly a base name. So the file name is mangled
+ 		*/
+ 		int ivldchar = fname[0] == '.';/* At least one invalid character */
+ 		int msdos_len = len;
+ 		int base_len;
+ 		/*
+ 			cardinal_per_size tells if there exist at least one
+ 			DOS pseudo devices on length n. See the test below.
+ 		*/
+ 		static const char cardinal_per_size[9]={
+ 			0, 0, 0, 1, 1, 0, 1, 0, 1
+ 		};
+ 		/*
+ 			lkp translate all character to acceptable character (for DOS).
+ 			When lkp[n] == n, it means also it is an acceptable one.
+ 			So it serve both as a flag and as a translator.
+ 		*/
+ 		static char lkp[256];
+ 		static char is_init=0;
+ 		if (!is_init){
+ 			/*
+ 				Initialisation of the array is easier and less error prone
+ 				like this.
+ 			*/
+ 			int i;
+ 			static char *spc = "\"*+,/:;<=>?[\\]|~";
+ 			is_init = 1;
+ 			for (i=0; i<=32; i++) lkp[i] = '#';
+ 			for (i=33; i<'A'; i++) lkp[i] = (char)i;
+ 			for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A'));
+ 			for (i='Z'+1; i<127; i++) lkp[i] = (char)i;
+ 			for (i=128; i<256; i++) lkp[i] = '#';
+ 
+ 			lkp['.'] = '_';
+ 			while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#';
+ 		}
+ 		/*	GLU
+ 			file name wich are longer than 8+'.'+3 are invalid for MsDOS.
+ 			So the file name is to be mangled no more test needed.
+ 			This Speed Up for long and very long name.
+ 			The position of the last point is no more necessary anyway.
+ 		*/
+ 		if (len<=(8+1+3)){
+ 			const char *pt = fname;
+ 			const char *endpt = fname + len;
+ 			while (pt < endpt){
+ 				if (*pt == '.'){
+ 					if (firstpt != NULL){
+ 						/* 2 . in a file name. Reject */
+ 						ivldchar = 1;
+ 						break;
+ 					}else{
+ 						int extlen = (int)(endpt - pt);
+ 						firstpt = pt;
+ 						if (firstpt - fname > 8){
+ 							/* base name longer than 8: reject */
+ 							ivldchar = 1;
+ 							break;
+ 						}else if (extlen > 4){
+ 							/* Extension longer than 4 (including .): reject */
+ 							ivldchar = 1;
+ 							break;
+ 						}else if (extlen == 1){
+ 							/* #Specification: file name / non MSDOS conforming / last char == .
+ 								If the last character of a file name is
+ 								a period, mangling is applied. MsDOS do
+ 								not support those file name.
+ 							*/
+ 							ivldchar = 1;
+ 							break;
+ 						}else if (extlen == 4){
+ 							/* #Specification: file name / non MSDOS conforming / mangling clash
+ 								To avoid clash with	the umsdos mangling, any file
+ 								with a special character as the first character
+ 								of the extension will be mangled. This solve the
+ 								following problem:
+ 				
+ 								touch FILE
+ 								# FILE is invalid for DOS, so mangling is applied
+ 								# file.{_1 is created in the DOS directory
+ 								touch file.{_1
+ 								# To UMSDOS file point to a single DOS entry.
+ 								# So file.{_1 has to be mangled.
+ 							*/	
+ 							static char special[]={
+ 								SPECIAL_MANGLING,'\0'
+ 							};
+ 							if (strchr(special,firstpt[1])!= NULL){
+ 								ivldchar = 1;
+ 								break;
+ 							}
+ 						}
+ 					}
+ 				}else if (lkp[(unsigned char)(*pt)] != *pt){
+ 					ivldchar = 1;
+ 					break;
+ 				}
+ 				pt++;
+ 			}
+ 		}else{
+ 			ivldchar = 1;
+ 		}
+ 		if (ivldchar
+ 			|| (firstpt == NULL && len > 8)
+ 			|| (len == UMSDOS_EMD_NAMELEN
+ 				&& memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){
+ 			/* #Specification: file name / --linux-.---
+ 				The name of the EMD file --linux-.--- is map to a mangled
+ 				name. So UMSDOS does not restrict its use.
+ 			*/
+ 			/* #Specification: file name / non MSDOS conforming / mangling
+ 				Non MSDOS conforming file name must use some alias to fit
+ 				in the MSDOS name space.
+ 
+ 				The strategy is simple. The name is simply truncated to
+ 				8 char. points are replace with underscore and a
+ 				number is given as an extension. This number correspond
+ 				to the entry number in the EMD file. The EMD file
+ 				only need to carry the real name.
+ 
+ 				Upper case is also convert to lower case.
+ 				Control character are converted to #.
+ 				Space are converted to #.
+ 				The following character are also converted to #.
+ 					" * + , / : ; < = > ? [ \ ] | ~
+ 
+ 				Sometime, the problem is not in MsDOS itself but in
+ 				command.com.
+ 			*/
+ 			int i;
+ 			char *pt = info->fake.fname;
+ 			base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len;
+ 			/*
+ 				There is no '.' any more so we know for a fact that
+ 				the base lenght is the lenght.
+ 			*/
+ 			memcpy (info->fake.fname,fname,msdos_len);
+ 			for (i=0; i<msdos_len; i++, pt++) *pt = lkp[(unsigned char)(*pt)];
+ 			*pt = '\0';	/* GLU	C'est sur on a un 0 a la fin */
+ 			info->msdos_reject = 1;
+ 			/*
+ 				The numeric extension is added only when we know
+ 				the position in the EMD file, in umsdos_newentry(),
+ 				umsdos_delentry(), and umsdos_findentry().
+ 				See umsdos_manglename().
+ 			*/
+ 		}else{
+ 			/* Conforming MSDOS file name */
+ 			strcpy (info->fake.fname,fname);	/* GLU	C'est sur on a un 0 a la fin */
+ 			info->msdos_reject = 0;
+ 			base_len = firstpt != NULL ? (int)(firstpt - fname) : len;
+ 		}
+ 		if (cardinal_per_size[base_len]){
+ 			/* #Specification: file name / MSDOS devices / mangling
+ 				To avoid unreachable file from MsDOS, any MsDOS conforming
+ 				file with a basename equal to one of the MsDOS pseudo
+ 				devices will be mangled.
+ 
+ 				If a file such as "prn" was created, it would be unreachable
+ 				under MsDOS because prn is assumed to be the printer, even
+ 				if the file does have an extension.
+ 
+ 				Since the extension is unimportant to MsDOS, we must patch
+ 				the basename also. We simply insert a minus '-'. To avoid
+ 				conflict with valid file with a minus in front (such as
+ 				"-prn"), we add an mangled extension like any other
+ 				mangled file name.
+ 
+ 				Here is the list of DOS pseudo devices:
+ 
+ 					"prn","con","aux","nul",
+ 					"lpt1","lpt2","lpt3","lpt4",
+ 					"com1","com2","com3","com4",
+ 					"clock$"
+ 
+ 				and some standard ones for common DOS programs
+ 
+ 					"emmxxxx0","xmsxxxx0","setverxx"
+ 
+ 				(Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK>
+ 				 for pointing these to me).
+ 
+ 				Is there one missing ?
+ 			*/
+ 			/* This table must be ordered by length */
+ 			static const char *tbdev[]={
+ 				"prn","con","aux","nul",
+ 				"lpt1","lpt2","lpt3","lpt4",
+ 				"com1","com2","com3","com4",
+ 				"clock$",
+ 				"emmxxxx0","xmsxxxx0","setverxx"
+ 			};
+ 			/* Tell where to find in tbdev[], the first name of */
+ 			/* a certain length */
+ 			static const char start_ind_dev[9]={
+ 				0, 0, 0, 4, 12, 12, 13, 13, 16 
+ 			};
+ 			char basen[9];
+ 			int i;
+ 			for (i=start_ind_dev[base_len-1]; i<start_ind_dev[base_len]; i++){
+ 				if (memcmp(info->fake.fname,tbdev[i],base_len)==0){
+ 					memcpy (basen,info->fake.fname,base_len);
+ 					basen[base_len] = '\0';		/* GLU	C'est sur on a un 0 a la fin */
+ 					/*
+ 					GLU	On ne fait cela que si necessaire, on essaye d'etre le
+ 					GLU	simple dans le cas general (le plus frequent).
+ 					*/
+ 					info->fake.fname[0] = '-';
+ 					strcpy (info->fake.fname+1,basen);	/* GLU	C'est sur on a un 0 a la fin */
+ 					msdos_len = (base_len==8) ? 8 : base_len + 1;
+ 					info->msdos_reject = 1;
+ 					break;
+ 				}
+ 			}
+ 		}
+ 		info->fake.fname[msdos_len] = '\0';	/* Help doing printk */
+ 		/* GLU	Ce zero devrais deja y etre ! (invariant ?) */
+ 		info->fake.len = msdos_len;
+ 		/* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/
+ 		memcpy (info->entry.name,fname,len);
+ 		info->entry.name_len = len;
+ 		ret = 0;
+ 	}
+ 	/*
+ 		Evaluate how many record are needed to store this entry.
+ 	*/
+ 	info->recsize = umsdos_evalrecsize (len);
+ 	return ret;
+ }
+ 
+ #ifdef TEST
+ 
+ struct MANG_TEST{
+ 	char *fname;		/* Name to validate */
+ 	int msdos_reject;	/* Expected msdos_reject flag */
+ 	char *msname;		/* Expected msdos name */
+ };
+ 
+ struct MANG_TEST tb[]={
+ 	"hello",		0,	"hello",
+ 	"hello.1",		0,	"hello.1",
+ 	"hello.1_",		0,	"hello.1_",
+ 	"prm",			0,	"prm",
+ 
+ #ifdef PROPOSITION
+ 	"HELLO",		1,	"hello",
+ 	"Hello.1",		1,	"hello.1",
+ 	"Hello.c",		1,	"hello.c",
+ #elseif
+ /*
+ 	Je trouve les trois exemples ci-dessous tres "malheureux".
+ 	Je propose de mettre en minuscule dans un passe preliminaire,
+ 	et de tester apres si il y a d'autres caracters "mechants".
+ 	Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement
+ 	modifiable que ca. Mais c'est pour le principe.
+ 	Evidemment cela augmente les chances de "Colision",
+ 	par exemple: entre "HELLO" et "Hello", mais ces problemes
+ 	peuvent etre traiter ailleur avec les autres colisions.
+ */
+ 	"HELLO",		1,	"hello",
+ 	"Hello.1",		1,	"hello_1",
+ 	"Hello.c",		1,	"hello_c",
+ #endif
+ 
+ 	"hello.{_1",		1,	"hello_{_",
+ 	"hello\t",		1,	"hello#",
+ 	"hello.1.1",		1,	"hello_1_",
+ 	"hel,lo",		1,	"hel#lo",
+ 	"Salut.Tu.vas.bien?",	1,	"salut_tu",
+ 	".profile",		1,	"_profile",
+ 	".xv",			1,	"_xv",
+ 	"toto.",		1,	"toto_",
+ 	"clock$.x",		1,	"-clock$",
+ 	"emmxxxx0",		1,	"-emmxxxx",
+ 	"emmxxxx0.abcd",	1,	"-emmxxxx",
+ 	"aux",			1,	"-aux",
+ 	"prn",			1,	"-prn",
+ 	"prn.abc",		1,	"-prn",
+ 	"PRN",			1,	"-prn",
+ /* 
+ GLU	ATTENTION : Le resultat de ceux-ci sont differents avec ma version
+ GLU	du mangle par rapport au mangle originale.
+ GLU	CAUSE: La maniere de calculer la variable baselen. 
+ GLU		Pour toi c'est toujours 3
+ GLU		Pour moi c'est respectivement 7, 8 et 8
+ */
+ 	"PRN.abc",		1,	"prn_abc",
+ 	"Prn.abcd",		1,	"prn_abcd",
+ 	"prn.abcd",		1,	"prn_abcd",
+ 	"Prn.abcdefghij",	1,	"prn_abcd"
+ };
+ 
+ int main (int argc, char *argv[])
+ {
+ 	int i,rold,rnew;
+ 	printf ("Testing the umsdos_parse.\n");
+ 	for (i=0; i<sizeof(tb)/sizeof(tb[0]); i++){
+ 		struct MANG_TEST *pttb = tb+i;
+ 		struct umsdos_info info;
+ 		int ok = umsdos_parse (pttb->fname,strlen(pttb->fname),&info);
+ 		if (strcmp(info.fake.fname,pttb->msname)!=0){
+ 			printf ("**** %s -> ",pttb->fname);
+ 			printf ("%s <> %s\n",info.fake.fname,pttb->msname);
+ 		}else if (info.msdos_reject != pttb->msdos_reject){
+ 			printf ("**** %s -> %s ",pttb->fname,pttb->msname);
+ 			printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject);
+ 		}else{
+ 			printf ("     %s -> %s %d\n",pttb->fname,pttb->msname
+ 				,pttb->msdos_reject);
+ 		}
+ 	}
+ 	printf ("Testing the new umsdos_evalrecsize.");
+ 	for (i=0; i<UMSDOS_MAXNAME ; i++){
+ 		rnew=umsdos_evalrecsize (i);
+ 		rold=umsdos_evalrecsize_old (i);
+ 		if (!(i%UMSDOS_REC_SIZE)){
+ 			printf ("\n%d:\t",i);
+ 		}
+ 		if (rnew!=rold){
+ 			printf ("**** %d newres: %d != %d \n", i, rnew, rold);
+ 		}else{
+ 			printf(".");
+ 		}
+ 	}
+ 	printf ("\nEnd of Testing.\n");
+ 
+ 	return 0;
+ }
+ 
+ #endif
diff -rc2P linux.1.1.12/fs/umsdos/namei.c linux/fs/umsdos/namei.c
*** linux.1.1.12/fs/umsdos/namei.c
--- linux/fs/umsdos/namei.c	Fri May 20 23:30:18 1994
***************
*** 0 ****
--- 1,992 ----
+ /*
+  *  linux/fs/umsdos/namei.c
+  *
+  *	Written 1993 by Jacques Gelinas 
+  *	Inspired from linux/fs/msdos/... by Werner Almesberger
+  *
+  * Maintain and access the --linux alternate directory file.
+ */
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/types.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/string.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/umsdos_fs.h>
+ #include <linux/malloc.h>
+ 
+ #define PRINTK(x)
+ #define Printk(x)	printk x
+ 
+ #if 1
+ /*
+ 	Wait for creation exclusivity.
+ 	Return 0 if the dir was already available.
+ 	Return 1 if a wait was necessary.
+ 		When 1 is return, it means a wait was done. It does not
+ 		mean the directory is available.
+ */
+ static int umsdos_waitcreate(struct inode *dir)
+ {
+ 	int ret = 0;
+ 	if (dir->u.umsdos_i.u.dir_info.creating
+ 		&& dir->u.umsdos_i.u.dir_info.pid != current->pid){
+ 		sleep_on(&dir->u.umsdos_i.u.dir_info.p);
+ 		ret = 1;
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Wait for any lookup process to finish
+ */
+ static void umsdos_waitlookup (struct inode *dir)
+ {
+ 	while (dir->u.umsdos_i.u.dir_info.looking){
+ 		sleep_on(&dir->u.umsdos_i.u.dir_info.p);
+ 	}
+ }
+ /*
+ 	Lock all other process out of this directory.
+ */
+ void umsdos_lockcreate (struct inode *dir)
+ {
+ 	/* #Specification: file creation / not atomic
+ 		File creation is a two step process. First we create (allocate)
+ 		an entry in the EMD file and then (using the entry offset) we
+ 		build a unique name for MSDOS. We create this name in the msdos
+ 		space.
+ 
+ 		We have to use semaphore (sleep_on/wake_up) to prevent lookup
+ 		into a directory when we create a file or directory and to
+ 		prevent creation while a lookup is going on. Since many lookup
+ 		may happen at the same time, the semaphore is a counter.
+ 
+ 		Only one creation is allowed at the same time. This protection
+ 		may not be necessary. The problem arise mainly when a lookup
+ 		or a readdir is done while a file is partially created. The
+ 		lookup process see that as a "normal" problem and silently
+ 		erase the file from the EMD file. Normal because a file
+ 		may be erased during a MSDOS session, but not removed from
+ 		the EMD file.
+ 
+ 		The locking is done on a directory per directory basis. Each
+ 		directory inode has its wait_queue.
+ 
+ 		For some operation like hard link, things even get worse. Many
+ 		creation must occur at once (atomic). To simplify the design
+ 		a process is allowed to recursivly lock the directory for
+ 		creation. The pid of the locking process is kept along with
+ 		a counter so a second level of locking is granted or not.
+ 	*/
+ 	/*
+ 		Wait for any creation process to finish except
+ 		if we (the process) own the lock
+ 	*/
+ 	while (umsdos_waitcreate(dir)!=0);
+ 	dir->u.umsdos_i.u.dir_info.creating++;
+ 	dir->u.umsdos_i.u.dir_info.pid = current->pid;
+ 	umsdos_waitlookup (dir);
+ }
+ /*
+ 	Lock all other process out of those two directories.
+ */
+ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
+ {
+ 	/*
+ 		We must check that both directory are available before
+ 		locking anyone of them. This is to avoid some deadlock.
+ 		Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
+ 		this to me.
+ 	*/
+ 	while (1){
+ 		if (umsdos_waitcreate(dir1)==0
+ 			&& umsdos_waitcreate(dir2)==0){
+ 			/* We own both now */
+ 			dir1->u.umsdos_i.u.dir_info.creating++;
+ 			dir1->u.umsdos_i.u.dir_info.pid = current->pid;
+ 			dir2->u.umsdos_i.u.dir_info.creating++;
+ 			dir2->u.umsdos_i.u.dir_info.pid = current->pid;
+ 			break;
+ 		}
+ 	}
+ 	umsdos_waitlookup(dir1);
+ 	umsdos_waitlookup(dir2);
+ }
+ /*
+ 	Wait until creation is finish in this directory.
+ */
+ void umsdos_startlookup (struct inode *dir)
+ {
+ 	while (umsdos_waitcreate (dir) != 0);
+ 	dir->u.umsdos_i.u.dir_info.looking++;
+ }
+ void check_page_tables(void);
+ 
+ /*
+ 	Unlock the directory.
+ */
+ void umsdos_unlockcreate (struct inode *dir)
+ {
+ 	dir->u.umsdos_i.u.dir_info.creating--;
+ 	if (dir->u.umsdos_i.u.dir_info.creating < 0){
+ 		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
+ 			,dir->u.umsdos_i.u.dir_info.creating);
+ 	}
+ 	wake_up (&dir->u.umsdos_i.u.dir_info.p);
+ }
+ /*
+ 	Tell directory lookup is over.
+ */
+ void umsdos_endlookup (struct inode *dir)
+ {
+ 	dir->u.umsdos_i.u.dir_info.looking--;
+ 	if (dir->u.umsdos_i.u.dir_info.looking < 0){
+ 		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
+ 			,dir->u.umsdos_i.u.dir_info.looking);
+ 	}
+ 	wake_up (&dir->u.umsdos_i.u.dir_info.p);
+ }
+ #else
+ static void umsdos_lockcreate (struct inode *dir){}
+ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
+ void umsdos_startlookup (struct inode *dir){}
+ static void umsdos_unlockcreate (struct inode *dir){}
+ void umsdos_endlookup (struct inode *dir){}
+ #endif
+ static int umsdos_nevercreat(
+ 	struct inode *dir,
+ 	const char *name,		/* Name of the file to add */
+ 	int len,
+ 	int errcod)				/* Length of the name */
+ {
+ 	int ret = 0;
+ 	if (umsdos_is_pseudodos(dir,name,len)){
+ 		/* #Specification: pseudo root / any file creation /DOS
+ 			The pseudo sub-directory /DOS can't be created!
+ 			EEXIST is returned.
+ 
+ 			The pseudo sub-directory /DOS can't be removed!
+ 			EPERM is returned.
+ 		*/
+ 		ret = -EPERM;
+ 		ret = errcod;
+ 	}else if (name[0] == '.'
+ 		&& (len == 1 || (len == 2 && name[1] == '.'))){
+ 		/* #Specification: create / . and ..
+ 			If one try to creates . or .., it always fail and return
+ 			EEXIST.
+ 
+ 			If one try to delete . or .., it always fail and return
+ 			EPERM.
+ 
+ 			This should be test at the VFS layer level to avoid
+ 			duplicating this in all file systems. Any comments ?
+ 		*/
+ 		ret = errcod;
+ 	}
+ 	return ret;
+ }
+ 	
+ /*
+ 	Add a new file (ordinary or special) into the alternate directory.
+ 	The file is added to the real MSDOS directory. If successfull, it
+ 	is then added to the EDM file.
+ 
+ 	Return the status of the operation. 0 mean success.
+ */
+ static int umsdos_create_any (
+ 	struct inode *dir,
+ 	const char *name,		/* Name of the file to add */
+ 	int len,				/* Length of the name */
+ 	int mode,				/* Permission bit + file type ??? */
+ 	int rdev,				/* major, minor or 0 for ordinary file */
+ 							/* and symlinks */
+ 	char flags,
+ 	struct inode **result)	/* Will hold the inode of the newly created */
+ 							/* file */
+ {
+ 	int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
+ 	if (ret == 0){
+ 		struct umsdos_info info;
+ 		ret = umsdos_parse (name,len,&info);
+ 		*result = NULL;
+ 		if (ret == 0){
+ 			info.entry.mode = mode;
+ 			info.entry.rdev = rdev;
+ 			info.entry.flags = flags;
+ 			info.entry.uid = current->euid;
+ 			info.entry.gid = (dir->i_mode & S_ISGID)
+ 				? dir->i_gid : current->egid;
+ 			info.entry.ctime = info.entry.atime = info.entry.mtime
+ 				= CURRENT_TIME;
+ 			info.entry.nlink = 1;
+ 			umsdos_lockcreate(dir);
+ 			ret = umsdos_newentry (dir,&info);
+ 			if (ret == 0){
+ 				dir->i_count++;
+ 				ret = msdos_create (dir,info.fake.fname,info.fake.len
+ 					,S_IFREG|0777,result);
+ 				if (ret == 0){
+ 					struct inode *inode = *result;
+ 					umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
+ 					PRINTK (("inode %p[%d] ",inode,inode->i_count));
+ 					PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
+ 						,info.fake.fname,current->pid,info.f_pos));
+ 				}else{
+ 					/* #Specification: create / file exist in DOS
+ 						Here is a situation. Trying to create a file with
+ 						UMSDOS. The file is unknown to UMSDOS but already
+ 						exist in the DOS directory.
+ 
+ 						Here is what we are NOT doing:
+ 
+ 						We could silently assume that everything is fine
+ 						and allows the creation to succeed.
+ 
+ 						It is possible not all files in the partition
+ 						are mean to be visible from linux. By trying to create
+ 						those file in some directory, one user may get access
+ 						to those file without proper permissions. Looks like
+ 						a security hole to me. Off course sharing a file system
+ 						with DOS is some kind of security hole :-)
+ 
+ 						So ?
+ 
+ 						We return EEXIST in this case.
+ 						The same is true for directory creation.
+ 					*/
+ 					if (ret == -EEXIST){
+ 						printk ("UMSDOS: out of sync, Creation error [%ld], "
+ 							"deleting %s %d %d pos %ld\n",dir->i_ino
+ 							,info.fake.fname,-ret,current->pid,info.f_pos);
+ 					}
+ 					umsdos_delentry (dir,&info,0);
+ 				}
+ 				PRINTK (("umsdos_create %s ret = %d pos %d\n"
+ 					,info.fake.fname,ret,info.f_pos));
+ 			}
+ 			umsdos_unlockcreate(dir);
+ 		}
+ 	}
+ 	iput (dir);
+ 	return ret;
+ }
+ /*
+ 	Initialise the new_entry from the old for a rename operation.
+ 	(Only useful for umsdos_rename_f() below).
+ */
+ static void umsdos_ren_init(
+ 	struct umsdos_info *new_info,
+ 	struct umsdos_info *old_info,
+ 	int flags)		/* 0 == copy flags from old_name */
+ 					/* != 0, this is the value of flags */
+ {
+ 	new_info->entry.mode = old_info->entry.mode;
+ 	new_info->entry.rdev = old_info->entry.rdev;
+ 	new_info->entry.uid = old_info->entry.uid;
+ 	new_info->entry.gid = old_info->entry.gid;
+ 	new_info->entry.ctime = old_info->entry.ctime;
+ 	new_info->entry.atime = old_info->entry.atime;
+ 	new_info->entry.mtime = old_info->entry.mtime;
+ 	new_info->entry.flags = flags ? flags : old_info->entry.flags;
+ 	new_info->entry.nlink = old_info->entry.nlink;
+ }
+ /*
+ 	Rename a file (move) in the file system.
+ */
+ static int umsdos_rename_f(
+ 	struct inode * old_dir,
+ 	const char * old_name,
+ 	int old_len,
+ 	struct inode * new_dir,
+ 	const char * new_name,
+ 	int new_len,
+ 	int flags)		/* 0 == copy flags from old_name */
+ 					/* != 0, this is the value of flags */
+ {
+ 	int ret = EPERM;
+ 	struct umsdos_info old_info;
+ 	int old_ret = umsdos_parse (old_name,old_len,&old_info);
+ 	struct umsdos_info new_info;
+ 	int new_ret = umsdos_parse (new_name,new_len,&new_info);
+ 	PRINTK (("umsdos_rename %d %d ",old_ret,new_ret));
+ 	if (old_ret == 0 && new_ret == 0){
+ 		umsdos_lockcreate2(old_dir,new_dir);
+ 		PRINTK (("old findentry "));
+ 		ret = umsdos_findentry(old_dir,&old_info,0);
+ 		PRINTK (("ret %d ",ret));
+ 		if (ret == 0){
+ 			PRINTK (("new newentry "));
+ 			umsdos_ren_init(&new_info,&old_info,flags);
+ 			ret = umsdos_newentry (new_dir,&new_info);
+ 			PRINTK (("ret %d %d ",ret,new_info.fake.len));
+ 			if (ret == -EEXIST){
+ 				/* #Specification: rename / new name exist
+ 					If the destination name already exist, it will
+ 					silently be removed. EXT2 does it this way
+ 					and this is the spec of SUNOS. So does UMSDOS.
+ 
+ 					If the destination is an empty directory it will
+ 					also be removed.
+ 				*/
+ 				/* This is not super efficient but should work */
+ 				new_dir->i_count++;
+ 				ret = UMSDOS_unlink (new_dir,new_name,new_len);
+ 				PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
+ 				if (ret == -EISDIR){
+ 					new_dir->i_count++;
+ 					ret = UMSDOS_rmdir (new_dir,new_name,new_len);
+ 					PRINTK (("rename rmdir ret %d -- ",ret));
+ 				}
+ 				if (ret == 0){
+ 					/*
+ 						The last umsdos_newentry had a side effect.
+ 						new_info was filled with information from the
+ 						existing entry (the one we just deleted).
+ 					*/
+ 					umsdos_parse (new_name,new_len,&new_info);
+ 					umsdos_ren_init(&new_info,&old_info,flags);
+ 					ret = umsdos_newentry (new_dir,&new_info);
+ 				}
+ 			}
+ 			if (ret == 0){
+ 				PRINTK (("msdos_rename "));
+ 				old_dir->i_count++;
+ 				new_dir->i_count++;	/* Both inode are needed later */
+ 				ret = msdos_rename (old_dir
+ 					,old_info.fake.fname,old_info.fake.len
+ 					,new_dir
+ 					,new_info.fake.fname,new_info.fake.len);
+ 				PRINTK (("after m_rename ret %d ",ret));
+ 				if (ret != 0){
+ 					umsdos_delentry (new_dir,&new_info
+ 						,S_ISDIR(new_info.entry.mode));
+ 				}else{
+ 					ret = umsdos_delentry (old_dir,&old_info
+ 						,S_ISDIR(old_info.entry.mode));
+ 					if (ret == 0){
+ 						/*
+ 							This UMSDOS_lookup does not look very useful.
+ 							It makes sure that the inode of the file will
+ 							be correctly setup (umsdos_patch_inode()) in
+ 							case it is already in use.
+ 
+ 							Not very efficient ...
+ 						*/
+ 						struct inode *inode;
+ 						new_dir->i_count++;
+ 						PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
+ 						ret = UMSDOS_lookup (new_dir,new_name,new_len
+ 							,&inode);
+ 						if (ret != 0){
+ 							printk ("UMSDOS: partial rename for file %s\n"
+ 								,new_info.entry.name);
+ 						}else{
+ 							/*
+ 								Update f_pos so notify_change will succeed
+ 								if the file was already in use.
+ 							*/
+ 							umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
+ 							iput (inode);
+ 						}
+ 					}
+ 				}
+ 			}
+ 		}
+ 		umsdos_unlockcreate(old_dir);
+ 		umsdos_unlockcreate(new_dir);
+ 	}
+ 	iput (old_dir);
+ 	iput (new_dir);
+ 	PRINTK (("\n"));
+ 	return ret;
+ }
+ /*
+ 	Setup un Symbolic link or a (pseudo) hard link
+ 	Return a negative error code or 0 if ok.
+ */
+ static int umsdos_symlink_x(
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len,
+ 	const char * symname,	/* name will point to this path */
+ 	int mode,
+ 	char flags)
+ {
+ 	/* #Specification: symbolic links / strategy
+ 		A symbolic link is simply a file which hold a path. It is
+ 		implemented as a normal MSDOS file (not very space efficient :-()
+ 
+ 		I see 2 different way to do it. One is to place the link data
+ 		in unused entry of the EMD file. The other is to have a separate
+ 		file dedicated to hold all symbolic links data.
+ 
+ 		Lets go for simplicity...
+ 	*/
+ 	struct inode *inode;
+ 	int ret;
+ 	dir->i_count++;		/* We keep the inode in case we need it */
+ 						/* later */
+ 	ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
+ 	PRINTK (("umsdos_symlink ret %d ",ret));
+ 	if (ret == 0){
+ 		int len = strlen(symname);
+ 		struct file filp;
+ 		filp.f_pos = 0;
+ 		/* Make the inode acceptable to MSDOS */
+ 		ret = msdos_file_write_kmem (inode,&filp,(char*)symname,len);
+ 		iput (inode);
+ 		if (ret >= 0){
+ 			if (ret != len){
+ 				ret = -EIO;
+ 				printk ("UMSDOS: "
+ 					"Can't write symbolic link data\n");
+ 			}else{
+ 				ret = 0;
+ 			}
+ 		}
+ 		if (ret != 0){
+ 			UMSDOS_unlink (dir,name,len);
+ 			dir = NULL;
+ 		}
+ 	}
+ 	iput (dir);
+ 	PRINTK (("\n"));
+ 	return ret;
+ }
+ /*
+ 	Setup un Symbolic link.
+ 	Return a negative error code or 0 if ok.
+ */
+ int UMSDOS_symlink(
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len,
+ 	const char * symname)	/* name will point to this path */
+ {
+ 	return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
+ }
+ /*
+ 	Add a link to an inode in a directory
+ */
+ int UMSDOS_link (
+ 	struct inode * oldinode,
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len)
+ {
+ 	/* #Specification: hard link / strategy
+ 		Well ... hard link are difficult to implement on top of an
+ 		MsDOS fat file system. Unlike UNIX file systems, there are no
+ 		inode. A directory entry hold the functionnality of the inode
+ 		and the entry.
+ 
+ 		We will used the same strategy as a normal Unix file system
+ 		(with inode) except we will do it symbolicly (using paths).
+ 
+ 		Because anything can happen during a DOS session (defragment,
+ 		directory sorting, etc...), we can't rely on MsDOS pseudo
+ 		inode number to record the link. For this reason, the link
+ 		will be done using hidden symbolic links. The following
+ 		scenario illustrate how it work.
+ 		
+ 		Given a file /foo/file
+ 
+ 			ln /foo/file /tmp/file2
+ 
+ 			become internally
+ 
+ 			mv /foo/file /foo/-LINK1
+ 			ln -s /foo/-LINK1 /foo/file
+ 			ln -s /foo/-LINK1 /tmp/file2
+ 
+ 		Using this strategy, we can operate on /foo/file or /foo/file2.
+ 		We can remove one and keep the other, like a normal Unix hard link.
+ 		We can rename /foo/file ou /tmp/file2 independantly.
+ 			
+ 		The entry -LINK1 will be hidden. It will hold a link count.
+ 		When all link are erased, the hidden file is erased too.
+ 	*/
+ 	/* #Specification: weakness / hard link
+ 		The strategy for hard link introduces a side effect that
+ 		may or may not be acceptable. Here is the sequence
+ 
+ 		mkdir subdir1
+ 		touch subdir1/file
+ 		mkdir subdir2
+ 		ln    subdir1/file subdir2/file
+ 		rm    subdir1/file
+ 		rmdir subdir1
+ 		rmdir: subdir1: Directory not empty
+ 
+ 		This happen because there is an invisible file (--link) in
+ 		subdir1 which is referenced by subdir2/file.
+ 
+ 		Any idea ?
+ 	*/
+ 	/* #Specification: weakness / hard link / rename directory
+ 		Another weakness of hard link come from the fact that
+ 		it is based on hidden symbolic links. Here is an example.
+ 
+ 		mkdir /subdir1
+ 		touch /subdir1/file
+ 		mkdir /subdir2
+ 		ln    /subdir1/file subdir2/file
+ 		mv    /subdir1 subdir3
+ 		ls -l /subdir2/file
+ 
+ 		Since /subdir2/file is a hidden symbolic link
+ 		to /subdir1/..hlinkNNN, accessing it will fail since
+ 		/subdir1 does not exist anymore (has been renamed).
+ 	*/
+ 	int ret = 0;
+ 	if (S_ISDIR(oldinode->i_mode)){
+ 		/* #Specification: hard link / directory
+ 			A hard link can't be made on a directory. EPERM is returned
+ 			in this case.
+ 		*/
+ 		ret = -EPERM;
+ 	}else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
+ 		struct inode *olddir;
+ 		ret = umsdos_get_dirowner(oldinode,&olddir);
+ 		PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
+ 			,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
+ 		if (ret == 0){
+ 			struct umsdos_dirent entry;
+ 			umsdos_lockcreate2(dir,olddir);
+ 			ret = umsdos_inode2entry (olddir,oldinode,&entry);
+ 			if (ret == 0){
+ 				PRINTK (("umsdos_link :%s: ino %d flags %d "
+ 					,entry.name
+ 					,oldinode->i_ino,entry.flags));
+ 				if (!(entry.flags & UMSDOS_HIDDEN)){
+ 					/* #Specification: hard link / first hard link
+ 						The first time a hard link is done on a file, this
+ 						file must be renamed and hidden. Then an internal
+ 						simbolic link must be done on the hidden file.
+ 
+ 						The second link is done after on this hidden file.
+ 
+ 						It is expected that the Linux MSDOS file system
+ 						keeps the same pseudo inode when a rename operation
+ 						is done on a file in the same directory.
+ 					*/
+ 					struct umsdos_info info;
+ 					ret = umsdos_newhidden (olddir,&info);
+ 					if (ret == 0){
+ 						olddir->i_count+=2;
+ 						PRINTK (("olddir[%d] ",olddir->i_count));
+ 						ret = umsdos_rename_f (olddir,entry.name
+ 							,entry.name_len
+ 							,olddir,info.entry.name,info.entry.name_len
+ 							,UMSDOS_HIDDEN);
+ 						if (ret == 0){
+ 							char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+ 							if (path == NULL){
+ 								ret = -ENOMEM;
+ 							}else{
+ 								PRINTK (("olddir[%d] ",olddir->i_count));
+ 								ret = umsdos_locate_path (oldinode,path);
+ 								PRINTK (("olddir[%d] ",olddir->i_count));
+ 								if (ret == 0){
+ 									olddir->i_count++;
+ 									ret = umsdos_symlink_x (olddir
+ 										,entry.name
+ 										,entry.name_len,path
+ 										,S_IFREG|0777,UMSDOS_HLINK);
+ 									if (ret == 0){
+ 										dir->i_count++;
+ 										ret = umsdos_symlink_x (dir,name,len
+ 											,path
+ 											,S_IFREG|0777,UMSDOS_HLINK);
+ 									}
+ 								}
+ 								kfree (path);
+ 							}
+ 						}
+ 					}
+ 				}else{
+ 					char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+ 					if (path == NULL){
+ 						ret = -ENOMEM;
+ 					}else{
+ 						ret = umsdos_locate_path (oldinode,path);
+ 						if (ret == 0){
+ 							dir->i_count++;
+ 							ret = umsdos_symlink_x (dir,name,len,path
+ 											,S_IFREG|0777,UMSDOS_HLINK);
+ 						}
+ 						kfree (path);
+ 					}
+ 				}
+ 			}
+ 			umsdos_unlockcreate(olddir);
+ 			umsdos_unlockcreate(dir);
+ 		}
+ 		iput (olddir);
+ 	}
+ 	if (ret == 0){
+ 		oldinode->i_nlink++;
+ 		ret = UMSDOS_notify_change (0,oldinode);
+ 	}
+ 	iput (oldinode);
+ 	iput (dir);
+ 	PRINTK (("umsdos_link %d\n",ret));
+ 	return ret;
+ }
+ /*
+ 	Add a new file into the alternate directory.
+ 	The file is added to the real MSDOS directory. If successfull, it
+ 	is then added to the EDM file.
+ 
+ 	Return the status of the operation. 0 mean success.
+ */
+ int UMSDOS_create (
+ 	struct inode *dir,
+ 	const char *name,		/* Name of the file to add */
+ 	int len,				/* Length of the name */
+ 	int mode,				/* Permission bit + file type ??? */
+ 	struct inode **result)	/* Will hold the inode of the newly created */
+ 							/* file */
+ {
+ 	return umsdos_create_any (dir,name,len,mode,0,0,result);
+ }
+ /*
+ 	Add a sub-directory in a directory
+ */
+ int UMSDOS_mkdir(
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len,
+ 	int mode)
+ {
+ 	int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
+ 	if (ret == 0){
+ 		struct umsdos_info info;
+ 		ret = umsdos_parse (name,len,&info);
+ 		PRINTK (("umsdos_mkdir %d\n",ret));
+ 		if (ret == 0){
+ 			info.entry.mode = mode | S_IFDIR;
+ 			info.entry.rdev = 0;
+ 			info.entry.uid = current->euid;
+ 			info.entry.gid = (dir->i_mode & S_ISGID)
+ 				? dir->i_gid : current->egid;
+ 			info.entry.ctime = info.entry.atime = info.entry.mtime
+ 				= CURRENT_TIME;
+ 			info.entry.flags = 0;
+ 			umsdos_lockcreate(dir);
+ 			info.entry.nlink = 1;
+ 			ret = umsdos_newentry (dir,&info);
+ 			PRINTK (("newentry %d ",ret));
+ 			if (ret == 0){
+ 				dir->i_count++;
+ 				ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
+ 				if (ret != 0){
+ 					umsdos_delentry (dir,&info,1);
+ 					/* #Specification: mkdir / Directory already exist in DOS
+ 						We do the same thing as for file creation.
+ 						For all user it is an error.
+ 					*/
+ 				}else{
+ 					/* #Specification: mkdir / umsdos directory / create EMD
+ 						When we created a new sub-directory in a UMSDOS
+ 						directory (one with full UMSDOS semantic), we
+ 						create immediatly an EMD file in the new
+ 						sub-directory so it inherit UMSDOS semantic.
+ 					*/
+ 					struct inode *subdir;
+ 					ret = umsdos_real_lookup (dir,info.fake.fname
+ 						,info.fake.len,&subdir);
+ 					if (ret == 0){
+ 						struct inode *result;
+ 						ret = msdos_create (subdir,UMSDOS_EMD_FILE
+ 							,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
+ 						subdir = NULL;
+ 						iput (result);
+ 					}
+ 					if (ret < 0){
+ 						printk ("UMSDOS: Can't create empty --linux-.---\n");
+ 					}
+ 					iput (subdir);
+ 				}
+ 			}
+ 			umsdos_unlockcreate(dir);
+ 		}
+ 	}
+ 	PRINTK (("umsdos_mkdir %d\n",ret));
+ 	iput (dir);
+ 	return ret;
+ }
+ /*
+ 	Add a new device special file into a directory.
+ */
+ int UMSDOS_mknod(
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len,
+ 	int mode,
+ 	int rdev)
+ {
+ 	/* #Specification: Special files / strategy
+ 		Device special file, pipes, etc ... are created like normal
+ 		file in the msdos file system. Of course they remain empty.
+ 
+ 		One strategy was to create thoses files only in the EMD file
+ 		since they were not important for MSDOS. The problem with
+ 		that, is that there were not getting inode number allocated.
+ 		The MSDOS filesystems is playing a nice game to fake inode
+ 		number, so why not use it.
+ 
+ 		The absence of inode number compatible with those allocated
+ 		for ordinary files was causing major trouble with hard link
+ 		in particular and other parts of the kernel I guess.
+ 	*/
+ 	struct inode *inode;
+ 	int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
+ 	iput (inode);
+ 	return ret;
+ }
+ 
+ /*
+ 	Remove a sub-directory.
+ */
+ int UMSDOS_rmdir(
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len)
+ {
+ 	/* #Specification: style / iput strategy
+ 		In the UMSDOS project, I am trying to apply a single
+ 		programming style regarding inode management. Many
+ 		entry point are receiving an inode to act on, and must
+ 		do an iput() as soon as they are finished with
+ 		the inode.
+ 
+ 		For simple case, there is no problem. When you introduce
+ 		error checking, you end up with many iput placed around the
+ 		code.
+ 
+ 		The coding style I use all around is one where I am trying
+ 		to provide independant flow logic (I don't know how to
+ 		name this). With this style, code is easier to understand
+ 		but you rapidly get iput() all around. Here is an exemple
+ 		of what I am trying to avoid.
+ 
+ 		if (a){
+ 			...
+ 			if(b){
+ 				...
+ 			}
+ 			...
+ 			if (c){
+ 				// Complexe state. Was b true ? 
+ 				...
+ 			}
+ 			...
+ 		}
+ 		// Weird state
+ 		if (d){
+ 			// ...
+ 		}
+ 		// Was iput finally done ?
+ 		return status;
+ 
+ 		Here is the style I am using. Still sometime I do the
+ 		first when things are very simple (or very complicated :-( )
+ 
+ 		if (a){
+ 			if (b){
+ 				...
+ 			}else if (c){
+ 				// A single state gets here
+ 			}
+ 		}else if (d){
+ 			...
+ 		}
+ 		return status;
+ 
+ 		Again, while this help clarifying the code, I often get a lot
+ 		of iput(), unlike the first style, where I can place few 
+ 		"strategic" iput(). "strategic" also mean, more difficult
+ 		to place.
+ 
+ 		So here is the style I will be using from now on in this project.
+ 		There is always an iput() at the end of a function (which has
+ 		to do an iput()). One iput by inode. There is also one iput()
+ 		at the places where a successful operation is achieved. This
+ 		iput() is often done by a sub-function (often from the msdos
+ 		file system). So I get one too many iput() ? At the place
+ 		where an iput() is done, the inode is simply nulled, disabling
+ 		the last one.
+ 
+ 		if (a){
+ 			if (b){
+ 				...
+ 			}else if (c){
+ 				msdos_rmdir(dir,...);
+ 				dir = NULL;
+ 			}
+ 		}else if (d){
+ 			...
+ 		}
+ 		iput (dir);
+ 		return status;
+ 
+ 		Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
+ 		paire goes against this practice of "forgetting" the inode as soon
+ 		as possible.
+ 	*/		
+ 	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
+ 	if (ret == 0){
+ 		struct inode *sdir;
+ 		dir->i_count++;
+ 		ret = UMSDOS_lookup (dir,name,len,&sdir);
+ 		PRINTK (("rmdir lookup %d ",ret));
+ 		if (ret == 0){
+ 			int empty;
+ 			umsdos_lockcreate(dir);
+ 			if ((empty = umsdos_isempty (sdir)) != 0){
+ 				PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
+ 				if (empty == 1){
+ 					/* We have to removed the EMD file */
+ 					ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
+ 						,UMSDOS_EMD_NAMELEN);
+ 					sdir = NULL;
+ 				}
+ 				/* sdir must be free before msdos_rmdir() */
+ 				iput (sdir);
+ 				sdir = NULL;
+ 				PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
+ 				if (ret == 0){
+ 					struct umsdos_info info;
+ 					dir->i_count++;
+ 					umsdos_parse (name,len,&info);
+ 					/* The findentry is there only to complete */
+ 					/* the mangling */
+ 					umsdos_findentry (dir,&info,2);
+ 					ret = msdos_rmdir (dir,info.fake.fname
+ 						,info.fake.len);
+ 					if (ret == 0){
+ 						ret = umsdos_delentry (dir,&info,1);
+ 					}
+ 				}
+ 			}else{	
+ 				/*
+ 					The subdirectory is not empty, so leave it there
+ 				*/
+ 				ret = -ENOTEMPTY;
+ 			}
+ 			iput(sdir);
+ 			umsdos_unlockcreate(dir);
+ 		}	
+ 	}
+ 	iput (dir);
+ 	PRINTK (("umsdos_rmdir %d\n",ret));
+ 	return ret;
+ }
+ /*
+ 	Remove a file from the directory.
+ */
+ int UMSDOS_unlink (
+ 	struct inode * dir,
+ 	const char * name,
+ 	int len)
+ {
+ 	struct umsdos_info info;
+ 	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
+ 	if (ret == 0){
+ 		ret = umsdos_parse (name,len,&info);
+ 		if (ret == 0){
+ 			umsdos_lockcreate(dir);
+ 			ret = umsdos_findentry(dir,&info,1);
+ 			if (ret == 0){
+ 				PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
+ 				if (info.entry.flags & UMSDOS_HLINK){
+ 					/* #Specification: hard link / deleting a link
+ 						When we deletes a file, and this file is a link
+ 						we must substract 1 to the nlink field of the
+ 						hidden link.
+ 
+ 						If the count goes to 0, we delete this hidden
+ 						link too.
+ 					*/
+ 					/*
+ 						First, get the inode of the hidden link
+ 						using the standard lookup function.
+ 					*/
+ 					struct inode *inode;
+ 					dir->i_count++;
+ 					ret = UMSDOS_lookup (dir,name,len,&inode);
+ 					if (ret == 0){
+ 						PRINTK (("unlink nlink = %d ",inode->i_nlink));
+ 						inode->i_nlink--;
+ 						if (inode->i_nlink == 0){
+ 							struct inode *hdir = iget(inode->i_sb
+ 								,inode->u.umsdos_i.i_dir_owner);
+ 							struct umsdos_dirent entry;
+ 							ret = umsdos_inode2entry (hdir,inode,&entry);
+ 							if (ret == 0){
+ 								ret = UMSDOS_unlink (hdir,entry.name
+ 									,entry.name_len);
+ 							}else{
+ 								iput (hdir);
+ 							}
+ 						}else{
+ 							ret = UMSDOS_notify_change (0,inode);
+ 						}
+ 						iput (inode);
+ 					}
+ 				}
+ 				if (ret == 0){
+ 					ret = umsdos_delentry (dir,&info,0);
+ 					if (ret == 0){
+ 						PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
+ 						dir->i_count++;
+ 						ret = msdos_unlink_umsdos (dir,info.fake.fname
+ 							,info.fake.len);
+ 						PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
+ 							,info.entry.mode,ret));
+ 					}
+ 				}
+ 			}
+ 			umsdos_unlockcreate(dir);
+ 		}
+ 	}	
+ 	iput (dir);
+ 	PRINTK (("umsdos_unlink %d\n",ret));
+ 	return ret;
+ }
+ 
+ /*
+ 	Rename a file (move) in the file system.
+ */
+ int UMSDOS_rename(
+ 	struct inode * old_dir,
+ 	const char * old_name,
+ 	int old_len,
+ 	struct inode * new_dir,
+ 	const char * new_name,
+ 	int new_len)
+ {
+ 	/* #Specification: weakness / rename
+ 		There is a case where UMSDOS rename has a different behavior
+ 		than normal UNIX file system. Renaming an open file across
+ 		directory boundary does not work. Renaming an open file within
+ 		a directory does work however.
+ 
+ 		The problem (not sure) is in the linux VFS msdos driver.
+ 		I believe this is not a bug but a design feature, because
+ 		an inode number represent some sort of directory address
+ 		in the MSDOS directory structure. So moving the file into
+ 		another directory does not preserve the inode number.
+ 	*/
+ 	int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
+ 	if (ret == 0){
+ 		ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
+ 			,new_len,0);
+ 	}
+ 	return ret;
+ }
+ 
diff -rc2P linux.1.1.12/fs/umsdos/notes linux/fs/umsdos/notes
*** linux.1.1.12/fs/umsdos/notes
--- linux/fs/umsdos/notes	Wed May 11 23:47:33 1994
***************
*** 0 ****
--- 1,17 ----
+ This file contain idea and things I don't want to forget
+ 
+ Possible bug in fs/read_write.c
+ Function sys_readdir()
+ 
+ 	There is a call the verify_area that does not take in account
+ 	the count parameter. I guess it should read
+ 
+ 	error = verify_area(VERIFY_WRITE, dirent, count*sizeof (*dirent));
+ 
+ 	instead of
+ 
+ 	error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent));
+ 
+ 	Of course, now , count is always 1
+ 
+ 
diff -rc2P linux.1.1.12/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
*** linux.1.1.12/fs/umsdos/rdir.c
--- linux/fs/umsdos/rdir.c	Wed May 11 23:47:33 1994
***************
*** 0 ****
--- 1,239 ----
+ /*
+  *  linux/fs/umsdos/rdir.c
+  *
+  *  Written 1994 by Jacques Gelinas
+  *
+  *  Extended MS-DOS directory pure MS-DOS handling functions
+  *  (For directory without EMD file).
+  */
+ 
+ #include <asm/segment.h>
+ 
+ #include <linux/sched.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/errno.h>
+ #include <linux/stat.h>
+ #include <linux/limits.h>
+ #include <linux/umsdos_fs.h>
+ #include <linux/malloc.h>
+ 
+ #define PRINTK(x)
+ #define Printk(x) printk x
+ 
+ 
+ extern struct inode *pseudo_root;
+ 
+ static int UMSDOS_rreaddir (
+ 	struct inode *dir,
+ 	struct file *filp,
+     struct dirent *dirent,
+ 	int count)
+ {
+ 	int ret = 0;
+ 	while (1){
+ 		ret = msdos_readdir(dir,filp,dirent,count);
+ 		if (ret == 5
+ 			&& pseudo_root != NULL
+ 			&& dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){
+ 			/*
+ 				In pseudo root mode, we must eliminate logically
+ 				the directory linux from the real root.
+ 			*/
+ 			char name[5];
+ 			memcpy_fromfs (name,dirent->d_name,5);
+ 			if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break;
+ 		}else{
+ 			if (pseudo_root != NULL
+ 				&& ret == 2
+ 				&& dir == dir->i_sb->s_mounted
+ 				&& dir == pseudo_root->i_sb->s_mounted){
+ 				char name[2];
+ 				memcpy_fromfs (name,dirent->d_name,2);
+ 				if (name[0] == '.' && name[1] == '.'){
+ 					put_fs_long (pseudo_root->i_ino,&dirent->d_ino);
+ 				}
+ 			}
+ 			break;
+ 		}
+ 	}
+ 	return ret;
+ }
+ 
+ int UMSDOS_rlookup(
+ 	struct inode *dir,
+ 	const char *name,
+ 	int len,
+ 	struct inode **result)	/* Will hold inode of the file, if successful */
+ {
+ 	int ret;
+ 	if (pseudo_root != NULL
+ 		&& len == 2
+ 		&& name[0] == '.'
+ 		&& name[1] == '.'
+ 		&& dir == dir->i_sb->s_mounted
+ 		&& dir == pseudo_root->i_sb->s_mounted){
+ 		*result = pseudo_root;
+ 		pseudo_root->i_count++;
+ 		ret = 0;
+ 		/* #Specification: pseudo root / DOS/..
+ 			In the real root directory (c:\), the directory ..
+ 			is the pseudo root (c:\linux).
+ 		*/
+ 	}else{
+ 		ret = umsdos_real_lookup (dir,name,len,result);
+ 		if (ret == 0){
+ 			struct inode *inode = *result;
+ 			if (inode == pseudo_root){
+ 				/* #Specification: pseudo root / DOS/linux
+ 					Even in the real root directory (c:\), the directory
+ 					/linux won't show
+ 				*/
+ 				ret = -ENOENT;
+ 				iput (pseudo_root);
+ 				*result = NULL;
+ 			}else if (S_ISDIR(inode->i_mode)){
+ 				/* We must place the proper function table */
+ 				/* depending if this is a MsDOS directory or an UMSDOS directory */
+ 				umsdos_setup_dir_inode(inode);
+ 			}
+ 		}
+ 	}
+ 	iput (dir);
+ 	return ret;
+ }
+ 
+ static int UMSDOS_rrmdir (
+ 	struct inode *dir,
+ 	const char *name,
+ 	int len)
+ {
+ 	/* #Specification: dual mode / rmdir in a DOS directory
+ 		In a DOS (not EMD in it) directory, we use a reverse strategy
+ 		compared with an Umsdos directory. We assume that a subdirectory
+ 		of a DOS directory is also a DOS directory. This is not always
+ 		true (umssync may be used anywhere), but make sense.
+ 
+ 		So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
+ 		then we check if it is a Umsdos directory. We check if it is
+ 		really empty (only . .. and --linux-.--- in it). If it is true
+ 		we remove the EMD and do a msdos_rmdir() again.
+ 
+ 		In a Umsdos directory, we assume all subdirectory are also
+ 		Umsdos directory, so we check the EMD file first.
+ 	*/
+ 	int ret;
+ 	if (umsdos_is_pseudodos(dir,name,len)){
+ 		/* #Specification: pseudo root / rmdir /DOS
+ 			The pseudo sub-directory /DOS can't be removed!
+ 			This is done even if the pseudo root is not a Umsdos
+ 			directory anymore (very unlikely), but an accident (under
+ 			MsDOS) is always possible.
+ 
+ 			EPERM is returned.
+ 		*/
+ 		ret = -EPERM;
+ 	}else{
+ 		umsdos_lockcreate (dir);
+ 		dir->i_count++;
+ 		ret = msdos_rmdir (dir,name,len);
+ 		if (ret == -ENOTEMPTY){
+ 			struct inode *sdir;
+ 			dir->i_count++;
+ 			ret = UMSDOS_rlookup (dir,name,len,&sdir);
+ 			PRINTK (("rrmdir lookup %d ",ret));
+ 			if (ret == 0){
+ 				int empty;
+ 				if ((empty = umsdos_isempty (sdir)) != 0){
+ 					PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
+ 					if (empty == 2){
+ 						/*
+ 							Not a Umsdos directory, so the previous msdos_rmdir
+ 							was not lying :-)
+ 						*/
+ 						ret = -ENOTEMPTY;
+ 					}else if (empty == 1){
+ 						/* We have to removed the EMD file */
+ 						ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
+ 							,UMSDOS_EMD_NAMELEN);
+ 						sdir = NULL;
+ 						if (ret == 0){
+ 							dir->i_count++;
+ 							ret = msdos_rmdir (dir,name,len);
+ 						}
+ 					}
+ 				}else{
+ 					ret = -ENOTEMPTY;
+ 				}
+ 				iput (sdir);
+ 			}
+ 		}
+ 		umsdos_unlockcreate (dir);
+ 	}
+ 	iput (dir);
+ 	return ret;
+ }
+ 
+ /* #Specification: dual mode / introduction
+ 	One goal of UMSDOS is to allow a practical and simple coexistence
+ 	between MsDOS and Linux in a single partition. Using the EMD file
+ 	in each directory, UMSDOS add Unix semantics and capabilities to
+ 	normal DOS file system. To help and simplify coexistence, here is
+ 	the logic related to the EMD file.
+ 
+ 	If it is missing, then the directory is managed by the MsDOS driver.
+ 	The names are limited to DOS limits (8.3). No links, no device special
+ 	and pipe and so on.
+ 
+ 	If it is there, it is the directory. If it is there but empty, then
+ 	the directory looks empty. The utility umssync allows synchronisation
+ 	of the real DOS directory and the EMD.
+ 
+ 	Whenever umssync is applied to a directory without EMD, one is
+ 	created on the fly. The directory is promoted to full unix semantic.
+ 	Of course, the ls command will show exactly the same content as before
+ 	the umssync session.
+ 
+ 	It is believed that the user/admin will promote directories to unix
+ 	semantic as needed.
+ 
+ 	The strategy to implement this is to use two function table (struct
+ 	inode_operations). One for true UMSDOS directory and one for directory
+ 	with missing EMD.
+ 
+ 	Functions related to the DOS semantic (but aware of UMSDOS) generally
+ 	have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
+ 	from the one with full UMSDOS semantic.
+ */
+ static struct file_operations umsdos_rdir_operations = {
+ 	NULL,				/* lseek - default */
+ 	UMSDOS_dir_read,	/* read */
+ 	NULL,				/* write - bad */
+ 	UMSDOS_rreaddir,	/* readdir */
+ 	NULL,				/* select - default */
+ 	UMSDOS_ioctl_dir,	/* ioctl - default */
+ 	NULL,				/* mmap */
+ 	NULL,				/* no special open code */
+ 	NULL,				/* no special release code */
+ 	NULL				/* fsync */
+ };
+ 
+ struct inode_operations umsdos_rdir_inode_operations = {
+ 	&umsdos_rdir_operations,	/* default directory file-ops */
+ 	msdos_create,		/* create */
+ 	UMSDOS_rlookup,		/* lookup */
+ 	NULL,				/* link */
+ 	msdos_unlink,		/* unlink */
+ 	NULL,				/* symlink */
+ 	msdos_mkdir,		/* mkdir */
+ 	UMSDOS_rrmdir,		/* rmdir */
+ 	NULL,				/* mknod */
+ 	msdos_rename,		/* rename */
+ 	NULL,				/* readlink */
+ 	NULL,				/* follow_link */
+ 	NULL,				/* bmap */
+ 	NULL,				/* truncate */
+ 	NULL				/* permission */
+ };
+ 
+ 
diff -rc2P linux.1.1.12/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
*** linux.1.1.12/fs/umsdos/symlink.c
--- linux/fs/umsdos/symlink.c	Thu May 12 00:21:54 1994
***************
*** 0 ****
--- 1,143 ----
+ /*
+  *  linux/fs/umsdos/file.c
+  *
+  *  Written 1992 by Jacques Gelinas
+  *	inpired from linux/fs/msdos/file.c Werner Almesberger
+  *
+  *  Extended MS-DOS regular file handling primitives
+  */
+ 
+ #include <asm/segment.h>
+ #include <asm/system.h>
+ 
+ #include <linux/sched.h>
+ #include <linux/fs.h>
+ #include <linux/msdos_fs.h>
+ #include <linux/errno.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/umsdos_fs.h>
+ #include <linux/malloc.h>
+ 
+ #define PRINTK(x)
+ #define Printk(x)	printk x
+ /*
+ 	Read the data associate with the symlink.
+ 	Return lenght read in buffer or  a negative error code.
+ */
+ static int umsdos_readlink_x (
+ 	struct inode *inode,
+ 	char *buffer,
+ 	int (*msdos_read)(struct inode *, struct file *, char *, int),
+ 	int bufsiz)
+ {
+ 	int ret = inode->i_size;
+ 	struct file filp;
+ 	filp.f_pos = 0;
+ 	if (ret > bufsiz) ret = bufsiz;
+ 	if ((*msdos_read) (inode, &filp, buffer,ret) != ret){
+ 		ret = -EIO;
+ 	}
+ 	return ret;
+ }
+ /*
+ 	Follow a symbolic link chain by calling open_namei recursivly
+ 	until an inode is found.
+ 
+ 	Return 0 if ok, or a negative error code if not.
+ */
+ static int UMSDOS_follow_link(
+ 	struct inode * dir,
+ 	struct inode * inode,
+ 	int flag,
+ 	int mode,
+ 	struct inode ** res_inode)
+ {
+ 	int ret = -ELOOP;
+ 	*res_inode = NULL;
+ 	if (current->link_count < 5) {
+ 		char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+ 		if (path == NULL){
+ 			ret = -ENOMEM;
+ 		}else{
+ 			if (!dir) {
+ 				dir = current->fs[1].root;
+ 				dir->i_count++;
+ 			}
+ 			if (!inode){
+ 				PRINTK (("symlink: inode = NULL\n"));
+ 				ret = -ENOENT;
+ 			}else if (!S_ISLNK(inode->i_mode)){
+ 				PRINTK (("symlink: Not ISLNK\n"));
+ 				*res_inode = inode;
+ 				inode = NULL;
+ 				ret = 0;
+ 			}else{
+ 				ret = umsdos_readlink_x (inode,path,msdos_file_read_kmem,PATH_MAX-1);
+ 				if (ret > 0){
+ 					path[ret] = '\0';
+ 					PRINTK (("follow :%s: %d ",path,ret));
+ 					iput(inode);
+ 					inode = NULL;
+ 					current->link_count++;
+ 					ret = open_namei(path,flag,mode,res_inode,dir);
+ 					current->link_count--;
+ 					dir = NULL;
+ 				}else{
+ 					ret = -EIO;
+ 				}
+ 			}
+ 			kfree (path);
+ 		}
+ 	}	
+ 	iput(inode);
+ 	iput(dir);
+ 	PRINTK (("follow_link ret %d\n",ret));
+ 	return ret;
+ }
+ 
+ static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen)
+ {
+ 	int ret = -EINVAL;
+ 	if (S_ISLNK(inode->i_mode)) {
+ 		ret = umsdos_readlink_x (inode,buffer,msdos_file_read,buflen);
+ 	}
+ 	PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen));
+ 	iput(inode);
+ 	return ret;
+ 	
+ }
+ 
+ static struct file_operations umsdos_symlink_operations = {
+ 	NULL,				/* lseek - default */
+ 	NULL,				/* read */
+ 	NULL,				/* write */
+ 	NULL,				/* readdir - bad */
+ 	NULL,				/* select - default */
+ 	NULL,				/* ioctl - default */
+ 	NULL,				/* mmap */
+ 	NULL,				/* no special open is needed */
+ 	NULL,				/* release */
+ 	NULL				/* fsync */
+ };
+ 
+ struct inode_operations umsdos_symlink_inode_operations = {
+ 	&umsdos_symlink_operations,	/* default file operations */
+ 	NULL,			/* create */
+ 	NULL,			/* lookup */
+ 	NULL,			/* link */
+ 	NULL,			/* unlink */
+ 	NULL,			/* symlink */
+ 	NULL,			/* mkdir */
+ 	NULL,			/* rmdir */
+ 	NULL,			/* mknod */
+ 	NULL,			/* rename */
+ 	UMSDOS_readlink,	/* readlink */
+ 	UMSDOS_follow_link,	/* follow_link */
+ 	NULL,			/* bmap */
+ 	NULL,			/* truncate */
+ 	NULL			/* permission */
+ };
+ 
+ 
+ 
diff -rc2P linux.1.1.12/include/linux/fs.h linux/include/linux/fs.h
*** linux.1.1.12/include/linux/fs.h	Fri May 20 23:49:07 1994
--- linux/include/linux/fs.h	Wed May 11 23:48:43 1994
***************
*** 158,161 ****
--- 158,162 ----
  #include <linux/hpfs_fs_i.h>
  #include <linux/msdos_fs_i.h>
+ #include <linux/umsdos_fs_i.h>
  #include <linux/iso_fs_i.h>
  #include <linux/nfs_fs_i.h>
***************
*** 202,205 ****
--- 203,207 ----
  		struct hpfs_inode_info hpfs_i;
  		struct msdos_inode_info msdos_i;
+ 		struct umsdos_inode_info umsdos_i;
  		struct iso_inode_info isofs_i;
  		struct nfs_inode_info nfs_i;
***************
*** 300,303 ****
--- 302,306 ----
  	void (*truncate) (struct inode *);
  	int (*permission) (struct inode *, int);
+ 	int (*smap) (struct inode *,int);
  };
  
diff -rc2P linux.1.1.12/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
*** linux.1.1.12/include/linux/msdos_fs.h	Wed Dec  1 07:44:15 1993
--- linux/include/linux/msdos_fs.h	Wed May 11 23:48:51 1994
***************
*** 162,165 ****
--- 162,166 ----
  extern int msdos_rmdir(struct inode *dir,const char *name,int len);
  extern int msdos_unlink(struct inode *dir,const char *name,int len);
+ extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len);
  extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
  	struct inode *new_dir,const char *new_name,int new_len);
***************
*** 180,190 ****
  
  extern struct inode_operations msdos_dir_inode_operations;
! 
  /* file.c */
  
  extern struct inode_operations msdos_file_inode_operations;
  extern struct inode_operations msdos_file_inode_operations_no_bmap;
  
  extern void msdos_truncate(struct inode *inode);
  
  #endif
--- 181,202 ----
  
  extern struct inode_operations msdos_dir_inode_operations;
! extern int msdos_readdir (struct inode *inode, struct file *filp,
! 	struct dirent *dirent, int count);
! extern int msdos_readdir_kmem (struct inode *inode, struct file *filp,
! 	struct dirent *dirent, int count);
  /* file.c */
  
  extern struct inode_operations msdos_file_inode_operations;
+ extern int msdos_file_read_kmem(struct inode *, struct file *, char *, int);
+ extern int msdos_file_read(struct inode *, struct file *, char *, int);
+ extern int msdos_file_write_kmem(struct inode *, struct file *, char *, int);
+ extern int msdos_file_write(struct inode *, struct file *, char *, int);
  extern struct inode_operations msdos_file_inode_operations_no_bmap;
  
  extern void msdos_truncate(struct inode *inode);
+ 
+ /* mmap.c */
+ extern int msdos_mmap (struct inode *, struct file *, unsigned long, size_t
+ 	,int , unsigned long);
  
  #endif
diff -rc2P linux.1.1.12/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h
*** linux.1.1.12/include/linux/msdos_fs_i.h	Wed Dec  1 07:44:15 1993
--- linux/include/linux/msdos_fs_i.h	Wed May 11 23:48:51 1994
***************
*** 2,5 ****
--- 2,12 ----
  #define _MSDOS_FS_I
  
+ #ifndef _LINUX_CONFIG_H
+ #include <linux/config.h>
+ #endif
+ #ifndef _LINUX_PIPE_FS_I_H
+ #include <linux/pipe_fs_i.h>
+ #endif
+ 
  /*
   * MS-DOS file system inode data in memory
***************
*** 7,10 ****
--- 14,32 ----
  
  struct msdos_inode_info {
+ 	/*
+ 		UMSDOS manage special file and fifo as normal empty
+ 		msdos file. fifo inode processing conflict with msdos
+ 		processing. So I insert the pipe_inode_info so the
+ 		information does not overlap. This increases the size of
+ 		the msdos_inode_info, but the clear winner here is
+ 		the ext2_inode_info. So it does not change anything to
+ 		the total size of a struct inode.
+ 
+ 		I have not put it conditionnal. With the advent of loadable
+ 		file system drivers, it would be very easy to compile
+ 		a MsDOS FS driver unaware of UMSDOS and then later to
+ 		load a (then incompatible) UMSDOS FS driver.
+ 	*/
+ 	struct pipe_inode_info reserved;
  	int i_start;	/* first cluster or 0 */
  	int i_attrs;	/* unused attribute bits */
diff -rc2P linux.1.1.12/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
*** linux.1.1.12/include/linux/umsdos_fs.h
--- linux/include/linux/umsdos_fs.h	Wed May 11 23:54:05 1994
***************
*** 0 ****
--- 1,105 ----
+ #ifndef LINUX_UMSDOS_FS_H
+ #define LINUX_UMSDOS_FS_H
+ 
+ #define UMSDOS_VERSION	0
+ #define UMSDOS_RELEASE	3
+ 
+ #ifndef LINUX_FS_H
+ #include <linux/fs.h>
+ #endif
+ 
+ /* This is the file acting as a directory extension */
+ #define UMSDOS_EMD_FILE		"--linux-.---"
+ #define UMSDOS_EMD_NAMELEN	12
+ #define UMSDOS_PSDROOT_NAME	"linux"
+ #define UMSDOS_PSDROOT_LEN	5
+ 
+ struct umsdos_fake_info {
+ 	char fname[13];
+ 	int  len;
+ };
+ 
+ #define UMSDOS_MAXNAME	220
+ /* This structure is 256 bytes large, depending on the name, only part */
+ /* of it is written to disk */
+ 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 */
+ 	uid_t		 uid;		/* Owner user id */
+ 	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 */
+ 							/* special file */
+ 	umode_t		mode;		/* Standard UNIX permissions bits + type of */
+ 	char	spare[12];		/* unused bytes for future extensions */
+ 							/* file, see linux/stat.h */
+ 	char name[UMSDOS_MAXNAME];	/* Not '\0' terminated */
+ 							/* but '\0' padded, so it will allow */
+ 							/* for adding news fields in this record */
+ 							/* by reducing the size of name[] */
+ };
+ #define UMSDOS_HIDDEN	1	/* Never show this entry in directory search */
+ #define UMSDOS_HLINK	2	/* It is a (pseudo) hard link */
+ 
+ /* #Specification: EMD file / record size
+ 	Entry are 64 bytes wide in the EMD file. It allows for a 30 characters
+ 	name. If a name is longer, contiguous entries are allocated. So a
+ 	umsdos_dirent may span multiple records.
+ */
+ #define UMSDOS_REC_SIZE		64
+ 
+ /* Translation between MSDOS name and UMSDOS name */
+ struct umsdos_info{
+ 	int msdos_reject;	/* Tell if the file name is invalid for MSDOS */
+ 						/* See umsdos_parse */
+ 	struct umsdos_fake_info fake;
+ 	struct umsdos_dirent entry;
+ 	off_t f_pos;		/* offset of the entry in the EMD file */
+ 						/* or offset where the entry may be store */
+ 						/* if it is a new entry */
+ 	int recsize;		/* Record size needed to store entry */
+ };
+ 
+ /* Definitions for ioctl (number randomly chosen) */
+ /* The next ioctl commands operate only on the DOS directory */
+ /* The file umsdos_progs/umsdosio.c contain a string table */
+ /* based on the order of those definition. Keep it in sync */
+ #define UMSDOS_READDIR_DOS	1234	/* Do a readdir of the DOS directory */
+ #define UMSDOS_UNLINK_DOS	1235	/* Erase in the DOS directory only */
+ #define UMSDOS_RMDIR_DOS	1236	/* rmdir in the DOS directory only */
+ #define UMSDOS_STAT_DOS		1237	/* Get info about a file */
+ /* The next ioctl commands operate only on the EMD file */
+ #define UMSDOS_CREAT_EMD	1238	/* Create a file */
+ #define UMSDOS_UNLINK_EMD	1239	/* unlink (rmdir) a file */
+ #define UMSDOS_READDIR_EMD	1240	/* read the EMD file only. */
+ #define UMSDOS_GETVERSION	1241	/* Get the release number of UMSDOS */
+ #define UMSDOS_INIT_EMD		1242	/* Create the EMD file if not there */
+ #define UMSDOS_DOS_SETUP	1243	/* Set the defaults of the MsDOS driver */
+ 
+ #ifndef _SYS_STAT_H
+ #include <sys/stat.h>
+ #endif
+ 
+ struct umsdos_ioctl{
+ 	struct dirent dos_dirent;
+ 	struct umsdos_dirent umsdos_dirent;
+ 	struct stat stat;
+ 	char version,release;
+ };
+ 
+ /* Different macros to access struct umsdos_dirent */
+ #define EDM_ENTRY_ISUSED(e) ((e)->name_len!=0)
+ 
+ extern struct inode_operations umsdos_dir_inode_operations;
+ extern struct file_operations  umsdos_file_operations;
+ extern struct inode_operations umsdos_file_inode_operations;
+ extern struct inode_operations umsdos_file_inode_operations_no_bmap;
+ extern struct inode_operations umsdos_symlink_inode_operations;
+ 
+ 
+ #include <linux/umsdos_fs.p>
+ 
+ #endif
diff -rc2P linux.1.1.12/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
*** linux.1.1.12/include/linux/umsdos_fs.p
--- linux/include/linux/umsdos_fs.p	Wed May 11 23:49:37 1994
***************
*** 0 ****
--- 1,122 ----
+ /* check.c 05/02/94 15.36.10 */
+ void check_page_tables (void);
+ /* dir.c 24/04/94 00.00.40 */
+ int UMSDOS_dir_read (struct inode *inode,
+ 	 struct file *filp,
+ 	 char *buf,
+ 	 int count);
+ void umsdos_lookup_patch (struct inode *dir,
+ 	 struct inode *inode,
+ 	 struct umsdos_dirent *entry,
+ 	 off_t emd_pos);
+ int umsdos_inode2entry (struct inode *dir,
+ 	 struct inode *inode,
+ 	 struct umsdos_dirent *entry);
+ int umsdos_locate_path (struct inode *inode, char *path);
+ int umsdos_is_pseudodos (struct inode *dir, const char *name, int len);
+ int UMSDOS_lookup (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 struct inode **result);
+ int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
+ /* emd.c 05/02/94 15.36.10 */
+ int umsdos_emd_dir_write (struct inode *emd_dir,
+ 	 struct file *filp,
+ 	 char *buf,
+ 	 int count);
+ int umsdos_emd_dir_read (struct inode *emd_dir,
+ 	 struct file *filp,
+ 	 char *buf,
+ 	 int count);
+ struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat);
+ int umsdos_emd_dir_readentry (struct inode *emd_dir,
+ 	 struct file *filp,
+ 	 struct umsdos_dirent *entry);
+ int umsdos_writeentry (struct inode *dir,
+ 	 struct inode *emd_dir,
+ 	 struct umsdos_info *info,
+ 	 int free_entry);
+ int umsdos_newentry (struct inode *dir, struct umsdos_info *info);
+ int umsdos_newhidden (struct inode *dir, struct umsdos_info *info);
+ int umsdos_delentry (struct inode *dir,
+ 	 struct umsdos_info *info,
+ 	 int isdir);
+ int umsdos_isempty (struct inode *dir);
+ int umsdos_findentry (struct inode *dir,
+ 	 struct umsdos_info *info,
+ 	 int expect);
+ /* file.c 05/02/94 15.36.10 */
+ /* inode.c 23/04/94 23.57.54 */
+ void UMSDOS_put_inode (struct inode *inode);
+ void UMSDOS_put_super (struct super_block *sb);
+ void UMSDOS_statfs (struct super_block *sb, struct statfs *buf);
+ int umsdos_real_lookup (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 struct inode **result);
+ void umsdos_setup_dir_inode (struct inode *inode);
+ void umsdos_set_dirinfo (struct inode *inode,
+ 	 struct inode *dir,
+ 	 off_t f_pos);
+ int umsdos_isinit (struct inode *inode);
+ void umsdos_patch_inode (struct inode *inode,
+ 	 struct inode *dir,
+ 	 off_t f_pos);
+ int umsdos_get_dirowner (struct inode *inode, struct inode **result);
+ void UMSDOS_read_inode (struct inode *inode);
+ void UMSDOS_write_inode (struct inode *inode);
+ int UMSDOS_notify_change (int flags, struct inode *inode);
+ struct super_block *UMSDOS_read_super (struct super_block *s,
+ 	 void *data,
+ 	 int silent);
+ /* ioctl.c 05/02/94 15.36.10 */
+ int UMSDOS_ioctl_dir (struct inode *dir,
+ 	 struct file *filp,
+ 	 unsigned int cmd,
+ 	 unsigned long data);
+ /* mangle.c 05/02/94 15.36.10 */
+ int printk (const char *msg, ...);
+ void umsdos_manglename (struct umsdos_info *info);
+ int umsdos_evalrecsize (int len);
+ int umsdos_parse (const char *fname, int len, struct umsdos_info *info);
+ /* namei.c 06/04/94 18.24.58 */
+ void umsdos_lockcreate (struct inode *dir);
+ void umsdos_startlookup (struct inode *dir);
+ void umsdos_unlockcreate (struct inode *dir);
+ void umsdos_endlookup (struct inode *dir);
+ int UMSDOS_symlink (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 const char *symname);
+ int UMSDOS_link (struct inode *oldinode,
+ 	 struct inode *dir,
+ 	 const char *name,
+ 	 int len);
+ int UMSDOS_create (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 int mode,
+ 	 struct inode **result);
+ int UMSDOS_mkdir (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 int mode);
+ int UMSDOS_mknod (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 int mode,
+ 	 int rdev);
+ int UMSDOS_rmdir (struct inode *dir, const char *name, int len);
+ int UMSDOS_unlink (struct inode *dir, const char *name, int len);
+ int UMSDOS_rename (struct inode *old_dir,
+ 	 const char *old_name,
+ 	 int old_len,
+ 	 struct inode *new_dir,
+ 	 const char *new_name,
+ 	 int new_len);
+ /* rdir.c 23/04/94 10.51.44 */
+ int UMSDOS_rlookup (struct inode *dir,
+ 	 const char *name,
+ 	 int len,
+ 	 struct inode **result);
+ /* symlink.c 05/02/94 15.36.10 */
diff -rc2P linux.1.1.12/include/linux/umsdos_fs_i.h linux/include/linux/umsdos_fs_i.h
*** linux.1.1.12/include/linux/umsdos_fs_i.h
--- linux/include/linux/umsdos_fs_i.h	Wed May 11 23:49:38 1994
***************
*** 0 ****
--- 1,140 ----
+ #ifndef UMSDOS_FS_I_H
+ #define UMSDOS_FS_I_H
+ 
+ #ifndef _LINUX_TYPES_H
+ #include <linux/types.h>
+ #endif
+ #include <linux/msdos_fs_i.h>
+ #include <linux/pipe_fs_i.h>
+ 
+ /* #Specification: strategy / in memory inode
+ 	Here is the information specific to the inode of the UMSDOS file
+ 	system. This information is added to the end of the standard struct
+ 	inode. Each file system has its own extension to struct inode,
+ 	so do the umsdos file system.
+ 
+ 	The strategy is to have the umsdos_inode_info as a superset of
+ 	the msdos_inode_info, since most of the time the job is done
+ 	by the msdos fs code.
+ 
+ 	So we duplicate the msdos_inode_info, and add our own info at the
+ 	end.
+ 
+ 	For all file type (and directory) the inode has a reference to:
+ 		the directory which hold this entry: i_dir_owner
+ 		The EMD file of i_dir_owner: i_emd_owner
+ 		The offset in this EMD file of the entry: pos
+ 
+ 	For directory, we also have a reference to the inode of its
+ 	own EMD file. Also, we have dir_locking_info to help synchronise
+ 	file creation and file lookup. This data is sharing space with
+ 	the pipe_inode_info not used by directory. See also msdos_fs_i.h
+ 	for more information about pipe_inode_info and msdos_inode_info.
+ 
+ 	Special file and fifo do have an inode which correspond to an
+ 	empty MSDOS file.
+ 
+ 	symlink are processed mostly like regular file. The content is the
+ 	link.
+ 
+ 	fifos add there own extension to the inode. I have reserved some
+ 	space for fifos side by side with msdos_inode_info. This is just
+ 	to for the show, because msdos_inode_info already include the
+ 	pipe_inode_info.
+ 
+ 	The UMSDOS specific extension is placed after the union.
+ */
+ struct dir_locking_info {
+ 	struct wait_queue *p;
+ 	short int looking;		/* How many process doing a lookup */
+ 	short int creating;		/* Is there any creation going on here */
+ 							/* Only one at a time, although one */
+ 							/* may recursivly lock, so it is a counter */
+ 	long pid;				/* pid of the process owning the creation */
+ 							/* lock */
+ };
+ struct umsdos_inode_info {
+ 	union {
+ 		struct msdos_inode_info msdos_info;
+ 		struct pipe_inode_info pipe_info;
+ 		struct dir_locking_info dir_info;
+ 	}u;	/* Simply a filler, never referenced by fs/umsdos/... */
+ 	unsigned long i_dir_owner;	/* Inode of the dir which hold this */
+ 								/* entry */
+ 	unsigned long i_emd_owner;	/* Inode of the EMD file of i_dir_owner */
+ 	off_t pos;					/* Entry offset in the emd_owner file */
+ 	/* The rest is used only if this inode describe a directory */
+ 	unsigned long i_emd_dir;	/* Inode of the EMD file of this inode */
+ };
+ 
+ #endif
+ #ifndef UMSDOS_FS_I_H
+ #define UMSDOS_FS_I_H
+ 
+ #ifndef _LINUX_TYPES_H
+ #include <linux/types.h>
+ #endif
+ #include <linux/msdos_fs_i.h>
+ #include <linux/pipe_fs_i.h>
+ 
+ /* #Specification: strategy / in memory inode
+ 	Here is the information specific to the inode of the UMSDOS file
+ 	system. This information is added to the end of the standard struct
+ 	inode. Each file system has its own extension to struct inode,
+ 	so do the umsdos file system.
+ 
+ 	The strategy is to have the umsdos_inode_info as a superset of
+ 	the msdos_inode_info, since most of the time the job is done
+ 	by the msdos fs code.
+ 
+ 	So we duplicate the msdos_inode_info, and add our own info at the
+ 	end.
+ 
+ 	For all file type (and directory) the inode has a reference to:
+ 		the directory which hold this entry: i_dir_owner
+ 		The EMD file of i_dir_owner: i_emd_owner
+ 		The offset in this EMD file of the entry: pos
+ 
+ 	For directory, we also have a reference to the inode of its
+ 	own EMD file. Also, we have dir_locking_info to help synchronise
+ 	file creation and file lookup. This data is sharing space with
+ 	the pipe_inode_info not used by directory. See also msdos_fs_i.h
+ 	for more information about pipe_inode_info and msdos_inode_info.
+ 
+ 	Special file and fifo do have an inode which correspond to an
+ 	empty MSDOS file.
+ 
+ 	symlink are processed mostly like regular file. The content is the
+ 	link.
+ 
+ 	fifos add there own extension to the inode. I have reserved some
+ 	space for fifos side by side with msdos_inode_info. This is just
+ 	to for the show, because msdos_inode_info already include the
+ 	pipe_inode_info.
+ 
+ 	The UMSDOS specific extension is placed after the union.
+ */
+ struct dir_locking_info {
+ 	struct wait_queue *p;
+ 	short int looking;		/* How many process doing a lookup */
+ 	short int creating;		/* Is there any creation going on here */
+ 							/* Only one at a time, although one */
+ 							/* may recursivly lock, so it is a counter */
+ 	long pid;				/* pid of the process owning the creation */
+ 							/* lock */
+ };
+ struct umsdos_inode_info {
+ 	union {
+ 		struct msdos_inode_info msdos_info;
+ 		struct pipe_inode_info pipe_info;
+ 		struct dir_locking_info dir_info;
+ 	}u;	/* Simply a filler, never referenced by fs/umsdos/... */
+ 	unsigned long i_dir_owner;	/* Inode of the dir which hold this */
+ 								/* entry */
+ 	unsigned long i_emd_owner;	/* Inode of the EMD file of i_dir_owner */
+ 	off_t pos;					/* Entry offset in the emd_owner file */
+ 	/* The rest is used only if this inode describe a directory */
+ 	unsigned long i_emd_dir;	/* Inode of the EMD file of this inode */
+ };
+ 
+ #endif
diff -rc2P linux.1.1.12/init/main.c linux/init/main.c
*** linux.1.1.12/init/main.c	Fri May 20 23:49:25 1994
--- linux/init/main.c	Wed May 11 23:38:32 1994
***************
*** 495,498 ****
--- 495,514 ----
  	setup();
  	sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
+ 
+ 	#ifdef CONFIG_UMSDOS_FS
+ 	{
+ 		/*
+ 			When mounting a umsdos fs as root, we detect
+ 			the pseudo_root (/linux) and initialise it here.
+ 			pseudo_root is defined in fs/umsdos/inode.c
+ 		*/
+ 		extern struct inode *pseudo_root;
+ 		if (pseudo_root != NULL){
+ 			current->fs->root = pseudo_root;
+ 			current->fs->pwd  = pseudo_root;
+ 		}
+ 	}
+ 	#endif
+ 
  	(void) open("/dev/tty1",O_RDWR,0);
  	(void) dup(0);
diff -rc2P linux.1.1.12/mm/swap.c linux/mm/swap.c
*** linux.1.1.12/mm/swap.c	Fri May 20 23:49:21 1994
--- linux/mm/swap.c	Wed May 11 23:38:32 1994
***************
*** 18,21 ****
--- 18,22 ----
  #include <linux/string.h>
  #include <linux/stat.h>
+ #include <linux/fs.h>
  
  #include <asm/system.h> /* for cli()/sti() */
***************
*** 84,99 ****
  		ll_rw_page(rw,p->swap_device,offset,buf);
  	} else if (p->swap_file) {
  		unsigned int zones[8];
! 		unsigned int block;
! 		int i, j;
! 
! 		block = offset << (12 - p->swap_file->i_sb->s_blocksize_bits);
! 
! 		for (i=0, j=0; j< PAGE_SIZE ; i++, j +=p->swap_file->i_sb->s_blocksize)
! 			if (!(zones[i] = bmap(p->swap_file,block++))) {
! 				printk("rw_swap_page: bad swap file\n");
! 				return;
  			}
! 		ll_rw_swap_file(rw,p->swap_file->i_dev, zones, i,buf);
  	} else
  		printk("re_swap_page: no swap file or device\n");
--- 85,126 ----
  		ll_rw_page(rw,p->swap_device,offset,buf);
  	} else if (p->swap_file) {
+ 		struct inode *swapf = p->swap_file;
  		unsigned int zones[8];
! 		int i;
! 		if (swapf->i_op->bmap == NULL
! 			&& swapf->i_op->smap != NULL){
! 			/*
! 				With MsDOS, we use msdos_smap which return
! 				a sector number (not a cluster or block number).
! 				It is a patch to enable the UMSDOS project.
! 				Other people are working on better solution.
! 
! 				It sounds like ll_rw_swap_file defined
! 				it operation size (sector size) based on
! 				PAGE_SIZE and the number of block to read.
! 				So using bmap ou smap should work even if
! 				smap will requiered more blocks.
! 			*/
! 			int j;
! 			unsigned int block = offset << 3;
! 
! 			for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
! 				if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
! 					printk("rw_swap_page: bad swap file\n");
! 					return;
! 				}
  			}
! 		}else{
! 			int j;
! 			unsigned int block = offset
! 				<< (12 - swapf->i_sb->s_blocksize_bits);
! 
! 			for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
! 				if (!(zones[i] = bmap(swapf,block++))) {
! 					printk("rw_swap_page: bad swap file\n");
! 					return;
! 				}
! 		}
! 		ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
  	} else
  		printk("re_swap_page: no swap file or device\n");
