fat.c revision 203874
1168404Spjd/* 2168404Spjd * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 3168404Spjd * Copyright (c) 1995 Martin Husemann 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer. 10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 11168404Spjd * notice, this list of conditions and the following disclaimer in the 12168404Spjd * documentation and/or other materials provided with the distribution. 13168404Spjd * 14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 15168404Spjd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16168404Spjd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17168404Spjd * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 18168404Spjd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19168404Spjd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20168404Spjd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21168404Spjd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22219089Spjd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23286575Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24296519Smav */ 25168404Spjd 26168404Spjd 27168404Spjd#include <sys/cdefs.h> 28168404Spjd#ifndef lint 29168404Spjd__RCSID("$NetBSD: fat.c,v 1.12 2000/10/10 20:24:52 is Exp $"); 30168404Spjdstatic const char rcsid[] = 31168404Spjd "$FreeBSD: head/sbin/fsck_msdosfs/fat.c 203874 2010-02-14 12:31:28Z kib $"; 32168404Spjd#endif /* not lint */ 33168404Spjd 34168404Spjd#include <stdlib.h> 35168404Spjd#include <string.h> 36168404Spjd#include <ctype.h> 37168404Spjd#include <stdio.h> 38168404Spjd#include <unistd.h> 39168404Spjd 40168404Spjd#include "ext.h" 41168404Spjd#include "fsutil.h" 42168404Spjd 43168404Spjdstatic int checkclnum(struct bootblock *, u_int, cl_t, cl_t *); 44168404Spjdstatic int clustdiffer(cl_t, cl_t *, cl_t *, u_int); 45168404Spjdstatic int tryclear(struct bootblock *, struct fatEntry *, cl_t, cl_t *); 46274337Sdelphijstatic int _readfat(int, struct bootblock *, u_int, u_char **); 47168404Spjd 48219089Spjd/*- 49219089Spjd * The first 2 FAT entries contain pseudo-cluster numbers with the following 50168404Spjd * layout: 51168404Spjd * 52168404Spjd * 31...... ........ ........ .......0 53168404Spjd * rrrr1111 11111111 11111111 mmmmmmmm FAT32 entry 0 54168404Spjd * rrrrsh11 11111111 11111111 11111xxx FAT32 entry 1 55168404Spjd * 56168404Spjd * 11111111 mmmmmmmm FAT16 entry 0 57168404Spjd * sh111111 11111xxx FAT16 entry 1 58168404Spjd * 59168404Spjd * r = reserved 60185029Spjd * m = BPB media ID byte 61185029Spjd * s = clean flag (1 = dismounted; 0 = still mounted) 62168404Spjd * h = hard error flag (1 = ok; 0 = I/O error) 63168404Spjd * x = any value ok 64168404Spjd */ 65168404Spjd 66168404Spjdint 67168404Spjdcheckdirty(int fs, struct bootblock *boot) 68168404Spjd{ 69168404Spjd off_t off; 70219089Spjd u_char *buffer; 71168404Spjd int ret = 0; 72168404Spjd 73219089Spjd if (boot->ClustMask != CLUST16_MASK && boot->ClustMask != CLUST32_MASK) 74275782Sdelphij return 0; 75168404Spjd 76168404Spjd off = boot->bpbResSectors; 77168404Spjd off *= boot->bpbBytesPerSec; 78168404Spjd 79168404Spjd buffer = malloc(boot->bpbBytesPerSec); 80168404Spjd if (buffer == NULL) { 81168404Spjd perror("No space for FAT"); 82168404Spjd return 1; 83168404Spjd } 84168404Spjd 85168404Spjd if (lseek(fs, off, SEEK_SET) != off) { 86168404Spjd perror("Unable to read FAT"); 87168404Spjd goto err; 88168404Spjd } 89168404Spjd 90168404Spjd if (read(fs, buffer, boot->bpbBytesPerSec) != boot->bpbBytesPerSec) { 91168404Spjd perror("Unable to read FAT"); 92168404Spjd goto err; 93168404Spjd } 94168404Spjd 95168404Spjd /* 96168404Spjd * If we don't understand the FAT, then the file system must be 97168404Spjd * assumed to be unclean. 98168404Spjd */ 99168404Spjd if (buffer[0] != boot->bpbMedia || buffer[1] != 0xff) 100168404Spjd goto err; 101168404Spjd if (boot->ClustMask == CLUST16_MASK) { 102168404Spjd if ((buffer[2] & 0xf8) != 0xf8 || (buffer[3] & 0x3f) != 0x3f) 103168404Spjd goto err; 104168404Spjd } else { 105168404Spjd if (buffer[2] != 0xff || (buffer[3] & 0x0f) != 0x0f 106168404Spjd || (buffer[4] & 0xf8) != 0xf8 || buffer[5] != 0xff 107168404Spjd || buffer[6] != 0xff || (buffer[7] & 0x03) != 0x03) 108275782Sdelphij goto err; 109168404Spjd } 110168404Spjd 111168404Spjd /* 112168404Spjd * Now check the actual clean flag (and the no-error flag). 113168404Spjd */ 114168404Spjd if (boot->ClustMask == CLUST16_MASK) { 115168404Spjd if ((buffer[3] & 0xc0) == 0xc0) 116168404Spjd ret = 1; 117168404Spjd } else { 118168404Spjd if ((buffer[7] & 0x0c) == 0x0c) 119168404Spjd ret = 1; 120168404Spjd } 121168404Spjd 122168404Spjderr: 123168404Spjd free(buffer); 124168404Spjd return ret; 125168404Spjd} 126168404Spjd 127168404Spjd/* 128168404Spjd * Check a cluster number for valid value 129168404Spjd */ 130168404Spjdstatic int 131185029Spjdcheckclnum(struct bootblock *boot, u_int fat, cl_t cl, cl_t *next) 132219089Spjd{ 133168404Spjd if (*next >= (CLUST_RSRVD&boot->ClustMask)) 134168404Spjd *next |= ~boot->ClustMask; 135168404Spjd if (*next == CLUST_FREE) { 136168404Spjd boot->NumFree++; 137168404Spjd return FSOK; 138168404Spjd } 139168404Spjd if (*next == CLUST_BAD) { 140168404Spjd boot->NumBad++; 141168404Spjd return FSOK; 142168404Spjd } 143168404Spjd if (*next < CLUST_FIRST 144286575Smav || (*next >= boot->NumClusters && *next < CLUST_EOFS)) { 145168404Spjd pwarn("Cluster %u in FAT %d continues with %s cluster number %u\n", 146168404Spjd cl, fat, 147168404Spjd *next < CLUST_RSRVD ? "out of range" : "reserved", 148168404Spjd *next&boot->ClustMask); 149185029Spjd if (ask(0, "Truncate")) { 150185029Spjd *next = CLUST_EOF; 151168404Spjd return FSFATMOD; 152168404Spjd } 153168404Spjd return FSERROR; 154168404Spjd } 155168404Spjd return FSOK; 156168404Spjd} 157168404Spjd 158168404Spjd/* 159168404Spjd * Read a FAT from disk. Returns 1 if successful, 0 otherwise. 160168404Spjd */ 161168404Spjdstatic int 162168404Spjd_readfat(int fs, struct bootblock *boot, u_int no, u_char **buffer) 163168404Spjd{ 164168404Spjd off_t off; 165168404Spjd 166168404Spjd *buffer = malloc(boot->FATsecs * boot->bpbBytesPerSec); 167168404Spjd if (*buffer == NULL) { 168168404Spjd perror("No space for FAT"); 169168404Spjd return 0; 170275782Sdelphij } 171275782Sdelphij 172275782Sdelphij off = boot->bpbResSectors + no * boot->FATsecs; 173275782Sdelphij off *= boot->bpbBytesPerSec; 174275782Sdelphij 175275782Sdelphij if (lseek(fs, off, SEEK_SET) != off) { 176275782Sdelphij perror("Unable to read FAT"); 177275782Sdelphij goto err; 178275782Sdelphij } 179275782Sdelphij 180275782Sdelphij if ((size_t)read(fs, *buffer, boot->FATsecs * boot->bpbBytesPerSec) 181275782Sdelphij != boot->FATsecs * boot->bpbBytesPerSec) { 182185029Spjd perror("Unable to read FAT"); 183185029Spjd goto err; 184219089Spjd } 185219089Spjd 186219089Spjd return 1; 187219089Spjd 188219089Spjd err: 189185029Spjd free(*buffer); 190185029Spjd return 0; 191185029Spjd} 192185029Spjd 193185029Spjd/* 194168404Spjd * Read a FAT and decode it into internal format 195168404Spjd */ 196168404Spjdint 197185029Spjdreadfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp) 198168404Spjd{ 199185029Spjd struct fatEntry *fat; 200168404Spjd u_char *buffer, *p; 201286575Smav cl_t cl; 202219089Spjd int ret = FSOK; 203185029Spjd size_t len; 204219089Spjd 205219089Spjd boot->NumFree = boot->NumBad = 0; 206219089Spjd 207168404Spjd if (!_readfat(fs, boot, no, &buffer)) 208168404Spjd return FSFATAL; 209168404Spjd 210168404Spjd fat = malloc(len = boot->NumClusters * sizeof(struct fatEntry)); 211168404Spjd if (fat == NULL) { 212185029Spjd perror("No space for FAT"); 213185029Spjd free(buffer); 214185029Spjd return FSFATAL; 215219089Spjd } 216209962Smm (void)memset(fat, 0, len); 217209962Smm 218185029Spjd if (buffer[0] != boot->bpbMedia 219168404Spjd || buffer[1] != 0xff || buffer[2] != 0xff 220185029Spjd || (boot->ClustMask == CLUST16_MASK && buffer[3] != 0xff) 221168404Spjd || (boot->ClustMask == CLUST32_MASK 222185029Spjd && ((buffer[3]&0x0f) != 0x0f 223168404Spjd || buffer[4] != 0xff || buffer[5] != 0xff 224185029Spjd || buffer[6] != 0xff || (buffer[7]&0x0f) != 0x0f))) { 225168404Spjd 226168404Spjd /* Windows 95 OSR2 (and possibly any later) changes 227168404Spjd * the FAT signature to 0xXXffff7f for FAT16 and to 228168404Spjd * 0xXXffff0fffffff07 for FAT32 upon boot, to know that the 229185029Spjd * file system is dirty if it doesn't reboot cleanly. 230168404Spjd * Check this special condition before errorring out. 231168404Spjd */ 232219089Spjd if (buffer[0] == boot->bpbMedia && buffer[1] == 0xff 233219089Spjd && buffer[2] == 0xff 234168404Spjd && ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f) 235168404Spjd || (boot->ClustMask == CLUST32_MASK 236168404Spjd && buffer[3] == 0x0f && buffer[4] == 0xff 237168404Spjd && buffer[5] == 0xff && buffer[6] == 0xff 238168404Spjd && buffer[7] == 0x07))) 239168404Spjd ret |= FSDIRTY; 240 else { 241 /* just some odd byte sequence in FAT */ 242 243 switch (boot->ClustMask) { 244 case CLUST32_MASK: 245 pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n", 246 "FAT starts with odd byte sequence", 247 buffer[0], buffer[1], buffer[2], buffer[3], 248 buffer[4], buffer[5], buffer[6], buffer[7]); 249 break; 250 case CLUST16_MASK: 251 pwarn("%s (%02x%02x%02x%02x)\n", 252 "FAT starts with odd byte sequence", 253 buffer[0], buffer[1], buffer[2], buffer[3]); 254 break; 255 default: 256 pwarn("%s (%02x%02x%02x)\n", 257 "FAT starts with odd byte sequence", 258 buffer[0], buffer[1], buffer[2]); 259 break; 260 } 261 262 263 if (ask(1, "Correct")) 264 ret |= FSFIXFAT; 265 } 266 } 267 switch (boot->ClustMask) { 268 case CLUST32_MASK: 269 p = buffer + 8; 270 break; 271 case CLUST16_MASK: 272 p = buffer + 4; 273 break; 274 default: 275 p = buffer + 3; 276 break; 277 } 278 for (cl = CLUST_FIRST; cl < boot->NumClusters;) { 279 switch (boot->ClustMask) { 280 case CLUST32_MASK: 281 fat[cl].next = p[0] + (p[1] << 8) 282 + (p[2] << 16) + (p[3] << 24); 283 fat[cl].next &= boot->ClustMask; 284 ret |= checkclnum(boot, no, cl, &fat[cl].next); 285 cl++; 286 p += 4; 287 break; 288 case CLUST16_MASK: 289 fat[cl].next = p[0] + (p[1] << 8); 290 ret |= checkclnum(boot, no, cl, &fat[cl].next); 291 cl++; 292 p += 2; 293 break; 294 default: 295 fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff; 296 ret |= checkclnum(boot, no, cl, &fat[cl].next); 297 cl++; 298 if (cl >= boot->NumClusters) 299 break; 300 fat[cl].next = ((p[1] >> 4) + (p[2] << 4)) & 0x0fff; 301 ret |= checkclnum(boot, no, cl, &fat[cl].next); 302 cl++; 303 p += 3; 304 break; 305 } 306 } 307 308 free(buffer); 309 if (ret & FSFATAL) { 310 free(fat); 311 *fp = NULL; 312 } else 313 *fp = fat; 314 return ret; 315} 316 317/* 318 * Get type of reserved cluster 319 */ 320char * 321rsrvdcltype(cl_t cl) 322{ 323 if (cl == CLUST_FREE) 324 return "free"; 325 if (cl < CLUST_BAD) 326 return "reserved"; 327 if (cl > CLUST_BAD) 328 return "as EOF"; 329 return "bad"; 330} 331 332static int 333clustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, u_int fatnum) 334{ 335 if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) { 336 if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) { 337 if ((*cp1 != CLUST_FREE && *cp1 < CLUST_BAD 338 && *cp2 != CLUST_FREE && *cp2 < CLUST_BAD) 339 || (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) { 340 pwarn("Cluster %u is marked %s with different indicators\n", 341 cl, rsrvdcltype(*cp1)); 342 if (ask(1, "Fix")) { 343 *cp2 = *cp1; 344 return FSFATMOD; 345 } 346 return FSFATAL; 347 } 348 pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %u\n", 349 cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum); 350 if (ask(0, "Use FAT 0's entry")) { 351 *cp2 = *cp1; 352 return FSFATMOD; 353 } 354 if (ask(0, "Use FAT %u's entry", fatnum)) { 355 *cp1 = *cp2; 356 return FSFATMOD; 357 } 358 return FSFATAL; 359 } 360 pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n", 361 cl, rsrvdcltype(*cp1), *cp2, fatnum); 362 if (ask(0, "Use continuation from FAT %u", fatnum)) { 363 *cp1 = *cp2; 364 return FSFATMOD; 365 } 366 if (ask(0, "Use mark from FAT 0")) { 367 *cp2 = *cp1; 368 return FSFATMOD; 369 } 370 return FSFATAL; 371 } 372 if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) { 373 pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %u\n", 374 cl, *cp1, rsrvdcltype(*cp2), fatnum); 375 if (ask(0, "Use continuation from FAT 0")) { 376 *cp2 = *cp1; 377 return FSFATMOD; 378 } 379 if (ask(0, "Use mark from FAT %d", fatnum)) { 380 *cp1 = *cp2; 381 return FSFATMOD; 382 } 383 return FSERROR; 384 } 385 pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %u\n", 386 cl, *cp1, *cp2, fatnum); 387 if (ask(0, "Use continuation from FAT 0")) { 388 *cp2 = *cp1; 389 return FSFATMOD; 390 } 391 if (ask(0, "Use continuation from FAT %u", fatnum)) { 392 *cp1 = *cp2; 393 return FSFATMOD; 394 } 395 return FSERROR; 396} 397 398/* 399 * Compare two FAT copies in memory. Resolve any conflicts and merge them 400 * into the first one. 401 */ 402int 403comparefat(struct bootblock *boot, struct fatEntry *first, 404 struct fatEntry *second, u_int fatnum) 405{ 406 cl_t cl; 407 int ret = FSOK; 408 409 for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) 410 if (first[cl].next != second[cl].next) 411 ret |= clustdiffer(cl, &first[cl].next, &second[cl].next, fatnum); 412 return ret; 413} 414 415void 416clearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head) 417{ 418 cl_t p, q; 419 420 for (p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = q) { 421 if (fat[p].head != head) 422 break; 423 q = fat[p].next; 424 fat[p].next = fat[p].head = CLUST_FREE; 425 fat[p].length = 0; 426 } 427} 428 429int 430tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc) 431{ 432 if (ask(0, "Clear chain starting at %u", head)) { 433 clearchain(boot, fat, head); 434 return FSFATMOD; 435 } else if (ask(0, "Truncate")) { 436 *trunc = CLUST_EOF; 437 return FSFATMOD; 438 } else 439 return FSERROR; 440} 441 442/* 443 * Check a complete FAT in-memory for crosslinks 444 */ 445int 446checkfat(struct bootblock *boot, struct fatEntry *fat) 447{ 448 cl_t head, p, h, n; 449 u_int len; 450 int ret = 0; 451 int conf; 452 453 /* 454 * pass 1: figure out the cluster chains. 455 */ 456 for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 457 /* find next untravelled chain */ 458 if (fat[head].head != 0 /* cluster already belongs to some chain */ 459 || fat[head].next == CLUST_FREE 460 || fat[head].next == CLUST_BAD) 461 continue; /* skip it. */ 462 463 /* follow the chain and mark all clusters on the way */ 464 for (len = 0, p = head; 465 p >= CLUST_FIRST && p < boot->NumClusters; 466 p = fat[p].next) { 467 fat[p].head = head; 468 len++; 469 } 470 471 /* the head record gets the length */ 472 fat[head].length = fat[head].next == CLUST_FREE ? 0 : len; 473 } 474 475 /* 476 * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because 477 * we didn't know the real start of the chain then - would have treated partial 478 * chains as interlinked with their main chain) 479 */ 480 for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 481 /* find next untravelled chain */ 482 if (fat[head].head != head) 483 continue; 484 485 /* follow the chain to its end (hopefully) */ 486 for (p = head; 487 (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters; 488 p = n) 489 if (fat[n].head != head) 490 break; 491 if (n >= CLUST_EOFS) 492 continue; 493 494 if (n == CLUST_FREE || n >= CLUST_RSRVD) { 495 pwarn("Cluster chain starting at %u ends with cluster marked %s\n", 496 head, rsrvdcltype(n)); 497 ret |= tryclear(boot, fat, head, &fat[p].next); 498 continue; 499 } 500 if (n < CLUST_FIRST || n >= boot->NumClusters) { 501 pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n", 502 head, n); 503 ret |= tryclear(boot, fat, head, &fat[p].next); 504 continue; 505 } 506 pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n", 507 head, fat[n].head, n); 508 conf = tryclear(boot, fat, head, &fat[p].next); 509 if (ask(0, "Clear chain starting at %u", h = fat[n].head)) { 510 if (conf == FSERROR) { 511 /* 512 * Transfer the common chain to the one not cleared above. 513 */ 514 for (p = n; 515 p >= CLUST_FIRST && p < boot->NumClusters; 516 p = fat[p].next) { 517 if (h != fat[p].head) { 518 /* 519 * Have to reexamine this chain. 520 */ 521 head--; 522 break; 523 } 524 fat[p].head = head; 525 } 526 } 527 clearchain(boot, fat, h); 528 conf |= FSFATMOD; 529 } 530 ret |= conf; 531 } 532 533 return ret; 534} 535 536/* 537 * Write out FATs encoding them from the internal format 538 */ 539int 540writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat) 541{ 542 u_char *buffer, *p; 543 cl_t cl; 544 u_int i; 545 size_t fatsz; 546 off_t off; 547 int ret = FSOK; 548 549 buffer = malloc(fatsz = boot->FATsecs * boot->bpbBytesPerSec); 550 if (buffer == NULL) { 551 perror("No space for FAT"); 552 return FSFATAL; 553 } 554 memset(buffer, 0, fatsz); 555 boot->NumFree = 0; 556 p = buffer; 557 if (correct_fat) { 558 *p++ = (u_char)boot->bpbMedia; 559 *p++ = 0xff; 560 *p++ = 0xff; 561 switch (boot->ClustMask) { 562 case CLUST16_MASK: 563 *p++ = 0xff; 564 break; 565 case CLUST32_MASK: 566 *p++ = 0x0f; 567 *p++ = 0xff; 568 *p++ = 0xff; 569 *p++ = 0xff; 570 *p++ = 0x0f; 571 break; 572 } 573 } else { 574 /* use same FAT signature as the old FAT has */ 575 int count; 576 u_char *old_fat; 577 578 switch (boot->ClustMask) { 579 case CLUST32_MASK: 580 count = 8; 581 break; 582 case CLUST16_MASK: 583 count = 4; 584 break; 585 default: 586 count = 3; 587 break; 588 } 589 590 if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0, 591 &old_fat)) { 592 free(buffer); 593 return FSFATAL; 594 } 595 596 memcpy(p, old_fat, count); 597 free(old_fat); 598 p += count; 599 } 600 601 for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) { 602 switch (boot->ClustMask) { 603 case CLUST32_MASK: 604 if (fat[cl].next == CLUST_FREE) 605 boot->NumFree++; 606 *p++ = (u_char)fat[cl].next; 607 *p++ = (u_char)(fat[cl].next >> 8); 608 *p++ = (u_char)(fat[cl].next >> 16); 609 *p &= 0xf0; 610 *p++ |= (fat[cl].next >> 24)&0x0f; 611 break; 612 case CLUST16_MASK: 613 if (fat[cl].next == CLUST_FREE) 614 boot->NumFree++; 615 *p++ = (u_char)fat[cl].next; 616 *p++ = (u_char)(fat[cl].next >> 8); 617 break; 618 default: 619 if (fat[cl].next == CLUST_FREE) 620 boot->NumFree++; 621 if (cl + 1 < boot->NumClusters 622 && fat[cl + 1].next == CLUST_FREE) 623 boot->NumFree++; 624 *p++ = (u_char)fat[cl].next; 625 *p++ = (u_char)((fat[cl].next >> 8) & 0xf) 626 |(u_char)(fat[cl+1].next << 4); 627 *p++ = (u_char)(fat[++cl].next >> 4); 628 break; 629 } 630 } 631 for (i = 0; i < boot->bpbFATs; i++) { 632 off = boot->bpbResSectors + i * boot->FATsecs; 633 off *= boot->bpbBytesPerSec; 634 if (lseek(fs, off, SEEK_SET) != off 635 || (size_t)write(fs, buffer, fatsz) != fatsz) { 636 perror("Unable to write FAT"); 637 ret = FSFATAL; /* Return immediately? XXX */ 638 } 639 } 640 free(buffer); 641 return ret; 642} 643 644/* 645 * Check a complete in-memory FAT for lost cluster chains 646 */ 647int 648checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat) 649{ 650 cl_t head; 651 int mod = FSOK; 652 int ret; 653 654 for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 655 /* find next untravelled chain */ 656 if (fat[head].head != head 657 || fat[head].next == CLUST_FREE 658 || (fat[head].next >= CLUST_RSRVD 659 && fat[head].next < CLUST_EOFS) 660 || (fat[head].flags & FAT_USED)) 661 continue; 662 663 pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n", 664 head, fat[head].length); 665 mod |= ret = reconnect(dosfs, boot, fat, head); 666 if (mod & FSFATAL) 667 break; 668 if (ret == FSERROR && ask(0, "Clear")) { 669 clearchain(boot, fat, head); 670 mod |= FSFATMOD; 671 } 672 } 673 finishlf(); 674 675 if (boot->bpbFSInfo) { 676 ret = 0; 677 if (boot->FSFree != boot->NumFree) { 678 pwarn("Free space in FSInfo block (%d) not correct (%d)\n", 679 boot->FSFree, boot->NumFree); 680 if (ask(1, "Fix")) { 681 boot->FSFree = boot->NumFree; 682 ret = 1; 683 } 684 } 685 if (ret) 686 mod |= writefsinfo(dosfs, boot); 687 } 688 689 return mod; 690} 691