summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2018-09-13 15:02:46 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-09-13 15:02:46 -0700
commit0cfae5e29d38d23e5364b67a10c299310d2c28d3 (patch)
treed65aa098bf2914d643a425d75fd589ffc7b58953
parent2edb366074e3c3ce4004f383ef20f598fd19769f (diff)
parent17ad1c883d02963530b5bbe919df46c2b6658244 (diff)
downloadfsck_msdos-0cfae5e29d38d23e5364b67a10c299310d2c28d3.tar.gz
Merge changes from topic "upstreamz"
am: 17ad1c883d Change-Id: Ia7c409cc86576c3d54727fed239b9f4edf23cbef
-rw-r--r--Android.bp25
-rw-r--r--Android.mk23
-rw-r--r--METADATA17
-rw-r--r--boot.c221
-rw-r--r--check.c83
-rw-r--r--dir.c329
-rw-r--r--dosfs.h45
-rw-r--r--ext.h35
-rw-r--r--fat.c263
-rw-r--r--fsutil.c234
-rw-r--r--fsutil.h59
-rw-r--r--main.c19
12 files changed, 733 insertions, 620 deletions
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..67858c3
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,25 @@
+cc_binary {
+ name: "fsck_msdos",
+ srcs: [
+ "boot.c",
+ "check.c",
+ "dir.c",
+ "fat.c",
+ "fsutil.c",
+ "main.c",
+ ],
+ include_dirs: ["external/fsck_msdos/"],
+ cflags: [
+ "-O2",
+ "-g",
+ "-Wall",
+ "-Werror",
+ "-D_BSD_SOURCE",
+ "-D_LARGEFILE_SOURCE",
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wno-unused-variable",
+ "-Wno-unused-const-variable",
+ "-Wno-format",
+ "-Wno-sign-compare",
+ ],
+}
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 8dec83a..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := boot.c check.c dir.c fat.c main.c
-
-LOCAL_C_INCLUDES := external/fsck_msdos/
-
-LOCAL_CFLAGS := -O2 -g \
- -Wall -Werror \
- -D_BSD_SOURCE \
- -D_LARGEFILE_SOURCE \
- -D_FILE_OFFSET_BITS=64 \
- -Wno-unused-variable \
- -Wno-unused-const-variable \
- -Wno-format \
- -Wno-sign-compare
-
-LOCAL_MODULE := fsck_msdos
-LOCAL_MODULE_TAGS :=
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-
-include $(BUILD_EXECUTABLE)
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..812c788
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,17 @@
+name: "fsck_msdos"
+description:
+ "This is the FreeBSD fsck_msdosfs."
+
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://github.com/freebsd/freebsd/tree/master/sbin/fsck_msdosfs"
+ }
+ url {
+ type: GIT
+ value: "https://github.com/freebsd/freebsd.git"
+ }
+ version: "9131ba637f003fb5894e3f6343a27d6322205f18"
+ last_upgrade_date { year: 2018 month: 9 day: 13 }
+ license_type: NOTICE
+}
diff --git a/boot.c b/boot.c
index 5326a45..9e0958a 100644
--- a/boot.c
+++ b/boot.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (C) 1995, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
@@ -10,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -33,14 +28,13 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: boot.c,v 1.9 2003/07/24 19:25:46 ws Exp $");
+__RCSID("$NetBSD: boot.c,v 1.11 2006/06/05 16:51:18 christos Exp ");
static const char rcsid[] =
- "$FreeBSD: src/sbin/fsck_msdosfs/boot.c,v 1.4.28.1 2009/04/15 03:14:26 kensmith Exp $";
+ "$FreeBSD$";
#endif /* not lint */
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
@@ -48,45 +42,56 @@ static const char rcsid[] =
#include "fsutil.h"
int
-readboot(dosfs, boot)
- int dosfs;
- struct bootblock *boot;
+readboot(int dosfs, struct bootblock *boot)
{
u_char block[DOSBOOTBLOCKSIZE];
u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
u_char backup[DOSBOOTBLOCKSIZE];
int ret = FSOK;
+ int i;
- if (read(dosfs, block, sizeof block) < sizeof block) {
- perror("could not read boot block");
- exit(2);
+ if ((size_t)read(dosfs, block, sizeof block) != sizeof block) {
+ perr("could not read boot block");
+ return FSFATAL;
}
if (block[510] != 0x55 || block[511] != 0xaa) {
- pfatal("Invalid signature in boot block: %02x%02x", block[511], block[510]);
- exit(2);
+ pfatal("Invalid signature in boot block: %02x%02x",
+ block[511], block[510]);
+ return FSFATAL;
}
memset(boot, 0, sizeof *boot);
boot->ValidFat = -1;
/* decode bios parameter block */
- boot->BytesPerSec = block[11] + (block[12] << 8);
- boot->SecPerClust = block[13];
- boot->ResSectors = block[14] + (block[15] << 8);
- boot->FATs = block[16];
- boot->RootDirEnts = block[17] + (block[18] << 8);
- boot->Sectors = block[19] + (block[20] << 8);
- boot->Media = block[21];
- boot->FATsmall = block[22] + (block[23] << 8);
+ boot->bpbBytesPerSec = block[11] + (block[12] << 8);
+ boot->bpbSecPerClust = block[13];
+ boot->bpbResSectors = block[14] + (block[15] << 8);
+ boot->bpbFATs = block[16];
+ boot->bpbRootDirEnts = block[17] + (block[18] << 8);
+ boot->bpbSectors = block[19] + (block[20] << 8);
+ boot->bpbMedia = block[21];
+ boot->bpbFATsmall = block[22] + (block[23] << 8);
boot->SecPerTrack = block[24] + (block[25] << 8);
- boot->Heads = block[26] + (block[27] << 8);
- boot->HiddenSecs = block[28] + (block[29] << 8) + (block[30] << 16) + (block[31] << 24);
- boot->HugeSectors = block[32] + (block[33] << 8) + (block[34] << 16) + (block[35] << 24);
+ boot->bpbHeads = block[26] + (block[27] << 8);
+ boot->bpbHiddenSecs = block[28] + (block[29] << 8) +
+ (block[30] << 16) + (block[31] << 24);
+ boot->bpbHugeSectors = block[32] + (block[33] << 8) +
+ (block[34] << 16) + (block[35] << 24);
- boot->FATsecs = boot->FATsmall;
+ boot->FATsecs = boot->bpbFATsmall;
- if (!boot->RootDirEnts)
+ if (boot->bpbBytesPerSec % DOSBOOTBLOCKSIZE_REAL != 0 ||
+ boot->bpbBytesPerSec / DOSBOOTBLOCKSIZE_REAL == 0) {
+ pfatal("Invalid sector size: %u", boot->bpbBytesPerSec);
+ return FSFATAL;
+ }
+ if (boot->bpbFATs == 0) {
+ pfatal("Invalid number of FATs: %u", boot->bpbFATs);
+ return FSFATAL;
+ }
+ if (!boot->bpbRootDirEnts)
boot->flags |= FAT32;
if (boot->flags & FAT32) {
boot->FATsecs = block[36] + (block[37] << 8)
@@ -99,12 +104,12 @@ readboot(dosfs, boot)
/* Correct? XXX */
pfatal("Unknown file system version: %x.%x",
block[43], block[42]);
- exit(2);
+ return FSFATAL;
}
- boot->RootCl = block[44] + (block[45] << 8)
+ boot->bpbRootClust = block[44] + (block[45] << 8)
+ (block[46] << 16) + (block[47] << 24);
- boot->FSInfo = block[48] + (block[49] << 8);
- boot->Backup = block[50] + (block[51] << 8);
+ boot->bpbFSInfo = block[48] + (block[49] << 8);
+ boot->bpbBackup = block[50] + (block[51] << 8);
/* If the OEM Name field is EXFAT, it's not FAT32, so bail */
if (!memcmp(&block[3], "EXFAT ", 8)) {
@@ -113,23 +118,19 @@ readboot(dosfs, boot)
}
/* check basic parameters */
- if ((boot->FSInfo == 0) ||
- (boot->BytesPerSec % DOSBOOTBLOCKSIZE != 0) ||
- (boot->BytesPerSec / DOSBOOTBLOCKSIZE == 0) ||
- (boot->SecPerClust == 0)) {
+ if ((boot->bpbFSInfo == 0) || (boot->bpbSecPerClust == 0)) {
/*
* Either the BIOS Parameter Block has been corrupted,
- * or this is not a FAT32 filesystem, most likely an
- * exFAT filesystem.
+ * or this is not a FAT32 filesystem, most likely an
+ * exFAT filesystem.
*/
pfatal("Invalid FAT32 Extended BIOS Parameter Block");
return FSFATAL;
}
- if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
- != boot->FSInfo * boot->BytesPerSec
- || read(dosfs, fsinfo, sizeof fsinfo)
- != sizeof fsinfo) {
- perror("could not read fsinfo block");
+ if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec,
+ SEEK_SET) != boot->bpbFSInfo * boot->bpbBytesPerSec
+ || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
+ perr("could not read fsinfo block");
return FSFATAL;
}
if (memcmp(fsinfo, "RRaA", 4)
@@ -143,7 +144,7 @@ readboot(dosfs, boot)
|| fsinfo[0x3fe] != 0x55
|| fsinfo[0x3ff] != 0xaa) {
pwarn("Invalid signature in fsinfo block\n");
- if (ask(1, "fix")) {
+ if (ask(0, "Fix")) {
memcpy(fsinfo, "RRaA", 4);
memcpy(fsinfo + 0x1e4, "rrAa", 4);
fsinfo[0x1fc] = fsinfo[0x1fd] = 0;
@@ -152,18 +153,19 @@ readboot(dosfs, boot)
fsinfo[0x3fc] = fsinfo[0x3fd] = 0;
fsinfo[0x3fe] = 0x55;
fsinfo[0x3ff] = 0xaa;
- if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
- != boot->FSInfo * boot->BytesPerSec
+ if (lseek(dosfs, boot->bpbFSInfo *
+ boot->bpbBytesPerSec, SEEK_SET)
+ != boot->bpbFSInfo * boot->bpbBytesPerSec
|| write(dosfs, fsinfo, sizeof fsinfo)
!= sizeof fsinfo) {
- perror("Unable to write FSInfo");
+ perr("Unable to write bpbFSInfo");
return FSFATAL;
}
ret = FSBOOTMOD;
} else
- boot->FSInfo = 0;
+ boot->bpbFSInfo = 0;
}
- if (boot->FSInfo) {
+ if (boot->bpbFSInfo) {
boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
+ (fsinfo[0x1ea] << 16)
+ (fsinfo[0x1eb] << 24);
@@ -172,75 +174,50 @@ readboot(dosfs, boot)
+ (fsinfo[0x1ef] << 24);
}
- if (lseek(dosfs, boot->Backup * boot->BytesPerSec, SEEK_SET)
- != boot->Backup * boot->BytesPerSec
+ if (lseek(dosfs, boot->bpbBackup * boot->bpbBytesPerSec,
+ SEEK_SET)
+ != boot->bpbBackup * boot->bpbBytesPerSec
|| read(dosfs, backup, sizeof backup) != sizeof backup) {
- perror("could not read backup bootblock");
+ perr("could not read backup bootblock");
return FSFATAL;
}
backup[65] = block[65]; /* XXX */
if (memcmp(block + 11, backup + 11, 79)) {
- char tmp[255];
- int i;
-
/*
- * For now, lets not bail out if they don't match
- * It seems a lot of sdcards are formatted with
- * the backup either empty or containing garbage.
+ * XXX We require a reference that explains
+ * that these bytes need to match, or should
+ * drop the check. gdt@NetBSD has observed
+ * filesystems that work fine under Windows XP
+ * and NetBSD that do not match, so the
+ * requirement is suspect. For now, just
+ * print out useful information and continue.
*/
-
- pwarn("Primary/Backup bootblock miscompare\n");
-
- strcpy(tmp, "");
- pwarn("Primary:\n");
- for (i = 0; i < 79; i++) {
- char tmp2[16];
- snprintf(tmp2, sizeof(tmp2), "%.2x ", block[11 + i]);
- strcat(tmp, tmp2);
- }
- pwarn("%s\n", tmp);
-
- strcpy(tmp, "");
- pwarn("Backup:\n");
- for (i = 0; i < 79; i++) {
- char tmp2[16];
- snprintf(tmp2, sizeof(tmp2), "%.2x ", backup[11 + i]);
- strcat(tmp, tmp2);
- }
- pwarn("%s\n", tmp);
+ pwarn("backup (block %d) mismatch with primary bootblock:\n",
+ boot->bpbBackup);
+ for (i = 11; i < 11 + 90; i++) {
+ if (block[i] != backup[i])
+ pwarn("\ti=%d\tprimary 0x%02x\tbackup 0x%02x\n",
+ i, block[i], backup[i]);
+ }
}
- /* Check backup FSInfo? XXX */
+ /* Check backup bpbFSInfo? XXX */
}
- if (boot->BytesPerSec % DOSBOOTBLOCKSIZE != 0) {
- pfatal("Invalid sector size: %u", boot->BytesPerSec);
- return FSFATAL;
- }
- if (boot->SecPerClust == 0) {
- pfatal("Invalid cluster size: %u", boot->SecPerClust);
- return FSFATAL;
- }
- if (boot->BytesPerSec == 0) {
- pfatal("Invalid sector size: %u", boot->BytesPerSec);
- return FSFATAL;
- }
- if (boot->FATs == 0) {
- pfatal("Invalid number of FATs: %u", boot->FATs);
+ if (boot->bpbSecPerClust == 0) {
+ pfatal("Invalid cluster size: %u", boot->bpbSecPerClust);
return FSFATAL;
}
- if (boot->Sectors) {
- boot->HugeSectors = 0;
- boot->NumSectors = boot->Sectors;
+ if (boot->bpbSectors) {
+ boot->bpbHugeSectors = 0;
+ boot->NumSectors = boot->bpbSectors;
} else
- boot->NumSectors = boot->HugeSectors;
-
- boot->ClusterOffset = (boot->RootDirEnts * 32 + boot->BytesPerSec - 1)
- / boot->BytesPerSec
- + boot->ResSectors
- + boot->FATs * boot->FATsecs
- - CLUST_FIRST * boot->SecPerClust;
-
- boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust;
+ boot->NumSectors = boot->bpbHugeSectors;
+ boot->ClusterOffset = (boot->bpbRootDirEnts * 32 +
+ boot->bpbBytesPerSec - 1) / boot->bpbBytesPerSec +
+ boot->bpbResSectors + boot->bpbFATs * boot->FATsecs -
+ CLUST_FIRST * boot->bpbSecPerClust;
+ boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) /
+ boot->bpbSecPerClust;
if (boot->flags&FAT32)
boot->ClustMask = CLUST32_MASK;
@@ -256,22 +233,22 @@ readboot(dosfs, boot)
switch (boot->ClustMask) {
case CLUST32_MASK:
- boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 4;
+ boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec) / 4;
break;
case CLUST16_MASK:
- boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 2;
+ boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec) / 2;
break;
default:
- boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec * 2) / 3;
+ boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec * 2) / 3;
break;
}
- if (boot->NumFatEntries < boot->NumClusters) {
+ if (boot->NumFatEntries < boot->NumClusters - CLUST_FIRST) {
pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
boot->NumClusters, boot->FATsecs);
return FSFATAL;
}
- boot->ClusterSize = boot->BytesPerSec * boot->SecPerClust;
+ boot->ClusterSize = boot->bpbBytesPerSec * boot->bpbSecPerClust;
boot->NumFiles = 1;
boot->NumFree = 0;
@@ -280,16 +257,14 @@ readboot(dosfs, boot)
}
int
-writefsinfo(dosfs, boot)
- int dosfs;
- struct bootblock *boot;
+writefsinfo(int dosfs, struct bootblock *boot)
{
u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
- if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
- != boot->FSInfo * boot->BytesPerSec
+ if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
+ != boot->bpbFSInfo * boot->bpbBytesPerSec
|| read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
- perror("could not read fsinfo block");
+ perr("could not read fsinfo block");
return FSFATAL;
}
fsinfo[0x1e8] = (u_char)boot->FSFree;
@@ -300,11 +275,11 @@ writefsinfo(dosfs, boot)
fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8);
fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
- if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
- != boot->FSInfo * boot->BytesPerSec
+ if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
+ != boot->bpbFSInfo * boot->bpbBytesPerSec
|| write(dosfs, fsinfo, sizeof fsinfo)
!= sizeof fsinfo) {
- perror("Unable to write FSInfo");
+ perr("Unable to write bpbFSInfo");
return FSFATAL;
}
/*
diff --git a/check.c b/check.c
index fab2d91..2431bd3 100644
--- a/check.c
+++ b/check.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
@@ -10,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -33,14 +28,13 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: check.c,v 1.10 2000/04/25 23:02:51 jdolecek Exp $");
+__RCSID("$NetBSD: check.c,v 1.14 2006/06/05 16:51:18 christos Exp $");
static const char rcsid[] =
- "$FreeBSD: src/sbin/fsck_msdosfs/check.c,v 1.10 2004/02/05 15:47:46 bde Exp $";
+ "$FreeBSD$";
#endif /* not lint */
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
@@ -48,27 +42,19 @@ static const char rcsid[] =
#include "ext.h"
#include "fsutil.h"
-/*
- * If the FAT > this size then skip comparing, lest we risk
- * OOMing the framework. in the future we need to just re-write
- * this whole thing and optimize for less memory
- */
-#define FAT_COMPARE_MAX_KB 4096
-
int
checkfilesys(const char *fname)
{
int dosfs;
struct bootblock boot;
struct fatEntry *fat = NULL;
- int i, finish_dosdirsection=0;
+ int finish_dosdirsection=0;
+ u_int i;
int mod = 0;
int ret = 8;
- int quiet = 0;
- int skip_fat_compare = 0;
rdonly = alwaysno;
- if (!quiet)
+ if (!preen)
printf("** %s", fname);
dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0);
@@ -76,14 +62,15 @@ checkfilesys(const char *fname)
dosfs = open(fname, O_RDONLY, 0);
if (dosfs >= 0)
pwarn(" (NO WRITE)\n");
- else if (!quiet)
+ else if (!preen)
printf("\n");
rdonly = 1;
- } else if (!quiet)
+ } else if (!preen)
printf("\n");
if (dosfs < 0) {
- perror("Can't open");
+ perr("Can't open `%s'", fname);
+ printf("\n");
return 8;
}
@@ -100,13 +87,8 @@ checkfilesys(const char *fname)
goto out;
}
- if (((boot.FATsecs * boot.BytesPerSec) / 1024) > FAT_COMPARE_MAX_KB)
- skip_fat_compare = 1;
-
- if (!quiet) {
- if (skip_fat_compare)
- printf("** Phase 1 - Read FAT (compare skipped)\n");
- else if (boot.ValidFat < 0)
+ if (!preen) {
+ if (boot.ValidFat < 0)
printf("** Phase 1 - Read and Compare FATs\n");
else
printf("** Phase 1 - Read FAT\n");
@@ -114,56 +96,47 @@ checkfilesys(const char *fname)
mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat);
if (mod & FSFATAL) {
- printf("Fatal error during readfat()\n");
close(dosfs);
return 8;
}
- if (!skip_fat_compare && boot.ValidFat < 0)
- for (i = 1; i < (int)boot.FATs; i++) {
+ if (boot.ValidFat < 0)
+ for (i = 1; i < boot.bpbFATs; i++) {
struct fatEntry *currentFat;
mod |= readfat(dosfs, &boot, i, &currentFat);
- if (mod & FSFATAL) {
- printf("Fatal error during readfat() for comparison\n");
+ if (mod & FSFATAL)
goto out;
- }
mod |= comparefat(&boot, fat, currentFat, i);
free(currentFat);
- if (mod & FSFATAL) {
- printf("Fatal error during FAT comparison\n");
+ if (mod & FSFATAL)
goto out;
- }
}
- if (!quiet)
+ if (!preen)
printf("** Phase 2 - Check Cluster Chains\n");
mod |= checkfat(&boot, fat);
- if (mod & FSFATAL) {
- printf("Fatal error during FAT check\n");
+ if (mod & FSFATAL)
goto out;
- }
/* delay writing FATs */
- if (!quiet)
+ if (!preen)
printf("** Phase 3 - Checking Directories\n");
mod |= resetDosDirSection(&boot, fat);
finish_dosdirsection = 1;
- if (mod & FSFATAL) {
- printf("Fatal error during resetDosDirSection()\n");
+ if (mod & FSFATAL)
goto out;
- }
/* delay writing FATs */
mod |= handleDirTree(dosfs, &boot, fat);
if (mod & FSFATAL)
goto out;
- if (!quiet)
+ if (!preen)
printf("** Phase 4 - Checking for Lost Files\n");
mod |= checklost(dosfs, &boot, fat);
@@ -171,13 +144,11 @@ checkfilesys(const char *fname)
goto out;
/* now write the FATs */
- if (mod & FSFATMOD) {
+ if (mod & (FSFATMOD|FSFIXFAT)) {
if (ask(1, "Update FATs")) {
mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT);
- if (mod & FSFATAL) {
- printf("Fatal error during writefat()\n");
+ if (mod & FSFATAL)
goto out;
- }
} else
mod |= FSERROR;
}
@@ -218,10 +189,8 @@ checkfilesys(const char *fname)
free(fat);
close(dosfs);
- if (mod & (FSFATMOD|FSDIRMOD)) {
+ if (mod & (FSFATMOD|FSDIRMOD))
pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
- return 4;
- }
return ret;
}
diff --git a/dir.c b/dir.c
index 7e4a567..38c7014 100644
--- a/dir.c
+++ b/dir.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
* Some structure declaration borrowed from Paul Popelka
@@ -12,13 +14,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -35,16 +30,15 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: dir.c,v 1.14 1998/08/25 19:18:15 ross Exp $");
+__RCSID("$NetBSD: dir.c,v 1.20 2006/06/05 16:51:18 christos Exp $");
static const char rcsid[] =
- "$FreeBSD: src/sbin/fsck_msdosfs/dir.c,v 1.3 2003/12/26 17:24:37 trhodes Exp $";
+ "$FreeBSD$";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include <stdio.h>
#include <unistd.h>
#include <time.h>
@@ -161,7 +155,7 @@ freeDirTodo(struct dirTodoNode *dt)
/*
* The stack of unread directories
*/
-struct dirTodoNode *pendingDirectories = NULL;
+static struct dirTodoNode *pendingDirectories = NULL;
/*
* Return the full pathname for a directory entry.
@@ -214,7 +208,7 @@ static char longName[DOSLONGNAMELEN] = "";
static u_char *buffer = NULL;
static u_char *delbuf = NULL;
-struct dosDirEntry *rootDir;
+static struct dosDirEntry *rootDir;
static struct dosDirEntry *lostDir;
/*
@@ -226,27 +220,41 @@ resetDosDirSection(struct bootblock *boot, struct fatEntry *fat)
int b1, b2;
cl_t cl;
int ret = FSOK;
+ size_t len;
+
+ b1 = boot->bpbRootDirEnts * 32;
+ b2 = boot->bpbSecPerClust * boot->bpbBytesPerSec;
+
+ if ((buffer = malloc(len = MAX(b1, b2))) == NULL) {
+ perr("No space for directory buffer (%zu)", len);
+ return FSFATAL;
+ }
- b1 = boot->RootDirEnts * 32;
- b2 = boot->SecPerClust * boot->BytesPerSec;
+ if ((delbuf = malloc(len = b2)) == NULL) {
+ free(buffer);
+ perr("No space for directory delbuf (%zu)", len);
+ return FSFATAL;
+ }
- if (!(buffer = malloc(b1 > b2 ? b1 : b2))
- || !(delbuf = malloc(b2))
- || !(rootDir = newDosDirEntry())) {
- perror("No space for directory");
+ if ((rootDir = newDosDirEntry()) == NULL) {
+ free(buffer);
+ free(delbuf);
+ perr("No space for directory entry");
return FSFATAL;
}
+
memset(rootDir, 0, sizeof *rootDir);
if (boot->flags & FAT32) {
- if (boot->RootCl < CLUST_FIRST || boot->RootCl >= boot->NumClusters) {
+ if (boot->bpbRootClust < CLUST_FIRST ||
+ boot->bpbRootClust >= boot->NumClusters) {
pfatal("Root directory starts with cluster out of range(%u)",
- boot->RootCl);
+ boot->bpbRootClust);
return FSFATAL;
}
- cl = fat[boot->RootCl].next;
+ cl = fat[boot->bpbRootClust].next;
if (cl < CLUST_FIRST
|| (cl >= CLUST_RSRVD && cl< CLUST_EOFS)
- || fat[boot->RootCl].head != boot->RootCl) {
+ || fat[boot->bpbRootClust].head != boot->bpbRootClust) {
if (cl == CLUST_FREE)
pwarn("Root directory starts with free cluster\n");
else if (cl >= CLUST_RSRVD)
@@ -257,14 +265,14 @@ resetDosDirSection(struct bootblock *boot, struct fatEntry *fat)
return FSFATAL;
}
if (ask(1, "Fix")) {
- fat[boot->RootCl].next = CLUST_FREE;
+ fat[boot->bpbRootClust].next = CLUST_FREE;
ret = FSFATMOD;
} else
ret = FSFATAL;
}
- fat[boot->RootCl].flags |= FAT_USED;
- rootDir->head = boot->RootCl;
+ fat[boot->bpbRootClust].flags |= FAT_USED;
+ rootDir->head = boot->bpbRootClust;
}
return ret;
@@ -283,7 +291,7 @@ finishDosDirSection(void)
np = p->next;
freeDirTodo(p);
}
- pendingDirectories = 0;
+ pendingDirectories = NULL;
for (d = rootDir; d; d = nd) {
if ((nd = d->child) != NULL) {
d->child = 0;
@@ -308,8 +316,8 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl,
int startoff, cl_t endcl, int endoff, int notlast)
{
u_char *s, *e;
- loff_t off;
- int clsz = boot->SecPerClust * boot->BytesPerSec;
+ off_t off;
+ int clsz = boot->bpbSecPerClust * boot->bpbBytesPerSec;
s = delbuf + startoff;
e = delbuf + clsz;
@@ -319,28 +327,20 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl,
break;
e = delbuf + endoff;
}
- off = startcl * boot->SecPerClust + boot->ClusterOffset;
- off *= boot->BytesPerSec;
- if (lseek64(f, off, SEEK_SET) != off) {
- printf("off = %llu\n", off);
- perror("Unable to lseek64");
- return FSFATAL;
- }
- if (read(f, delbuf, clsz) != clsz) {
- perror("Unable to read directory");
+ off = startcl * boot->bpbSecPerClust + boot->ClusterOffset;
+ off *= boot->bpbBytesPerSec;
+ if (lseek(f, off, SEEK_SET) != off
+ || read(f, delbuf, clsz) != clsz) {
+ perr("Unable to read directory");
return FSFATAL;
}
while (s < e) {
*s = SLOT_DELETED;
s += 32;
}
- if (lseek64(f, off, SEEK_SET) != off) {
- printf("off = %llu\n", off);
- perror("Unable to lseek64");
- return FSFATAL;
- }
- if (write(f, delbuf, clsz) != clsz) {
- perror("Unable to write directory");
+ if (lseek(f, off, SEEK_SET) != off
+ || write(f, delbuf, clsz) != clsz) {
+ perr("Unable to write directory");
return FSFATAL;
}
if (startcl == endcl)
@@ -360,13 +360,14 @@ removede(int f, struct bootblock *boot, struct fatEntry *fat, u_char *start,
pwarn("Invalid long filename entry for %s\n", path);
break;
case 1:
- pwarn("Invalid long filename entry at end of directory %s\n", path);
+ pwarn("Invalid long filename entry at end of directory %s\n",
+ path);
break;
case 2:
pwarn("Invalid long filename entry for volume label\n");
break;
}
- if (ask(1, "Remove")) {
+ if (ask(0, "Remove")) {
if (startcl != curcl) {
if (delete(f, boot, fat,
startcl, start - buffer,
@@ -375,7 +376,8 @@ removede(int f, struct bootblock *boot, struct fatEntry *fat, u_char *start,
return FSFATAL;
start = buffer;
}
- if (endcl == curcl)
+ /* startcl is < CLUST_FIRST for !fat32 root */
+ if ((endcl == curcl) || (startcl < CLUST_FIRST))
for (; start < end; start += 32)
*start = SLOT_DELETED;
return FSDIRMOD;
@@ -393,7 +395,7 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
/*
* Check size on ordinary files
*/
- int32_t physicalSize;
+ u_int32_t physicalSize;
if (dir->head == CLUST_FREE)
physicalSize = 0;
@@ -419,12 +421,14 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
fullpath(dir));
if (ask(1, "Drop superfluous clusters")) {
cl_t cl;
- u_int32_t sz = 0;
+ u_int32_t sz, len;
- for (cl = dir->head; (sz += boot->ClusterSize) < dir->size;)
+ for (cl = dir->head, len = sz = 0;
+ (sz += boot->ClusterSize) < dir->size; len++)
cl = fat[cl].next;
clearchain(boot, fat, fat[cl].next);
fat[cl].next = CLUST_EOF;
+ fat[dir->head].length = len;
return FSFATMOD;
} else
return FSERROR;
@@ -432,89 +436,6 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
return FSOK;
}
-
-static u_char dot_header[16]={0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00};
-static u_char dot_dot_header[16]={0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00};
-
-/*
- * Check for missing or broken '.' and '..' entries.
- */
-static int
-check_dot_dot(int f, struct bootblock *boot, struct fatEntry *fat,struct dosDirEntry *dir)
-{
- u_char *p, *buf;
- loff_t off;
- int last;
- cl_t cl;
- int rc=0, n_count;
-
- int dot, dotdot;
- dot = dotdot = 0;
- cl = dir->head;
-
- if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) {
- return rc;
- }
-
- do {
- if (!(boot->flags & FAT32) && !dir->parent) {
- last = boot->RootDirEnts * 32;
- off = boot->ResSectors + boot->FATs * boot->FATsecs;
- } else {
- last = boot->SecPerClust * boot->BytesPerSec;
- off = cl * boot->SecPerClust + boot->ClusterOffset;
- }
-
- off *= boot->BytesPerSec;
- buf = malloc(last);
- if (!buf) {
- perror("Unable to malloc");
- return FSFATAL;
- }
- if (lseek64(f, off, SEEK_SET) != off) {
- printf("off = %llu\n", off);
- perror("Unable to lseek64");
- free(buf);
- return FSFATAL;
- }
- if (read(f, buf, last) != last) {
- perror("Unable to read");
- free(buf);
- return FSFATAL;
- }
- last /= 32;
- p = buf;
- for (n_count=0, rc=0; n_count < 11; n_count++) {
- if (dot_header[n_count] != p[n_count]) {
- rc=-1;
- break;
- }
- }
- if(!rc)
- dot=1;
-
- for (n_count = 0, rc = 0; n_count < 11; n_count++) {
- if (dot_dot_header[n_count] != p[n_count+32]) {
- rc=-1;
- break;
- }
- }
- if(!rc)
- dotdot=1;
- free(buf);
- } while ((cl = fat[cl].next) >= CLUST_FIRST && cl < boot->NumClusters);
-
- if (!dot || !dotdot) {
- if (!dot)
- pwarn("%s: '.' absent for %s.\n",__func__,dir->name);
-
- if (!dotdot)
- pwarn("%s: '..' absent for %s. \n",__func__,dir->name);
- return -1;
- }
- return 0;
-}
-
/*
* Read a directory and
* - resolve long name records
@@ -527,15 +448,13 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
{
struct dosDirEntry dirent, *d;
u_char *p, *vallfn, *invlfn, *empty;
- loff_t off;
+ off_t off;
int i, j, k, last;
cl_t cl, valcl = ~0, invcl = ~0, empcl = ~0;
char *t;
u_int lidx = 0;
int shortSum;
int mod = FSOK;
- int n_count=0;
- int rc=0;
#define THISMOD 0x8000 /* Only used within this routine */
cl = dir->head;
@@ -547,29 +466,26 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
shortSum = -1;
vallfn = invlfn = empty = NULL;
- int dot,dotdot;
- dot = dotdot = 0;
-
do {
if (!(boot->flags & FAT32) && !dir->parent) {
- last = boot->RootDirEnts * 32;
- off = boot->ResSectors + boot->FATs * boot->FATsecs;
+ last = boot->bpbRootDirEnts * 32;
+ off = boot->bpbResSectors + boot->bpbFATs *
+ boot->FATsecs;
} else {
- last = boot->SecPerClust * boot->BytesPerSec;
- off = cl * boot->SecPerClust + boot->ClusterOffset;
+ last = boot->bpbSecPerClust * boot->bpbBytesPerSec;
+ off = cl * boot->bpbSecPerClust + boot->ClusterOffset;
}
- off *= boot->BytesPerSec;
- if (lseek64(f, off, SEEK_SET) != off) {
- printf("off = %llu\n", off);
- perror("Unable to lseek64");
+ off *= boot->bpbBytesPerSec;
+ if (lseek(f, off, SEEK_SET) != off
+ || read(f, buffer, last) != last) {
+ perr("Unable to read directory");
return FSFATAL;
- }
- if (read(f, buffer, last) != last) {
- perror("Unable to read");
- return FSFATAL;
- }
+ }
last /= 32;
+ /*
+ * Check `.' and `..' entries here? XXX
+ */
for (p = buffer, i = 0; i < last; i++, p += 32) {
if (dir->fsckflags & DIREMPWARN) {
*p = SLOT_EMPTY;
@@ -601,7 +517,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
for (; q < p; q += 32)
*q = SLOT_DELETED;
mod |= THISMOD|FSDIRMOD;
- } else if (ask(1, "Truncate"))
+ } else if (ask(0, "Truncate"))
dir->fsckflags |= DIREMPWARN;
}
if (dir->fsckflags & DIREMPWARN) {
@@ -639,7 +555,8 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
lidx = *p & LRNOMASK;
t = longName + --lidx * 13;
- for (k = 1; k < 11 && t < longName + sizeof(longName); k += 2) {
+ for (k = 1; k < 11 && t < longName +
+ sizeof(longName); k += 2) {
if (!p[k] && !p[k + 1])
break;
*t++ = p[k];
@@ -704,7 +621,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
dirent.name[8] = '\0';
for (k = 7; k >= 0 && dirent.name[k] == ' '; k--)
dirent.name[k] = '\0';
- if (dirent.name[k] != '\0')
+ if (k < 0 || dirent.name[k] != '\0')
k++;
if (dirent.name[0] == SLOT_E5)
dirent.name[0] = 0xe5;
@@ -741,7 +658,8 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
dirent.head |= (p[20] << 16) | (p[21] << 24);
dirent.size = p[28] | (p[29] << 8) | (p[30] << 16) | (p[31] << 24);
if (vallfn) {
- strcpy(dirent.lname, longName);
+ strlcpy(dirent.lname, longName,
+ sizeof(dirent.lname));
longName[0] = '\0';
shortSum = -1;
}
@@ -812,7 +730,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
pwarn("%s doesn't start a cluster chain\n",
fullpath(&dirent));
if (dirent.flags & ATTR_DIRECTORY) {
- if (ask(1, "Remove")) {
+ if (ask(0, "Remove")) {
*p = SLOT_DELETED;
mod |= THISMOD|FSDIRMOD;
} else
@@ -851,11 +769,11 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
mod |= FSERROR;
}
/*
- * handle '.' and '..' specially
+ * handle `.' and `..' specially
*/
if (strcmp(dirent.name, ".") == 0) {
if (dirent.head != dir->head) {
- pwarn("'.' entry in %s has incorrect start cluster\n",
+ pwarn("`.' entry in %s has incorrect start cluster\n",
fullpath(dir));
if (ask(1, "Correct")) {
dirent.head = dir->head;
@@ -870,11 +788,12 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
mod |= FSERROR;
}
continue;
- } else if (strcmp(dirent.name, "..") == 0) {
+ }
+ if (strcmp(dirent.name, "..") == 0) {
if (dir->parent) { /* XXX */
if (!dir->parent->parent) {
if (dirent.head) {
- pwarn("'..' entry in %s has non-zero start cluster\n",
+ pwarn("`..' entry in %s has non-zero start cluster\n",
fullpath(dir));
if (ask(1, "Correct")) {
dirent.head = 0;
@@ -886,7 +805,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
mod |= FSERROR;
}
} else if (dirent.head != dir->parent->head) {
- pwarn("'..' entry in %s has incorrect start cluster\n",
+ pwarn("`..' entry in %s has incorrect start cluster\n",
fullpath(dir));
if (ask(1, "Correct")) {
dirent.head = dir->parent->head;
@@ -902,48 +821,20 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
}
continue;
- } else { //only one directory entry can point to dir->head, it's '.'
- if (dirent.head == dir->head) {
- pwarn("%s entry in %s has incorrect start cluster.remove\n",
- dirent.name, fullpath(dir));
- //we have to remove this directory entry rigth now rigth here
- if (ask(1, "Remove")) {
- *p = SLOT_DELETED;
- mod |= THISMOD|FSDIRMOD;
- } else
- mod |= FSERROR;
- continue;
- }
- /* Consistency checking. a directory must have at least two entries:
- a dot (.) entry that points to itself, and a dot-dot (..)
- entry that points to its parent.
- */
- if (check_dot_dot(f,boot,fat,&dirent)) {
- //mark directory entry as deleted.
- if (ask(1, "Remove")) {
- *p = SLOT_DELETED;
- mod |= THISMOD|FSDIRMOD;
- } else
- mod |= FSERROR;
- continue;
- }
}
/* create directory tree node */
if (!(d = newDosDirEntry())) {
- perror("No space for directory");
+ perr("No space for directory");
return FSFATAL;
}
memcpy(d, &dirent, sizeof(struct dosDirEntry));
/* link it into the tree */
dir->child = d;
-#if 0
- printf("%s: %s : 0x%02x:head %d, next 0x%0x parent 0x%0x child 0x%0x\n",
- __func__,d->name,d->flags,d->head,d->next,d->parent,d->child);
-#endif
+
/* Enter this directory into the todo list */
if (!(n = newDirTodo())) {
- perror("No space for todo list");
+ perr("No space for todo list");
return FSFATAL;
}
n->next = pendingDirectories;
@@ -956,11 +847,15 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
boot->NumFiles++;
}
+
+ if (!(boot->flags & FAT32) && !dir->parent)
+ break;
+
if (mod & THISMOD) {
last *= 32;
- if (lseek64(f, off, SEEK_SET) != off
+ if (lseek(f, off, SEEK_SET) != off
|| write(f, buffer, last) != last) {
- perror("Unable to write directory");
+ perr("Unable to write directory");
return FSFATAL;
}
mod &= ~THISMOD;
@@ -971,6 +866,19 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
invlfn ? invlfn : vallfn, p,
invlfn ? invcl : valcl, -1, 0,
fullpath(dir), 1);
+
+ /* The root directory of non fat32 filesystems is in a special
+ * area and may have been modified above without being written out.
+ */
+ if ((mod & FSDIRMOD) && !(boot->flags & FAT32) && !dir->parent) {
+ last *= 32;
+ if (lseek(f, off, SEEK_SET) != off
+ || write(f, buffer, last) != last) {
+ perr("Unable to write directory");
+ return FSFATAL;
+ }
+ mod &= ~THISMOD;
+ }
return mod & ~THISMOD;
}
@@ -1013,12 +921,13 @@ handleDirTree(int dosfs, struct bootblock *boot, struct fatEntry *fat)
*/
static u_char *lfbuf;
static cl_t lfcl;
-static loff_t lfoff;
+static off_t lfoff;
int
reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
{
struct dosDirEntry d;
+ int len;
u_char *p;
if (!ask(1, "Reconnect"))
@@ -1037,7 +946,7 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
if (!lfbuf) {
lfbuf = malloc(boot->ClusterSize);
if (!lfbuf) {
- perror("No space for buffer");
+ perr("No space for buffer");
return FSFATAL;
}
p = NULL;
@@ -1055,14 +964,13 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
if (lfcl < CLUST_FIRST || lfcl >= boot->NumClusters) {
/* Extend LOSTDIR? XXX */
pwarn("No space in %s\n", LOSTDIR);
- lfcl = (lostDir->head < boot->NumClusters) ? lostDir->head : 0;
return FSERROR;
}
lfoff = lfcl * boot->ClusterSize
- + boot->ClusterOffset * boot->BytesPerSec;
- if (lseek64(dosfs, lfoff, SEEK_SET) != lfoff
- || read(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
- perror("could not read LOST.DIR");
+ + boot->ClusterOffset * boot->bpbBytesPerSec;
+ if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
+ || (size_t)read(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
+ perr("could not read LOST.DIR");
return FSFATAL;
}
p = lfbuf;
@@ -1071,14 +979,15 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
boot->NumFiles++;
/* Ensure uniqueness of entry here! XXX */
memset(&d, 0, sizeof d);
- (void)snprintf(d.name, sizeof(d.name), "%u", head);
+ /* worst case -1 = 4294967295, 10 digits */
+ len = snprintf(d.name, sizeof(d.name), "%u", head);
d.flags = 0;
d.head = head;
d.size = fat[head].length * boot->ClusterSize;
- memset(p, 0, 32);
- memset(p, ' ', 11);
- memcpy(p, d.name, strlen(d.name));
+ memcpy(p, d.name, len);
+ memset(p + len, ' ', 11 - len);
+ memset(p + 11, 0, 32 - 11);
p[26] = (u_char)d.head;
p[27] = (u_char)(d.head >> 8);
if (boot->ClustMask == CLUST32_MASK) {
@@ -1090,9 +999,9 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
p[30] = (u_char)(d.size >> 16);
p[31] = (u_char)(d.size >> 24);
fat[head].flags |= FAT_USED;
- if (lseek64(dosfs, lfoff, SEEK_SET) != lfoff
- || write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
- perror("could not write LOST.DIR");
+ if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
+ || (size_t)write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
+ perr("could not write LOST.DIR");
return FSFATAL;
}
return FSDIRMOD;
diff --git a/dosfs.h b/dosfs.h
index 5420e25..3d84ea0 100644
--- a/dosfs.h
+++ b/dosfs.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
* Some structure declaration borrowed from Paul Popelka
@@ -12,13 +14,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -31,13 +26,15 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* $NetBSD: dosfs.h,v 1.4 1997/01/03 14:32:48 ws Exp $
- * $FreeBSD: src/sbin/fsck_msdosfs/dosfs.h,v 1.3 2003/12/26 17:24:37 trhodes Exp $
+ * $FreeBSD$
*/
#ifndef DOSFS_H
#define DOSFS_H
-#define DOSBOOTBLOCKSIZE 512
+/* support 4Kn disk reads */
+#define DOSBOOTBLOCKSIZE_REAL 512
+#define DOSBOOTBLOCKSIZE 4096
typedef u_int32_t cl_t; /* type holding a cluster number */
@@ -46,21 +43,21 @@ typedef u_int32_t cl_t; /* type holding a cluster number */
* FAT boot block.
*/
struct bootblock {
- u_int BytesPerSec; /* bytes per sector */
- u_int SecPerClust; /* sectors per cluster */
- u_int ResSectors; /* number of reserved sectors */
- u_int FATs; /* number of FATs */
- u_int RootDirEnts; /* number of root directory entries */
- u_int Media; /* media descriptor */
- u_int FATsmall; /* number of sectors per FAT */
+ u_int bpbBytesPerSec; /* bytes per sector */
+ u_int bpbSecPerClust; /* sectors per cluster */
+ u_int bpbResSectors; /* number of reserved sectors */
+ u_int bpbFATs; /* number of bpbFATs */
+ u_int bpbRootDirEnts; /* number of root directory entries */
+ u_int32_t bpbSectors; /* total number of sectors */
+ u_int bpbMedia; /* media descriptor */
+ u_int bpbFATsmall; /* number of sectors per FAT */
u_int SecPerTrack; /* sectors per track */
- u_int Heads; /* number of heads */
- u_int32_t Sectors; /* total number of sectors */
- u_int32_t HiddenSecs; /* # of hidden sectors */
- u_int32_t HugeSectors; /* # of sectors if bpbSectors == 0 */
- u_int FSInfo; /* FSInfo sector */
- u_int Backup; /* Backup of Bootblocks */
- cl_t RootCl; /* Start of Root Directory */
+ u_int bpbHeads; /* number of heads */
+ u_int32_t bpbHiddenSecs; /* # of hidden sectors */
+ u_int32_t bpbHugeSectors; /* # of sectors if bpbbpbSectors == 0 */
+ cl_t bpbRootClust; /* Start of Root Directory */
+ u_int bpbFSInfo; /* FSInfo sector */
+ u_int bpbBackup; /* Backup of Bootblocks */
cl_t FSFree; /* Number of free clusters acc. FSInfo */
cl_t FSNext; /* Next free cluster acc. FSInfo */
diff --git a/ext.h b/ext.h
index 6d183e9..ebc9467 100644
--- a/ext.h
+++ b/ext.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
@@ -10,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -29,11 +24,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* $NetBSD: ext.h,v 1.6 2000/04/25 23:02:51 jdolecek Exp $
- * $FreeBSD: src/sbin/fsck_msdosfs/ext.h,v 1.10.20.1 2009/04/15 03:14:26 kensmith Exp $
+ * $FreeBSD$
*/
#ifndef EXT_H
-#define EXT_H
+#define EXT_H
#include <sys/types.h>
@@ -50,12 +45,10 @@ extern int preen; /* we are preening */
extern int rdonly; /* device is opened read only (supersedes above) */
extern int skipclean; /* skip clean file systems if preening */
-extern struct dosDirEntry *rootDir;
-
/*
* function declarations
*/
-int ask(int, const char *, ...);
+int ask(int, const char *, ...) __printflike(2, 3);
/*
* Check the dirty flag. If the file system is clean, then return 1.
@@ -77,12 +70,12 @@ int checkfilesys(const char *);
#define FSDIRMOD 2 /* Some directory was modified */
#define FSFATMOD 4 /* The FAT was modified */
#define FSERROR 8 /* Some unrecovered error remains */
-#define FSFATAL 16 /* Some unrecoverable error occured */
-#define FSDIRTY 32 /* File system is dirty */
-#define FSFIXFAT 64 /* Fix file system FAT */
+#define FSFATAL 16 /* Some unrecoverable error occurred */
+#define FSDIRTY 32 /* File system is dirty */
+#define FSFIXFAT 64 /* Fix file system FAT */
/*
- * read a boot block in a machine independend fashion and translate
+ * read a boot block in a machine independent fashion and translate
* it into our struct bootblock.
*/
int readboot(int, struct bootblock *);
@@ -96,13 +89,13 @@ int writefsinfo(int, struct bootblock *);
* Read one of the FAT copies and return a pointer to the new
* allocated array holding our description of it.
*/
-int readfat(int, struct bootblock *, int, struct fatEntry **);
+int readfat(int, struct bootblock *, u_int, struct fatEntry **);
/*
* Check two FAT copies for consistency and merge changes into the
- * first if neccessary.
+ * first if necessary.
*/
-int comparefat(struct bootblock *, struct fatEntry *, struct fatEntry *, int);
+int comparefat(struct bootblock *, struct fatEntry *, struct fatEntry *, u_int);
/*
* Check a FAT
@@ -140,7 +133,7 @@ void finishlf(void);
/*
* Return the type of a reserved cluster as text
*/
-char *rsrvdcltype(cl_t);
+const char *rsrvdcltype(cl_t);
/*
* Clear a cluster chain in a FAT
diff --git a/fat.c b/fat.c
index 9b58ffb..9e4f5c8 100644
--- a/fat.c
+++ b/fat.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
@@ -10,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -33,9 +28,9 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: fat.c,v 1.12 2000/10/10 20:24:52 is Exp $");
+__RCSID("$NetBSD: fat.c,v 1.18 2006/06/05 16:51:18 christos Exp $");
static const char rcsid[] =
- "$FreeBSD: src/sbin/fsck_msdosfs/fat.c,v 1.9 2008/01/31 13:22:13 yar Exp $";
+ "$FreeBSD$";
#endif /* not lint */
#include <stdlib.h>
@@ -47,10 +42,10 @@ static const char rcsid[] =
#include "ext.h"
#include "fsutil.h"
-static int checkclnum(struct bootblock *, int, cl_t, cl_t *);
-static int clustdiffer(cl_t, cl_t *, cl_t *, int);
+static int checkclnum(struct bootblock *, u_int, cl_t, cl_t *);
+static int clustdiffer(cl_t, cl_t *, cl_t *, u_int);
static int tryclear(struct bootblock *, struct fatEntry *, cl_t, cl_t *);
-static int _readfat(int, struct bootblock *, int, u_char **);
+static int _readfat(int, struct bootblock *, u_int, u_char **);
/*-
* The first 2 FAT entries contain pseudo-cluster numbers with the following
@@ -76,26 +71,28 @@ checkdirty(int fs, struct bootblock *boot)
off_t off;
u_char *buffer;
int ret = 0;
+ size_t len;
if (boot->ClustMask != CLUST16_MASK && boot->ClustMask != CLUST32_MASK)
return 0;
- off = boot->ResSectors;
- off *= boot->BytesPerSec;
+ off = boot->bpbResSectors;
+ off *= boot->bpbBytesPerSec;
- buffer = malloc(boot->BytesPerSec);
+ buffer = malloc(len = boot->bpbBytesPerSec);
if (buffer == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT sectors (%zu)", len);
return 1;
}
if (lseek(fs, off, SEEK_SET) != off) {
- perror("Unable to read FAT");
+ perr("Unable to read FAT");
goto err;
}
- if (read(fs, buffer, boot->BytesPerSec) != boot->BytesPerSec) {
- perror("Unable to read FAT");
+ if ((size_t)read(fs, buffer, boot->bpbBytesPerSec) !=
+ boot->bpbBytesPerSec) {
+ perr("Unable to read FAT");
goto err;
}
@@ -103,7 +100,7 @@ checkdirty(int fs, struct bootblock *boot)
* If we don't understand the FAT, then the file system must be
* assumed to be unclean.
*/
- if (buffer[0] != boot->Media || buffer[1] != 0xff)
+ if (buffer[0] != boot->bpbMedia || buffer[1] != 0xff)
goto err;
if (boot->ClustMask == CLUST16_MASK) {
if ((buffer[2] & 0xf8) != 0xf8 || (buffer[3] & 0x3f) != 0x3f)
@@ -135,7 +132,7 @@ err:
* Check a cluster number for valid value
*/
static int
-checkclnum(struct bootblock *boot, int fat, cl_t cl, cl_t *next)
+checkclnum(struct bootblock *boot, u_int fat, cl_t cl, cl_t *next)
{
if (*next >= (CLUST_RSRVD&boot->ClustMask))
*next |= ~boot->ClustMask;
@@ -153,7 +150,7 @@ checkclnum(struct bootblock *boot, int fat, cl_t cl, cl_t *next)
cl, fat,
*next < CLUST_RSRVD ? "out of range" : "reserved",
*next&boot->ClustMask);
- if (ask(1, "Truncate")) {
+ if (ask(0, "Truncate")) {
*next = CLUST_EOF;
return FSFATMOD;
}
@@ -166,30 +163,28 @@ checkclnum(struct bootblock *boot, int fat, cl_t cl, cl_t *next)
* Read a FAT from disk. Returns 1 if successful, 0 otherwise.
*/
static int
-_readfat(int fs, struct bootblock *boot, int no, u_char **buffer)
+_readfat(int fs, struct bootblock *boot, u_int no, u_char **buffer)
{
off_t off;
+ size_t len;
- printf("Attempting to allocate %u KB for FAT\n",
- (boot->FATsecs * boot->BytesPerSec) / 1024);
-
- *buffer = malloc(boot->FATsecs * boot->BytesPerSec);
+ *buffer = malloc(len = boot->FATsecs * boot->bpbBytesPerSec);
if (*buffer == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT sectors (%zu)", len);
return 0;
}
- off = boot->ResSectors + no * boot->FATsecs;
- off *= boot->BytesPerSec;
+ off = boot->bpbResSectors + no * boot->FATsecs;
+ off *= boot->bpbBytesPerSec;
if (lseek(fs, off, SEEK_SET) != off) {
- perror("Unable to read FAT");
+ perr("Unable to read FAT");
goto err;
}
- if (read(fs, *buffer, boot->FATsecs * boot->BytesPerSec)
- != boot->FATsecs * boot->BytesPerSec) {
- perror("Unable to read FAT");
+ if ((size_t)read(fs, *buffer, boot->FATsecs * boot->bpbBytesPerSec)
+ != boot->FATsecs * boot->bpbBytesPerSec) {
+ perr("Unable to read FAT");
goto err;
}
@@ -204,26 +199,28 @@ _readfat(int fs, struct bootblock *boot, int no, u_char **buffer)
* Read a FAT and decode it into internal format
*/
int
-readfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp)
+readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
{
struct fatEntry *fat;
u_char *buffer, *p;
cl_t cl;
int ret = FSOK;
+ size_t len;
boot->NumFree = boot->NumBad = 0;
if (!_readfat(fs, boot, no, &buffer))
return FSFATAL;
-
- fat = calloc(boot->NumClusters, sizeof(struct fatEntry));
+
+ fat = malloc(len = boot->NumClusters * sizeof(struct fatEntry));
if (fat == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT clusters (%zu)", len);
free(buffer);
return FSFATAL;
}
+ (void)memset(fat, 0, len);
- if (buffer[0] != boot->Media
+ if (buffer[0] != boot->bpbMedia
|| buffer[1] != 0xff || buffer[2] != 0xff
|| (boot->ClustMask == CLUST16_MASK && buffer[3] != 0xff)
|| (boot->ClustMask == CLUST32_MASK
@@ -237,7 +234,7 @@ readfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp)
* file system is dirty if it doesn't reboot cleanly.
* Check this special condition before errorring out.
*/
- if (buffer[0] == boot->Media && buffer[1] == 0xff
+ if (buffer[0] == boot->bpbMedia && buffer[1] == 0xff
&& buffer[2] == 0xff
&& ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f)
|| (boot->ClustMask == CLUST32_MASK
@@ -247,7 +244,7 @@ readfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp)
ret |= FSDIRTY;
else {
/* just some odd byte sequence in FAT */
-
+
switch (boot->ClustMask) {
case CLUST32_MASK:
pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n",
@@ -267,7 +264,7 @@ readfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp)
break;
}
-
+
if (ask(1, "Correct"))
ret |= FSFIXFAT;
}
@@ -314,14 +311,18 @@ readfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp)
}
free(buffer);
- *fp = fat;
+ if (ret & FSFATAL) {
+ free(fat);
+ *fp = NULL;
+ } else
+ *fp = fat;
return ret;
}
/*
* Get type of reserved cluster
*/
-char *
+const char *
rsrvdcltype(cl_t cl)
{
if (cl == CLUST_FREE)
@@ -334,7 +335,7 @@ rsrvdcltype(cl_t cl)
}
static int
-clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, int fatnum)
+clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, u_int fatnum)
{
if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) {
if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
@@ -349,13 +350,13 @@ clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, int fatnum)
}
return FSFATAL;
}
- pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %d\n",
+ pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %u\n",
cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum);
- if (ask(1, "Use FAT 0's entry")) {
+ if (ask(0, "Use FAT 0's entry")) {
*cp2 = *cp1;
return FSFATMOD;
}
- if (ask(1, "Use FAT %d's entry", fatnum)) {
+ if (ask(0, "Use FAT %u's entry", fatnum)) {
*cp1 = *cp2;
return FSFATMOD;
}
@@ -363,36 +364,36 @@ clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, int fatnum)
}
pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n",
cl, rsrvdcltype(*cp1), *cp2, fatnum);
- if (ask(1, "Use continuation from FAT %d", fatnum)) {
+ if (ask(0, "Use continuation from FAT %u", fatnum)) {
*cp1 = *cp2;
return FSFATMOD;
}
- if (ask(1, "Use mark from FAT 0")) {
+ if (ask(0, "Use mark from FAT 0")) {
*cp2 = *cp1;
return FSFATMOD;
}
return FSFATAL;
}
if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
- pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %d\n",
+ pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %u\n",
cl, *cp1, rsrvdcltype(*cp2), fatnum);
- if (ask(1, "Use continuation from FAT 0")) {
+ if (ask(0, "Use continuation from FAT 0")) {
*cp2 = *cp1;
return FSFATMOD;
}
- if (ask(1, "Use mark from FAT %d", fatnum)) {
+ if (ask(0, "Use mark from FAT %d", fatnum)) {
*cp1 = *cp2;
return FSFATMOD;
}
return FSERROR;
}
- pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %d\n",
+ pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %u\n",
cl, *cp1, *cp2, fatnum);
- if (ask(1, "Use continuation from FAT 0")) {
+ if (ask(0, "Use continuation from FAT 0")) {
*cp2 = *cp1;
return FSFATMOD;
}
- if (ask(1, "Use continuation from FAT %d", fatnum)) {
+ if (ask(0, "Use continuation from FAT %u", fatnum)) {
*cp1 = *cp2;
return FSFATMOD;
}
@@ -404,8 +405,8 @@ clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, int fatnum)
* into the first one.
*/
int
-comparefat(struct bootblock *boot, struct fatEntry *first,
- struct fatEntry *second, int fatnum)
+comparefat(struct bootblock *boot, struct fatEntry *first,
+ struct fatEntry *second, u_int fatnum)
{
cl_t cl;
int ret = FSOK;
@@ -431,13 +432,21 @@ clearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head)
}
int
-tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc)
+tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *truncp)
{
- if (ask(1, "Clear chain starting at %u", head)) {
+ if (ask(0, "Clear chain starting at %u", head)) {
clearchain(boot, fat, head);
return FSFATMOD;
- } else if (ask(1, "Truncate")) {
- *trunc = CLUST_EOF;
+ } else if (ask(0, "Truncate")) {
+ uint32_t len;
+ cl_t p;
+
+ for (p = head, len = 0;
+ p >= CLUST_FIRST && p < boot->NumClusters;
+ p = fat[p].next, len++)
+ continue;
+ *truncp = CLUST_EOF;
+ fat[head].length = len;
return FSFATMOD;
} else
return FSERROR;
@@ -449,7 +458,7 @@ tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc)
int
checkfat(struct bootblock *boot, struct fatEntry *fat)
{
- cl_t head, p, h, n, wdk;
+ cl_t head, p, h, n;
u_int len;
int ret = 0;
int conf;
@@ -466,14 +475,9 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
/* follow the chain and mark all clusters on the way */
for (len = 0, p = head;
- p >= CLUST_FIRST && p < boot->NumClusters;
- p = fat[p].next) {
- /* we have to check the len, to avoid infinite loop */
- if (len > boot->NumClusters) {
- printf("detect cluster chain loop: head %u for p %u\n", head, p);
- break;
- }
-
+ p >= CLUST_FIRST && p < boot->NumClusters &&
+ fat[p].head != head;
+ p = fat[p].next) {
fat[p].head = head;
len++;
}
@@ -493,33 +497,36 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
continue;
/* follow the chain to its end (hopefully) */
- /* also possible infinite loop, that's why I insert wdk counter */
- for (p = head,wdk=boot->NumClusters;
- (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters && wdk;
- p = n,wdk--) {
- if (fat[n].head != head)
+ for (len = fat[head].length, p = head;
+ (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
+ p = n)
+ if (fat[n].head != head || len-- < 2)
break;
- }
-
if (n >= CLUST_EOFS)
continue;
if (n == CLUST_FREE || n >= CLUST_RSRVD) {
pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
head, rsrvdcltype(n));
+clear:
ret |= tryclear(boot, fat, head, &fat[p].next);
continue;
}
if (n < CLUST_FIRST || n >= boot->NumClusters) {
pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
- head, n);
- ret |= tryclear(boot, fat, head, &fat[p].next);
- continue;
+ head, n);
+ goto clear;
+ }
+ if (head == fat[n].head) {
+ pwarn("Cluster chain starting at %u loops at cluster %u\n",
+
+ head, p);
+ goto clear;
}
pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
head, fat[n].head, n);
conf = tryclear(boot, fat, head, &fat[p].next);
- if (ask(1, "Clear chain starting at %u", h = fat[n].head)) {
+ if (ask(0, "Clear chain starting at %u", h = fat[n].head)) {
if (conf == FSERROR) {
/*
* Transfer the common chain to the one not cleared above.
@@ -554,21 +561,21 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
{
u_char *buffer, *p;
cl_t cl;
- int i;
- u_int32_t fatsz;
+ u_int i;
+ size_t fatsz;
off_t off;
int ret = FSOK;
- buffer = malloc(fatsz = boot->FATsecs * boot->BytesPerSec);
+ buffer = malloc(fatsz = boot->FATsecs * boot->bpbBytesPerSec);
if (buffer == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT sectors (%zu)", fatsz);
return FSFATAL;
}
memset(buffer, 0, fatsz);
boot->NumFree = 0;
p = buffer;
if (correct_fat) {
- *p++ = (u_char)boot->Media;
+ *p++ = (u_char)boot->bpbMedia;
*p++ = 0xff;
*p++ = 0xff;
switch (boot->ClustMask) {
@@ -610,7 +617,7 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
free(old_fat);
p += count;
}
-
+
for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
switch (boot->ClustMask) {
case CLUST32_MASK:
@@ -631,22 +638,24 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
default:
if (fat[cl].next == CLUST_FREE)
boot->NumFree++;
- if (cl + 1 < boot->NumClusters
- && fat[cl + 1].next == CLUST_FREE)
- boot->NumFree++;
*p++ = (u_char)fat[cl].next;
- *p++ = (u_char)((fat[cl].next >> 8) & 0xf)
- |(u_char)(fat[cl+1].next << 4);
- *p++ = (u_char)(fat[++cl].next >> 4);
+ *p = (u_char)((fat[cl].next >> 8) & 0xf);
+ cl++;
+ if (cl >= boot->NumClusters)
+ break;
+ if (fat[cl].next == CLUST_FREE)
+ boot->NumFree++;
+ *p++ |= (u_char)(fat[cl + 1].next << 4);
+ *p++ = (u_char)(fat[cl + 1].next >> 4);
break;
}
}
- for (i = 0; i < boot->FATs; i++) {
- off = boot->ResSectors + i * boot->FATsecs;
- off *= boot->BytesPerSec;
+ for (i = 0; i < boot->bpbFATs; i++) {
+ off = boot->bpbResSectors + i * boot->FATsecs;
+ off *= boot->bpbBytesPerSec;
if (lseek(fs, off, SEEK_SET) != off
- || write(fs, buffer, fatsz) != fatsz) {
- perror("Unable to write FAT");
+ || (size_t)write(fs, buffer, fatsz) != fatsz) {
+ perr("Unable to write FAT");
ret = FSFATAL; /* Return immediately? XXX */
}
}
@@ -663,7 +672,7 @@ checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
cl_t head;
int mod = FSOK;
int ret;
-
+
for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
/* find next untravelled chain */
if (fat[head].head != head
@@ -676,64 +685,26 @@ checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n",
head, fat[head].length);
mod |= ret = reconnect(dosfs, boot, fat, head);
- if (mod & FSFATAL) {
- /* If the reconnect failed, then just clear the chain */
- pwarn("Error reconnecting chain - clearing\n");
- mod &= ~FSFATAL;
- clearchain(boot, fat, head);
- mod |= FSFATMOD;
- continue;
- }
- if (ret == FSERROR && ask(1, "Clear")) {
+ if (mod & FSFATAL)
+ break;
+ if (ret == FSERROR && ask(0, "Clear")) {
clearchain(boot, fat, head);
mod |= FSFATMOD;
}
}
finishlf();
- if (boot->FSInfo) {
+ if (boot->bpbFSInfo) {
ret = 0;
- if (boot->FSFree != boot->NumFree) {
- pwarn("Free space in FSInfo block (%d) not correct (%d)\n",
+ if (boot->FSFree != 0xffffffffU &&
+ boot->FSFree != boot->NumFree) {
+ pwarn("Free space in FSInfo block (%u) not correct (%u)\n",
boot->FSFree, boot->NumFree);
if (ask(1, "Fix")) {
boot->FSFree = boot->NumFree;
ret = 1;
}
}
-
- if (boot->NumFree) {
- if ((boot->FSNext >= boot->NumClusters) || (fat[boot->FSNext].next != CLUST_FREE)) {
- pwarn("Next free cluster in FSInfo block (%u) not free\n",
- boot->FSNext);
- if (ask(1, "Fix"))
- for (head = CLUST_FIRST; head < boot->NumClusters; head++)
- if (fat[head].next == CLUST_FREE) {
- boot->FSNext = head;
- ret = 1;
- break;
- }
- }
- }
-
- if (boot->FSNext > boot->NumClusters ) {
- pwarn("FSNext block (%d) not correct NumClusters (%d)\n",
- boot->FSNext, boot->NumClusters);
- boot->FSNext=CLUST_FIRST; // boot->FSNext can have -1 value.
- }
-
- if (boot->NumFree && fat[boot->FSNext].next != CLUST_FREE) {
- pwarn("Next free cluster in FSInfo block (%u) not free\n",
- boot->FSNext);
- if (ask(1, "Fix"))
- for (head = CLUST_FIRST; head < boot->NumClusters; head++)
- if (fat[head].next == CLUST_FREE) {
- boot->FSNext = head;
- ret = 1;
- break;
- }
- }
-
if (ret)
mod |= writefsinfo(dosfs, boot);
}
diff --git a/fsutil.c b/fsutil.c
new file mode 100644
index 0000000..0fb0613
--- /dev/null
+++ b/fsutil.c
@@ -0,0 +1,234 @@
+/* $NetBSD: fsutil.c,v 1.15 2006/06/05 16:52:05 christos Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: fsutil.c,v 1.15 2006/06/05 16:52:05 christos Exp $");
+#endif /* not lint */
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#ifndef __ANDROID__
+#include <fstab.h>
+#endif
+#include <paths.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fsutil.h"
+
+static const char *dev = NULL;
+static int preen = 0;
+
+static void vmsg(int, const char *, va_list) __printflike(2, 0);
+
+void
+setcdevname(const char *cd, int pr)
+{
+ dev = cd;
+ preen = pr;
+}
+
+const char *
+cdevname(void)
+{
+ return dev;
+}
+
+static void
+vmsg(int fatal, const char *fmt, va_list ap)
+{
+ if (!fatal && preen)
+ (void) printf("%s: ", dev);
+
+ (void) vprintf(fmt, ap);
+
+ if (fatal && preen)
+ (void) printf("\n");
+
+ if (fatal && preen) {
+ (void) printf(
+ "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
+ dev, getprogname());
+ exit(8);
+ }
+}
+
+/*VARARGS*/
+void
+pfatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg(1, fmt, ap);
+ va_end(ap);
+}
+
+/*VARARGS*/
+void
+pwarn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg(0, fmt, ap);
+ va_end(ap);
+}
+
+void
+perr(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg(1, fmt, ap);
+ va_end(ap);
+}
+
+void
+panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg(1, fmt, ap);
+ va_end(ap);
+ exit(8);
+}
+
+const char *
+devcheck(const char *origname)
+{
+ struct stat stslash, stchar;
+
+ if (stat("/", &stslash) < 0) {
+ perr("Can't stat `/'");
+ return (origname);
+ }
+ if (stat(origname, &stchar) < 0) {
+ perr("Can't stat %s\n", origname);
+ return (origname);
+ }
+ if (!S_ISCHR(stchar.st_mode)) {
+ perr("%s is not a char device\n", origname);
+ }
+ return (origname);
+}
+
+#ifndef __ANDROID__
+/*
+ * Get the mount point information for name.
+ */
+struct statfs *
+getmntpt(const char *name)
+{
+ struct stat devstat, mntdevstat;
+ char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
+ char *dev_name;
+ struct statfs *mntbuf, *statfsp;
+ int i, mntsize, isdev;
+
+ if (stat(name, &devstat) != 0)
+ return (NULL);
+ if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))
+ isdev = 1;
+ else
+ isdev = 0;
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ for (i = 0; i < mntsize; i++) {
+ statfsp = &mntbuf[i];
+ dev_name = statfsp->f_mntfromname;
+ if (*dev_name != '/') {
+ if (strlen(_PATH_DEV) + strlen(dev_name) + 1 >
+ sizeof(statfsp->f_mntfromname))
+ continue;
+ strcpy(device, _PATH_DEV);
+ strcat(device, dev_name);
+ strcpy(statfsp->f_mntfromname, device);
+ }
+ if (isdev == 0) {
+ if (strcmp(name, statfsp->f_mntonname))
+ continue;
+ return (statfsp);
+ }
+ if (stat(dev_name, &mntdevstat) == 0 &&
+ mntdevstat.st_rdev == devstat.st_rdev)
+ return (statfsp);
+ }
+ statfsp = NULL;
+ return (statfsp);
+}
+#endif
+
+void *
+emalloc(size_t s)
+{
+ void *p;
+
+ p = malloc(s);
+ if (p == NULL)
+ err(1, "malloc failed");
+ return (p);
+}
+
+
+void *
+erealloc(void *p, size_t s)
+{
+ void *q;
+
+ q = realloc(p, s);
+ if (q == NULL)
+ err(1, "realloc failed");
+ return (q);
+}
+
+
+char *
+estrdup(const char *s)
+{
+ char *p;
+
+ p = strdup(s);
+ if (p == NULL)
+ err(1, "strdup failed");
+ return (p);
+}
diff --git a/fsutil.h b/fsutil.h
index 7acfdd6..21e3649 100644
--- a/fsutil.h
+++ b/fsutil.h
@@ -1,7 +1,58 @@
-#ifndef _FS_UTIL_H
-#define _FS_UTIL_H
+/* $NetBSD: fsutil.h,v 1.114 2009/10/21 01:07:46 snj Exp $ */
-#define pwarn printf
-#define pfatal printf
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1996 Christos Zoulas. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifdef __ANDROID__
+#define __dead2 __attribute__((__noreturn__))
+#endif
+
+void pfatal(const char *, ...) __printflike(1, 2);
+void pwarn(const char *, ...) __printflike(1, 2);
+void perr(const char *, ...) __printflike(1, 2);
+void panic(const char *, ...) __dead2 __printflike(1, 2);
+const char *devcheck(const char *);
+const char *cdevname(void);
+void setcdevname(const char *, int);
+struct statfs *getmntpt(const char *);
+void *emalloc(size_t);
+void *erealloc(void *, size_t);
+char *estrdup(const char *);
+
+#ifndef __ANDROID__
+#define CHECK_PREEN 0x0001
+#define CHECK_VERBOSE 0x0002
+#define CHECK_DEBUG 0x0004
+#define CHECK_BACKGRD 0x0008
+#define DO_BACKGRD 0x0010
+#define CHECK_CLEAN 0x0020
+
+struct fstab;
+int checkfstab(int, int (*)(struct fstab *),
+ int (*) (const char *, const char *, const char *, const char *, pid_t *));
#endif
diff --git a/main.c b/main.c
index 4938227..8425d8a 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright (C) 1995 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
@@ -10,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Martin Husemann
- * and Wolfgang Solfrank.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -35,12 +30,11 @@
#ifndef lint
__RCSID("$NetBSD: main.c,v 1.10 1997/10/01 02:18:14 enami Exp $");
static const char rcsid[] =
- "$FreeBSD: src/sbin/fsck_msdosfs/main.c,v 1.16 2009/06/10 19:02:54 avg Exp $";
+ "$FreeBSD$";
#endif /* not lint */
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
@@ -55,7 +49,7 @@ int preen; /* set when preening */
int rdonly; /* device is opened read only (supersedes above) */
int skipclean; /* skip clean file systems if preening */
-static void usage(void);
+static void usage(void) __dead2;
static void
usage(void)
@@ -117,7 +111,7 @@ main(int argc, char **argv)
usage();
while (--argc >= 0) {
-// setcdevname(*argv, preen);
+ setcdevname(*argv, preen);
erg = checkfilesys(*argv++);
if (erg > ret)
ret = erg;
@@ -146,6 +140,7 @@ ask(int def, const char *fmt, ...)
va_start(ap, fmt);
vsnprintf(prompt, sizeof(prompt), fmt, ap);
+ va_end(ap);
if (alwaysyes || rdonly) {
printf("%s? %s\n", prompt, rdonly ? "no" : "yes");
return !rdonly;