MFC r268632:
fsck_msdosfs: Assorted fixes from other BSDs. When truncating cluster chains fix the length of the cluster head. http://marc.info/?t=140304310700005&r=1&w=2 Avoid infinite loops in cluster chain linked lists. http://marc.info/?l=openbsd-tech&m=140275150804337&w=2 Avoid off-by-one on FAT12 filesystems. http://marc.info/?l=openbsd-tech&m=140234174104724&w=2 Obtained from: NetBSD (from OpenBSD)
This commit is contained in:
parent
7dbe20dfe1
commit
1a6840cdce
@ -419,13 +419,14 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
|
||||
fullpath(dir));
|
||||
if (ask(1, "Drop superfluous clusters")) {
|
||||
cl_t cl;
|
||||
u_int32_t sz = 0;
|
||||
u_int32_t sz, len;
|
||||
|
||||
for (cl = dir->head; (sz += boot->ClusterSize) <
|
||||
dir->size;)
|
||||
for (cl = dir->head, len = sz = 0;
|
||||
(sz += boot->ClusterSize) < dir->size; len++)
|
||||
cl = fat[cl].next;
|
||||
clearchain(boot, fat, fat[cl].next);
|
||||
fat[cl].next = CLUST_EOF;
|
||||
fat[dir->head].length = len;
|
||||
return FSFATMOD;
|
||||
} else
|
||||
return FSERROR;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user