]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sbin/fsck_msdosfs/fat.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sbin / fsck_msdosfs / fat.c
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$";
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
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
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(0, "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
169 _readfat(int fs, struct bootblock *boot, int no, u_char **buffer)
170 {
171         off_t off;
172
173         *buffer = malloc(boot->FATsecs * boot->BytesPerSec);
174         if (*buffer == NULL) {
175                 perror("No space for FAT");
176                 return 0;
177         }
178
179         off = boot->ResSectors + no * boot->FATsecs;
180         off *= boot->BytesPerSec;
181
182         if (lseek(fs, off, SEEK_SET) != off) {
183                 perror("Unable to read FAT");
184                 goto err;
185         }
186
187         if (read(fs, *buffer, boot->FATsecs * boot->BytesPerSec)
188             != boot->FATsecs * boot->BytesPerSec) {
189                 perror("Unable to read FAT");
190                 goto err;
191         }
192
193         return 1;
194
195     err:
196         free(*buffer);
197         return 0;
198 }
199
200 /*
201  * Read a FAT and decode it into internal format
202  */
203 int
204 readfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp)
205 {
206         struct fatEntry *fat;
207         u_char *buffer, *p;
208         cl_t cl;
209         int ret = FSOK;
210
211         boot->NumFree = boot->NumBad = 0;
212
213         if (!_readfat(fs, boot, no, &buffer))
214                 return FSFATAL;
215                 
216         fat = calloc(boot->NumClusters, sizeof(struct fatEntry));
217         if (fat == NULL) {
218                 perror("No space for FAT");
219                 free(buffer);
220                 return FSFATAL;
221         }
222
223         if (buffer[0] != boot->Media
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->Media && 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         *fp = fat;
315         return ret;
316 }
317
318 /*
319  * Get type of reserved cluster
320  */
321 char *
322 rsrvdcltype(cl_t cl)
323 {
324         if (cl == CLUST_FREE)
325                 return "free";
326         if (cl < CLUST_BAD)
327                 return "reserved";
328         if (cl > CLUST_BAD)
329                 return "as EOF";
330         return "bad";
331 }
332
333 static int
334 clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, int fatnum)
335 {
336         if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) {
337                 if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
338                         if ((*cp1 != CLUST_FREE && *cp1 < CLUST_BAD
339                              && *cp2 != CLUST_FREE && *cp2 < CLUST_BAD)
340                             || (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) {
341                                 pwarn("Cluster %u is marked %s with different indicators, ",
342                                       cl, rsrvdcltype(*cp1));
343                                 if (ask(1, "fix")) {
344                                         *cp2 = *cp1;
345                                         return FSFATMOD;
346                                 }
347                                 return FSFATAL;
348                         }
349                         pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %d\n",
350                               cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum);
351                         if (ask(0, "use FAT 0's entry")) {
352                                 *cp2 = *cp1;
353                                 return FSFATMOD;
354                         }
355                         if (ask(0, "use FAT %d's entry", fatnum)) {
356                                 *cp1 = *cp2;
357                                 return FSFATMOD;
358                         }
359                         return FSFATAL;
360                 }
361                 pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n",
362                       cl, rsrvdcltype(*cp1), *cp2, fatnum);
363                 if (ask(0, "Use continuation from FAT %d", fatnum)) {
364                         *cp1 = *cp2;
365                         return FSFATMOD;
366                 }
367                 if (ask(0, "Use mark from FAT 0")) {
368                         *cp2 = *cp1;
369                         return FSFATMOD;
370                 }
371                 return FSFATAL;
372         }
373         if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
374                 pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %d\n",
375                       cl, *cp1, rsrvdcltype(*cp2), fatnum);
376                 if (ask(0, "Use continuation from FAT 0")) {
377                         *cp2 = *cp1;
378                         return FSFATMOD;
379                 }
380                 if (ask(0, "Use mark from FAT %d", fatnum)) {
381                         *cp1 = *cp2;
382                         return FSFATMOD;
383                 }
384                 return FSERROR;
385         }
386         pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %d\n",
387               cl, *cp1, *cp2, fatnum);
388         if (ask(0, "Use continuation from FAT 0")) {
389                 *cp2 = *cp1;
390                 return FSFATMOD;
391         }
392         if (ask(0, "Use continuation from FAT %d", fatnum)) {
393                 *cp1 = *cp2;
394                 return FSFATMOD;
395         }
396         return FSERROR;
397 }
398
399 /*
400  * Compare two FAT copies in memory. Resolve any conflicts and merge them
401  * into the first one.
402  */
403 int
404 comparefat(struct bootblock *boot, struct fatEntry *first, 
405     struct fatEntry *second, int fatnum)
406 {
407         cl_t cl;
408         int ret = FSOK;
409
410         for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++)
411                 if (first[cl].next != second[cl].next)
412                         ret |= clustdiffer(cl, &first[cl].next, &second[cl].next, fatnum);
413         return ret;
414 }
415
416 void
417 clearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head)
418 {
419         cl_t p, q;
420
421         for (p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = q) {
422                 if (fat[p].head != head)
423                         break;
424                 q = fat[p].next;
425                 fat[p].next = fat[p].head = CLUST_FREE;
426                 fat[p].length = 0;
427         }
428 }
429
430 int
431 tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc)
432 {
433         if (ask(0, "Clear chain starting at %u", head)) {
434                 clearchain(boot, fat, head);
435                 return FSFATMOD;
436         } else if (ask(0, "Truncate")) {
437                 *trunc = CLUST_EOF;
438                 return FSFATMOD;
439         } else
440                 return FSERROR;
441 }
442
443 /*
444  * Check a complete FAT in-memory for crosslinks
445  */
446 int
447 checkfat(struct bootblock *boot, struct fatEntry *fat)
448 {
449         cl_t head, p, h, n;
450         u_int len;
451         int ret = 0;
452         int conf;
453
454         /*
455          * pass 1: figure out the cluster chains.
456          */
457         for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
458                 /* find next untravelled chain */
459                 if (fat[head].head != 0         /* cluster already belongs to some chain */
460                     || fat[head].next == CLUST_FREE
461                     || fat[head].next == CLUST_BAD)
462                         continue;               /* skip it. */
463
464                 /* follow the chain and mark all clusters on the way */
465                 for (len = 0, p = head;
466                      p >= CLUST_FIRST && p < boot->NumClusters;
467                      p = fat[p].next) {
468                         fat[p].head = head;
469                         len++;
470                 }
471
472                 /* the head record gets the length */
473                 fat[head].length = fat[head].next == CLUST_FREE ? 0 : len;
474         }
475
476         /*
477          * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because
478          * we didn't know the real start of the chain then - would have treated partial
479          * chains as interlinked with their main chain)
480          */
481         for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
482                 /* find next untravelled chain */
483                 if (fat[head].head != head)
484                         continue;
485
486                 /* follow the chain to its end (hopefully) */
487                 for (p = head;
488                      (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
489                      p = n)
490                         if (fat[n].head != head)
491                                 break;
492                 if (n >= CLUST_EOFS)
493                         continue;
494
495                 if (n == CLUST_FREE || n >= CLUST_RSRVD) {
496                         pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
497                               head, rsrvdcltype(n));
498                         ret |= tryclear(boot, fat, head, &fat[p].next);
499                         continue;
500                 }
501                 if (n < CLUST_FIRST || n >= boot->NumClusters) {
502                         pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
503                               head, n);
504                         ret |= tryclear(boot, fat, head, &fat[p].next);
505                         continue;
506                 }
507                 pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
508                       head, fat[n].head, n);
509                 conf = tryclear(boot, fat, head, &fat[p].next);
510                 if (ask(0, "Clear chain starting at %u", h = fat[n].head)) {
511                         if (conf == FSERROR) {
512                                 /*
513                                  * Transfer the common chain to the one not cleared above.
514                                  */
515                                 for (p = n;
516                                      p >= CLUST_FIRST && p < boot->NumClusters;
517                                      p = fat[p].next) {
518                                         if (h != fat[p].head) {
519                                                 /*
520                                                  * Have to reexamine this chain.
521                                                  */
522                                                 head--;
523                                                 break;
524                                         }
525                                         fat[p].head = head;
526                                 }
527                         }
528                         clearchain(boot, fat, h);
529                         conf |= FSFATMOD;
530                 }
531                 ret |= conf;
532         }
533
534         return ret;
535 }
536
537 /*
538  * Write out FATs encoding them from the internal format
539  */
540 int
541 writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
542 {
543         u_char *buffer, *p;
544         cl_t cl;
545         int i;
546         u_int32_t fatsz;
547         off_t off;
548         int ret = FSOK;
549
550         buffer = malloc(fatsz = boot->FATsecs * boot->BytesPerSec);
551         if (buffer == NULL) {
552                 perror("No space for FAT");
553                 return FSFATAL;
554         }
555         memset(buffer, 0, fatsz);
556         boot->NumFree = 0;
557         p = buffer;
558         if (correct_fat) {
559                 *p++ = (u_char)boot->Media;
560                 *p++ = 0xff;
561                 *p++ = 0xff;
562                 switch (boot->ClustMask) {
563                 case CLUST16_MASK:
564                         *p++ = 0xff;
565                         break;
566                 case CLUST32_MASK:
567                         *p++ = 0x0f;
568                         *p++ = 0xff;
569                         *p++ = 0xff;
570                         *p++ = 0xff;
571                         *p++ = 0x0f;
572                         break;
573                 }
574         } else {
575                 /* use same FAT signature as the old FAT has */
576                 int count;
577                 u_char *old_fat;
578
579                 switch (boot->ClustMask) {
580                 case CLUST32_MASK:
581                         count = 8;
582                         break;
583                 case CLUST16_MASK:
584                         count = 4;
585                         break;
586                 default:
587                         count = 3;
588                         break;
589                 }
590
591                 if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0,
592                                          &old_fat)) {
593                         free(buffer);
594                         return FSFATAL;
595                 }
596
597                 memcpy(p, old_fat, count);
598                 free(old_fat);
599                 p += count;
600         }
601                         
602         for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
603                 switch (boot->ClustMask) {
604                 case CLUST32_MASK:
605                         if (fat[cl].next == CLUST_FREE)
606                                 boot->NumFree++;
607                         *p++ = (u_char)fat[cl].next;
608                         *p++ = (u_char)(fat[cl].next >> 8);
609                         *p++ = (u_char)(fat[cl].next >> 16);
610                         *p &= 0xf0;
611                         *p++ |= (fat[cl].next >> 24)&0x0f;
612                         break;
613                 case CLUST16_MASK:
614                         if (fat[cl].next == CLUST_FREE)
615                                 boot->NumFree++;
616                         *p++ = (u_char)fat[cl].next;
617                         *p++ = (u_char)(fat[cl].next >> 8);
618                         break;
619                 default:
620                         if (fat[cl].next == CLUST_FREE)
621                                 boot->NumFree++;
622                         if (cl + 1 < boot->NumClusters
623                             && fat[cl + 1].next == CLUST_FREE)
624                                 boot->NumFree++;
625                         *p++ = (u_char)fat[cl].next;
626                         *p++ = (u_char)((fat[cl].next >> 8) & 0xf)
627                                |(u_char)(fat[cl+1].next << 4);
628                         *p++ = (u_char)(fat[++cl].next >> 4);
629                         break;
630                 }
631         }
632         for (i = 0; i < boot->FATs; i++) {
633                 off = boot->ResSectors + i * boot->FATsecs;
634                 off *= boot->BytesPerSec;
635                 if (lseek(fs, off, SEEK_SET) != off
636                     || write(fs, buffer, fatsz) != fatsz) {
637                         perror("Unable to write FAT");
638                         ret = FSFATAL; /* Return immediately?           XXX */
639                 }
640         }
641         free(buffer);
642         return ret;
643 }
644
645 /*
646  * Check a complete in-memory FAT for lost cluster chains
647  */
648 int
649 checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
650 {
651         cl_t head;
652         int mod = FSOK;
653         int ret;
654         
655         for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
656                 /* find next untravelled chain */
657                 if (fat[head].head != head
658                     || fat[head].next == CLUST_FREE
659                     || (fat[head].next >= CLUST_RSRVD
660                         && fat[head].next < CLUST_EOFS)
661                     || (fat[head].flags & FAT_USED))
662                         continue;
663
664                 pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n",
665                       head, fat[head].length);
666                 mod |= ret = reconnect(dosfs, boot, fat, head);
667                 if (mod & FSFATAL)
668                         break;
669                 if (ret == FSERROR && ask(0, "Clear")) {
670                         clearchain(boot, fat, head);
671                         mod |= FSFATMOD;
672                 }
673         }
674         finishlf();
675
676         if (boot->FSInfo) {
677                 ret = 0;
678                 if (boot->FSFree != boot->NumFree) {
679                         pwarn("Free space in FSInfo block (%d) not correct (%d)\n",
680                               boot->FSFree, boot->NumFree);
681                         if (ask(1, "fix")) {
682                                 boot->FSFree = boot->NumFree;
683                                 ret = 1;
684                         }
685                 }
686                 if (boot->NumFree && fat[boot->FSNext].next != CLUST_FREE) {
687                         pwarn("Next free cluster in FSInfo block (%u) not free\n",
688                               boot->FSNext);
689                         if (ask(1, "fix"))
690                                 for (head = CLUST_FIRST; head < boot->NumClusters; head++)
691                                         if (fat[head].next == CLUST_FREE) {
692                                                 boot->FSNext = head;
693                                                 ret = 1;
694                                                 break;
695                                         }
696                 }
697                 if (ret)
698                         mod |= writefsinfo(dosfs, boot);
699         }
700
701         return mod;
702 }