On Fri, Feb 24, 2012 at 04:59:59PM +0200, Alexey Vatchenko wrote:
> On Wed, Feb 22, 2012 at 04:16:27PM -0500, Kenneth R Westerback wrote:
> > First very hacky attempt. Could easily destroy your data!
> >
> > .... Ken
> >
> >
> > Index: boot.c
> > ===================================================================
> > RCS file: /cvs/src/sbin/fsck_msdos/boot.c,v
> > retrieving revision 1.15
> > diff -u -p -r1.15 boot.c
> > --- boot.c 18 Dec 2010 04:57:34 -0000 1.15
> > +++ boot.c 22 Feb 2012 21:12:50 -0000
> > @@ -33,6 +33,9 @@
> > * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > */
>
> [skipped]
>
> >
> > - o = boot->Backup * boot->BytesPerSec;
> > - if ((o = lseek(dosfs, o, SEEK_SET)) == -1
> > - || o != boot->Backup * boot->BytesPerSec
> > - || (n = read(dosfs, backup, sizeof backup)) == -1
> > - || n != sizeof backup) {
> > + o = lseek(dosfs, boot->Backup * secsize, SEEK_SET);
> > + if (o == -1 || o != boot->Backup * secsize) {
> > + xperror("could not seek backup bootblock");
> > + return (FSFATAL);
> > + }
> > + n = read(dosfs, block, secsize);
> ^^^^^^^^^
> > + if (n == -1 || n != secsize) {
> > xperror("could not read backup bootblock");
> > return FSFATAL;
> > }
>
> You are reading backup boot block into `block` but later you are
> checking `backup` pointer. I put 'memcpy(backup, block, 512);' after
> 'read();' and... other things seem to work fine.
>
> So, put proper code there and i'm ready to test next patch :)
>
> Thanks!
Good point.
.... Ken
Index: boot.c
===================================================================
RCS file: /cvs/src/sbin/fsck_msdos/boot.c,v
retrieving revision 1.15
diff -u -p -r1.15 boot.c
--- boot.c 18 Dec 2010 04:57:34 -0000 1.15
+++ boot.c 24 Feb 2012 15:52:35 -0000
@@ -33,6 +33,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/param.h>
+#include <sys/disklabel.h>
+
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -44,21 +47,42 @@
int
readboot(int dosfs, struct bootblock *boot)
{
- u_char block[DOSBOOTBLOCKSIZE];
- u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
- u_char backup[DOSBOOTBLOCKSIZE];
- int ret = FSOK;
+ u_char *block;
+ u_char *fsinfo;
+ u_char *backup;
+ int ret = FSOK, secsize = lab.d_secsize, fsinfosz;
off_t o;
ssize_t n;
- if ((n = read(dosfs, block, sizeof block)) == -1 || n != sizeof block) {
+ if (secsize < DOSBOOTBLOCKSIZE) {
+ xperror("sector size < DOSBOOTBLOCKSIZE");
+ return (FSFATAL);
+ }
+ if (DOSBOOTBLOCKSIZE != DEV_BSIZE) {
+ xperror("DOSBOOTBLOCKSIZE != DEV_BSIZE");
+ return (FSFATAL);
+ }
+
+ block = malloc(2 * secsize);
+ if (block == NULL) {
+ xperror("could not malloc boot block");
+ return FSFATAL;
+ }
+
+ if ((o = lseek(dosfs, 0, SEEK_SET)) == -1) {
+ xperror("could not seek boot block");
+ return FSFATAL;
+ }
+
+ n = read(dosfs, block, secsize);
+ if (n == -1 || n != secsize) {
xperror("could not read boot block");
return (FSFATAL);
}
if (block[510] != 0x55 || block[511] != 0xaa) {
- pfatal("Invalid signature in boot block: %02x%02x\n",
block[511], block[510]);
- return FSFATAL;
+ pfatal("Invalid signature in boot block: %02x%02x\n",
+ block[511], block[510]);
}
memset(boot, 0, sizeof *boot);
@@ -66,7 +90,15 @@ readboot(int dosfs, struct bootblock *bo
/* decode bios parameter block */
boot->BytesPerSec = block[11] + (block[12] << 8);
+ if (boot->BytesPerSec == 0 || boot->BytesPerSec != secsize) {
+ pfatal("Invalid sector size: %u\n", boot->BytesPerSec);
+ return (FSFATAL);
+ }
boot->SecPerClust = block[13];
+ if (boot->SecPerClust == 0) {
+ pfatal("Invalid cluster size: %u\n", boot->SecPerClust);
+ return (FSFATAL);
+ }
boot->ResSectors = block[14] + (block[15] << 8);
boot->FATs = block[16];
boot->RootDirEnts = block[17] + (block[18] << 8);
@@ -100,14 +132,23 @@ readboot(int dosfs, struct bootblock *bo
boot->FSInfo = block[48] + (block[49] << 8);
boot->Backup = block[50] + (block[51] << 8);
- o = boot->FSInfo * boot->BytesPerSec;
- if ((o = lseek(dosfs, o, SEEK_SET)) == -1
- || o != boot->FSInfo * boot->BytesPerSec
- || (n = read(dosfs, fsinfo, sizeof fsinfo)) == -1
- || n != sizeof fsinfo) {
+ o = lseek(dosfs, boot->FSInfo * secsize, SEEK_SET);
+ if (o == -1 || o != boot->FSInfo * secsize) {
+ xperror("could not seek fsinfo block");
+ return FSFATAL;
+ }
+
+ if ((2 * DOSBOOTBLOCKSIZE) < secsize)
+ fsinfosz = secsize;
+ else
+ fsinfosz = 2 * secsize;
+ n = read(dosfs, block, fsinfosz);
+ if (n == -1 || n != fsinfosz) {
xperror("could not read fsinfo block");
return FSFATAL;
}
+ fsinfo = block;
+
if (memcmp(fsinfo, "RRaA", 4)
|| memcmp(fsinfo + 0x1e4, "rrAa", 4)
|| fsinfo[0x1fc]
@@ -129,11 +170,14 @@ readboot(int dosfs, struct bootblock *bo
fsinfo[0x3fe] = 0x55;
fsinfo[0x3ff] = 0xaa;
- o = boot->FSInfo * boot->BytesPerSec;
- if ((o = lseek(dosfs, o, SEEK_SET)) == -1
- || o != boot->FSInfo * boot->BytesPerSec
- || (n = write(dosfs, fsinfo, sizeof
fsinfo)) == -1
- || n != sizeof fsinfo) {
+ o = lseek(dosfs, boot->FSInfo * secsize,
+ SEEK_SET);
+ if (o == -1 || o != boot->FSInfo * secsize) {
+ xperror("Unable to seek FSInfo");
+ return FSFATAL;
+ }
+ n = write(dosfs, block, fsinfosz);
+ if (n == -1 || n != fsinfosz) {
xperror("Unable to write FSInfo");
return FSFATAL;
}
@@ -150,11 +194,18 @@ readboot(int dosfs, struct bootblock *bo
+ (fsinfo[0x1ef] << 24);
}
- o = boot->Backup * boot->BytesPerSec;
- if ((o = lseek(dosfs, o, SEEK_SET)) == -1
- || o != boot->Backup * boot->BytesPerSec
- || (n = read(dosfs, backup, sizeof backup)) == -1
- || n != sizeof backup) {
+ o = lseek(dosfs, boot->Backup * secsize, SEEK_SET);
+ if (o == -1 || o != boot->Backup * secsize) {
+ xperror("could not seek backup bootblock");
+ return (FSFATAL);
+ }
+ backup = malloc(2 * secsize); /* In case we check fsinfo. */
+ if (backup == NULL) {
+ xperror("could not malloc backup boot block");
+ return FSFATAL;
+ }
+ n = read(dosfs, backup, secsize);
+ if (n == -1 || n != secsize) {
xperror("could not read backup bootblock");
return FSFATAL;
}
@@ -172,7 +223,6 @@ readboot(int dosfs, struct bootblock *bo
*/
if (backup[510] != 0x55 || backup[511] != 0xaa) {
pfatal("Invalid signature in backup boot block:
%02x%02x\n", backup[511], backup[510]);
- return FSFATAL;
}
if (memcmp(block + 11, backup + 11, 79)) {
pfatal("backup doesn't compare to primary bootblock\n");
@@ -181,18 +231,8 @@ readboot(int dosfs, struct bootblock *bo
/* Check backup FSInfo? XXX */
}
- if (boot->BytesPerSec == 0 || boot->BytesPerSec % DOSBOOTBLOCKSIZE
- != 0) {
- pfatal("Invalid sector size: %u\n", boot->BytesPerSec);
- return (FSFATAL);
- }
- if (boot->SecPerClust == 0) {
- pfatal("Invalid cluster size: %u\n", boot->SecPerClust);
- return (FSFATAL);
- }
-
- boot->ClusterOffset = (boot->RootDirEnts * 32 + boot->BytesPerSec - 1)
- / boot->BytesPerSec
+ boot->ClusterOffset = (boot->RootDirEnts * 32 + secsize - 1)
+ / secsize
+ boot->ResSectors
+ boot->FATs * boot->FATsecs
- CLUST_FIRST * boot->SecPerClust;
@@ -218,13 +258,13 @@ readboot(int dosfs, struct bootblock *bo
switch (boot->ClustMask) {
case CLUST32_MASK:
- boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 4;
+ boot->NumFatEntries = (boot->FATsecs * secsize) / 4;
break;
case CLUST16_MASK:
- boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 2;
+ boot->NumFatEntries = (boot->FATsecs * secsize) / 2;
break;
default:
- boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec * 2) /
3;
+ boot->NumFatEntries = (boot->FATsecs * secsize * 2) / 3;
break;
}
@@ -233,7 +273,7 @@ readboot(int dosfs, struct bootblock *bo
boot->NumClusters, boot->FATsecs);
return (FSFATAL);
}
- boot->ClusterSize = boot->BytesPerSec * boot->SecPerClust;
+ boot->ClusterSize = boot->SecPerClust * secsize;
boot->NumFiles = 1;
boot->NumFree = 0;
@@ -244,18 +284,34 @@ readboot(int dosfs, struct bootblock *bo
int
writefsinfo(int dosfs, struct bootblock *boot)
{
- u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
+ u_char *fsinfo;
+ int secsize = lab.d_secsize, fsinfosz;
off_t o;
ssize_t n;
- o = boot->FSInfo * boot->BytesPerSec;
- if ((o = lseek(dosfs, o, SEEK_SET)) == -1
- || o != boot->FSInfo * boot->BytesPerSec
- || (n = read(dosfs, fsinfo, sizeof fsinfo)) == -1
- || n != sizeof fsinfo) {
+ if ((2 * DOSBOOTBLOCKSIZE) < secsize)
+ fsinfosz = secsize;
+ else
+ fsinfosz = 2 * secsize;
+
+ fsinfo = malloc(fsinfosz);
+ if (fsinfo == NULL) {
+ xperror("could not malloc fsinfo block");
+ return FSFATAL;
+ }
+
+ o = lseek(dosfs, boot->FSInfo * secsize, SEEK_SET);
+ if (o == -1 || o != boot->FSInfo * secsize) {
+ xperror("could not seek fsinfo block");
+ return FSFATAL;
+ }
+
+ n = read(dosfs, fsinfo, fsinfosz);
+ if (n == -1 || n != fsinfosz) {
xperror("could not read fsinfo block");
return FSFATAL;
}
+
fsinfo[0x1e8] = (u_char)boot->FSFree;
fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8);
fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16);
@@ -265,14 +321,17 @@ writefsinfo(int dosfs, struct bootblock
fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
- o = boot->FSInfo * boot->BytesPerSec;
- if ((o = lseek(dosfs, o, SEEK_SET)) == -1
- || o != boot->FSInfo * boot->BytesPerSec
- || (n = write(dosfs, fsinfo, sizeof fsinfo)) == -1
- || n != sizeof fsinfo) {
+ o = lseek(dosfs, o, SEEK_SET);
+ if (o == -1 || o != boot->FSInfo * boot->BytesPerSec) {
+ xperror("Unable to seek FSInfo");
+ return FSFATAL;
+ }
+ n = write(dosfs, fsinfo, fsinfosz);
+ if (n == -1 || n != fsinfosz) {
xperror("Unable to write FSInfo");
return FSFATAL;
}
+
/*
* Technically, we should return FSBOOTMOD here.
*
Index: check.c
===================================================================
RCS file: /cvs/src/sbin/fsck_msdos/check.c,v
retrieving revision 1.14
diff -u -p -r1.14 check.c
--- check.c 17 Dec 2010 19:36:03 -0000 1.14
+++ check.c 24 Feb 2012 15:52:35 -0000
@@ -34,6 +34,9 @@
*/
#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/dkio.h>
+#include <sys/disklabel.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -44,6 +47,8 @@
#include "ext.h"
+struct disklabel lab;
+
int
checkfilesys(const char *fname)
{
@@ -74,6 +79,9 @@ checkfilesys(const char *fname)
printf(" (NO WRITE)");
printf("\n");
}
+
+ if (ioctl(dosfs, DIOCGDINFO, (char *)&lab) < 0)
+ pfatal("can't read disk label for %s\n", fname);
if (readboot(dosfs, &boot) != FSOK) {
(void)close(dosfs);
Index: ext.h
===================================================================
RCS file: /cvs/src/sbin/fsck_msdos/ext.h,v
retrieving revision 1.9
diff -u -p -r1.9 ext.h
--- ext.h 7 Feb 2008 01:34:12 -0000 1.9
+++ ext.h 24 Feb 2012 15:52:35 -0000
@@ -51,7 +51,7 @@ extern int alwaysyes; /* assume "yes" fo
extern int preen; /* we are preening */
extern int rdonly; /* device is opened read only (supersedes above) */
-extern char *fname; /* filesystem currently checked */
+extern struct disklabel lab;
extern struct dosDirEntry *rootDir;
Index: main.c
===================================================================
RCS file: /cvs/src/sbin/fsck_msdos/main.c,v
retrieving revision 1.17
diff -u -p -r1.17 main.c
--- main.c 12 Aug 2010 15:26:34 -0000 1.17
+++ main.c 24 Feb 2012 15:52:35 -0000
@@ -98,7 +98,7 @@ main(int argc, char *argv[])
while (argc-- > 0) {
setcdevname(*argv, NULL, preen);
- erg = checkfilesys(*argv++);
+ erg = checkfilesys(blockcheck(*argv++));
if (erg > ret)
ret = erg;
}