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/* 526702a4436d04b4fbe1be2f11ce5c1cd9ce64574cSan Mehat * If the FAT > this size then skip comparing, lest we risk 536702a4436d04b4fbe1be2f11ce5c1cd9ce64574cSan Mehat * OOMing the framework. in the future we need to just re-write 546702a4436d04b4fbe1be2f11ce5c1cd9ce64574cSan Mehat * this whole thing and optimize for less memory 5558d4c6c35633437182289e3d226d156d31d3e801San Mehat */ 566702a4436d04b4fbe1be2f11ce5c1cd9ce64574cSan Mehat#define FAT_COMPARE_MAX_KB 4096 5758d4c6c35633437182289e3d226d156d31d3e801San Mehat 5858d4c6c35633437182289e3d226d156d31d3e801San Mehatint 5958d4c6c35633437182289e3d226d156d31d3e801San Mehatcheckfilesys(const char *fname) 6058d4c6c35633437182289e3d226d156d31d3e801San Mehat{ 6158d4c6c35633437182289e3d226d156d31d3e801San Mehat int dosfs; 6258d4c6c35633437182289e3d226d156d31d3e801San Mehat struct bootblock boot; 6358d4c6c35633437182289e3d226d156d31d3e801San Mehat struct fatEntry *fat = NULL; 6458d4c6c35633437182289e3d226d156d31d3e801San Mehat int i, finish_dosdirsection=0; 6558d4c6c35633437182289e3d226d156d31d3e801San Mehat int mod = 0; 6658d4c6c35633437182289e3d226d156d31d3e801San Mehat int ret = 8; 6758d4c6c35633437182289e3d226d156d31d3e801San Mehat int quiet = 0; 6858d4c6c35633437182289e3d226d156d31d3e801San Mehat int skip_fat_compare = 0; 6958d4c6c35633437182289e3d226d156d31d3e801San Mehat 7058d4c6c35633437182289e3d226d156d31d3e801San Mehat rdonly = alwaysno; 7158d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 7258d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** %s", fname); 7358d4c6c35633437182289e3d226d156d31d3e801San Mehat 7458d4c6c35633437182289e3d226d156d31d3e801San Mehat dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0); 7558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (dosfs < 0 && !rdonly) { 7658d4c6c35633437182289e3d226d156d31d3e801San Mehat dosfs = open(fname, O_RDONLY, 0); 7758d4c6c35633437182289e3d226d156d31d3e801San Mehat if (dosfs >= 0) 7858d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn(" (NO WRITE)\n"); 7958d4c6c35633437182289e3d226d156d31d3e801San Mehat else if (!quiet) 8058d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("\n"); 8158d4c6c35633437182289e3d226d156d31d3e801San Mehat rdonly = 1; 8258d4c6c35633437182289e3d226d156d31d3e801San Mehat } else if (!quiet) 8358d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("\n"); 8458d4c6c35633437182289e3d226d156d31d3e801San Mehat 8558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (dosfs < 0) { 8658d4c6c35633437182289e3d226d156d31d3e801San Mehat perror("Can't open"); 8758d4c6c35633437182289e3d226d156d31d3e801San Mehat return 8; 8858d4c6c35633437182289e3d226d156d31d3e801San Mehat } 8958d4c6c35633437182289e3d226d156d31d3e801San Mehat 90d8775a29ea7eac2e5f1504dd21da3725b93b3036San Mehat if (readboot(dosfs, &boot) == FSFATAL) { 9158d4c6c35633437182289e3d226d156d31d3e801San Mehat close(dosfs); 9258d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("\n"); 9358d4c6c35633437182289e3d226d156d31d3e801San Mehat return 8; 9458d4c6c35633437182289e3d226d156d31d3e801San Mehat } 9558d4c6c35633437182289e3d226d156d31d3e801San Mehat 9658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (skipclean && preen && checkdirty(dosfs, &boot)) { 9758d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("%s: ", fname); 9858d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("FILESYSTEM CLEAN; SKIPPING CHECKS\n"); 9958d4c6c35633437182289e3d226d156d31d3e801San Mehat ret = 0; 10058d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 10158d4c6c35633437182289e3d226d156d31d3e801San Mehat } 10258d4c6c35633437182289e3d226d156d31d3e801San Mehat 10358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (((boot.FATsecs * boot.BytesPerSec) / 1024) > FAT_COMPARE_MAX_KB) 10458d4c6c35633437182289e3d226d156d31d3e801San Mehat skip_fat_compare = 1; 10558d4c6c35633437182289e3d226d156d31d3e801San Mehat 10658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) { 10758d4c6c35633437182289e3d226d156d31d3e801San Mehat if (skip_fat_compare) 10858d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 1 - Read FAT (compare skipped)\n"); 10958d4c6c35633437182289e3d226d156d31d3e801San Mehat else if (boot.ValidFat < 0) 11058d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 1 - Read and Compare FATs\n"); 11158d4c6c35633437182289e3d226d156d31d3e801San Mehat else 11258d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 1 - Read FAT\n"); 11358d4c6c35633437182289e3d226d156d31d3e801San Mehat } 11458d4c6c35633437182289e3d226d156d31d3e801San Mehat 11558d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat); 11658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) { 11711877c86e96c485b9632ea758b225bcacf6e7670San Mehat printf("Fatal error during readfat()\n"); 11858d4c6c35633437182289e3d226d156d31d3e801San Mehat close(dosfs); 11958d4c6c35633437182289e3d226d156d31d3e801San Mehat return 8; 12058d4c6c35633437182289e3d226d156d31d3e801San Mehat } 12158d4c6c35633437182289e3d226d156d31d3e801San Mehat 12258d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!skip_fat_compare && boot.ValidFat < 0) 12358d4c6c35633437182289e3d226d156d31d3e801San Mehat for (i = 1; i < (int)boot.FATs; i++) { 12458d4c6c35633437182289e3d226d156d31d3e801San Mehat struct fatEntry *currentFat; 12558d4c6c35633437182289e3d226d156d31d3e801San Mehat 12658d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= readfat(dosfs, &boot, i, ¤tFat); 12758d4c6c35633437182289e3d226d156d31d3e801San Mehat 12811877c86e96c485b9632ea758b225bcacf6e7670San Mehat if (mod & FSFATAL) { 12911877c86e96c485b9632ea758b225bcacf6e7670San Mehat printf("Fatal error during readfat() for comparison\n"); 13058d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 13111877c86e96c485b9632ea758b225bcacf6e7670San Mehat } 13258d4c6c35633437182289e3d226d156d31d3e801San Mehat 13358d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= comparefat(&boot, fat, currentFat, i); 13458d4c6c35633437182289e3d226d156d31d3e801San Mehat free(currentFat); 13511877c86e96c485b9632ea758b225bcacf6e7670San Mehat if (mod & FSFATAL) { 13611877c86e96c485b9632ea758b225bcacf6e7670San Mehat printf("Fatal error during FAT comparison\n"); 13758d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 13811877c86e96c485b9632ea758b225bcacf6e7670San Mehat } 13958d4c6c35633437182289e3d226d156d31d3e801San Mehat } 14058d4c6c35633437182289e3d226d156d31d3e801San Mehat 14158d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 14258d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 2 - Check Cluster Chains\n"); 14358d4c6c35633437182289e3d226d156d31d3e801San Mehat 14458d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= checkfat(&boot, fat); 14511877c86e96c485b9632ea758b225bcacf6e7670San Mehat if (mod & FSFATAL) { 14611877c86e96c485b9632ea758b225bcacf6e7670San Mehat printf("Fatal error during FAT check\n"); 14758d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 14811877c86e96c485b9632ea758b225bcacf6e7670San Mehat } 14958d4c6c35633437182289e3d226d156d31d3e801San Mehat /* delay writing FATs */ 15058d4c6c35633437182289e3d226d156d31d3e801San Mehat 15158d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 15258d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 3 - Checking Directories\n"); 15358d4c6c35633437182289e3d226d156d31d3e801San Mehat 15458d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= resetDosDirSection(&boot, fat); 15558d4c6c35633437182289e3d226d156d31d3e801San Mehat finish_dosdirsection = 1; 15611877c86e96c485b9632ea758b225bcacf6e7670San Mehat if (mod & FSFATAL) { 15711877c86e96c485b9632ea758b225bcacf6e7670San Mehat printf("Fatal error during resetDosDirSection()\n"); 15858d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 15911877c86e96c485b9632ea758b225bcacf6e7670San Mehat } 16058d4c6c35633437182289e3d226d156d31d3e801San Mehat /* delay writing FATs */ 16158d4c6c35633437182289e3d226d156d31d3e801San Mehat 16258d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= handleDirTree(dosfs, &boot, fat); 16358d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 16458d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 16558d4c6c35633437182289e3d226d156d31d3e801San Mehat 16658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (!quiet) 16758d4c6c35633437182289e3d226d156d31d3e801San Mehat printf("** Phase 4 - Checking for Lost Files\n"); 16858d4c6c35633437182289e3d226d156d31d3e801San Mehat 16958d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= checklost(dosfs, &boot, fat); 17058d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATAL) 17158d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 17258d4c6c35633437182289e3d226d156d31d3e801San Mehat 17358d4c6c35633437182289e3d226d156d31d3e801San Mehat /* now write the FATs */ 17458d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSFATMOD) { 17558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (ask(1, "Update FATs")) { 17658d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT); 17711877c86e96c485b9632ea758b225bcacf6e7670San Mehat if (mod & FSFATAL) { 17811877c86e96c485b9632ea758b225bcacf6e7670San Mehat printf("Fatal error during writefat()\n"); 17958d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 18011877c86e96c485b9632ea758b225bcacf6e7670San Mehat } 18158d4c6c35633437182289e3d226d156d31d3e801San Mehat } else 18258d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= FSERROR; 18358d4c6c35633437182289e3d226d156d31d3e801San Mehat } 18458d4c6c35633437182289e3d226d156d31d3e801San Mehat 18558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (boot.NumBad) 18658d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n", 18758d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFiles, 18858d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFree * boot.ClusterSize / 1024, boot.NumFree, 18958d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumBad * boot.ClusterSize / 1024, boot.NumBad); 19058d4c6c35633437182289e3d226d156d31d3e801San Mehat else 19158d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("%d files, %d free (%d clusters)\n", 19258d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFiles, 19358d4c6c35633437182289e3d226d156d31d3e801San Mehat boot.NumFree * boot.ClusterSize / 1024, boot.NumFree); 19458d4c6c35633437182289e3d226d156d31d3e801San Mehat 19558d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod && (mod & FSERROR) == 0) { 19658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSDIRTY) { 19758d4c6c35633437182289e3d226d156d31d3e801San Mehat if (ask(1, "MARK FILE SYSTEM CLEAN") == 0) 19858d4c6c35633437182289e3d226d156d31d3e801San Mehat mod &= ~FSDIRTY; 19958d4c6c35633437182289e3d226d156d31d3e801San Mehat 20058d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & FSDIRTY) { 20158d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("MARKING FILE SYSTEM CLEAN\n"); 20258d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= writefat(dosfs, &boot, fat, 1); 20358d4c6c35633437182289e3d226d156d31d3e801San Mehat } else { 20458d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n"); 20558d4c6c35633437182289e3d226d156d31d3e801San Mehat mod |= FSERROR; /* file system not clean */ 20658d4c6c35633437182289e3d226d156d31d3e801San Mehat } 20758d4c6c35633437182289e3d226d156d31d3e801San Mehat } 20858d4c6c35633437182289e3d226d156d31d3e801San Mehat } 20958d4c6c35633437182289e3d226d156d31d3e801San Mehat 21058d4c6c35633437182289e3d226d156d31d3e801San Mehat if (mod & (FSFATAL | FSERROR)) 21158d4c6c35633437182289e3d226d156d31d3e801San Mehat goto out; 21258d4c6c35633437182289e3d226d156d31d3e801San Mehat 21358d4c6c35633437182289e3d226d156d31d3e801San Mehat ret = 0; 21458d4c6c35633437182289e3d226d156d31d3e801San Mehat 21558d4c6c35633437182289e3d226d156d31d3e801San Mehat out: 21658d4c6c35633437182289e3d226d156d31d3e801San Mehat if (finish_dosdirsection) 21758d4c6c35633437182289e3d226d156d31d3e801San Mehat finishDosDirSection(); 21858d4c6c35633437182289e3d226d156d31d3e801San Mehat free(fat); 21958d4c6c35633437182289e3d226d156d31d3e801San Mehat close(dosfs); 22058d4c6c35633437182289e3d226d156d31d3e801San Mehat 22111877c86e96c485b9632ea758b225bcacf6e7670San Mehat if (mod & (FSFATMOD|FSDIRMOD)) { 22258d4c6c35633437182289e3d226d156d31d3e801San Mehat pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 22311877c86e96c485b9632ea758b225bcacf6e7670San Mehat return 4; 22411877c86e96c485b9632ea758b225bcacf6e7670San Mehat } 22558d4c6c35633437182289e3d226d156d31d3e801San Mehat 22658d4c6c35633437182289e3d226d156d31d3e801San Mehat return ret; 22758d4c6c35633437182289e3d226d156d31d3e801San Mehat} 228