Multivolume: prevent file rename attempts across volumes.
[kugel-rb.git] / firmware / drivers / fat.c
blob85bd525eff50a8296b32728ffd44d6be6ff84b35
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <stdbool.h>
24 #include "fat.h"
25 #include "ata.h"
26 #include "debug.h"
27 #include "panic.h"
28 #include "system.h"
29 #include "timefuncs.h"
30 #include "kernel.h"
32 #define BYTES2INT16(array,pos) \
33 (array[pos] | (array[pos+1] << 8 ))
34 #define BYTES2INT32(array,pos) \
35 (array[pos] | (array[pos+1] << 8 ) | \
36 (array[pos+2] << 16 ) | (array[pos+3] << 24 ))
38 #define FATTYPE_FAT12 0
39 #define FATTYPE_FAT16 1
40 #define FATTYPE_FAT32 2
42 /* BPB offsets; generic */
43 #define BS_JMPBOOT 0
44 #define BS_OEMNAME 3
45 #define BPB_BYTSPERSEC 11
46 #define BPB_SECPERCLUS 13
47 #define BPB_RSVDSECCNT 14
48 #define BPB_NUMFATS 16
49 #define BPB_ROOTENTCNT 17
50 #define BPB_TOTSEC16 19
51 #define BPB_MEDIA 21
52 #define BPB_FATSZ16 22
53 #define BPB_SECPERTRK 24
54 #define BPB_NUMHEADS 26
55 #define BPB_HIDDSEC 28
56 #define BPB_TOTSEC32 32
58 /* fat12/16 */
59 #define BS_DRVNUM 36
60 #define BS_RESERVED1 37
61 #define BS_BOOTSIG 38
62 #define BS_VOLID 39
63 #define BS_VOLLAB 43
64 #define BS_FILSYSTYPE 54
66 /* fat32 */
67 #define BPB_FATSZ32 36
68 #define BPB_EXTFLAGS 40
69 #define BPB_FSVER 42
70 #define BPB_ROOTCLUS 44
71 #define BPB_FSINFO 48
72 #define BPB_BKBOOTSEC 50
73 #define BS_32_DRVNUM 64
74 #define BS_32_BOOTSIG 66
75 #define BS_32_VOLID 67
76 #define BS_32_VOLLAB 71
77 #define BS_32_FILSYSTYPE 82
79 #define BPB_LAST_WORD 510
82 /* attributes */
83 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
84 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
85 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
86 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
87 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
89 #define FATDIR_NAME 0
90 #define FATDIR_ATTR 11
91 #define FATDIR_NTRES 12
92 #define FATDIR_CRTTIMETENTH 13
93 #define FATDIR_CRTTIME 14
94 #define FATDIR_CRTDATE 16
95 #define FATDIR_LSTACCDATE 18
96 #define FATDIR_FSTCLUSHI 20
97 #define FATDIR_WRTTIME 22
98 #define FATDIR_WRTDATE 24
99 #define FATDIR_FSTCLUSLO 26
100 #define FATDIR_FILESIZE 28
102 #define FATLONG_ORDER 0
103 #define FATLONG_TYPE 12
104 #define FATLONG_CHKSUM 13
106 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
107 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
108 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
109 #define DIR_ENTRY_SIZE 32
110 #define NAME_BYTES_PER_ENTRY 13
111 #define FAT_BAD_MARK 0x0ffffff7
112 #define FAT_EOF_MARK 0x0ffffff8
114 /* filename charset conversion table */
115 static const unsigned char unicode2iso8859_2[] = {
116 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x0100 */
117 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x0108 */
118 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110 */
119 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x0118 */
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120 */
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0128 */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0130 */
123 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x0138 */
124 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x0140 */
125 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0148 */
126 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x0150 */
127 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x0158 */
128 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x0160 */
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x0168 */
130 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0170 */
131 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x0178 */
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180 */
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0188 */
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0190 */
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0198 */
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0 */
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a8 */
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b0 */
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b8 */
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0 */
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c8 */
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d0 */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d8 */
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e0 */
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e8 */
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f0 */
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f8 */
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200 */
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0208 */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0210 */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0218 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0220 */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0228 */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0230 */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0238 */
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240 */
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0248 */
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0250 */
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0258 */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0260 */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0268 */
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0270 */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0278 */
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280 */
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0288 */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0290 */
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0298 */
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a0 */
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a8 */
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b0 */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b8 */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0x02c0 */
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c8 */
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02d0 */
175 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0x02d8 */
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e0 */
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e8 */
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02f0 */
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x02f8 */
182 struct fsinfo {
183 unsigned int freecount; /* last known free cluster count */
184 unsigned int nextfree; /* first cluster to start looking for free
185 clusters, or 0xffffffff for no hint */
187 /* fsinfo offsets */
188 #define FSINFO_FREECOUNT 488
189 #define FSINFO_NEXTFREE 492
191 struct bpb
193 int bpb_bytspersec; /* Bytes per sector, typically 512 */
194 unsigned int bpb_secperclus; /* Sectors per cluster */
195 int bpb_rsvdseccnt; /* Number of reserved sectors */
196 int bpb_numfats; /* Number of FAT structures, typically 2 */
197 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
198 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
199 int bpb_fatsz16; /* Number of used sectors per FAT structure */
200 unsigned int bpb_totsec32; /* Number of sectors on the volume
201 (new 32-bit) */
202 int last_word; /* 0xAA55 */
204 /**** FAT32 specific *****/
205 int bpb_fatsz32;
206 int bpb_rootclus;
207 int bpb_fsinfo;
209 /* variables for internal use */
210 unsigned int fatsize;
211 unsigned int totalsectors;
212 unsigned int rootdirsector;
213 unsigned int firstdatasector;
214 unsigned int startsector;
215 unsigned int dataclusters;
216 struct fsinfo fsinfo;
217 #ifdef HAVE_FAT16SUPPORT
218 int bpb_rootentcnt; /* Number of dir entries in the root */
219 /* internals for FAT16 support */
220 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
221 unsigned int rootdiroffset; /* sector offset of root dir relative to start
222 * of first pseudo cluster */
223 #endif /* #ifdef HAVE_FAT16SUPPORT */
224 #ifdef HAVE_MULTIVOLUME
225 int drive; /* on which physical device is this located */
226 bool mounted; /* flag if this volume is mounted */
227 #endif
230 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
232 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
233 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
234 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,) int secnum, bool dirty);
235 static int create_dos_name(const unsigned char *name, unsigned char *newname);
236 static unsigned int find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned int start);
237 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned int start, int count, char* buf, bool write );
239 #define FAT_CACHE_SIZE 0x20
240 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
242 struct fat_cache_entry
244 int secnum;
245 bool inuse;
246 bool dirty;
247 #ifdef HAVE_MULTIVOLUME
248 struct bpb* fat_vol ; /* shared cache for all volumes */
249 #endif
252 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
253 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
254 static struct mutex cache_mutex;
256 static int cluster2sec(IF_MV2(struct bpb* fat_bpb,) int cluster)
258 #ifndef HAVE_MULTIVOLUME
259 struct bpb* fat_bpb = &fat_bpbs[0];
260 #endif
261 #ifdef HAVE_FAT16SUPPORT
262 /* negative clusters (FAT16 root dir) don't get the 2 offset */
263 int zerocluster = cluster < 0 ? 0 : 2;
264 #else
265 const int zerocluster = 2;
266 #endif
267 int max_cluster = fat_bpb->totalsectors -
268 fat_bpb->firstdatasector / fat_bpb->bpb_secperclus + 1;
270 if (cluster > max_cluster)
272 DEBUGF( "cluster2sec() - Bad cluster number (%d)\n", cluster);
273 return -1;
276 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
277 + fat_bpb->firstdatasector;
280 int fat_startsector(IF_MV_NONVOID(int volume))
282 #ifndef HAVE_MULTIVOLUME
283 const int volume = 0;
284 #endif
285 struct bpb* fat_bpb = &fat_bpbs[volume];
286 return fat_bpb->startsector;
289 void fat_size(IF_MV2(int volume,) unsigned int* size, unsigned int* free)
291 #ifndef HAVE_MULTIVOLUME
292 const int volume = 0;
293 #endif
294 struct bpb* fat_bpb = &fat_bpbs[volume];
295 if (size)
296 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
297 if (free)
298 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
301 void fat_init(void)
303 unsigned int i;
305 mutex_init(&cache_mutex);
307 /* mark the FAT cache as unused */
308 for(i = 0;i < FAT_CACHE_SIZE;i++)
310 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
311 fat_cache[i].inuse = false;
312 fat_cache[i].dirty = false;
313 #ifdef HAVE_MULTIVOLUME
314 fat_cache[i].fat_vol = NULL;
315 #endif
317 #ifdef HAVE_MULTIVOLUME
318 /* mark the possible volumes as not mounted */
319 for (i=0; i<NUM_VOLUMES;i++)
321 fat_bpbs[i].mounted = false;
323 #endif
326 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) int startsector)
328 #ifndef HAVE_MULTIVOLUME
329 const int volume = 0;
330 #endif
331 struct bpb* fat_bpb = &fat_bpbs[volume];
332 unsigned char buf[SECTOR_SIZE];
333 int rc;
334 int datasec;
335 #ifdef HAVE_FAT16SUPPORT
336 int rootdirsectors;
337 #endif
339 /* Read the sector */
340 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
341 if(rc)
343 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
344 return rc * 10 - 1;
347 memset(fat_bpb, 0, sizeof(struct bpb));
348 fat_bpb->startsector = startsector;
349 #ifdef HAVE_MULTIVOLUME
350 fat_bpb->drive = drive;
351 #endif
353 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
354 fat_bpb->bpb_secperclus = buf[BPB_SECPERCLUS];
355 fat_bpb->bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT);
356 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
357 fat_bpb->bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16);
358 fat_bpb->bpb_media = buf[BPB_MEDIA];
359 fat_bpb->bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16);
360 fat_bpb->bpb_fatsz32 = BYTES2INT32(buf,BPB_FATSZ32);
361 fat_bpb->bpb_totsec32 = BYTES2INT32(buf,BPB_TOTSEC32);
362 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
364 /* calculate a few commonly used values */
365 if (fat_bpb->bpb_fatsz16 != 0)
366 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
367 else
368 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
370 if (fat_bpb->bpb_totsec16 != 0)
371 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
372 else
373 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
375 #ifdef HAVE_FAT16SUPPORT
376 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
377 rootdirsectors = ((fat_bpb->bpb_rootentcnt * 32)
378 + (fat_bpb->bpb_bytspersec - 1)) / fat_bpb->bpb_bytspersec;
379 #endif /* #ifdef HAVE_FAT16SUPPORT */
381 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
382 #ifdef HAVE_FAT16SUPPORT
383 + rootdirsectors
384 #endif
385 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
387 /* Determine FAT type */
388 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
389 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
391 #ifdef TEST_FAT
393 we are sometimes testing with "illegally small" fat32 images,
394 so we don't use the proper fat32 test case for test code
396 if ( fat_bpb->bpb_fatsz16 )
397 #else
398 if ( fat_bpb->dataclusters < 65525 )
399 #endif
400 { /* FAT16 */
401 #ifdef HAVE_FAT16SUPPORT
402 fat_bpb->is_fat16 = true;
403 if (fat_bpb->dataclusters < 4085)
404 { /* FAT12 */
405 DEBUGF("This is FAT12. Go away!\n");
406 return -2;
408 #else /* #ifdef HAVE_FAT16SUPPORT */
409 DEBUGF("This is not FAT32. Go away!\n");
410 return -2;
411 #endif /* #ifndef HAVE_FAT16SUPPORT */
414 #ifdef HAVE_FAT16SUPPORT
415 if (fat_bpb->is_fat16)
416 { /* FAT16 specific part of BPB */
417 int dirclusters;
418 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
419 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
420 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
421 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
422 /* I assign negative pseudo cluster numbers for the root directory,
423 their range is counted upward until -1. */
424 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
425 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
426 - rootdirsectors;
428 else
429 #endif /* #ifdef HAVE_FAT16SUPPORT */
430 { /* FAT32 specific part of BPB */
431 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
432 fat_bpb->bpb_fsinfo = BYTES2INT16(buf,BPB_FSINFO);
433 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,) fat_bpb->bpb_rootclus);
436 rc = bpb_is_sane(IF_MV(fat_bpb));
437 if (rc < 0)
439 DEBUGF( "fat_mount() - BPB is not sane\n");
440 return rc * 10 - 3;
443 #ifdef HAVE_FAT16SUPPORT
444 if (fat_bpb->is_fat16)
446 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
447 fat_bpb->fsinfo.nextfree = 0xffffffff;
449 else
450 #endif /* #ifdef HAVE_FAT16SUPPORT */
452 /* Read the fsinfo sector */
453 rc = ata_read_sectors(IF_MV2(drive,)
454 startsector + fat_bpb->bpb_fsinfo, 1, buf);
455 if (rc < 0)
457 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
458 return rc * 10 - 4;
460 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
461 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
464 /* calculate freecount if unset */
465 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
467 fat_recalc_free(IF_MV(volume));
470 LDEBUGF("Freecount: %d\n",fat_bpb->fsinfo.freecount);
471 LDEBUGF("Nextfree: 0x%x\n",fat_bpb->fsinfo.nextfree);
472 LDEBUGF("Cluster count: 0x%x\n",fat_bpb->dataclusters);
473 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
474 LDEBUGF("FAT sectors: 0x%x\n",fat_bpb->fatsize);
476 #ifdef HAVE_MULTIVOLUME
477 fat_bpb->mounted = true;
478 #endif
480 return 0;
483 void fat_recalc_free(IF_MV_NONVOID(int volume))
485 #ifndef HAVE_MULTIVOLUME
486 const int volume = 0;
487 #endif
488 struct bpb* fat_bpb = &fat_bpbs[volume];
489 int free = 0;
490 unsigned i;
491 #ifdef HAVE_FAT16SUPPORT
492 if (fat_bpb->is_fat16)
494 for (i = 0; i<fat_bpb->fatsize; i++) {
495 unsigned int j;
496 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
497 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
498 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
499 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
500 break;
502 if (SWAB16(fat[j]) == 0x0000) {
503 free++;
504 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
505 fat_bpb->fsinfo.nextfree = c;
510 else
511 #endif /* #ifdef HAVE_FAT16SUPPORT */
513 for (i = 0; i<fat_bpb->fatsize; i++) {
514 unsigned int j;
515 unsigned int* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
516 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
517 unsigned int c = i * CLUSTERS_PER_FAT_SECTOR + j;
518 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
519 break;
521 if (!(SWAB32(fat[j]) & 0x0fffffff)) {
522 free++;
523 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
524 fat_bpb->fsinfo.nextfree = c;
529 fat_bpb->fsinfo.freecount = free;
530 update_fsinfo(IF_MV(fat_bpb));
533 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
535 #ifndef HAVE_MULTIVOLUME
536 struct bpb* fat_bpb = &fat_bpbs[0];
537 #endif
538 if(fat_bpb->bpb_bytspersec != 512)
540 DEBUGF( "bpb_is_sane() - Error: sector size is not 512 (%d)\n",
541 fat_bpb->bpb_bytspersec);
542 return -1;
544 if(fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec > 128*1024)
546 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
547 "(%d * %d = %d)\n",
548 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
549 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
550 return -2;
552 if(fat_bpb->bpb_numfats != 2)
554 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
555 fat_bpb->bpb_numfats);
557 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
559 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
560 "media type (0x%02x)\n",
561 fat_bpb->bpb_media);
563 if(fat_bpb->last_word != 0xaa55)
565 DEBUGF( "bpb_is_sane() - Error: Last word is not "
566 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
567 return -3;
570 if (fat_bpb->fsinfo.freecount >
571 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
572 fat_bpb->bpb_secperclus)
574 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
575 "(0x%04x)\n", fat_bpb->fsinfo.freecount);
576 return -4;
579 return 0;
582 static void flush_fat_sector(struct fat_cache_entry *fce,
583 unsigned char *sectorbuf)
585 int rc;
586 int secnum;
588 /* With multivolume, use only the FAT info from the cached sector! */
589 #ifdef HAVE_MULTIVOLUME
590 secnum = fce->secnum + fce->fat_vol->startsector;
591 #else
592 secnum = fce->secnum + fat_bpbs[0].startsector;
593 #endif
595 /* Write to the first FAT */
596 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
597 secnum, 1,
598 sectorbuf);
599 if(rc < 0)
601 panicf("flush_fat_sector() - Could not write sector %d"
602 " (error %d)\n",
603 secnum, rc);
605 #ifdef HAVE_MULTIVOLUME
606 if(fce->fat_vol->bpb_numfats > 1)
607 #else
608 if(fat_bpbs[0].bpb_numfats > 1)
609 #endif
611 /* Write to the second FAT */
612 #ifdef HAVE_MULTIVOLUME
613 secnum += fce->fat_vol->fatsize;
614 #else
615 secnum += fat_bpbs[0].fatsize;
616 #endif
617 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
618 secnum, 1, sectorbuf);
619 if(rc < 0)
621 panicf("flush_fat_sector() - Could not write sector %d"
622 " (error %d)\n",
623 secnum, rc);
626 fce->dirty = false;
629 /* Note: The returned pointer is only safely valid until the next
630 task switch! (Any subsequent ata read/write may yield.) */
631 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
632 int fatsector, bool dirty)
634 #ifndef HAVE_MULTIVOLUME
635 struct bpb* fat_bpb = &fat_bpbs[0];
636 #endif
637 int secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
638 int cache_index = secnum & FAT_CACHE_MASK;
639 struct fat_cache_entry *fce = &fat_cache[cache_index];
640 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
641 int rc;
643 mutex_lock(&cache_mutex); /* make changes atomic */
645 /* Delete the cache entry if it isn't the sector we want */
646 if(fce->inuse && (fce->secnum != secnum
647 #ifdef HAVE_MULTIVOLUME
648 || fce->fat_vol != fat_bpb
649 #endif
652 /* Write back if it is dirty */
653 if(fce->dirty)
655 flush_fat_sector(fce, sectorbuf);
657 fce->inuse = false;
660 /* Load the sector if it is not cached */
661 if(!fce->inuse)
663 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
664 secnum + fat_bpb->startsector,1,
665 sectorbuf);
666 if(rc < 0)
668 DEBUGF( "cache_fat_sector() - Could not read sector %d"
669 " (error %d)\n", secnum, rc);
670 mutex_unlock(&cache_mutex);
671 return NULL;
673 fce->inuse = true;
674 fce->secnum = secnum;
675 #ifdef HAVE_MULTIVOLUME
676 fce->fat_vol = fat_bpb;
677 #endif
679 if (dirty)
680 fce->dirty = true; /* dirt remains, sticky until flushed */
681 mutex_unlock(&cache_mutex);
682 return sectorbuf;
685 static unsigned int find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned int startcluster)
687 #ifndef HAVE_MULTIVOLUME
688 struct bpb* fat_bpb = &fat_bpbs[0];
689 #endif
690 unsigned int sector;
691 unsigned int offset;
692 unsigned int i;
694 #ifdef HAVE_FAT16SUPPORT
695 if (fat_bpb->is_fat16)
697 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
698 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
700 for (i = 0; i<fat_bpb->fatsize; i++) {
701 unsigned int j;
702 unsigned int nr = (i + sector) % fat_bpb->fatsize;
703 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
704 if ( !fat )
705 break;
706 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
707 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
708 if (SWAB16(fat[k]) == 0x0000) {
709 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
710 /* Ignore the reserved clusters 0 & 1, and also
711 cluster numbers out of bounds */
712 if ( c < 2 || c > fat_bpb->dataclusters+1 )
713 continue;
714 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
715 fat_bpb->fsinfo.nextfree = c;
716 return c;
719 offset = 0;
722 else
723 #endif /* #ifdef HAVE_FAT16SUPPORT */
725 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
726 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
728 for (i = 0; i<fat_bpb->fatsize; i++) {
729 unsigned int j;
730 unsigned int nr = (i + sector) % fat_bpb->fatsize;
731 unsigned int* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
732 if ( !fat )
733 break;
734 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
735 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
736 if (!(SWAB32(fat[k]) & 0x0fffffff)) {
737 unsigned int c = nr * CLUSTERS_PER_FAT_SECTOR + k;
738 /* Ignore the reserved clusters 0 & 1, and also
739 cluster numbers out of bounds */
740 if ( c < 2 || c > fat_bpb->dataclusters+1 )
741 continue;
742 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
743 fat_bpb->fsinfo.nextfree = c;
744 return c;
747 offset = 0;
751 LDEBUGF("find_free_cluster(%x) == 0\n",startcluster);
752 return 0; /* 0 is an illegal cluster number */
755 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned int entry, unsigned int val)
757 #ifndef HAVE_MULTIVOLUME
758 struct bpb* fat_bpb = &fat_bpbs[0];
759 #endif
760 #ifdef HAVE_FAT16SUPPORT
761 if (fat_bpb->is_fat16)
763 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
764 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
765 unsigned short* sec;
767 val &= 0xFFFF;
769 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
771 if (entry==val)
772 panicf("Creating FAT loop: %x,%x\n",entry,val);
774 if ( entry < 2 )
775 panicf("Updating reserved FAT entry %d.\n",entry);
777 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
778 if (!sec)
780 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
781 return -1;
784 if ( val ) {
785 if (SWAB16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
786 fat_bpb->fsinfo.freecount--;
788 else {
789 if (SWAB16(sec[offset]))
790 fat_bpb->fsinfo.freecount++;
793 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
795 sec[offset] = SWAB16(val);
797 else
798 #endif /* #ifdef HAVE_FAT16SUPPORT */
800 int sector = entry / CLUSTERS_PER_FAT_SECTOR;
801 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
802 unsigned int* sec;
804 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
806 if (entry==val)
807 panicf("Creating FAT loop: %x,%x\n",entry,val);
809 if ( entry < 2 )
810 panicf("Updating reserved FAT entry %d.\n",entry);
812 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
813 if (!sec)
815 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
816 return -1;
819 if ( val ) {
820 if (!(SWAB32(sec[offset]) & 0x0fffffff) &&
821 fat_bpb->fsinfo.freecount > 0)
822 fat_bpb->fsinfo.freecount--;
824 else {
825 if (SWAB32(sec[offset]) & 0x0fffffff)
826 fat_bpb->fsinfo.freecount++;
829 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
831 /* don't change top 4 bits */
832 sec[offset] &= SWAB32(0xf0000000);
833 sec[offset] |= SWAB32(val & 0x0fffffff);
836 return 0;
839 static int read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned int entry)
841 #ifdef HAVE_FAT16SUPPORT
842 #ifndef HAVE_MULTIVOLUME
843 struct bpb* fat_bpb = &fat_bpbs[0];
844 #endif
845 if (fat_bpb->is_fat16)
847 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
848 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
849 unsigned short* sec;
851 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
852 if (!sec)
854 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
855 return -1;
858 return SWAB16(sec[offset]);
860 else
861 #endif /* #ifdef HAVE_FAT16SUPPORT */
863 int sector = entry / CLUSTERS_PER_FAT_SECTOR;
864 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
865 unsigned int* sec;
867 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
868 if (!sec)
870 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
871 return -1;
874 return SWAB32(sec[offset]) & 0x0fffffff;
878 static int get_next_cluster(IF_MV2(struct bpb* fat_bpb,) int cluster)
880 int next_cluster;
881 int eof_mark = FAT_EOF_MARK;
883 #ifdef HAVE_FAT16SUPPORT
884 #ifndef HAVE_MULTIVOLUME
885 struct bpb* fat_bpb = &fat_bpbs[0];
886 #endif
887 if (fat_bpb->is_fat16)
889 eof_mark &= 0xFFFF; /* only 16 bit */
890 if (cluster < 0) /* FAT16 root dir */
891 return cluster + 1; /* don't use the FAT */
893 #endif
894 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
896 /* is this last cluster in chain? */
897 if ( next_cluster >= eof_mark )
898 return 0;
899 else
900 return next_cluster;
903 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
905 #ifndef HAVE_MULTIVOLUME
906 struct bpb* fat_bpb = &fat_bpbs[0];
907 #endif
908 unsigned char fsinfo[SECTOR_SIZE];
909 unsigned int* intptr;
910 int rc;
912 #ifdef HAVE_FAT16SUPPORT
913 if (fat_bpb->is_fat16)
914 return 0; /* FAT16 has no FsInfo */
915 #endif /* #ifdef HAVE_FAT16SUPPORT */
917 /* update fsinfo */
918 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
919 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
920 if (rc < 0)
922 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
923 return rc * 10 - 1;
925 intptr = (int*)&(fsinfo[FSINFO_FREECOUNT]);
926 *intptr = SWAB32(fat_bpb->fsinfo.freecount);
928 intptr = (int*)&(fsinfo[FSINFO_NEXTFREE]);
929 *intptr = SWAB32(fat_bpb->fsinfo.nextfree);
931 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
932 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
933 if (rc < 0)
935 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
936 return rc * 10 - 2;
939 return 0;
942 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
944 int i;
945 int rc;
946 unsigned char *sec;
947 LDEBUGF("flush_fat()\n");
949 for(i = 0;i < FAT_CACHE_SIZE;i++)
951 struct fat_cache_entry *fce = &fat_cache[i];
952 if(fce->inuse && fce->dirty)
954 sec = fat_cache_sectors[i];
955 flush_fat_sector(fce, sec);
959 rc = update_fsinfo(IF_MV(fat_bpb));
960 if (rc < 0)
961 return rc * 10 - 3;
963 return 0;
966 static void fat_time(unsigned short* date,
967 unsigned short* time,
968 unsigned short* tenth )
970 #ifdef HAVE_RTC
971 struct tm* tm = get_time();
973 if (date)
974 *date = ((tm->tm_year - 80) << 9) |
975 ((tm->tm_mon + 1) << 5) |
976 tm->tm_mday;
978 if (time)
979 *time = (tm->tm_hour << 11) |
980 (tm->tm_min << 5) |
981 (tm->tm_sec >> 1);
983 if (tenth)
984 *tenth = (tm->tm_sec & 1) * 100;
985 #else
986 /* non-RTC version returns an increment from the supplied time, or a
987 * fixed standard time/date if no time given as input */
988 bool next_day = false;
990 if (time)
992 if (0 == *time)
994 /* set to 00:15:00 */
995 *time = (15 << 5);
997 else
999 unsigned short mins = (*time >> 5) & 0x003F;
1000 unsigned short hours = (*time >> 11) & 0x001F;
1001 if ((mins += 10) >= 60)
1003 mins = 0;
1004 hours++;
1006 if ((++hours) >= 24)
1008 hours = hours - 24;
1009 next_day = true;
1011 *time = (hours << 11) | (mins << 5);
1015 if (date)
1017 if (0 == *date)
1019 /* set to 1 August 2003 */
1020 *date = ((2003 - 1980) << 9) | (8 << 5) | 1;
1022 else
1024 unsigned short day = *date & 0x001F;
1025 unsigned short month = (*date >> 5) & 0x000F;
1026 unsigned short year = (*date >> 9) & 0x007F;
1027 if (next_day)
1029 /* do a very simple day increment - never go above 28 days */
1030 if (++day > 28)
1032 day = 1;
1033 if (++month > 12)
1035 month = 1;
1036 year++;
1039 *date = (year << 9) | (month << 5) | day;
1043 if (tenth)
1044 *tenth = 0;
1045 #endif /* HAVE_RTC */
1048 static int write_long_name(struct fat_file* file,
1049 unsigned int firstentry,
1050 unsigned int numentries,
1051 const unsigned char* name,
1052 const unsigned char* shortname,
1053 bool is_directory)
1055 unsigned char buf[SECTOR_SIZE];
1056 unsigned char* entry;
1057 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1058 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1059 unsigned int i, j=0;
1060 unsigned char chksum = 0;
1061 int nameidx=0, namelen = strlen(name);
1062 int rc;
1064 LDEBUGF("write_long_name(file:%x, first:%d, num:%d, name:%s)\n",
1065 file->firstcluster, firstentry, numentries, name);
1067 rc = fat_seek(file, sector);
1068 if (rc<0)
1069 return rc * 10 - 1;
1071 rc = fat_readwrite(file, 1, buf, false);
1072 if (rc<1)
1073 return rc * 10 - 2;
1075 /* calculate shortname checksum */
1076 for (i=11; i>0; i--)
1077 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1079 /* calc position of last name segment */
1080 if ( namelen > NAME_BYTES_PER_ENTRY )
1081 for (nameidx=0;
1082 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1083 nameidx += NAME_BYTES_PER_ENTRY);
1085 for (i=0; i < numentries; i++) {
1086 /* new sector? */
1087 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1088 /* update current sector */
1089 rc = fat_seek(file, sector);
1090 if (rc<0)
1091 return rc * 10 - 3;
1093 rc = fat_readwrite(file, 1, buf, true);
1094 if (rc<1)
1095 return rc * 10 - 4;
1097 /* read next sector */
1098 rc = fat_readwrite(file, 1, buf, false);
1099 if (rc<0) {
1100 LDEBUGF("Failed writing new sector: %d\n",rc);
1101 return rc * 10 - 5;
1103 if (rc==0)
1104 /* end of dir */
1105 memset(buf, 0, sizeof buf);
1107 sector++;
1108 idx = 0;
1111 entry = buf + idx * DIR_ENTRY_SIZE;
1113 /* verify this entry is free */
1114 if (entry[0] && entry[0] != 0xe5 )
1115 panicf("Dir entry %d in sector %x is not free! "
1116 "%02x %02x %02x %02x",
1117 idx, sector,
1118 entry[0], entry[1], entry[2], entry[3]);
1120 memset(entry, 0, DIR_ENTRY_SIZE);
1121 if ( i+1 < numentries ) {
1122 /* longname entry */
1123 int k, l = nameidx;
1125 entry[FATLONG_ORDER] = numentries-i-1;
1126 if (i==0) {
1127 /* mark this as last long entry */
1128 entry[FATLONG_ORDER] |= 0x40;
1130 /* pad name with 0xffff */
1131 for (k=1; k<12; k++) entry[k] = 0xff;
1132 for (k=14; k<26; k++) entry[k] = 0xff;
1133 for (k=28; k<32; k++) entry[k] = 0xff;
1135 /* set name */
1136 for (k=0; k<5 && l <= namelen; k++) {
1137 entry[k*2 + 1] = name[l++];
1138 entry[k*2 + 2] = 0;
1140 for (k=0; k<6 && l <= namelen; k++) {
1141 entry[k*2 + 14] = name[l++];
1142 entry[k*2 + 15] = 0;
1144 for (k=0; k<2 && l <= namelen; k++) {
1145 entry[k*2 + 28] = name[l++];
1146 entry[k*2 + 29] = 0;
1149 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1150 entry[FATDIR_FSTCLUSLO] = 0;
1151 entry[FATLONG_TYPE] = 0;
1152 entry[FATLONG_CHKSUM] = chksum;
1153 LDEBUGF("Longname entry %d: %.13s\n", idx, name+nameidx);
1155 else {
1156 /* shortname entry */
1157 unsigned short date=0, time=0, tenth=0;
1158 LDEBUGF("Shortname entry: %.13s\n", shortname);
1159 strncpy(entry + FATDIR_NAME, shortname, 11);
1160 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1161 entry[FATDIR_NTRES] = 0;
1163 fat_time(&date, &time, &tenth);
1164 entry[FATDIR_CRTTIMETENTH] = tenth;
1165 *(unsigned short*)(entry + FATDIR_CRTTIME) = SWAB16(time);
1166 *(unsigned short*)(entry + FATDIR_WRTTIME) = SWAB16(time);
1167 *(unsigned short*)(entry + FATDIR_CRTDATE) = SWAB16(date);
1168 *(unsigned short*)(entry + FATDIR_WRTDATE) = SWAB16(date);
1169 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = SWAB16(date);
1171 idx++;
1172 nameidx -= NAME_BYTES_PER_ENTRY;
1175 /* update last sector */
1176 rc = fat_seek(file, sector);
1177 if (rc<0)
1178 return rc * 10 - 6;
1180 rc = fat_readwrite(file, 1, buf, true);
1181 if (rc<1)
1182 return rc * 10 - 7;
1184 return 0;
1187 static int add_dir_entry(struct fat_dir* dir,
1188 struct fat_file* file,
1189 const char* name,
1190 bool is_directory,
1191 bool dotdir)
1193 #ifdef HAVE_MULTIVOLUME
1194 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1195 #else
1196 struct bpb* fat_bpb = &fat_bpbs[0];
1197 #endif
1198 unsigned char buf[SECTOR_SIZE];
1199 unsigned char shortname[16];
1200 int rc;
1201 unsigned int sector;
1202 bool done = false;
1203 bool eof = false;
1204 bool last = false;
1205 int entries_needed, entries_found = 0;
1206 int namelen = strlen(name);
1207 int firstentry;
1209 LDEBUGF( "add_dir_entry(%s,%x)\n",
1210 name, file->firstcluster);
1212 #ifdef HAVE_MULTIVOLUME
1213 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1214 #endif
1216 /* The "." and ".." directory entries must not be long names */
1217 if(dotdir) {
1218 int i;
1219 strncpy(shortname, name, 16);
1220 for(i = strlen(shortname);i < 12;i++)
1221 shortname[i] = ' ';
1223 entries_needed = 1;
1224 } else {
1225 /* create dos name */
1226 rc = create_dos_name(name, shortname);
1227 if (rc < 0)
1228 return rc * 10 - 0;
1230 /* one dir entry needed for every 13 bytes of filename,
1231 plus one entry for the short name */
1232 entries_needed = namelen / NAME_BYTES_PER_ENTRY + 1;
1233 if (namelen % NAME_BYTES_PER_ENTRY)
1234 entries_needed++;
1237 restart:
1238 firstentry = 0;
1240 rc = fat_seek(&dir->file, 0);
1241 if (rc < 0)
1242 return rc * 10 - 1;
1244 for (sector=0; !done; sector++)
1246 unsigned int i;
1248 rc = 0;
1249 if (!eof) {
1250 rc = fat_readwrite(&dir->file, 1, buf, false);
1252 if (rc == 0) {
1253 /* eof: add new sector */
1254 eof = true;
1256 memset(buf, 0, sizeof buf);
1257 LDEBUGF("Adding new sector to dir\n");
1258 rc = fat_seek(&dir->file, sector);
1259 if (rc < 0)
1260 return rc * 10 - 2;
1262 /* add sectors (we must clear the whole cluster) */
1263 do {
1264 rc = fat_readwrite(&dir->file, 1, buf, true);
1265 if (rc < 1)
1266 return rc * 10 - 3;
1267 } while (dir->file.sectornum < (int)fat_bpb->bpb_secperclus);
1269 if (rc < 0) {
1270 DEBUGF( "add_dir_entry() - Couldn't read dir"
1271 " (error code %d)\n", rc);
1272 return rc * 10 - 4;
1275 /* look for free slots */
1276 for (i=0; i < DIR_ENTRIES_PER_SECTOR && !done; i++)
1278 unsigned char firstbyte = buf[i * DIR_ENTRY_SIZE];
1279 switch (firstbyte) {
1280 case 0: /* end of dir */
1281 entries_found = entries_needed;
1282 LDEBUGF("Found last entry %d\n",
1283 sector * DIR_ENTRIES_PER_SECTOR + i);
1284 done = true;
1285 break;
1287 case 0xe5: /* free entry */
1288 entries_found++;
1289 LDEBUGF("Found free entry %d (%d/%d)\n",
1290 sector * DIR_ENTRIES_PER_SECTOR + i,
1291 entries_found, entries_needed);
1292 break;
1294 default:
1295 entries_found = 0;
1297 /* check that our intended shortname doesn't already exist */
1298 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 12)) {
1299 /* filename exists already. make a new one */
1300 snprintf(shortname+8, 4, "%03X", (unsigned)rand() & 0xfff);
1301 LDEBUGF("Duplicate shortname, changing to %s\n",
1302 shortname);
1304 /* name has changed, we need to restart search */
1305 goto restart;
1307 break;
1310 if (!firstentry && (entries_found == entries_needed)) {
1311 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i;
1313 /* if we're not extending the dir,
1314 we must go back to first free entry */
1315 if (done)
1316 last = true;
1317 else
1318 firstentry -= (entries_needed - 1);
1323 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1324 LDEBUGF("Adding longname to entry %d in sector %d\n",
1325 firstentry, sector);
1327 rc = write_long_name(&dir->file, firstentry,
1328 entries_needed, name, shortname, is_directory);
1329 if (rc < 0)
1330 return rc * 10 - 5;
1332 /* remember where the shortname dir entry is located */
1333 file->direntry = firstentry + entries_needed - 1;
1334 file->direntries = entries_needed;
1335 file->dircluster = dir->file.firstcluster;
1336 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1337 file->direntry, file->direntries);
1339 /* advance the end-of-dir marker? */
1340 if (last)
1342 unsigned int lastentry = firstentry + entries_needed;
1344 LDEBUGF("Updating end-of-dir entry %d\n",lastentry);
1346 if (lastentry % DIR_ENTRIES_PER_SECTOR)
1348 int idx = (lastentry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE;
1350 rc = fat_seek(&dir->file, lastentry / DIR_ENTRIES_PER_SECTOR);
1351 if (rc < 0)
1352 return rc * 10 - 6;
1354 rc = fat_readwrite(&dir->file, 1, buf, false);
1355 if (rc < 1)
1356 return rc * 10 - 7;
1358 /* clear last entry */
1359 buf[idx] = 0;
1361 rc = fat_seek(&dir->file, lastentry / DIR_ENTRIES_PER_SECTOR);
1362 if (rc < 0)
1363 return rc * 10 - 8;
1365 /* we must clear entire last cluster */
1366 do {
1367 rc = fat_readwrite(&dir->file, 1, buf, true);
1368 if (rc < 1)
1369 return rc * 10 - 9;
1370 memset(buf, 0, sizeof buf);
1371 } while (dir->file.sectornum < (int)fat_bpb->bpb_secperclus);
1373 else
1375 /* add a new sector/cluster for last entry */
1376 memset(buf, 0, sizeof buf);
1377 do {
1378 rc = fat_readwrite(&dir->file, 1, buf, true);
1379 if (rc < 1)
1380 return rc * 10 - 9; /* Same error code as above, can't be
1381 more than -9 */
1382 } while (dir->file.sectornum < (int)fat_bpb->bpb_secperclus);
1386 return 0;
1389 unsigned char char2dos(unsigned char c)
1391 switch(c)
1393 case 0xe5: /* Special kanji character */
1394 c = 0x05;
1395 break;
1396 case 0x20:
1397 case 0x22:
1398 case 0x2a:
1399 case 0x2b:
1400 case 0x2c:
1401 case 0x2e:
1402 case 0x3a:
1403 case 0x3b:
1404 case 0x3c:
1405 case 0x3d:
1406 case 0x3e:
1407 case 0x3f:
1408 case 0x5b:
1409 case 0x5c:
1410 case 0x5d:
1411 case 0x7c:
1412 /* Illegal name */
1413 c = 0;
1414 break;
1416 default:
1417 if(c < 0x20)
1419 /* Illegal name */
1420 c = 0;
1422 break;
1424 return c;
1427 static int create_dos_name(const unsigned char *name, unsigned char *newname)
1429 int i,j;
1431 /* Name part */
1432 for (i=0, j=0; name[i] && (j < 8); i++)
1434 unsigned char c = char2dos(name[i]);
1435 if (c)
1436 newname[j++] = toupper(c);
1438 while (j < 8)
1439 newname[j++] = ' ';
1441 /* Extension part */
1442 snprintf(newname+8, 4, "%03X", (unsigned)rand() & 0xfff);
1444 return 0;
1447 static int update_short_entry( struct fat_file* file, int size, int attr )
1449 unsigned char buf[SECTOR_SIZE];
1450 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1451 unsigned char* entry =
1452 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1453 unsigned int* sizeptr;
1454 unsigned short* clusptr;
1455 struct fat_file dir;
1456 int rc;
1458 LDEBUGF("update_file_size(cluster:%x entry:%d size:%d)\n",
1459 file->firstcluster, file->direntry, size);
1461 /* create a temporary file handle for the dir holding this file */
1462 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1463 if (rc < 0)
1464 return rc * 10 - 1;
1466 rc = fat_seek( &dir, sector );
1467 if (rc<0)
1468 return rc * 10 - 2;
1470 rc = fat_readwrite(&dir, 1, buf, false);
1471 if (rc < 1)
1472 return rc * 10 - 3;
1474 if (!entry[0] || entry[0] == 0xe5)
1475 panicf("Updating size on empty dir entry %d\n", file->direntry);
1477 entry[FATDIR_ATTR] = attr & 0xFF;
1479 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1480 *clusptr = SWAB16(file->firstcluster >> 16);
1482 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1483 *clusptr = SWAB16(file->firstcluster & 0xffff);
1485 sizeptr = (int*)(entry + FATDIR_FILESIZE);
1486 *sizeptr = SWAB32(size);
1489 #ifdef HAVE_RTC
1490 unsigned short time = 0;
1491 unsigned short date = 0;
1492 #else
1493 /* get old time to increment from */
1494 unsigned short time = SWAB16(*(unsigned short*)(entry + FATDIR_WRTTIME));
1495 unsigned short date = SWAB16(*(unsigned short*)(entry + FATDIR_WRTDATE));
1496 #endif
1497 fat_time(&date, &time, NULL);
1498 *(unsigned short*)(entry + FATDIR_WRTTIME) = SWAB16(time);
1499 *(unsigned short*)(entry + FATDIR_WRTDATE) = SWAB16(date);
1500 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = SWAB16(date);
1503 rc = fat_seek( &dir, sector );
1504 if (rc < 0)
1505 return rc * 10 - 4;
1507 rc = fat_readwrite(&dir, 1, buf, true);
1508 if (rc < 1)
1509 return rc * 10 - 5;
1511 return 0;
1514 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1516 int i=0,j=0;
1517 memset(de, 0, sizeof(struct fat_direntry));
1518 de->attr = buf[FATDIR_ATTR];
1519 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1520 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1521 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1522 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1523 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1524 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1525 de->firstcluster = BYTES2INT16(buf,FATDIR_FSTCLUSLO) |
1526 (BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1528 /* fix the name */
1529 for (i=0; (i<8) && (buf[FATDIR_NAME+i] != ' '); i++)
1530 de->name[j++] = buf[FATDIR_NAME+i];
1531 if ( buf[FATDIR_NAME+8] != ' ' ) {
1532 de->name[j++] = '.';
1533 for (i=8; (i<11) && (buf[FATDIR_NAME+i] != ' '); i++)
1534 de->name[j++] = buf[FATDIR_NAME+i];
1536 return 1;
1539 int fat_open(IF_MV2(int volume,)
1540 int startcluster,
1541 struct fat_file *file,
1542 const struct fat_dir* dir)
1544 file->firstcluster = startcluster;
1545 file->lastcluster = startcluster;
1546 file->lastsector = 0;
1547 file->clusternum = 0;
1548 file->sectornum = 0;
1549 file->eof = false;
1550 #ifdef HAVE_MULTIVOLUME
1551 file->volume = volume;
1552 /* fixme: remove error check when done */
1553 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1555 LDEBUGF("fat_open() illegal volume %d\n", volume);
1556 return -1;
1558 #endif
1560 /* remember where the file's dir entry is located */
1561 if ( dir ) {
1562 file->direntry = dir->entry - 1;
1563 file->direntries = dir->entrycount;
1564 file->dircluster = dir->file.firstcluster;
1566 LDEBUGF("fat_open(%x), entry %d\n",startcluster,file->direntry);
1567 return 0;
1570 int fat_create_file(const char* name,
1571 struct fat_file* file,
1572 struct fat_dir* dir)
1574 int rc;
1576 LDEBUGF("fat_create_file(\"%s\",%x,%x)\n",name,file,dir);
1577 rc = add_dir_entry(dir, file, name, false, false);
1578 if (!rc) {
1579 file->firstcluster = 0;
1580 file->lastcluster = 0;
1581 file->lastsector = 0;
1582 file->clusternum = 0;
1583 file->sectornum = 0;
1584 file->eof = false;
1587 return rc;
1590 int fat_create_dir(const char* name,
1591 struct fat_dir* newdir,
1592 struct fat_dir* dir)
1594 #ifdef HAVE_MULTIVOLUME
1595 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1596 #else
1597 struct bpb* fat_bpb = &fat_bpbs[0];
1598 #endif
1599 unsigned char buf[SECTOR_SIZE];
1600 int i;
1601 int sector;
1602 int rc;
1603 struct fat_file dummyfile;
1605 LDEBUGF("fat_create_dir(\"%s\",%x,%x)\n",name,newdir,dir);
1607 memset(newdir, 0, sizeof(struct fat_dir));
1608 memset(&dummyfile, 0, sizeof(struct fat_file));
1610 /* First, add the entry in the parent directory */
1611 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1612 if (rc < 0)
1613 return rc * 10 - 1;
1615 /* Allocate a new cluster for the directory */
1616 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
1617 if(newdir->file.firstcluster == 0)
1618 return -1;
1620 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1622 /* Clear the entire cluster */
1623 memset(buf, 0, sizeof buf);
1624 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1625 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1626 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1627 if (rc < 0)
1628 return rc * 10 - 2;
1631 /* Then add the "." entry */
1632 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1633 if (rc < 0)
1634 return rc * 10 - 3;
1635 dummyfile.firstcluster = newdir->file.firstcluster;
1636 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1638 /* and the ".." entry */
1639 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1640 if (rc < 0)
1641 return rc * 10 - 4;
1643 /* The root cluster is cluster 0 in the ".." entry */
1644 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1645 dummyfile.firstcluster = 0;
1646 else
1647 dummyfile.firstcluster = dir->file.firstcluster;
1648 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1650 /* Set the firstcluster field in the direntry */
1651 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1653 rc = flush_fat(IF_MV(fat_bpb));
1654 if (rc < 0)
1655 return rc * 10 - 5;
1657 return rc;
1660 int fat_truncate(const struct fat_file *file)
1662 /* truncate trailing clusters */
1663 int next;
1664 int last = file->lastcluster;
1665 #ifdef HAVE_MULTIVOLUME
1666 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1667 #endif
1669 LDEBUGF("fat_truncate(%x, %x)\n", file->firstcluster, last);
1671 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1672 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1673 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1675 if (file->lastcluster)
1676 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1678 return 0;
1681 int fat_closewrite(struct fat_file *file, int size, int attr)
1683 int rc;
1684 #ifdef HAVE_MULTIVOLUME
1685 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1686 #endif
1687 LDEBUGF("fat_closewrite(size=%d)\n",size);
1689 if (!size) {
1690 /* empty file */
1691 if ( file->firstcluster ) {
1692 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1693 file->firstcluster = 0;
1697 if (file->dircluster) {
1698 rc = update_short_entry(file, size, attr);
1699 if (rc < 0)
1700 return rc * 10 - 1;
1703 flush_fat(IF_MV(fat_bpb));
1705 #ifdef TEST_FAT
1706 if ( file->firstcluster ) {
1707 /* debug */
1708 #ifdef HAVE_MULTIVOLUME
1709 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1710 #else
1711 struct bpb* fat_bpb = &fat_bpbs[0];
1712 #endif
1713 int count = 0;
1714 int len;
1715 int next;
1716 for ( next = file->firstcluster; next;
1717 next = get_next_cluster(IF_MV2(fat_bpb,) next) )
1718 LDEBUGF("cluster %d: %x\n", count++, next);
1719 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1720 LDEBUGF("File is %d clusters (chainlen=%d, size=%d)\n",
1721 count, len, size );
1722 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1723 panicf("Cluster chain is too long\n");
1724 if ( len < size )
1725 panicf("Cluster chain is too short\n");
1727 #endif
1729 return 0;
1732 static int free_direntries(struct fat_file* file)
1734 unsigned char buf[SECTOR_SIZE];
1735 struct fat_file dir;
1736 int numentries = file->direntries;
1737 unsigned int entry = file->direntry - numentries + 1;
1738 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1739 int i;
1740 int rc;
1742 /* create a temporary file handle for the dir holding this file */
1743 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1744 if (rc < 0)
1745 return rc * 10 - 1;
1747 rc = fat_seek( &dir, sector );
1748 if (rc < 0)
1749 return rc * 10 - 2;
1751 rc = fat_readwrite(&dir, 1, buf, false);
1752 if (rc < 1)
1753 return rc * 10 - 3;
1755 for (i=0; i < numentries; i++) {
1756 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1757 entry, i+1, numentries);
1758 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1759 entry++;
1761 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1762 /* flush this sector */
1763 rc = fat_seek(&dir, sector);
1764 if (rc < 0)
1765 return rc * 10 - 4;
1767 rc = fat_readwrite(&dir, 1, buf, true);
1768 if (rc < 1)
1769 return rc * 10 - 5;
1771 if ( i+1 < numentries ) {
1772 /* read next sector */
1773 rc = fat_readwrite(&dir, 1, buf, false);
1774 if (rc < 1)
1775 return rc * 10 - 6;
1777 sector++;
1781 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1782 /* flush this sector */
1783 rc = fat_seek(&dir, sector);
1784 if (rc < 0)
1785 return rc * 10 - 7;
1787 rc = fat_readwrite(&dir, 1, buf, true);
1788 if (rc < 1)
1789 return rc * 10 - 8;
1792 return 0;
1795 int fat_remove(struct fat_file* file)
1797 int next, last = file->firstcluster;
1798 int rc;
1799 #ifdef HAVE_MULTIVOLUME
1800 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1801 #endif
1803 LDEBUGF("fat_remove(%x)\n",last);
1805 while ( last ) {
1806 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1807 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1808 last = next;
1811 if ( file->dircluster ) {
1812 rc = free_direntries(file);
1813 if (rc < 0)
1814 return rc * 10 - 1;
1817 file->firstcluster = 0;
1818 file->dircluster = 0;
1820 rc = flush_fat(IF_MV(fat_bpb));
1821 if (rc < 0)
1822 return rc * 10 - 2;
1824 return 0;
1827 int fat_rename(struct fat_file* file,
1828 struct fat_dir* dir,
1829 const unsigned char* newname,
1830 int size,
1831 int attr)
1833 int rc;
1834 struct fat_dir olddir;
1835 struct fat_file newfile = *file;
1836 #ifdef HAVE_MULTIVOLUME
1837 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1839 if (file->volume != dir->file.volume) {
1840 DEBUGF("No rename across volumes!\n");
1841 return -1;
1843 #endif
1845 if ( !file->dircluster ) {
1846 DEBUGF("File has no dir cluster!\n");
1847 return -2;
1850 /* create a temporary file handle */
1851 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1852 if (rc < 0)
1853 return rc * 10 - 3;
1855 /* create new name */
1856 rc = add_dir_entry(dir, &newfile, newname, false, false);
1857 if (rc < 0)
1858 return rc * 10 - 4;
1860 /* write size and cluster link */
1861 rc = update_short_entry(&newfile, size, attr);
1862 if (rc < 0)
1863 return rc * 10 - 5;
1865 /* remove old name */
1866 rc = free_direntries(file);
1867 if (rc < 0)
1868 return rc * 10 - 6;
1870 rc = flush_fat(IF_MV(fat_bpb));
1871 if (rc < 0)
1872 return rc * 10 - 7;
1874 return 0;
1877 static int next_write_cluster(struct fat_file* file,
1878 int oldcluster,
1879 int* newsector)
1881 #ifdef HAVE_MULTIVOLUME
1882 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1883 #else
1884 struct bpb* fat_bpb = &fat_bpbs[0];
1885 #endif
1886 int cluster = 0;
1887 int sector;
1889 LDEBUGF("next_write_cluster(%x,%x)\n",file->firstcluster, oldcluster);
1891 if (oldcluster)
1892 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
1894 if (!cluster) {
1895 if (oldcluster > 0)
1896 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
1897 else if (oldcluster == 0)
1898 cluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
1899 #ifdef HAVE_FAT16SUPPORT
1900 else /* negative, pseudo-cluster of the root dir */
1901 return 0; /* impossible to append something to the root */
1902 #endif
1904 if (cluster) {
1905 if (oldcluster)
1906 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
1907 else
1908 file->firstcluster = cluster;
1909 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
1911 else {
1912 #ifdef TEST_FAT
1913 if (fat_bpb->fsinfo.freecount>0)
1914 panicf("There is free space, but find_free_cluster() "
1915 "didn't find it!\n");
1916 #endif
1917 DEBUGF("next_write_cluster(): Disk full!\n");
1918 return 0;
1921 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
1922 if (sector<0)
1923 return 0;
1925 *newsector = sector;
1926 return cluster;
1929 static int transfer(IF_MV2(struct bpb* fat_bpb,)
1930 unsigned int start, int count, char* buf, bool write )
1932 #ifndef HAVE_MULTIVOLUME
1933 struct bpb* fat_bpb = &fat_bpbs[0];
1934 #endif
1935 int rc;
1937 LDEBUGF("transfer(s=%x, c=%x, %s)\n",
1938 start+ fat_bpb->startsector, count, write?"write":"read");
1939 if (write) {
1940 unsigned int firstallowed;
1941 #ifdef HAVE_FAT16SUPPORT
1942 if (fat_bpb->is_fat16)
1943 firstallowed = fat_bpb->rootdirsector;
1944 else
1945 #endif
1946 firstallowed = fat_bpb->firstdatasector;
1948 if (start < firstallowed)
1949 panicf("Write %d before data\n", firstallowed - start);
1950 if (start + count > fat_bpb->totalsectors)
1951 panicf("Write %d after data\n",
1952 start + count - fat_bpb->totalsectors);
1953 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
1954 start + fat_bpb->startsector, count, buf);
1956 else
1957 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
1958 start + fat_bpb->startsector, count, buf);
1959 if (rc < 0) {
1960 DEBUGF( "transfer() - Couldn't %s sector %x"
1961 " (error code %d)\n",
1962 write ? "write":"read", start, rc);
1963 return rc;
1965 return 0;
1969 int fat_readwrite( struct fat_file *file, int sectorcount,
1970 void* buf, bool write )
1972 #ifdef HAVE_MULTIVOLUME
1973 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1974 #else
1975 struct bpb* fat_bpb = &fat_bpbs[0];
1976 #endif
1977 int cluster = file->lastcluster;
1978 int sector = file->lastsector;
1979 int clusternum = file->clusternum;
1980 int numsec = file->sectornum;
1981 bool eof = file->eof;
1982 int first=0, last=0;
1983 int i;
1984 int rc;
1986 LDEBUGF( "fat_readwrite(file:%x,count:0x%x,buf:%x,%s)\n",
1987 file->firstcluster,sectorcount,buf,write?"write":"read");
1988 LDEBUGF( "fat_readwrite: sec=%x numsec=%d eof=%d\n",
1989 sector,numsec, eof?1:0);
1991 if ( eof && !write)
1992 return 0;
1994 /* find sequential sectors and write them all at once */
1995 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
1996 numsec++;
1997 if ( numsec > (int)fat_bpb->bpb_secperclus || !cluster ) {
1998 int oldcluster = cluster;
1999 if (write)
2000 cluster = next_write_cluster(file, cluster, &sector);
2001 else {
2002 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2003 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2006 clusternum++;
2007 numsec=1;
2009 if (!cluster) {
2010 eof = true;
2011 if ( write ) {
2012 /* remember last cluster, in case
2013 we want to append to the file */
2014 cluster = oldcluster;
2015 clusternum--;
2016 i = -1; /* Error code */
2017 break;
2020 else
2021 eof = false;
2023 else {
2024 if (sector)
2025 sector++;
2026 else {
2027 /* look up first sector of file */
2028 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2029 numsec=1;
2030 #ifdef HAVE_FAT16SUPPORT
2031 if (file->firstcluster < 0)
2032 { /* FAT16 root dir */
2033 sector += fat_bpb->rootdiroffset;
2034 numsec += fat_bpb->rootdiroffset;
2036 #endif
2040 if (!first)
2041 first = sector;
2043 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2044 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2045 int count = last - first + 1;
2046 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2047 if (rc < 0)
2048 return rc * 10 - 1;
2050 buf = (char *)buf + count * SECTOR_SIZE;
2051 first = sector;
2054 if ((i == sectorcount-1) && /* last sector requested */
2055 (!eof))
2057 int count = sector - first + 1;
2058 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2059 if (rc < 0)
2060 return rc * 10 - 2;
2063 last = sector;
2066 file->lastcluster = cluster;
2067 file->lastsector = sector;
2068 file->clusternum = clusternum;
2069 file->sectornum = numsec;
2070 file->eof = eof;
2072 /* if eof, don't report last block as read/written */
2073 if (eof)
2074 i--;
2076 DEBUGF("Sectors written: %d\n", i);
2077 return i;
2080 int fat_seek(struct fat_file *file, unsigned int seeksector )
2082 #ifdef HAVE_MULTIVOLUME
2083 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2084 #else
2085 struct bpb* fat_bpb = &fat_bpbs[0];
2086 #endif
2087 int clusternum=0, numclusters=0, sectornum=0, sector=0;
2088 int cluster = file->firstcluster;
2089 int i;
2091 #ifdef HAVE_FAT16SUPPORT
2092 if (cluster < 0) /* FAT16 root dir */
2093 seeksector += fat_bpb->rootdiroffset;
2094 #endif
2096 file->eof = false;
2097 if (seeksector) {
2098 /* we need to find the sector BEFORE the requested, since
2099 the file struct stores the last accessed sector */
2100 seeksector--;
2101 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2102 sectornum = seeksector % fat_bpb->bpb_secperclus;
2104 if (file->clusternum && clusternum >= file->clusternum)
2106 cluster = file->lastcluster;
2107 numclusters -= file->clusternum;
2110 for (i=0; i<numclusters; i++) {
2111 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2112 if (!cluster) {
2113 DEBUGF("Seeking beyond the end of the file! "
2114 "(sector %d, cluster %d)\n", seeksector, i);
2115 return -1;
2119 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2121 else {
2122 sectornum = -1;
2125 LDEBUGF("fat_seek(%x, %x) == %x, %x, %x\n",
2126 file->firstcluster, seeksector, cluster, sector, sectornum);
2128 file->lastcluster = cluster;
2129 file->lastsector = sector;
2130 file->clusternum = clusternum;
2131 file->sectornum = sectornum + 1;
2132 return 0;
2135 int fat_opendir(IF_MV2(int volume,)
2136 struct fat_dir *dir, unsigned int startcluster,
2137 const struct fat_dir *parent_dir)
2139 #ifdef HAVE_MULTIVOLUME
2140 struct bpb* fat_bpb = &fat_bpbs[volume];
2141 /* fixme: remove error check when done */
2142 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2144 LDEBUGF("fat_open() illegal volume %d\n", volume);
2145 return -1;
2147 #else
2148 struct bpb* fat_bpb = &fat_bpbs[0];
2149 #endif
2150 int rc;
2152 dir->entry = 0;
2153 dir->sector = 0;
2155 if (startcluster == 0)
2156 startcluster = fat_bpb->bpb_rootclus;
2158 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2159 if(rc)
2161 DEBUGF( "fat_opendir() - Couldn't open dir"
2162 " (error code %d)\n", rc);
2163 return rc * 10 - 1;
2166 return 0;
2169 /* convert from unicode to a single-byte charset */
2170 static void unicode2iso(const unsigned char* unicode, unsigned char* iso,
2171 int count)
2173 int i;
2175 for (i=0; i<count; i++) {
2176 int x = i*2;
2177 switch (unicode[x+1]) {
2178 case 0x01: /* latin extended. convert to ISO 8859-2 */
2179 case 0x02:
2180 iso[i] = unicode2iso8859_2[unicode[x]];
2181 break;
2183 case 0x03: /* greek, convert to ISO 8859-7 */
2184 iso[i] = unicode[x] + 0x30;
2185 break;
2187 /* Sergei says most russians use Win1251, so we will too.
2188 Win1251 differs from ISO 8859-5 by an offset of 0x10. */
2189 case 0x04: /* cyrillic, convert to Win1251 */
2190 switch (unicode[x]) {
2191 case 1:
2192 iso[i] = 168;
2193 break;
2195 case 81:
2196 iso[i] = 184;
2197 break;
2199 default:
2200 iso[i] = unicode[x] + 0xb0; /* 0xa0 for ISO 8859-5 */
2201 break;
2203 break;
2205 case 0x05: /* hebrew, convert to ISO 8859-8 */
2206 iso[i] = unicode[x] + 0x10;
2207 break;
2209 case 0x06: /* arabic, convert to ISO 8859-6 */
2210 case 0x0e: /* thai, convert to ISO 8859-11 */
2211 iso[i] = unicode[x] + 0xa0;
2212 break;
2214 default:
2215 iso[i] = unicode[x];
2216 break;
2221 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2223 bool done = false;
2224 int i;
2225 int rc;
2226 unsigned char firstbyte;
2227 int longarray[20];
2228 int longs=0;
2229 int sectoridx=0;
2230 unsigned char* cached_buf = dir->sectorcache[0];
2232 dir->entrycount = 0;
2234 while(!done)
2236 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2238 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2239 if (rc == 0) {
2240 /* eof */
2241 entry->name[0] = 0;
2242 break;
2244 if (rc < 0) {
2245 DEBUGF( "fat_getnext() - Couldn't read dir"
2246 " (error code %d)\n", rc);
2247 return rc * 10 - 1;
2249 dir->sector = dir->file.lastsector;
2252 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2253 i < DIR_ENTRIES_PER_SECTOR; i++)
2255 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2257 firstbyte = cached_buf[entrypos];
2258 dir->entry++;
2260 if (firstbyte == 0xe5) {
2261 /* free entry */
2262 sectoridx = 0;
2263 dir->entrycount = 0;
2264 continue;
2267 if (firstbyte == 0) {
2268 /* last entry */
2269 entry->name[0] = 0;
2270 dir->entrycount = 0;
2271 return 0;
2274 dir->entrycount++;
2276 /* longname entry? */
2277 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2278 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2279 longarray[longs++] = entrypos + sectoridx;
2281 else {
2282 if ( parse_direntry(entry,
2283 &cached_buf[entrypos]) ) {
2285 /* don't return volume id entry */
2286 if ( entry->attr == FAT_ATTR_VOLUME_ID )
2287 continue;
2289 /* replace shortname with longname? */
2290 if ( longs ) {
2291 int j,l=0;
2292 /* iterate backwards through the dir entries */
2293 for (j=longs-1; j>=0; j--) {
2294 unsigned char* ptr = cached_buf;
2295 int index = longarray[j];
2296 /* current or cached sector? */
2297 if ( sectoridx >= SECTOR_SIZE ) {
2298 if ( sectoridx >= SECTOR_SIZE*2 ) {
2299 if ( ( index >= SECTOR_SIZE ) &&
2300 ( index < SECTOR_SIZE*2 ))
2301 ptr = dir->sectorcache[1];
2302 else
2303 ptr = dir->sectorcache[2];
2305 else {
2306 if ( index < SECTOR_SIZE )
2307 ptr = dir->sectorcache[1];
2310 index &= SECTOR_SIZE-1;
2313 /* names are stored in unicode, but we
2314 only grab the low byte (iso8859-1). */
2315 unicode2iso(ptr + index + 1, entry->name + l, 5);
2316 l+= 5;
2317 unicode2iso(ptr + index + 14, entry->name + l, 6);
2318 l+= 6;
2319 unicode2iso(ptr + index + 28, entry->name + l, 2);
2320 l+= 2;
2322 entry->name[l]=0;
2324 done = true;
2325 sectoridx = 0;
2326 i++;
2327 break;
2332 /* save this sector, for longname use */
2333 if ( sectoridx )
2334 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2335 else
2336 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2337 sectoridx += SECTOR_SIZE;
2340 return 0;
2343 int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2345 #ifndef HAVE_MULTIVOLUME
2346 const int volume = 0;
2347 #endif
2348 struct bpb* fat_bpb = &fat_bpbs[volume];
2349 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2352 #ifdef HAVE_MULTIVOLUME
2353 bool fat_ismounted(int volume)
2355 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2357 #endif