Add fsck_msdosfs.
Obtained from: NetBSD
This commit is contained in:
parent
70d51341bf
commit
0121b42aca
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=79455
11
sbin/fsck_msdosfs/Makefile
Normal file
11
sbin/fsck_msdosfs/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# $NetBSD: Makefile,v 1.6 1997/05/08 21:11:11 gwr Exp $
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
PROG= fsck_msdosfs
|
||||||
|
MAN= fsck_msdosfs.8
|
||||||
|
SRCS= main.c check.c boot.c fat.c dir.c fsutil.c
|
||||||
|
FSCK= ${.CURDIR}/../fsck
|
||||||
|
CFLAGS+= -I${FSCK}
|
||||||
|
.PATH: ${FSCK}
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
268
sbin/fsck_msdosfs/boot.c
Normal file
268
sbin/fsck_msdosfs/boot.c
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1997 Wolfgang Solfrank
|
||||||
|
* Copyright (c) 1995 Martin Husemann
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Martin Husemann
|
||||||
|
* and Wolfgang Solfrank.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: boot.c,v 1.5 1997/10/17 11:19:23 ws Exp $");
|
||||||
|
static const char rcsid[] =
|
||||||
|
"$FreeBSD$";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ext.h"
|
||||||
|
#include "fsutil.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
readboot(dosfs, boot)
|
||||||
|
int dosfs;
|
||||||
|
struct bootblock *boot;
|
||||||
|
{
|
||||||
|
u_char block[DOSBOOTBLOCKSIZE];
|
||||||
|
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];
|
||||||
|
boot->ResSectors = block[14] + (block[15] << 8);
|
||||||
|
boot->FATs = block[16];
|
||||||
|
boot->RootDirEnts = block[17] + (block[18] << 8);
|
||||||
|
boot->Sectors = block[19] + (block[20] << 8);
|
||||||
|
boot->Media = block[21];
|
||||||
|
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
|
||||||
|
+ boot->FATs * boot->FATsecs
|
||||||
|
- CLUST_FIRST * boot->SecPerClust;
|
||||||
|
|
||||||
|
if (boot->BytesPerSec % DOSBOOTBLOCKSIZE != 0) {
|
||||||
|
pfatal("Invalid sector size: %u", boot->BytesPerSec);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
if (boot->SecPerClust == 0) {
|
||||||
|
pfatal("Invalid cluster size: %u", boot->SecPerClust);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
if (boot->Sectors) {
|
||||||
|
boot->HugeSectors = 0;
|
||||||
|
boot->NumSectors = boot->Sectors;
|
||||||
|
} else
|
||||||
|
boot->NumSectors = boot->HugeSectors;
|
||||||
|
boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust;
|
||||||
|
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec * 2) / 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot->NumFatEntries < boot->NumClusters) {
|
||||||
|
pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
|
||||||
|
boot->NumClusters, boot->FATsecs);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
boot->ClusterSize = boot->BytesPerSec * boot->SecPerClust;
|
||||||
|
|
||||||
|
boot->NumFiles = 1;
|
||||||
|
boot->NumFree = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Technically, we should return FSBOOTMOD here.
|
||||||
|
*
|
||||||
|
* However, since Win95 OSR2 (the first M$ OS that has
|
||||||
|
* support for FAT32) doesn't maintain the FSINFO block
|
||||||
|
* correctly, it has to be fixed pretty often.
|
||||||
|
*
|
||||||
|
* Therefor, we handle the FSINFO block only informally,
|
||||||
|
* fixing it if neccessary, but otherwise ignoring the
|
||||||
|
* fact that it was incorrect.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
194
sbin/fsck_msdosfs/check.c
Normal file
194
sbin/fsck_msdosfs/check.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
|
||||||
|
* Copyright (c) 1995 Martin Husemann
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Martin Husemann
|
||||||
|
* and Wolfgang Solfrank.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: check.c,v 1.10 2000/04/25 23:02:51 jdolecek Exp $");
|
||||||
|
static const char rcsid[] =
|
||||||
|
"$FreeBSD$";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "ext.h"
|
||||||
|
#include "fsutil.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
checkfilesys(fname)
|
||||||
|
const char *fname;
|
||||||
|
{
|
||||||
|
int dosfs;
|
||||||
|
struct bootblock boot;
|
||||||
|
struct fatEntry *fat = NULL;
|
||||||
|
int i, finish_dosdirsection=0;
|
||||||
|
int mod = 0;
|
||||||
|
int ret = 8;
|
||||||
|
|
||||||
|
rdonly = alwaysno;
|
||||||
|
if (!preen)
|
||||||
|
printf("** %s", fname);
|
||||||
|
|
||||||
|
dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0);
|
||||||
|
if (dosfs < 0 && !rdonly) {
|
||||||
|
dosfs = open(fname, O_RDONLY, 0);
|
||||||
|
if (dosfs >= 0)
|
||||||
|
pwarn(" (NO WRITE)\n");
|
||||||
|
else if (!preen)
|
||||||
|
printf("\n");
|
||||||
|
rdonly = 1;
|
||||||
|
} else if (!preen)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (dosfs < 0) {
|
||||||
|
perror("Can't open");
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readboot(dosfs, &boot) != FSOK) {
|
||||||
|
close(dosfs);
|
||||||
|
printf("\n");
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preen) {
|
||||||
|
if (boot.ValidFat < 0)
|
||||||
|
printf("** Phase 1 - Read and Compare FATs\n");
|
||||||
|
else
|
||||||
|
printf("** Phase 1 - Read FAT\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat);
|
||||||
|
if (mod & FSFATAL) {
|
||||||
|
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)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mod |= comparefat(&boot, fat, currentFat, i);
|
||||||
|
free(currentFat);
|
||||||
|
if (mod & FSFATAL)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preen)
|
||||||
|
printf("** Phase 2 - Check Cluster Chains\n");
|
||||||
|
|
||||||
|
mod |= checkfat(&boot, fat);
|
||||||
|
if (mod & FSFATAL)
|
||||||
|
goto out;
|
||||||
|
/* delay writing FATs */
|
||||||
|
|
||||||
|
if (!preen)
|
||||||
|
printf("** Phase 3 - Checking Directories\n");
|
||||||
|
|
||||||
|
mod |= resetDosDirSection(&boot, fat);
|
||||||
|
finish_dosdirsection = 1;
|
||||||
|
if (mod & FSFATAL)
|
||||||
|
goto out;
|
||||||
|
/* delay writing FATs */
|
||||||
|
|
||||||
|
mod |= handleDirTree(dosfs, &boot, fat);
|
||||||
|
if (mod & FSFATAL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!preen)
|
||||||
|
printf("** Phase 4 - Checking for Lost Files\n");
|
||||||
|
|
||||||
|
mod |= checklost(dosfs, &boot, fat);
|
||||||
|
if (mod & FSFATAL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* now write the FATs */
|
||||||
|
if (mod & FSFATMOD) {
|
||||||
|
if (ask(1, "Update FATs")) {
|
||||||
|
mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT);
|
||||||
|
if (mod & FSFATAL)
|
||||||
|
goto out;
|
||||||
|
} else
|
||||||
|
mod |= FSERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot.NumBad)
|
||||||
|
pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n",
|
||||||
|
boot.NumFiles,
|
||||||
|
boot.NumFree * boot.ClusterSize / 1024, boot.NumFree,
|
||||||
|
boot.NumBad * boot.ClusterSize / 1024, boot.NumBad);
|
||||||
|
else
|
||||||
|
pwarn("%d files, %d free (%d clusters)\n",
|
||||||
|
boot.NumFiles,
|
||||||
|
boot.NumFree * boot.ClusterSize / 1024, boot.NumFree);
|
||||||
|
|
||||||
|
if (mod && (mod & FSERROR) == 0) {
|
||||||
|
if (mod & FSDIRTY) {
|
||||||
|
if (ask(1, "MARK FILE SYSTEM CLEAN") == 0)
|
||||||
|
mod &= ~FSDIRTY;
|
||||||
|
|
||||||
|
if (mod & FSDIRTY) {
|
||||||
|
pwarn("MARKING FILE SYSTEM CLEAN\n");
|
||||||
|
mod |= writefat(dosfs, &boot, fat, 1);
|
||||||
|
} else {
|
||||||
|
pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n");
|
||||||
|
mod |= FSERROR; /* file system not clean */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod & (FSFATAL | FSERROR))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (finish_dosdirsection)
|
||||||
|
finishDosDirSection();
|
||||||
|
free(fat);
|
||||||
|
close(dosfs);
|
||||||
|
|
||||||
|
if (mod & (FSFATMOD|FSDIRMOD))
|
||||||
|
pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
1017
sbin/fsck_msdosfs/dir.c
Normal file
1017
sbin/fsck_msdosfs/dir.c
Normal file
File diff suppressed because it is too large
Load Diff
144
sbin/fsck_msdosfs/dosfs.h
Normal file
144
sbin/fsck_msdosfs/dosfs.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
|
||||||
|
* Copyright (c) 1995 Martin Husemann
|
||||||
|
* 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
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Martin Husemann
|
||||||
|
* and Wolfgang Solfrank.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* $NetBSD: dosfs.h,v 1.4 1997/01/03 14:32:48 ws Exp $
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DOSFS_H
|
||||||
|
#define DOSFS_H
|
||||||
|
|
||||||
|
#define DOSBOOTBLOCKSIZE 512
|
||||||
|
|
||||||
|
typedef u_int32_t cl_t; /* type holding a cluster number */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* architecture independent description of all the info stored in a
|
||||||
|
* FAT boot block.
|
||||||
|
*/
|
||||||
|
struct bootblock {
|
||||||
|
u_int BytesPerSec; /* bytes per sector */
|
||||||
|
u_int SecPerClust; /* sectors per cluster */
|
||||||
|
u_int ResSectors; /* number of reserved sectors */
|
||||||
|
u_int FATs; /* number of FATs */
|
||||||
|
u_int RootDirEnts; /* number of root directory entries */
|
||||||
|
u_int Media; /* media descriptor */
|
||||||
|
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 */
|
||||||
|
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 */
|
||||||
|
u_int NumBad; /* # of bad clusters */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fatEntry {
|
||||||
|
cl_t next; /* pointer to next cluster */
|
||||||
|
cl_t head; /* pointer to start of chain */
|
||||||
|
u_int32_t length; /* number of clusters on chain */
|
||||||
|
int flags; /* see below */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CLUST_FREE 0 /* 0 means cluster is free */
|
||||||
|
#define CLUST_FIRST 2 /* 2 is the minimum valid cluster number */
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
#define DOSLONGNAMELEN 256 /* long name maximal length */
|
||||||
|
#define LRFIRST 0x40 /* first long name record */
|
||||||
|
#define LRNOMASK 0x1f /* mask to extract long record
|
||||||
|
* sequence number */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Architecture independent description of a directory entry
|
||||||
|
*/
|
||||||
|
struct dosDirEntry {
|
||||||
|
struct dosDirEntry
|
||||||
|
*parent, /* previous tree level */
|
||||||
|
*next, /* next brother */
|
||||||
|
*child; /* if this is a directory */
|
||||||
|
char name[8+1+3+1]; /* alias name first part */
|
||||||
|
char lname[DOSLONGNAMELEN]; /* real name */
|
||||||
|
uint flags; /* attributes */
|
||||||
|
cl_t head; /* cluster no */
|
||||||
|
u_int32_t size; /* filesize in bytes */
|
||||||
|
uint fsckflags; /* flags during fsck */
|
||||||
|
};
|
||||||
|
/* Flags in fsckflags: */
|
||||||
|
#define DIREMPTY 1
|
||||||
|
#define DIREMPWARN 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO-list of unread directories
|
||||||
|
*/
|
||||||
|
struct dirTodoNode {
|
||||||
|
struct dosDirEntry *dir;
|
||||||
|
struct dirTodoNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
144
sbin/fsck_msdosfs/ext.h
Normal file
144
sbin/fsck_msdosfs/ext.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
|
||||||
|
* Copyright (c) 1995 Martin Husemann
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Martin Husemann
|
||||||
|
* and Wolfgang Solfrank.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* $NetBSD: ext.h,v 1.6 2000/04/25 23:02:51 jdolecek Exp $
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXT_H
|
||||||
|
#define EXT_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "dosfs.h"
|
||||||
|
|
||||||
|
#define LOSTDIR "LOST.DIR"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Options:
|
||||||
|
*/
|
||||||
|
extern int alwaysno; /* assume "no" for all questions */
|
||||||
|
extern int alwaysyes; /* assume "yes" for all questions */
|
||||||
|
extern int preen; /* we are preening */
|
||||||
|
extern int rdonly; /* device is opened read only (supersedes above) */
|
||||||
|
|
||||||
|
extern char *fname; /* filesystem currently checked */
|
||||||
|
|
||||||
|
extern struct dosDirEntry *rootDir;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function declarations
|
||||||
|
*/
|
||||||
|
int ask __P((int, const char *, ...)) __attribute__((__format__(__printf__,2,3)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check filesystem given as arg
|
||||||
|
*/
|
||||||
|
int checkfilesys __P((const char *));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return values of various functions
|
||||||
|
*/
|
||||||
|
#define FSOK 0 /* Check was OK */
|
||||||
|
#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 */
|
||||||
|
#define FSDIRTY 32 /* File system is dirty */
|
||||||
|
#define FSFIXFAT 64 /* Fix file system FAT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read a boot block in a machine independend fashion and translate
|
||||||
|
* it into our struct bootblock.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
int readfat __P((int, struct bootblock *, int, struct fatEntry **));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check two FAT copies for consistency and merge changes into the
|
||||||
|
* first if neccessary.
|
||||||
|
*/
|
||||||
|
int comparefat __P((struct bootblock *, struct fatEntry *, struct fatEntry *, int));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a FAT
|
||||||
|
*/
|
||||||
|
int checkfat __P((struct bootblock *, struct fatEntry *));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write back FAT entries
|
||||||
|
*/
|
||||||
|
int writefat __P((int, struct bootblock *, struct fatEntry *, int));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a directory
|
||||||
|
*/
|
||||||
|
int resetDosDirSection __P((struct bootblock *, struct fatEntry *));
|
||||||
|
void finishDosDirSection __P((void));
|
||||||
|
int handleDirTree __P((int, struct bootblock *, struct fatEntry *));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cross-check routines run after everything is completely in memory
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Check for lost cluster chains
|
||||||
|
*/
|
||||||
|
int checklost __P((int, struct bootblock *, struct fatEntry *));
|
||||||
|
/*
|
||||||
|
* Try to reconnect a lost cluster chain
|
||||||
|
*/
|
||||||
|
int reconnect __P((int, struct bootblock *, struct fatEntry *, cl_t));
|
||||||
|
void finishlf __P((void));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Small helper functions
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Return the type of a reserved cluster as text
|
||||||
|
*/
|
||||||
|
char *rsrvdcltype __P((cl_t));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear a cluster chain in a FAT
|
||||||
|
*/
|
||||||
|
void clearchain __P((struct bootblock *, struct fatEntry *, cl_t));
|
||||||
|
|
||||||
|
#endif
|
659
sbin/fsck_msdosfs/fat.c
Normal file
659
sbin/fsck_msdosfs/fat.c
Normal file
@ -0,0 +1,659 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
|
||||||
|
* Copyright (c) 1995 Martin Husemann
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Martin Husemann
|
||||||
|
* and Wolfgang Solfrank.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: fat.c,v 1.12 2000/10/10 20:24:52 is Exp $");
|
||||||
|
static const char rcsid[] =
|
||||||
|
"$FreeBSD$";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ext.h"
|
||||||
|
#include "fsutil.h"
|
||||||
|
|
||||||
|
static int checkclnum __P((struct bootblock *, int, cl_t, cl_t *));
|
||||||
|
static int clustdiffer __P((cl_t, cl_t *, cl_t *, int));
|
||||||
|
static int tryclear __P((struct bootblock *, struct fatEntry *, cl_t, cl_t *));
|
||||||
|
static int _readfat __P((int, struct bootblock *, int, u_char **));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a cluster number for valid value
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
checkclnum(boot, fat, cl, next)
|
||||||
|
struct bootblock *boot;
|
||||||
|
int fat;
|
||||||
|
cl_t cl;
|
||||||
|
cl_t *next;
|
||||||
|
{
|
||||||
|
if (*next >= (CLUST_RSRVD&boot->ClustMask))
|
||||||
|
*next |= ~boot->ClustMask;
|
||||||
|
if (*next == CLUST_FREE) {
|
||||||
|
boot->NumFree++;
|
||||||
|
return FSOK;
|
||||||
|
}
|
||||||
|
if (*next == CLUST_BAD) {
|
||||||
|
boot->NumBad++;
|
||||||
|
return FSOK;
|
||||||
|
}
|
||||||
|
if (*next < CLUST_FIRST
|
||||||
|
|| (*next >= boot->NumClusters && *next < CLUST_EOFS)) {
|
||||||
|
pwarn("Cluster %u in FAT %d continues with %s cluster number %u\n",
|
||||||
|
cl, fat,
|
||||||
|
*next < CLUST_RSRVD ? "out of range" : "reserved",
|
||||||
|
*next&boot->ClustMask);
|
||||||
|
if (ask(0, "Truncate")) {
|
||||||
|
*next = CLUST_EOF;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
return FSERROR;
|
||||||
|
}
|
||||||
|
return FSOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a FAT from disk. Returns 1 if successful, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_readfat(fs, boot, no, buffer)
|
||||||
|
int fs;
|
||||||
|
struct bootblock *boot;
|
||||||
|
int no;
|
||||||
|
u_char **buffer;
|
||||||
|
{
|
||||||
|
off_t off;
|
||||||
|
|
||||||
|
*buffer = malloc(boot->FATsecs * boot->BytesPerSec);
|
||||||
|
if (*buffer == NULL) {
|
||||||
|
perror("No space for FAT");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
off = boot->ResSectors + no * boot->FATsecs;
|
||||||
|
off *= boot->BytesPerSec;
|
||||||
|
|
||||||
|
if (lseek(fs, off, SEEK_SET) != off) {
|
||||||
|
perror("Unable to read FAT");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(fs, *buffer, boot->FATsecs * boot->BytesPerSec)
|
||||||
|
!= boot->FATsecs * boot->BytesPerSec) {
|
||||||
|
perror("Unable to read FAT");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(*buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a FAT and decode it into internal format
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
readfat(fs, boot, no, fp)
|
||||||
|
int fs;
|
||||||
|
struct bootblock *boot;
|
||||||
|
int no;
|
||||||
|
struct fatEntry **fp;
|
||||||
|
{
|
||||||
|
struct fatEntry *fat;
|
||||||
|
u_char *buffer, *p;
|
||||||
|
cl_t cl;
|
||||||
|
int ret = FSOK;
|
||||||
|
|
||||||
|
boot->NumFree = boot->NumBad = 0;
|
||||||
|
|
||||||
|
if (!_readfat(fs, boot, no, &buffer))
|
||||||
|
return FSFATAL;
|
||||||
|
|
||||||
|
fat = calloc(boot->NumClusters, sizeof(struct fatEntry));
|
||||||
|
if (fat == NULL) {
|
||||||
|
perror("No space for FAT");
|
||||||
|
free(buffer);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer[0] != boot->Media
|
||||||
|
|| buffer[1] != 0xff || buffer[2] != 0xff
|
||||||
|
|| (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))) {
|
||||||
|
|
||||||
|
/* Windows 95 OSR2 (and possibly any later) changes
|
||||||
|
* the FAT signature to 0xXXffff7f for FAT16 and to
|
||||||
|
* 0xXXffff0fffffff07 for FAT32 upon boot, to know that the
|
||||||
|
* filesystem is dirty if it doesn't reboot cleanly.
|
||||||
|
* Check this special condition before errorring out.
|
||||||
|
*/
|
||||||
|
if (buffer[0] == boot->Media && buffer[1] == 0xff
|
||||||
|
&& buffer[2] == 0xff
|
||||||
|
&& ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f)
|
||||||
|
|| (boot->ClustMask == CLUST32_MASK
|
||||||
|
&& buffer[3] == 0x0f && buffer[4] == 0xff
|
||||||
|
&& buffer[5] == 0xff && buffer[6] == 0xff
|
||||||
|
&& buffer[7] == 0x07)))
|
||||||
|
ret |= FSDIRTY;
|
||||||
|
else {
|
||||||
|
/* just some odd byte sequence in FAT */
|
||||||
|
|
||||||
|
switch (boot->ClustMask) {
|
||||||
|
case CLUST32_MASK:
|
||||||
|
pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n",
|
||||||
|
"FAT starts with odd byte sequence",
|
||||||
|
buffer[0], buffer[1], buffer[2], buffer[3],
|
||||||
|
buffer[4], buffer[5], buffer[6], buffer[7]);
|
||||||
|
break;
|
||||||
|
case CLUST16_MASK:
|
||||||
|
pwarn("%s (%02x%02x%02x%02x)\n",
|
||||||
|
"FAT starts with odd byte sequence",
|
||||||
|
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pwarn("%s (%02x%02x%02x)\n",
|
||||||
|
"FAT starts with odd byte sequence",
|
||||||
|
buffer[0], buffer[1], buffer[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ask(1, "Correct"))
|
||||||
|
ret |= FSFIXFAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (boot->ClustMask) {
|
||||||
|
case CLUST32_MASK:
|
||||||
|
p = buffer + 8;
|
||||||
|
break;
|
||||||
|
case CLUST16_MASK:
|
||||||
|
p = buffer + 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
p = buffer + 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (cl = CLUST_FIRST; cl < boot->NumClusters;) {
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff;
|
||||||
|
ret |= checkclnum(boot, no, cl, &fat[cl].next);
|
||||||
|
cl++;
|
||||||
|
if (cl >= boot->NumClusters)
|
||||||
|
break;
|
||||||
|
fat[cl].next = ((p[1] >> 4) + (p[2] << 4)) & 0x0fff;
|
||||||
|
ret |= checkclnum(boot, no, cl, &fat[cl].next);
|
||||||
|
cl++;
|
||||||
|
p += 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
*fp = fat;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get type of reserved cluster
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
rsrvdcltype(cl)
|
||||||
|
cl_t cl;
|
||||||
|
{
|
||||||
|
if (cl == CLUST_FREE)
|
||||||
|
return "free";
|
||||||
|
if (cl < CLUST_BAD)
|
||||||
|
return "reserved";
|
||||||
|
if (cl > CLUST_BAD)
|
||||||
|
return "as EOF";
|
||||||
|
return "bad";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
clustdiffer(cl, cp1, cp2, fatnum)
|
||||||
|
cl_t cl;
|
||||||
|
cl_t *cp1;
|
||||||
|
cl_t *cp2;
|
||||||
|
int fatnum;
|
||||||
|
{
|
||||||
|
if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) {
|
||||||
|
if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
|
||||||
|
if ((*cp1 != CLUST_FREE && *cp1 < CLUST_BAD
|
||||||
|
&& *cp2 != CLUST_FREE && *cp2 < CLUST_BAD)
|
||||||
|
|| (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) {
|
||||||
|
pwarn("Cluster %u is marked %s with different indicators, ",
|
||||||
|
cl, rsrvdcltype(*cp1));
|
||||||
|
if (ask(1, "fix")) {
|
||||||
|
*cp2 = *cp1;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
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 0's entry")) {
|
||||||
|
*cp2 = *cp1;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
if (ask(0, "use FAT %d's entry", fatnum)) {
|
||||||
|
*cp1 = *cp2;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
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 0")) {
|
||||||
|
*cp2 = *cp1;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
|
||||||
|
pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %d\n",
|
||||||
|
cl, *cp1, rsrvdcltype(*cp2), fatnum);
|
||||||
|
if (ask(0, "Use continuation from FAT 0")) {
|
||||||
|
*cp2 = *cp1;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
if (ask(0, "Use mark from FAT %d", fatnum)) {
|
||||||
|
*cp1 = *cp2;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
return FSERROR;
|
||||||
|
}
|
||||||
|
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 0")) {
|
||||||
|
*cp2 = *cp1;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
if (ask(0, "Use continuation from FAT %d", fatnum)) {
|
||||||
|
*cp1 = *cp2;
|
||||||
|
return FSFATMOD;
|
||||||
|
}
|
||||||
|
return FSERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare two FAT copies in memory. Resolve any conflicts and merge them
|
||||||
|
* into the first one.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
comparefat(boot, first, second, fatnum)
|
||||||
|
struct bootblock *boot;
|
||||||
|
struct fatEntry *first;
|
||||||
|
struct fatEntry *second;
|
||||||
|
int fatnum;
|
||||||
|
{
|
||||||
|
cl_t cl;
|
||||||
|
int ret = FSOK;
|
||||||
|
|
||||||
|
for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++)
|
||||||
|
if (first[cl].next != second[cl].next)
|
||||||
|
ret |= clustdiffer(cl, &first[cl].next, &second[cl].next, fatnum);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clearchain(boot, fat, head)
|
||||||
|
struct bootblock *boot;
|
||||||
|
struct fatEntry *fat;
|
||||||
|
cl_t head;
|
||||||
|
{
|
||||||
|
cl_t p, q;
|
||||||
|
|
||||||
|
for (p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = q) {
|
||||||
|
if (fat[p].head != head)
|
||||||
|
break;
|
||||||
|
q = fat[p].next;
|
||||||
|
fat[p].next = fat[p].head = CLUST_FREE;
|
||||||
|
fat[p].length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tryclear(boot, fat, head, trunc)
|
||||||
|
struct bootblock *boot;
|
||||||
|
struct fatEntry *fat;
|
||||||
|
cl_t head;
|
||||||
|
cl_t *trunc;
|
||||||
|
{
|
||||||
|
if (ask(0, "Clear chain starting at %u", head)) {
|
||||||
|
clearchain(boot, fat, head);
|
||||||
|
return FSFATMOD;
|
||||||
|
} else if (ask(0, "Truncate")) {
|
||||||
|
*trunc = CLUST_EOF;
|
||||||
|
return FSFATMOD;
|
||||||
|
} else
|
||||||
|
return FSERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a complete FAT in-memory for crosslinks
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
checkfat(boot, fat)
|
||||||
|
struct bootblock *boot;
|
||||||
|
struct fatEntry *fat;
|
||||||
|
{
|
||||||
|
cl_t head, p, h, n;
|
||||||
|
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 untravelled chain */
|
||||||
|
if (fat[head].head != 0 /* cluster already belongs to some chain */
|
||||||
|
|| fat[head].next == CLUST_FREE
|
||||||
|
|| fat[head].next == CLUST_BAD)
|
||||||
|
continue; /* skip it. */
|
||||||
|
|
||||||
|
/* follow the chain and mark all clusters on the way */
|
||||||
|
for (len = 0, p = head;
|
||||||
|
p >= CLUST_FIRST && p < boot->NumClusters;
|
||||||
|
p = fat[p].next) {
|
||||||
|
fat[p].head = head;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the head record gets the length */
|
||||||
|
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 untravelled chain */
|
||||||
|
if (fat[head].head != head)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* follow the chain to its end (hopefully) */
|
||||||
|
for (p = head;
|
||||||
|
(n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
|
||||||
|
p = n)
|
||||||
|
if (fat[n].head != head)
|
||||||
|
break;
|
||||||
|
if (n >= CLUST_EOFS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (n == CLUST_FREE || n >= CLUST_RSRVD) {
|
||||||
|
pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
|
||||||
|
head, rsrvdcltype(n));
|
||||||
|
ret |= tryclear(boot, fat, head, &fat[p].next);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (n < CLUST_FIRST || n >= boot->NumClusters) {
|
||||||
|
pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
|
||||||
|
head, n);
|
||||||
|
ret |= tryclear(boot, fat, head, &fat[p].next);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
|
||||||
|
head, fat[n].head, n);
|
||||||
|
conf = tryclear(boot, fat, head, &fat[p].next);
|
||||||
|
if (ask(0, "Clear chain starting at %u", h = fat[n].head)) {
|
||||||
|
if (conf == FSERROR) {
|
||||||
|
/*
|
||||||
|
* Transfer the common chain to the one not cleared above.
|
||||||
|
*/
|
||||||
|
for (p = n;
|
||||||
|
p >= CLUST_FIRST && p < boot->NumClusters;
|
||||||
|
p = fat[p].next) {
|
||||||
|
if (h != fat[p].head) {
|
||||||
|
/*
|
||||||
|
* Have to reexamine this chain.
|
||||||
|
*/
|
||||||
|
head--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fat[p].head = head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearchain(boot, fat, h);
|
||||||
|
conf |= FSFATMOD;
|
||||||
|
}
|
||||||
|
ret |= conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out FATs encoding them from the internal format
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
writefat(fs, boot, fat, correct_fat)
|
||||||
|
int fs;
|
||||||
|
struct bootblock *boot;
|
||||||
|
struct fatEntry *fat;
|
||||||
|
int correct_fat;
|
||||||
|
{
|
||||||
|
u_char *buffer, *p;
|
||||||
|
cl_t cl;
|
||||||
|
int i;
|
||||||
|
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");
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
memset(buffer, 0, fatsz);
|
||||||
|
boot->NumFree = 0;
|
||||||
|
p = buffer;
|
||||||
|
if (correct_fat) {
|
||||||
|
*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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* use same FAT signature as the old FAT has */
|
||||||
|
int count;
|
||||||
|
u_char *old_fat;
|
||||||
|
|
||||||
|
switch (boot->ClustMask) {
|
||||||
|
case CLUST32_MASK:
|
||||||
|
count = 8;
|
||||||
|
break;
|
||||||
|
case CLUST16_MASK:
|
||||||
|
count = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
count = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0,
|
||||||
|
&old_fat)) {
|
||||||
|
free(buffer);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(p, old_fat, count);
|
||||||
|
free(old_fat);
|
||||||
|
p += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
|
||||||
|
switch (boot->ClustMask) {
|
||||||
|
case CLUST32_MASK:
|
||||||
|
if (fat[cl].next == CLUST_FREE)
|
||||||
|
boot->NumFree++;
|
||||||
|
*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++ = (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++) {
|
||||||
|
off = boot->ResSectors + i * boot->FATsecs;
|
||||||
|
off *= boot->BytesPerSec;
|
||||||
|
if (lseek(fs, off, SEEK_SET) != off
|
||||||
|
|| write(fs, buffer, fatsz) != fatsz) {
|
||||||
|
perror("Unable to write FAT");
|
||||||
|
ret = FSFATAL; /* Return immediately? XXX */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a complete in-memory FAT for lost cluster chains
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
checklost(dosfs, boot, fat)
|
||||||
|
int dosfs;
|
||||||
|
struct bootblock *boot;
|
||||||
|
struct fatEntry *fat;
|
||||||
|
{
|
||||||
|
cl_t head;
|
||||||
|
int mod = FSOK;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
|
||||||
|
/* find next untravelled chain */
|
||||||
|
if (fat[head].head != head
|
||||||
|
|| fat[head].next == CLUST_FREE
|
||||||
|
|| (fat[head].next >= CLUST_RSRVD
|
||||||
|
&& fat[head].next < CLUST_EOFS)
|
||||||
|
|| (fat[head].flags & FAT_USED))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n",
|
||||||
|
head, fat[head].length);
|
||||||
|
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;
|
||||||
|
}
|
114
sbin/fsck_msdosfs/fsck_msdosfs.8
Normal file
114
sbin/fsck_msdosfs/fsck_msdosfs.8
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
.\" $NetBSD: fsck_msdos.8,v 1.9 1997/10/17 11:19:58 ws Exp $
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.\" Copyright (C) 1995 Wolfgang Solfrank
|
||||||
|
.\" Copyright (c) 1995 Martin Husemann
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\" 3. All advertising materials mentioning features or use of this software
|
||||||
|
.\" must display the following acknowledgement:
|
||||||
|
.\" This product includes software developed by Martin Husemann
|
||||||
|
.\" and Wolfgang Solfrank.
|
||||||
|
.\" 4. Neither the name of the University nor the names of its contributors
|
||||||
|
.\" may be used to endorse or promote products derived from this software
|
||||||
|
.\" without specific prior written permission.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
.\" IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.Dd August 13, 1995
|
||||||
|
.Dt FSCK_MSDOS 8
|
||||||
|
.Os NetBSD 1.1a
|
||||||
|
.Sh NAME
|
||||||
|
.Nm fsck_msdos
|
||||||
|
.Nd DOS/Windows (FAT) filesystem consistency checker
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm ""
|
||||||
|
.Fl p
|
||||||
|
.Op Fl f
|
||||||
|
.Ar filesystem ...
|
||||||
|
.Nm ""
|
||||||
|
.Op Fl fny
|
||||||
|
.Ar filesystem ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility verifies and repairs
|
||||||
|
.Tn FAT
|
||||||
|
filesystems (more commonly known
|
||||||
|
as
|
||||||
|
.Tn DOS
|
||||||
|
filesystems).
|
||||||
|
.Pp
|
||||||
|
The first form of
|
||||||
|
.Nm
|
||||||
|
preens the specified filesystems.
|
||||||
|
It is normally started by
|
||||||
|
.Xr fsck 8
|
||||||
|
run from
|
||||||
|
.Pa /etc/rc
|
||||||
|
during automatic reboot, when a FAT filesystem is detected.
|
||||||
|
When preening file systems,
|
||||||
|
.Nm
|
||||||
|
will fix common inconsistencies non-interactively. If
|
||||||
|
more serious problems are found,
|
||||||
|
.Nm
|
||||||
|
does not try to fix them, indicates that it was not
|
||||||
|
successful, and exits.
|
||||||
|
.Pp
|
||||||
|
The second form of
|
||||||
|
.Nm
|
||||||
|
checks the specified file systems and tries to repair all
|
||||||
|
detected inconsistencies, requesting confirmation before
|
||||||
|
making any changes.
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -hang -offset indent
|
||||||
|
.It Fl f
|
||||||
|
This option is ignored by
|
||||||
|
.Nm "" ,
|
||||||
|
and is present only for compatibility with programs that
|
||||||
|
check other file system types for consistency, such as
|
||||||
|
.Xr fsck_ffs 8 .
|
||||||
|
.It Fl n
|
||||||
|
Causes
|
||||||
|
.Nm
|
||||||
|
to assume no as the answer to all operator
|
||||||
|
questions, except
|
||||||
|
.Dq CONTINUE? .
|
||||||
|
.It Fl p
|
||||||
|
Preen the specified filesystems.
|
||||||
|
.It Fl y
|
||||||
|
Causes
|
||||||
|
.Nm
|
||||||
|
to assume yes as the answer to all operator questions.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr fsck 8 ,
|
||||||
|
.Xr fsck_ffs 8 ,
|
||||||
|
.Xr mount_msdos 8
|
||||||
|
.Sh BUGS
|
||||||
|
.Nm
|
||||||
|
is still under construction.
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
command first appeared in
|
||||||
|
.Fx 4.4 .
|
165
sbin/fsck_msdosfs/main.c
Normal file
165
sbin/fsck_msdosfs/main.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995 Wolfgang Solfrank
|
||||||
|
* Copyright (c) 1995 Martin Husemann
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Martin Husemann
|
||||||
|
* and Wolfgang Solfrank.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: main.c,v 1.10 1997/10/01 02:18:14 enami Exp $");
|
||||||
|
static const char rcsid[] =
|
||||||
|
"$FreeBSD$";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#if __STDC__
|
||||||
|
#include <stdarg.h>
|
||||||
|
#else
|
||||||
|
#include <varargs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "fsutil.h"
|
||||||
|
#include "ext.h"
|
||||||
|
|
||||||
|
int alwaysno; /* assume "no" for all questions */
|
||||||
|
int alwaysyes; /* assume "yes" for all questions */
|
||||||
|
int preen; /* set when preening */
|
||||||
|
int rdonly; /* device is opened read only (supersedes above) */
|
||||||
|
|
||||||
|
static void usage __P((void));
|
||||||
|
int main __P((int, char **));
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
errexit("Usage: fsck_msdos [-fnpy] filesystem ... \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
int ret = 0, erg;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "pynf")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'f':
|
||||||
|
/*
|
||||||
|
* We are always forced, since we don't
|
||||||
|
* have a clean flag
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
alwaysno = 1;
|
||||||
|
alwaysyes = preen = 0;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
alwaysyes = 1;
|
||||||
|
alwaysno = preen = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
preen = 1;
|
||||||
|
alwaysyes = alwaysno = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
while (--argc >= 0) {
|
||||||
|
setcdevname(*argv, preen);
|
||||||
|
erg = checkfilesys(*argv++);
|
||||||
|
if (erg > ret)
|
||||||
|
ret = erg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*VARARGS*/
|
||||||
|
int
|
||||||
|
#if __STDC__
|
||||||
|
ask(int def, const char *fmt, ...)
|
||||||
|
#else
|
||||||
|
ask(def, fmt, va_alist)
|
||||||
|
int def;
|
||||||
|
char *fmt;
|
||||||
|
va_dcl
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
char prompt[256];
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (preen) {
|
||||||
|
if (rdonly)
|
||||||
|
def = 0;
|
||||||
|
if (def)
|
||||||
|
printf("FIXED\n");
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __STDC__
|
||||||
|
va_start(ap, fmt);
|
||||||
|
#else
|
||||||
|
va_start(ap);
|
||||||
|
#endif
|
||||||
|
vsnprintf(prompt, sizeof(prompt), fmt, ap);
|
||||||
|
if (alwaysyes || rdonly) {
|
||||||
|
printf("%s? %s\n", prompt, rdonly ? "no" : "yes");
|
||||||
|
return !rdonly;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
printf("%s? [yn] ", prompt);
|
||||||
|
fflush(stdout);
|
||||||
|
c = getchar();
|
||||||
|
while (c != '\n' && getchar() != '\n')
|
||||||
|
if (feof(stdin))
|
||||||
|
return 0;
|
||||||
|
} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
|
||||||
|
return c == 'y' || c == 'Y';
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user