Revert r356249 for now as it broke GCC builds.
This commit is contained in:
parent
b06cf1e44f
commit
73db93b889
@ -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;
|
||||||
|
@ -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, ¤tFat);
|
||||||
|
|
||||||
|
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 */
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user