svn commit: r356250 - head/sbin/fsck_msdosfs
Xin LI
delphij at FreeBSD.org
Wed Jan 1 09:22:08 UTC 2020
Author: delphij
Date: Wed Jan 1 09:22:06 2020
New Revision: 356250
URL: https://svnweb.freebsd.org/changeset/base/356250
Log:
Revert r356249 for now as it broke GCC builds.
Modified:
head/sbin/fsck_msdosfs/boot.c
head/sbin/fsck_msdosfs/check.c
head/sbin/fsck_msdosfs/dir.c
head/sbin/fsck_msdosfs/dosfs.h
head/sbin/fsck_msdosfs/ext.h
head/sbin/fsck_msdosfs/fat.c
head/sbin/fsck_msdosfs/main.c
Modified: head/sbin/fsck_msdosfs/boot.c
==============================================================================
--- head/sbin/fsck_msdosfs/boot.c Wed Jan 1 07:43:08 2020 (r356249)
+++ head/sbin/fsck_msdosfs/boot.c Wed Jan 1 09:22:06 2020 (r356250)
@@ -152,6 +152,9 @@ readboot(int dosfs, struct bootblock *boot)
boot->NumSectors = boot->bpbHugeSectors;
}
+
+
+
if (boot->flags & FAT32) {
/* If the OEM Name field is EXFAT, it's not FAT32, so bail */
if (!memcmp(&block[3], "EXFAT ", 8)) {
@@ -269,30 +272,13 @@ readboot(int dosfs, struct bootblock *boot)
boot->NumClusters = (boot->NumSectors - boot->FirstCluster) / boot->bpbSecPerClust +
CLUST_FIRST;
- if (boot->flags & FAT32) {
- if (boot->NumClusters > (CLUST_RSRVD & CLUST32_MASK)) {
- pfatal("Filesystem too big (%u clusters) for FAT32 partition",
- boot->NumClusters);
- return FSFATAL;
- }
- if (boot->NumClusters < (CLUST_RSRVD & CLUST16_MASK)) {
- pfatal("Filesystem too small (%u clusters) for FAT32 partition",
- boot->NumClusters);
- return FSFATAL;
- }
+ if (boot->flags & FAT32)
boot->ClustMask = CLUST32_MASK;
-
- if (boot->bpbRootClust < CLUST_FIRST ||
- boot->bpbRootClust >= boot->NumClusters) {
- pfatal("Root directory starts with cluster out of range(%u)",
- boot->bpbRootClust);
- return FSFATAL;
- }
- } else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK)) {
+ else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK))
boot->ClustMask = CLUST12_MASK;
- } else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK)) {
+ else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK))
boot->ClustMask = CLUST16_MASK;
- } else {
+ else {
pfatal("Filesystem too big (%u clusters) for non-FAT32 partition",
boot->NumClusters);
return FSFATAL;
Modified: head/sbin/fsck_msdosfs/check.c
==============================================================================
--- head/sbin/fsck_msdosfs/check.c Wed Jan 1 07:43:08 2020 (r356249)
+++ head/sbin/fsck_msdosfs/check.c Wed Jan 1 09:22:06 2020 (r356250)
@@ -47,8 +47,9 @@ checkfilesys(const char *fname)
{
int dosfs;
struct bootblock boot;
- struct fat_descriptor *fat = NULL;
+ struct fatEntry *fat = NULL;
int finish_dosdirsection=0;
+ u_int i;
int mod = 0;
int ret = 8;
@@ -87,39 +88,65 @@ checkfilesys(const char *fname)
}
if (!preen) {
- printf("** Phase 1 - Read FAT and checking connectivity\n");
+ if (boot.ValidFat < 0)
+ printf("** Phase 1 - Read and Compare FATs\n");
+ else
+ printf("** Phase 1 - Read FAT\n");
}
- mod |= readfat(dosfs, &boot, &fat);
+ mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat);
if (mod & FSFATAL) {
close(dosfs);
return 8;
}
+ if (boot.ValidFat < 0)
+ for (i = 1; i < boot.bpbFATs; i++) {
+ struct fatEntry *currentFat;
+
+ mod |= readfat(dosfs, &boot, i, ¤tFat);
+
+ if (mod & FSFATAL)
+ goto out;
+
+ mod |= comparefat(&boot, fat, currentFat, i);
+ free(currentFat);
+ if (mod & FSFATAL)
+ goto out;
+ }
+
if (!preen)
- printf("** Phase 2 - Checking Directories\n");
+ printf("** Phase 2 - Check Cluster Chains\n");
- mod |= resetDosDirSection(fat);
+ mod |= checkfat(&boot, fat);
+ if (mod & FSFATAL)
+ goto out;
+ /* delay writing FATs */
+
+ if (!preen)
+ printf("** Phase 3 - Checking Directories\n");
+
+ mod |= resetDosDirSection(&boot, fat);
finish_dosdirsection = 1;
if (mod & FSFATAL)
goto out;
/* delay writing FATs */
- mod |= handleDirTree(fat);
+ mod |= handleDirTree(dosfs, &boot, fat);
if (mod & FSFATAL)
goto out;
if (!preen)
- printf("** Phase 3 - Checking for Lost Files\n");
+ printf("** Phase 4 - Checking for Lost Files\n");
- mod |= checklost(fat);
+ mod |= checklost(dosfs, &boot, fat);
if (mod & FSFATAL)
goto out;
/* now write the FATs */
- if (mod & FSFATMOD) {
+ if (mod & (FSFATMOD|FSFIXFAT)) {
if (ask(1, "Update FATs")) {
- mod |= writefat(fat);
+ mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT);
if (mod & FSFATAL)
goto out;
} else
@@ -143,7 +170,7 @@ checkfilesys(const char *fname)
if (mod & FSDIRTY) {
pwarn("MARKING FILE SYSTEM CLEAN\n");
- mod |= writefat(fat);
+ mod |= writefat(dosfs, &boot, fat, 1);
} else {
pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n");
mod |= FSERROR; /* file system not clean */
Modified: head/sbin/fsck_msdosfs/dir.c
==============================================================================
--- head/sbin/fsck_msdosfs/dir.c Wed Jan 1 07:43:08 2020 (r356249)
+++ head/sbin/fsck_msdosfs/dir.c Wed Jan 1 09:22:06 2020 (r356250)
@@ -1,7 +1,6 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
- * Copyright (c) 2019 Google LLC
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
* Some structure declaration borrowed from Paul Popelka
@@ -96,11 +95,14 @@ static struct dirTodoNode *newDirTodo(void);
static void freeDirTodo(struct dirTodoNode *);
static char *fullpath(struct dosDirEntry *);
static u_char calcShortSum(u_char *);
-static int delete(struct fat_descriptor *, cl_t, int, cl_t, int, int);
-static int removede(struct fat_descriptor *, u_char *, u_char *,
- cl_t, cl_t, cl_t, char *, int);
-static int checksize(struct fat_descriptor *, u_char *, struct dosDirEntry *);
-static int readDosDirSection(struct fat_descriptor *, struct dosDirEntry *);
+static int delete(int, struct bootblock *, struct fatEntry *, cl_t, int,
+ cl_t, int, int);
+static int removede(int, struct bootblock *, struct fatEntry *, u_char *,
+ u_char *, cl_t, cl_t, cl_t, char *, int);
+static int checksize(struct bootblock *, struct fatEntry *, u_char *,
+ struct dosDirEntry *);
+static int readDosDirSection(int, struct bootblock *, struct fatEntry *,
+ struct dosDirEntry *);
/*
* Manage free dosDirEntry structures.
@@ -114,7 +116,7 @@ newDosDirEntry(void)
if (!(de = freede)) {
if (!(de = malloc(sizeof *de)))
- return (NULL);
+ return 0;
} else
freede = de->next;
return de;
@@ -191,7 +193,7 @@ fullpath(struct dosDirEntry *dir)
/*
* Calculate a checksum over an 8.3 alias name
*/
-static inline u_char
+static u_char
calcShortSum(u_char *p)
{
u_char sum = 0;
@@ -219,24 +221,21 @@ static struct dosDirEntry *lostDir;
* Init internal state for a new directory scan.
*/
int
-resetDosDirSection(struct fat_descriptor *fat)
+resetDosDirSection(struct bootblock *boot, struct fatEntry *fat)
{
- int rootdir_size, cluster_size;
+ int b1, b2;
int ret = FSOK;
size_t len;
- struct bootblock *boot;
- boot = fat_get_boot(fat);
+ b1 = boot->bpbRootDirEnts * 32;
+ b2 = boot->bpbSecPerClust * boot->bpbBytesPerSec;
- rootdir_size = boot->bpbRootDirEnts * 32;
- cluster_size = boot->bpbSecPerClust * boot->bpbBytesPerSec;
-
- if ((buffer = malloc(len = MAX(rootdir_size, cluster_size))) == NULL) {
+ if ((buffer = malloc(len = MAX(b1, b2))) == NULL) {
perr("No space for directory buffer (%zu)", len);
return FSFATAL;
}
- if ((delbuf = malloc(len = cluster_size)) == NULL) {
+ if ((delbuf = malloc(len = b2)) == NULL) {
free(buffer);
perr("No space for directory delbuf (%zu)", len);
return FSFATAL;
@@ -251,10 +250,18 @@ resetDosDirSection(struct fat_descriptor *fat)
memset(rootDir, 0, sizeof *rootDir);
if (boot->flags & FAT32) {
- if (!fat_is_cl_head(fat, boot->bpbRootClust)) {
+ if (boot->bpbRootClust < CLUST_FIRST ||
+ boot->bpbRootClust >= boot->NumClusters) {
+ pfatal("Root directory starts with cluster out of range(%u)",
+ boot->bpbRootClust);
+ return FSFATAL;
+ }
+ if (fat[boot->bpbRootClust].head != boot->bpbRootClust) {
pfatal("Root directory doesn't start a cluster chain");
return FSFATAL;
}
+
+ fat[boot->bpbRootClust].flags |= FAT_USED;
rootDir->head = boot->bpbRootClust;
}
@@ -295,21 +302,16 @@ finishDosDirSection(void)
* Delete directory entries between startcl, startoff and endcl, endoff.
*/
static int
-delete(struct fat_descriptor *fat, cl_t startcl,
+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;
off_t off;
- int clsz, fd;
- struct bootblock *boot;
+ int clsz = boot->bpbSecPerClust * boot->bpbBytesPerSec;
- boot = fat_get_boot(fat);
- fd = fat_get_fd(fat);
- clsz = boot->bpbSecPerClust * boot->bpbBytesPerSec;
-
s = delbuf + startoff;
e = delbuf + clsz;
- while (fat_is_valid_cl(fat, startcl)) {
+ while (startcl >= CLUST_FIRST && startcl < boot->NumClusters) {
if (startcl == endcl) {
if (notlast)
break;
@@ -318,11 +320,11 @@ delete(struct fat_descriptor *fat, cl_t startcl,
off = (startcl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
off *= boot->bpbBytesPerSec;
- if (lseek(fd, off, SEEK_SET) != off) {
+ if (lseek(f, off, SEEK_SET) != off) {
perr("Unable to lseek to %" PRId64, off);
return FSFATAL;
}
- if (read(fd, delbuf, clsz) != clsz) {
+ if (read(f, delbuf, clsz) != clsz) {
perr("Unable to read directory");
return FSFATAL;
}
@@ -330,26 +332,25 @@ delete(struct fat_descriptor *fat, cl_t startcl,
*s = SLOT_DELETED;
s += 32;
}
- if (lseek(fd, off, SEEK_SET) != off) {
+ if (lseek(f, off, SEEK_SET) != off) {
perr("Unable to lseek to %" PRId64, off);
return FSFATAL;
}
- if (write(fd, delbuf, clsz) != clsz) {
+ if (write(f, delbuf, clsz) != clsz) {
perr("Unable to write directory");
return FSFATAL;
}
if (startcl == endcl)
break;
- startcl = fat_get_cl_next(fat, startcl);
+ startcl = fat[startcl].next;
s = delbuf;
}
return FSOK;
}
static int
-removede(struct fat_descriptor *fat, u_char *start,
- u_char *end, cl_t startcl, cl_t endcl, cl_t curcl,
- char *path, int type)
+removede(int f, struct bootblock *boot, struct fatEntry *fat, u_char *start,
+ u_char *end, cl_t startcl, cl_t endcl, cl_t curcl, char *path, int type)
{
switch (type) {
case 0:
@@ -365,14 +366,14 @@ removede(struct fat_descriptor *fat, u_char *start,
}
if (ask(0, "Remove")) {
if (startcl != curcl) {
- if (delete(fat,
+ if (delete(f, boot, fat,
startcl, start - buffer,
endcl, end - buffer,
endcl == curcl) == FSFATAL)
return FSFATAL;
start = buffer;
}
- /* startcl is < CLUST_FIRST for !FAT32 root */
+ /* startcl is < CLUST_FIRST for !fat32 root */
if ((endcl == curcl) || (startcl < CLUST_FIRST))
for (; start < end; start += 32)
*start = SLOT_DELETED;
@@ -385,37 +386,23 @@ removede(struct fat_descriptor *fat, u_char *start,
* Check an in-memory file entry
*/
static int
-checksize(struct fat_descriptor *fat, u_char *p, struct dosDirEntry *dir)
+checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
+ struct dosDirEntry *dir)
{
- int ret = FSOK;
- size_t physicalSize;
- struct bootblock *boot;
-
- boot = fat_get_boot(fat);
-
/*
* Check size on ordinary files
*/
- if (dir->head == CLUST_FREE) {
+ u_int32_t physicalSize;
+
+ if (dir->head == CLUST_FREE)
physicalSize = 0;
- } else {
- if (!fat_is_valid_cl(fat, dir->head))
+ else {
+ if (dir->head < CLUST_FIRST || dir->head >= boot->NumClusters)
return FSERROR;
- ret = checkchain(fat, dir->head, &physicalSize);
- /*
- * Upon return, physicalSize would hold the chain length
- * that checkchain() was able to validate, but if the user
- * refused the proposed repair, it would be unsafe to
- * proceed with directory entry fix, so bail out in that
- * case.
- */
- if (ret == FSERROR) {
- return (FSERROR);
- }
- physicalSize *= boot->ClusterSize;
+ physicalSize = fat[dir->head].length * boot->ClusterSize;
}
if (physicalSize < dir->size) {
- pwarn("size of %s is %u, should at most be %zu\n",
+ pwarn("size of %s is %u, should at most be %u\n",
fullpath(dir), dir->size, physicalSize);
if (ask(1, "Truncate")) {
dir->size = physicalSize;
@@ -435,10 +422,11 @@ checksize(struct fat_descriptor *fat, u_char *p, struc
for (cl = dir->head, len = sz = 0;
(sz += boot->ClusterSize) < dir->size; len++)
- cl = fat_get_cl_next(fat, cl);
- clearchain(fat, fat_get_cl_next(fat, cl));
- ret = fat_set_cl_next(fat, cl, CLUST_EOF);
- return (FSFATMOD | ret);
+ 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;
}
@@ -454,20 +442,15 @@ static const u_char dotdot_name[11] = ".. ";
* when we traverse into it.
*/
static int
-check_subdirectory(struct fat_descriptor *fat, struct dosDirEntry *dir)
+check_subdirectory(int f, struct bootblock *boot, struct dosDirEntry *dir)
{
u_char *buf, *cp;
off_t off;
cl_t cl;
int retval = FSOK;
- int fd;
- struct bootblock *boot;
- boot = fat_get_boot(fat);
- fd = fat_get_fd(fat);
-
cl = dir->head;
- if (dir->parent && !fat_is_valid_cl(fat, cl)) {
+ if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) {
return FSERROR;
}
@@ -491,8 +474,8 @@ check_subdirectory(struct fat_descriptor *fat, struct
}
off *= boot->bpbBytesPerSec;
- if (lseek(fd, off, SEEK_SET) != off ||
- read(fd, buf, boot->bpbBytesPerSec) != (ssize_t)boot->bpbBytesPerSec) {
+ if (lseek(f, off, SEEK_SET) != off ||
+ read(f, buf, boot->bpbBytesPerSec) != (ssize_t)boot->bpbBytesPerSec) {
perr("Unable to read directory");
free(buf);
return FSFATAL;
@@ -526,27 +509,22 @@ check_subdirectory(struct fat_descriptor *fat, struct
* - push directories onto the todo-stack
*/
static int
-readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
+readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
+ struct dosDirEntry *dir)
{
- struct bootblock *boot;
struct dosDirEntry dirent, *d;
u_char *p, *vallfn, *invlfn, *empty;
off_t off;
- int fd, i, j, k, iosize, entries;
- bool is_legacyroot;
+ 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;
- size_t dirclusters;
#define THISMOD 0x8000 /* Only used within this routine */
- boot = fat_get_boot(fat);
- fd = fat_get_fd(fat);
-
cl = dir->head;
- if (dir->parent && (!fat_is_valid_cl(fat, cl))) {
+ if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) {
/*
* Already handled somewhere else.
*/
@@ -554,50 +532,24 @@ readDosDirSection(struct fat_descriptor *fat, struct d
}
shortSum = -1;
vallfn = invlfn = empty = NULL;
-
- /*
- * If we are checking the legacy root (for FAT12/FAT16),
- * we will operate on the whole directory; otherwise, we
- * will operate on one cluster at a time, and also take
- * this opportunity to examine the chain.
- *
- * Derive how many entries we are going to encounter from
- * the I/O size.
- */
- is_legacyroot = (dir->parent == NULL && !(boot->flags & FAT32));
- if (is_legacyroot) {
- iosize = boot->bpbRootDirEnts * 32;
- entries = boot->bpbRootDirEnts;
- } else {
- iosize = boot->bpbSecPerClust * boot->bpbBytesPerSec;
- entries = iosize / 32;
- mod |= checkchain(fat, dir->head, &dirclusters);
- }
-
do {
- if (is_legacyroot) {
- /*
- * Special case for FAT12/FAT16 root -- read
- * in the whole root directory.
- */
+ if (!(boot->flags & FAT32) && !dir->parent) {
+ last = boot->bpbRootDirEnts * 32;
off = boot->bpbResSectors + boot->bpbFATs *
boot->FATsecs;
} else {
- /*
- * Otherwise, read in a cluster of the
- * directory.
- */
+ last = boot->bpbSecPerClust * boot->bpbBytesPerSec;
off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
}
off *= boot->bpbBytesPerSec;
- if (lseek(fd, off, SEEK_SET) != off ||
- read(fd, buffer, iosize) != iosize) {
+ if (lseek(f, off, SEEK_SET) != off
+ || read(f, buffer, last) != last) {
perr("Unable to read directory");
return FSFATAL;
}
-
- for (p = buffer, i = 0; i < entries; i++, p += 32) {
+ last /= 32;
+ for (p = buffer, i = 0; i < last; i++, p += 32) {
if (dir->fsckflags & DIREMPWARN) {
*p = SLOT_EMPTY;
continue;
@@ -620,7 +572,7 @@ readDosDirSection(struct fat_descriptor *fat, struct d
u_char *q;
dir->fsckflags &= ~DIREMPTY;
- if (delete(fat,
+ if (delete(f, boot, fat,
empcl, empty - buffer,
cl, p - buffer, 1) == FSFATAL)
return FSFATAL;
@@ -749,7 +701,7 @@ readDosDirSection(struct fat_descriptor *fat, struct d
if (dirent.flags & ATTR_VOLUME) {
if (vallfn || invlfn) {
- mod |= removede(fat,
+ mod |= removede(f, boot, fat,
invlfn ? invlfn : vallfn, p,
invlfn ? invcl : valcl, -1, 0,
fullpath(dir), 2);
@@ -789,7 +741,7 @@ readDosDirSection(struct fat_descriptor *fat, struct d
dirent.next = dir->child;
if (invlfn) {
- mod |= k = removede(fat,
+ mod |= k = removede(f, boot, fat,
invlfn, vallfn ? vallfn : p,
invcl, vallfn ? valcl : cl, cl,
fullpath(&dirent), 0);
@@ -805,61 +757,74 @@ readDosDirSection(struct fat_descriptor *fat, struct d
vallfn = NULL; /* not used any longer */
invlfn = NULL;
- /*
- * Check if the directory entry is sane.
- *
- * '.' and '..' are skipped, their sanity is
- * checked somewhere else.
- *
- * For everything else, check if we have a new,
- * valid cluster chain (beginning of a file or
- * directory that was never previously claimed
- * by another file) when it's a non-empty file
- * or a directory. The sanity of the cluster
- * chain is checked at a later time when we
- * traverse into the directory, or examine the
- * file's directory entry.
- *
- * The only possible fix is to delete the entry
- * if it's a directory; for file, we have to
- * truncate the size to 0.
- */
- if (!(dirent.flags & ATTR_DIRECTORY) ||
- (strcmp(dirent.name, ".") != 0 &&
- strcmp(dirent.name, "..") != 0)) {
- if ((dirent.size != 0 || (dirent.flags & ATTR_DIRECTORY)) &&
- ((!fat_is_valid_cl(fat, dirent.head) ||
- !fat_is_cl_head(fat, dirent.head)))) {
- if (!fat_is_valid_cl(fat, dirent.head)) {
- pwarn("%s starts with cluster out of range(%u)\n",
- fullpath(&dirent),
- dirent.head);
- } else {
- pwarn("%s doesn't start a new cluster chain\n",
- fullpath(&dirent));
- }
-
- if (dirent.flags & ATTR_DIRECTORY) {
- if (ask(0, "Remove")) {
- *p = SLOT_DELETED;
- mod |= THISMOD|FSDIRMOD;
- } else
- mod |= FSERROR;
- continue;
- } else {
- if (ask(1, "Truncate")) {
- p[28] = p[29] = p[30] = p[31] = 0;
- p[26] = p[27] = 0;
- if (boot->ClustMask == CLUST32_MASK)
- p[20] = p[21] = 0;
- dirent.size = 0;
- dirent.head = 0;
- mod |= THISMOD|FSDIRMOD;
- } else
- mod |= FSERROR;
- }
+ if (dirent.size == 0 && !(dirent.flags & ATTR_DIRECTORY)) {
+ if (dirent.head != 0) {
+ pwarn("%s has clusters, but size 0\n",
+ fullpath(&dirent));
+ if (ask(1, "Drop allocated clusters")) {
+ p[26] = p[27] = 0;
+ if (boot->ClustMask == CLUST32_MASK)
+ p[20] = p[21] = 0;
+ clearchain(boot, fat, dirent.head);
+ dirent.head = 0;
+ mod |= THISMOD|FSDIRMOD|FSFATMOD;
+ } else
+ mod |= FSERROR;
}
+ } else if (dirent.head == 0
+ && !strcmp(dirent.name, "..")
+ && dir->parent /* XXX */
+ && !dir->parent->parent) {
+ /*
+ * Do nothing, the parent is the root
+ */
+ } else if (dirent.head < CLUST_FIRST
+ || dirent.head >= boot->NumClusters
+ || fat[dirent.head].next == CLUST_FREE
+ || (fat[dirent.head].next >= CLUST_RSRVD
+ && fat[dirent.head].next < CLUST_EOFS)
+ || fat[dirent.head].head != dirent.head) {
+ if (dirent.head == 0)
+ pwarn("%s has no clusters\n",
+ fullpath(&dirent));
+ else if (dirent.head < CLUST_FIRST
+ || dirent.head >= boot->NumClusters)
+ pwarn("%s starts with cluster out of range(%u)\n",
+ fullpath(&dirent),
+ dirent.head);
+ else if (fat[dirent.head].next == CLUST_FREE)
+ pwarn("%s starts with free cluster\n",
+ fullpath(&dirent));
+ else if (fat[dirent.head].next >= CLUST_RSRVD)
+ pwarn("%s starts with cluster marked %s\n",
+ fullpath(&dirent),
+ rsrvdcltype(fat[dirent.head].next));
+ else
+ pwarn("%s doesn't start a cluster chain\n",
+ fullpath(&dirent));
+ if (dirent.flags & ATTR_DIRECTORY) {
+ if (ask(0, "Remove")) {
+ *p = SLOT_DELETED;
+ mod |= THISMOD|FSDIRMOD;
+ } else
+ mod |= FSERROR;
+ continue;
+ } else {
+ if (ask(1, "Truncate")) {
+ p[28] = p[29] = p[30] = p[31] = 0;
+ p[26] = p[27] = 0;
+ if (boot->ClustMask == CLUST32_MASK)
+ p[20] = p[21] = 0;
+ dirent.size = 0;
+ mod |= THISMOD|FSDIRMOD;
+ } else
+ mod |= FSERROR;
+ }
}
+
+ if (dirent.head >= CLUST_FIRST && dirent.head < boot->NumClusters)
+ fat[dirent.head].flags |= FAT_USED;
+
if (dirent.flags & ATTR_DIRECTORY) {
/*
* gather more info for directories
@@ -896,7 +861,8 @@ readDosDirSection(struct fat_descriptor *fat, struct d
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) {
@@ -942,7 +908,7 @@ readDosDirSection(struct fat_descriptor *fat, struct d
} else
mod |= FSERROR;
continue;
- } else if ((check_subdirectory(fat,
+ } else if ((check_subdirectory(f, boot,
&dirent) & FSERROR) == FSERROR) {
/*
* A subdirectory should have
@@ -978,43 +944,39 @@ readDosDirSection(struct fat_descriptor *fat, struct d
n->dir = d;
pendingDirectories = n;
} else {
- mod |= k = checksize(fat, p, &dirent);
+ mod |= k = checksize(boot, fat, p, &dirent);
if (k & FSDIRMOD)
mod |= THISMOD;
}
boot->NumFiles++;
}
- if (is_legacyroot) {
- /*
- * Don't bother to write back right now because
- * we may continue to make modification to the
- * non-FAT32 root directory below.
- */
+ if (!(boot->flags & FAT32) && !dir->parent)
break;
- } else if (mod & THISMOD) {
- if (lseek(fd, off, SEEK_SET) != off
- || write(fd, buffer, iosize) != iosize) {
+
+ if (mod & THISMOD) {
+ last *= 32;
+ if (lseek(f, off, SEEK_SET) != off
+ || write(f, buffer, last) != last) {
perr("Unable to write directory");
return FSFATAL;
}
mod &= ~THISMOD;
}
- } while (fat_is_valid_cl(fat, (cl = fat_get_cl_next(fat, cl))));
+ } while ((cl = fat[cl].next) >= CLUST_FIRST && cl < boot->NumClusters);
if (invlfn || vallfn)
- mod |= removede(fat,
+ mod |= removede(f, boot, 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 removede() without
- * being written out.
+ /* 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) && is_legacyroot) {
- if (lseek(fd, off, SEEK_SET) != off
- || write(fd, buffer, iosize) != iosize) {
+ 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;
}
@@ -1024,11 +986,11 @@ readDosDirSection(struct fat_descriptor *fat, struct d
}
int
-handleDirTree(struct fat_descriptor *fat)
+handleDirTree(int dosfs, struct bootblock *boot, struct fatEntry *fat)
{
int mod;
- mod = readDosDirSection(fat, rootDir);
+ mod = readDosDirSection(dosfs, boot, fat, rootDir);
if (mod & FSFATAL)
return FSFATAL;
@@ -1049,7 +1011,7 @@ handleDirTree(struct fat_descriptor *fat)
/*
* handle subdirectory
*/
- mod |= readDosDirSection(fat, dir);
+ mod |= readDosDirSection(dosfs, boot, fat, dir);
if (mod & FSFATAL)
return FSFATAL;
}
@@ -1065,15 +1027,12 @@ static cl_t lfcl;
static off_t lfoff;
int
-reconnect(struct fat_descriptor *fat, cl_t head, size_t length)
+reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
{
- struct bootblock *boot = fat_get_boot(fat);
struct dosDirEntry d;
- int len, dosfs;
+ int len;
u_char *p;
- dosfs = fat_get_fd(fat);
-
if (!ask(1, "Reconnect"))
return FSERROR;
@@ -1104,7 +1063,7 @@ reconnect(struct fat_descriptor *fat, cl_t head, size_
break;
if (p && p < lfbuf + boot->ClusterSize)
break;
- lfcl = p ? fat_get_cl_next(fat, lfcl) : lostDir->head;
+ lfcl = p ? fat[lfcl].next : lostDir->head;
if (lfcl < CLUST_FIRST || lfcl >= boot->NumClusters) {
/* Extend LOSTDIR? XXX */
pwarn("No space in %s\n", LOSTDIR);
@@ -1129,7 +1088,7 @@ reconnect(struct fat_descriptor *fat, cl_t head, size_
len = snprintf(d.name, sizeof(d.name), "%u", head);
d.flags = 0;
d.head = head;
- d.size = length * boot->ClusterSize;
+ d.size = fat[head].length * boot->ClusterSize;
memcpy(p, d.name, len);
memset(p + len, ' ', 11 - len);
@@ -1144,6 +1103,7 @@ reconnect(struct fat_descriptor *fat, cl_t head, size_
p[29] = (u_char)(d.size >> 8);
p[30] = (u_char)(d.size >> 16);
p[31] = (u_char)(d.size >> 24);
+ fat[head].flags |= FAT_USED;
if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
|| (size_t)write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
perr("could not write LOST.DIR");
Modified: head/sbin/fsck_msdosfs/dosfs.h
==============================================================================
--- head/sbin/fsck_msdosfs/dosfs.h Wed Jan 1 07:43:08 2020 (r356249)
+++ head/sbin/fsck_msdosfs/dosfs.h Wed Jan 1 09:22:06 2020 (r356250)
@@ -83,13 +83,19 @@ struct bootblock {
u_int NumBad; /* # of bad clusters */
};
+struct fatEntry {
+ cl_t next; /* pointer to next cluster */
+ cl_t head; /* pointer to start of chain */
+ u_int32_t length; /* number of clusters on chain */
+ int flags; /* see below */
+};
+
#define CLUST_FREE 0 /* 0 means cluster is free */
#define CLUST_FIRST 2 /* 2 is the minimum valid cluster number */
#define CLUST_RSRVD 0xfffffff6 /* start of reserved clusters */
#define CLUST_BAD 0xfffffff7 /* a cluster with a defect */
#define CLUST_EOFS 0xfffffff8 /* start of EOF indicators */
#define CLUST_EOF 0xffffffff /* standard value for last cluster */
-#define CLUST_DEAD 0xfdeadc0d /* error encountered */
/*
* Masks for cluster values
@@ -97,6 +103,8 @@ struct bootblock {
#define CLUST12_MASK 0xfff
#define CLUST16_MASK 0xffff
#define CLUST32_MASK 0xfffffff
+
+#define FAT_USED 1 /* This fat chain is used in a file */
#define DOSLONGNAMELEN 256 /* long name maximal length */
#define LRFIRST 0x40 /* first long name record */
Modified: head/sbin/fsck_msdosfs/ext.h
==============================================================================
--- head/sbin/fsck_msdosfs/ext.h Wed Jan 1 07:43:08 2020 (r356249)
+++ head/sbin/fsck_msdosfs/ext.h Wed Jan 1 09:22:06 2020 (r356250)
@@ -32,8 +32,6 @@
#include <sys/types.h>
-#include <stdbool.h>
-
#include "dosfs.h"
#define LOSTDIR "LOST.DIR"
@@ -46,7 +44,6 @@ extern int alwaysyes; /* assume "yes" for all question
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 int allow_mmap; /* allow the use of mmap() */
/*
* function declarations
@@ -75,6 +72,7 @@ int checkfilesys(const char *);
#define FSERROR 8 /* Some unrecovered error remains */
#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 independent fashion and translate
@@ -87,53 +85,46 @@ int readboot(int, struct bootblock *);
*/
int writefsinfo(int, struct bootblock *);
-/* Opaque type */
-struct fat_descriptor;
+/*
+ * 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 *, u_int, struct fatEntry **);
-void fat_clear_cl_head(struct fat_descriptor *, cl_t);
-bool fat_is_cl_head(struct fat_descriptor *, cl_t);
+/*
+ * Check two FAT copies for consistency and merge changes into the
+ * first if necessary.
+ */
+int comparefat(struct bootblock *, struct fatEntry *, struct fatEntry *, u_int);
-cl_t fat_get_cl_next(struct fat_descriptor *, cl_t);
-
-int fat_set_cl_next(struct fat_descriptor *, cl_t, cl_t);
-
-cl_t fat_allocate_cluster(struct fat_descriptor *fat);
-
-struct bootblock* fat_get_boot(struct fat_descriptor *);
-int fat_get_fd(struct fat_descriptor *);
-bool fat_is_valid_cl(struct fat_descriptor *, cl_t);
-
/*
- * Read the FAT 0 and return a pointer to the newly allocated
- * descriptor of it.
+ * Check a FAT
*/
-int readfat(int, struct bootblock *, struct fat_descriptor **);
+int checkfat(struct bootblock *, struct fatEntry *);
/*
* Write back FAT entries
*/
-int writefat(struct fat_descriptor *);
+int writefat(int, struct bootblock *, struct fatEntry *, int);
/*
* Read a directory
*/
-int resetDosDirSection(struct fat_descriptor *);
+int resetDosDirSection(struct bootblock *, struct fatEntry *);
void finishDosDirSection(void);
-int handleDirTree(struct fat_descriptor *);
+int handleDirTree(int, struct bootblock *, struct fatEntry *);
/*
* Cross-check routines run after everything is completely in memory
*/
-int checkchain(struct fat_descriptor *, cl_t, size_t *);
-
/*
* Check for lost cluster chains
*/
-int checklost(struct fat_descriptor *);
+int checklost(int, struct bootblock *, struct fatEntry *);
/*
* Try to reconnect a lost cluster chain
*/
-int reconnect(struct fat_descriptor *, cl_t, size_t);
+int reconnect(int, struct bootblock *, struct fatEntry *, cl_t);
void finishlf(void);
/*
@@ -147,6 +138,6 @@ const char *rsrvdcltype(cl_t);
/*
* Clear a cluster chain in a FAT
*/
-void clearchain(struct fat_descriptor *, cl_t);
+void clearchain(struct bootblock *, struct fatEntry *, cl_t);
#endif
Modified: head/sbin/fsck_msdosfs/fat.c
==============================================================================
--- head/sbin/fsck_msdosfs/fat.c Wed Jan 1 07:43:08 2020 (r356249)
+++ head/sbin/fsck_msdosfs/fat.c Wed Jan 1 09:22:06 2020 (r356250)
@@ -1,7 +1,6 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2019 Google LLC
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann
*
@@ -34,14 +33,6 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
-#include <sys/endian.h>
-#include <sys/queue.h>
-#include <sys/limits.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-
-#include <assert.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -51,517 +42,12 @@ static const char rcsid[] =
#include "ext.h"
#include "fsutil.h"
-static int _readfat(struct fat_descriptor *);
-static inline struct bootblock* boot_of_(struct fat_descriptor *);
-static inline int fd_of_(struct fat_descriptor *);
-static inline bool valid_cl(struct fat_descriptor *, cl_t);
+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 *, u_int, u_char **);
-
-/*
- * Head bitmap for FAT scanning.
- *
- * FAT32 have up to 2^28 = 256M entries, and FAT16/12 have much less.
- * For each cluster, we use 1 bit to represent if it's a head cluster
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list