Home | History | Annotate | Download | only in fsck_msdos
      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