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