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