Revert r356249 for now as it broke GCC builds.

This commit is contained in:
Xin LI 2020-01-01 09:22:06 +00:00
parent b06cf1e44f
commit 73db93b889
7 changed files with 646 additions and 1225 deletions

View File

@ -152,6 +152,9 @@ readboot(int dosfs, struct bootblock *boot)
boot->NumSectors = boot->bpbHugeSectors; boot->NumSectors = boot->bpbHugeSectors;
} }
if (boot->flags & FAT32) { if (boot->flags & FAT32) {
/* If the OEM Name field is EXFAT, it's not FAT32, so bail */ /* If the OEM Name field is EXFAT, it's not FAT32, so bail */
if (!memcmp(&block[3], "EXFAT ", 8)) { if (!memcmp(&block[3], "EXFAT ", 8)) {
@ -269,30 +272,13 @@ readboot(int dosfs, struct bootblock *boot)
boot->NumClusters = (boot->NumSectors - boot->FirstCluster) / boot->bpbSecPerClust + boot->NumClusters = (boot->NumSectors - boot->FirstCluster) / boot->bpbSecPerClust +
CLUST_FIRST; CLUST_FIRST;
if (boot->flags & FAT32) { 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;
}
boot->ClustMask = CLUST32_MASK; boot->ClustMask = CLUST32_MASK;
else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_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)) {
boot->ClustMask = 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; boot->ClustMask = CLUST16_MASK;
} else { else {
pfatal("Filesystem too big (%u clusters) for non-FAT32 partition", pfatal("Filesystem too big (%u clusters) for non-FAT32 partition",
boot->NumClusters); boot->NumClusters);
return FSFATAL; return FSFATAL;

View File

@ -47,8 +47,9 @@ checkfilesys(const char *fname)
{ {
int dosfs; int dosfs;
struct bootblock boot; struct bootblock boot;
struct fat_descriptor *fat = NULL; struct fatEntry *fat = NULL;
int finish_dosdirsection=0; int finish_dosdirsection=0;
u_int i;
int mod = 0; int mod = 0;
int ret = 8; int ret = 8;
@ -87,39 +88,65 @@ checkfilesys(const char *fname)
} }
if (!preen) { 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) { if (mod & FSFATAL) {
close(dosfs); close(dosfs);
return 8; return 8;
} }
if (!preen) if (boot.ValidFat < 0)
printf("** Phase 2 - Checking Directories\n"); for (i = 1; i < boot.bpbFATs; i++) {
struct fatEntry *currentFat;
mod |= resetDosDirSection(fat); mod |= readfat(dosfs, &boot, i, &currentFat);
if (mod & FSFATAL)
goto out;
mod |= comparefat(&boot, fat, currentFat, i);
free(currentFat);
if (mod & FSFATAL)
goto out;
}
if (!preen)
printf("** Phase 2 - Check Cluster Chains\n");
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; finish_dosdirsection = 1;
if (mod & FSFATAL) if (mod & FSFATAL)
goto out; goto out;
/* delay writing FATs */ /* delay writing FATs */
mod |= handleDirTree(fat); mod |= handleDirTree(dosfs, &boot, fat);
if (mod & FSFATAL) if (mod & FSFATAL)
goto out; goto out;
if (!preen) 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) if (mod & FSFATAL)
goto out; goto out;
/* now write the FATs */ /* now write the FATs */
if (mod & FSFATMOD) { if (mod & (FSFATMOD|FSFIXFAT)) {
if (ask(1, "Update FATs")) { if (ask(1, "Update FATs")) {
mod |= writefat(fat); mod |= writefat(dosfs, &boot, fat, mod & FSFIXFAT);
if (mod & FSFATAL) if (mod & FSFATAL)
goto out; goto out;
} else } else
@ -143,7 +170,7 @@ checkfilesys(const char *fname)
if (mod & FSDIRTY) { if (mod & FSDIRTY) {
pwarn("MARKING FILE SYSTEM CLEAN\n"); pwarn("MARKING FILE SYSTEM CLEAN\n");
mod |= writefat(fat); mod |= writefat(dosfs, &boot, fat, 1);
} else { } else {
pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n"); pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n");
mod |= FSERROR; /* file system not clean */ mod |= FSERROR; /* file system not clean */

View File

@ -1,7 +1,6 @@
/*- /*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
* *
* Copyright (c) 2019 Google LLC
* Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
* Copyright (c) 1995 Martin Husemann * Copyright (c) 1995 Martin Husemann
* Some structure declaration borrowed from Paul Popelka * Some structure declaration borrowed from Paul Popelka
@ -96,11 +95,14 @@ static struct dirTodoNode *newDirTodo(void);
static void freeDirTodo(struct dirTodoNode *); static void freeDirTodo(struct dirTodoNode *);
static char *fullpath(struct dosDirEntry *); static char *fullpath(struct dosDirEntry *);
static u_char calcShortSum(u_char *); static u_char calcShortSum(u_char *);
static int delete(struct fat_descriptor *, cl_t, int, cl_t, int, int); static int delete(int, struct bootblock *, struct fatEntry *, cl_t, int,
static int removede(struct fat_descriptor *, u_char *, u_char *, cl_t, int, int);
cl_t, cl_t, cl_t, char *, int); static int removede(int, struct bootblock *, struct fatEntry *, u_char *,
static int checksize(struct fat_descriptor *, u_char *, struct dosDirEntry *); u_char *, cl_t, cl_t, cl_t, char *, int);
static int readDosDirSection(struct fat_descriptor *, struct dosDirEntry *); 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. * Manage free dosDirEntry structures.
@ -114,7 +116,7 @@ newDosDirEntry(void)
if (!(de = freede)) { if (!(de = freede)) {
if (!(de = malloc(sizeof *de))) if (!(de = malloc(sizeof *de)))
return (NULL); return 0;
} else } else
freede = de->next; freede = de->next;
return de; return de;
@ -191,7 +193,7 @@ fullpath(struct dosDirEntry *dir)
/* /*
* Calculate a checksum over an 8.3 alias name * Calculate a checksum over an 8.3 alias name
*/ */
static inline u_char static u_char
calcShortSum(u_char *p) calcShortSum(u_char *p)
{ {
u_char sum = 0; u_char sum = 0;
@ -219,24 +221,21 @@ static struct dosDirEntry *lostDir;
* Init internal state for a new directory scan. * Init internal state for a new directory scan.
*/ */
int int
resetDosDirSection(struct fat_descriptor *fat) resetDosDirSection(struct bootblock *boot, struct fatEntry *fat)
{ {
int rootdir_size, cluster_size; int b1, b2;
int ret = FSOK; int ret = FSOK;
size_t len; 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; if ((buffer = malloc(len = MAX(b1, b2))) == NULL) {
cluster_size = boot->bpbSecPerClust * boot->bpbBytesPerSec;
if ((buffer = malloc(len = MAX(rootdir_size, cluster_size))) == NULL) {
perr("No space for directory buffer (%zu)", len); perr("No space for directory buffer (%zu)", len);
return FSFATAL; return FSFATAL;
} }
if ((delbuf = malloc(len = cluster_size)) == NULL) { if ((delbuf = malloc(len = b2)) == NULL) {
free(buffer); free(buffer);
perr("No space for directory delbuf (%zu)", len); perr("No space for directory delbuf (%zu)", len);
return FSFATAL; return FSFATAL;
@ -251,10 +250,18 @@ resetDosDirSection(struct fat_descriptor *fat)
memset(rootDir, 0, sizeof *rootDir); memset(rootDir, 0, sizeof *rootDir);
if (boot->flags & FAT32) { 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"); pfatal("Root directory doesn't start a cluster chain");
return FSFATAL; return FSFATAL;
} }
fat[boot->bpbRootClust].flags |= FAT_USED;
rootDir->head = boot->bpbRootClust; rootDir->head = boot->bpbRootClust;
} }
@ -295,21 +302,16 @@ finishDosDirSection(void)
* Delete directory entries between startcl, startoff and endcl, endoff. * Delete directory entries between startcl, startoff and endcl, endoff.
*/ */
static int 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) int startoff, cl_t endcl, int endoff, int notlast)
{ {
u_char *s, *e; u_char *s, *e;
off_t off; off_t off;
int clsz, fd; int clsz = boot->bpbSecPerClust * boot->bpbBytesPerSec;
struct bootblock *boot;
boot = fat_get_boot(fat);
fd = fat_get_fd(fat);
clsz = boot->bpbSecPerClust * boot->bpbBytesPerSec;
s = delbuf + startoff; s = delbuf + startoff;
e = delbuf + clsz; e = delbuf + clsz;
while (fat_is_valid_cl(fat, startcl)) { while (startcl >= CLUST_FIRST && startcl < boot->NumClusters) {
if (startcl == endcl) { if (startcl == endcl) {
if (notlast) if (notlast)
break; break;
@ -318,11 +320,11 @@ delete(struct fat_descriptor *fat, cl_t startcl,
off = (startcl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster; off = (startcl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
off *= boot->bpbBytesPerSec; off *= boot->bpbBytesPerSec;
if (lseek(fd, off, SEEK_SET) != off) { if (lseek(f, off, SEEK_SET) != off) {
perr("Unable to lseek to %" PRId64, off); perr("Unable to lseek to %" PRId64, off);
return FSFATAL; return FSFATAL;
} }
if (read(fd, delbuf, clsz) != clsz) { if (read(f, delbuf, clsz) != clsz) {
perr("Unable to read directory"); perr("Unable to read directory");
return FSFATAL; return FSFATAL;
} }
@ -330,26 +332,25 @@ delete(struct fat_descriptor *fat, cl_t startcl,
*s = SLOT_DELETED; *s = SLOT_DELETED;
s += 32; s += 32;
} }
if (lseek(fd, off, SEEK_SET) != off) { if (lseek(f, off, SEEK_SET) != off) {
perr("Unable to lseek to %" PRId64, off); perr("Unable to lseek to %" PRId64, off);
return FSFATAL; return FSFATAL;
} }
if (write(fd, delbuf, clsz) != clsz) { if (write(f, delbuf, clsz) != clsz) {
perr("Unable to write directory"); perr("Unable to write directory");
return FSFATAL; return FSFATAL;
} }
if (startcl == endcl) if (startcl == endcl)
break; break;
startcl = fat_get_cl_next(fat, startcl); startcl = fat[startcl].next;
s = delbuf; s = delbuf;
} }
return FSOK; return FSOK;
} }
static int static int
removede(struct fat_descriptor *fat, u_char *start, removede(int f, struct bootblock *boot, struct fatEntry *fat, u_char *start,
u_char *end, cl_t startcl, cl_t endcl, cl_t curcl, u_char *end, cl_t startcl, cl_t endcl, cl_t curcl, char *path, int type)
char *path, int type)
{ {
switch (type) { switch (type) {
case 0: case 0:
@ -365,14 +366,14 @@ removede(struct fat_descriptor *fat, u_char *start,
} }
if (ask(0, "Remove")) { if (ask(0, "Remove")) {
if (startcl != curcl) { if (startcl != curcl) {
if (delete(fat, if (delete(f, boot, fat,
startcl, start - buffer, startcl, start - buffer,
endcl, end - buffer, endcl, end - buffer,
endcl == curcl) == FSFATAL) endcl == curcl) == FSFATAL)
return FSFATAL; return FSFATAL;
start = buffer; start = buffer;
} }
/* startcl is < CLUST_FIRST for !FAT32 root */ /* startcl is < CLUST_FIRST for !fat32 root */
if ((endcl == curcl) || (startcl < CLUST_FIRST)) if ((endcl == curcl) || (startcl < CLUST_FIRST))
for (; start < end; start += 32) for (; start < end; start += 32)
*start = SLOT_DELETED; *start = SLOT_DELETED;
@ -385,37 +386,23 @@ removede(struct fat_descriptor *fat, u_char *start,
* Check an in-memory file entry * Check an in-memory file entry
*/ */
static int 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 * Check size on ordinary files
*/ */
if (dir->head == CLUST_FREE) { u_int32_t physicalSize;
if (dir->head == CLUST_FREE)
physicalSize = 0; physicalSize = 0;
} else { else {
if (!fat_is_valid_cl(fat, dir->head)) if (dir->head < CLUST_FIRST || dir->head >= boot->NumClusters)
return FSERROR; return FSERROR;
ret = checkchain(fat, dir->head, &physicalSize); physicalSize = fat[dir->head].length * boot->ClusterSize;
/*
* 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;
} }
if (physicalSize < dir->size) { 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); fullpath(dir), dir->size, physicalSize);
if (ask(1, "Truncate")) { if (ask(1, "Truncate")) {
dir->size = physicalSize; dir->size = physicalSize;
@ -435,10 +422,11 @@ checksize(struct fat_descriptor *fat, u_char *p, struct dosDirEntry *dir)
for (cl = dir->head, len = sz = 0; for (cl = dir->head, len = sz = 0;
(sz += boot->ClusterSize) < dir->size; len++) (sz += boot->ClusterSize) < dir->size; len++)
cl = fat_get_cl_next(fat, cl); cl = fat[cl].next;
clearchain(fat, fat_get_cl_next(fat, cl)); clearchain(boot, fat, fat[cl].next);
ret = fat_set_cl_next(fat, cl, CLUST_EOF); fat[cl].next = CLUST_EOF;
return (FSFATMOD | ret); fat[dir->head].length = len;
return FSFATMOD;
} else } else
return FSERROR; return FSERROR;
} }
@ -454,20 +442,15 @@ static const u_char dotdot_name[11] = ".. ";
* when we traverse into it. * when we traverse into it.
*/ */
static int 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; u_char *buf, *cp;
off_t off; off_t off;
cl_t cl; cl_t cl;
int retval = FSOK; int retval = FSOK;
int fd;
struct bootblock *boot;
boot = fat_get_boot(fat);
fd = fat_get_fd(fat);
cl = dir->head; cl = dir->head;
if (dir->parent && !fat_is_valid_cl(fat, cl)) { if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) {
return FSERROR; return FSERROR;
} }
@ -491,8 +474,8 @@ check_subdirectory(struct fat_descriptor *fat, struct dosDirEntry *dir)
} }
off *= boot->bpbBytesPerSec; off *= boot->bpbBytesPerSec;
if (lseek(fd, off, SEEK_SET) != off || if (lseek(f, off, SEEK_SET) != off ||
read(fd, buf, boot->bpbBytesPerSec) != (ssize_t)boot->bpbBytesPerSec) { read(f, buf, boot->bpbBytesPerSec) != (ssize_t)boot->bpbBytesPerSec) {
perr("Unable to read directory"); perr("Unable to read directory");
free(buf); free(buf);
return FSFATAL; return FSFATAL;
@ -526,27 +509,22 @@ check_subdirectory(struct fat_descriptor *fat, struct dosDirEntry *dir)
* - push directories onto the todo-stack * - push directories onto the todo-stack
*/ */
static int 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; struct dosDirEntry dirent, *d;
u_char *p, *vallfn, *invlfn, *empty; u_char *p, *vallfn, *invlfn, *empty;
off_t off; off_t off;
int fd, i, j, k, iosize, entries; int i, j, k, last;
bool is_legacyroot;
cl_t cl, valcl = ~0, invcl = ~0, empcl = ~0; cl_t cl, valcl = ~0, invcl = ~0, empcl = ~0;
char *t; char *t;
u_int lidx = 0; u_int lidx = 0;
int shortSum; int shortSum;
int mod = FSOK; int mod = FSOK;
size_t dirclusters;
#define THISMOD 0x8000 /* Only used within this routine */ #define THISMOD 0x8000 /* Only used within this routine */
boot = fat_get_boot(fat);
fd = fat_get_fd(fat);
cl = dir->head; 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. * Already handled somewhere else.
*/ */
@ -554,50 +532,24 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
} }
shortSum = -1; shortSum = -1;
vallfn = invlfn = empty = NULL; 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 { do {
if (is_legacyroot) { if (!(boot->flags & FAT32) && !dir->parent) {
/* last = boot->bpbRootDirEnts * 32;
* Special case for FAT12/FAT16 root -- read
* in the whole root directory.
*/
off = boot->bpbResSectors + boot->bpbFATs * off = boot->bpbResSectors + boot->bpbFATs *
boot->FATsecs; boot->FATsecs;
} else { } else {
/* last = boot->bpbSecPerClust * boot->bpbBytesPerSec;
* Otherwise, read in a cluster of the
* directory.
*/
off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster; off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
} }
off *= boot->bpbBytesPerSec; off *= boot->bpbBytesPerSec;
if (lseek(fd, off, SEEK_SET) != off || if (lseek(f, off, SEEK_SET) != off
read(fd, buffer, iosize) != iosize) { || read(f, buffer, last) != last) {
perr("Unable to read directory"); perr("Unable to read directory");
return FSFATAL; return FSFATAL;
} }
last /= 32;
for (p = buffer, i = 0; i < entries; i++, p += 32) { for (p = buffer, i = 0; i < last; i++, p += 32) {
if (dir->fsckflags & DIREMPWARN) { if (dir->fsckflags & DIREMPWARN) {
*p = SLOT_EMPTY; *p = SLOT_EMPTY;
continue; continue;
@ -620,7 +572,7 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
u_char *q; u_char *q;
dir->fsckflags &= ~DIREMPTY; dir->fsckflags &= ~DIREMPTY;
if (delete(fat, if (delete(f, boot, fat,
empcl, empty - buffer, empcl, empty - buffer,
cl, p - buffer, 1) == FSFATAL) cl, p - buffer, 1) == FSFATAL)
return FSFATAL; return FSFATAL;
@ -749,7 +701,7 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
if (dirent.flags & ATTR_VOLUME) { if (dirent.flags & ATTR_VOLUME) {
if (vallfn || invlfn) { if (vallfn || invlfn) {
mod |= removede(fat, mod |= removede(f, boot, fat,
invlfn ? invlfn : vallfn, p, invlfn ? invlfn : vallfn, p,
invlfn ? invcl : valcl, -1, 0, invlfn ? invcl : valcl, -1, 0,
fullpath(dir), 2); fullpath(dir), 2);
@ -789,7 +741,7 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
dirent.next = dir->child; dirent.next = dir->child;
if (invlfn) { if (invlfn) {
mod |= k = removede(fat, mod |= k = removede(f, boot, fat,
invlfn, vallfn ? vallfn : p, invlfn, vallfn ? vallfn : p,
invcl, vallfn ? valcl : cl, cl, invcl, vallfn ? valcl : cl, cl,
fullpath(&dirent), 0); fullpath(&dirent), 0);
@ -805,61 +757,74 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
vallfn = NULL; /* not used any longer */ vallfn = NULL; /* not used any longer */
invlfn = NULL; invlfn = NULL;
/* if (dirent.size == 0 && !(dirent.flags & ATTR_DIRECTORY)) {
* Check if the directory entry is sane. if (dirent.head != 0) {
* pwarn("%s has clusters, but size 0\n",
* '.' and '..' are skipped, their sanity is fullpath(&dirent));
* checked somewhere else. if (ask(1, "Drop allocated clusters")) {
* p[26] = p[27] = 0;
* For everything else, check if we have a new, if (boot->ClustMask == CLUST32_MASK)
* valid cluster chain (beginning of a file or p[20] = p[21] = 0;
* directory that was never previously claimed clearchain(boot, fat, dirent.head);
* by another file) when it's a non-empty file dirent.head = 0;
* or a directory. The sanity of the cluster mod |= THISMOD|FSDIRMOD|FSFATMOD;
* chain is checked at a later time when we } else
* traverse into the directory, or examine the mod |= FSERROR;
* file's directory entry. }
* } else if (dirent.head == 0
* The only possible fix is to delete the entry && !strcmp(dirent.name, "..")
* if it's a directory; for file, we have to && dir->parent /* XXX */
* truncate the size to 0. && !dir->parent->parent) {
*/ /*
if (!(dirent.flags & ATTR_DIRECTORY) || * Do nothing, the parent is the root
(strcmp(dirent.name, ".") != 0 && */
strcmp(dirent.name, "..") != 0)) { } else if (dirent.head < CLUST_FIRST
if ((dirent.size != 0 || (dirent.flags & ATTR_DIRECTORY)) && || dirent.head >= boot->NumClusters
((!fat_is_valid_cl(fat, dirent.head) || || fat[dirent.head].next == CLUST_FREE
!fat_is_cl_head(fat, dirent.head)))) { || (fat[dirent.head].next >= CLUST_RSRVD
if (!fat_is_valid_cl(fat, dirent.head)) { && fat[dirent.head].next < CLUST_EOFS)
pwarn("%s starts with cluster out of range(%u)\n", || fat[dirent.head].head != dirent.head) {
fullpath(&dirent), if (dirent.head == 0)
dirent.head); pwarn("%s has no clusters\n",
} else { fullpath(&dirent));
pwarn("%s doesn't start a new cluster chain\n", else if (dirent.head < CLUST_FIRST
fullpath(&dirent)); || dirent.head >= boot->NumClusters)
} pwarn("%s starts with cluster out of range(%u)\n",
fullpath(&dirent),
if (dirent.flags & ATTR_DIRECTORY) { dirent.head);
if (ask(0, "Remove")) { else if (fat[dirent.head].next == CLUST_FREE)
*p = SLOT_DELETED; pwarn("%s starts with free cluster\n",
mod |= THISMOD|FSDIRMOD; fullpath(&dirent));
} else else if (fat[dirent.head].next >= CLUST_RSRVD)
mod |= FSERROR; pwarn("%s starts with cluster marked %s\n",
continue; fullpath(&dirent),
} else { rsrvdcltype(fat[dirent.head].next));
if (ask(1, "Truncate")) { else
p[28] = p[29] = p[30] = p[31] = 0; pwarn("%s doesn't start a cluster chain\n",
p[26] = p[27] = 0; fullpath(&dirent));
if (boot->ClustMask == CLUST32_MASK) if (dirent.flags & ATTR_DIRECTORY) {
p[20] = p[21] = 0; if (ask(0, "Remove")) {
dirent.size = 0; *p = SLOT_DELETED;
dirent.head = 0; mod |= THISMOD|FSDIRMOD;
mod |= THISMOD|FSDIRMOD; } else
} else mod |= FSERROR;
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) { if (dirent.flags & ATTR_DIRECTORY) {
/* /*
* gather more info for directories * gather more info for directories
@ -896,7 +861,8 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
mod |= FSERROR; mod |= FSERROR;
} }
continue; continue;
} else if (strcmp(dirent.name, "..") == 0) { }
if (strcmp(dirent.name, "..") == 0) {
if (dir->parent) { /* XXX */ if (dir->parent) { /* XXX */
if (!dir->parent->parent) { if (!dir->parent->parent) {
if (dirent.head) { if (dirent.head) {
@ -942,7 +908,7 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
} else } else
mod |= FSERROR; mod |= FSERROR;
continue; continue;
} else if ((check_subdirectory(fat, } else if ((check_subdirectory(f, boot,
&dirent) & FSERROR) == FSERROR) { &dirent) & FSERROR) == FSERROR) {
/* /*
* A subdirectory should have * A subdirectory should have
@ -978,43 +944,39 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
n->dir = d; n->dir = d;
pendingDirectories = n; pendingDirectories = n;
} else { } else {
mod |= k = checksize(fat, p, &dirent); mod |= k = checksize(boot, fat, p, &dirent);
if (k & FSDIRMOD) if (k & FSDIRMOD)
mod |= THISMOD; mod |= THISMOD;
} }
boot->NumFiles++; boot->NumFiles++;
} }
if (is_legacyroot) { if (!(boot->flags & FAT32) && !dir->parent)
/*
* Don't bother to write back right now because
* we may continue to make modification to the
* non-FAT32 root directory below.
*/
break; break;
} else if (mod & THISMOD) {
if (lseek(fd, off, SEEK_SET) != off if (mod & THISMOD) {
|| write(fd, buffer, iosize) != iosize) { last *= 32;
if (lseek(f, off, SEEK_SET) != off
|| write(f, buffer, last) != last) {
perr("Unable to write directory"); perr("Unable to write directory");
return FSFATAL; return FSFATAL;
} }
mod &= ~THISMOD; 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) if (invlfn || vallfn)
mod |= removede(fat, mod |= removede(f, boot, fat,
invlfn ? invlfn : vallfn, p, invlfn ? invlfn : vallfn, p,
invlfn ? invcl : valcl, -1, 0, invlfn ? invcl : valcl, -1, 0,
fullpath(dir), 1); fullpath(dir), 1);
/* /* The root directory of non fat32 filesystems is in a special
* The root directory of non-FAT32 filesystems is in a special * area and may have been modified above without being written out.
* area and may have been modified above removede() without
* being written out.
*/ */
if ((mod & FSDIRMOD) && is_legacyroot) { if ((mod & FSDIRMOD) && !(boot->flags & FAT32) && !dir->parent) {
if (lseek(fd, off, SEEK_SET) != off last *= 32;
|| write(fd, buffer, iosize) != iosize) { if (lseek(f, off, SEEK_SET) != off
|| write(f, buffer, last) != last) {
perr("Unable to write directory"); perr("Unable to write directory");
return FSFATAL; return FSFATAL;
} }
@ -1024,11 +986,11 @@ readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
} }
int int
handleDirTree(struct fat_descriptor *fat) handleDirTree(int dosfs, struct bootblock *boot, struct fatEntry *fat)
{ {
int mod; int mod;
mod = readDosDirSection(fat, rootDir); mod = readDosDirSection(dosfs, boot, fat, rootDir);
if (mod & FSFATAL) if (mod & FSFATAL)
return FSFATAL; return FSFATAL;
@ -1049,7 +1011,7 @@ handleDirTree(struct fat_descriptor *fat)
/* /*
* handle subdirectory * handle subdirectory
*/ */
mod |= readDosDirSection(fat, dir); mod |= readDosDirSection(dosfs, boot, fat, dir);
if (mod & FSFATAL) if (mod & FSFATAL)
return FSFATAL; return FSFATAL;
} }
@ -1065,15 +1027,12 @@ static cl_t lfcl;
static off_t lfoff; static off_t lfoff;
int 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; struct dosDirEntry d;
int len, dosfs; int len;
u_char *p; u_char *p;
dosfs = fat_get_fd(fat);
if (!ask(1, "Reconnect")) if (!ask(1, "Reconnect"))
return FSERROR; return FSERROR;
@ -1104,7 +1063,7 @@ reconnect(struct fat_descriptor *fat, cl_t head, size_t length)
break; break;
if (p && p < lfbuf + boot->ClusterSize) if (p && p < lfbuf + boot->ClusterSize)
break; 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) { if (lfcl < CLUST_FIRST || lfcl >= boot->NumClusters) {
/* Extend LOSTDIR? XXX */ /* Extend LOSTDIR? XXX */
pwarn("No space in %s\n", LOSTDIR); pwarn("No space in %s\n", LOSTDIR);
@ -1129,7 +1088,7 @@ reconnect(struct fat_descriptor *fat, cl_t head, size_t length)
len = snprintf(d.name, sizeof(d.name), "%u", head); len = snprintf(d.name, sizeof(d.name), "%u", head);
d.flags = 0; d.flags = 0;
d.head = head; d.head = head;
d.size = length * boot->ClusterSize; d.size = fat[head].length * boot->ClusterSize;
memcpy(p, d.name, len); memcpy(p, d.name, len);
memset(p + len, ' ', 11 - len); memset(p + len, ' ', 11 - len);
@ -1144,6 +1103,7 @@ reconnect(struct fat_descriptor *fat, cl_t head, size_t length)
p[29] = (u_char)(d.size >> 8); p[29] = (u_char)(d.size >> 8);
p[30] = (u_char)(d.size >> 16); p[30] = (u_char)(d.size >> 16);
p[31] = (u_char)(d.size >> 24); p[31] = (u_char)(d.size >> 24);
fat[head].flags |= FAT_USED;
if (lseek(dosfs, lfoff, SEEK_SET) != lfoff if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
|| (size_t)write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) { || (size_t)write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
perr("could not write LOST.DIR"); perr("could not write LOST.DIR");

View File

@ -83,13 +83,19 @@ struct bootblock {
u_int NumBad; /* # of bad clusters */ 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_FREE 0 /* 0 means cluster is free */
#define CLUST_FIRST 2 /* 2 is the minimum valid cluster number */ #define CLUST_FIRST 2 /* 2 is the minimum valid cluster number */
#define CLUST_RSRVD 0xfffffff6 /* start of reserved clusters */ #define CLUST_RSRVD 0xfffffff6 /* start of reserved clusters */
#define CLUST_BAD 0xfffffff7 /* a cluster with a defect */ #define CLUST_BAD 0xfffffff7 /* a cluster with a defect */
#define CLUST_EOFS 0xfffffff8 /* start of EOF indicators */ #define CLUST_EOFS 0xfffffff8 /* start of EOF indicators */
#define CLUST_EOF 0xffffffff /* standard value for last cluster */ #define CLUST_EOF 0xffffffff /* standard value for last cluster */
#define CLUST_DEAD 0xfdeadc0d /* error encountered */
/* /*
* Masks for cluster values * Masks for cluster values
@ -98,6 +104,8 @@ struct bootblock {
#define CLUST16_MASK 0xffff #define CLUST16_MASK 0xffff
#define CLUST32_MASK 0xfffffff #define CLUST32_MASK 0xfffffff
#define FAT_USED 1 /* This fat chain is used in a file */
#define DOSLONGNAMELEN 256 /* long name maximal length */ #define DOSLONGNAMELEN 256 /* long name maximal length */
#define LRFIRST 0x40 /* first long name record */ #define LRFIRST 0x40 /* first long name record */
#define LRNOMASK 0x1f /* mask to extract long record #define LRNOMASK 0x1f /* mask to extract long record

View File

@ -32,8 +32,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdbool.h>
#include "dosfs.h" #include "dosfs.h"
#define LOSTDIR "LOST.DIR" #define LOSTDIR "LOST.DIR"
@ -46,7 +44,6 @@ extern int alwaysyes; /* assume "yes" for all questions */
extern int preen; /* we are preening */ extern int preen; /* we are preening */
extern int rdonly; /* device is opened read only (supersedes above) */ extern int rdonly; /* device is opened read only (supersedes above) */
extern int skipclean; /* skip clean file systems if preening */ extern int skipclean; /* skip clean file systems if preening */
extern int allow_mmap; /* allow the use of mmap() */
/* /*
* function declarations * function declarations
@ -75,6 +72,7 @@ int checkfilesys(const char *);
#define FSERROR 8 /* Some unrecovered error remains */ #define FSERROR 8 /* Some unrecovered error remains */
#define FSFATAL 16 /* Some unrecoverable error occurred */ #define FSFATAL 16 /* Some unrecoverable error occurred */
#define FSDIRTY 32 /* File system is dirty */ #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 * 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 *); 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.
void fat_clear_cl_head(struct fat_descriptor *, cl_t); */
bool fat_is_cl_head(struct fat_descriptor *, cl_t); int readfat(int, struct bootblock *, u_int, struct fatEntry **);
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 * Check two FAT copies for consistency and merge changes into the
* descriptor of it. * first if necessary.
*/ */
int readfat(int, struct bootblock *, struct fat_descriptor **); int comparefat(struct bootblock *, struct fatEntry *, struct fatEntry *, u_int);
/*
* Check a FAT
*/
int checkfat(struct bootblock *, struct fatEntry *);
/* /*
* Write back FAT entries * Write back FAT entries
*/ */
int writefat(struct fat_descriptor *); int writefat(int, struct bootblock *, struct fatEntry *, int);
/* /*
* Read a directory * Read a directory
*/ */
int resetDosDirSection(struct fat_descriptor *); int resetDosDirSection(struct bootblock *, struct fatEntry *);
void finishDosDirSection(void); 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 * Cross-check routines run after everything is completely in memory
*/ */
int checkchain(struct fat_descriptor *, cl_t, size_t *);
/* /*
* Check for lost cluster chains * Check for lost cluster chains
*/ */
int checklost(struct fat_descriptor *); int checklost(int, struct bootblock *, struct fatEntry *);
/* /*
* Try to reconnect a lost cluster chain * 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); void finishlf(void);
/* /*
@ -147,6 +138,6 @@ const char *rsrvdcltype(cl_t);
/* /*
* Clear a cluster chain in a FAT * Clear a cluster chain in a FAT
*/ */
void clearchain(struct fat_descriptor *, cl_t); void clearchain(struct bootblock *, struct fatEntry *, cl_t);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,6 @@ int alwaysyes; /* assume "yes" for all questions */
int preen; /* set when preening */ int preen; /* set when preening */
int rdonly; /* device is opened read only (supersedes above) */ int rdonly; /* device is opened read only (supersedes above) */
int skipclean; /* skip clean file systems if preening */ int skipclean; /* skip clean file systems if preening */
int allow_mmap; /* Allow the use of mmap(), if possible */
static void usage(void) __dead2; static void usage(void) __dead2;
@ -69,8 +68,7 @@ main(int argc, char **argv)
int ch; int ch;
skipclean = 1; skipclean = 1;
allow_mmap = 1; while ((ch = getopt(argc, argv, "CfFnpy")) != -1) {
while ((ch = getopt(argc, argv, "CfFnpyM")) != -1) {
switch (ch) { switch (ch) {
case 'C': /* for fsck_ffs compatibility */ case 'C': /* for fsck_ffs compatibility */
break; break;
@ -100,10 +98,6 @@ main(int argc, char **argv)
preen = 1; preen = 1;
break; break;
case 'M':
allow_mmap = 0;
break;
default: default:
usage(); usage();
break; break;