sbin/fsck_msdosfs: Bring in freebsd/freebsd@55bd3d12 (fix index)
[dragonfly.git] / sbin / fsck_msdosfs / fat.c
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 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <unistd.h>
33
34 #include "ext.h"
35 #include "fsutil.h"
36
37 static int checkclnum(struct bootblock *, u_int, cl_t, cl_t *);
38 static int clustdiffer(cl_t, cl_t *, cl_t *, u_int);
39 static int tryclear(struct bootblock *, struct fatEntry *, cl_t, cl_t *);
40 static int _readfat(int, struct bootblock *, u_int, u_char **);
41
42 /*
43  * Check a cluster number for valid value
44  */
45 static int
46 checkclnum(struct bootblock *boot, u_int fat, cl_t cl, cl_t *next)
47 {
48         if (*next >= (CLUST_RSRVD&boot->ClustMask))
49                 *next |= ~boot->ClustMask;
50         if (*next == CLUST_FREE) {
51                 boot->NumFree++;
52                 return FSOK;
53         }
54         if (*next == CLUST_BAD) {
55                 boot->NumBad++;
56                 return FSOK;
57         }
58         if (*next < CLUST_FIRST
59             || (*next >= boot->NumClusters && *next < CLUST_EOFS)) {
60                 pwarn("Cluster %u in FAT %d continues with %s cluster number %u\n",
61                       cl, fat,
62                       *next < CLUST_RSRVD ? "out of range" : "reserved",
63                       *next&boot->ClustMask);
64                 if (ask(0, "Truncate")) {
65                         *next = CLUST_EOF;
66                         return FSFATMOD;
67                 }
68                 return FSERROR;
69         }
70         return FSOK;
71 }
72
73 /*
74  * Read a FAT from disk. Returns 1 if successful, 0 otherwise.
75  */
76 static int
77 _readfat(int fs, struct bootblock *boot, u_int no, u_char **buffer)
78 {
79         off_t off;
80
81         *buffer = calloc(boot->FATsecs, boot->bpbBytesPerSec);
82         if (*buffer == NULL) {
83                 perr("No space for FAT sectors (%zu)",
84                     (size_t)boot->FATsecs);
85                 return 0;
86         }
87
88         off = boot->bpbResSectors + no * boot->FATsecs;
89         off *= boot->bpbBytesPerSec;
90
91         if (lseek(fs, off, SEEK_SET) != off) {
92                 perr("Unable to read FAT");
93                 goto err;
94         }
95
96         if ((size_t)read(fs, *buffer, boot->FATsecs * boot->bpbBytesPerSec)
97             != boot->FATsecs * boot->bpbBytesPerSec) {
98                 perr("Unable to read FAT");
99                 goto err;
100         }
101
102         return 1;
103
104 err:
105         free(*buffer);
106         return 0;
107 }
108
109 /*
110  * Read a FAT and decode it into internal format
111  */
112 int
113 readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
114 {
115         struct fatEntry *fat;
116         u_char *buffer, *p;
117         cl_t cl;
118         int ret = FSOK;
119
120         boot->NumFree = boot->NumBad = 0;
121
122         if (!_readfat(fs, boot, no, &buffer))
123                 return FSFATAL;
124
125         fat = calloc(boot->NumClusters, sizeof(struct fatEntry));
126         if (fat == NULL) {
127                 perr("No space for FAT clusters (%zu)",
128                     (size_t)boot->NumClusters);
129                 free(buffer);
130                 return FSFATAL;
131         }
132
133         if (buffer[0] != boot->bpbMedia
134             || buffer[1] != 0xff || buffer[2] != 0xff
135             || (boot->ClustMask == CLUST16_MASK && buffer[3] != 0xff)
136             || (boot->ClustMask == CLUST32_MASK
137                 && ((buffer[3]&0x0f) != 0x0f
138                     || buffer[4] != 0xff || buffer[5] != 0xff
139                     || buffer[6] != 0xff || (buffer[7]&0x0f) != 0x0f))) {
140
141                 /* Windows 95 OSR2 (and possibly any later) changes
142                  * the FAT signature to 0xXXffff7f for FAT16 and to
143                  * 0xXXffff0fffffff07 for FAT32 upon boot, to know that the
144                  * file system is dirty if it doesn't reboot cleanly.
145                  * Check this special condition before errorring out.
146                  */
147                 if (buffer[0] == boot->bpbMedia && buffer[1] == 0xff
148                     && buffer[2] == 0xff
149                     && ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f)
150                         || (boot->ClustMask == CLUST32_MASK
151                             && buffer[3] == 0x0f && buffer[4] == 0xff
152                             && buffer[5] == 0xff && buffer[6] == 0xff
153                             && buffer[7] == 0x07)))
154                         ret |= FSDIRTY;
155                 else {
156                         /* just some odd byte sequence in FAT */
157                         switch (boot->ClustMask) {
158                         case CLUST32_MASK:
159                                 pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n",
160                                       "FAT starts with odd byte sequence",
161                                       buffer[0], buffer[1], buffer[2], buffer[3],
162                                       buffer[4], buffer[5], buffer[6], buffer[7]);
163                                 break;
164                         case CLUST16_MASK:
165                                 pwarn("%s (%02x%02x%02x%02x)\n",
166                                     "FAT starts with odd byte sequence",
167                                     buffer[0], buffer[1], buffer[2], buffer[3]);
168                                 break;
169                         default:
170                                 pwarn("%s (%02x%02x%02x)\n",
171                                     "FAT starts with odd byte sequence",
172                                     buffer[0], buffer[1], buffer[2]);
173                                 break;
174                         }
175
176                         if (ask(1, "Correct"))
177                                 ret |= FSFIXFAT;
178                 }
179         }
180         switch (boot->ClustMask) {
181         case CLUST32_MASK:
182                 p = buffer + 8;
183                 break;
184         case CLUST16_MASK:
185                 p = buffer + 4;
186                 break;
187         default:
188                 p = buffer + 3;
189                 break;
190         }
191         for (cl = CLUST_FIRST; cl < boot->NumClusters;) {
192                 switch (boot->ClustMask) {
193                 case CLUST32_MASK:
194                         fat[cl].next = p[0] + (p[1] << 8)
195                                        + (p[2] << 16) + (p[3] << 24);
196                         fat[cl].next &= boot->ClustMask;
197                         ret |= checkclnum(boot, no, cl, &fat[cl].next);
198                         cl++;
199                         p += 4;
200                         break;
201                 case CLUST16_MASK:
202                         fat[cl].next = p[0] + (p[1] << 8);
203                         ret |= checkclnum(boot, no, cl, &fat[cl].next);
204                         cl++;
205                         p += 2;
206                         break;
207                 default:
208                         fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff;
209                         ret |= checkclnum(boot, no, cl, &fat[cl].next);
210                         cl++;
211                         if (cl >= boot->NumClusters)
212                                 break;
213                         fat[cl].next = ((p[1] >> 4) + (p[2] << 4)) & 0x0fff;
214                         ret |= checkclnum(boot, no, cl, &fat[cl].next);
215                         cl++;
216                         p += 3;
217                         break;
218                 }
219         }
220
221         free(buffer);
222         if (ret & FSFATAL) {
223                 free(fat);
224                 *fp = NULL;
225         } else
226                 *fp = fat;
227         return ret;
228 }
229
230 /*
231  * Get type of reserved cluster
232  */
233 const char *
234 rsrvdcltype(cl_t cl)
235 {
236         if (cl == CLUST_FREE)
237                 return "free";
238         if (cl < CLUST_BAD)
239                 return "reserved";
240         if (cl > CLUST_BAD)
241                 return "as EOF";
242         return "bad";
243 }
244
245 static int
246 clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, u_int fatnum)
247 {
248         if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) {
249                 if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
250                         if ((*cp1 != CLUST_FREE && *cp1 < CLUST_BAD
251                              && *cp2 != CLUST_FREE && *cp2 < CLUST_BAD)
252                             || (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) {
253                                 pwarn("Cluster %u is marked %s with different indicators\n",
254                                       cl, rsrvdcltype(*cp1));
255                                 if (ask(1, "Fix")) {
256                                         *cp2 = *cp1;
257                                         return FSFATMOD;
258                                 }
259                                 return FSFATAL;
260                         }
261                         pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %u\n",
262                               cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum);
263                         if (ask(0, "Use FAT 0's entry")) {
264                                 *cp2 = *cp1;
265                                 return FSFATMOD;
266                         }
267                         if (ask(0, "Use FAT %u's entry", fatnum)) {
268                                 *cp1 = *cp2;
269                                 return FSFATMOD;
270                         }
271                         return FSFATAL;
272                 }
273                 pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n",
274                       cl, rsrvdcltype(*cp1), *cp2, fatnum);
275                 if (ask(0, "Use continuation from FAT %u", fatnum)) {
276                         *cp1 = *cp2;
277                         return FSFATMOD;
278                 }
279                 if (ask(0, "Use mark from FAT 0")) {
280                         *cp2 = *cp1;
281                         return FSFATMOD;
282                 }
283                 return FSFATAL;
284         }
285         if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) {
286                 pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %u\n",
287                       cl, *cp1, rsrvdcltype(*cp2), fatnum);
288                 if (ask(0, "Use continuation from FAT 0")) {
289                         *cp2 = *cp1;
290                         return FSFATMOD;
291                 }
292                 if (ask(0, "Use mark from FAT %d", fatnum)) {
293                         *cp1 = *cp2;
294                         return FSFATMOD;
295                 }
296                 return FSERROR;
297         }
298         pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %u\n",
299               cl, *cp1, *cp2, fatnum);
300         if (ask(0, "Use continuation from FAT 0")) {
301                 *cp2 = *cp1;
302                 return FSFATMOD;
303         }
304         if (ask(0, "Use continuation from FAT %u", fatnum)) {
305                 *cp1 = *cp2;
306                 return FSFATMOD;
307         }
308         return FSERROR;
309 }
310
311 /*
312  * Compare two FAT copies in memory. Resolve any conflicts and merge them
313  * into the first one.
314  */
315 int
316 comparefat(struct bootblock *boot, struct fatEntry *first,
317     struct fatEntry *second, u_int fatnum)
318 {
319         cl_t cl;
320         int ret = FSOK;
321
322         for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++)
323                 if (first[cl].next != second[cl].next)
324                         ret |= clustdiffer(cl, &first[cl].next, &second[cl].next, fatnum);
325         return ret;
326 }
327
328 void
329 clearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head)
330 {
331         cl_t p, q;
332
333         for (p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = q) {
334                 if (fat[p].head != head)
335                         break;
336                 q = fat[p].next;
337                 fat[p].next = fat[p].head = CLUST_FREE;
338                 fat[p].length = 0;
339         }
340 }
341
342 int
343 tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *truncp)
344 {
345         if (ask(0, "Clear chain starting at %u", head)) {
346                 clearchain(boot, fat, head);
347                 return FSFATMOD;
348         } else if (ask(0, "Truncate")) {
349                 uint32_t len;
350                 cl_t p;
351
352                 for (p = head, len = 0;
353                     p >= CLUST_FIRST && p < boot->NumClusters;
354                     p = fat[p].next, len++)
355                         continue;
356                 *truncp = CLUST_EOF;
357                 fat[head].length = len;
358                 return FSFATMOD;
359         } else
360                 return FSERROR;
361 }
362
363 /*
364  * Check a complete FAT in-memory for crosslinks
365  */
366 int
367 checkfat(struct bootblock *boot, struct fatEntry *fat)
368 {
369         cl_t head, p, h, n;
370         u_int len;
371         int ret = 0;
372         int conf;
373
374         /*
375          * pass 1: figure out the cluster chains.
376          */
377         for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
378                 /* find next untravelled chain */
379                 if (fat[head].head != 0         /* cluster already belongs to some chain */
380                     || fat[head].next == CLUST_FREE
381                     || fat[head].next == CLUST_BAD)
382                         continue;               /* skip it. */
383
384                 /* follow the chain and mark all clusters on the way */
385                 for (len = 0, p = head;
386                      p >= CLUST_FIRST && p < boot->NumClusters &&
387                      fat[p].head != head;
388                      p = fat[p].next) {
389                         fat[p].head = head;
390                         len++;
391                 }
392
393                 /* the head record gets the length */
394                 fat[head].length = fat[head].next == CLUST_FREE ? 0 : len;
395         }
396
397         /*
398          * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because
399          * we didn't know the real start of the chain then - would have treated partial
400          * chains as interlinked with their main chain)
401          */
402         for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
403                 /* find next untravelled chain */
404                 if (fat[head].head != head)
405                         continue;
406
407                 /* follow the chain to its end (hopefully) */
408                 for (len = fat[head].length, p = head;
409                      (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
410                      p = n)
411                         if (fat[n].head != head || len-- < 2)
412                                 break;
413                 if (n >= CLUST_EOFS)
414                         continue;
415
416                 if (n == CLUST_FREE || n >= CLUST_RSRVD) {
417                         pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
418                               head, rsrvdcltype(n));
419 clear:
420                         ret |= tryclear(boot, fat, head, &fat[p].next);
421                         continue;
422                 }
423                 if (n < CLUST_FIRST || n >= boot->NumClusters) {
424                         pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
425                             head, n);
426                         goto clear;
427                 }
428                 if (head == fat[n].head) {
429                         pwarn("Cluster chain starting at %u loops at cluster %u\n",
430                             head, p);
431                         goto clear;
432                 }
433                 pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
434                       head, fat[n].head, n);
435                 conf = tryclear(boot, fat, head, &fat[p].next);
436                 if (ask(0, "Clear chain starting at %u", h = fat[n].head)) {
437                         if (conf == FSERROR) {
438                                 /*
439                                  * Transfer the common chain to the one not cleared above.
440                                  */
441                                 for (p = n;
442                                      p >= CLUST_FIRST && p < boot->NumClusters;
443                                      p = fat[p].next) {
444                                         if (h != fat[p].head) {
445                                                 /*
446                                                  * Have to reexamine this chain.
447                                                  */
448                                                 head--;
449                                                 break;
450                                         }
451                                         fat[p].head = head;
452                                 }
453                         }
454                         clearchain(boot, fat, h);
455                         conf |= FSFATMOD;
456                 }
457                 ret |= conf;
458         }
459
460         return ret;
461 }
462
463 /*
464  * Write out FATs encoding them from the internal format
465  */
466 int
467 writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
468 {
469         u_char *buffer, *p;
470         cl_t cl;
471         u_int i;
472         size_t fatsz;
473         off_t off;
474         int ret = FSOK;
475
476         fatsz = boot->FATsecs * boot->bpbBytesPerSec;
477         buffer = calloc(boot->FATsecs, boot->bpbBytesPerSec);
478         if (buffer == NULL) {
479                 perr("No space for FAT sectors (%zu)",
480                     (size_t)boot->FATsecs);
481                 return FSFATAL;
482         }
483         boot->NumFree = 0;
484         p = buffer;
485         if (correct_fat) {
486                 *p++ = (u_char)boot->bpbMedia;
487                 *p++ = 0xff;
488                 *p++ = 0xff;
489                 switch (boot->ClustMask) {
490                 case CLUST16_MASK:
491                         *p++ = 0xff;
492                         break;
493                 case CLUST32_MASK:
494                         *p++ = 0x0f;
495                         *p++ = 0xff;
496                         *p++ = 0xff;
497                         *p++ = 0xff;
498                         *p++ = 0x0f;
499                         break;
500                 }
501         } else {
502                 /* use same FAT signature as the old FAT has */
503                 int count;
504                 u_char *old_fat;
505
506                 switch (boot->ClustMask) {
507                 case CLUST32_MASK:
508                         count = 8;
509                         break;
510                 case CLUST16_MASK:
511                         count = 4;
512                         break;
513                 default:
514                         count = 3;
515                         break;
516                 }
517
518                 if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0,
519                                          &old_fat)) {
520                         free(buffer);
521                         return FSFATAL;
522                 }
523
524                 memcpy(p, old_fat, count);
525                 free(old_fat);
526                 p += count;
527         }
528
529         for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
530                 switch (boot->ClustMask) {
531                 case CLUST32_MASK:
532                         if (fat[cl].next == CLUST_FREE)
533                                 boot->NumFree++;
534                         *p++ = (u_char)fat[cl].next;
535                         *p++ = (u_char)(fat[cl].next >> 8);
536                         *p++ = (u_char)(fat[cl].next >> 16);
537                         *p &= 0xf0;
538                         *p++ |= (fat[cl].next >> 24)&0x0f;
539                         break;
540                 case CLUST16_MASK:
541                         if (fat[cl].next == CLUST_FREE)
542                                 boot->NumFree++;
543                         *p++ = (u_char)fat[cl].next;
544                         *p++ = (u_char)(fat[cl].next >> 8);
545                         break;
546                 default:
547                         if (fat[cl].next == CLUST_FREE)
548                                 boot->NumFree++;
549                         *p++ = (u_char)fat[cl].next;
550                         *p = (u_char)((fat[cl].next >> 8) & 0xf);
551                         cl++;
552                         if (cl >= boot->NumClusters)
553                                 break;
554                         if (fat[cl].next == CLUST_FREE)
555                                 boot->NumFree++;
556                         *p++ |= (u_char)(fat[cl].next << 4);
557                         *p++ = (u_char)(fat[cl].next >> 4);
558                         break;
559                 }
560         }
561         for (i = 0; i < boot->bpbFATs; i++) {
562                 off = boot->bpbResSectors + i * boot->FATsecs;
563                 off *= boot->bpbBytesPerSec;
564                 if (lseek(fs, off, SEEK_SET) != off
565                     || (size_t)write(fs, buffer, fatsz) != fatsz) {
566                         perr("Unable to write FAT");
567                         ret = FSFATAL; /* Return immediately?           XXX */
568                 }
569         }
570         free(buffer);
571         return ret;
572 }
573
574 /*
575  * Check a complete in-memory FAT for lost cluster chains
576  */
577 int
578 checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
579 {
580         cl_t head;
581         int mod = FSOK;
582         int ret;
583
584         for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
585                 /* find next untravelled chain */
586                 if (fat[head].head != head
587                     || fat[head].next == CLUST_FREE
588                     || (fat[head].next >= CLUST_RSRVD
589                         && fat[head].next < CLUST_EOFS)
590                     || (fat[head].flags & FAT_USED))
591                         continue;
592
593                 pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n",
594                       head, fat[head].length);
595                 mod |= ret = reconnect(dosfs, boot, fat, head);
596                 if (mod & FSFATAL)
597                         break;
598                 if (ret == FSERROR && ask(0, "Clear")) {
599                         clearchain(boot, fat, head);
600                         mod |= FSFATMOD;
601                 }
602         }
603         finishlf();
604
605         if (boot->bpbFSInfo) {
606                 ret = 0;
607                 if (boot->FSFree != boot->NumFree) {
608                         pwarn("Free space in FSInfo block (%d) not correct (%d)\n",
609                               boot->FSFree, boot->NumFree);
610                         if (ask(1, "Fix")) {
611                                 boot->FSFree = boot->NumFree;
612                                 ret = 1;
613                         }
614                 }
615                 if (ret)
616                         mod |= writefsinfo(dosfs, boot);
617         }
618
619         return mod;
620 }