diff options
author | Niels Provos <provos@cvs.openbsd.org> | 1998-01-11 20:40:35 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 1998-01-11 20:40:35 +0000 |
commit | 28d8359f8470d4f9956b9ce108964c4b005dfd35 (patch) | |
tree | 66ccf2c8983772a096f4bb3ea0c39f6ab261f4e5 | |
parent | 487fe4efe824e828cdefbee41c1d03ef04a885f3 (diff) |
FAT32 support from NetBSD by Wolfgang Solfrank.
-rw-r--r-- | sbin/fsck_msdos/boot.c | 184 | ||||
-rw-r--r-- | sbin/fsck_msdos/check.c | 78 | ||||
-rw-r--r-- | sbin/fsck_msdos/dir.c | 175 | ||||
-rw-r--r-- | sbin/fsck_msdos/dosfs.h | 48 | ||||
-rw-r--r-- | sbin/fsck_msdos/ext.h | 27 | ||||
-rw-r--r-- | sbin/fsck_msdos/fat.c | 231 | ||||
-rw-r--r-- | sbin/fsck_msdos/fsck_msdos.8 | 4 |
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, ¤tFat); + 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, ¤tFat); - 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 |