Add fsck_msdosfs.
Obtained from: NetBSD
This commit is contained in:
parent
eaa6ee03b8
commit
a72361c15b
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