1) There is no place on a FAT drive to put a disklabel. So when asked where
to write a disklabel on a FAT device, return an error. I chose ENXIO, but
can easily be argued around to something else.

2) When deciding if we have processed one or more MBR/EBR's check the
number of MBR/EBR's we have transited and not the number of partitions
we have spoofed as a result. Increment the count after deciding if we
processing MBR's.

3) If there is a missing signature on the first block, and we thus
decide it isn't an MBR, don't skip checking if it's a FAT device. The
signature should also be there for FAT, but we have other tests to
ensure we are looking at a FAT, and some devices do not have the
signature. And Windows doesn't seem to care.

4) Rename some labels to make more sense. Various other minor cleanups
and comment editing.

This fixes getting a spoofed 'i' partition on my HiMD media, FAT
formatted with 2048-byte sectors.

Thoughts? People with odd spoofing requirements sought as testers. :-).

.... Ken


Index: subr_disk.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_disk.c,v
retrieving revision 1.143
diff -u -p -r1.143 subr_disk.c
--- subr_disk.c 10 Feb 2012 18:41:36 -0000      1.143
+++ subr_disk.c 24 Feb 2012 01:27:40 -0000
@@ -406,7 +406,6 @@ readdoslabel(struct buf *bp, void (*stra
         * Map the partitions to disklabel entries i-p
         */
        while (wander && loop < DOS_MAXEBR) {
-               loop++;
                wander = 0;
                if (part_blkno < extoff)
                        part_blkno = extoff;
@@ -428,16 +427,19 @@ readdoslabel(struct buf *bp, void (*stra
 
                bcopy(bp->b_data + offset, dp, sizeof(dp));
 
-               if (n == 0 && part_blkno == DOSBBSECTOR) {
-                       u_int16_t fattest;
+               if (loop == 0 && part_blkno == DOSBBSECTOR) {
+                       u_int16_t mbrtest;
 
                        /* Check the end of sector marker. */
-                       fattest = ((bp->b_data[510] << 8) & 0xff00) |
+                       mbrtest = ((bp->b_data[510] << 8) & 0xff00) |
                            (bp->b_data[511] & 0xff);
-                       if (fattest != 0x55aa)
-                               goto notfat;
+                       if (mbrtest != 0x55aa)
+                               break;
                }
 
+               /* Keep track of # of mbr's traversed. */
+               loop++;
+
                if (ourpart == -1) {
                        /* Search for our MBR partition */
                        for (dp2=dp, i=0; i < NDOSPART && ourpart == -1;
@@ -446,7 +448,7 @@ readdoslabel(struct buf *bp, void (*stra
                                    dp2->dp_typ == DOSPTYP_OPENBSD)
                                        ourpart = i;
                        if (ourpart == -1)
-                               goto donot;
+                               goto spoofmbrparts;
                        /*
                         * This is our MBR partition. need sector
                         * address for SCSI/IDE, cylinder for
@@ -458,7 +460,7 @@ readdoslabel(struct buf *bp, void (*stra
 
                        /* found our OpenBSD partition, finish up */
                        if (partoffp)
-                               goto notfat;
+                               goto done;
 
                        if (lp->d_ntracks == 0)
                                lp->d_ntracks = dp2->dp_ehd + 1;
@@ -468,11 +470,7 @@ readdoslabel(struct buf *bp, void (*stra
                                lp->d_secpercyl = lp->d_ntracks *
                                    lp->d_nsectors;
                }
-donot:
-               /*
-                * In case the disklabel read below fails, we want to
-                * provide a fake label in i-p.
-                */
+spoofmbrparts:
                for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
                        struct partition *pp;
                        u_int8_t fstype;
@@ -515,7 +513,6 @@ donot:
                                        part_blkno = 0;
                                }
                                wander = 1;
-                               continue;
                                break;
                        default:
                                fstype = FS_OTHER;
@@ -523,6 +520,9 @@ donot:
                        }
 
                        /*
+                        * If we are 'wandering', i.e. partition was an
+                        * EXTEND/EXTENDL, there is no spoofing to be done.
+                        * 
                         * Don't set fstype/offset/size when just looking for
                         * the offset of the OpenBSD partition. It would
                         * invalidate the disklabel checksum!
@@ -530,7 +530,7 @@ donot:
                         * Don't try to spoof more than 8 partitions, i.e.
                         * 'i' -'p'.
                         */
-                       if (partoffp || n >= 8)
+                       if (wander || partoffp || n >= 8)
                                continue;
 
                        pp = &lp->d_partitions[8+n];
@@ -542,13 +542,9 @@ donot:
                        DL_SETPSIZE(pp, letoh32(dp2->dp_size));
                }
        }
-       if (partoffp)
-               /* dospartoff has been set and we must not modify *lp. */
-               goto notfat;
 
-       lp->d_npartitions = MAXPARTITIONS;
-
-       if (n == 0 && part_blkno == DOSBBSECTOR) {
+       /* No MBR? Maybe it's a FAT. */
+       if (loop == 0 && part_blkno == DOSBBSECTOR) {
                u_int16_t fattest;
 
                /* Check for a valid initial jmp instruction. */
@@ -559,7 +555,7 @@ donot:
                         * of bytes to jmp and the 3rd byte must be a NOP.
                         */
                        if ((u_int8_t)bp->b_data[2] != 0x90)
-                               goto notfat;
+                               goto done;
                        break;
                case 0xe9:
                        /*
@@ -568,7 +564,7 @@ donot:
                         */
                        break;
                default:
-                       goto notfat;
+                       goto done;
                        break;
                }
 
@@ -576,22 +572,27 @@ donot:
                fattest = ((bp->b_data[12] << 8) & 0xff00) |
                    (bp->b_data[11] & 0xff);
                if (fattest < 512 || fattest > 4096 || (fattest % 512 != 0))
-                       goto notfat;
+                       goto done;
 
-               /* Looks like a FAT filesystem. Spoof 'i'. */
+               /* Looks like a FAT filesystem. Spoof 'i' and bail out. */
                DL_SETPSIZE(&lp->d_partitions['i' - 'a'],
                    DL_GETPSIZE(&lp->d_partitions[RAW_PART]));
                DL_SETPOFFSET(&lp->d_partitions['i' - 'a'], 0);
                lp->d_partitions['i' - 'a'].p_fstype = FS_MSDOS;
+               if (partoffp)
+                       return (ENXIO); /* FAT has no place for a disklabel! */
+               else
+                       return (0);
        }
-notfat:
+
+done:
        /* record the OpenBSD partition's placement for the caller */
        if (partoffp)
                *partoffp = dospartoff;
        else {
                DL_SETBSTART(lp, dospartoff);
-               DL_SETBEND(lp,
-                   dospartend < DL_GETDSIZE(lp) ? dospartend : 
DL_GETDSIZE(lp));
+               DL_SETBEND(lp, dospartend < DL_GETDSIZE(lp) ?
+                   dospartend : DL_GETDSIZE(lp));
        }
 
        /* don't read the on-disk label if we are in spoofed-only mode */

Reply via email to