summaryrefslogtreecommitdiffstats
path: root/sbin/fsck_msdosfs/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/fsck_msdosfs/fat.c')
-rw-r--r--sbin/fsck_msdosfs/fat.c52
1 files changed, 35 insertions, 17 deletions
diff --git a/sbin/fsck_msdosfs/fat.c b/sbin/fsck_msdosfs/fat.c
index d2d1444..b509c50 100644
--- a/sbin/fsck_msdosfs/fat.c
+++ b/sbin/fsck_msdosfs/fat.c
@@ -242,7 +242,7 @@ readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
ret |= FSDIRTY;
else {
/* just some odd byte sequence in FAT */
-
+
switch (boot->ClustMask) {
case CLUST32_MASK:
pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n",
@@ -262,7 +262,7 @@ readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
break;
}
-
+
if (ask(1, "Correct"))
ret |= FSFIXFAT;
}
@@ -436,7 +436,15 @@ tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *truncp)
clearchain(boot, fat, head);
return FSFATMOD;
} else if (ask(0, "Truncate")) {
+ uint32_t len;
+ cl_t p;
+
+ for (p = head, len = 0;
+ p >= CLUST_FIRST && p < boot->NumClusters;
+ p = fat[p].next, len++)
+ continue;
*truncp = CLUST_EOF;
+ fat[head].length = len;
return FSFATMOD;
} else
return FSERROR;
@@ -465,7 +473,8 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
/* follow the chain and mark all clusters on the way */
for (len = 0, p = head;
- p >= CLUST_FIRST && p < boot->NumClusters;
+ p >= CLUST_FIRST && p < boot->NumClusters &&
+ fat[p].head != head;
p = fat[p].next) {
fat[p].head = head;
len++;
@@ -486,10 +495,10 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
continue;
/* follow the chain to its end (hopefully) */
- for (p = head;
+ for (len = fat[head].length, p = head;
(n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
p = n)
- if (fat[n].head != head)
+ if (fat[n].head != head || len-- < 2)
break;
if (n >= CLUST_EOFS)
continue;
@@ -497,14 +506,20 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
if (n == CLUST_FREE || n >= CLUST_RSRVD) {
pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
head, rsrvdcltype(n));
+clear:
ret |= tryclear(boot, fat, head, &fat[p].next);
continue;
}
if (n < CLUST_FIRST || n >= boot->NumClusters) {
pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
- head, n);
- ret |= tryclear(boot, fat, head, &fat[p].next);
- continue;
+ head, n);
+ goto clear;
+ }
+ if (head == fat[n].head) {
+ pwarn("Cluster chain starting at %u loops at cluster %u\n",
+
+ head, p);
+ goto clear;
}
pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
head, fat[n].head, n);
@@ -621,13 +636,15 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
default:
if (fat[cl].next == CLUST_FREE)
boot->NumFree++;
- if (cl + 1 < boot->NumClusters
- && fat[cl + 1].next == CLUST_FREE)
- boot->NumFree++;
*p++ = (u_char)fat[cl].next;
- *p++ = (u_char)((fat[cl].next >> 8) & 0xf)
- |(u_char)(fat[cl+1].next << 4);
- *p++ = (u_char)(fat[++cl].next >> 4);
+ *p = (u_char)((fat[cl].next >> 8) & 0xf);
+ cl++;
+ if (cl >= boot->NumClusters)
+ break;
+ if (fat[cl].next == CLUST_FREE)
+ boot->NumFree++;
+ *p++ |= (u_char)(fat[cl + 1].next << 4);
+ *p++ = (u_char)(fat[cl + 1].next >> 4);
break;
}
}
@@ -653,7 +670,7 @@ checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
cl_t head;
int mod = FSOK;
int ret;
-
+
for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
/* find next untravelled chain */
if (fat[head].head != head
@@ -677,8 +694,9 @@ checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
if (boot->bpbFSInfo) {
ret = 0;
- if (boot->FSFree != boot->NumFree) {
- pwarn("Free space in FSInfo block (%d) not correct (%d)\n",
+ if (boot->FSFree != 0xffffffffU &&
+ boot->FSFree != boot->NumFree) {
+ pwarn("Free space in FSInfo block (%u) not correct (%u)\n",
boot->FSFree, boot->NumFree);
if (ask(1, "Fix")) {
boot->FSFree = boot->NumFree;
OpenPOWER on IntegriCloud