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