From 324610c081065230c1ea3ceb5228eae4ea53ec0f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 13 Sep 2018 10:55:17 -0600 Subject: Convert makefile to blueprint. Bug: 29899852 Test: manual Change-Id: I15c7f2eb4a1c5130c19e0b51c827e4408ce1051e --- Android.bp | 24 ++++++++++++++++++++++++ Android.mk | 23 ----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 Android.bp delete mode 100644 Android.mk diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..32ef6a2 --- /dev/null +++ b/Android.bp @@ -0,0 +1,24 @@ +cc_binary { + name: "fsck_msdos", + srcs: [ + "boot.c", + "check.c", + "dir.c", + "fat.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) -- cgit v1.2.3 From 74d9e588482ae8475de19a51cd3ca8e88e2f8da5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 13 Sep 2018 11:15:24 -0600 Subject: Update to latest FreeBSD upstream. Snapshot as of 9131ba637f003fb5894e3f6343a27d6322205f18 with minimal modifications to keep it compiling on Android. (For example, using ifdef __ANDROID__ to guard BSD-specific code.) Bug: 29899852 Test: manual Change-Id: I2b8f498332f83fbc486d20540d00a06117907bf8 --- Android.bp | 1 + METADATA | 17 ++++ boot.c | 221 ++++++++++++++++++----------------------- check.c | 83 +++++----------- dir.c | 329 ++++++++++++++++++++++--------------------------------------- dosfs.h | 45 ++++----- ext.h | 35 +++---- fat.c | 263 ++++++++++++++++++++++-------------------------- fsutil.c | 234 +++++++++++++++++++++++++++++++++++++++++++ fsutil.h | 59 ++++++++++- main.c | 19 ++-- 11 files changed, 709 insertions(+), 597 deletions(-) create mode 100644 METADATA create mode 100644 fsutil.c diff --git a/Android.bp b/Android.bp index 32ef6a2..67858c3 100644 --- a/Android.bp +++ b/Android.bp @@ -5,6 +5,7 @@ cc_binary { "check.c", "dir.c", "fat.c", + "fsutil.c", "main.c", ], include_dirs: ["external/fsck_msdos/"], 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 #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 #include -#include #include #include @@ -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 #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 #include -#include #include #include #include @@ -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, ¤tFat); - 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 #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 #include #include #include -#include #include #include @@ -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 @@ -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 #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 @@ -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 +#ifndef lint +__RCSID("$NetBSD: fsutil.c,v 1.15 2006/06/05 16:52:05 christos Exp $"); +#endif /* not lint */ +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#ifndef __ANDROID__ +#include +#endif +#include +#include +#include +#include +#include + +#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 #include -#include #include #include #include @@ -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; -- cgit v1.2.3