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