check.c revision 123873
179455Sobrien/* 279455Sobrien * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 379455Sobrien * Copyright (c) 1995 Martin Husemann 479455Sobrien * 579455Sobrien * Redistribution and use in source and binary forms, with or without 679455Sobrien * modification, are permitted provided that the following conditions 779455Sobrien * are met: 879455Sobrien * 1. Redistributions of source code must retain the above copyright 979455Sobrien * notice, this list of conditions and the following disclaimer. 1079455Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1179455Sobrien * notice, this list of conditions and the following disclaimer in the 1279455Sobrien * documentation and/or other materials provided with the distribution. 1379455Sobrien * 3. All advertising materials mentioning features or use of this software 1479455Sobrien * must display the following acknowledgement: 1579455Sobrien * This product includes software developed by Martin Husemann 1679455Sobrien * and Wolfgang Solfrank. 1779455Sobrien * 4. Neither the name of the University nor the names of its contributors 1879455Sobrien * may be used to endorse or promote products derived from this software 1979455Sobrien * without specific prior written permission. 2079455Sobrien * 2179455Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2279455Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2379455Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2479455Sobrien * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2579455Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2679455Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2779455Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2879455Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2979455Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3079455Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3179455Sobrien */ 3279455Sobrien 3379455Sobrien 3479455Sobrien#include <sys/cdefs.h> 3579455Sobrien#ifndef lint 3679455Sobrien__RCSID("$NetBSD: check.c,v 1.10 2000/04/25 23:02:51 jdolecek Exp $"); 3779455Sobrienstatic const char rcsid[] = 3879455Sobrien "$FreeBSD: head/sbin/fsck_msdosfs/check.c 123873 2003-12-26 17:19:19Z trhodes $"; 3979455Sobrien#endif /* not lint */ 4079455Sobrien 4179455Sobrien#include <stdlib.h> 4279455Sobrien#include <string.h> 4379455Sobrien#include <ctype.h> 4479455Sobrien#include <stdio.h> 4579455Sobrien#include <unistd.h> 4679455Sobrien#include <fcntl.h> 4779455Sobrien 4879455Sobrien#include "ext.h" 4979455Sobrien#include "fsutil.h" 5079455Sobrien 5179455Sobrienint 52121726Strhodescheckfilesys(const char *fname) 5379455Sobrien{ 5479455Sobrien int dosfs; 5579455Sobrien struct bootblock boot; 5679455Sobrien struct fatEntry *fat = NULL; 5779455Sobrien int i, finish_dosdirsection=0; 5879455Sobrien int mod = 0; 5979455Sobrien int ret = 8; 6079455Sobrien 6179455Sobrien rdonly = alwaysno; 6279455Sobrien if (!preen) 6379455Sobrien printf("** %s", fname); 6479455Sobrien 6579455Sobrien dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0); 6679455Sobrien if (dosfs < 0 && !rdonly) { 6779455Sobrien dosfs = open(fname, O_RDONLY, 0); 6879455Sobrien if (dosfs >= 0) 6979455Sobrien pwarn(" (NO WRITE)\n"); 7079455Sobrien else if (!preen) 7179455Sobrien printf("\n"); 7279455Sobrien rdonly = 1; 7379455Sobrien } else if (!preen) 7479455Sobrien printf("\n"); 7579455Sobrien 7679455Sobrien if (dosfs < 0) { 7779455Sobrien perror("Can't open"); 7879455Sobrien return 8; 7979455Sobrien } 8079455Sobrien 8179455Sobrien if (readboot(dosfs, &boot) != FSOK) { 8279455Sobrien close(dosfs); 8379455Sobrien printf("\n"); 8479455Sobrien return 8; 8579455Sobrien } 8679455Sobrien 87123873Strhodes if (checkdirty(dosfs, &boot) && !force) { 88123873Strhodes if (preen) printf("%s: ", fname); 89123873Strhodes printf("FILESYSTEM CLEAN; SKIPPING CHECKS\n"); 90123873Strhodes ret = 0; 91123873Strhodes goto out; 92123873Strhodes } 93123873Strhodes 9479455Sobrien if (!preen) { 9579455Sobrien if (boot.ValidFat < 0) 9679455Sobrien printf("** Phase 1 - Read and Compare FATs\n"); 9779455Sobrien else 9879455Sobrien printf("** Phase 1 - Read FAT\n"); 9979455Sobrien } 10079455Sobrien 10179455Sobrien mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat); 10279455Sobrien if (mod & FSFATAL) { 10379455Sobrien close(dosfs); 10479455Sobrien return 8; 10579455Sobrien } 10679455Sobrien 10779455Sobrien if (boot.ValidFat < 0) 108121726Strhodes for (i = 1; i < (int)boot.FATs; i++) { 10979455Sobrien struct fatEntry *currentFat; 11079455Sobrien 11179455Sobrien mod |= readfat(dosfs, &boot, i, ¤tFat); 11279455Sobrien 11379455Sobrien if (mod & FSFATAL) 11479455Sobrien goto out; 11579455Sobrien 11679455Sobrien mod |= comparefat(&boot, fat, currentFat, i); 11779455Sobrien free(currentFat); 11879455Sobrien if (mod & FSFATAL) 11979455Sobrien goto out; 12079455Sobrien } 12179455Sobrien 12279455Sobrien if (!preen) 12379455Sobrien printf("** Phase 2 - Check Cluster Chains\n"); 12479455Sobrien 12579455Sobrien mod |= checkfat(&boot, fat); 12679455Sobrien if (mod & FSFATAL) 12779455Sobrien goto out; 12879455Sobrien /* delay writing FATs */ 12979455Sobrien 13079455Sobrien if (!preen) 13179455Sobrien printf("** Phase 3 - Checking Directories\n"); 13279455Sobrien 13379455Sobrien mod |= resetDosDirSection(&boot, fat); 13479455Sobrien finish_dosdirsection = 1; 13579455Sobrien if (mod & FSFATAL) 13679455Sobrien goto out; 13779455Sobrien /* delay writing FATs */ 13879455Sobrien 13979455Sobrien mod |= handleDirTree(dosfs, &boot, fat); 14079455Sobrien if (mod & FSFATAL) 14179455Sobrien goto out; 14279455Sobrien 14379455Sobrien if (!preen) 14479455Sobrien printf("** Phase 4 - Checking for Lost Files\n"); 14579455Sobrien 14679455Sobrien mod |= checklost(dosfs, &boot, fat); 14779455Sobrien if (mod & FSFATAL) 14879455Sobrien goto out; 14979455Sobrien 15079455Sobrien /* now write the FATs */ 15179455Sobrien if (mod & FSFATMOD) { 15279455Sobrien if (ask(1, "Update FATs")) { 15379455Sobrien mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT); 15479455Sobrien if (mod & FSFATAL) 15579455Sobrien goto out; 15679455Sobrien } else 15779455Sobrien mod |= FSERROR; 15879455Sobrien } 15979455Sobrien 16079455Sobrien if (boot.NumBad) 16179455Sobrien pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n", 16279455Sobrien boot.NumFiles, 16379455Sobrien boot.NumFree * boot.ClusterSize / 1024, boot.NumFree, 16479455Sobrien boot.NumBad * boot.ClusterSize / 1024, boot.NumBad); 16579455Sobrien else 16679455Sobrien pwarn("%d files, %d free (%d clusters)\n", 16779455Sobrien boot.NumFiles, 16879455Sobrien boot.NumFree * boot.ClusterSize / 1024, boot.NumFree); 16979455Sobrien 17079455Sobrien if (mod && (mod & FSERROR) == 0) { 17179455Sobrien if (mod & FSDIRTY) { 17279455Sobrien if (ask(1, "MARK FILE SYSTEM CLEAN") == 0) 17379455Sobrien mod &= ~FSDIRTY; 17479455Sobrien 17579455Sobrien if (mod & FSDIRTY) { 17679455Sobrien pwarn("MARKING FILE SYSTEM CLEAN\n"); 17779455Sobrien mod |= writefat(dosfs, &boot, fat, 1); 17879455Sobrien } else { 17979455Sobrien pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n"); 180102231Strhodes mod |= FSERROR; /* file system not clean */ 18179455Sobrien } 18279455Sobrien } 18379455Sobrien } 18479455Sobrien 18579455Sobrien if (mod & (FSFATAL | FSERROR)) 18679455Sobrien goto out; 18779455Sobrien 18879455Sobrien ret = 0; 18979455Sobrien 19079455Sobrien out: 19179455Sobrien if (finish_dosdirsection) 19279455Sobrien finishDosDirSection(); 19379455Sobrien free(fat); 19479455Sobrien close(dosfs); 19579455Sobrien 19679455Sobrien if (mod & (FSFATMOD|FSDIRMOD)) 19779455Sobrien pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 19879455Sobrien 19979455Sobrien return ret; 20079455Sobrien} 201123873Strhodes 202123873Strhodesint checkdirty(int fs, struct bootblock *boot) 203123873Strhodes{ 204123873Strhodes off_t off; 205123873Strhodes u_char *buffer; 206123873Strhodes int ret = 0; 207123873Strhodes 208123873Strhodes if (boot->ClustMask == CLUST12_MASK) 209123873Strhodes return 0; 210123873Strhodes 211123873Strhodes off = boot->ResSectors; 212123873Strhodes off *= boot->BytesPerSec; 213123873Strhodes 214123873Strhodes buffer = malloc(boot->BytesPerSec); 215123873Strhodes if (buffer == NULL) { 216123873Strhodes perror("No space for FAT"); 217123873Strhodes return 1; 218123873Strhodes } 219123873Strhodes 220123873Strhodes if (lseek(fs, off, SEEK_SET) != off) { 221123873Strhodes perror("Unable to read FAT"); 222123873Strhodes goto err; 223123873Strhodes } 224123873Strhodes 225123873Strhodes if (read(fs, buffer, boot->BytesPerSec) 226123873Strhodes != boot->BytesPerSec) { 227123873Strhodes perror("Unable to read FAT"); 228123873Strhodes goto err; 229123873Strhodes } 230123873Strhodes 231123873Strhodes if (buffer[0] == boot->Media && buffer[1] == 0xff 232123873Strhodes && buffer[2] == 0xff 233123873Strhodes && ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f) 234123873Strhodes || (boot->ClustMask == CLUST32_MASK 235123873Strhodes && buffer[3] == 0x0f && buffer[4] == 0xff 236123873Strhodes && buffer[5] == 0xff && buffer[6] == 0xff 237123873Strhodes && buffer[7] == 0x07))) 238123873Strhodes ret = 0; 239123873Strhodes else 240123873Strhodes ret = 1; 241123873Strhodes 242123873Strhodeserr: 243123873Strhodes free(buffer); 244123873Strhodes return ret; 245123873Strhodes} 246