1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
5 * Copyright (c) 1995 Martin Husemann
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: fat.c,v 1.18 2006/06/05 16:51:18 christos Exp $");
32 static const char rcsid[] =
33 "$FreeBSD$";
34 #endif /* not lint */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <unistd.h>
41
42 #include "ext.h"
43 #include "fsutil.h"
44
45 static int checkclnum(struct bootblock *, u_int, cl_t, cl_t *);
46 static int clustdiffer(cl_t, cl_t *, cl_t *, u_int);
47 static int tryclear(struct bootblock *, struct fatEntry *, cl_t, cl_t *);
48 static int _readfat(int, struct bootblock *, u_int, u_char **);
49
50 /*-
51 * The first 2 FAT entries contain pseudo-cluster numbers with the following
52 * layout:
53 *
54 * 31...... ........ ........ .......0
55 * rrrr1111 11111111 11111111 mmmmmmmm FAT32 entry 0
56 * rrrrsh11 11111111 11111111 11111xxx FAT32 entry 1
57 *
58 * 11111111 mmmmmmmm FAT16 entry 0
59 * sh111111 11111xxx FAT16 entry 1
60 *
61 * r = reserved
62 * m = BPB media ID byte
63 * s = clean flag (1 = dismounted; 0 = still mounted)
64 * h = hard error flag (1 = ok; 0 = I/O error)
65 * x = any value ok
66 */
67
68 int
checkdirty(int fs,struct bootblock * boot)69 checkdirty(int fs, struct bootblock *boot)
70 {
71 off_t off;
72 u_char *buffer;
73 int ret = 0;
74 size_t len;
75
76 if (boot->ClustMask != CLUST16_MASK && boot->ClustMask != CLUST32_MASK)
77 return 0;
78
79 off = boot->bpbResSectors;
80 off *= boot->bpbBytesPerSec;
81
82 buffer = malloc(len = boot->bpbBytesPerSec);
83 if (buffer == NULL) {
84 perr("No space for FAT sectors (%zu)", len);
85 return 1;
86 }
87
88 if (lseek(fs, off, SEEK_SET) != off) {
89 perr("Unable to read FAT");
90 goto err;
91 }
92
93 if ((size_t)read(fs, buffer, boot->bpbBytesPerSec) !=
94 boot->bpbBytesPerSec) {
95 perr("Unable to read FAT");
96 goto err;
97 }
98
99 /*
100 * If we don't understand the FAT, then the file system must be
101 * assumed to be unclean.
102 */
103 if (buffer[0] != boot->bpbMedia || buffer[1] != 0xff)
104 goto err;
105 if (boot->ClustMask == CLUST16_MASK) {
106 if ((buffer[2] & 0xf8) != 0xf8 || (buffer[3] & 0x3f) != 0x3f)
107 goto err;
108 } else {
109 if (buffer[2] != 0xff || (buffer[3] & 0x0f) != 0x0f
110 || (buffer[4] & 0xf8) != 0xf8 || buffer[5] != 0xff
111 || buffer[6] != 0xff || (buffer[7] & 0x03) != 0x03)
112 goto err;
113 }
114
115 /*
116 * Now check the actual clean flag (and the no-error flag).
117 */
118 if (boot->ClustMask == CLUST16_MASK) {
119 if ((buffer[3] & 0xc0) == 0xc0)
120 ret = 1;
121 } else {
122 if ((buffer[7] & 0x0c) == 0x0c)
123 ret = 1;
124 }
125
126 err:
127 free(buffer);
128 return ret;
129 }
130
131 /*
132 * Check a cluster number for valid value
133 */
134 static int
checkclnum(struct bootblock * boot,u_int fat,cl_t cl,cl_t * next)135 checkclnum(struct bootblock *boot, u_int fat, cl_t cl, cl_t *next)
136 {
137 if (*next >= (CLUST_RSRVD&boot->ClustMask))
138 *next |= ~boot->ClustMask;
139 if (*next == CLUST_FREE) {
140 boot->NumFree++;
141 return FSOK;
142 }
143 if (*next == CLUST_BAD) {
144 boot->NumBad++;
145 return FSOK;
146 }
147 if (*next < CLUST_FIRST
148 || (*next >= boot->NumClusters && *next < CLUST_EOFS)) {
149 pwarn("Cluster %u in FAT %d continues with %s cluster number %u\n",
150 cl, fat,
151 *next < CLUST_RSRVD ? "out of range" : "reserved",
152 *next&boot->ClustMask);
153 if (ask(0, "Truncate")) {
154 *next = CLUST_EOF;
155 return FSFATMOD;
156 }
157 return FSERROR;
158 }
159 return FSOK;
160 }
161
162 /*
163 * Read a FAT from disk. Returns 1 if successful, 0 otherwise.
164 */
165 static int
_readfat(int fs,struct bootblock * boot,u_int no,u_char ** buffer)166 _readfat(int fs, struct bootblock *boot, u_int no, u_char **buffer)
167 {
168 off_t off;
169 size_t len;
170
171 *buffer = malloc(len = boot->FATsecs * boot->bpbBytesPerSec);
172 if (*buffer == NULL) {
173 perr("No space for FAT sectors (%zu)", len);
174 return 0;
175 }
176
177 off = boot->bpbResSectors + no * boot->FATsecs;
178 off *= boot->bpbBytesPerSec;
179
180 if (lseek(fs, off, SEEK_SET) != off) {
181 perr("Unable to read FAT");
182 goto err;
183 }
184
185 if ((size_t)read(fs, *buffer, boot->FATsecs * boot->bpbBytesPerSec)
186 != boot->FATsecs * boot->bpbBytesPerSec) {
187 perr("Unable to read FAT");
188 goto err;
189 }
190
191 return 1;
192
193 err:
194 free(*buffer);
195 return 0;
196 }
197
198 /*
199 * Read a FAT and decode it into internal format
200 */
201 int
readfat(int fs,struct bootblock * boot,u_int no,struct fatEntry ** fp)202 readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
203 {
204 struct fatEntry *fat;
205 u_char *buffer, *p;
206 cl_t cl;
207 int ret = FSOK;
208 size_t len;
209
210 boot->NumFree = boot->NumBad = 0;
211
212 if (!_readfat(fs, boot, no, &buffer))
213 return FSFATAL;
214
215 fat = malloc(len = boot->NumClusters * sizeof(struct fatEntry));
216 if (fat == NULL) {
217 perr("No space for FAT clusters (%zu)", len);
218 free(buffer);
219 return FSFATAL;
220 }
221 (void)memset(fat, 0, len);
222
223 if (buffer[0] != boot->bpbMedia
224 || buffer[1] != 0xff || buffer[2] != 0xff
225 || (boot->ClustMask == CLUST16_MASK && buffer[3] != 0xff)
226 || (boot->ClustMask == CLUST32_MASK
227 && ((buffer[3]&0x0f) != 0x0f
228 || buffer[4] != 0xff || buffer[5] != 0xff
229 || buffer[6] != 0xff || (buffer[7]&0x0f) != 0x0f))) {
230
231 /* Windows 95 OSR2 (and possibly any later) changes
232 * the FAT signature to 0xXXffff7f for FAT16 and to
233 * 0xXXffff0fffffff07 for FAT32 upon boot, to know that the
234 * file system is dirty if it doesn't reboot cleanly.
235 * Check this special condition before errorring out.
236 */
237 if (buffer[0] == boot->bpbMedia && buffer[1] == 0xff
238 && buffer[2] == 0xff
239 && ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f)
240 || (boot->ClustMask == CLUST32_MASK
241 && buffer[3] == 0x0f && buffer[4] == 0xff
242 && buffer[5] == 0xff && buffer[6] == 0xff
243 && buffer[7] == 0x07)))
244 ret |= FSDIRTY;
245 else {
246 /* just some odd byte sequence in FAT */
247
248 switch (boot->ClustMask) {
249 case CLUST32_MASK:
250 pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n",
251 "FAT starts with odd byte sequence",
252 buffer[0], buffer[1], buffer[2], buffer[3],
253 buffer[4], buffer[5], buffer[6], buffer[7]);
254 break;
255 case CLUST16_MASK:
256 pwarn("%s (%02x%02x%02x%02x)\n",
257 "FAT starts with odd byte sequence",
258 buffer[0], buffer[1], buffer[2], buffer[3]);
259 break;
260 default:
261 pwarn("%s (%02x%02x%02x)\n",
262 "FAT starts with odd byte sequence",
263 buffer[0], buffer[1], buffer[2]);
264 break;
265 }
266
267
268 if (ask(1, "Correct"))
269 ret |= FSFIXFAT;
270 }
271 }
272 switch (boot->ClustMask) {
273 case CLUST32_MASK:
274 p = buffer + 8;
275 break;
276 case CLUST16_MASK:
277 p = buffer + 4;
278 break;
279 default:
280 p = buffer + 3;
281 break;
282 }
283 for (cl = CLUST_FIRST; cl < boot->NumClusters;) {
284 switch (boot->ClustMask) {
285 case CLUST32_MASK:
286 fat[cl].next = p[0] + (p[1] << 8)
287 + (p[2] << 16) + (p[3] << 24);
288 fat[cl].next &= boot->ClustMask;
289 ret |= checkclnum(boot, no, cl, &fat[cl].next);
290 cl++;
291 p += 4;
292 break;
293 case CLUST16_MASK:
294 fat[cl].next = p[0] + (p[1] << 8);
295 ret |= checkclnum(boot, no, cl, &fat[cl].next);
296 cl++;
297 p += 2;
298 break;
299 default:
300 fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff;
301 ret |= checkclnum(boot, no, cl, &fat[cl].next);
302 cl++;
303 if (cl >= boot->NumClusters)
304 break;
305 fat[cl].next = ((p[1] >> 4) + (p[2] << 4)) & 0x0fff;
306 ret |= checkclnum(boot, no, cl, &fat[cl].next);
307 cl++;
308 p += 3;
309 break;
310 }
311 }
312
313 free(buffer);
314 if (ret & FSFATAL) {
315 free(fat);
316 *fp = NULL;
317 } else
318 *fp = fat;
319 return ret;
320 }
321
322 /*
323 * Get type of reserved cluster
324 */
325 const char *
rsrvdcltype(cl_t cl)326 rsrvdcltype(cl_t cl)
327 {
328 if (cl == CLUST_FREE)
329 return "free";
330 if (cl < CLUST_BAD)
331 return "reserved";
332 if (cl > CLUST_BAD)
333 return "as EOF";
334 return "bad";
335 }
336
337 static int
clustdiffer(cl_t cl,cl_t * cp1,cl_t * cp2,u_int fatnum)338 clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, u_int fatnum)
339 {
340 if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) {
341 if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
342 if ((*cp1 != CLUST_FREE && *cp1 < CLUST_BAD
343 && *cp2 != CLUST_FREE && *cp2 < CLUST_BAD)
344 || (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) {
345 pwarn("Cluster %u is marked %s with different indicators\n",
346 cl, rsrvdcltype(*cp1));
347 if (ask(1, "Fix")) {
348 *cp2 = *cp1;
349 return FSFATMOD;
350 }
351 return FSFATAL;
352 }
353 pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %u\n",
354 cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum);
355 if (ask(0, "Use FAT 0's entry")) {
356 *cp2 = *cp1;
357 return FSFATMOD;
358 }
359 if (ask(0, "Use FAT %u's entry", fatnum)) {
360 *cp1 = *cp2;
361 return FSFATMOD;
362 }
363 return FSFATAL;
364 }
365 pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n",
366 cl, rsrvdcltype(*cp1), *cp2, fatnum);
367 if (ask(0, "Use continuation from FAT %u", fatnum)) {
368 *cp1 = *cp2;
369 return FSFATMOD;
370 }
371 if (ask(0, "Use mark from FAT 0")) {
372 *cp2 = *cp1;
373 return FSFATMOD;
374 }
375 return FSFATAL;
376 }
377 if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
378 pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %u\n",
379 cl, *cp1, rsrvdcltype(*cp2), fatnum);
380 if (ask(0, "Use continuation from FAT 0")) {
381 *cp2 = *cp1;
382 return FSFATMOD;
383 }
384 if (ask(0, "Use mark from FAT %d", fatnum)) {
385 *cp1 = *cp2;
386 return FSFATMOD;
387 }
388 return FSERROR;
389 }
390 pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %u\n",
391 cl, *cp1, *cp2, fatnum);
392 if (ask(0, "Use continuation from FAT 0")) {
393 *cp2 = *cp1;
394 return FSFATMOD;
395 }
396 if (ask(0, "Use continuation from FAT %u", fatnum)) {
397 *cp1 = *cp2;
398 return FSFATMOD;
399 }
400 return FSERROR;
401 }
402
403 /*
404 * Compare two FAT copies in memory. Resolve any conflicts and merge them
405 * into the first one.
406 */
407 int
comparefat(struct bootblock * boot,struct fatEntry * first,struct fatEntry * second,u_int fatnum)408 comparefat(struct bootblock *boot, struct fatEntry *first,
409 struct fatEntry *second, u_int fatnum)
410 {
411 cl_t cl;
412 int ret = FSOK;
413
414 for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++)
415 if (first[cl].next != second[cl].next)
416 ret |= clustdiffer(cl, &first[cl].next, &second[cl].next, fatnum);
417 return ret;
418 }
419
420 void
clearchain(struct bootblock * boot,struct fatEntry * fat,cl_t head)421 clearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head)
422 {
423 cl_t p, q;
424
425 for (p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = q) {
426 if (fat[p].head != head)
427 break;
428 q = fat[p].next;
429 fat[p].next = fat[p].head = CLUST_FREE;
430 fat[p].length = 0;
431 }
432 }
433
434 int
tryclear(struct bootblock * boot,struct fatEntry * fat,cl_t head,cl_t * truncp)435 tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *truncp)
436 {
437 if (ask(0, "Clear chain starting at %u", head)) {
438 clearchain(boot, fat, head);
439 return FSFATMOD;
440 } else if (ask(0, "Truncate")) {
441 uint32_t len;
442 cl_t p;
443
444 for (p = head, len = 0;
445 p >= CLUST_FIRST && p < boot->NumClusters;
446 p = fat[p].next, len++)
447 continue;
448 *truncp = CLUST_EOF;
449 fat[head].length = len;
450 return FSFATMOD;
451 } else
452 return FSERROR;
453 }
454
455 /*
456 * Check a complete FAT in-memory for crosslinks
457 */
458 int
checkfat(struct bootblock * boot,struct fatEntry * fat)459 checkfat(struct bootblock *boot, struct fatEntry *fat)
460 {
461 cl_t head, p, h, n;
462 u_int len;
463 int ret = 0;
464 int conf;
465
466 /*
467 * pass 1: figure out the cluster chains.
468 */
469 for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
470 /* find next untravelled chain */
471 if (fat[head].head != 0 /* cluster already belongs to some chain */
472 || fat[head].next == CLUST_FREE
473 || fat[head].next == CLUST_BAD)
474 continue; /* skip it. */
475
476 /* follow the chain and mark all clusters on the way */
477 for (len = 0, p = head;
478 p >= CLUST_FIRST && p < boot->NumClusters &&
479 fat[p].head != head;
480 p = fat[p].next) {
481 fat[p].head = head;
482 len++;
483 }
484
485 /* the head record gets the length */
486 fat[head].length = fat[head].next == CLUST_FREE ? 0 : len;
487 }
488
489 /*
490 * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because
491 * we didn't know the real start of the chain then - would have treated partial
492 * chains as interlinked with their main chain)
493 */
494 for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
495 /* find next untravelled chain */
496 if (fat[head].head != head)
497 continue;
498
499 /* follow the chain to its end (hopefully) */
500 for (len = fat[head].length, p = head;
501 (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
502 p = n)
503 if (fat[n].head != head || len-- < 2)
504 break;
505 if (n >= CLUST_EOFS)
506 continue;
507
508 if (n == CLUST_FREE || n >= CLUST_RSRVD) {
509 pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
510 head, rsrvdcltype(n));
511 clear:
512 ret |= tryclear(boot, fat, head, &fat[p].next);
513 continue;
514 }
515 if (n < CLUST_FIRST || n >= boot->NumClusters) {
516 pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
517 head, n);
518 goto clear;
519 }
520 if (head == fat[n].head) {
521 pwarn("Cluster chain starting at %u loops at cluster %u\n",
522
523 head, p);
524 goto clear;
525 }
526 pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
527 head, fat[n].head, n);
528 conf = tryclear(boot, fat, head, &fat[p].next);
529 if (ask(0, "Clear chain starting at %u", h = fat[n].head)) {
530 if (conf == FSERROR) {
531 /*
532 * Transfer the common chain to the one not cleared above.
533 */
534 for (p = n;
535 p >= CLUST_FIRST && p < boot->NumClusters;
536 p = fat[p].next) {
537 if (h != fat[p].head) {
538 /*
539 * Have to reexamine this chain.
540 */
541 head--;
542 break;
543 }
544 fat[p].head = head;
545 }
546 }
547 clearchain(boot, fat, h);
548 conf |= FSFATMOD;
549 }
550 ret |= conf;
551 }
552
553 return ret;
554 }
555
556 /*
557 * Write out FATs encoding them from the internal format
558 */
559 int
writefat(int fs,struct bootblock * boot,struct fatEntry * fat,int correct_fat)560 writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
561 {
562 u_char *buffer, *p;
563 cl_t cl;
564 u_int i;
565 size_t fatsz;
566 off_t off;
567 int ret = FSOK;
568
569 buffer = malloc(fatsz = boot->FATsecs * boot->bpbBytesPerSec);
570 if (buffer == NULL) {
571 perr("No space for FAT sectors (%zu)", fatsz);
572 return FSFATAL;
573 }
574 memset(buffer, 0, fatsz);
575 boot->NumFree = 0;
576 p = buffer;
577 if (correct_fat) {
578 *p++ = (u_char)boot->bpbMedia;
579 *p++ = 0xff;
580 *p++ = 0xff;
581 switch (boot->ClustMask) {
582 case CLUST16_MASK:
583 *p++ = 0xff;
584 break;
585 case CLUST32_MASK:
586 *p++ = 0x0f;
587 *p++ = 0xff;
588 *p++ = 0xff;
589 *p++ = 0xff;
590 *p++ = 0x0f;
591 break;
592 }
593 } else {
594 /* use same FAT signature as the old FAT has */
595 int count;
596 u_char *old_fat;
597
598 switch (boot->ClustMask) {
599 case CLUST32_MASK:
600 count = 8;
601 break;
602 case CLUST16_MASK:
603 count = 4;
604 break;
605 default:
606 count = 3;
607 break;
608 }
609
610 if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0,
611 &old_fat)) {
612 free(buffer);
613 return FSFATAL;
614 }
615
616 memcpy(p, old_fat, count);
617 free(old_fat);
618 p += count;
619 }
620
621 for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
622 switch (boot->ClustMask) {
623 case CLUST32_MASK:
624 if (fat[cl].next == CLUST_FREE)
625 boot->NumFree++;
626 *p++ = (u_char)fat[cl].next;
627 *p++ = (u_char)(fat[cl].next >> 8);
628 *p++ = (u_char)(fat[cl].next >> 16);
629 *p &= 0xf0;
630 *p++ |= (fat[cl].next >> 24)&0x0f;
631 break;
632 case CLUST16_MASK:
633 if (fat[cl].next == CLUST_FREE)
634 boot->NumFree++;
635 *p++ = (u_char)fat[cl].next;
636 *p++ = (u_char)(fat[cl].next >> 8);
637 break;
638 default:
639 if (fat[cl].next == CLUST_FREE)
640 boot->NumFree++;
641 *p++ = (u_char)fat[cl].next;
642 *p = (u_char)((fat[cl].next >> 8) & 0xf);
643 cl++;
644 if (cl >= boot->NumClusters)
645 break;
646 if (fat[cl].next == CLUST_FREE)
647 boot->NumFree++;
648 *p++ |= (u_char)(fat[cl + 1].next << 4);
649 *p++ = (u_char)(fat[cl + 1].next >> 4);
650 break;
651 }
652 }
653 for (i = 0; i < boot->bpbFATs; i++) {
654 off = boot->bpbResSectors + i * boot->FATsecs;
655 off *= boot->bpbBytesPerSec;
656 if (lseek(fs, off, SEEK_SET) != off
657 || (size_t)write(fs, buffer, fatsz) != fatsz) {
658 perr("Unable to write FAT");
659 ret = FSFATAL; /* Return immediately? XXX */
660 }
661 }
662 free(buffer);
663 return ret;
664 }
665
666 /*
667 * Check a complete in-memory FAT for lost cluster chains
668 */
669 int
checklost(int dosfs,struct bootblock * boot,struct fatEntry * fat)670 checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
671 {
672 cl_t head;
673 int mod = FSOK;
674 int ret;
675
676 for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
677 /* find next untravelled chain */
678 if (fat[head].head != head
679 || fat[head].next == CLUST_FREE
680 || (fat[head].next >= CLUST_RSRVD
681 && fat[head].next < CLUST_EOFS)
682 || (fat[head].flags & FAT_USED))
683 continue;
684
685 pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n",
686 head, fat[head].length);
687 mod |= ret = reconnect(dosfs, boot, fat, head);
688 if (mod & FSFATAL)
689 break;
690 if (ret == FSERROR && ask(0, "Clear")) {
691 clearchain(boot, fat, head);
692 mod |= FSFATMOD;
693 }
694 }
695 finishlf();
696
697 if (boot->bpbFSInfo) {
698 ret = 0;
699 if (boot->FSFree != 0xffffffffU &&
700 boot->FSFree != boot->NumFree) {
701 pwarn("Free space in FSInfo block (%u) not correct (%u)\n",
702 boot->FSFree, boot->NumFree);
703 if (ask(1, "Fix")) {
704 boot->FSFree = boot->NumFree;
705 ret = 1;
706 }
707 }
708 if (ret)
709 mod |= writefsinfo(dosfs, boot);
710 }
711
712 return mod;
713 }
714