/* * Check a complete in-memory FAT for lost cluster chains */ int 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 || fat[head].next == CLUST_FREE || (fat[head].next >= CLUST_RSRVD && fat[head].next < CLUST_EOFS) || (fat[head].flags & FAT_USED)) continue; pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n", head, fat[head].length); mod |= ret = reconnect(dosfs, boot, fat, head); if (mod & FSFATAL) break; if (ret == FSERROR && ask(0, "Clear")) { clearchain(boot, fat, head); mod |= FSFATMOD; } } finishlf(); if (boot->FSInfo) { ret = 0; if (boot->FSFree != boot->NumFree) { pwarn("Free space in FSInfo block (%d) not correct (%d)\n", boot->FSFree, boot->NumFree); if (ask(1, "fix")) { boot->FSFree = boot->NumFree; ret = 1; } } if (boot->NumFree && (boot->FSNext >= boot->NumClusters || fat[boot->FSNext].next != CLUST_FREE)) { pwarn("Next free cluster in FSInfo block (%u) not free\n", boot->FSNext); if (ask(1, "fix")) for (head = CLUST_FIRST; head < boot->NumClusters; head++) if (fat[head].next == CLUST_FREE) { boot->FSNext = head; ret = 1; break; } } if (ret) mod |= writefsinfo(dosfs, boot); } return mod; }
int tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc) { if (ask(0, "Clear chain starting at %u", head)) { clearchain(boot, fat, head); return FSFATMOD; } else if (ask(0, "Truncate")) { *trunc = CLUST_EOF; return FSFATMOD; } else return FSERROR; }
int tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *truncp) { if (ask(0, "Clear chain starting at %u", head)) { 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; }
/* * Check a complete FAT in-memory for crosslinks */ int checkfat(struct bootblock *boot, struct fatEntry *fat) { cl_t head, p, h, n; u_int len; int ret = 0; int conf; /* * pass 1: figure out the cluster chains. */ for (head = CLUST_FIRST; head < boot->NumClusters; head++) { /* find next untravelled chain */ if (fat[head].head != 0 /* cluster already belongs to some chain */ || fat[head].next == CLUST_FREE || fat[head].next == CLUST_BAD) continue; /* skip it. */ /* follow the chain and mark all clusters on the way */ for (len = 0, p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = fat[p].next) { fat[p].head = head; len++; } /* the head record gets the length */ fat[head].length = fat[head].next == CLUST_FREE ? 0 : len; } /* * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because * we didn't know the real start of the chain then - would have treated partial * chains as interlinked with their main chain) */ for (head = CLUST_FIRST; head < boot->NumClusters; head++) { /* find next untravelled chain */ if (fat[head].head != head) continue; /* follow the chain to its end (hopefully) */ for (p = head; (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters; p = n) if (fat[n].head != head) break; if (n >= CLUST_EOFS) continue; if (n == CLUST_FREE || n >= CLUST_RSRVD) { pwarn("Cluster chain starting at %u ends with cluster marked %s\n", head, rsrvdcltype(n)); 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; } pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n", head, fat[n].head, n); conf = tryclear(boot, fat, head, &fat[p].next); if (ask(0, "Clear chain starting at %u", h = fat[n].head)) { if (conf == FSERROR) { /* * Transfer the common chain to the one not cleared above. */ for (p = n; p >= CLUST_FIRST && p < boot->NumClusters; p = fat[p].next) { if (h != fat[p].head) { /* * Have to reexamine this chain. */ head--; break; } fat[p].head = head; } } clearchain(boot, fat, h); conf |= FSFATMOD; } ret |= conf; } return ret; }