check.c revision 58d4c6c35633437182289e3d226d156d31d3e801
158d4c6c35633437182289e3d226d156d31d3e801San Mehat/* 258d4c6c35633437182289e3d226d156d31d3e801San Mehat * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 358d4c6c35633437182289e3d226d156d31d3e801San Mehat * Copyright (c) 1995 Martin Husemann 458d4c6c35633437182289e3d226d156d31d3e801San Mehat * 558d4c6c35633437182289e3d226d156d31d3e801San Mehat * Redistribution and use in source and binary forms, with or without 658d4c6c35633437182289e3d226d156d31d3e801San Mehat * modification, are permitted provided that the following conditions 758d4c6c35633437182289e3d226d156d31d3e801San Mehat * are met: 858d4c6c35633437182289e3d226d156d31d3e801San Mehat * 1. Redistributions of source code must retain the above copyright 958d4c6c35633437182289e3d226d156d31d3e801San Mehat * notice, this list of conditions and the following disclaimer. 1058d4c6c35633437182289e3d226d156d31d3e801San Mehat * 2. Redistributions in binary form must reproduce the above copyright 1158d4c6c35633437182289e3d226d156d31d3e801San Mehat * notice, this list of conditions and the following disclaimer in the 1258d4c6c35633437182289e3d226d156d31d3e801San Mehat * documentation and/or other materials provided with the distribution. 1358d4c6c35633437182289e3d226d156d31d3e801San Mehat * 3. All advertising materials mentioning features or use of this software 1458d4c6c35633437182289e3d226d156d31d3e801San Mehat * must display the following acknowledgement: 1558d4c6c35633437182289e3d226d156d31d3e801San Mehat * This product includes software developed by Martin Husemann 1658d4c6c35633437182289e3d226d156d31d3e801San Mehat * and Wolfgang Solfrank. 1758d4c6c35633437182289e3d226d156d31d3e801San Mehat * 4. Neither the name of the University nor the names of its contributors 1858d4c6c35633437182289e3d226d156d31d3e801San Mehat * may be used to endorse or promote products derived from this software 1958d4c6c35633437182289e3d226d156d31d3e801San Mehat * without specific prior written permission. 2058d4c6c35633437182289e3d226d156d31d3e801San Mehat * 2158d4c6c35633437182289e3d226d156d31d3e801San Mehat * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2258d4c6c35633437182289e3d226d156d31d3e801San Mehat * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2358d4c6c35633437182289e3d226d156d31d3e801San Mehat * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2458d4c6c35633437182289e3d226d156d31d3e801San Mehat * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2558d4c6c35633437182289e3d226d156d31d3e801San Mehat * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2658d4c6c35633437182289e3d226d156d31d3e801San Mehat * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2758d4c6c35633437182289e3d226d156d31d3e801San Mehat * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2858d4c6c35633437182289e3d226d156d31d3e801San Mehat * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2958d4c6c35633437182289e3d226d156d31d3e801San Mehat * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3058d4c6c35633437182289e3d226d156d31d3e801San Mehat * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3158d4c6c35633437182289e3d226d156d31d3e801San Mehat */ 3258d4c6c35633437182289e3d226d156d31d3e801San Mehat 3358d4c6c35633437182289e3d226d156d31d3e801San Mehat 3458d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <sys/cdefs.h> 3558d4c6c35633437182289e3d226d156d31d3e801San Mehat#ifndef lint 3658d4c6c35633437182289e3d226d156d31d3e801San Mehat__RCSID("$NetBSD: check.c,v 1.10 2000/04/25 23:02:51 jdolecek Exp $"); 3758d4c6c35633437182289e3d226d156d31d3e801San Mehatstatic const char rcsid[] = 3858d4c6c35633437182289e3d226d156d31d3e801San Mehat "$FreeBSD: src/sbin/fsck_msdosfs/check.c,v 1.10 2004/02/05 15:47:46 bde Exp $"; 3958d4c6c35633437182289e3d226d156d31d3e801San Mehat#endif /* not lint */ 4058d4c6c35633437182289e3d226d156d31d3e801San Mehat 4158d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <stdlib.h> 4258d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <string.h> 4358d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <ctype.h> 4458d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <stdio.h> 4558d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <unistd.h> 4658d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <fcntl.h> 4758d4c6c35633437182289e3d226d156d31d3e801San Mehat 4858d4c6c35633437182289e3d226d156d31d3e801San Mehat#include "ext.h" 4958d4c6c35633437182289e3d226d156d31d3e801San Mehat#include "fsutil.h" 5058d4c6c35633437182289e3d226d156d31d3e801San Mehat 5158d4c6c35633437182289e3d226d156d31d3e801San Mehat/* 5258d4c6c35633437182289e3d226d156d31d3e801San Mehat * If the FAT > this size then skip comparing 5358d4c6c35633437182289e3d226d156d31d3e801San Mehat */ 5458d4c6c35633437182289e3d226d156d31d3e801San Mehat#define FAT_COMPARE_MAX_KB 8192 5558d4c6c35633437182289e3d226d156d31d3e801San Mehat 5658d4c6c35633437182289e3d226d156d31d3e801San Mehatint 5758d4c6c35633437182289e3d226d156d31d3e801San Mehatcheckfilesys(const char *fname) 5858d4c6c35633437182289e3d226d156d31d3e801San Mehat{ 5958d4c6c35633437182289e3d226d156d31d3e801San Mehat int dosfs; 6058d4c6c35633437182289e3d226d156d31d3e801San Mehat struct bootblock boot; 6158d4c6c35633437182289e3d226d156d31d3e801San Mehat struct fatEntry *fat = NULL; 6258d4c6c35633437182289e3d226d156d31d3e801San Mehat int i, finish_dosdirsection=0; 6358d4c6c35633437182289e3d226d156d31d3e801San Mehat int mod = 0; 6458d4c6c35633437182289e3d226d156d31d3e801San Mehat int ret = 8; 6558d4c6c35633437182289e3d226d156d31d3e801San Mehat int quiet = 0; 6658d4c6c35633437182289e3d226d156d31d3e801San Mehat int skip_fat_compare = 0; 6758d4c6c35633437182289e3d226d156d31d3e801San Mehat 6858d4c6c35633437182289e3d226d156d31d3e801San Mehat rdonly = alwaysno; 6958d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 7058d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** %s", fname); 7158d4c6c35633437182289e3d226d156d31d3e801San Mehat 7258d4c6c35633437182289e3d226d156d31d3e801San Mehat dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0); 7358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (dosfs < 0 && !rdonly) { 7458d4c6c35633437182289e3d226d156d31d3e801San Mehat dosfs = open(fname, O_RDONLY, 0); 7558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (dosfs >= 0) 7658d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn(" (NO WRITE)\n"); 7758d4c6c35633437182289e3d226d156d31d3e801San Mehat else if (!quiet) 7858d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("\n"); 7958d4c6c35633437182289e3d226d156d31d3e801San Mehat rdonly = 1; 8058d4c6c35633437182289e3d226d156d31d3e801San Mehat } else if (!quiet) 8158d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("\n"); 8258d4c6c35633437182289e3d226d156d31d3e801San Mehat 8358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (dosfs < 0) { 8458d4c6c35633437182289e3d226d156d31d3e801San Mehat perror("Can't open"); 8558d4c6c35633437182289e3d226d156d31d3e801San Mehat return 8; 8658d4c6c35633437182289e3d226d156d31d3e801San Mehat } 8758d4c6c35633437182289e3d226d156d31d3e801San Mehat 8858d4c6c35633437182289e3d226d156d31d3e801San Mehat if (readboot(dosfs, &boot) != FSOK) { 8958d4c6c35633437182289e3d226d156d31d3e801San Mehat close(dosfs); 9058d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("\n"); 9158d4c6c35633437182289e3d226d156d31d3e801San Mehat return 8; 9258d4c6c35633437182289e3d226d156d31d3e801San Mehat } 9358d4c6c35633437182289e3d226d156d31d3e801San Mehat 9458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (skipclean && preen && checkdirty(dosfs, &boot)) { 9558d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("%s: ", fname); 9658d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("FILESYSTEM CLEAN; SKIPPING CHECKS\n"); 9758d4c6c35633437182289e3d226d156d31d3e801San Mehat ret = 0; 9858d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 9958d4c6c35633437182289e3d226d156d31d3e801San Mehat } 10058d4c6c35633437182289e3d226d156d31d3e801San Mehat 10158d4c6c35633437182289e3d226d156d31d3e801San Mehat if (((boot.FATsecs * boot.BytesPerSec) / 1024) > FAT_COMPARE_MAX_KB) 10258d4c6c35633437182289e3d226d156d31d3e801San Mehat skip_fat_compare = 1; 10358d4c6c35633437182289e3d226d156d31d3e801San Mehat 10458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) { 10558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (skip_fat_compare) 10658d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 1 - Read FAT (compare skipped)\n"); 10758d4c6c35633437182289e3d226d156d31d3e801San Mehat else if (boot.ValidFat < 0) 10858d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 1 - Read and Compare FATs\n"); 10958d4c6c35633437182289e3d226d156d31d3e801San Mehat else 11058d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 1 - Read FAT\n"); 11158d4c6c35633437182289e3d226d156d31d3e801San Mehat } 11258d4c6c35633437182289e3d226d156d31d3e801San Mehat 11358d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat); 11458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) { 11558d4c6c35633437182289e3d226d156d31d3e801San Mehat close(dosfs); 11658d4c6c35633437182289e3d226d156d31d3e801San Mehat return 8; 11758d4c6c35633437182289e3d226d156d31d3e801San Mehat } 11858d4c6c35633437182289e3d226d156d31d3e801San Mehat 11958d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!skip_fat_compare && boot.ValidFat < 0) 12058d4c6c35633437182289e3d226d156d31d3e801San Mehat for (i = 1; i < (int)boot.FATs; i++) { 12158d4c6c35633437182289e3d226d156d31d3e801San Mehat struct fatEntry *currentFat; 12258d4c6c35633437182289e3d226d156d31d3e801San Mehat 12358d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= readfat(dosfs, &boot, i, ¤tFat); 12458d4c6c35633437182289e3d226d156d31d3e801San Mehat 12558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 12658d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 12758d4c6c35633437182289e3d226d156d31d3e801San Mehat 12858d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= comparefat(&boot, fat, currentFat, i); 12958d4c6c35633437182289e3d226d156d31d3e801San Mehat free(currentFat); 13058d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 13158d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 13258d4c6c35633437182289e3d226d156d31d3e801San Mehat } 13358d4c6c35633437182289e3d226d156d31d3e801San Mehat 13458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 13558d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 2 - Check Cluster Chains\n"); 13658d4c6c35633437182289e3d226d156d31d3e801San Mehat 13758d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= checkfat(&boot, fat); 13858d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 13958d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 14058d4c6c35633437182289e3d226d156d31d3e801San Mehat /* delay writing FATs */ 14158d4c6c35633437182289e3d226d156d31d3e801San Mehat 14258d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 14358d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 3 - Checking Directories\n"); 14458d4c6c35633437182289e3d226d156d31d3e801San Mehat 14558d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= resetDosDirSection(&boot, fat); 14658d4c6c35633437182289e3d226d156d31d3e801San Mehat finish_dosdirsection = 1; 14758d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 14858d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 14958d4c6c35633437182289e3d226d156d31d3e801San Mehat /* delay writing FATs */ 15058d4c6c35633437182289e3d226d156d31d3e801San Mehat 15158d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= handleDirTree(dosfs, &boot, fat); 15258d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 15358d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 15458d4c6c35633437182289e3d226d156d31d3e801San Mehat 15558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 15658d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 4 - Checking for Lost Files\n"); 15758d4c6c35633437182289e3d226d156d31d3e801San Mehat 15858d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= checklost(dosfs, &boot, fat); 15958d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 16058d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 16158d4c6c35633437182289e3d226d156d31d3e801San Mehat 16258d4c6c35633437182289e3d226d156d31d3e801San Mehat /* now write the FATs */ 16358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATMOD) { 16458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (ask(1, "Update FATs")) { 16558d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT); 16658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 16758d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 16858d4c6c35633437182289e3d226d156d31d3e801San Mehat } else 16958d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= FSERROR; 17058d4c6c35633437182289e3d226d156d31d3e801San Mehat } 17158d4c6c35633437182289e3d226d156d31d3e801San Mehat 17258d4c6c35633437182289e3d226d156d31d3e801San Mehat if (boot.NumBad) 17358d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n", 17458d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFiles, 17558d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFree * boot.ClusterSize / 1024, boot.NumFree, 17658d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumBad * boot.ClusterSize / 1024, boot.NumBad); 17758d4c6c35633437182289e3d226d156d31d3e801San Mehat else 17858d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("%d files, %d free (%d clusters)\n", 17958d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFiles, 18058d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFree * boot.ClusterSize / 1024, boot.NumFree); 18158d4c6c35633437182289e3d226d156d31d3e801San Mehat 18258d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod && (mod & FSERROR) == 0) { 18358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSDIRTY) { 18458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (ask(1, "MARK FILE SYSTEM CLEAN") == 0) 18558d4c6c35633437182289e3d226d156d31d3e801San Mehat mod &= ~FSDIRTY; 18658d4c6c35633437182289e3d226d156d31d3e801San Mehat 18758d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSDIRTY) { 18858d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("MARKING FILE SYSTEM CLEAN\n"); 18958d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= writefat(dosfs, &boot, fat, 1); 19058d4c6c35633437182289e3d226d156d31d3e801San Mehat } else { 19158d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n"); 19258d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= FSERROR; /* file system not clean */ 19358d4c6c35633437182289e3d226d156d31d3e801San Mehat } 19458d4c6c35633437182289e3d226d156d31d3e801San Mehat } 19558d4c6c35633437182289e3d226d156d31d3e801San Mehat } 19658d4c6c35633437182289e3d226d156d31d3e801San Mehat 19758d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & (FSFATAL | FSERROR)) 19858d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 19958d4c6c35633437182289e3d226d156d31d3e801San Mehat 20058d4c6c35633437182289e3d226d156d31d3e801San Mehat ret = 0; 20158d4c6c35633437182289e3d226d156d31d3e801San Mehat 20258d4c6c35633437182289e3d226d156d31d3e801San Mehat out: 20358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (finish_dosdirsection) 20458d4c6c35633437182289e3d226d156d31d3e801San Mehat finishDosDirSection(); 20558d4c6c35633437182289e3d226d156d31d3e801San Mehat free(fat); 20658d4c6c35633437182289e3d226d156d31d3e801San Mehat close(dosfs); 20758d4c6c35633437182289e3d226d156d31d3e801San Mehat 20858d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & (FSFATMOD|FSDIRMOD)) 20958d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 21058d4c6c35633437182289e3d226d156d31d3e801San Mehat 21158d4c6c35633437182289e3d226d156d31d3e801San Mehat return ret; 21258d4c6c35633437182289e3d226d156d31d3e801San Mehat} 213