xref: /aosp_15_r20/external/mtools/fat.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1*d5c9a868SElliott Hughes /*  Copyright 1996-2006,2008,2009 Alain Knaff.
2*d5c9a868SElliott Hughes  *  This file is part of mtools.
3*d5c9a868SElliott Hughes  *
4*d5c9a868SElliott Hughes  *  Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes  *  it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes  *  the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes  *  (at your option) any later version.
8*d5c9a868SElliott Hughes  *
9*d5c9a868SElliott Hughes  *  Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*d5c9a868SElliott Hughes  *  GNU General Public License for more details.
13*d5c9a868SElliott Hughes  *
14*d5c9a868SElliott Hughes  *  You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes  */
17*d5c9a868SElliott Hughes 
18*d5c9a868SElliott Hughes 
19*d5c9a868SElliott Hughes #include "sysincludes.h"
20*d5c9a868SElliott Hughes #include "msdos.h"
21*d5c9a868SElliott Hughes #include "stream.h"
22*d5c9a868SElliott Hughes #include "mtools.h"
23*d5c9a868SElliott Hughes #include "fsP.h"
24*d5c9a868SElliott Hughes #include "file_name.h"
25*d5c9a868SElliott Hughes 
26*d5c9a868SElliott Hughes #ifdef HAVE_LONG_LONG
27*d5c9a868SElliott Hughes typedef long long fatBitMask;
28*d5c9a868SElliott Hughes #else
29*d5c9a868SElliott Hughes typedef long fatBitMask;
30*d5c9a868SElliott Hughes #endif
31*d5c9a868SElliott Hughes 
32*d5c9a868SElliott Hughes typedef struct FatMap_t {
33*d5c9a868SElliott Hughes 	unsigned char *data;
34*d5c9a868SElliott Hughes 	fatBitMask dirty;
35*d5c9a868SElliott Hughes 	fatBitMask valid;
36*d5c9a868SElliott Hughes } FatMap_t;
37*d5c9a868SElliott Hughes 
38*d5c9a868SElliott Hughes #define SECT_PER_ENTRY (sizeof(fatBitMask)*8)
39*d5c9a868SElliott Hughes #define ONE ((fatBitMask) 1)
40*d5c9a868SElliott Hughes 
readSector(Fs_t * This,char * buf,unsigned int off,size_t size)41*d5c9a868SElliott Hughes static __inline__ ssize_t readSector(Fs_t *This, char *buf, unsigned int off,
42*d5c9a868SElliott Hughes 				     size_t size)
43*d5c9a868SElliott Hughes {
44*d5c9a868SElliott Hughes 	return PREADS(This->head.Next, buf, sectorsToBytes(This, off),
45*d5c9a868SElliott Hughes 		      size << This->sectorShift);
46*d5c9a868SElliott Hughes }
47*d5c9a868SElliott Hughes 
48*d5c9a868SElliott Hughes 
forceReadSector(Fs_t * This,char * buf,unsigned int off,size_t size)49*d5c9a868SElliott Hughes static __inline__ ssize_t forceReadSector(Fs_t *This, char *buf,
50*d5c9a868SElliott Hughes 					  unsigned int off, size_t size)
51*d5c9a868SElliott Hughes {
52*d5c9a868SElliott Hughes 	return force_pread(This->head.Next, buf, sectorsToBytes(This, off),
53*d5c9a868SElliott Hughes 			   size << This->sectorShift);
54*d5c9a868SElliott Hughes }
55*d5c9a868SElliott Hughes 
56*d5c9a868SElliott Hughes 
forceWriteSector(Fs_t * This,char * buf,unsigned int off,size_t size)57*d5c9a868SElliott Hughes static __inline__ ssize_t forceWriteSector(Fs_t *This, char *buf, unsigned int off,
58*d5c9a868SElliott Hughes 					   size_t size)
59*d5c9a868SElliott Hughes {
60*d5c9a868SElliott Hughes 	return force_pwrite(This->head.Next, buf, sectorsToBytes(This, off),
61*d5c9a868SElliott Hughes 			    size << This->sectorShift);
62*d5c9a868SElliott Hughes }
63*d5c9a868SElliott Hughes 
64*d5c9a868SElliott Hughes 
GetFatMap(Fs_t * Stream)65*d5c9a868SElliott Hughes static FatMap_t *GetFatMap(Fs_t *Stream)
66*d5c9a868SElliott Hughes {
67*d5c9a868SElliott Hughes 	size_t nr_entries;
68*d5c9a868SElliott Hughes 	size_t i;
69*d5c9a868SElliott Hughes 	FatMap_t *map;
70*d5c9a868SElliott Hughes 
71*d5c9a868SElliott Hughes 	Stream->fat_error = 0;
72*d5c9a868SElliott Hughes 	nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
73*d5c9a868SElliott Hughes 	map = NewArray(nr_entries, FatMap_t);
74*d5c9a868SElliott Hughes 	if(!map)
75*d5c9a868SElliott Hughes 		return 0;
76*d5c9a868SElliott Hughes 
77*d5c9a868SElliott Hughes 	for(i=0; i< nr_entries; i++) {
78*d5c9a868SElliott Hughes 		map[i].data = 0;
79*d5c9a868SElliott Hughes 		map[i].valid = 0;
80*d5c9a868SElliott Hughes 		map[i].dirty = 0;
81*d5c9a868SElliott Hughes 	}
82*d5c9a868SElliott Hughes 
83*d5c9a868SElliott Hughes 	return map;
84*d5c9a868SElliott Hughes }
85*d5c9a868SElliott Hughes 
locate(Fs_t * Stream,uint32_t offset,uint32_t * slot,uint32_t * bit)86*d5c9a868SElliott Hughes static __inline__ int locate(Fs_t *Stream, uint32_t offset,
87*d5c9a868SElliott Hughes 			     uint32_t *slot, uint32_t *bit)
88*d5c9a868SElliott Hughes {
89*d5c9a868SElliott Hughes 	if(offset >= Stream->fat_len)
90*d5c9a868SElliott Hughes 		return -1;
91*d5c9a868SElliott Hughes 	*slot = offset / SECT_PER_ENTRY;
92*d5c9a868SElliott Hughes 	*bit = offset % SECT_PER_ENTRY;
93*d5c9a868SElliott Hughes 	return 0;
94*d5c9a868SElliott Hughes }
95*d5c9a868SElliott Hughes 
fatReadSector(Fs_t * This,unsigned int sector,unsigned int slot,unsigned int bit,unsigned int dupe,fatBitMask bitmap)96*d5c9a868SElliott Hughes static __inline__ ssize_t fatReadSector(Fs_t *This,
97*d5c9a868SElliott Hughes 					unsigned int sector,
98*d5c9a868SElliott Hughes 					unsigned int slot,
99*d5c9a868SElliott Hughes 					unsigned int bit, unsigned int dupe,
100*d5c9a868SElliott Hughes 					fatBitMask bitmap)
101*d5c9a868SElliott Hughes {
102*d5c9a868SElliott Hughes 	unsigned int fat_start;
103*d5c9a868SElliott Hughes 	ssize_t ret;
104*d5c9a868SElliott Hughes 	unsigned int nr_sectors;
105*d5c9a868SElliott Hughes 
106*d5c9a868SElliott Hughes 	dupe = (dupe + This->primaryFat) % This->num_fat;
107*d5c9a868SElliott Hughes 	fat_start = This->fat_start + This->fat_len * dupe;
108*d5c9a868SElliott Hughes 
109*d5c9a868SElliott Hughes 	if(bitmap == 0) {
110*d5c9a868SElliott Hughes 	    nr_sectors = SECT_PER_ENTRY - bit%SECT_PER_ENTRY;
111*d5c9a868SElliott Hughes 	} else {
112*d5c9a868SElliott Hughes 	    nr_sectors = 1;
113*d5c9a868SElliott Hughes 	}
114*d5c9a868SElliott Hughes 
115*d5c9a868SElliott Hughes 	/* first, read as much as the buffer can give us */
116*d5c9a868SElliott Hughes 	ret = readSector(This,
117*d5c9a868SElliott Hughes 			 (char *)(This->FatMap[slot].data+(bit<<This->sectorShift)),
118*d5c9a868SElliott Hughes 			 fat_start+sector,
119*d5c9a868SElliott Hughes 			 nr_sectors);
120*d5c9a868SElliott Hughes 	if(ret < 0)
121*d5c9a868SElliott Hughes 		return 0;
122*d5c9a868SElliott Hughes 
123*d5c9a868SElliott Hughes 	if((size_t) ret < This->sector_size) {
124*d5c9a868SElliott Hughes 		/* if we got less than one sector's worth, insist to get at
125*d5c9a868SElliott Hughes 		 * least one sector */
126*d5c9a868SElliott Hughes 		ret = forceReadSector(This,
127*d5c9a868SElliott Hughes 				      (char *) (This->FatMap[slot].data +
128*d5c9a868SElliott Hughes 						(bit << This->sectorShift)),
129*d5c9a868SElliott Hughes 				      fat_start+sector, 1);
130*d5c9a868SElliott Hughes 		if(ret < (int) This->sector_size)
131*d5c9a868SElliott Hughes 			return 0;
132*d5c9a868SElliott Hughes 		return 1;
133*d5c9a868SElliott Hughes 	}
134*d5c9a868SElliott Hughes 
135*d5c9a868SElliott Hughes 	return ret >> This->sectorShift;
136*d5c9a868SElliott Hughes }
137*d5c9a868SElliott Hughes 
138*d5c9a868SElliott Hughes 
fatWriteSector(Fs_t * This,unsigned int sector,unsigned int slot,unsigned int bit,unsigned int dupe)139*d5c9a868SElliott Hughes static ssize_t fatWriteSector(Fs_t *This,
140*d5c9a868SElliott Hughes 			      unsigned int sector,
141*d5c9a868SElliott Hughes 			      unsigned int slot,
142*d5c9a868SElliott Hughes 			      unsigned int bit,
143*d5c9a868SElliott Hughes 			      unsigned int dupe)
144*d5c9a868SElliott Hughes {
145*d5c9a868SElliott Hughes 	unsigned int fat_start;
146*d5c9a868SElliott Hughes 
147*d5c9a868SElliott Hughes 	dupe = (dupe + This->primaryFat) % This->num_fat;
148*d5c9a868SElliott Hughes 	if(dupe && !This->writeAllFats)
149*d5c9a868SElliott Hughes 		return This->sector_size;
150*d5c9a868SElliott Hughes 
151*d5c9a868SElliott Hughes 	fat_start = This->fat_start + This->fat_len * dupe;
152*d5c9a868SElliott Hughes 
153*d5c9a868SElliott Hughes 	return forceWriteSector(This,
154*d5c9a868SElliott Hughes 				(char *)
155*d5c9a868SElliott Hughes 				(This->FatMap[slot].data + bit * This->sector_size),
156*d5c9a868SElliott Hughes 				fat_start+sector, 1);
157*d5c9a868SElliott Hughes }
158*d5c9a868SElliott Hughes 
loadSector(Fs_t * This,unsigned int sector,fatAccessMode_t mode,int recurs)159*d5c9a868SElliott Hughes static unsigned char *loadSector(Fs_t *This,
160*d5c9a868SElliott Hughes 				 unsigned int sector, fatAccessMode_t mode,
161*d5c9a868SElliott Hughes 				 int recurs)
162*d5c9a868SElliott Hughes {
163*d5c9a868SElliott Hughes 	uint32_t slot, bit;
164*d5c9a868SElliott Hughes 	ssize_t ret;
165*d5c9a868SElliott Hughes 
166*d5c9a868SElliott Hughes 	if(locate(This,sector, &slot, &bit) < 0)
167*d5c9a868SElliott Hughes 		return 0;
168*d5c9a868SElliott Hughes #if 0
169*d5c9a868SElliott Hughes         if (((This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY) <= slot) {
170*d5c9a868SElliott Hughes 		fprintf(stderr,"This should not happen\n");
171*d5c9a868SElliott Hughes 		fprintf(stderr, "fat_len = %d\n", This->fat_len);
172*d5c9a868SElliott Hughes 		fprintf(stderr, "SECT_PER_ENTRY=%d\n", (int)SECT_PER_ENTRY);
173*d5c9a868SElliott Hughes 		fprintf(stderr, "sector = %d slot = %d bit=%d\n",
174*d5c9a868SElliott Hughes 			sector, slot, bit);
175*d5c9a868SElliott Hughes 		fprintf(stderr, "left = %d",(int)
176*d5c9a868SElliott Hughes 			((This->fat_len+SECT_PER_ENTRY-1) / SECT_PER_ENTRY));
177*d5c9a868SElliott Hughes                 return 0;
178*d5c9a868SElliott Hughes 	}
179*d5c9a868SElliott Hughes #endif
180*d5c9a868SElliott Hughes 	if(!This->FatMap[slot].data) {
181*d5c9a868SElliott Hughes 		/* allocate the storage space */
182*d5c9a868SElliott Hughes 		This->FatMap[slot].data =
183*d5c9a868SElliott Hughes 			malloc(This->sector_size * SECT_PER_ENTRY);
184*d5c9a868SElliott Hughes 		if(!This->FatMap[slot].data)
185*d5c9a868SElliott Hughes 			return 0;
186*d5c9a868SElliott Hughes 		memset(This->FatMap[slot].data, 0xee,
187*d5c9a868SElliott Hughes 		       This->sector_size * SECT_PER_ENTRY);
188*d5c9a868SElliott Hughes 	}
189*d5c9a868SElliott Hughes 
190*d5c9a868SElliott Hughes 	if(! (This->FatMap[slot].valid & (ONE << bit))) {
191*d5c9a868SElliott Hughes 		unsigned int i;
192*d5c9a868SElliott Hughes 		ret = -1;
193*d5c9a868SElliott Hughes 		for(i=0; i< This->num_fat; i++) {
194*d5c9a868SElliott Hughes 			/* read the sector */
195*d5c9a868SElliott Hughes 			ret = fatReadSector(This, sector, slot, bit, i,
196*d5c9a868SElliott Hughes 					    This->FatMap[slot].valid);
197*d5c9a868SElliott Hughes 
198*d5c9a868SElliott Hughes 			if(ret == 0) {
199*d5c9a868SElliott Hughes 				fprintf(stderr,
200*d5c9a868SElliott Hughes 					"Error reading fat number %d\n", i);
201*d5c9a868SElliott Hughes 				continue;
202*d5c9a868SElliott Hughes 			}
203*d5c9a868SElliott Hughes 			if(This->FatMap[slot].valid)
204*d5c9a868SElliott Hughes 			    /* Set recurs if there have already been
205*d5c9a868SElliott Hughes 			     * sectors loaded in this bitmap long
206*d5c9a868SElliott Hughes 			     */
207*d5c9a868SElliott Hughes 			    recurs = 1;
208*d5c9a868SElliott Hughes 			break;
209*d5c9a868SElliott Hughes 		}
210*d5c9a868SElliott Hughes 
211*d5c9a868SElliott Hughes 		/* all copies bad.  Return error */
212*d5c9a868SElliott Hughes 		if(ret == 0)
213*d5c9a868SElliott Hughes 			return 0;
214*d5c9a868SElliott Hughes 
215*d5c9a868SElliott Hughes 		for(i=0; (int) i < ret; i++)
216*d5c9a868SElliott Hughes 			This->FatMap[slot].valid |= ONE << (bit + i);
217*d5c9a868SElliott Hughes 
218*d5c9a868SElliott Hughes 		if(!recurs && ret == 1)
219*d5c9a868SElliott Hughes 			/* do some prefetching, if we happened to only
220*d5c9a868SElliott Hughes 			 * get one sector */
221*d5c9a868SElliott Hughes 			loadSector(This, sector+1, mode, 1);
222*d5c9a868SElliott Hughes 		if(!recurs && batchmode)
223*d5c9a868SElliott Hughes 			for(i=0; i < 1024; i++)
224*d5c9a868SElliott Hughes 				loadSector(This, sector+i, mode, 1);
225*d5c9a868SElliott Hughes 	}
226*d5c9a868SElliott Hughes 
227*d5c9a868SElliott Hughes 	if(mode == FAT_ACCESS_WRITE) {
228*d5c9a868SElliott Hughes 		This->FatMap[slot].dirty |= ONE << bit;
229*d5c9a868SElliott Hughes 		This->fat_dirty = 1;
230*d5c9a868SElliott Hughes 	}
231*d5c9a868SElliott Hughes 	return This->FatMap[slot].data + (bit << This->sectorShift);
232*d5c9a868SElliott Hughes }
233*d5c9a868SElliott Hughes 
234*d5c9a868SElliott Hughes 
getAddress(Fs_t * Stream,unsigned int num,fatAccessMode_t mode)235*d5c9a868SElliott Hughes static unsigned char *getAddress(Fs_t *Stream,
236*d5c9a868SElliott Hughes 				 unsigned int num, fatAccessMode_t mode)
237*d5c9a868SElliott Hughes {
238*d5c9a868SElliott Hughes 	unsigned char *ret;
239*d5c9a868SElliott Hughes 	unsigned int sector;
240*d5c9a868SElliott Hughes 	unsigned int offset;
241*d5c9a868SElliott Hughes 
242*d5c9a868SElliott Hughes 	sector = num >> Stream->sectorShift;
243*d5c9a868SElliott Hughes 	ret = 0;
244*d5c9a868SElliott Hughes 	if(sector == Stream->lastFatSectorNr &&
245*d5c9a868SElliott Hughes 	   Stream->lastFatAccessMode >= mode)
246*d5c9a868SElliott Hughes 		ret = Stream->lastFatSectorData;
247*d5c9a868SElliott Hughes 	if(!ret) {
248*d5c9a868SElliott Hughes 		ret = loadSector(Stream, sector, mode, 0);
249*d5c9a868SElliott Hughes 		if(!ret)
250*d5c9a868SElliott Hughes 			return 0;
251*d5c9a868SElliott Hughes 		Stream->lastFatSectorNr = sector;
252*d5c9a868SElliott Hughes 		Stream->lastFatSectorData = ret;
253*d5c9a868SElliott Hughes 		Stream->lastFatAccessMode = mode;
254*d5c9a868SElliott Hughes 	}
255*d5c9a868SElliott Hughes 	offset = num & Stream->sectorMask;
256*d5c9a868SElliott Hughes 	return ret+offset;
257*d5c9a868SElliott Hughes }
258*d5c9a868SElliott Hughes 
259*d5c9a868SElliott Hughes 
readByte(Fs_t * Stream,unsigned int start)260*d5c9a868SElliott Hughes static int readByte(Fs_t *Stream, unsigned int start)
261*d5c9a868SElliott Hughes {
262*d5c9a868SElliott Hughes 	unsigned char *address;
263*d5c9a868SElliott Hughes 
264*d5c9a868SElliott Hughes 	address = getAddress(Stream, start, FAT_ACCESS_READ);
265*d5c9a868SElliott Hughes 	if(!address)
266*d5c9a868SElliott Hughes 		return -1;
267*d5c9a868SElliott Hughes 	return *address;
268*d5c9a868SElliott Hughes }
269*d5c9a868SElliott Hughes 
270*d5c9a868SElliott Hughes 
271*d5c9a868SElliott Hughes /*
272*d5c9a868SElliott Hughes  * Fat 12 encoding:
273*d5c9a868SElliott Hughes  *	|    byte n     |   byte n+1    |   byte n+2    |
274*d5c9a868SElliott Hughes  *	|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
275*d5c9a868SElliott Hughes  *	| | | | | | | | | | | | | | | | | | | | | | | | |
276*d5c9a868SElliott Hughes  *	| n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
277*d5c9a868SElliott Hughes  *	    \_____  \____   \______/________/_____   /
278*d5c9a868SElliott Hughes  *	      ____\______\________/   _____/  ____\_/
279*d5c9a868SElliott Hughes  *	     /     \      \          /       /     \
280*d5c9a868SElliott Hughes  *	| n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 |
281*d5c9a868SElliott Hughes  *	|      FAT entry k      |    FAT entry k+1      |
282*d5c9a868SElliott Hughes  */
283*d5c9a868SElliott Hughes 
284*d5c9a868SElliott Hughes  /*
285*d5c9a868SElliott Hughes  * Get and decode a FAT (file allocation table) entry.  Returns the cluster
286*d5c9a868SElliott Hughes  * number on success or 1 on failure.
287*d5c9a868SElliott Hughes  */
288*d5c9a868SElliott Hughes 
fat12_decode(Fs_t * Stream,unsigned int num)289*d5c9a868SElliott Hughes static unsigned int fat12_decode(Fs_t *Stream, unsigned int num)
290*d5c9a868SElliott Hughes {
291*d5c9a868SElliott Hughes 	unsigned int start = num * 3 / 2;
292*d5c9a868SElliott Hughes 	int byte0 = readByte(Stream, start);
293*d5c9a868SElliott Hughes 	int byte1 = readByte(Stream, start+1);
294*d5c9a868SElliott Hughes 
295*d5c9a868SElliott Hughes 	if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1) {
296*d5c9a868SElliott Hughes 		fprintf(stderr,"[1] Bad address %d\n", num);
297*d5c9a868SElliott Hughes 		return 1;
298*d5c9a868SElliott Hughes 	}
299*d5c9a868SElliott Hughes 
300*d5c9a868SElliott Hughes 	if (num & 1)
301*d5c9a868SElliott Hughes 		return ((uint32_t)byte1 << 4) | (((uint32_t)byte0 & 0xf0)>>4);
302*d5c9a868SElliott Hughes 	else
303*d5c9a868SElliott Hughes 		return (((uint32_t)byte1 & 0xf) << 8) | (uint32_t)byte0;
304*d5c9a868SElliott Hughes }
305*d5c9a868SElliott Hughes 
306*d5c9a868SElliott Hughes 
307*d5c9a868SElliott Hughes /*
308*d5c9a868SElliott Hughes  * Puts a code into the FAT table.  Is the opposite of fat_decode().  No
309*d5c9a868SElliott Hughes  * sanity checking is done on the code.  Returns a 1 on error.
310*d5c9a868SElliott Hughes  */
fat12_encode(Fs_t * Stream,unsigned int num,unsigned int code)311*d5c9a868SElliott Hughes static void fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code)
312*d5c9a868SElliott Hughes {
313*d5c9a868SElliott Hughes 	unsigned int start = num * 3 / 2;
314*d5c9a868SElliott Hughes 	unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE);
315*d5c9a868SElliott Hughes 	unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE);
316*d5c9a868SElliott Hughes 
317*d5c9a868SElliott Hughes 	if (num & 1) {
318*d5c9a868SElliott Hughes 		/* (odd) not on byte boundary */
319*d5c9a868SElliott Hughes 		*address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0);
320*d5c9a868SElliott Hughes 		*address1 = (code >> 4) & 0xff;
321*d5c9a868SElliott Hughes 	} else {
322*d5c9a868SElliott Hughes 		/* (even) on byte boundary */
323*d5c9a868SElliott Hughes 		*address0 = code & 0xff;
324*d5c9a868SElliott Hughes 		*address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f);
325*d5c9a868SElliott Hughes 	}
326*d5c9a868SElliott Hughes }
327*d5c9a868SElliott Hughes 
328*d5c9a868SElliott Hughes 
329*d5c9a868SElliott Hughes /*
330*d5c9a868SElliott Hughes  * Fat 16 encoding:
331*d5c9a868SElliott Hughes  *	|    byte n     |   byte n+1    |
332*d5c9a868SElliott Hughes  *	|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
333*d5c9a868SElliott Hughes  *	| | | | | | | | | | | | | | | | |
334*d5c9a868SElliott Hughes  *	|         FAT entry k           |
335*d5c9a868SElliott Hughes  */
336*d5c9a868SElliott Hughes 
fat16_decode(Fs_t * Stream,unsigned int num)337*d5c9a868SElliott Hughes static unsigned int fat16_decode(Fs_t *Stream, unsigned int num)
338*d5c9a868SElliott Hughes {
339*d5c9a868SElliott Hughes 	unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ);
340*d5c9a868SElliott Hughes 	if(!address)
341*d5c9a868SElliott Hughes 		return 1;
342*d5c9a868SElliott Hughes 	return _WORD(address);
343*d5c9a868SElliott Hughes }
344*d5c9a868SElliott Hughes 
fat16_encode(Fs_t * Stream,unsigned int num,unsigned int code)345*d5c9a868SElliott Hughes static void fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
346*d5c9a868SElliott Hughes {
347*d5c9a868SElliott Hughes 	if(code > UINT16_MAX) {
348*d5c9a868SElliott Hughes 		fprintf(stderr, "FAT16 code %x too big\n", code);
349*d5c9a868SElliott Hughes 		exit(1);
350*d5c9a868SElliott Hughes 	}
351*d5c9a868SElliott Hughes 	unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE);
352*d5c9a868SElliott Hughes 	set_word(address, (uint16_t) code);
353*d5c9a868SElliott Hughes }
354*d5c9a868SElliott Hughes 
355*d5c9a868SElliott Hughes 
356*d5c9a868SElliott Hughes #pragma GCC diagnostic push
357*d5c9a868SElliott Hughes #pragma GCC diagnostic ignored "-Wcast-align"
358*d5c9a868SElliott Hughes /* Ignore alignment warnings about casting to type with higher
359*d5c9a868SElliott Hughes  * alignment requirement. Requirement is met, as initial pointer is an
360*d5c9a868SElliott Hughes  * even offset into a buffer allocated by malloc, which according to
361*d5c9a868SElliott Hughes  * manpage is "suitably aligned for any built-in type */
fast_fat16_decode(Fs_t * Stream,unsigned int num)362*d5c9a868SElliott Hughes static unsigned int fast_fat16_decode(Fs_t *Stream, unsigned int num)
363*d5c9a868SElliott Hughes {
364*d5c9a868SElliott Hughes 	unsigned short *address =
365*d5c9a868SElliott Hughes 		(unsigned short *) getAddress(Stream, num << 1,
366*d5c9a868SElliott Hughes 					      FAT_ACCESS_READ);
367*d5c9a868SElliott Hughes 	if(!address)
368*d5c9a868SElliott Hughes 		return 1;
369*d5c9a868SElliott Hughes 	return *address;
370*d5c9a868SElliott Hughes }
371*d5c9a868SElliott Hughes 
fast_fat16_encode(Fs_t * Stream,unsigned int num,unsigned int code)372*d5c9a868SElliott Hughes static void fast_fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
373*d5c9a868SElliott Hughes {
374*d5c9a868SElliott Hughes 	unsigned short *address =
375*d5c9a868SElliott Hughes 		(unsigned short *) getAddress(Stream, num << 1,
376*d5c9a868SElliott Hughes 					      FAT_ACCESS_WRITE);
377*d5c9a868SElliott Hughes 	if(code > UINT16_MAX) {
378*d5c9a868SElliott Hughes 		fprintf(stderr, "FAT16 code %x too big\n", code);
379*d5c9a868SElliott Hughes 		exit(1);
380*d5c9a868SElliott Hughes 	}
381*d5c9a868SElliott Hughes 	*address = (uint16_t) code;
382*d5c9a868SElliott Hughes }
383*d5c9a868SElliott Hughes #pragma GCC diagnostic pop
384*d5c9a868SElliott Hughes 
385*d5c9a868SElliott Hughes 
386*d5c9a868SElliott Hughes 
387*d5c9a868SElliott Hughes /*
388*d5c9a868SElliott Hughes  * Fat 32 encoding
389*d5c9a868SElliott Hughes  */
390*d5c9a868SElliott Hughes #define FAT32_HIGH 0xf0000000
391*d5c9a868SElliott Hughes #define FAT32_ADDR 0x0fffffff
392*d5c9a868SElliott Hughes 
fat32_decode(Fs_t * Stream,unsigned int num)393*d5c9a868SElliott Hughes static unsigned int fat32_decode(Fs_t *Stream, unsigned int num)
394*d5c9a868SElliott Hughes {
395*d5c9a868SElliott Hughes 	unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ);
396*d5c9a868SElliott Hughes 	if(!address)
397*d5c9a868SElliott Hughes 		return 1;
398*d5c9a868SElliott Hughes 	return _DWORD(address) & FAT32_ADDR;
399*d5c9a868SElliott Hughes }
400*d5c9a868SElliott Hughes 
fat32_encode(Fs_t * Stream,unsigned int num,unsigned int code)401*d5c9a868SElliott Hughes static void fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
402*d5c9a868SElliott Hughes {
403*d5c9a868SElliott Hughes 	unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE);
404*d5c9a868SElliott Hughes 	set_dword(address,(code&FAT32_ADDR) | (_DWORD(address)&FAT32_HIGH));
405*d5c9a868SElliott Hughes }
406*d5c9a868SElliott Hughes 
407*d5c9a868SElliott Hughes #pragma GCC diagnostic push
408*d5c9a868SElliott Hughes #pragma GCC diagnostic ignored "-Wcast-align"
fast_fat32_decode(Fs_t * Stream,unsigned int num)409*d5c9a868SElliott Hughes static unsigned int fast_fat32_decode(Fs_t *Stream, unsigned int num)
410*d5c9a868SElliott Hughes {
411*d5c9a868SElliott Hughes 	unsigned int *address =
412*d5c9a868SElliott Hughes 		(unsigned int *) getAddress(Stream, num << 2,
413*d5c9a868SElliott Hughes 					    FAT_ACCESS_READ);
414*d5c9a868SElliott Hughes 	if(!address)
415*d5c9a868SElliott Hughes 		return 1;
416*d5c9a868SElliott Hughes 	return (*address) & FAT32_ADDR;
417*d5c9a868SElliott Hughes }
418*d5c9a868SElliott Hughes 
fast_fat32_encode(Fs_t * Stream,unsigned int num,unsigned int code)419*d5c9a868SElliott Hughes static void fast_fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
420*d5c9a868SElliott Hughes {
421*d5c9a868SElliott Hughes 	unsigned int *address =
422*d5c9a868SElliott Hughes 		(unsigned int *) getAddress(Stream, num << 2,
423*d5c9a868SElliott Hughes 					    FAT_ACCESS_WRITE);
424*d5c9a868SElliott Hughes 	*address = (*address & FAT32_HIGH) | (code & FAT32_ADDR);
425*d5c9a868SElliott Hughes }
426*d5c9a868SElliott Hughes #pragma GCC diagnostic pop
427*d5c9a868SElliott Hughes 
428*d5c9a868SElliott Hughes /*
429*d5c9a868SElliott Hughes  * Write the FAT table to the disk.  Up to now the FAT manipulation has
430*d5c9a868SElliott Hughes  * been done in memory.  All errors are fatal.  (Might not be too smart
431*d5c9a868SElliott Hughes  * to wait till the end of the program to write the table.  Oh well...)
432*d5c9a868SElliott Hughes  */
433*d5c9a868SElliott Hughes 
fat_write(Fs_t * This)434*d5c9a868SElliott Hughes void fat_write(Fs_t *This)
435*d5c9a868SElliott Hughes {
436*d5c9a868SElliott Hughes 	unsigned int i, j, dups, bit, slot;
437*d5c9a868SElliott Hughes 	ssize_t ret;
438*d5c9a868SElliott Hughes 
439*d5c9a868SElliott Hughes 	/*fprintf(stderr, "Fat write\n");*/
440*d5c9a868SElliott Hughes 
441*d5c9a868SElliott Hughes 	if (!This->fat_dirty)
442*d5c9a868SElliott Hughes 		return;
443*d5c9a868SElliott Hughes 
444*d5c9a868SElliott Hughes 	dups = This->num_fat;
445*d5c9a868SElliott Hughes 	if (This->fat_error)
446*d5c9a868SElliott Hughes 		dups = 1;
447*d5c9a868SElliott Hughes 
448*d5c9a868SElliott Hughes 
449*d5c9a868SElliott Hughes 	for(i=0; i<dups; i++){
450*d5c9a868SElliott Hughes 		j = 0;
451*d5c9a868SElliott Hughes 		for(slot=0;j<This->fat_len;slot++) {
452*d5c9a868SElliott Hughes 			if(!This->FatMap[slot].dirty) {
453*d5c9a868SElliott Hughes 				j += SECT_PER_ENTRY;
454*d5c9a868SElliott Hughes 				continue;
455*d5c9a868SElliott Hughes 			}
456*d5c9a868SElliott Hughes 			for(bit=0;
457*d5c9a868SElliott Hughes 			    bit < SECT_PER_ENTRY && j<This->fat_len;
458*d5c9a868SElliott Hughes 			    bit++,j++) {
459*d5c9a868SElliott Hughes 				if(!(This->FatMap[slot].dirty & (ONE << bit)))
460*d5c9a868SElliott Hughes 					continue;
461*d5c9a868SElliott Hughes 				ret = fatWriteSector(This,j,slot, bit, i);
462*d5c9a868SElliott Hughes 				if (ret < (int) This->sector_size){
463*d5c9a868SElliott Hughes 					if (ret < 0 ){
464*d5c9a868SElliott Hughes 						perror("error in fat_write");
465*d5c9a868SElliott Hughes 						exit(1);
466*d5c9a868SElliott Hughes 					} else {
467*d5c9a868SElliott Hughes 						fprintf(stderr,
468*d5c9a868SElliott Hughes 							"end of file in fat_write\n");
469*d5c9a868SElliott Hughes 						exit(1);
470*d5c9a868SElliott Hughes 					}
471*d5c9a868SElliott Hughes 				}
472*d5c9a868SElliott Hughes 				/* if last dupe, zero it out */
473*d5c9a868SElliott Hughes 				if(i==dups-1)
474*d5c9a868SElliott Hughes 					This->FatMap[slot].dirty &= ~(ONE<<bit);
475*d5c9a868SElliott Hughes 			}
476*d5c9a868SElliott Hughes 		}
477*d5c9a868SElliott Hughes 	}
478*d5c9a868SElliott Hughes 	/* write the info sector, if any */
479*d5c9a868SElliott Hughes 	if(This->infoSectorLoc && This->infoSectorLoc != MAX32) {
480*d5c9a868SElliott Hughes 		/* initialize info sector */
481*d5c9a868SElliott Hughes 		InfoSector_t *infoSector;
482*d5c9a868SElliott Hughes 		infoSector = (InfoSector_t *) safe_malloc(This->sector_size);
483*d5c9a868SElliott Hughes 		if(forceReadSector(This, (char *)infoSector,
484*d5c9a868SElliott Hughes 				   This->infoSectorLoc, 1) !=
485*d5c9a868SElliott Hughes 		   (signed int) This->sector_size) {
486*d5c9a868SElliott Hughes 			fprintf(stderr,"Trouble reading the info sector\n");
487*d5c9a868SElliott Hughes 			memset(infoSector->filler1, 0, sizeof(infoSector->filler1));
488*d5c9a868SElliott Hughes 			memset(infoSector->filler2, 0, sizeof(infoSector->filler2));
489*d5c9a868SElliott Hughes 		}
490*d5c9a868SElliott Hughes 		set_dword(infoSector->signature1, INFOSECT_SIGNATURE1);
491*d5c9a868SElliott Hughes 		set_dword(infoSector->signature2, INFOSECT_SIGNATURE2);
492*d5c9a868SElliott Hughes 		set_dword(infoSector->pos, This->last);
493*d5c9a868SElliott Hughes 		set_dword(infoSector->count, This->freeSpace);
494*d5c9a868SElliott Hughes 		set_word(infoSector->signature3, 0xaa55);
495*d5c9a868SElliott Hughes 		if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) !=
496*d5c9a868SElliott Hughes 		   (signed int) This->sector_size)
497*d5c9a868SElliott Hughes 			fprintf(stderr,"Trouble writing the info sector\n");
498*d5c9a868SElliott Hughes 		free(infoSector);
499*d5c9a868SElliott Hughes 	}
500*d5c9a868SElliott Hughes 	This->fat_dirty = 0;
501*d5c9a868SElliott Hughes 	This->lastFatAccessMode = FAT_ACCESS_READ;
502*d5c9a868SElliott Hughes }
503*d5c9a868SElliott Hughes 
504*d5c9a868SElliott Hughes 
505*d5c9a868SElliott Hughes 
506*d5c9a868SElliott Hughes /*
507*d5c9a868SElliott Hughes  * Zero-Fat
508*d5c9a868SElliott Hughes  * Used by mformat.
509*d5c9a868SElliott Hughes  */
zero_fat(Fs_t * Stream,uint8_t media_descriptor)510*d5c9a868SElliott Hughes int zero_fat(Fs_t *Stream, uint8_t media_descriptor)
511*d5c9a868SElliott Hughes {
512*d5c9a868SElliott Hughes 	unsigned int i, j;
513*d5c9a868SElliott Hughes 	unsigned int fat_start;
514*d5c9a868SElliott Hughes 	unsigned char *buf;
515*d5c9a868SElliott Hughes 
516*d5c9a868SElliott Hughes 	buf = malloc(Stream->sector_size);
517*d5c9a868SElliott Hughes 	if(!buf) {
518*d5c9a868SElliott Hughes 		perror("alloc fat sector buffer");
519*d5c9a868SElliott Hughes 		return -1;
520*d5c9a868SElliott Hughes 	}
521*d5c9a868SElliott Hughes 	for(i=0; i< Stream->num_fat; i++) {
522*d5c9a868SElliott Hughes 		fat_start = Stream->fat_start + i*Stream->fat_len;
523*d5c9a868SElliott Hughes 		for(j = 0; j < Stream->fat_len; j++) {
524*d5c9a868SElliott Hughes 			if(j <= 1)
525*d5c9a868SElliott Hughes 				memset(buf, 0, Stream->sector_size);
526*d5c9a868SElliott Hughes 			if(!j) {
527*d5c9a868SElliott Hughes 				buf[0] = media_descriptor;
528*d5c9a868SElliott Hughes 				buf[2] = buf[1] = 0xff;
529*d5c9a868SElliott Hughes 				if(Stream->fat_bits > 12)
530*d5c9a868SElliott Hughes 					buf[3] = 0xff;
531*d5c9a868SElliott Hughes 				if(Stream->fat_bits > 16) {
532*d5c9a868SElliott Hughes 					buf[4] = 0xff;
533*d5c9a868SElliott Hughes 					buf[5] = 0xff;
534*d5c9a868SElliott Hughes 					buf[6] = 0xff;
535*d5c9a868SElliott Hughes 					buf[7] = 0x0f;
536*d5c9a868SElliott Hughes 				}
537*d5c9a868SElliott Hughes 			}
538*d5c9a868SElliott Hughes 
539*d5c9a868SElliott Hughes 			if(forceWriteSector(Stream, (char *)buf,
540*d5c9a868SElliott Hughes 					    fat_start + j, 1) !=
541*d5c9a868SElliott Hughes 			   (signed int) Stream->sector_size) {
542*d5c9a868SElliott Hughes 				fprintf(stderr,
543*d5c9a868SElliott Hughes 					"Trouble initializing a FAT sector\n");
544*d5c9a868SElliott Hughes 				free(buf);
545*d5c9a868SElliott Hughes 				return -1;
546*d5c9a868SElliott Hughes 			}
547*d5c9a868SElliott Hughes 		}
548*d5c9a868SElliott Hughes 	}
549*d5c9a868SElliott Hughes 
550*d5c9a868SElliott Hughes 	free(buf);
551*d5c9a868SElliott Hughes 	Stream->FatMap = GetFatMap(Stream);
552*d5c9a868SElliott Hughes 	if (Stream->FatMap == NULL) {
553*d5c9a868SElliott Hughes 		perror("alloc fat map");
554*d5c9a868SElliott Hughes 		return -1;
555*d5c9a868SElliott Hughes 	}
556*d5c9a868SElliott Hughes 	return 0;
557*d5c9a868SElliott Hughes }
558*d5c9a868SElliott Hughes 
559*d5c9a868SElliott Hughes 
set_fat12(Fs_t * This)560*d5c9a868SElliott Hughes static void set_fat12(Fs_t *This)
561*d5c9a868SElliott Hughes {
562*d5c9a868SElliott Hughes 	This->fat_bits = 12;
563*d5c9a868SElliott Hughes 	This->end_fat = 0xfff;
564*d5c9a868SElliott Hughes 	This->last_fat = 0xff6;
565*d5c9a868SElliott Hughes 	This->fat_decode = fat12_decode;
566*d5c9a868SElliott Hughes 	This->fat_encode = fat12_encode;
567*d5c9a868SElliott Hughes }
568*d5c9a868SElliott Hughes 
569*d5c9a868SElliott Hughes static uint16_t word_endian_test = 0x1234;
570*d5c9a868SElliott Hughes 
set_fat16(Fs_t * This)571*d5c9a868SElliott Hughes static void set_fat16(Fs_t *This)
572*d5c9a868SElliott Hughes {
573*d5c9a868SElliott Hughes 	uint8_t *t = (uint8_t *) &word_endian_test;
574*d5c9a868SElliott Hughes 	This->fat_bits = 16;
575*d5c9a868SElliott Hughes 	This->end_fat = 0xffff;
576*d5c9a868SElliott Hughes 	This->last_fat = 0xfff6;
577*d5c9a868SElliott Hughes 
578*d5c9a868SElliott Hughes 	if(t[0] == 0x34 && t[1] == 0x12) {
579*d5c9a868SElliott Hughes 		This->fat_decode = fast_fat16_decode;
580*d5c9a868SElliott Hughes 		This->fat_encode = fast_fat16_encode;
581*d5c9a868SElliott Hughes 	} else {
582*d5c9a868SElliott Hughes 		This->fat_decode = fat16_decode;
583*d5c9a868SElliott Hughes 		This->fat_encode = fat16_encode;
584*d5c9a868SElliott Hughes 	}
585*d5c9a868SElliott Hughes }
586*d5c9a868SElliott Hughes 
587*d5c9a868SElliott Hughes static uint32_t dword_endian_test = 0x12345678;
588*d5c9a868SElliott Hughes 
set_fat32(Fs_t * This)589*d5c9a868SElliott Hughes static void set_fat32(Fs_t *This)
590*d5c9a868SElliott Hughes {
591*d5c9a868SElliott Hughes 	uint8_t *t = (uint8_t *) &dword_endian_test;
592*d5c9a868SElliott Hughes 	This->fat_bits = 32;
593*d5c9a868SElliott Hughes 	This->end_fat = 0xfffffff;
594*d5c9a868SElliott Hughes 	This->last_fat = 0xffffff6;
595*d5c9a868SElliott Hughes 
596*d5c9a868SElliott Hughes 	if(t[0] == 0x78 && t[1] == 0x56 && t[2] == 0x34 && t[3] == 0x12) {
597*d5c9a868SElliott Hughes 		This->fat_decode = fast_fat32_decode;
598*d5c9a868SElliott Hughes 		This->fat_encode = fast_fat32_encode;
599*d5c9a868SElliott Hughes 	} else {
600*d5c9a868SElliott Hughes 		This->fat_decode = fat32_decode;
601*d5c9a868SElliott Hughes 		This->fat_encode = fat32_encode;
602*d5c9a868SElliott Hughes 	}
603*d5c9a868SElliott Hughes }
604*d5c9a868SElliott Hughes 
set_fat(Fs_t * This)605*d5c9a868SElliott Hughes void set_fat(Fs_t *This) {
606*d5c9a868SElliott Hughes 	if(This->num_clus < FAT12)
607*d5c9a868SElliott Hughes 		set_fat12(This);
608*d5c9a868SElliott Hughes 	else if(This->num_clus < FAT16)
609*d5c9a868SElliott Hughes 		set_fat16(This);
610*d5c9a868SElliott Hughes 	else
611*d5c9a868SElliott Hughes 		set_fat32(This);
612*d5c9a868SElliott Hughes }
613*d5c9a868SElliott Hughes 
check_fat(Fs_t * This)614*d5c9a868SElliott Hughes static int check_fat(Fs_t *This)
615*d5c9a868SElliott Hughes {
616*d5c9a868SElliott Hughes 	/*
617*d5c9a868SElliott Hughes 	 * This is only a sanity check.  For disks with really big FATs,
618*d5c9a868SElliott Hughes 	 * there is no point in checking the whole FAT.
619*d5c9a868SElliott Hughes 	 */
620*d5c9a868SElliott Hughes 
621*d5c9a868SElliott Hughes 	unsigned int i, f;
622*d5c9a868SElliott Hughes 	unsigned int tocheck;
623*d5c9a868SElliott Hughes 	if(mtools_skip_check)
624*d5c9a868SElliott Hughes 		return 0;
625*d5c9a868SElliott Hughes 
626*d5c9a868SElliott Hughes 	/* too few sectors in the FAT */
627*d5c9a868SElliott Hughes 	if(This->fat_len < NEEDED_FAT_SIZE(This)) {
628*d5c9a868SElliott Hughes 		fprintf(stderr, "Too few sectors in FAT\n");
629*d5c9a868SElliott Hughes 		return -1;
630*d5c9a868SElliott Hughes 	}
631*d5c9a868SElliott Hughes 	/* we do not warn about too much sectors in FAT, which may
632*d5c9a868SElliott Hughes 	 * happen when a partition has been shrunk using FIPS, or on
633*d5c9a868SElliott Hughes 	 * other occurrences */
634*d5c9a868SElliott Hughes 
635*d5c9a868SElliott Hughes 	tocheck = This->num_clus;
636*d5c9a868SElliott Hughes 	if (tocheck + 1 >= This->last_fat) {
637*d5c9a868SElliott Hughes 		fprintf(stderr, "Too many clusters in FAT\n");
638*d5c9a868SElliott Hughes 		return -1;
639*d5c9a868SElliott Hughes 	}
640*d5c9a868SElliott Hughes 
641*d5c9a868SElliott Hughes 	if(tocheck > 4096)
642*d5c9a868SElliott Hughes 		tocheck = 4096;
643*d5c9a868SElliott Hughes 
644*d5c9a868SElliott Hughes 	for ( i= 3 ; i < tocheck; i++){
645*d5c9a868SElliott Hughes 		f = This->fat_decode(This,i);
646*d5c9a868SElliott Hughes 		if (f == 1 || (f < This->last_fat && f > This->num_clus)){
647*d5c9a868SElliott Hughes 			fprintf(stderr,
648*d5c9a868SElliott Hughes 				"Cluster # at %d too big(%#x)\n", i,f);
649*d5c9a868SElliott Hughes 			fprintf(stderr,"Probably non MS-DOS disk\n");
650*d5c9a868SElliott Hughes 			return -1;
651*d5c9a868SElliott Hughes 		}
652*d5c9a868SElliott Hughes 	}
653*d5c9a868SElliott Hughes 	return 0;
654*d5c9a868SElliott Hughes }
655*d5c9a868SElliott Hughes 
656*d5c9a868SElliott Hughes 
657*d5c9a868SElliott Hughes /*
658*d5c9a868SElliott Hughes  * Read the first sector of FAT table into memory.  Crude error detection on
659*d5c9a868SElliott Hughes  * wrong FAT encoding scheme.
660*d5c9a868SElliott Hughes  */
check_media_type(Fs_t * This,union bootsector * boot)661*d5c9a868SElliott Hughes static int check_media_type(Fs_t *This, union bootsector *boot)
662*d5c9a868SElliott Hughes {
663*d5c9a868SElliott Hughes 	unsigned char *address;
664*d5c9a868SElliott Hughes 
665*d5c9a868SElliott Hughes 	This->FatMap = GetFatMap(This);
666*d5c9a868SElliott Hughes 	if (This->FatMap == NULL) {
667*d5c9a868SElliott Hughes 		perror("alloc fat map");
668*d5c9a868SElliott Hughes 		return -1;
669*d5c9a868SElliott Hughes 	}
670*d5c9a868SElliott Hughes 
671*d5c9a868SElliott Hughes 	address = getAddress(This, 0, FAT_ACCESS_READ);
672*d5c9a868SElliott Hughes 	if(!address) {
673*d5c9a868SElliott Hughes 		fprintf(stderr,
674*d5c9a868SElliott Hughes 			"Could not read first FAT sector\n");
675*d5c9a868SElliott Hughes 		return -1;
676*d5c9a868SElliott Hughes 	}
677*d5c9a868SElliott Hughes 
678*d5c9a868SElliott Hughes 	if(mtools_skip_check)
679*d5c9a868SElliott Hughes 		return 0;
680*d5c9a868SElliott Hughes 
681*d5c9a868SElliott Hughes 	if(!address[0] && !address[1] && !address[2])
682*d5c9a868SElliott Hughes 		/* Some Atari disks have zeroes where Dos has media descriptor
683*d5c9a868SElliott Hughes 		 * and 0xff.  Do not consider this as an error */
684*d5c9a868SElliott Hughes 		return 0;
685*d5c9a868SElliott Hughes 
686*d5c9a868SElliott Hughes 	if((address[0] != boot->boot.descr && boot->boot.descr >= 0xf0 &&
687*d5c9a868SElliott Hughes 	    ((address[0] != 0xf9 && address[0] != 0xf7)
688*d5c9a868SElliott Hughes 	     || boot->boot.descr != 0xf0)) || address[0] < 0xf0) {
689*d5c9a868SElliott Hughes 		fprintf(stderr,
690*d5c9a868SElliott Hughes 			"Bad media types %02x/%02x, probably non-MSDOS disk\n",
691*d5c9a868SElliott Hughes 				address[0],
692*d5c9a868SElliott Hughes 				boot->boot.descr);
693*d5c9a868SElliott Hughes 		return -1;
694*d5c9a868SElliott Hughes 	}
695*d5c9a868SElliott Hughes 
696*d5c9a868SElliott Hughes 	if(address[1] != 0xff || address[2] != 0xff){
697*d5c9a868SElliott Hughes 		fprintf(stderr,"Initial bytes of fat is not 0xff\n");
698*d5c9a868SElliott Hughes 		return -1;
699*d5c9a868SElliott Hughes 	}
700*d5c9a868SElliott Hughes 
701*d5c9a868SElliott Hughes 	return 0;
702*d5c9a868SElliott Hughes }
703*d5c9a868SElliott Hughes 
fat_32_read(Fs_t * This,union bootsector * boot)704*d5c9a868SElliott Hughes static int fat_32_read(Fs_t *This, union bootsector *boot)
705*d5c9a868SElliott Hughes {
706*d5c9a868SElliott Hughes 	size_t size;
707*d5c9a868SElliott Hughes 
708*d5c9a868SElliott Hughes 	This->fat_len = DWORD(ext.fat32.bigFat);
709*d5c9a868SElliott Hughes 	This->writeAllFats = !(boot->boot.ext.fat32.extFlags[0] & 0x80);
710*d5c9a868SElliott Hughes 	This->primaryFat = boot->boot.ext.fat32.extFlags[0] & 0xf;
711*d5c9a868SElliott Hughes 	This->rootCluster = DWORD(ext.fat32.rootCluster);
712*d5c9a868SElliott Hughes 	This->clus_start = This->fat_start + This->num_fat * This->fat_len;
713*d5c9a868SElliott Hughes 
714*d5c9a868SElliott Hughes 	/* read the info sector */
715*d5c9a868SElliott Hughes 	size = This->sector_size;
716*d5c9a868SElliott Hughes 	This->infoSectorLoc = WORD(ext.fat32.infoSector);
717*d5c9a868SElliott Hughes 	if(This->sector_size >= 512 &&
718*d5c9a868SElliott Hughes 	   This->infoSectorLoc && This->infoSectorLoc != MAX32) {
719*d5c9a868SElliott Hughes 		InfoSector_t *infoSector;
720*d5c9a868SElliott Hughes 		infoSector = (InfoSector_t *) safe_malloc(size);
721*d5c9a868SElliott Hughes 		if(forceReadSector(This, (char *)infoSector,
722*d5c9a868SElliott Hughes 				   This->infoSectorLoc, 1) ==
723*d5c9a868SElliott Hughes 		   (signed int) This->sector_size &&
724*d5c9a868SElliott Hughes 		   _DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1 &&
725*d5c9a868SElliott Hughes 		   _DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2) {
726*d5c9a868SElliott Hughes 			This->freeSpace = _DWORD(infoSector->count);
727*d5c9a868SElliott Hughes 			This->last = _DWORD(infoSector->pos);
728*d5c9a868SElliott Hughes 		}
729*d5c9a868SElliott Hughes 		free(infoSector);
730*d5c9a868SElliott Hughes 	}
731*d5c9a868SElliott Hughes 
732*d5c9a868SElliott Hughes 	return(check_media_type(This, boot) || check_fat(This));
733*d5c9a868SElliott Hughes }
734*d5c9a868SElliott Hughes 
735*d5c9a868SElliott Hughes 
old_fat_read(Fs_t * This,union bootsector * boot,int nodups)736*d5c9a868SElliott Hughes static int old_fat_read(Fs_t *This, union bootsector *boot, int nodups)
737*d5c9a868SElliott Hughes {
738*d5c9a868SElliott Hughes 	This->writeAllFats = 1;
739*d5c9a868SElliott Hughes 	This->primaryFat = 0;
740*d5c9a868SElliott Hughes 	This->dir_start = This->fat_start + This->num_fat * This->fat_len;
741*d5c9a868SElliott Hughes 	This->infoSectorLoc = MAX32;
742*d5c9a868SElliott Hughes 
743*d5c9a868SElliott Hughes 	if(nodups)
744*d5c9a868SElliott Hughes 		This->num_fat = 1;
745*d5c9a868SElliott Hughes 
746*d5c9a868SElliott Hughes 	if(check_media_type(This, boot))
747*d5c9a868SElliott Hughes 		return -1;
748*d5c9a868SElliott Hughes 
749*d5c9a868SElliott Hughes 	if(This->num_clus >= FAT12)
750*d5c9a868SElliott Hughes 		/* third FAT byte must be 0xff */
751*d5c9a868SElliott Hughes 		if(!mtools_skip_check && readByte(This, 3) != 0xff)
752*d5c9a868SElliott Hughes 			return -1;
753*d5c9a868SElliott Hughes 
754*d5c9a868SElliott Hughes 	return check_fat(This);
755*d5c9a868SElliott Hughes }
756*d5c9a868SElliott Hughes 
757*d5c9a868SElliott Hughes /*
758*d5c9a868SElliott Hughes  * Read the first sector of the  FAT table into memory and initialize
759*d5c9a868SElliott Hughes  * structures.
760*d5c9a868SElliott Hughes  */
fat_read(Fs_t * This,union bootsector * boot,int nodups)761*d5c9a868SElliott Hughes int fat_read(Fs_t *This, union bootsector *boot, int nodups)
762*d5c9a868SElliott Hughes {
763*d5c9a868SElliott Hughes 	This->fat_error = 0;
764*d5c9a868SElliott Hughes 	This->fat_dirty = 0;
765*d5c9a868SElliott Hughes 	This->last = MAX32;
766*d5c9a868SElliott Hughes 	This->freeSpace = MAX32;
767*d5c9a868SElliott Hughes 	This->lastFatSectorNr = 0;
768*d5c9a868SElliott Hughes 	This->lastFatSectorData = 0;
769*d5c9a868SElliott Hughes 
770*d5c9a868SElliott Hughes 	if(This->num_clus < FAT16)
771*d5c9a868SElliott Hughes 		return old_fat_read(This, boot, nodups);
772*d5c9a868SElliott Hughes 	else
773*d5c9a868SElliott Hughes 		return fat_32_read(This, boot);
774*d5c9a868SElliott Hughes }
775*d5c9a868SElliott Hughes 
776*d5c9a868SElliott Hughes 
fatDecode(Fs_t * This,unsigned int pos)777*d5c9a868SElliott Hughes unsigned int fatDecode(Fs_t *This, unsigned int pos)
778*d5c9a868SElliott Hughes {
779*d5c9a868SElliott Hughes 	unsigned int ret;
780*d5c9a868SElliott Hughes 
781*d5c9a868SElliott Hughes 	ret = This->fat_decode(This, pos);
782*d5c9a868SElliott Hughes 	if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) {
783*d5c9a868SElliott Hughes 		fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos);
784*d5c9a868SElliott Hughes 		This->fat_error++;
785*d5c9a868SElliott Hughes 	}
786*d5c9a868SElliott Hughes 	return ret;
787*d5c9a868SElliott Hughes }
788*d5c9a868SElliott Hughes 
789*d5c9a868SElliott Hughes /* append a new cluster */
fatAppend(Fs_t * This,unsigned int pos,unsigned int newpos)790*d5c9a868SElliott Hughes void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos)
791*d5c9a868SElliott Hughes {
792*d5c9a868SElliott Hughes 	This->fat_encode(This, pos, newpos);
793*d5c9a868SElliott Hughes 	This->fat_encode(This, newpos, This->end_fat);
794*d5c9a868SElliott Hughes 	if(This->freeSpace != MAX32)
795*d5c9a868SElliott Hughes 		This->freeSpace--;
796*d5c9a868SElliott Hughes }
797*d5c9a868SElliott Hughes 
798*d5c9a868SElliott Hughes /* de-allocates the given cluster */
fatDeallocate(Fs_t * This,unsigned int pos)799*d5c9a868SElliott Hughes void fatDeallocate(Fs_t *This, unsigned int pos)
800*d5c9a868SElliott Hughes {
801*d5c9a868SElliott Hughes 	This->fat_encode(This, pos, 0);
802*d5c9a868SElliott Hughes 	if(This->freeSpace != MAX32)
803*d5c9a868SElliott Hughes 		This->freeSpace++;
804*d5c9a868SElliott Hughes }
805*d5c9a868SElliott Hughes 
806*d5c9a868SElliott Hughes /* allocate a new cluster */
fatAllocate(Fs_t * This,unsigned int pos,unsigned int value)807*d5c9a868SElliott Hughes void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value)
808*d5c9a868SElliott Hughes {
809*d5c9a868SElliott Hughes 	This->fat_encode(This, pos, value);
810*d5c9a868SElliott Hughes 	if(This->freeSpace != MAX32)
811*d5c9a868SElliott Hughes 		This->freeSpace--;
812*d5c9a868SElliott Hughes }
813*d5c9a868SElliott Hughes 
fatEncode(Fs_t * This,unsigned int pos,unsigned int value)814*d5c9a868SElliott Hughes void fatEncode(Fs_t *This, unsigned int pos, unsigned int value)
815*d5c9a868SElliott Hughes {
816*d5c9a868SElliott Hughes 	unsigned int oldvalue = This->fat_decode(This, pos);
817*d5c9a868SElliott Hughes 	This->fat_encode(This, pos, value);
818*d5c9a868SElliott Hughes 	if(This->freeSpace != MAX32) {
819*d5c9a868SElliott Hughes 		if(oldvalue)
820*d5c9a868SElliott Hughes 			This->freeSpace++;
821*d5c9a868SElliott Hughes 		if(value)
822*d5c9a868SElliott Hughes 			This->freeSpace--;
823*d5c9a868SElliott Hughes 	}
824*d5c9a868SElliott Hughes }
825*d5c9a868SElliott Hughes 
get_next_free_cluster(Fs_t * This,unsigned int last)826*d5c9a868SElliott Hughes unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
827*d5c9a868SElliott Hughes {
828*d5c9a868SElliott Hughes 	unsigned int i;
829*d5c9a868SElliott Hughes 
830*d5c9a868SElliott Hughes 	if(This->last != MAX32)
831*d5c9a868SElliott Hughes 		last = This->last;
832*d5c9a868SElliott Hughes 
833*d5c9a868SElliott Hughes 	if (last < 2 ||
834*d5c9a868SElliott Hughes 	    last >= This->num_clus+1)
835*d5c9a868SElliott Hughes 		last = 1;
836*d5c9a868SElliott Hughes 
837*d5c9a868SElliott Hughes 	for (i=last+1; i< This->num_clus+2; i++) {
838*d5c9a868SElliott Hughes 		unsigned int r = fatDecode(This, i);
839*d5c9a868SElliott Hughes 		if(r == 1)
840*d5c9a868SElliott Hughes 			goto exit_0;
841*d5c9a868SElliott Hughes 		if (!r) {
842*d5c9a868SElliott Hughes 			This->last = i;
843*d5c9a868SElliott Hughes 			return i;
844*d5c9a868SElliott Hughes 		}
845*d5c9a868SElliott Hughes 	}
846*d5c9a868SElliott Hughes 
847*d5c9a868SElliott Hughes 	for(i=2; i < last+1; i++) {
848*d5c9a868SElliott Hughes 		unsigned int r = fatDecode(This, i);
849*d5c9a868SElliott Hughes 		if(r == 1)
850*d5c9a868SElliott Hughes 			goto exit_0;
851*d5c9a868SElliott Hughes 		if (!r) {
852*d5c9a868SElliott Hughes 			This->last = i;
853*d5c9a868SElliott Hughes 			return i;
854*d5c9a868SElliott Hughes 		}
855*d5c9a868SElliott Hughes 	}
856*d5c9a868SElliott Hughes 
857*d5c9a868SElliott Hughes 
858*d5c9a868SElliott Hughes 	fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters,
859*d5c9a868SElliott Hughes 		This->last);
860*d5c9a868SElliott Hughes 	return 1;
861*d5c9a868SElliott Hughes  exit_0:
862*d5c9a868SElliott Hughes 	fprintf(stderr, "FAT error\n");
863*d5c9a868SElliott Hughes 	return 1;
864*d5c9a868SElliott Hughes }
865*d5c9a868SElliott Hughes 
getSerialized(Fs_t * Fs)866*d5c9a868SElliott Hughes bool getSerialized(Fs_t *Fs) {
867*d5c9a868SElliott Hughes 	return Fs->serialized;
868*d5c9a868SElliott Hughes }
869*d5c9a868SElliott Hughes 
getSerialNumber(Fs_t * Fs)870*d5c9a868SElliott Hughes unsigned long getSerialNumber(Fs_t *Fs) {
871*d5c9a868SElliott Hughes 	return Fs->serial_number;
872*d5c9a868SElliott Hughes }
873*d5c9a868SElliott Hughes 
getClusterBytes(Fs_t * Fs)874*d5c9a868SElliott Hughes uint32_t getClusterBytes(Fs_t *Fs) {
875*d5c9a868SElliott Hughes 	return Fs->cluster_size * Fs->sector_size;
876*d5c9a868SElliott Hughes }
877*d5c9a868SElliott Hughes 
fat_error(Stream_t * Dir)878*d5c9a868SElliott Hughes int fat_error(Stream_t *Dir)
879*d5c9a868SElliott Hughes {
880*d5c9a868SElliott Hughes 	Stream_t *Stream = GetFs(Dir);
881*d5c9a868SElliott Hughes 	DeclareThis(Fs_t);
882*d5c9a868SElliott Hughes 
883*d5c9a868SElliott Hughes 	if(This->fat_error)
884*d5c9a868SElliott Hughes 		fprintf(stderr,"Fat error detected\n");
885*d5c9a868SElliott Hughes 
886*d5c9a868SElliott Hughes 	return This->fat_error;
887*d5c9a868SElliott Hughes }
888*d5c9a868SElliott Hughes 
fat32RootCluster(Stream_t * Dir)889*d5c9a868SElliott Hughes uint32_t fat32RootCluster(Stream_t *Dir)
890*d5c9a868SElliott Hughes {
891*d5c9a868SElliott Hughes 	Stream_t *Stream = GetFs(Dir);
892*d5c9a868SElliott Hughes 	DeclareThis(Fs_t);
893*d5c9a868SElliott Hughes 
894*d5c9a868SElliott Hughes 	if(This->fat_bits == 32)
895*d5c9a868SElliott Hughes 		return This->rootCluster;
896*d5c9a868SElliott Hughes 	else
897*d5c9a868SElliott Hughes 		return 0;
898*d5c9a868SElliott Hughes }
899*d5c9a868SElliott Hughes 
900*d5c9a868SElliott Hughes 
901*d5c9a868SElliott Hughes /*
902*d5c9a868SElliott Hughes  * Get the amount of free space on the diskette
903*d5c9a868SElliott Hughes  */
getfree(Stream_t * Dir)904*d5c9a868SElliott Hughes mt_off_t getfree(Stream_t *Dir)
905*d5c9a868SElliott Hughes {
906*d5c9a868SElliott Hughes 	Stream_t *Stream = GetFs(Dir);
907*d5c9a868SElliott Hughes 	DeclareThis(Fs_t);
908*d5c9a868SElliott Hughes 
909*d5c9a868SElliott Hughes 	if(This->freeSpace == MAX32 || This->freeSpace == 0) {
910*d5c9a868SElliott Hughes 		register unsigned int i;
911*d5c9a868SElliott Hughes 		uint32_t total;
912*d5c9a868SElliott Hughes 
913*d5c9a868SElliott Hughes 		total = 0L;
914*d5c9a868SElliott Hughes 		for (i = 2; i < This->num_clus + 2; i++) {
915*d5c9a868SElliott Hughes 			unsigned int r = fatDecode(This,i);
916*d5c9a868SElliott Hughes 			if(r == 1) {
917*d5c9a868SElliott Hughes 				return -1;
918*d5c9a868SElliott Hughes 			}
919*d5c9a868SElliott Hughes 			if (!r)
920*d5c9a868SElliott Hughes 				total++;
921*d5c9a868SElliott Hughes 		}
922*d5c9a868SElliott Hughes 		This->freeSpace = total;
923*d5c9a868SElliott Hughes 	}
924*d5c9a868SElliott Hughes 	return sectorsToBytes(This,
925*d5c9a868SElliott Hughes 			      This->freeSpace * This->cluster_size);
926*d5c9a868SElliott Hughes }
927*d5c9a868SElliott Hughes 
928*d5c9a868SElliott Hughes 
929*d5c9a868SElliott Hughes /*
930*d5c9a868SElliott Hughes  * Ensure that there is a minimum of total sectors free
931*d5c9a868SElliott Hughes  */
getfreeMinClusters(Stream_t * Dir,uint32_t size)932*d5c9a868SElliott Hughes int getfreeMinClusters(Stream_t *Dir, uint32_t size)
933*d5c9a868SElliott Hughes {
934*d5c9a868SElliott Hughes 	Stream_t *Stream = GetFs(Dir);
935*d5c9a868SElliott Hughes 	DeclareThis(Fs_t);
936*d5c9a868SElliott Hughes 	register unsigned int i, last;
937*d5c9a868SElliott Hughes 	size_t total;
938*d5c9a868SElliott Hughes 
939*d5c9a868SElliott Hughes 	if(batchmode && This->freeSpace == MAX32)
940*d5c9a868SElliott Hughes 		getfree(Stream);
941*d5c9a868SElliott Hughes 
942*d5c9a868SElliott Hughes 	if(This->freeSpace != MAX32) {
943*d5c9a868SElliott Hughes 		if(This->freeSpace >= size)
944*d5c9a868SElliott Hughes 			return 1;
945*d5c9a868SElliott Hughes 		else {
946*d5c9a868SElliott Hughes 			fprintf(stderr, "Disk full\n");
947*d5c9a868SElliott Hughes 			got_signal = 1;
948*d5c9a868SElliott Hughes 			return 0;
949*d5c9a868SElliott Hughes 		}
950*d5c9a868SElliott Hughes 	}
951*d5c9a868SElliott Hughes 
952*d5c9a868SElliott Hughes 	total = 0L;
953*d5c9a868SElliott Hughes 
954*d5c9a868SElliott Hughes 	/* we start at the same place where we'll start later to actually
955*d5c9a868SElliott Hughes 	 * allocate the sectors.  That way, the same sectors of the FAT, which
956*d5c9a868SElliott Hughes 	 * are already loaded during getfreeMin will be able to be reused
957*d5c9a868SElliott Hughes 	 * during get_next_free_cluster */
958*d5c9a868SElliott Hughes 	last = This->last;
959*d5c9a868SElliott Hughes 
960*d5c9a868SElliott Hughes 	if ( last < 2 || last >= This->num_clus + 2)
961*d5c9a868SElliott Hughes 		last = 1;
962*d5c9a868SElliott Hughes 	for (i=last+1; i< This->num_clus+2; i++){
963*d5c9a868SElliott Hughes 		unsigned int r = fatDecode(This, i);
964*d5c9a868SElliott Hughes 		if(r == 1) {
965*d5c9a868SElliott Hughes 			goto exit_0;
966*d5c9a868SElliott Hughes 		}
967*d5c9a868SElliott Hughes 		if (!r)
968*d5c9a868SElliott Hughes 			total++;
969*d5c9a868SElliott Hughes 		if(total >= size)
970*d5c9a868SElliott Hughes 			return 1;
971*d5c9a868SElliott Hughes 	}
972*d5c9a868SElliott Hughes 	for(i=2; i < last+1; i++){
973*d5c9a868SElliott Hughes 		unsigned int r = fatDecode(This, i);
974*d5c9a868SElliott Hughes 		if(r == 1) {
975*d5c9a868SElliott Hughes 			goto exit_0;
976*d5c9a868SElliott Hughes 		}
977*d5c9a868SElliott Hughes 		if (!r)
978*d5c9a868SElliott Hughes 			total++;
979*d5c9a868SElliott Hughes 		if(total >= size)
980*d5c9a868SElliott Hughes 			return 1;
981*d5c9a868SElliott Hughes 	}
982*d5c9a868SElliott Hughes 	fprintf(stderr, "Disk full\n");
983*d5c9a868SElliott Hughes 	got_signal = 1;
984*d5c9a868SElliott Hughes 	return 0;
985*d5c9a868SElliott Hughes  exit_0:
986*d5c9a868SElliott Hughes 	fprintf(stderr, "FAT error\n");
987*d5c9a868SElliott Hughes 	return 0;
988*d5c9a868SElliott Hughes }
989*d5c9a868SElliott Hughes 
990*d5c9a868SElliott Hughes 
getfreeMinBytes(Stream_t * Dir,mt_off_t size)991*d5c9a868SElliott Hughes int getfreeMinBytes(Stream_t *Dir, mt_off_t size)
992*d5c9a868SElliott Hughes {
993*d5c9a868SElliott Hughes 	Stream_t *Stream = GetFs(Dir);
994*d5c9a868SElliott Hughes 	DeclareThis(Fs_t);
995*d5c9a868SElliott Hughes 	mt_off_t size2;
996*d5c9a868SElliott Hughes 
997*d5c9a868SElliott Hughes 	size2 = size  / (This->sector_size * This->cluster_size);
998*d5c9a868SElliott Hughes 	if(size % (This->sector_size * This->cluster_size))
999*d5c9a868SElliott Hughes 		size2++;
1000*d5c9a868SElliott Hughes 	if((smt_off_t)size2 > UINT32_MAX) {
1001*d5c9a868SElliott Hughes 		fprintf(stderr, "Requested size too big\n");
1002*d5c9a868SElliott Hughes 		exit(1);
1003*d5c9a868SElliott Hughes 	}
1004*d5c9a868SElliott Hughes 	return getfreeMinClusters(Dir, (uint32_t) size2);
1005*d5c9a868SElliott Hughes }
1006*d5c9a868SElliott Hughes 
1007*d5c9a868SElliott Hughes 
getStart(Stream_t * Dir,struct directory * dir)1008*d5c9a868SElliott Hughes uint32_t getStart(Stream_t *Dir, struct directory *dir)
1009*d5c9a868SElliott Hughes {
1010*d5c9a868SElliott Hughes 	Stream_t *Stream = GetFs(Dir);
1011*d5c9a868SElliott Hughes 	uint32_t first;
1012*d5c9a868SElliott Hughes 
1013*d5c9a868SElliott Hughes 	first = START(dir);
1014*d5c9a868SElliott Hughes 	if(fat32RootCluster(Stream)) {
1015*d5c9a868SElliott Hughes 		first |=  (uint32_t) STARTHI(dir) << 16;
1016*d5c9a868SElliott Hughes 	}
1017*d5c9a868SElliott Hughes 	return first;
1018*d5c9a868SElliott Hughes }
1019*d5c9a868SElliott Hughes 
fs_free(Stream_t * Stream)1020*d5c9a868SElliott Hughes int fs_free(Stream_t *Stream)
1021*d5c9a868SElliott Hughes {
1022*d5c9a868SElliott Hughes 	DeclareThis(Fs_t);
1023*d5c9a868SElliott Hughes 
1024*d5c9a868SElliott Hughes 	if(This->FatMap) {
1025*d5c9a868SElliott Hughes 		int i, nr_entries;
1026*d5c9a868SElliott Hughes 		nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) /
1027*d5c9a868SElliott Hughes 			SECT_PER_ENTRY;
1028*d5c9a868SElliott Hughes 		for(i=0; i< nr_entries; i++)
1029*d5c9a868SElliott Hughes 			if(This->FatMap[i].data)
1030*d5c9a868SElliott Hughes 				free(This->FatMap[i].data);
1031*d5c9a868SElliott Hughes 		free(This->FatMap);
1032*d5c9a868SElliott Hughes 	}
1033*d5c9a868SElliott Hughes 	if(This->cp)
1034*d5c9a868SElliott Hughes 		cp_close(This->cp);
1035*d5c9a868SElliott Hughes 	return 0;
1036*d5c9a868SElliott Hughes }
1037