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