Add fsck_msdosfs.

Obtained from:	NetBSD
This commit is contained in:
obrien 2001-07-09 10:35:18 +00:00
parent eaa6ee03b8
commit a72361c15b
9 changed files with 2716 additions and 0 deletions

View 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
View 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
View 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, &currentFat);
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

File diff suppressed because it is too large Load Diff

144
sbin/fsck_msdosfs/dosfs.h Normal file
View 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
View 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
View 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;
}

View 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
View 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';
}