summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>1998-01-11 20:40:35 +0000
committerNiels Provos <provos@cvs.openbsd.org>1998-01-11 20:40:35 +0000
commit28d8359f8470d4f9956b9ce108964c4b005dfd35 (patch)
tree66ccf2c8983772a096f4bb3ea0c39f6ab261f4e5
parent487fe4efe824e828cdefbee41c1d03ef04a885f3 (diff)
FAT32 support from NetBSD by Wolfgang Solfrank.
-rw-r--r--sbin/fsck_msdos/boot.c184
-rw-r--r--sbin/fsck_msdos/check.c78
-rw-r--r--sbin/fsck_msdos/dir.c175
-rw-r--r--sbin/fsck_msdos/dosfs.h48
-rw-r--r--sbin/fsck_msdos/ext.h27
-rw-r--r--sbin/fsck_msdos/fat.c231
-rw-r--r--sbin/fsck_msdos/fsck_msdos.84
7 files changed, 538 insertions, 209 deletions
diff --git a/sbin/fsck_msdos/boot.c b/sbin/fsck_msdos/boot.c
index 191388c60ac..b160fbfea39 100644
--- a/sbin/fsck_msdos/boot.c
+++ b/sbin/fsck_msdos/boot.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: boot.c,v 1.3 1997/03/02 05:25:51 millert Exp $ */
-/* $NetBSD: boot.c,v 1.3 1996/09/27 23:22:51 christos Exp $ */
+/* $OpenBSD: boot.c,v 1.4 1998/01/11 20:40:28 provos Exp $ */
+/* $NetBSD: boot.c,v 1.5 1997/10/17 11:19:23 ws Exp $ */
/*
- * Copyright (C) 1995 Wolfgang Solfrank
+ * Copyright (C) 1995, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
#ifndef lint
-static char rcsid[] = "$OpenBSD: boot.c,v 1.3 1997/03/02 05:25:51 millert Exp $";
+static char rcsid[] = "$OpenBSD: boot.c,v 1.4 1998/01/11 20:40:28 provos Exp $";
#endif /* not lint */
#include <stdlib.h>
@@ -52,16 +52,23 @@ readboot(dosfs, boot)
struct bootblock *boot;
{
u_char block[DOSBOOTBLOCKSIZE];
- int n;
-
- if ((n = read(dosfs, block, sizeof block)) < (int)sizeof block) {
- if (n < 0)
- perror("could not read boot block");
- else
- pfatal("Short bootblock?");
+ u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
+ u_char backup[DOSBOOTBLOCKSIZE];
+ int ret = FSOK;
+
+ if (read(dosfs, block, sizeof block) < sizeof block) {
+ perror("could not read boot block");
return (FSFATAL);
}
+ if (block[510] != 0x55 || block[511] != 0xaa) {
+ pfatal("Invalid signature in boot block: %02x%02x", block[511], block[510]);
+ return FSFATAL;
+ }
+
+ memset(boot, 0, sizeof *boot);
+ boot->ValidFat = -1;
+
/* decode bios parameter block */
boot->BytesPerSec = block[11] + (block[12] << 8);
boot->SecPerClust = block[13];
@@ -70,11 +77,95 @@ readboot(dosfs, boot)
boot->RootDirEnts = block[17] + (block[18] << 8);
boot->Sectors = block[19] + (block[20] << 8);
boot->Media = block[21];
- boot->FATsecs = block[22] + (block[23] << 8);
+ boot->FATsmall = block[22] + (block[23] << 8);
boot->SecPerTrack = block[24] + (block[25] << 8);
boot->Heads = block[26] + (block[27] << 8);
boot->HiddenSecs = block[28] + (block[29] << 8) + (block[30] << 16) + (block[31] << 24);
boot->HugeSectors = block[32] + (block[33] << 8) + (block[34] << 16) + (block[35] << 24);
+
+ boot->FATsecs = boot->FATsmall;
+
+ if (!boot->RootDirEnts)
+ boot->flags |= FAT32;
+ if (boot->flags & FAT32) {
+ boot->FATsecs = block[36] + (block[37] << 8)
+ + (block[38] << 16) + (block[39] << 24);
+ if (block[40] & 0x80)
+ boot->ValidFat = block[40] & 0x0f;
+
+ /* check version number: */
+ if (block[42] || block[43]) {
+ /* Correct? XXX */
+ pfatal("Unknown filesystem version: %x.%x",
+ block[43], block[42]);
+ return FSFATAL;
+ }
+ boot->RootCl = block[44] + (block[45] << 8)
+ + (block[46] << 16) + (block[47] << 24);
+ boot->FSInfo = block[48] + (block[49] << 8);
+ boot->Backup = block[50] + (block[51] << 8);
+
+ if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
+ != boot->FSInfo * boot->BytesPerSec
+ || read(dosfs, fsinfo, sizeof fsinfo)
+ != sizeof fsinfo) {
+ perror("could not read fsinfo block");
+ return FSFATAL;
+ }
+ if (memcmp(fsinfo, "RRaA", 4)
+ || memcmp(fsinfo + 0x1e4, "rrAa", 4)
+ || fsinfo[0x1fc]
+ || fsinfo[0x1fd]
+ || fsinfo[0x1fe] != 0x55
+ || fsinfo[0x1ff] != 0xaa
+ || fsinfo[0x3fc]
+ || fsinfo[0x3fd]
+ || fsinfo[0x3fe] != 0x55
+ || fsinfo[0x3ff] != 0xaa) {
+ pwarn("Invalid signature in fsinfo block");
+ if (ask(0, "fix")) {
+ memcpy(fsinfo, "RRaA", 4);
+ memcpy(fsinfo + 0x1e4, "rrAa", 4);
+ fsinfo[0x1fc] = fsinfo[0x1fd] = 0;
+ fsinfo[0x1fe] = 0x55;
+ fsinfo[0x1ff] = 0xaa;
+ fsinfo[0x3fc] = fsinfo[0x3fd] = 0;
+ fsinfo[0x3fe] = 0x55;
+ fsinfo[0x3ff] = 0xaa;
+ if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
+ != boot->FSInfo * boot->BytesPerSec
+ || write(dosfs, fsinfo, sizeof fsinfo)
+ != sizeof fsinfo) {
+ perror("Unable to write FSInfo");
+ return FSFATAL;
+ }
+ ret = FSBOOTMOD;
+ } else
+ boot->FSInfo = 0;
+ }
+ if (boot->FSInfo) {
+ boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
+ + (fsinfo[0x1ea] << 16)
+ + (fsinfo[0x1eb] << 24);
+ boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8)
+ + (fsinfo[0x1ee] << 16)
+ + (fsinfo[0x1ef] << 24);
+ }
+
+ if (lseek(dosfs, boot->Backup * boot->BytesPerSec, SEEK_SET)
+ != boot->Backup * boot->BytesPerSec
+ || read(dosfs, backup, sizeof backup) != sizeof backup) {
+ perror("could not read backup bootblock");
+ return FSFATAL;
+ }
+ if (memcmp(block, backup, DOSBOOTBLOCKSIZE)) {
+ /* Correct? XXX */
+ pfatal("backup doesn't compare to primary bootblock");
+ return FSFATAL;
+ }
+ /* Check backup FSInfo? XXX */
+ }
+
boot->ClusterOffset = (boot->RootDirEnts * 32 + boot->BytesPerSec - 1)
/ boot->BytesPerSec
+ boot->ResSectors
@@ -82,11 +173,11 @@ readboot(dosfs, boot)
- CLUST_FIRST * boot->SecPerClust;
if (boot->BytesPerSec % DOSBOOTBLOCKSIZE != 0) {
- pfatal("Invalid sector size: %u\n", boot->BytesPerSec);
+ pfatal("Invalid sector size: %u", boot->BytesPerSec);
return (FSFATAL);
}
if (boot->SecPerClust == 0) {
- pfatal("Invalid cluster size: %u\n", boot->SecPerClust);
+ pfatal("Invalid cluster size: %u", boot->SecPerClust);
return (FSFATAL);
}
if (boot->Sectors) {
@@ -95,17 +186,33 @@ readboot(dosfs, boot)
} else
boot->NumSectors = boot->HugeSectors;
boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust;
- if (boot->NumClusters >= MAX12BITCLUSTERS)
- boot->Is16BitFat = 1;
- else
- boot->Is16BitFat = 0;
- if (boot->Is16BitFat)
+ if (boot->flags&FAT32)
+ boot->ClustMask = CLUST32_MASK;
+ else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK))
+ boot->ClustMask = CLUST12_MASK;
+ else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK))
+ boot->ClustMask = CLUST16_MASK;
+ else {
+ pfatal("Filesystem too big (%u clusters) for non-FAT32 partition",
+ boot->NumClusters);
+ return FSFATAL;
+ }
+
+ switch (boot->ClustMask) {
+ case CLUST32_MASK:
+ boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 4;
+ break;
+ case CLUST16_MASK:
boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 2;
- else
+ break;
+ default:
boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec * 2) / 3;
+ break;
+ }
+
if (boot->NumFatEntries < boot->NumClusters) {
- pfatal("FAT size too small, %d entries won't fit into %u sectors\n",
+ pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
boot->NumClusters, boot->FATsecs);
return (FSFATAL);
}
@@ -113,6 +220,37 @@ readboot(dosfs, boot)
boot->NumFiles = 1;
boot->NumFree = 0;
-
- return (FSOK);
+
+ return ret;
+}
+
+int
+writefsinfo(dosfs, boot)
+ int dosfs;
+ struct bootblock *boot;
+{
+ u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
+
+ if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
+ != boot->FSInfo * boot->BytesPerSec
+ || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
+ perror("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);
+ fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24);
+ fsinfo[0x1ec] = (u_char)boot->FSNext;
+ fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8);
+ fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
+ fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
+ if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
+ != boot->FSInfo * boot->BytesPerSec
+ || write(dosfs, fsinfo, sizeof fsinfo)
+ != sizeof fsinfo) {
+ perror("Unable to write FSInfo");
+ return FSFATAL;
+ }
+ return FSBOOTMOD;
}
diff --git a/sbin/fsck_msdos/check.c b/sbin/fsck_msdos/check.c
index 2403c3fa3ae..0c8522add02 100644
--- a/sbin/fsck_msdos/check.c
+++ b/sbin/fsck_msdos/check.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: check.c,v 1.5 1997/03/02 05:25:52 millert Exp $ */
-/* $NetBSD: check.c,v 1.6 1997/01/03 14:32:48 ws Exp $ */
+/* $OpenBSD: check.c,v 1.6 1998/01/11 20:40:30 provos Exp $ */
+/* $NetBSD: check.c,v 1.8 1997/10/17 11:19:29 ws Exp $ */
/*
- * Copyright (C) 1995, 1996 Wolfgang Solfrank
+ * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
#ifndef lint
-static char rcsid[] = "$OpenBSD: check.c,v 1.5 1997/03/02 05:25:52 millert Exp $";
+static char rcsid[] = "$OpenBSD: check.c,v 1.6 1998/01/11 20:40:30 provos Exp $";
#endif /* not lint */
#include <stdlib.h>
@@ -53,7 +53,7 @@ checkfilesys(fname)
{
int dosfs;
struct bootblock boot;
- struct fatEntry * fat = NULL;
+ struct fatEntry *fat = NULL;
int i;
int mod = 0;
@@ -71,7 +71,7 @@ checkfilesys(fname)
rdonly = 1;
} else if (!preen)
printf("\n");
-
+
if (dosfs < 0) {
perror("Can't open");
return (8);
@@ -83,24 +83,29 @@ checkfilesys(fname)
}
if (!preen)
- printf("** Phase 1 - Read and Compare FATs\n");
-
- for (i = 0; i < boot.FATs; i++) {
- struct fatEntry *currentFat;
+ if (boot.ValidFat < 0)
+ printf("** Phase 1 - Read and Compare FATs\n");
+ else
+ printf("** Phase 1 - Read FAT\n");
- mod |= readfat(dosfs, &boot, i, &currentFat);
+ mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat);
+ if (mod & FSFATAL) {
+ (void)close(dosfs);
+ return 8;
+ }
+
+ if (boot.ValidFat < 0)
+ for (i = 1; i < boot.FATs; i++) {
+ struct fatEntry *currentFat;
+ mod |= readfat(dosfs, &boot, i, &currentFat);
- if (mod & FSFATAL) {
- if (fat)
+ if (mod & FSFATAL) {
free(fat);
- (void)close(dosfs);
- return (8);
- }
-
- if (fat == NULL)
- fat = currentFat;
- else {
- mod |= comparefat(&boot, fat, currentFat, i + 1);
+ (void)close(dosfs);
+ return 8;
+ }
+
+ mod |= comparefat(&boot, fat, currentFat, i);
free(currentFat);
if (mod & FSFATAL) {
free(fat);
@@ -108,18 +113,17 @@ checkfilesys(fname)
return (8);
}
}
- }
if (!preen)
printf("** Phase 2 - Check Cluster Chains\n");
-
+
mod |= checkfat(&boot, fat);
if (mod & FSFATAL) {
free(fat);
(void)close(dosfs);
return (8);
}
-
+
if (mod & FSFATMOD)
mod |= writefat(dosfs, &boot, fat); /* delay writing fats? XXX */
if (mod & FSFATAL) {
@@ -131,7 +135,17 @@ checkfilesys(fname)
if (!preen)
printf("** Phase 3 - Checking Directories\n");
- if (resetDosDirSection(&boot) & FSFATAL) {
+ mod |= resetDosDirSection(&boot, fat);
+ if (mod & FSFATAL) {
+ free(fat);
+ close(dosfs);
+ return 8;
+ }
+
+ if (mod & FSFATMOD)
+ mod |= writefat(dosfs, &boot, fat); /* delay writing fats? XXX */
+ if (mod & FSFATAL) {
+ finishDosDirSection();
free(fat);
(void)close(dosfs);
return (8);
@@ -149,10 +163,21 @@ checkfilesys(fname)
printf("** Phase 4 - Checking for Lost Files\n");
mod |= checklost(dosfs, &boot, fat);
-
+ if (mod & FSFATAL) {
+ finishDosDirSection();
+ free(fat);
+ (void)close(dosfs);
+ return 8;
+ }
+
+ if (mod & FSFATMOD)
+ mod |= writefat(dosfs, &boot, fat); /* delay writing fats? XXX */
+
finishDosDirSection();
free(fat);
(void)close(dosfs);
+ if (mod & FSFATAL)
+ return 8;
if (boot.NumBad)
pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n",
@@ -163,6 +188,7 @@ checkfilesys(fname)
pwarn("%d files, %d free (%d clusters)\n",
boot.NumFiles,
boot.NumFree * boot.ClusterSize / 1024, boot.NumFree);
+
if (mod & (FSFATAL | FSERROR))
return (8);
if (mod) {
diff --git a/sbin/fsck_msdos/dir.c b/sbin/fsck_msdos/dir.c
index 46f70a2dfd6..5491f510290 100644
--- a/sbin/fsck_msdos/dir.c
+++ b/sbin/fsck_msdos/dir.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: dir.c,v 1.8 1997/09/11 08:15:24 deraadt Exp $ */
-/* NetBSD: dir.c,v 1.9 1997/09/08 14:05:30 ws Exp $ */
+/* $OpenBSD: dir.c,v 1.9 1998/01/11 20:40:31 provos Exp $ */
+/* $NetBSD: dir.c,v 1.11 1997/10/17 11:19:35 ws Exp $ */
/*
- * Copyright (C) 1995, 1996 Wolfgang Solfrank
+ * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
- * Some structure declaration borrowed from Paul Popelka
+ * Some structure declaration borrowed from Paul Popelka
* (paulp@uts.amdahl.com), see /sys/msdosfs/ for reference.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,7 @@
#ifndef lint
-static char rcsid[] = "$OpenBSD: dir.c,v 1.8 1997/09/11 08:15:24 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: dir.c,v 1.9 1998/01/11 20:40:31 provos Exp $";
#endif /* not lint */
#include <stdio.h>
@@ -115,7 +115,7 @@ static struct dosDirEntry *
newDosDirEntry()
{
struct dosDirEntry *de;
-
+
if (!(de = freede)) {
if (!(de = (struct dosDirEntry *)malloc(sizeof *de)))
return (0);
@@ -141,7 +141,7 @@ static struct dirTodoNode *
newDirTodo()
{
struct dirTodoNode *dt;
-
+
if (!(dt = freedt)) {
if (!(dt = (struct dirTodoNode *)malloc(sizeof *dt)))
return (0);
@@ -173,7 +173,7 @@ fullpath(dir)
static char namebuf[MAXPATHLEN + 1];
char *cp, *np;
int nl;
-
+
cp = namebuf + sizeof namebuf - 1;
*cp = '\0';
do {
@@ -223,14 +223,17 @@ static struct dosDirEntry *lostDir;
* Init internal state for a new directory scan.
*/
int
-resetDosDirSection(boot)
+resetDosDirSection(boot, fat)
struct bootblock *boot;
+ struct fatEntry *fat;
{
int b1, b2;
-
+ cl_t cl;
+ int ret = FSOK;
+
b1 = boot->RootDirEnts * 32;
b2 = boot->SecPerClust * boot->BytesPerSec;
-
+
if (!(buffer = malloc(b1 > b2 ? b1 : b2))
|| !(delbuf = malloc(b2))
|| !(rootDir = newDosDirEntry())) {
@@ -238,7 +241,37 @@ resetDosDirSection(boot)
return (FSFATAL);
}
(void)memset(rootDir, 0, sizeof *rootDir);
- return (FSOK);
+ if (boot->flags & FAT32) {
+ if (boot->RootCl < CLUST_FIRST || boot->RootCl >= boot->NumClusters) {
+ pfatal("Root directory starts with cluster out of range(%u)",
+ boot->RootCl);
+ return (FSFATAL);
+ }
+ cl = fat[boot->RootCl].next;
+ if (cl < CLUST_FIRST
+ || (cl >= CLUST_RSRVD && cl< CLUST_EOFS)
+ || fat[boot->RootCl].head != boot->RootCl) {
+ if (cl == CLUST_FREE)
+ pwarn("Root directory starts with free cluster\n");
+ else if (cl >= CLUST_RSRVD)
+ pwarn("Root directory starts with cluster marked %s\n",
+ rsrvdcltype(cl));
+ else {
+ pfatal("Root directory doesn't start a cluster chain");
+ return (FSFATAL);
+ }
+ if (ask(1, "Fix")) {
+ fat[boot->RootCl].next = CLUST_FREE;
+ ret = FSFATMOD;
+ } else
+ ret = FSFATAL;
+ }
+
+ fat[boot->RootCl].flags |= FAT_USED;
+ rootDir->head = boot->RootCl;
+ }
+
+ return (ret);
}
/*
@@ -249,7 +282,7 @@ finishDosDirSection()
{
struct dirTodoNode *p, *np;
struct dosDirEntry *d, *nd;
-
+
for (p = pendingDirectories; p; p = np) {
np = p->next;
freeDirTodo(p);
@@ -288,7 +321,7 @@ delete(f, boot, fat, startcl, startoff, endcl, endoff, notlast)
u_char *s, *e;
off_t off;
int clsz = boot->SecPerClust * boot->BytesPerSec;
-
+
s = delbuf + startoff;
e = delbuf + clsz;
while (startcl >= CLUST_FIRST && startcl < boot->NumClusters) {
@@ -361,7 +394,7 @@ removede(f, boot, fat, start, end, startcl, endcl, curcl, path, type)
}
return (FSERROR);
}
-
+
/*
* Check an in-memory file entry
*/
@@ -402,7 +435,7 @@ checksize(boot, fat, p, dir)
if (ask(1, "Drop superfluous clusters")) {
cl_t cl;
u_int32_t sz = 0;
-
+
for (cl = dir->head; (sz += boot->ClusterSize) < dir->size;)
cl = fat[cl].next;
clearchain(boot, fat, fat[cl].next);
@@ -448,14 +481,14 @@ readDosDirSection(f, boot, fat, dir)
shortSum = -1;
vallfn = invlfn = empty = NULL;
do {
- if (!dir->parent) {
+ if (!(boot->flags & FAT32) && !dir->parent) {
last = boot->RootDirEnts * 32;
off = boot->ResSectors + boot->FATs * boot->FATsecs;
} else {
last = boot->SecPerClust * boot->BytesPerSec;
off = cl * boot->SecPerClust + boot->ClusterOffset;
}
-
+
off *= boot->BytesPerSec;
if (lseek(f, off, SEEK_SET) != off
|| read(f, buffer, last) != last) {
@@ -471,7 +504,7 @@ readDosDirSection(f, boot, fat, dir)
*p = SLOT_EMPTY;
continue;
}
-
+
if (*p == SLOT_EMPTY || *p == SLOT_DELETED) {
if (*p == SLOT_EMPTY) {
dir->fsckflags |= DIREMPTY;
@@ -480,7 +513,7 @@ readDosDirSection(f, boot, fat, dir)
}
continue;
}
-
+
if (dir->fsckflags & DIREMPTY) {
if (!(dir->fsckflags & DIREMPWARN)) {
pwarn("%s has entries after end of directory\n",
@@ -508,7 +541,7 @@ readDosDirSection(f, boot, fat, dir)
mod |= FSERROR;
empty = NULL;
}
-
+
if (p[11] == ATTR_WIN95) {
if (*p & LRFIRST) {
if (shortSum != -1) {
@@ -585,13 +618,13 @@ readDosDirSection(f, boot, fat, dir)
* This is a standard msdosfs directory entry.
*/
(void)memset(&dirent, 0, sizeof dirent);
-
+
/*
* it's a short name record, but we need to know
* more, so get the flags first.
*/
dirent.flags = p[11];
-
+
/*
* Translate from 850 to ISO here XXX
*/
@@ -624,7 +657,7 @@ readDosDirSection(f, boot, fat, dir)
dirent.name[k] = '\0';
for (k--; k >= 0 && dirent.name[k] == ' '; k--)
dirent.name[k] = '\0';
-
+
if (vallfn && shortSum != calcShortSum(p)) {
if (!invlfn) {
invlfn = vallfn;
@@ -633,6 +666,8 @@ readDosDirSection(f, boot, fat, dir)
vallfn = NULL;
}
dirent.head = p[26] | (p[27] << 8);
+ if (boot->ClustMask == CLUST32_MASK)
+ dirent.head |= (p[20] << 16) | (p[21] << 24);
dirent.size = p[28] | (p[29] << 8) | (p[30] << 16) | (p[31] << 24);
if (vallfn) {
strcpy(dirent.lname, longName);
@@ -640,6 +675,9 @@ readDosDirSection(f, boot, fat, dir)
shortSum = -1;
}
+ dirent.parent = dir;
+ dirent.next = dir->child;
+
if (invlfn) {
mod |= k = removede(f, boot, fat,
invlfn, vallfn ? vallfn : p,
@@ -653,10 +691,9 @@ readDosDirSection(f, boot, fat, dir)
if (k & FSDIRMOD)
mod |= THISMOD;
}
+
vallfn = NULL; /* not used any longer */
invlfn = NULL;
- dirent.parent = dir;
- dirent.next = dir->child;
if (dirent.size == 0 && !(dirent.flags & ATTR_DIRECTORY)) {
if (dirent.head != 0) {
@@ -664,6 +701,8 @@ readDosDirSection(f, boot, fat, dir)
fullpath(&dirent));
if (ask(1, "Drop allocated clusters")) {
p[26] = p[27] = 0;
+ if (boot->ClustMask == CLUST32_MASK)
+ p[20] = p[21] = 0;
clearchain(boot, fat, dirent.head);
dirent.head = 0;
mod |= THISMOD|FSDIRMOD|FSFATMOD;
@@ -688,14 +727,14 @@ readDosDirSection(f, boot, fat, dir)
fullpath(&dirent));
else if (dirent.head < CLUST_FIRST
|| dirent.head >= boot->NumClusters)
- pwarn("%s starts with cluster out of range(%d)\n",
+ pwarn("%s starts with cluster out of range(%u)\n",
fullpath(&dirent),
dirent.head);
else if (fat[dirent.head].next == CLUST_FREE)
pwarn("%s starts with free cluster\n",
fullpath(&dirent));
else if (fat[dirent.head].next >= CLUST_RSRVD)
- pwarn("%s starts with %s cluster\n",
+ pwarn("%s starts with cluster marked %s\n",
fullpath(&dirent),
rsrvdcltype(fat[dirent.head].next));
else
@@ -711,22 +750,25 @@ readDosDirSection(f, boot, fat, dir)
} else {
if (ask(1, "Truncate")) {
p[28] = p[29] = p[30] = p[31] = 0;
+ p[26] = p[27] = 0;
+ if (boot->ClustMask == CLUST32_MASK)
+ p[20] = p[21] = 0;
dirent.size = 0;
mod |= THISMOD|FSDIRMOD;
} else
mod |= FSERROR;
}
}
-
+
if (dirent.head >= CLUST_FIRST && dirent.head < boot->NumClusters)
fat[dirent.head].flags |= FAT_USED;
-
+
if (dirent.flags & ATTR_DIRECTORY) {
/*
* gather more info for directories
*/
- struct dirTodoNode * n;
-
+ struct dirTodoNode *n;
+
if (dirent.size) {
pwarn("Directory %s has size != 0\n",
fullpath(&dirent));
@@ -748,6 +790,10 @@ readDosDirSection(f, boot, fat, dir)
dirent.head = dir->head;
p[26] = (u_char)dirent.head;
p[27] = (u_char)(dirent.head >> 8);
+ if (boot->ClustMask == CLUST32_MASK) {
+ p[20] = (u_char)(dirent.head >> 16);
+ p[21] = (u_char)(dirent.head >> 24);
+ }
mod |= THISMOD|FSDIRMOD;
} else
mod |= FSERROR;
@@ -755,21 +801,38 @@ readDosDirSection(f, boot, fat, dir)
continue;
}
if (strcmp(dirent.name, "..") == 0) {
- if (dir->parent /* XXX */
- && dirent.head != dir->parent->head) {
- pwarn("`..' entry in %s has incorrect start cluster\n",
- fullpath(dir));
- if (ask(1, "Correct")) {
- dirent.head = dir->parent->head;
- p[26] = (u_char)dirent.head;
- p[27] = (u_char)(dirent.head >> 8);
- mod |= THISMOD|FSDIRMOD;
- } else
- mod |= FSERROR;
- }
+ if (dir->parent) /* XXX */
+ if (!dir->parent->parent) {
+ if (dirent.head) {
+ pwarn("`..' entry in %s has non-zero start cluster\n",
+ fullpath(dir));
+ if (ask(1, "Correct")) {
+ dirent.head = 0;
+ p[26] = p[27] = 0;
+ if (boot->ClustMask == CLUST32_MASK)
+ p[20] = p[21] = 0;
+ mod |= THISMOD|FSDIRMOD;
+ } else
+ mod |= FSERROR;
+ }
+ } else if (dirent.head != dir->parent->head) {
+ pwarn("`..' entry in %s has incorrect start cluster\n",
+ fullpath(dir));
+ if (ask(1, "Correct")) {
+ dirent.head = dir->parent->head;
+ p[26] = (u_char)dirent.head;
+ p[27] = (u_char)(dirent.head >> 8);
+ if (boot->ClustMask == CLUST32_MASK) {
+ p[20] = (u_char)(dirent.head >> 16);
+ p[21] = (u_char)(dirent.head >> 24);
+ }
+ mod |= THISMOD|FSDIRMOD;
+ } else
+ mod |= FSERROR;
+ }
continue;
}
-
+
/* create directory tree node */
if (!(d = newDosDirEntry())) {
perror("No space for directory");
@@ -778,7 +841,7 @@ readDosDirSection(f, boot, fat, dir)
(void)memcpy(d, &dirent, sizeof(struct dosDirEntry));
/* link it into the tree */
dir->child = d;
-
+
/* Enter this directory into the todo list */
if (!(n = newDirTodo())) {
perror("No space for todo list");
@@ -823,7 +886,7 @@ handleDirTree(dosfs, boot, fat)
mod = readDosDirSection(dosfs, boot, fat, rootDir);
if (mod & FSFATAL)
return (FSFATAL);
-
+
if (mod & FSFATMOD) {
mod &= ~FSFATMOD;
mod |= writefat(dosfs, boot, fat); /* delay writing fats? XXX */
@@ -831,7 +894,7 @@ handleDirTree(dosfs, boot, fat)
if (mod & FSFATAL)
return (FSFATAL);
-
+
/*
* process the directory todo list
*/
@@ -878,7 +941,10 @@ reconnect(dosfs, boot, fat, head)
{
struct dosDirEntry d;
u_char *p;
-
+
+ if (ask(1, "Reconnect"))
+ return FSERROR;
+
if (!lostDir) {
for (lostDir = rootDir->child; lostDir; lostDir = lostDir->next) {
if (!strcmp(lostDir->name, LOSTDIR))
@@ -922,22 +988,23 @@ reconnect(dosfs, boot, fat, head)
p = lfbuf;
}
- if (!ask(0, "Reconnect"))
- return (FSERROR);
-
boot->NumFiles++;
/* Ensure uniqueness of entry here! XXX */
(void)memset(&d, 0, sizeof d);
- sprintf(d.name, "%d", head);
+ sprintf(d.name, "%u", head);
d.flags = 0;
d.head = head;
d.size = fat[head].length * boot->ClusterSize;
-
+
(void)memset(p, 0, 32);
(void)memset(p, ' ', 11);
(void)memcpy(p, d.name, strlen(d.name));
p[26] = (u_char)d.head;
p[27] = (u_char)(d.head >> 8);
+ if (boot->ClustMask == CLUST32_MASK) {
+ p[20] = (u_char)(d.head >> 16);
+ p[21] = (u_char)(d.head >> 24);
+ }
p[28] = (u_char)d.size;
p[29] = (u_char)(d.size >> 8);
p[30] = (u_char)(d.size >> 16);
diff --git a/sbin/fsck_msdos/dosfs.h b/sbin/fsck_msdos/dosfs.h
index 25e04eb6123..fa3608ea9ac 100644
--- a/sbin/fsck_msdos/dosfs.h
+++ b/sbin/fsck_msdos/dosfs.h
@@ -1,10 +1,10 @@
-/* $OpenBSD: dosfs.h,v 1.4 1997/02/28 08:36:11 millert Exp $ */
-/* $NetBSD: dosfs.h,v 1.4 1997/01/03 14:32:48 ws Exp $ */
+/* $OpenBSD: dosfs.h,v 1.5 1998/01/11 20:40:31 provos Exp $ */
+/* $NetBSD: dosfs.h,v 1.5 1997/10/17 11:19:41 ws Exp $ */
/*
- * Copyright (C) 1995, 1996 Wolfgang Solfrank
+ * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
- * Some structure declaration borrowed from Paul Popelka
+ * Some structure declaration borrowed from Paul Popelka
* (paulp@uts.amdahl.com), see /sys/msdosfs/ for reference.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,9 +40,7 @@
#define DOSBOOTBLOCKSIZE 512
-#define MAX12BITCLUSTERS 4078
-
-typedef u_int16_t cl_t; /* type holding a cluster number */
+typedef u_int32_t cl_t; /* type holding a cluster number */
/*
* architecture independent description of all the info stored in a
@@ -54,22 +52,35 @@ struct bootblock {
u_int ResSectors; /* number of reserved sectors */
u_int FATs; /* number of FATs */
u_int RootDirEnts; /* number of root directory entries */
- u_int32_t Sectors; /* total number of sectors */
u_int Media; /* media descriptor */
- u_int FATsecs; /* number of sectors per FAT */
+ u_int FATsmall; /* number of sectors per FAT */
u_int SecPerTrack; /* sectors per track */
u_int Heads; /* number of heads */
+ u_int32_t Sectors; /* total number of sectors */
u_int32_t HiddenSecs; /* # of hidden sectors */
u_int32_t HugeSectors; /* # of sectors if bpbSectors == 0 */
+ u_int FSInfo; /* FSInfo sector */
+ u_int Backup; /* Backup of Bootblocks */
+ cl_t RootCl; /* Start of Root Directory */
+ cl_t FSFree; /* Number of free clusters acc. FSInfo */
+ cl_t FSNext; /* Next free cluster acc. FSInfo */
/* and some more calculated values */
- int Is16BitFat; /* 0 for 12 bit, 1 for 16 bit */
+ u_int flags; /* some flags: */
+#define FAT32 1 /* this is a FAT32 filesystem */
+ /*
+ * Maybe, we should separate out
+ * various parts of FAT32? XXX
+ */
+ int ValidFat; /* valid fat if FAT32 non-mirrored */
+ cl_t ClustMask; /* mask for entries in FAT */
cl_t NumClusters; /* # of entries in a FAT */
u_int32_t NumSectors; /* how many sectors are there */
+ u_int32_t FATsecs; /* how many sectors are in FAT */
u_int32_t NumFatEntries; /* how many entries really are there */
u_int ClusterOffset; /* at what sector would sector 0 start */
u_int ClusterSize; /* Cluster size in bytes */
-
+
/* Now some statistics: */
u_int NumFiles; /* # of plain files */
u_int NumFree; /* # of free clusters */
@@ -85,10 +96,17 @@ struct fatEntry {
#define CLUST_FREE 0 /* 0 means cluster is free */
#define CLUST_FIRST 2 /* 2 is the minimum valid cluster number */
-#define CLUST_RSRVD 0xfff0 /* start of reserved clusters */
-#define CLUST_BAD 0xfff7 /* a cluster with a defect */
-#define CLUST_EOFS 0xfff8 /* start of EOF indicators */
-#define CLUST_EOF 0xffff /* standard value for last cluster */
+#define CLUST_RSRVD 0xfffffff6 /* start of reserved clusters */
+#define CLUST_BAD 0xfffffff7 /* a cluster with a defect */
+#define CLUST_EOFS 0xfffffff8 /* start of EOF indicators */
+#define CLUST_EOF 0xffffffff /* standard value for last cluster */
+
+/*
+ * Masks for cluster values
+ */
+#define CLUST12_MASK 0xfff
+#define CLUST16_MASK 0xffff
+#define CLUST32_MASK 0xfffffff
#define FAT_USED 1 /* This fat chain is used in a file */
diff --git a/sbin/fsck_msdos/ext.h b/sbin/fsck_msdos/ext.h
index aa74ea1ff17..a2897518367 100644
--- a/sbin/fsck_msdos/ext.h
+++ b/sbin/fsck_msdos/ext.h
@@ -1,8 +1,8 @@
-/* $OpenBSD: ext.h,v 1.4 1997/03/02 05:25:54 millert Exp $ */
-/* $NetBSD: ext.h,v 1.4 1996/09/23 16:27:59 christos Exp $ */
+/* $OpenBSD: ext.h,v 1.5 1998/01/11 20:40:33 provos Exp $ */
+/* $NetBSD: ext.h,v 1.5 1997/10/17 11:19:48 ws Exp $ */
/*
- * Copyright (C) 1995, 1996 Wolfgang Solfrank
+ * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,7 @@ extern char *fname; /* filesystem currently checked */
extern struct dosDirEntry *rootDir;
-/*
+/*
* function declarations
*/
int ask __P((int, const char *, ...));
@@ -69,10 +69,11 @@ int checkfilesys __P((const char *));
* Return values of various functions
*/
#define FSOK 0 /* Check was OK */
-#define FSDIRMOD 1 /* Some directory was modified */
-#define FSFATMOD 2 /* The FAT was modified */
-#define FSERROR 4 /* Some unrecovered error remains */
-#define FSFATAL 8 /* Some unrecoverable error occured */
+#define FSBOOTMOD 1 /* Boot block was modified */
+#define FSDIRMOD 2 /* Some directory was modified */
+#define FSFATMOD 4 /* The FAT was modified */
+#define FSERROR 8 /* Some unrecovered error remains */
+#define FSFATAL 16 /* Some unrecoverable error occured */
/*
* read a boot block in a machine independend fashion and translate
@@ -80,10 +81,14 @@ int checkfilesys __P((const char *));
*/
int readboot __P((int, struct bootblock *));
+/*
+ * Correct the FSInfo block.
+ */
+int writefsinfo __P((int, struct bootblock *));
/*
* Read one of the FAT copies and return a pointer to the new
- * allocated array holding our description of it.
+ * allocated array holding our description of it.
*/
int readfat __P((int, struct bootblock *, int, struct fatEntry **));
@@ -106,7 +111,7 @@ int writefat __P((int, struct bootblock *, struct fatEntry *));
/*
* Read a directory
*/
-int resetDosDirSection __P((struct bootblock *));
+int resetDosDirSection __P((struct bootblock *, struct fatEntry *));
void finishDosDirSection __P((void));
int handleDirTree __P((int, struct bootblock *, struct fatEntry *));
@@ -122,7 +127,7 @@ int checklost __P((int, struct bootblock *, struct fatEntry *));
*/
int reconnect __P((int, struct bootblock *, struct fatEntry *, cl_t));
void finishlf __P((void));
-
+
/*
* Small helper functions
*/
diff --git a/sbin/fsck_msdos/fat.c b/sbin/fsck_msdos/fat.c
index 116322de1dc..d4091087e3e 100644
--- a/sbin/fsck_msdos/fat.c
+++ b/sbin/fsck_msdos/fat.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: fat.c,v 1.6 1997/09/11 08:15:26 deraadt Exp $ */
-/* $NetBSD: fat.c,v 1.6 1997/09/08 14:05:31 ws Exp $ */
+/* $OpenBSD: fat.c,v 1.7 1998/01/11 20:40:33 provos Exp $ */
+/* $NetBSD: fat.c,v 1.8 1997/10/17 11:19:53 ws Exp $ */
/*
- * Copyright (C) 1995, 1996 Wolfgang Solfrank
+ * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
#ifndef lint
-static char rcsid[] = "$OpenBSD: fat.c,v 1.6 1997/09/11 08:15:26 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: fat.c,v 1.7 1998/01/11 20:40:33 provos Exp $";
#endif /* not lint */
#include <stdlib.h>
@@ -59,8 +59,8 @@ checkclnum(boot, fat, cl, next)
cl_t cl;
cl_t *next;
{
- if (!boot->Is16BitFat && *next >= (CLUST_RSRVD&0xfff))
- *next |= 0xf000;
+ if (*next >= (CLUST_RSRVD&boot->ClustMask))
+ *next |= ~boot->ClustMask;
if (*next == CLUST_FREE) {
boot->NumFree++;
return (FSOK);
@@ -71,10 +71,10 @@ checkclnum(boot, fat, cl, next)
}
if (*next < CLUST_FIRST
|| (*next >= boot->NumClusters && *next < CLUST_EOFS)) {
- pwarn("Cluster %d in FAT %d continues with %s cluster number %d\n",
+ pwarn("Cluster %u in FAT %d continues with %s cluster number %u\n",
cl, fat,
*next < CLUST_RSRVD ? "out of range" : "reserved",
- *next);
+ *next&boot->ClustMask);
if (ask(0, "Truncate")) {
*next = CLUST_EOF;
return (FSFATMOD);
@@ -98,7 +98,6 @@ readfat(fs, boot, no, fp)
u_char *buffer, *p;
cl_t cl;
off_t off;
- int size;
int ret = FSOK;
boot->NumFree = boot->NumBad = 0;
@@ -122,44 +121,69 @@ readfat(fs, boot, no, fp)
free(fat);
return (FSFATAL);
}
-
- if ((size = read(fs, buffer, boot->FATsecs * boot->BytesPerSec))
+
+ if (read(fs, buffer, boot->FATsecs * boot->BytesPerSec)
!= boot->FATsecs * boot->BytesPerSec) {
- if (size < 0)
- perror("Unable to read FAT");
- else
- pfatal("Short FAT?");
+ perror("Unable to read FAT");
free(buffer);
free(fat);
return (FSFATAL);
}
- /*
- * Remember start of FAT to allow keeping it in write_fat.
- */
- fat[0].length = buffer[0]|(buffer[1] << 8)|(buffer[2] << 16);
- if (boot->Is16BitFat)
- fat[0].length |= buffer[3] << 24;
if (buffer[0] != boot->Media
|| buffer[1] != 0xff || buffer[2] != 0xff
- || (boot->Is16BitFat && buffer[3] != 0xff)) {
- char *msg = boot->Is16BitFat
- ? "FAT starts with odd byte sequence (%02x%02x%02x%02x)\n"
- : "FAT starts with odd byte sequence (%02x%02x%02x)\n";
- pwarn(msg, buffer[0], buffer[1], buffer[2], buffer[3]);
- if (ask(1, "Correct")) {
- fat[0].length = boot->Media|0xffffff;
- ret |= FSFATMOD;
+ || (boot->ClustMask == CLUST16_MASK && buffer[3] != 0xff)
+ || (boot->ClustMask == CLUST32_MASK
+ && ((buffer[3]&0x0f) != 0x0f
+ || buffer[4] != 0xff || buffer[5] != 0xff
+ || buffer[6] != 0xff || (buffer[7]&0x0f) != 0x0f))) {
+ char *msg;
+
+ switch (boot->ClustMask) {
+ case CLUST32_MASK:
+ msg = "FAT starts with odd byte sequence (%02x%02x%02x%02x%02x%02x%02x%02x)\n";
+ break;
+ case CLUST16_MASK:
+ msg = "FAT starts with odd byte sequence (%02x%02x%02x%02x)\n";
+ break;
+ default:
+ msg = "FAT starts with odd byte sequence (%02x%02x%02x)\n";
+ break;
}
+ pwarn(msg,
+ buffer[0], buffer[1], buffer[2], buffer[3],
+ buffer[4], buffer[5], buffer[6], buffer[7]);
+ if (ask(1, "Correct"))
+ ret |= FSFATMOD;
+ }
+ switch (boot->ClustMask) {
+ case CLUST32_MASK:
+ p = buffer + 8;
+ break;
+ case CLUST16_MASK:
+ p = buffer + 4;
+ break;
+ default:
+ p = buffer + 3;
+ break;
}
- p = buffer + (boot->Is16BitFat ? 4 : 3);
for (cl = CLUST_FIRST; cl < boot->NumClusters;) {
- if (boot->Is16BitFat) {
+ switch (boot->ClustMask) {
+ case CLUST32_MASK:
+ fat[cl].next = p[0] + (p[1] << 8)
+ + (p[2] << 16) + (p[3] << 24);
+ fat[cl].next &= boot->ClustMask;
+ ret |= checkclnum(boot, no, cl, &fat[cl].next);
+ cl++;
+ p += 4;
+ break;
+ case CLUST16_MASK:
fat[cl].next = p[0] + (p[1] << 8);
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
p += 2;
- } else {
+ break;
+ default:
fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff;
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
@@ -169,9 +193,10 @@ readfat(fs, boot, no, fp)
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
p += 3;
+ break;
}
}
-
+
free(buffer);
*fp = fat;
return (ret);
@@ -202,7 +227,7 @@ clustdiffer(cl, cp1, cp2, fatnum)
if (*cp2 >= CLUST_RSRVD) {
if ((*cp1 < CLUST_BAD && *cp2 < CLUST_BAD)
|| (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) {
- pwarn("Cluster %d is marked %s with different indicators, ",
+ pwarn("Cluster %u is marked %s with different indicators, ",
cl, rsrvdcltype(*cp1));
if (ask(1, "fix")) {
*cp2 = *cp1;
@@ -210,34 +235,34 @@ clustdiffer(cl, cp1, cp2, fatnum)
}
return (FSFATAL);
}
- pwarn("Cluster %d is marked %s in FAT 1, %s in FAT %d\n",
+ pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %d\n",
cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum);
- if (ask(0, "use FAT #1's entry")) {
+ if (ask(0, "use FAT 0's entry")) {
*cp2 = *cp1;
return (FSFATMOD);
}
- if (ask(0, "use FAT #%d's entry", fatnum)) {
+ if (ask(0, "use FAT %d's entry", fatnum)) {
*cp1 = *cp2;
return (FSFATMOD);
}
return (FSFATAL);
}
- pwarn("Cluster %d is marked %s in FAT 1, but continues with cluster %d in FAT %d\n",
+ pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n",
cl, rsrvdcltype(*cp1), *cp2, fatnum);
if (ask(0, "Use continuation from FAT %d", fatnum)) {
*cp1 = *cp2;
return (FSFATMOD);
}
- if (ask(0, "Use mark from FAT 1")) {
+ if (ask(0, "Use mark from FAT 0")) {
*cp2 = *cp1;
return (FSFATMOD);
}
return (FSFATAL);
}
if (*cp2 >= CLUST_RSRVD) {
- pwarn("Cluster %d continues with cluster %d in FAT 1, but is marked %s in FAT %d\n",
+ pwarn("Cluster %u continues with cluster %u in FAT 1, but is marked %s in FAT %d\n",
cl, *cp1, rsrvdcltype(*cp2), fatnum);
- if (ask(0, "Use continuation from FAT 1")) {
+ if (ask(0, "Use continuation from FAT 0")) {
*cp2 = *cp1;
return (FSFATMOD);
}
@@ -247,9 +272,9 @@ clustdiffer(cl, cp1, cp2, fatnum)
}
return (FSERROR);
}
- pwarn("Cluster %d continues with cluster %d in FAT 1, but with cluster %d in FAT %d\n",
+ pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %d\n",
cl, *cp1, *cp2, fatnum);
- if (ask(0, "Use continuation from FAT 1")) {
+ if (ask(0, "Use continuation from FAT 0")) {
*cp2 = *cp1;
return (FSFATMOD);
}
@@ -309,12 +334,12 @@ checkfat(boot, fat)
u_int len;
int ret = 0;
int conf;
-
+
/*
* pass 1: figure out the cluster chains.
*/
for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
- /* find next untraveled chain */
+ /* find next untravelled chain */
if (fat[head].head != 0 /* cluster already belongs to some chain */
|| fat[head].next == CLUST_FREE
|| fat[head].next == CLUST_BAD)
@@ -329,16 +354,16 @@ checkfat(boot, fat)
}
/* the head record gets the length */
- fat[head].length = len;
+ fat[head].length = fat[head].next == CLUST_FREE ? 0 : len;
}
-
+
/*
* pass 2: check for crosslinked chains (we couldn't do this in pass 1 because
* we didn't know the real start of the chain then - would have treated partial
* chains as interlinked with their main chain)
*/
for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
- /* find next untraveled chain */
+ /* find next untravelled chain */
if (fat[head].head != head)
continue;
@@ -350,10 +375,10 @@ checkfat(boot, fat)
break;
if (fat[p].next >= CLUST_EOFS)
continue;
-
+
if (fat[p].next == 0) {
- pwarn("Cluster chain starting at %d ends with free cluster\n", head);
- if (ask(0, "Clear chain starting at %d", head)) {
+ pwarn("Cluster chain starting at %u ends with free cluster\n", head);
+ if (ask(0, "Clear chain starting at %u", head)) {
clearchain(boot, fat, head);
ret |= FSFATMOD;
} else
@@ -361,9 +386,9 @@ checkfat(boot, fat)
continue;
}
if (fat[p].next >= CLUST_RSRVD) {
- pwarn("Cluster chain starting at %d ends with cluster marked %s\n",
+ pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
head, rsrvdcltype(fat[p].next));
- if (ask(0, "Clear chain starting at %d", head)) {
+ if (ask(0, "Clear chain starting at %u", head)) {
clearchain(boot, fat, head);
ret |= FSFATMOD;
} else
@@ -371,22 +396,22 @@ checkfat(boot, fat)
continue;
}
if (fat[p].next < CLUST_FIRST || fat[p].next >= boot->NumClusters) {
- pwarn("Cluster chain starting at %d ends with cluster out of range (%d)\n",
+ pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
head, fat[p].next);
- if (ask(0, "Clear chain starting at %d", head)) {
+ if (ask(0, "Clear chain starting at %u", head)) {
clearchain(boot, fat, head);
ret |= FSFATMOD;
} else
ret |= FSERROR;
}
- pwarn("Cluster chains starting at %d and %d are linked at cluster %d\n",
+ pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
head, fat[p].head, p);
conf = FSERROR;
- if (ask(0, "Clear chain starting at %d", head)) {
+ if (ask(0, "Clear chain starting at %u", head)) {
clearchain(boot, fat, head);
conf = FSFATMOD;
}
- if (ask(0, "Clear chain starting at %d", h = fat[p].head)) {
+ if (ask(0, "Clear chain starting at %u", h = fat[p].head)) {
if (conf == FSERROR) {
/*
* Transfer the common chain to the one not cleared above.
@@ -427,7 +452,7 @@ writefat(fs, boot, fat)
u_int32_t fatsz;
off_t off;
int ret = FSOK;
-
+
buffer = malloc(fatsz = boot->FATsecs * boot->BytesPerSec);
if (buffer == NULL) {
perror("No space for FAT");
@@ -436,29 +461,49 @@ writefat(fs, boot, fat)
(void)memset(buffer, 0, fatsz);
boot->NumFree = 0;
p = buffer;
- *p++ = (u_char)fat[0].length;
- *p++ = (u_char)(fat[0].length >> 8);
- *p++ = (u_char)(fat[0].length >> 16);
- if (boot->Is16BitFat)
- *p++ = (u_char)(fat[0].length >> 24);
+ *p++ = (u_char)boot->Media;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ switch (boot->ClustMask) {
+ case CLUST16_MASK:
+ *p++ = 0xff;
+ break;
+ case CLUST32_MASK:
+ *p++ = 0x0f;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ *p++ = 0x0f;
+ break;
+ }
for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
- if (boot->Is16BitFat) {
- p[0] = (u_char)fat[cl].next;
+ switch (boot->ClustMask) {
+ case CLUST32_MASK:
if (fat[cl].next == CLUST_FREE)
boot->NumFree++;
- p[1] = (u_char)(fat[cl].next >> 8);
- p += 2;
- } else {
+ *p++ = (u_char)fat[cl].next;
+ *p++ = (u_char)(fat[cl].next >> 8);
+ *p++ = (u_char)(fat[cl].next >> 16);
+ *p &= 0xf0;
+ *p++ |= (fat[cl].next >> 24)&0x0f;
+ break;
+ case CLUST16_MASK:
+ if (fat[cl].next == CLUST_FREE)
+ boot->NumFree++;
+ *p++ = (u_char)fat[cl].next;
+ *p++ = (u_char)(fat[cl].next >> 8);
+ break;
+ default:
if (fat[cl].next == CLUST_FREE)
boot->NumFree++;
if (cl + 1 < boot->NumClusters
&& fat[cl + 1].next == CLUST_FREE)
boot->NumFree++;
- p[0] = (u_char)fat[cl].next;
- p[1] = (u_char)((fat[cl].next >> 8) & 0xf)
- |(u_char)(fat[cl+1].next << 4);
- p[2] = (u_char)(fat[++cl].next >> 4);
- p += 3;
+ *p++ = (u_char)fat[cl].next;
+ *p++ = (u_char)((fat[cl].next >> 8) & 0xf)
+ |(u_char)(fat[cl+1].next << 4);
+ *p++ = (u_char)(fat[++cl].next >> 4);
+ break;
}
}
for (i = 0; i < boot->FATs; i++) {
@@ -485,9 +530,10 @@ checklost(dosfs, boot, fat)
{
cl_t head;
int mod = FSOK;
+ int ret;
for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
- /* find next untraveled chain */
+ /* find next untravelled chain */
if (fat[head].head != head
|| fat[head].next == CLUST_FREE
|| (fat[head].next >= CLUST_RSRVD
@@ -495,13 +541,42 @@ checklost(dosfs, boot, fat)
|| (fat[head].flags & FAT_USED))
continue;
- pwarn("Lost cluster chain at cluster 0x%04x\n%d Cluster(s) lost\n",
+ pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n",
head, fat[head].length);
- mod |= reconnect(dosfs, boot, fat, head);
+ mod |= ret = reconnect(dosfs, boot, fat, head);
if (mod & FSFATAL)
break;
+ if (ret == FSERROR && ask(0, "Clear")) {
+ clearchain(boot, fat, head);
+ mod |= FSFATMOD;
+ }
}
finishlf();
-
+
+ if (boot->FSInfo) {
+ ret = 0;
+ if (boot->FSFree != boot->NumFree) {
+ pwarn("Free space in FSInfo block (%d) not correct (%d)\n",
+ boot->FSFree, boot->NumFree);
+ if (ask(1, "fix")) {
+ boot->FSFree = boot->NumFree;
+ ret = 1;
+ }
+ }
+ if (boot->NumFree && fat[boot->FSNext].next != CLUST_FREE) {
+ pwarn("Next free cluster in FSInfo block (%u) not free\n",
+ boot->FSNext);
+ if (ask(1, "fix"))
+ for (head = CLUST_FIRST; head < boot->NumClusters; head++)
+ if (fat[head].next == CLUST_FREE) {
+ boot->FSNext = head;
+ ret = 1;
+ break;
+ }
+ }
+ if (ret)
+ mod |= writefsinfo(dosfs, boot);
+ }
+
return (mod);
}
diff --git a/sbin/fsck_msdos/fsck_msdos.8 b/sbin/fsck_msdos/fsck_msdos.8
index a61c33b7810..1d8095e61fa 100644
--- a/sbin/fsck_msdos/fsck_msdos.8
+++ b/sbin/fsck_msdos/fsck_msdos.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: fsck_msdos.8,v 1.4 1997/03/02 05:25:55 millert Exp $
+.\" $OpenBSD: fsck_msdos.8,v 1.5 1998/01/11 20:40:34 provos Exp $
.\" $NetBSD: fsck_msdos.8,v 1.4 1996/10/17 20:41:24 cgd Exp $
.\"
.\" Copyright (C) 1995 Wolfgang Solfrank
@@ -50,7 +50,7 @@
.Ar ...
.Sh DESCRIPTION
.Pp
-The
+The
.Nm
utility verifies and repairs
.Tn FAT