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