1/*
2 * Copyright (c) 2000,2005-2007,2010-2011 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
25 * Copyright (c) 1995 Martin Husemann
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 *    notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 *    notice, this list of conditions and the following disclaimer in the
34 *    documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 *    must display the following acknowledgement:
37 *	This product includes software developed by Martin Husemann
38 *	and Wolfgang Solfrank.
39 * 4. Neither the name of the University nor the names of its contributors
40 *    may be used to endorse or promote products derived from this software
41 *    without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55
56#include <sys/cdefs.h>
57
58#include <stdlib.h>
59#include <string.h>
60#include <ctype.h>
61#include <stdint.h>
62#include <stdio.h>
63#include <unistd.h>
64
65#include <sys/param.h>
66
67#include "ext.h"
68#include "fsutil.h"
69
70/*
71 * The following value should be a multiple of the sector size in bytes.  The
72 * Microsoft supported sector sizes are 512, 1024, 2048, and 4096, which means
73 * this should be a multiple of 4096.  It should also be a minimum of 6K so
74 * that a maximal FAT12 FAT can fit in a single chunk (so the code doesn't
75 * have to handle a FAT entry crossing a chunk boundary).  It should be
76 * large enough to make the I/O efficient, without occupying too much memory.
77 */
78#define FAT_CHUNK_SIZE (64*1024)
79
80
81ssize_t	deblock_read(int d, void *buf, size_t nbytes);
82ssize_t	deblock_write(int d, void *buf, size_t nbytes);
83
84static cl_t fat32_get(cl_t cluster);
85static int fat32_set(cl_t cluster, cl_t value);
86static cl_t fat16_get(cl_t cluster);
87static int fat16_set(cl_t cluster, cl_t value);
88static cl_t fat12_get(cl_t cluster);
89static int fat12_set(cl_t cluster, cl_t value);
90
91cl_t (*fat_get)(cl_t cluster);
92int (*fat_set)(cl_t cluster, cl_t value);
93
94static int gFS;		/* File descriptor to read/write the volume */
95static struct bootblock *gBoot;
96static size_t gUseMapBytes;
97static size_t gNumCacheBlocks;
98
99/*
100 * A cached FAT sector.
101 */
102struct fat_cache_block {
103	unsigned int	dirty:1;
104	unsigned int	chunk:31;
105	struct fat_cache_block *next;	/* LRU list */
106	uint8_t *		buffer;
107	uint32_t		length;	/* Size of this block, in bytes */
108};
109enum { FAT_CHUNK_MAX = 0x7FFFFFFF };
110
111static uint8_t *fat_cache_buffers;
112static struct fat_cache_block *fat_cache;
113static struct fat_cache_block *fat_cache_mru;
114
115/*
116 * Initialize the FAT structures and cache.
117 *
118 * Should we use a global, or return a structure to be passed
119 * back into other routines?
120 */
121int fat_init(int fs, struct bootblock *boot)
122{
123	int mod = 0;
124	int i;
125	cl_t temp;
126	cl_t value;
127
128	/*
129	 * We can get called multiple times if a first
130	 * repair didn't work.  Be prepared to re-use
131	 * or free/reallocate memory.
132	 */
133	fat_uninit();
134
135	gFS = fs;
136	gBoot = boot;
137
138	/*
139	 * Point fat_get and fat_set to the appropriate routine for the volume's
140	 * FAT type.  (Virtual functions in C)
141	 */
142	switch (boot->ClustMask)
143	{
144		case CLUST12_MASK:
145			fat_get = fat12_get;
146			fat_set = fat12_set;
147			break;
148		case CLUST16_MASK:
149			fat_get = fat16_get;
150			fat_set = fat16_set;
151			break;
152		case CLUST32_MASK:
153			fat_get = fat32_get;
154			fat_set = fat32_set;
155			break;
156		default:
157			pfatal("Unknown cluster mask (0x%08X)\n", boot->ClustMask);
158			return FSFATAL;
159	}
160
161	if (initUseMap(boot))
162		return FSFATAL;
163
164	/*
165	 * Allocate space for the FAT cache structures
166	 *
167	 * If maxmem is set, limit the FAT bitmap plus buffers to that amount
168	 * of memory.  TODO: If the entire FAT plus bitmap would fit in less
169	 * than maxmem bytes, just allocate as much as actually needed for the
170	 * entire FAT.
171	 *
172	 * If maxmem is not set, allocate enough to cache the entire FAT.
173	 * TODO: Should we use a smaller number of bigger blocks to minimize the
174	 * overhead of finding a cache block?
175	 */
176	if (maxmem)
177	{
178		gNumCacheBlocks = (maxmem-gUseMapBytes)/FAT_CHUNK_SIZE;
179	}
180	else
181	{
182		gNumCacheBlocks = (boot->FATsecs*boot->BytesPerSec+FAT_CHUNK_SIZE-1)/FAT_CHUNK_SIZE;
183	}
184	fat_cache = calloc(gNumCacheBlocks, sizeof(struct fat_cache_block));
185	if (fat_cache == NULL)
186	{
187		freeUseMap();
188		perr("No memory for FAT cache headers\n");
189		return FSFATAL;
190	}
191	fat_cache_buffers = calloc(gNumCacheBlocks, FAT_CHUNK_SIZE);
192	if (fat_cache_buffers == NULL)
193	{
194		free(fat_cache);
195		fat_cache = NULL;
196		freeUseMap();
197		perr("No memory for FAT cache buffers\n");
198		return FSFATAL;
199	}
200
201	/*
202	 * Initialize the FAT cache buffers and buffer headers
203	 */
204	for (i=0; i<gNumCacheBlocks; ++i)
205	{
206		fat_cache[i].dirty = 0;
207		fat_cache[i].chunk = FAT_CHUNK_MAX;
208		fat_cache[i].buffer = fat_cache_buffers + i * FAT_CHUNK_SIZE;
209		if (i != gNumCacheBlocks-1)
210			fat_cache[i].next = &fat_cache[i+1];
211	}
212	fat_cache_mru = &fat_cache[0];
213
214	/*
215	 * Check the first (index 0) entry of the FAT.  The low byte should be
216	 * the same as boot->Media.  All other bits should be set.  Note that we
217	 * can't rely on fat_get() sign extending the value for us, since 0xF0
218	 * is a valid media type, and is less than CLUST_RSRVD, so won't get
219	 * sign extended.
220	 */
221	value = fat_get(0);
222	if (value == CLUST_ERROR)
223		return FSFATAL;
224	value &= boot->ClustMask;
225	temp = boot->ClustMask & (0xFFFFFF00+boot->Media);
226	if (value != temp)
227	{
228		pwarn("FAT[0] is incorrect (is 0x%X; should be 0x%X)\n", value, temp);
229		if (ask(1, "Correct"))
230		{
231			mod = fat_set(0, temp);
232			if (!mod)
233				mod = FSFATMOD;
234		}
235		else
236		{
237			mod = FSERROR;
238		}
239	}
240
241	/*
242	 * Check the second (index 1) entry of the FAT.  It should be set to an
243	 * end of file mark.  For FAT16 and FAT32, the upper two bits may be cleared
244	 * to indicate "volume dirty" and "hard errors"; for FAT12, it must always
245	 * be an EOF value.
246	 *
247	 * Also check the "clean" bit.  If it is not set (i.e., the volume is dirty),
248	 * set the FSDIRTY status.
249	 */
250	value = fat_get(1);
251	if (value == CLUST_ERROR)
252		return FSFATAL;
253	switch (boot->ClustMask)
254	{
255		case CLUST16_MASK:
256			if ((value & 0x8000) == 0)
257				mod |= FSDIRTY;
258			break;
259		case CLUST32_MASK:
260			if ((value & 0x08000000) == 0)
261				mod |= FSDIRTY;
262			break;
263		default:
264			break;
265	}
266	/*
267	 * Figure out how many bits of the FAT[1] entry to compare.  FAT16 and
268	 * FAT32 use the upper two bits as flags, so we don't want to compare
269	 * them.  The >>2 part below leaves temp set to the cluster mask, but
270	 * with the upper two bits zeroed.  (Note that the cluster mask has
271	 * the lower N bits set.)  FAT12 has no flags, and uses all 12 bits.
272	 *
273	 * The second if statement then compares the significant bits (i.e. not
274	 * the flags) of the fetched value with the same bits of the expected
275	 * value (CLUST_EOFS).
276	 */
277	if (boot->ClustMask == CLUST12_MASK)
278		temp = boot->ClustMask;
279	else
280		temp = boot->ClustMask >> 2;
281	if ((value & temp) < (CLUST_EOFS & temp))
282	{
283		pwarn("FAT[1] is incorrect\n");
284		if (ask(1, "Correct"))
285		{
286			/*
287			 * Set the lower bits of FAT[1] to all ones (i.e. the
288			 * value in temp), but preserving the flags from the
289			 * FAT[1] entry (in the upper two significant bits of
290			 * value).
291			 */
292			i = fat_set(1, value | temp);
293			if (i)
294				mod |= i;
295			else
296				mod |= FSFATMOD;
297		}
298		else
299		{
300			mod |= FSERROR;
301		}
302	}
303
304	return mod;
305}
306
307
308/*
309 * Find the FAT cache block associated with the given cluster.  If not found,
310 * try to find an unused cache block.  Otherwise, recycle the least recently
311 * used block (writing it out first if it was dirty).  Move the found cache
312 * block to the head of the most recently used list.
313 *
314 * Returns NULL on I/O error
315 */
316static struct fat_cache_block *
317fat_cache_find(uint32_t offset)
318{
319	struct fat_cache_block *found;
320	struct fat_cache_block *prev;
321	uint32_t chunk;
322	uint32_t length;
323
324	/* Figure out which chunk we're looking for */
325	chunk = offset / FAT_CHUNK_SIZE;
326	length = (gBoot->FATsecs * gBoot->BytesPerSec) - (chunk * FAT_CHUNK_SIZE);
327	if (length > FAT_CHUNK_SIZE)
328		length = FAT_CHUNK_SIZE;
329
330	/* Find the matching buffer, else LRU buffer */
331	prev = NULL;
332	found = fat_cache_mru;
333	while (found->chunk != chunk && found->next != NULL)
334	{
335		prev = found;
336		found = found->next;
337	}
338
339	/*
340	 * If we didn't find the desired sector in the cache, recycle
341	 * the least recently used buffer.
342	 */
343	if (found->chunk != chunk)
344	{
345		int activeFAT;
346		off_t io_offset;
347
348		activeFAT = gBoot->ValidFat >= 0 ? gBoot->ValidFat : 0;
349
350		if (found->dirty)
351		{
352//			fprintf(stderr, "Writing FAT sector %u\n", found->sector);
353
354			/* Byte offset of start of active FAT */
355			io_offset = (gBoot->ResSectors + activeFAT * gBoot->FATsecs) * gBoot->BytesPerSec;
356
357			/* Byte offset of current chunk */
358			io_offset += found->chunk * FAT_CHUNK_SIZE;
359
360			if (lseek(gFS, io_offset, SEEK_SET) != io_offset)
361			{
362				perr("Unable to seek FAT");
363				return NULL;
364			}
365			if (deblock_write(gFS, found->buffer, found->length) != found->length)
366			{
367				perr("Unable to write FAT");
368				return NULL;
369			}
370
371			found->dirty = 0;
372		}
373
374		/* Figure out where the desired chunk is on disk */
375		found->chunk = chunk;
376		found->length = length;
377
378		/* Byte offset of start of active FAT */
379		io_offset = (gBoot->ResSectors + activeFAT * gBoot->FATsecs) * gBoot->BytesPerSec;
380
381		/* Byte offset of desired chunk */
382		io_offset += chunk * FAT_CHUNK_SIZE;
383
384		/* Read in the sector */
385//		fprintf(stderr, "Reading FAT sector %u\n", found->sector);
386		if (lseek(gFS, io_offset, SEEK_SET) != io_offset)
387		{
388			perr("Unable to seek FAT");
389			return NULL;
390		}
391		if (deblock_read(gFS, found->buffer, length) != length)
392		{
393			perr("Unable to read FAT");
394			return NULL;
395		}
396	}
397
398	/*
399	 * Move the found buffer to the head of the MRU list.
400	 */
401	if (found != fat_cache_mru)
402	{
403		if (prev)
404			prev->next = found->next;
405		found->next = fat_cache_mru;
406		fat_cache_mru = found;
407	}
408
409	return found;
410}
411
412
413void fat_uninit(void)
414{
415	if (fat_cache != NULL)
416	{
417		free(fat_cache);
418		fat_cache = NULL;
419	}
420	if (fat_cache_buffers != NULL)
421	{
422		free(fat_cache_buffers);
423		fat_cache_buffers = NULL;
424	}
425	freeUseMap();
426}
427
428
429/*
430 * Returns the entry for cluster @cluster in @*value.
431 * The function result is the error, if any.
432 */
433static cl_t fat32_get(cl_t cluster)
434{
435	struct fat_cache_block *block;
436	uint8_t *p;
437	cl_t value;
438
439	if (cluster >= gBoot->NumClusters)
440	{
441		fprintf(stderr, "fat32_get: invalid cluster (%u)\n", cluster);
442		return CLUST_ERROR;
443	}
444
445	block = fat_cache_find(cluster*4);
446	if (block == NULL)
447		return CLUST_ERROR;
448
449	/* Point to the @cluster'th entry. */
450	p = block->buffer + (cluster * 4) % FAT_CHUNK_SIZE;
451
452	/* Extract the raw value, ignoring the reserved bits. */
453	value = (p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24)) & CLUST32_MASK;
454
455	/* Sign extended the special values for consistency. */
456	if (value >= (CLUST_RSRVD & CLUST32_MASK))
457		value |= ~CLUST32_MASK;
458
459	return value;
460}
461
462static cl_t fat16_get(cl_t cluster)
463{
464	struct fat_cache_block *block;
465	uint8_t *p;
466	cl_t value;
467
468	if (cluster >= gBoot->NumClusters)
469	{
470		fprintf(stderr, "fat16_get: invalid cluster (%u)\n", cluster);
471		return CLUST_ERROR;
472	}
473
474	block = fat_cache_find(cluster*2);
475	if (block == NULL)
476		return CLUST_ERROR;
477
478	/* Point to the @cluster'th entry. */
479	p = block->buffer + (cluster * 2) % FAT_CHUNK_SIZE;
480
481	/* Extract the value. */
482	value = p[0] + (p[1] << 8);
483
484	/* Sign extended the special values for consistency. */
485	if (value >= (CLUST_RSRVD & CLUST16_MASK))
486		value |= ~CLUST16_MASK;
487
488	return value;
489}
490
491static cl_t fat12_get(cl_t cluster)
492{
493	struct fat_cache_block *block;
494	uint8_t *p;
495	cl_t value;
496
497	if (cluster >= gBoot->NumClusters)
498	{
499		fprintf(stderr, "fat16_get: invalid cluster (%u)\n", cluster);
500		return CLUST_ERROR;
501	}
502
503	block = fat_cache_find(cluster + cluster/2);
504	if (block == NULL)
505		return CLUST_ERROR;
506
507	/* Point to the @cluster'th entry. */
508	p = block->buffer + (cluster + cluster/2) % FAT_CHUNK_SIZE;
509
510	/* Extract the value. */
511	value = p[0] + (p[1] << 8);
512	if (cluster & 1)
513		value >>= 4;
514	else
515		value &= 0x0FFF;
516
517	/* Sign extended the special values for consistency. */
518	if (value >= (CLUST_RSRVD & CLUST12_MASK))
519		value |= ~CLUST12_MASK;
520
521	return value;
522}
523
524
525/*
526 * Sets the entry for cluster @cluster to @value.
527 * The function result is the error, if any.
528 *
529 * For now, this is FAT32-only.
530 */
531static int fat32_set(cl_t cluster, cl_t value)
532{
533	struct fat_cache_block *block;
534	uint8_t *p;
535
536	if (cluster >= gBoot->NumClusters)
537	{
538		fprintf(stderr, "fat32_set: invalid cluster (%u)\n", cluster);
539		return FSFATAL;
540	}
541
542	block = fat_cache_find(cluster*4);
543	if (block == NULL)
544		return FSFATAL;
545
546	/* Point to the @cluster'th entry in the FAT. */
547	p = block->buffer + (cluster * 4) % FAT_CHUNK_SIZE;
548
549	/* Store the value, preserving the reserved bits. */
550	*p++ = (uint8_t) value;
551	*p++ = (uint8_t) (value >> 8);
552	*p++ = (uint8_t) (value >> 16);
553	*p &= 0xF0;
554	*p |= (value >> 24) & 0x0F;
555
556	/* Update the use map. */
557	if (value == CLUST_FREE)
558		markFree(cluster);
559	else
560		markUsed(cluster);
561
562	/* Remember that this block has been changed. */
563	block->dirty = 1;
564
565	return 0;
566}
567
568static int fat16_set(cl_t cluster, cl_t value)
569{
570	struct fat_cache_block *block;
571	uint8_t *p;
572
573	if (cluster >= gBoot->NumClusters)
574	{
575		fprintf(stderr, "fat16_set: invalid cluster (%u)\n", cluster);
576		return FSFATAL;
577	}
578
579	block = fat_cache_find(cluster*2);
580	if (block == NULL)
581		return FSFATAL;
582
583	/* Point to the @cluster'th entry in the FAT. */
584	p = block->buffer + (cluster * 2) % FAT_CHUNK_SIZE;
585
586	/* Store the value. */
587	*p++ = (uint8_t) value;
588	*p   = (uint8_t) (value >> 8);
589
590	/* Update the use map. */
591	if (value == CLUST_FREE)
592		markFree(cluster);
593	else
594		markUsed(cluster);
595
596	/* Remember that this block has been changed. */
597	block->dirty = 1;
598
599	return 0;
600}
601
602static int fat12_set(cl_t cluster, cl_t value)
603{
604	struct fat_cache_block *block;
605	uint8_t *p;
606
607	if (cluster >= gBoot->NumClusters)
608	{
609		fprintf(stderr, "fat16_set: invalid cluster (%u)\n", cluster);
610		return FSFATAL;
611	}
612
613	block = fat_cache_find(cluster + cluster/2);
614	if (block == NULL)
615		return FSFATAL;
616
617	/* Point to the @cluster'th entry in the FAT. */
618	p = block->buffer + (cluster + cluster/2) % FAT_CHUNK_SIZE;
619
620	/* Mix the new value with other nibble. */
621	if (cluster & 1)
622		value = (value << 4) | (p[0] & 0x0F);
623	else
624		value |= (p[1] & 0xF0) << 8;
625	*p++ = (uint8_t) value;
626	*p   = (uint8_t) (value >> 8);
627
628	/* Update the use map. */
629	if (value == CLUST_FREE)
630		markFree(cluster);
631	else
632		markUsed(cluster);
633
634	/* Remember that this block has been changed. */
635	block->dirty = 1;
636
637	return 0;
638}
639
640
641/*
642 * If the FAT has been modified, write it back to disk.
643 */
644int fat_flush(void)
645{
646	int i;
647	int activeFAT;
648	off_t offset;
649
650	activeFAT = gBoot->ValidFat >= 0 ? gBoot->ValidFat : 0;
651
652	for (i=0; i<gNumCacheBlocks; ++i)
653	{
654		if (fat_cache[i].dirty)
655		{
656			/* Byte offset of start of active FAT */
657			offset = (gBoot->ResSectors + activeFAT * gBoot->FATsecs) * gBoot->BytesPerSec;
658
659			/* Byte offset of current chunk */
660			offset += fat_cache[i].chunk * FAT_CHUNK_SIZE;
661
662//			fprintf(stderr, "Flushing FAT sector %u\n", fat_cache[i].sector);
663			if (lseek(gFS, offset, SEEK_SET) != offset)
664			{
665				perr("Unable to seek FAT");
666				return FSFATAL;
667			}
668			if (deblock_write(gFS, fat_cache[i].buffer, fat_cache[i].length) != fat_cache[i].length)
669			{
670				perr("Unable to write FAT");
671				return FSFATAL;
672			}
673
674			fat_cache[i].dirty = 0;
675		}
676	}
677
678	return 0;
679}
680
681
682/*
683 * Mark all unreferenced clusters as CLUST_FREE.  Also calculate
684 * the number of free clusters.
685 */
686int fat_free_unused(void)
687{
688	int err = 0;
689	cl_t cluster, value;
690	cl_t count = 0;
691	int fix=0;
692
693	for (cluster = CLUST_FIRST; cluster < gBoot->NumClusters; ++cluster)
694	{
695		value = fat_get(cluster);
696		if (value == CLUST_ERROR)
697			break;
698		if (!isUsed(cluster))
699		{
700			if (value == CLUST_BAD)
701			{
702				gBoot->NumBad++;
703			}
704			else if (value == CLUST_FREE)
705			{
706				gBoot->NumFree++;
707			}
708			else
709			{
710				if (count == 0)
711				{
712					pwarn("Found orphan cluster(s)\n");
713					fix = ask(1, "Fix");
714				}
715				++count;
716				if (fix)
717				{
718					err = fat_set(cluster, CLUST_FREE);
719					if (err)
720						break;
721					gBoot->NumFree++;
722				}
723			}
724		}
725	}
726
727	if (count)
728	{
729		if (fix)
730		{
731			pwarn("Marked %u clusters as free\n", count);
732			err |= FSFATMOD;
733		}
734		else
735		{
736			pwarn("Found %u orphaned clusters\n", count);
737			err |= FSERROR;
738		}
739	}
740
741	/*
742	 * Check the FSInfo sector.
743	 *
744	 * NOTE: Since the values there are merely "hints", we don't return a
745	 * non-zero exit status if the values are unexpected.
746	 */
747	if (gBoot->FSInfo) {
748		fix = 0;
749		if (gBoot->FSFree != gBoot->NumFree) {
750			pwarn("Free space in FSInfo block (%d) not correct (%d)\n",
751			      gBoot->FSFree, gBoot->NumFree);
752			if (ask(1, "Fix")) {
753				gBoot->FSFree = gBoot->NumFree;
754				fix = 1;
755			} else
756				err |= FSERROR;
757		}
758		if (fix)
759			err |= writefsinfo(gFS, gBoot);
760	}
761
762	return err;
763}
764
765
766/*
767 * Determine whether a volume is dirty, without reading the entire FAT.
768 */
769int isdirty(int fs, struct bootblock *boot, int fat)
770{
771       int             result;
772       u_char  *buffer;
773       off_t   offset;
774
775       result = 1;             /* In case of error, assume volume was dirty */
776
777       /* FAT12 volumes don't have a "clean" bit, so always assume they are dirty */
778       if (boot->ClustMask == CLUST12_MASK)
779               return 1;
780
781       buffer = malloc(boot->BytesPerSec);
782       if (buffer == NULL) {
783               perr("No space for FAT sector");
784               return 1;               /* Assume it was dirty */
785       }
786
787       offset = boot->ResSectors + fat * boot->FATsecs;
788       offset *= boot->BytesPerSec;
789
790       if (lseek(fs, offset, SEEK_SET) != offset) {
791               perr("Unable to read FAT");
792               goto ERROR;
793       }
794
795       if (deblock_read(fs, buffer, boot->BytesPerSec) != boot->BytesPerSec) {
796               perr("Unable to read FAT");
797               goto ERROR;
798       }
799
800       switch (boot->ClustMask) {
801       case CLUST32_MASK:
802               /* FAT32 uses bit 27 of FAT[1] */
803               if ((buffer[7] & 0x08) != 0)
804                       result = 0;             /* It's clean */
805               break;
806       case CLUST16_MASK:
807               /* FAT16 uses bit 15 of FAT[1] */
808               if ((buffer[3] & 0x80) != 0)
809                       result = 0;             /* It's clean */
810               break;
811       }
812
813ERROR:
814       free(buffer);
815       return result;
816}
817
818
819/*
820 * Mark a FAT16 or FAT32 volume "clean."  Ignored for FAT12.
821 */
822int fat_mark_clean(void)
823{
824	cl_t value;
825
826	/*
827	 * FAT12 does not have a "dirty" bit, so do nothing.
828	 */
829	if (gBoot->ClustMask == CLUST12_MASK)
830		return 0;
831
832	value = fat_get(1);
833	if (value == CLUST_ERROR)
834		return FSERROR;
835
836	if (gBoot->ClustMask == CLUST16_MASK)
837		value |= 0x8000;
838	else
839		value |= 0x08000000;
840	return fat_set(1, value);
841}
842
843
844/*
845 * Get type of reserved cluster
846 */
847char *
848rsrvdcltype(cl)
849	cl_t cl;
850{
851	if (cl == CLUST_FREE)
852		return "free";
853	if (cl < CLUST_BAD)
854		return "reserved";
855	if (cl > CLUST_BAD)
856		return "as EOF";
857	return "bad";
858}
859
860#define DEBLOCK_SIZE 		(MAXPHYSIO>>2)
861ssize_t	deblock_read(int d, void *buf, size_t nbytes) {
862    ssize_t		totbytes = 0, readbytes;
863    char		*b = buf;
864
865    while (nbytes > 0) {
866        size_t 		rbytes = nbytes < DEBLOCK_SIZE? nbytes : DEBLOCK_SIZE;
867        readbytes = read(d, b, rbytes);
868        if (readbytes < 0)
869            return readbytes;
870        else if (readbytes == 0)
871            break;
872        else {
873            nbytes-=readbytes;
874            totbytes += readbytes;
875            b += readbytes;
876        }
877    }
878
879    return totbytes;
880}
881
882ssize_t	deblock_write(int d, void *buf, size_t nbytes) {
883    ssize_t		totbytes = 0, writebytes;
884    char		*b = buf;
885
886    while (nbytes > 0) {
887        size_t 		wbytes = nbytes < DEBLOCK_SIZE ? nbytes : DEBLOCK_SIZE;
888        writebytes = write(d, b, wbytes);
889        if (writebytes < 0)
890            return writebytes;
891        else if (writebytes == 0)
892            break;
893        else {
894            nbytes-=writebytes;
895            totbytes += writebytes;
896            b += writebytes;
897        }
898    }
899
900    return totbytes;
901}
902
903
904/*======================================================================
905	Cluster Use Map Routines
906
907	These routines keep track of which clusters have been referenced
908	(by a directory entry).
909
910	Right now, the implementation is a simple bitmap.  But it could be
911	replaced with something else (list of allocated ranges, etc.).
912======================================================================*/
913
914static uint32_t *useMap = NULL;
915
916int initUseMap(struct bootblock *boot)
917{
918	/* Round up clusters to a multiple of 32 */
919	cl_t clusters = (boot->NumClusters + 31) & ~31;
920	if (useMap != NULL)
921		free(useMap);
922	gUseMapBytes = clusters/8;
923	if (maxmem != 0 && maxmem < (gUseMapBytes + FAT_CHUNK_SIZE))
924	{
925		pfatal("Cannot allocate %zd bytes for usemap (maxmem=%zd, clusters=%d)\n"
926			"maxmem must be at least %zd\n",
927			gUseMapBytes, maxmem, clusters, gUseMapBytes + FAT_CHUNK_SIZE);
928		useMap = NULL;
929	}
930	else
931	{
932		useMap = calloc(clusters/32, sizeof(uint32_t));
933	}
934	return useMap==NULL;
935}
936
937void freeUseMap(void)
938{
939	if (useMap != NULL)
940		free(useMap);
941	useMap = NULL;
942}
943
944int isUsed(cl_t cluster)
945{
946	return (useMap[cluster/32] >> cluster%32) & 1;
947}
948
949int markUsed(cl_t cluster)
950{
951	int error = 0;
952	cl_t index = cluster / 32;
953	uint32_t mask = 1 << (cluster % 32);
954
955	if (useMap[index] & mask)
956		error = 1;
957	else
958		useMap[index] |= mask;
959
960	return error;
961}
962
963int markFree(cl_t cluster)
964{
965	int error = 0;
966	cl_t index = cluster / 32;
967	uint32_t mask = 1 << (cluster % 32);
968
969	if (useMap[index] & mask)
970		useMap[index] &= ~mask;
971	else
972		error = 1;
973
974	return error;
975}
976