diff -urN --exclude-from=diff-exclude linux-2.4.26/fs/fat/inode.c linux-2.4.26-patch/fs/fat/inode.c
--- linux-2.4.26/fs/fat/inode.c	2004-05-19 21:34:40.000000000 +0100
+++ linux-2.4.26-patch/fs/fat/inode.c	2004-05-26 23:27:31.000000000 +0100
@@ -8,6 +8,12 @@
  *  Fixes:
  *
  *  	Max Cohan: Fixed invalid FSINFO offset when info_sector is 0
+ *
+ *  Added:
+ *
+ *      Paul Evans: Added fmode/dmode options for separate file/dir permissions
+ *                  See also include/linux/msdos_fs_sb.h
+ *
  */
 
 #include <linux/module.h>
@@ -75,6 +81,9 @@
 static struct list_head fat_inode_hashtable[FAT_HASH_SIZE];
 spinlock_t fat_inode_lock = SPIN_LOCK_UNLOCKED;
 
+/* mask for inode permission bits - used by fmode/dmode */
+#define MODEMASK (~0777)
+
 void fat_hash_init(void)
 {
 	int i;
@@ -220,6 +229,8 @@
 	opts->fs_uid = current->uid;
 	opts->fs_gid = current->gid;
 	opts->fs_umask = current->fs->umask;
+	opts->fs_fmode = 0666; /* rw-rw-rw- */
+	opts->fs_dmode = 0777; /* rwxrwxrwx */
 	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;
 	opts->codepage = 0;
 	opts->nocase = 0;
@@ -299,6 +310,20 @@
 				if (*value) ret = 0;
 			}
 		}
+		else if (!strcmp(this_char,"fmode")) {
+			if (!value || !*value) ret = 0;
+			else {
+				opts->fs_fmode = simple_strtoul(value,&value,8);
+				if (*value) ret = 0;
+			}
+		}
+		else if (!strcmp(this_char,"dmode")) {
+			if (!value || !*value) ret = 0;
+			else {
+				opts->fs_dmode = simple_strtoul(value,&value,8);
+				if (*value) ret = 0;
+			}
+		}
 		else if (!strcmp(this_char,"debug")) {
 			if (value) ret = 0;
 			else *debug = 1;
@@ -385,7 +410,7 @@
 	inode->i_gid = sbi->options.fs_gid;
 	inode->i_version = ++event;
 	inode->i_generation = 0;
-	inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR;
+	inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask & (sbi->options.fs_dmode | MODEMASK)) | S_IFDIR;
 	inode->i_op = sbi->dir_ops;
 	inode->i_fop = &fat_dir_operations;
 	if (sbi->fat_bits == 32) {
@@ -745,9 +770,10 @@
 	if (error || debug) {
 		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
 		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
-		       "uid=%d,gid=%d,umask=%03o%s]\n",
+		       "uid=%d,gid=%d,umask=%03o,fmode=%03o,dmode=%03o%s]\n",
 		       sbi->fat_bits,opts.name_check,
 		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
+		       opts.fs_fmode,opts.fs_dmode,
 		       MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
 		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
 		       "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
@@ -913,7 +939,7 @@
 	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
 		inode->i_generation &= ~1;
 		inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO &
-		    ~sbi->options.fs_umask) | S_IFDIR;
+		    ~sbi->options.fs_umask & (sbi->options.fs_dmode | MODEMASK)) | S_IFDIR;
 		inode->i_op = sbi->dir_ops;
 		inode->i_fop = &fat_dir_operations;
 
@@ -946,7 +972,7 @@
 		    ((sbi->options.showexec &&
 		       !is_exec(de->ext))
 		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
-		    & ~sbi->options.fs_umask) | S_IFREG;
+		    & ~sbi->options.fs_umask & (sbi->options.fs_fmode | MODEMASK)) | S_IFREG;
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
 		if (sbi->fat_bits == 32)
 			MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
@@ -1037,6 +1063,7 @@
 	struct super_block *sb = dentry->d_sb;
 	struct inode *inode = dentry->d_inode;
 	int error;
+	unsigned int mode;
 
 	/* FAT cannot truncate to a longer file */
 	if (attr->ia_valid & ATTR_SIZE) {
@@ -1063,12 +1090,17 @@
 	if (error)
 		return error;
 
-	if (S_ISDIR(inode->i_mode))
+	if (S_ISDIR(inode->i_mode)) {
 		inode->i_mode |= S_IXUGO;
+		mode = ~MSDOS_SB(sb)->options.fs_umask & (MSDOS_SB(sb)->options.fs_dmode | MODEMASK);
+		}
+	else
+		mode = ~MSDOS_SB(sb)->options.fs_umask & (MSDOS_SB(sb)->options.fs_fmode | MODEMASK);
+
+	inode->i_mode = ((inode->i_mode & S_IFMT) | 
+			 ((((inode->i_mode & S_IRWXU & mode) | S_IRUSR) >> 6)*S_IXUGO)
+			) & mode;
 
-	inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU
-	    & ~MSDOS_SB(sb)->options.fs_umask) | S_IRUSR) >> 6)*S_IXUGO)) &
-	    ~MSDOS_SB(sb)->options.fs_umask;
 	return 0;
 }
 MODULE_LICENSE("GPL");
diff -urN --exclude-from=diff-exclude linux-2.4.26/include/linux/msdos_fs_sb.h linux-2.4.26-patch/include/linux/msdos_fs_sb.h
--- linux-2.4.26/include/linux/msdos_fs_sb.h	2001-10-12 21:48:42.000000000 +0100
+++ linux-2.4.26-patch/include/linux/msdos_fs_sb.h	2004-05-26 23:27:31.000000000 +0100
@@ -9,7 +9,9 @@
 struct fat_mount_options {
 	uid_t fs_uid;
 	gid_t fs_gid;
-	unsigned short fs_umask;
+	unsigned short fs_umask;  /* global mask that masks off bits from either following two fields */
+	unsigned short fs_fmode;  /* mode bits for files for fdmode */
+	unsigned short fs_dmode;  /* mode bits for directories for fdmode */
 	unsigned short codepage;  /* Codepage for shortname conversions */
 	char *iocharset;          /* Charset used for filename input/display */
 	unsigned short shortname; /* flags for shortname display/create rule */
