diff options
author | pfg <pfg@FreeBSD.org> | 2014-07-21 23:23:20 +0000 |
---|---|---|
committer | pfg <pfg@FreeBSD.org> | 2014-07-21 23:23:20 +0000 |
commit | 1a6840cdcec9e054b3cd6b67ddf4e141474dce72 (patch) | |
tree | 7c37aa7d34405d4a83c7ccbac12ca996430cb4eb /sbin | |
parent | 7dbe20dfe17a0f32481021e5757ed851af808e15 (diff) | |
download | FreeBSD-src-1a6840cdcec9e054b3cd6b67ddf4e141474dce72.zip FreeBSD-src-1a6840cdcec9e054b3cd6b67ddf4e141474dce72.tar.gz |
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)
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/fsck_msdosfs/dir.c | 7 | ||||
-rw-r--r-- | sbin/fsck_msdosfs/fat.c | 41 |
2 files changed, 33 insertions, 15 deletions
diff --git a/sbin/fsck_msdosfs/dir.c b/sbin/fsck_msdosfs/dir.c index 008d0b3..65298d8 100644 --- a/sbin/fsck_msdosfs/dir.c +++ b/sbin/fsck_msdosfs/dir.c @@ -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; diff --git a/sbin/fsck_msdosfs/fat.c b/sbin/fsck_msdosfs/fat.c index 8db861a..b509c50 100644 --- a/sbin/fsck_msdosfs/fat.c +++ b/sbin/fsck_msdosfs/fat.c @@ -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; } } |