Subject: MS-DOS filesystem mounting woes, and proposed fix
To: None <tech-kern@netbsd.org>
From: Greg Troxel <gdt@ir.bbn.com>
List: tech-kern
Date: 08/08/2006 15:07:26
--=-=-=
Content-Transfer-Encoding: quoted-printable


I've been mounting CF cards with MS-DOS filesystems for a long time to
use digital cameras.  Recently a friend got a new camera and a new
Sandisk 4 GB Extreme III CF.  She put the card in the camera, did a
format (since apparently the CF doesn't have the DCIM structure to
start with), shot a bunch of pictures, and was able to mount the CF on
windows without problems.  On her NetBSD machine (i386/3-stable),
mount failed with EINVAL.

On inspection, I found two problems with NetBSD's msdosfs
support.

1) fsck_msdos complains about primary/alternate superblock mismatches.

cmp -l between block 0 and 6 (alternate) shows:

    73 111 117
    74 113  40
    75 117 116
    76 116 101
    77  40 115
    78 104 105
    79  62  40
    80  60  40
    81  60  40

This is "IKON D200" and "O NAME   ".  Fairly clearly, the camera wrote
the primary superblock and didn't update the name in the backup.

The mount vfsop does not check the backup superblock, so this is not
an actual problem.  But fsck_msdos should make this be a warning, and
perhaps check the creator name separately.

2) msdosfs's mount vfsop insists on bootsig2 and bootsig3 (bytes
   252-253) being 0 for FAT32.  But, sandisk ships cards without 0, a
   good quality camera formats without changing these, and windows
   doesn't care.  So I'd say that this isn't part of the real spec.

Block 0 of the card was:

0000000  353 376 220   M   S   D   O   S   5   .   0  \0 002   @      \0
0000020  002  \0  \0  \0  \0 370  \0  \0   ?  \0 020  \0   ?  \0  \0  \0
0000040  301 017   z  \0 321 003  \0  \0  \0  \0  \0  \0 002  \0  \0  \0
0000060  001  \0 006  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000100  200  \0   )  \0  \0  \0  \0   N   I   K   O   N       D   2   0
0000120    0       F   A   T   3   2             220 220 220 220 220 220
0000140  220 220 220 220 220 220 220 220 220 220 220 220 220 220 220 220
*
0000760  220 220 220 220 220 220 220 220 220 220 220 220 220 220   U 252
0001000

I dd'd this to a file, changed bytes 252 and 253 to zero, and dd'd
back to the CF.  I was then able to mount the card.


I suggested to my friend that after she had the bits off, that she
format the card under Windows XP (assuming that's the working
definition of msdosfs since there are no real specs), and then in the
camera.  This resulted a card that works on Windows but not on NetBSD.

for reference, this is from sys/fs/msdosfs/bootsect.h:

struct bootsector710 {
	u_int8_t	bsJump[3];		/* jump inst E9xxxx or EBxx90 */
	int8_t		bsOEMName[8];		/* OEM name and version */
	int8_t		bsBPB[53];		/* BIOS parameter block */
	int8_t		bsExt[26];		/* Bootsector Extension */
	int8_t		bsBootCode[418];	/* pad so structure is 512b */
	u_int8_t	bsBootSectSig2;		/* 2 & 3 are only defined for FAT32? */
	u_int8_t	bsBootSectSig3;
	u_int8_t	bsBootSectSig0;
	u_int8_t	bsBootSectSig1;
#define	BOOTSIG0	0x55
#define	BOOTSIG1	0xaa
#define	BOOTSIG2	0
#define	BOOTSIG3	0
};

I'd like to do the following:

  1) modify msdosfs_vfsops.c to not check sig2/sig3, since it seems
     that isn't really a rule.

  2) modify fsck_msdos to not complain about the creator name being
     different in the backup superblock, since apparently that isn't
     really a rule either.

any objections?


patch for msdosfs to be more verbose about errors:

=2D-- msdosfs_vfsops.c.~1.33~	2006-07-31 16:02:16.000000000 -0400
+++ msdosfs_vfsops.c	2006-07-31 16:03:06.000000000 -0400
@@ -474,6 +474,7 @@
 	if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
 		if (bsp->bs50.bsBootSectSig0 !=3D BOOTSIG0
 		    || bsp->bs50.bsBootSectSig1 !=3D BOOTSIG1) {
+			printf("msdosfs_mountfs: bootsig[01]");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -503,6 +504,7 @@
 		/* XXX - We should probably check more values here */
     		if (!pmp->pm_BytesPerSec || !SecPerClust
 	    		|| pmp->pm_Heads > 255 || pmp->pm_SecPerTrack > 63) {
+			printf("msdosfs_mountfs: secpertrack");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -522,6 +524,12 @@
 		    || pmp->pm_Sectors
 		    || pmp->pm_FATsecs
 		    || getushort(b710->bpbFSVers)) {
+			printf("msdosfs_mountfs: bs710 sig2 %d sig3 %d Sectors %d fatSecs %ld F=
SVers %d\n",
+			       bsp->bs710.bsBootSectSig2,
+			       bsp->bs710.bsBootSectSig3,
+			       pmp->pm_Sectors,
+			       pmp->pm_FATsecs,
+			       getushort(b710->bpbFSVers));
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -543,6 +551,7 @@
 			/*
 			 * GEMDOS doesn't know fat32.
 			 */
+			printf("msdosfs_mountfs: GEMDOS fat32");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -561,6 +570,7 @@
 		  || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
 							> dpart.part->p_size)
 		   ) {
+			printf("msdosfs_mountfs: GEMDOS logical");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -651,6 +661,7 @@
 	 * must be a power of 2
 	 */
 	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
+		printf("msdosfs_mountfs: cluster size");
 		error =3D EINVAL;
 		goto error_exit;
 	}

Index: msdosfs_vfsops.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/fs/msdosfs/msdosfs_vfsops.c,v
retrieving revision 1.33
diff -u -r1.33 msdosfs_vfsops.c
=2D-- msdosfs_vfsops.c	23 Jul 2006 22:06:10 -0000	1.33
+++ msdosfs_vfsops.c	31 Jul 2006 19:43:41 -0000
@@ -474,6 +474,7 @@
 	if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
 		if (bsp->bs50.bsBootSectSig0 !=3D BOOTSIG0
 		    || bsp->bs50.bsBootSectSig1 !=3D BOOTSIG1) {
+			printf("msdosfs_mountfs: bootsig[01]");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -503,6 +504,7 @@
 		/* XXX - We should probably check more values here */
     		if (!pmp->pm_BytesPerSec || !SecPerClust
 	    		|| pmp->pm_Heads > 255 || pmp->pm_SecPerTrack > 63) {
+			printf("msdosfs_mountfs: secpertrack");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -522,6 +524,7 @@
 		    || pmp->pm_Sectors
 		    || pmp->pm_FATsecs
 		    || getushort(b710->bpbFSVers)) {
+			printf("msdosfs_mountfs: bs710");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -543,6 +546,7 @@
 			/*
 			 * GEMDOS doesn't know fat32.
 			 */
+			printf("msdosfs_mountfs: GEMDOS fat32");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -561,6 +565,7 @@
 		  || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
 							> dpart.part->p_size)
 		   ) {
+			printf("msdosfs_mountfs: GEMDOS logical");
 			error =3D EINVAL;
 			goto error_exit;
 		}
@@ -651,6 +656,7 @@
 	 * must be a power of 2
 	 */
 	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
+		printf("msdosfs_mountfs: cluster size");
 		error =3D EINVAL;
 		goto error_exit;
 	}



patch for fsck_msdos (too messy to commit, but may be helpful in
exploring).

Index: boot.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sbin/fsck_msdos/boot.c,v
retrieving revision 1.11
diff -u -r1.11 boot.c
=2D-- boot.c	5 Jun 2006 16:51:18 -0000	1.11
+++ boot.c	8 Aug 2006 18:52:01 -0000
@@ -54,6 +54,7 @@
 	u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
 	u_char backup[DOSBOOTBLOCKSIZE];
 	int ret =3D FSOK;
+	int i;
=20=09
 	if (read(dosfs, block, sizeof block) < sizeof block) {
 		perr("could not read boot block");
@@ -160,10 +161,14 @@
 		backup[65] =3D block[65];				/* XXX */
 		if (memcmp(block + 11, backup + 11, 79)) {
 			/* Correct?					XXX */
=2D			pfatal("backup doesn't compare to primary bootblock");
=2D			if (alwaysno)
=2D				pfatal("\n");
=2D			else
+			pfatal("backup mismatch with primary bootblock\n");
+			pfatal(" backup block %d\n", boot->Backup);
+			for (i=3D0; i< 90; i++) {
+				if (block[i] !=3D backup[i])
+					pfatal("i=3D%d\tm %02x\tb %02x\n",
+					       i, block[i], backup[i]);
+			}
+			if (!alwaysno)
 				return FSFATAL;
 		}
 		/* Check backup FSInfo?					XXX */

=2D-=20
    Greg Troxel <gdt@ir.bbn.com>

--=-=-=
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (NetBSD)

iD8DBQFE2OD2+vesoDJhHiURAlQOAKCRTx46XlvRGY6/CLGZGdaIDJ9BAACfS4kr
DbZZJdP/iMffWTp6CSNbVm8=
=BG/v
-----END PGP SIGNATURE-----
--=-=-=--