1*c6dcfc10Smlelstv /* $NetBSD: check.c,v 1.20 2022/08/28 10:20:25 mlelstv Exp $ */
26ae4c91aSws
36ae4c91aSws /*
4d445160eSws * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
56ae4c91aSws * Copyright (c) 1995 Martin Husemann
66ae4c91aSws *
76ae4c91aSws * Redistribution and use in source and binary forms, with or without
86ae4c91aSws * modification, are permitted provided that the following conditions
96ae4c91aSws * are met:
106ae4c91aSws * 1. Redistributions of source code must retain the above copyright
116ae4c91aSws * notice, this list of conditions and the following disclaimer.
126ae4c91aSws * 2. Redistributions in binary form must reproduce the above copyright
136ae4c91aSws * notice, this list of conditions and the following disclaimer in the
146ae4c91aSws * documentation and/or other materials provided with the distribution.
156ae4c91aSws *
166ae4c91aSws * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
176ae4c91aSws * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
186ae4c91aSws * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
196ae4c91aSws * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
206ae4c91aSws * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
216ae4c91aSws * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
226ae4c91aSws * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
236ae4c91aSws * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
246ae4c91aSws * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
256ae4c91aSws * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
266ae4c91aSws */
276ae4c91aSws
286ae4c91aSws
295a94f674Slukem #include <sys/cdefs.h>
306ae4c91aSws #ifndef lint
31*c6dcfc10Smlelstv __RCSID("$NetBSD: check.c,v 1.20 2022/08/28 10:20:25 mlelstv Exp $");
326ae4c91aSws #endif /* not lint */
336ae4c91aSws
346ae4c91aSws #include <stdlib.h>
356ae4c91aSws #include <string.h>
366ae4c91aSws #include <stdio.h>
376ae4c91aSws #include <unistd.h>
386ae4c91aSws #include <fcntl.h>
396ae4c91aSws
406ae4c91aSws #include "ext.h"
41a0c84e7dSchristos #include "fsutil.h"
42742b48d5Schristos #include "exitvalues.h"
436ae4c91aSws
446ae4c91aSws int
checkfilesys(const char * filename)4565e67723Sxtraeme checkfilesys(const char *filename)
466ae4c91aSws {
476ae4c91aSws int dosfs;
486ae4c91aSws struct bootblock boot;
496ae4c91aSws struct fatEntry *fat = NULL;
50a2b5923eSlukem int finish_dosdirsection=0;
51a2b5923eSlukem u_int i;
526ae4c91aSws int mod = 0;
53742b48d5Schristos int ret = FSCK_EXIT_CHECK_FAILED;
546ae4c91aSws
556ae4c91aSws rdonly = alwaysno;
566ae4c91aSws if (!preen)
578e78c802Swiz printf("** %s", filename);
586ae4c91aSws
598e78c802Swiz dosfs = open(filename, rdonly ? O_RDONLY : O_RDWR, 0);
606ae4c91aSws if (dosfs < 0 && !rdonly) {
618e78c802Swiz dosfs = open(filename, O_RDONLY, 0);
626ae4c91aSws if (dosfs >= 0)
636ae4c91aSws pwarn(" (NO WRITE)\n");
646ae4c91aSws else if (!preen)
656ae4c91aSws printf("\n");
666ae4c91aSws rdonly = 1;
676ae4c91aSws } else if (!preen)
686ae4c91aSws printf("\n");
696ae4c91aSws
706ae4c91aSws if (dosfs < 0) {
7115f3040fSchristos perr("Can't open `%s'", filename);
72742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
736ae4c91aSws }
746ae4c91aSws
75*c6dcfc10Smlelstv mod = readboot(dosfs, &boot);
76*c6dcfc10Smlelstv if (mod & FSFATAL) {
776ae4c91aSws close(dosfs);
783b81524aSabs printf("\n");
79742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
806ae4c91aSws }
816ae4c91aSws
82029a64ccSross if (!preen) {
83d445160eSws if (boot.ValidFat < 0)
846ae4c91aSws printf("** Phase 1 - Read and Compare FATs\n");
85d445160eSws else
86d445160eSws printf("** Phase 1 - Read FAT\n");
87029a64ccSross }
886ae4c91aSws
89d445160eSws mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat);
90d445160eSws if (mod & FSFATAL) {
91d445160eSws close(dosfs);
92742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
93d445160eSws }
94d445160eSws
95d445160eSws if (boot.ValidFat < 0)
96d445160eSws for (i = 1; i < boot.FATs; i++) {
976ae4c91aSws struct fatEntry *currentFat;
986ae4c91aSws
996ae4c91aSws mod |= readfat(dosfs, &boot, i, ¤tFat);
1006ae4c91aSws
1014ab49897Sjdolecek if (mod & FSFATAL)
1024ab49897Sjdolecek goto out;
1036ae4c91aSws
104d445160eSws mod |= comparefat(&boot, fat, currentFat, i);
10525e3d62eSws free(currentFat);
1064ab49897Sjdolecek if (mod & FSFATAL)
1074ab49897Sjdolecek goto out;
1086ae4c91aSws }
1096ae4c91aSws
1106ae4c91aSws if (!preen)
1116ae4c91aSws printf("** Phase 2 - Check Cluster Chains\n");
1126ae4c91aSws
1136ae4c91aSws mod |= checkfat(&boot, fat);
1144ab49897Sjdolecek if (mod & FSFATAL)
1154ab49897Sjdolecek goto out;
1164ab49897Sjdolecek /* delay writing FATs */
1176ae4c91aSws
1186ae4c91aSws if (!preen)
1196ae4c91aSws printf("** Phase 3 - Checking Directories\n");
1206ae4c91aSws
121d445160eSws mod |= resetDosDirSection(&boot, fat);
1224ab49897Sjdolecek finish_dosdirsection = 1;
1234ab49897Sjdolecek if (mod & FSFATAL)
1244ab49897Sjdolecek goto out;
1254ab49897Sjdolecek /* delay writing FATs */
1266ae4c91aSws
12725e3d62eSws mod |= handleDirTree(dosfs, &boot, fat);
1284ab49897Sjdolecek if (mod & FSFATAL)
1294ab49897Sjdolecek goto out;
1306ae4c91aSws
1316ae4c91aSws if (!preen)
1326ae4c91aSws printf("** Phase 4 - Checking for Lost Files\n");
1336ae4c91aSws
13425e3d62eSws mod |= checklost(dosfs, &boot, fat);
135d445160eSws if (mod & FSFATAL)
1364ab49897Sjdolecek goto out;
1374ab49897Sjdolecek
1384ab49897Sjdolecek /* now write the FATs */
139698f62dfSchristos if (mod & (FSFATMOD|FSFIXFAT)) {
1404ab49897Sjdolecek if (ask(1, "Update FATs")) {
1414ab49897Sjdolecek mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT);
1424ab49897Sjdolecek if (mod & FSFATAL)
1434ab49897Sjdolecek goto out;
1444ab49897Sjdolecek } else
1454ab49897Sjdolecek mod |= FSERROR;
1464ab49897Sjdolecek }
14725e3d62eSws
148fdbcbfc2Sws if (boot.NumBad)
149fdbcbfc2Sws pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n",
150fdbcbfc2Sws boot.NumFiles,
151fdbcbfc2Sws boot.NumFree * boot.ClusterSize / 1024, boot.NumFree,
152fdbcbfc2Sws boot.NumBad * boot.ClusterSize / 1024, boot.NumBad);
153fdbcbfc2Sws else
1546ae4c91aSws pwarn("%d files, %d free (%d clusters)\n",
155fdbcbfc2Sws boot.NumFiles,
156fdbcbfc2Sws boot.NumFree * boot.ClusterSize / 1024, boot.NumFree);
157d445160eSws
1584ab49897Sjdolecek if (mod && (mod & FSERROR) == 0) {
1594ab49897Sjdolecek if (mod & FSDIRTY) {
1604ab49897Sjdolecek if (ask(1, "MARK FILE SYSTEM CLEAN") == 0)
1614ab49897Sjdolecek mod &= ~FSDIRTY;
1624ab49897Sjdolecek
1634ab49897Sjdolecek if (mod & FSDIRTY) {
1644ab49897Sjdolecek pwarn("MARKING FILE SYSTEM CLEAN\n");
1654ab49897Sjdolecek mod |= writefat(dosfs, &boot, fat, 1);
1664ab49897Sjdolecek } else {
1674ab49897Sjdolecek pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n");
1684ab49897Sjdolecek mod |= FSERROR; /* file system not clean */
1696ae4c91aSws }
1704ab49897Sjdolecek }
1714ab49897Sjdolecek }
1724ab49897Sjdolecek
1734ab49897Sjdolecek if (mod & (FSFATAL | FSERROR))
1744ab49897Sjdolecek goto out;
1754ab49897Sjdolecek
176742b48d5Schristos ret = FSCK_EXIT_OK;
1774ab49897Sjdolecek
1784ab49897Sjdolecek out:
1794ab49897Sjdolecek if (finish_dosdirsection)
1804ab49897Sjdolecek finishDosDirSection();
1814ab49897Sjdolecek free(fat);
1824ab49897Sjdolecek close(dosfs);
1834ab49897Sjdolecek
1844ab49897Sjdolecek if (mod & (FSFATMOD|FSDIRMOD))
1854ab49897Sjdolecek pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
1864ab49897Sjdolecek
1874ab49897Sjdolecek return ret;
1886ae4c91aSws }
189