Simulate the effects of sector caching a bit. Bypass I/O yield if a byte counter...
[Rockbox.git] / firmware / drivers / fat.c
blobdd0d4d650e5de88dd95da69c0c2e9d7c4d333ef2
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"
31 #include "rbunicode.h"
32 #include "logf.h"
33 #include "atoi.h"
35 #define BYTES2INT16(array,pos) \
36 (array[pos] | (array[pos+1] << 8 ))
37 #define BYTES2INT32(array,pos) \
38 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
39 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
41 #define FATTYPE_FAT12 0
42 #define FATTYPE_FAT16 1
43 #define FATTYPE_FAT32 2
45 /* BPB offsets; generic */
46 #define BS_JMPBOOT 0
47 #define BS_OEMNAME 3
48 #define BPB_BYTSPERSEC 11
49 #define BPB_SECPERCLUS 13
50 #define BPB_RSVDSECCNT 14
51 #define BPB_NUMFATS 16
52 #define BPB_ROOTENTCNT 17
53 #define BPB_TOTSEC16 19
54 #define BPB_MEDIA 21
55 #define BPB_FATSZ16 22
56 #define BPB_SECPERTRK 24
57 #define BPB_NUMHEADS 26
58 #define BPB_HIDDSEC 28
59 #define BPB_TOTSEC32 32
61 /* fat12/16 */
62 #define BS_DRVNUM 36
63 #define BS_RESERVED1 37
64 #define BS_BOOTSIG 38
65 #define BS_VOLID 39
66 #define BS_VOLLAB 43
67 #define BS_FILSYSTYPE 54
69 /* fat32 */
70 #define BPB_FATSZ32 36
71 #define BPB_EXTFLAGS 40
72 #define BPB_FSVER 42
73 #define BPB_ROOTCLUS 44
74 #define BPB_FSINFO 48
75 #define BPB_BKBOOTSEC 50
76 #define BS_32_DRVNUM 64
77 #define BS_32_BOOTSIG 66
78 #define BS_32_VOLID 67
79 #define BS_32_VOLLAB 71
80 #define BS_32_FILSYSTYPE 82
82 #define BPB_LAST_WORD 510
85 /* attributes */
86 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
87 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
88 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
90 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
92 /* NTRES flags */
93 #define FAT_NTRES_LC_NAME 0x08
94 #define FAT_NTRES_LC_EXT 0x10
96 #define FATDIR_NAME 0
97 #define FATDIR_ATTR 11
98 #define FATDIR_NTRES 12
99 #define FATDIR_CRTTIMETENTH 13
100 #define FATDIR_CRTTIME 14
101 #define FATDIR_CRTDATE 16
102 #define FATDIR_LSTACCDATE 18
103 #define FATDIR_FSTCLUSHI 20
104 #define FATDIR_WRTTIME 22
105 #define FATDIR_WRTDATE 24
106 #define FATDIR_FSTCLUSLO 26
107 #define FATDIR_FILESIZE 28
109 #define FATLONG_ORDER 0
110 #define FATLONG_TYPE 12
111 #define FATLONG_CHKSUM 13
113 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
114 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
115 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
116 #define DIR_ENTRY_SIZE 32
117 #define NAME_BYTES_PER_ENTRY 13
118 #define FAT_BAD_MARK 0x0ffffff7
119 #define FAT_EOF_MARK 0x0ffffff8
120 #define FAT_LONGNAME_PAD_BYTE 0xff
121 #define FAT_LONGNAME_PAD_UCS 0xffff
123 struct fsinfo {
124 unsigned long freecount; /* last known free cluster count */
125 unsigned long nextfree; /* first cluster to start looking for free
126 clusters, or 0xffffffff for no hint */
128 /* fsinfo offsets */
129 #define FSINFO_FREECOUNT 488
130 #define FSINFO_NEXTFREE 492
132 /* Note: This struct doesn't hold the raw values after mounting if
133 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
134 * physical sectors. */
135 struct bpb
137 int bpb_bytspersec; /* Bytes per sector, typically 512 */
138 unsigned int bpb_secperclus; /* Sectors per cluster */
139 int bpb_rsvdseccnt; /* Number of reserved sectors */
140 int bpb_numfats; /* Number of FAT structures, typically 2 */
141 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
142 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
143 int bpb_fatsz16; /* Number of used sectors per FAT structure */
144 unsigned long bpb_totsec32; /* Number of sectors on the volume
145 (new 32-bit) */
146 unsigned int last_word; /* 0xAA55 */
148 /**** FAT32 specific *****/
149 long bpb_fatsz32;
150 long bpb_rootclus;
151 long bpb_fsinfo;
153 /* variables for internal use */
154 unsigned long fatsize;
155 unsigned long totalsectors;
156 unsigned long rootdirsector;
157 unsigned long firstdatasector;
158 unsigned long startsector;
159 unsigned long dataclusters;
160 struct fsinfo fsinfo;
161 #ifdef HAVE_FAT16SUPPORT
162 int bpb_rootentcnt; /* Number of dir entries in the root */
163 /* internals for FAT16 support */
164 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
165 unsigned int rootdiroffset; /* sector offset of root dir relative to start
166 * of first pseudo cluster */
167 #endif /* #ifdef HAVE_FAT16SUPPORT */
168 #ifdef HAVE_MULTIVOLUME
169 int drive; /* on which physical device is this located */
170 bool mounted; /* flag if this volume is mounted */
171 #endif
174 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
176 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
177 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
178 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
179 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
180 long secnum, bool dirty);
181 static void create_dos_name(const unsigned char *name, unsigned char *newname);
182 static void randomize_dos_name(unsigned char *name);
183 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
184 unsigned long start);
185 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
186 long count, char* buf, bool write );
188 #define FAT_CACHE_SIZE 0x20
189 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
191 struct fat_cache_entry
193 long secnum;
194 bool inuse;
195 bool dirty;
196 #ifdef HAVE_MULTIVOLUME
197 struct bpb* fat_vol ; /* shared cache for all volumes */
198 #endif
201 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
202 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
203 static struct mutex cache_mutex NOCACHEBSS_ATTR;
205 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
207 #ifndef HAVE_MULTIVOLUME
208 struct bpb* fat_bpb = &fat_bpbs[0];
209 #endif
210 #ifdef HAVE_FAT16SUPPORT
211 /* negative clusters (FAT16 root dir) don't get the 2 offset */
212 int zerocluster = cluster < 0 ? 0 : 2;
213 #else
214 const long zerocluster = 2;
215 #endif
217 if (cluster > (long)(fat_bpb->dataclusters + 1))
219 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
220 return -1;
223 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
224 + fat_bpb->firstdatasector;
227 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
229 #ifndef HAVE_MULTIVOLUME
230 const int volume = 0;
231 #endif
232 struct bpb* fat_bpb = &fat_bpbs[volume];
233 if (size)
234 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
235 if (free)
236 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
239 void fat_init(void)
241 unsigned int i;
243 mutex_init(&cache_mutex);
245 /* mark the FAT cache as unused */
246 for(i = 0;i < FAT_CACHE_SIZE;i++)
248 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
249 fat_cache[i].inuse = false;
250 fat_cache[i].dirty = false;
251 #ifdef HAVE_MULTIVOLUME
252 fat_cache[i].fat_vol = NULL;
253 #endif
255 #ifdef HAVE_MULTIVOLUME
256 /* mark the possible volumes as not mounted */
257 for (i=0; i<NUM_VOLUMES;i++)
259 fat_bpbs[i].mounted = false;
261 #endif
264 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
266 #ifndef HAVE_MULTIVOLUME
267 const int volume = 0;
268 #endif
269 struct bpb* fat_bpb = &fat_bpbs[volume];
270 unsigned char buf[SECTOR_SIZE];
271 int rc;
272 int secmult;
273 long datasec;
274 #ifdef HAVE_FAT16SUPPORT
275 int rootdirsectors;
276 #endif
278 /* Read the sector */
279 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
280 if(rc)
282 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
283 return rc * 10 - 1;
286 memset(fat_bpb, 0, sizeof(struct bpb));
287 fat_bpb->startsector = startsector;
288 #ifdef HAVE_MULTIVOLUME
289 fat_bpb->drive = drive;
290 #endif
292 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
293 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
294 /* Sanity check is performed later */
296 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
297 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
298 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
299 fat_bpb->bpb_media = buf[BPB_MEDIA];
300 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
301 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
302 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
303 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
304 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
306 /* calculate a few commonly used values */
307 if (fat_bpb->bpb_fatsz16 != 0)
308 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
309 else
310 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
312 if (fat_bpb->bpb_totsec16 != 0)
313 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
314 else
315 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
317 #ifdef HAVE_FAT16SUPPORT
318 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
319 if (!fat_bpb->bpb_bytspersec)
320 return -2;
321 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
322 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
323 #endif /* #ifdef HAVE_FAT16SUPPORT */
325 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
326 #ifdef HAVE_FAT16SUPPORT
327 + rootdirsectors
328 #endif
329 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
331 /* Determine FAT type */
332 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
333 if (fat_bpb->bpb_secperclus)
334 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
335 else
336 return -2;
338 #ifdef TEST_FAT
340 we are sometimes testing with "illegally small" fat32 images,
341 so we don't use the proper fat32 test case for test code
343 if ( fat_bpb->bpb_fatsz16 )
344 #else
345 if ( fat_bpb->dataclusters < 65525 )
346 #endif
347 { /* FAT16 */
348 #ifdef HAVE_FAT16SUPPORT
349 fat_bpb->is_fat16 = true;
350 if (fat_bpb->dataclusters < 4085)
351 { /* FAT12 */
352 DEBUGF("This is FAT12. Go away!\n");
353 return -2;
355 #else /* #ifdef HAVE_FAT16SUPPORT */
356 DEBUGF("This is not FAT32. Go away!\n");
357 return -2;
358 #endif /* #ifndef HAVE_FAT16SUPPORT */
361 #ifdef HAVE_FAT16SUPPORT
362 if (fat_bpb->is_fat16)
363 { /* FAT16 specific part of BPB */
364 int dirclusters;
365 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
366 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
367 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
368 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
369 /* I assign negative pseudo cluster numbers for the root directory,
370 their range is counted upward until -1. */
371 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
372 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
373 - rootdirsectors;
375 else
376 #endif /* #ifdef HAVE_FAT16SUPPORT */
377 { /* FAT32 specific part of BPB */
378 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
379 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
380 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
381 fat_bpb->bpb_rootclus);
384 rc = bpb_is_sane(IF_MV(fat_bpb));
385 if (rc < 0)
387 DEBUGF( "fat_mount() - BPB is not sane\n");
388 return rc * 10 - 3;
391 #ifdef HAVE_FAT16SUPPORT
392 if (fat_bpb->is_fat16)
394 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
395 fat_bpb->fsinfo.nextfree = 0xffffffff;
397 else
398 #endif /* #ifdef HAVE_FAT16SUPPORT */
400 /* Read the fsinfo sector */
401 rc = ata_read_sectors(IF_MV2(drive,)
402 startsector + fat_bpb->bpb_fsinfo, 1, buf);
403 if (rc < 0)
405 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
406 return rc * 10 - 4;
408 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
409 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
412 /* calculate freecount if unset */
413 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
415 fat_recalc_free(IF_MV(volume));
418 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
419 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
420 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
421 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
422 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
424 #ifdef HAVE_MULTIVOLUME
425 fat_bpb->mounted = true;
426 #endif
428 return 0;
431 #ifdef HAVE_HOTSWAP
432 int fat_unmount(int volume, bool flush)
434 int rc;
435 struct bpb* fat_bpb = &fat_bpbs[volume];
437 if(flush)
439 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
441 else
442 { /* volume is not accessible any more, e.g. MMC removed */
443 int i;
444 mutex_lock(&cache_mutex);
445 for(i = 0;i < FAT_CACHE_SIZE;i++)
447 struct fat_cache_entry *fce = &fat_cache[i];
448 if(fce->inuse && fce->fat_vol == fat_bpb)
450 fce->inuse = false; /* discard all from that volume */
451 fce->dirty = false;
454 mutex_unlock(&cache_mutex);
455 rc = 0;
457 fat_bpb->mounted = false;
458 return rc;
460 #endif /* #ifdef HAVE_HOTSWAP */
462 void fat_recalc_free(IF_MV_NONVOID(int volume))
464 #ifndef HAVE_MULTIVOLUME
465 const int volume = 0;
466 #endif
467 struct bpb* fat_bpb = &fat_bpbs[volume];
468 long free = 0;
469 unsigned long i;
470 #ifdef HAVE_FAT16SUPPORT
471 if (fat_bpb->is_fat16)
473 for (i = 0; i<fat_bpb->fatsize; i++) {
474 unsigned int j;
475 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
476 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
477 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
478 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
479 break;
481 if (letoh16(fat[j]) == 0x0000) {
482 free++;
483 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
484 fat_bpb->fsinfo.nextfree = c;
489 else
490 #endif /* #ifdef HAVE_FAT16SUPPORT */
492 for (i = 0; i<fat_bpb->fatsize; i++) {
493 unsigned int j;
494 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
495 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
496 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
497 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
498 break;
500 if (!(letoh32(fat[j]) & 0x0fffffff)) {
501 free++;
502 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
503 fat_bpb->fsinfo.nextfree = c;
508 fat_bpb->fsinfo.freecount = free;
509 update_fsinfo(IF_MV(fat_bpb));
512 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
514 #ifndef HAVE_MULTIVOLUME
515 struct bpb* fat_bpb = &fat_bpbs[0];
516 #endif
517 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
519 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
520 fat_bpb->bpb_bytspersec);
521 return -1;
523 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
524 > 128L*1024L)
526 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
527 "(%d * %d = %d)\n",
528 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
529 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
530 return -2;
532 if(fat_bpb->bpb_numfats != 2)
534 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
535 fat_bpb->bpb_numfats);
537 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
539 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
540 "media type (0x%02x)\n",
541 fat_bpb->bpb_media);
543 if(fat_bpb->last_word != 0xaa55)
545 DEBUGF( "bpb_is_sane() - Error: Last word is not "
546 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
547 return -3;
550 if (fat_bpb->fsinfo.freecount >
551 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
552 fat_bpb->bpb_secperclus)
554 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
555 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
556 return -4;
559 return 0;
562 static void flush_fat_sector(struct fat_cache_entry *fce,
563 unsigned char *sectorbuf)
565 int rc;
566 long secnum;
568 /* With multivolume, use only the FAT info from the cached sector! */
569 #ifdef HAVE_MULTIVOLUME
570 secnum = fce->secnum + fce->fat_vol->startsector;
571 #else
572 secnum = fce->secnum + fat_bpbs[0].startsector;
573 #endif
575 /* Write to the first FAT */
576 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
577 secnum, 1,
578 sectorbuf);
579 if(rc < 0)
581 panicf("flush_fat_sector() - Could not write sector %ld"
582 " (error %d)\n",
583 secnum, rc);
585 #ifdef HAVE_MULTIVOLUME
586 if(fce->fat_vol->bpb_numfats > 1)
587 #else
588 if(fat_bpbs[0].bpb_numfats > 1)
589 #endif
591 /* Write to the second FAT */
592 #ifdef HAVE_MULTIVOLUME
593 secnum += fce->fat_vol->fatsize;
594 #else
595 secnum += fat_bpbs[0].fatsize;
596 #endif
597 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
598 secnum, 1, sectorbuf);
599 if(rc < 0)
601 panicf("flush_fat_sector() - Could not write sector %ld"
602 " (error %d)\n",
603 secnum, rc);
606 fce->dirty = false;
609 /* Note: The returned pointer is only safely valid until the next
610 task switch! (Any subsequent ata read/write may yield.) */
611 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
612 long fatsector, bool dirty)
614 #ifndef HAVE_MULTIVOLUME
615 struct bpb* fat_bpb = &fat_bpbs[0];
616 #endif
617 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
618 int cache_index = secnum & FAT_CACHE_MASK;
619 struct fat_cache_entry *fce = &fat_cache[cache_index];
620 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
621 int rc;
623 mutex_lock(&cache_mutex); /* make changes atomic */
625 /* Delete the cache entry if it isn't the sector we want */
626 if(fce->inuse && (fce->secnum != secnum
627 #ifdef HAVE_MULTIVOLUME
628 || fce->fat_vol != fat_bpb
629 #endif
632 /* Write back if it is dirty */
633 if(fce->dirty)
635 flush_fat_sector(fce, sectorbuf);
637 fce->inuse = false;
640 /* Load the sector if it is not cached */
641 if(!fce->inuse)
643 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
644 secnum + fat_bpb->startsector,1,
645 sectorbuf);
646 if(rc < 0)
648 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
649 " (error %d)\n", secnum, rc);
650 mutex_unlock(&cache_mutex);
651 return NULL;
653 fce->inuse = true;
654 fce->secnum = secnum;
655 #ifdef HAVE_MULTIVOLUME
656 fce->fat_vol = fat_bpb;
657 #endif
659 if (dirty)
660 fce->dirty = true; /* dirt remains, sticky until flushed */
661 mutex_unlock(&cache_mutex);
662 return sectorbuf;
665 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
666 unsigned long startcluster)
668 #ifndef HAVE_MULTIVOLUME
669 struct bpb* fat_bpb = &fat_bpbs[0];
670 #endif
671 unsigned long sector;
672 unsigned long offset;
673 unsigned long i;
675 #ifdef HAVE_FAT16SUPPORT
676 if (fat_bpb->is_fat16)
678 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
679 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
681 for (i = 0; i<fat_bpb->fatsize; i++) {
682 unsigned int j;
683 unsigned int nr = (i + sector) % fat_bpb->fatsize;
684 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
685 if ( !fat )
686 break;
687 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
688 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
689 if (letoh16(fat[k]) == 0x0000) {
690 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
691 /* Ignore the reserved clusters 0 & 1, and also
692 cluster numbers out of bounds */
693 if ( c < 2 || c > fat_bpb->dataclusters+1 )
694 continue;
695 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
696 fat_bpb->fsinfo.nextfree = c;
697 return c;
700 offset = 0;
703 else
704 #endif /* #ifdef HAVE_FAT16SUPPORT */
706 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
707 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
709 for (i = 0; i<fat_bpb->fatsize; i++) {
710 unsigned int j;
711 unsigned long nr = (i + sector) % fat_bpb->fatsize;
712 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
713 if ( !fat )
714 break;
715 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
716 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
717 if (!(letoh32(fat[k]) & 0x0fffffff)) {
718 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
719 /* Ignore the reserved clusters 0 & 1, and also
720 cluster numbers out of bounds */
721 if ( c < 2 || c > fat_bpb->dataclusters+1 )
722 continue;
723 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
724 fat_bpb->fsinfo.nextfree = c;
725 return c;
728 offset = 0;
732 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
733 return 0; /* 0 is an illegal cluster number */
736 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
737 unsigned long val)
739 #ifndef HAVE_MULTIVOLUME
740 struct bpb* fat_bpb = &fat_bpbs[0];
741 #endif
742 #ifdef HAVE_FAT16SUPPORT
743 if (fat_bpb->is_fat16)
745 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
746 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
747 unsigned short* sec;
749 val &= 0xFFFF;
751 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
753 if (entry==val)
754 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
756 if ( entry < 2 )
757 panicf("Updating reserved FAT entry %ld.\n",entry);
759 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
760 if (!sec)
762 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
763 return -1;
766 if ( val ) {
767 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
768 fat_bpb->fsinfo.freecount--;
770 else {
771 if (letoh16(sec[offset]))
772 fat_bpb->fsinfo.freecount++;
775 LDEBUGF("update_fat_entry: %d free clusters\n",
776 fat_bpb->fsinfo.freecount);
778 sec[offset] = htole16(val);
780 else
781 #endif /* #ifdef HAVE_FAT16SUPPORT */
783 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
784 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
785 unsigned long* sec;
787 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
789 if (entry==val)
790 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
792 if ( entry < 2 )
793 panicf("Updating reserved FAT entry %ld.\n",entry);
795 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
796 if (!sec)
798 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
799 return -1;
802 if ( val ) {
803 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
804 fat_bpb->fsinfo.freecount > 0)
805 fat_bpb->fsinfo.freecount--;
807 else {
808 if (letoh32(sec[offset]) & 0x0fffffff)
809 fat_bpb->fsinfo.freecount++;
812 LDEBUGF("update_fat_entry: %ld free clusters\n",
813 fat_bpb->fsinfo.freecount);
815 /* don't change top 4 bits */
816 sec[offset] &= htole32(0xf0000000);
817 sec[offset] |= htole32(val & 0x0fffffff);
820 return 0;
823 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
825 #ifdef HAVE_FAT16SUPPORT
826 #ifndef HAVE_MULTIVOLUME
827 struct bpb* fat_bpb = &fat_bpbs[0];
828 #endif
829 if (fat_bpb->is_fat16)
831 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
832 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
833 unsigned short* sec;
835 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
836 if (!sec)
838 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
839 return -1;
842 return letoh16(sec[offset]);
844 else
845 #endif /* #ifdef HAVE_FAT16SUPPORT */
847 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
848 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
849 unsigned long* sec;
851 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
852 if (!sec)
854 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
855 return -1;
858 return letoh32(sec[offset]) & 0x0fffffff;
862 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
864 long next_cluster;
865 long eof_mark = FAT_EOF_MARK;
867 #ifdef HAVE_FAT16SUPPORT
868 #ifndef HAVE_MULTIVOLUME
869 struct bpb* fat_bpb = &fat_bpbs[0];
870 #endif
871 if (fat_bpb->is_fat16)
873 eof_mark &= 0xFFFF; /* only 16 bit */
874 if (cluster < 0) /* FAT16 root dir */
875 return cluster + 1; /* don't use the FAT */
877 #endif
878 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
880 /* is this last cluster in chain? */
881 if ( next_cluster >= eof_mark )
882 return 0;
883 else
884 return next_cluster;
887 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
889 #ifndef HAVE_MULTIVOLUME
890 struct bpb* fat_bpb = &fat_bpbs[0];
891 #endif
892 unsigned char fsinfo[SECTOR_SIZE];
893 unsigned long* intptr;
894 int rc;
896 #ifdef HAVE_FAT16SUPPORT
897 if (fat_bpb->is_fat16)
898 return 0; /* FAT16 has no FsInfo */
899 #endif /* #ifdef HAVE_FAT16SUPPORT */
901 /* update fsinfo */
902 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
903 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
904 if (rc < 0)
906 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
907 return rc * 10 - 1;
909 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
910 *intptr = htole32(fat_bpb->fsinfo.freecount);
912 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
913 *intptr = htole32(fat_bpb->fsinfo.nextfree);
915 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
916 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
917 if (rc < 0)
919 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
920 return rc * 10 - 2;
923 return 0;
926 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
928 int i;
929 int rc;
930 unsigned char *sec;
931 LDEBUGF("flush_fat()\n");
933 mutex_lock(&cache_mutex);
934 for(i = 0;i < FAT_CACHE_SIZE;i++)
936 struct fat_cache_entry *fce = &fat_cache[i];
937 if(fce->inuse
938 #ifdef HAVE_MULTIVOLUME
939 && fce->fat_vol == fat_bpb
940 #endif
941 && fce->dirty)
943 sec = fat_cache_sectors[i];
944 flush_fat_sector(fce, sec);
947 mutex_unlock(&cache_mutex);
949 rc = update_fsinfo(IF_MV(fat_bpb));
950 if (rc < 0)
951 return rc * 10 - 3;
953 return 0;
956 static void fat_time(unsigned short* date,
957 unsigned short* time,
958 unsigned short* tenth )
960 #if CONFIG_RTC
961 struct tm* tm = get_time();
963 if (date)
964 *date = ((tm->tm_year - 80) << 9) |
965 ((tm->tm_mon + 1) << 5) |
966 tm->tm_mday;
968 if (time)
969 *time = (tm->tm_hour << 11) |
970 (tm->tm_min << 5) |
971 (tm->tm_sec >> 1);
973 if (tenth)
974 *tenth = (tm->tm_sec & 1) * 100;
975 #else
976 /* non-RTC version returns an increment from the supplied time, or a
977 * fixed standard time/date if no time given as input */
978 bool next_day = false;
980 if (time)
982 if (0 == *time)
984 /* set to 00:15:00 */
985 *time = (15 << 5);
987 else
989 unsigned short mins = (*time >> 5) & 0x003F;
990 unsigned short hours = (*time >> 11) & 0x001F;
991 if ((mins += 10) >= 60)
993 mins = 0;
994 hours++;
996 if ((++hours) >= 24)
998 hours = hours - 24;
999 next_day = true;
1001 *time = (hours << 11) | (mins << 5);
1005 if (date)
1007 if (0 == *date)
1009 /* Macros to convert a 2-digit string to a decimal constant.
1010 (YEAR), MONTH and DAY are set by the date command, which outputs
1011 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1012 misinterpretation as an octal constant. */
1013 #define S100(x) 1 ## x
1014 #define C2DIG2DEC(x) (S100(x)-100)
1015 /* set to build date */
1016 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1017 | C2DIG2DEC(DAY);
1019 else
1021 unsigned short day = *date & 0x001F;
1022 unsigned short month = (*date >> 5) & 0x000F;
1023 unsigned short year = (*date >> 9) & 0x007F;
1024 if (next_day)
1026 /* do a very simple day increment - never go above 28 days */
1027 if (++day > 28)
1029 day = 1;
1030 if (++month > 12)
1032 month = 1;
1033 year++;
1036 *date = (year << 9) | (month << 5) | day;
1040 if (tenth)
1041 *tenth = 0;
1042 #endif /* CONFIG_RTC */
1045 static int write_long_name(struct fat_file* file,
1046 unsigned int firstentry,
1047 unsigned int numentries,
1048 const unsigned char* name,
1049 const unsigned char* shortname,
1050 bool is_directory)
1052 unsigned char buf[SECTOR_SIZE];
1053 unsigned char* entry;
1054 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1055 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1056 unsigned char chksum = 0;
1057 unsigned int i, j=0;
1058 unsigned int nameidx=0, namelen = utf8length(name);
1059 int rc;
1060 unsigned short name_utf16[namelen + 1];
1062 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1063 file->firstcluster, firstentry, numentries, name);
1065 rc = fat_seek(file, sector);
1066 if (rc<0)
1067 return rc * 10 - 1;
1069 rc = fat_readwrite(file, 1, buf, false);
1070 if (rc<1)
1071 return rc * 10 - 2;
1073 /* calculate shortname checksum */
1074 for (i=11; i>0; i--)
1075 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1077 /* calc position of last name segment */
1078 if ( namelen > NAME_BYTES_PER_ENTRY )
1079 for (nameidx=0;
1080 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1081 nameidx += NAME_BYTES_PER_ENTRY);
1083 /* we need to convert the name first */
1084 /* since it is written in reverse order */
1085 for (i = 0; i <= namelen; i++)
1086 name = utf8decode(name, &name_utf16[i]);
1088 for (i=0; i < numentries; i++) {
1089 /* new sector? */
1090 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1091 /* update current sector */
1092 rc = fat_seek(file, sector);
1093 if (rc<0)
1094 return rc * 10 - 3;
1096 rc = fat_readwrite(file, 1, buf, true);
1097 if (rc<1)
1098 return rc * 10 - 4;
1100 /* read next sector */
1101 rc = fat_readwrite(file, 1, buf, false);
1102 if (rc<0) {
1103 LDEBUGF("Failed writing new sector: %d\n",rc);
1104 return rc * 10 - 5;
1106 if (rc==0)
1107 /* end of dir */
1108 memset(buf, 0, sizeof buf);
1110 sector++;
1111 idx = 0;
1114 entry = buf + idx * DIR_ENTRY_SIZE;
1116 /* verify this entry is free */
1117 if (entry[0] && entry[0] != 0xe5 )
1118 panicf("Dir entry %d in sector %x is not free! "
1119 "%02x %02x %02x %02x",
1120 idx, sector,
1121 entry[0], entry[1], entry[2], entry[3]);
1123 memset(entry, 0, DIR_ENTRY_SIZE);
1124 if ( i+1 < numentries ) {
1125 /* longname entry */
1126 unsigned int k, l = nameidx;
1128 entry[FATLONG_ORDER] = numentries-i-1;
1129 if (i==0) {
1130 /* mark this as last long entry */
1131 entry[FATLONG_ORDER] |= 0x40;
1133 /* pad name with 0xffff */
1134 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1135 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1136 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1138 /* set name */
1139 for (k=0; k<5 && l <= namelen; k++) {
1140 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1141 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1143 for (k=0; k<6 && l <= namelen; k++) {
1144 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1145 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1147 for (k=0; k<2 && l <= namelen; k++) {
1148 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1149 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1152 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1153 entry[FATDIR_FSTCLUSLO] = 0;
1154 entry[FATLONG_TYPE] = 0;
1155 entry[FATLONG_CHKSUM] = chksum;
1156 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1158 else {
1159 /* shortname entry */
1160 unsigned short date=0, time=0, tenth=0;
1161 LDEBUGF("Shortname entry: %s\n", shortname);
1162 strncpy(entry + FATDIR_NAME, shortname, 11);
1163 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1164 entry[FATDIR_NTRES] = 0;
1166 fat_time(&date, &time, &tenth);
1167 entry[FATDIR_CRTTIMETENTH] = tenth;
1168 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1169 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1170 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1171 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1172 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1174 idx++;
1175 nameidx -= NAME_BYTES_PER_ENTRY;
1178 /* update last sector */
1179 rc = fat_seek(file, sector);
1180 if (rc<0)
1181 return rc * 10 - 6;
1183 rc = fat_readwrite(file, 1, buf, true);
1184 if (rc<1)
1185 return rc * 10 - 7;
1187 return 0;
1190 static int fat_checkname(const unsigned char* newname)
1192 static const char invalid_chars[] = "\"*/:<>?\\|";
1193 int len = strlen(newname);
1194 /* More sanity checks are probably needed */
1195 if (len > 255 || newname[len - 1] == '.')
1197 return -1;
1199 while (*newname)
1201 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1202 return -1;
1203 newname++;
1205 return 0;
1208 static int add_dir_entry(struct fat_dir* dir,
1209 struct fat_file* file,
1210 const char* name,
1211 bool is_directory,
1212 bool dotdir)
1214 #ifdef HAVE_MULTIVOLUME
1215 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1216 #else
1217 struct bpb* fat_bpb = &fat_bpbs[0];
1218 #endif
1219 unsigned char buf[SECTOR_SIZE];
1220 unsigned char shortname[12];
1221 int rc;
1222 unsigned int sector;
1223 bool done = false;
1224 int entries_needed, entries_found = 0;
1225 int firstentry;
1227 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1228 name, file->firstcluster);
1230 /* Don't check dotdirs name for validity */
1231 if (dotdir == false) {
1232 rc = fat_checkname(name);
1233 if (rc < 0) {
1234 /* filename is invalid */
1235 return rc * 10 - 1;
1239 #ifdef HAVE_MULTIVOLUME
1240 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1241 #endif
1243 /* The "." and ".." directory entries must not be long names */
1244 if(dotdir) {
1245 int i;
1246 strncpy(shortname, name, 12);
1247 for(i = strlen(shortname); i < 12; i++)
1248 shortname[i] = ' ';
1250 entries_needed = 1;
1251 } else {
1252 create_dos_name(name, shortname);
1254 /* one dir entry needed for every 13 bytes of filename,
1255 plus one entry for the short name */
1256 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1257 / NAME_BYTES_PER_ENTRY + 1;
1260 restart:
1261 firstentry = -1;
1263 rc = fat_seek(&dir->file, 0);
1264 if (rc < 0)
1265 return rc * 10 - 2;
1267 /* step 1: search for free entries and check for duplicate shortname */
1268 for (sector = 0; !done; sector++)
1270 unsigned int i;
1272 rc = fat_readwrite(&dir->file, 1, buf, false);
1273 if (rc < 0) {
1274 DEBUGF( "add_dir_entry() - Couldn't read dir"
1275 " (error code %d)\n", rc);
1276 return rc * 10 - 3;
1279 if (rc == 0) { /* current end of dir reached */
1280 LDEBUGF("End of dir on cluster boundary\n");
1281 break;
1284 /* look for free slots */
1285 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1287 switch (buf[i * DIR_ENTRY_SIZE]) {
1288 case 0:
1289 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1290 LDEBUGF("Found end of dir %d\n",
1291 sector * DIR_ENTRIES_PER_SECTOR + i);
1292 i = DIR_ENTRIES_PER_SECTOR - 1;
1293 done = true;
1294 break;
1296 case 0xe5:
1297 entries_found++;
1298 LDEBUGF("Found free entry %d (%d/%d)\n",
1299 sector * DIR_ENTRIES_PER_SECTOR + i,
1300 entries_found, entries_needed);
1301 break;
1303 default:
1304 entries_found = 0;
1306 /* check that our intended shortname doesn't already exist */
1307 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1308 /* shortname exists already, make a new one */
1309 randomize_dos_name(shortname);
1310 LDEBUGF("Duplicate shortname, changing to %s\n",
1311 shortname);
1313 /* name has changed, we need to restart search */
1314 goto restart;
1316 break;
1318 if (firstentry < 0 && (entries_found >= entries_needed))
1319 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1320 - entries_found;
1324 /* step 2: extend the dir if necessary */
1325 if (firstentry < 0)
1327 LDEBUGF("Adding new sector(s) to dir\n");
1328 rc = fat_seek(&dir->file, sector);
1329 if (rc < 0)
1330 return rc * 10 - 4;
1331 memset(buf, 0, sizeof buf);
1333 /* we must clear whole clusters */
1334 for (; (entries_found < entries_needed) ||
1335 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1337 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1338 return -5; /* dir too large -- FAT specification */
1340 rc = fat_readwrite(&dir->file, 1, buf, true);
1341 if (rc < 1) /* No more room or something went wrong */
1342 return rc * 10 - 6;
1344 entries_found += DIR_ENTRIES_PER_SECTOR;
1347 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1350 /* step 3: add entry */
1351 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1352 LDEBUGF("Adding longname to entry %d in sector %d\n",
1353 firstentry, sector);
1355 rc = write_long_name(&dir->file, firstentry,
1356 entries_needed, name, shortname, is_directory);
1357 if (rc < 0)
1358 return rc * 10 - 7;
1360 /* remember where the shortname dir entry is located */
1361 file->direntry = firstentry + entries_needed - 1;
1362 file->direntries = entries_needed;
1363 file->dircluster = dir->file.firstcluster;
1364 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1365 file->direntry, file->direntries);
1367 return 0;
1370 static unsigned char char2dos(unsigned char c, int* randomize)
1372 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1374 if (c <= 0x20)
1375 c = 0; /* Illegal char, remove */
1376 else if (strchr(invalid_chars, c) != NULL)
1378 /* Illegal char, replace */
1379 c = '_';
1380 *randomize = 1; /* as per FAT spec */
1382 else
1383 c = toupper(c);
1385 return c;
1388 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1390 int i;
1391 unsigned char *ext;
1392 int randomize = 0;
1394 /* Find extension part */
1395 ext = strrchr(name, '.');
1396 if (ext == name) /* handle .dotnames */
1397 ext = NULL;
1399 /* needs to randomize? */
1400 if((ext && (strlen(ext) > 4)) ||
1401 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1402 randomize = 1;
1404 /* Name part */
1405 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1407 unsigned char c = char2dos(*name, &randomize);
1408 if (c)
1409 newname[i++] = c;
1412 /* Pad both name and extension */
1413 while (i < 11)
1414 newname[i++] = ' ';
1416 if (newname[0] == 0xe5) /* Special kanji character */
1417 newname[0] = 0x05;
1419 if (ext)
1420 { /* Extension part */
1421 ext++;
1422 for (i = 8; *ext && (i < 11); ext++)
1424 unsigned char c = char2dos(*ext, &randomize);
1425 if (c)
1426 newname[i++] = c;
1430 if(randomize)
1431 randomize_dos_name(newname);
1434 static void randomize_dos_name(unsigned char *name)
1436 unsigned char* tilde = NULL; /* ~ location */
1437 unsigned char* lastpt = NULL; /* last point of filename */
1438 unsigned char* nameptr = name; /* working copy of name pointer */
1439 unsigned char num[9]; /* holds number as string */
1440 int i = 0;
1441 int cnt = 1;
1442 int numlen;
1443 int offset;
1445 while(i++ < 8)
1447 /* hunt for ~ and where to put it */
1448 if((!tilde) && (*nameptr == '~'))
1449 tilde = nameptr;
1450 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1451 lastpt = nameptr;
1452 nameptr++;
1454 if(tilde)
1456 /* extract current count and increment */
1457 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1458 num[7-(unsigned int)(tilde-name)] = 0;
1459 cnt = atoi(num) + 1;
1461 cnt %= 10000000; /* protection */
1462 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1463 numlen = strlen(num); /* required space */
1464 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1465 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1467 memcpy(&name[offset], num, numlen);
1469 /* in special case of counter overflow: pad with spaces */
1470 for(offset = offset+numlen; offset < 8; offset++)
1471 name[offset] = ' ';
1474 static int update_short_entry( struct fat_file* file, long size, int attr )
1476 unsigned char buf[SECTOR_SIZE];
1477 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1478 unsigned char* entry =
1479 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1480 unsigned long* sizeptr;
1481 unsigned short* clusptr;
1482 struct fat_file dir;
1483 int rc;
1485 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1486 file->firstcluster, file->direntry, size);
1488 /* create a temporary file handle for the dir holding this file */
1489 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1490 if (rc < 0)
1491 return rc * 10 - 1;
1493 rc = fat_seek( &dir, sector );
1494 if (rc<0)
1495 return rc * 10 - 2;
1497 rc = fat_readwrite(&dir, 1, buf, false);
1498 if (rc < 1)
1499 return rc * 10 - 3;
1501 if (!entry[0] || entry[0] == 0xe5)
1502 panicf("Updating size on empty dir entry %d\n", file->direntry);
1504 entry[FATDIR_ATTR] = attr & 0xFF;
1506 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1507 *clusptr = htole16(file->firstcluster >> 16);
1509 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1510 *clusptr = htole16(file->firstcluster & 0xffff);
1512 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1513 *sizeptr = htole32(size);
1516 #if CONFIG_RTC
1517 unsigned short time = 0;
1518 unsigned short date = 0;
1519 #else
1520 /* get old time to increment from */
1521 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1522 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1523 #endif
1524 fat_time(&date, &time, NULL);
1525 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1526 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1527 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1530 rc = fat_seek( &dir, sector );
1531 if (rc < 0)
1532 return rc * 10 - 4;
1534 rc = fat_readwrite(&dir, 1, buf, true);
1535 if (rc < 1)
1536 return rc * 10 - 5;
1538 return 0;
1541 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1543 int i=0,j=0;
1544 unsigned char c;
1545 bool lowercase;
1547 memset(de, 0, sizeof(struct fat_direntry));
1548 de->attr = buf[FATDIR_ATTR];
1549 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1550 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1551 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1552 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1553 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1554 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1555 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1556 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1557 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1558 (the result of the shift is always considered signed) */
1560 /* fix the name */
1561 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1562 c = buf[FATDIR_NAME];
1563 if (c == 0x05) /* special kanji char */
1564 c = 0xe5;
1565 i = 0;
1566 while (c != ' ') {
1567 de->name[j++] = lowercase ? tolower(c) : c;
1568 if (++i >= 8)
1569 break;
1570 c = buf[FATDIR_NAME+i];
1572 if (buf[FATDIR_NAME+8] != ' ') {
1573 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1574 de->name[j++] = '.';
1575 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1576 de->name[j++] = lowercase ? tolower(c) : c;
1578 return 1;
1581 int fat_open(IF_MV2(int volume,)
1582 long startcluster,
1583 struct fat_file *file,
1584 const struct fat_dir* dir)
1586 file->firstcluster = startcluster;
1587 file->lastcluster = startcluster;
1588 file->lastsector = 0;
1589 file->clusternum = 0;
1590 file->sectornum = 0;
1591 file->eof = false;
1592 #ifdef HAVE_MULTIVOLUME
1593 file->volume = volume;
1594 /* fixme: remove error check when done */
1595 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1597 LDEBUGF("fat_open() illegal volume %d\n", volume);
1598 return -1;
1600 #endif
1602 /* remember where the file's dir entry is located */
1603 if ( dir ) {
1604 file->direntry = dir->entry - 1;
1605 file->direntries = dir->entrycount;
1606 file->dircluster = dir->file.firstcluster;
1608 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1609 return 0;
1612 int fat_create_file(const char* name,
1613 struct fat_file* file,
1614 struct fat_dir* dir)
1616 int rc;
1618 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1619 rc = add_dir_entry(dir, file, name, false, false);
1620 if (!rc) {
1621 file->firstcluster = 0;
1622 file->lastcluster = 0;
1623 file->lastsector = 0;
1624 file->clusternum = 0;
1625 file->sectornum = 0;
1626 file->eof = false;
1629 return rc;
1632 int fat_create_dir(const char* name,
1633 struct fat_dir* newdir,
1634 struct fat_dir* dir)
1636 #ifdef HAVE_MULTIVOLUME
1637 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1638 #else
1639 struct bpb* fat_bpb = &fat_bpbs[0];
1640 #endif
1641 unsigned char buf[SECTOR_SIZE];
1642 int i;
1643 long sector;
1644 int rc;
1645 struct fat_file dummyfile;
1647 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1649 memset(newdir, 0, sizeof(struct fat_dir));
1650 memset(&dummyfile, 0, sizeof(struct fat_file));
1652 /* First, add the entry in the parent directory */
1653 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1654 if (rc < 0)
1655 return rc * 10 - 1;
1657 /* Allocate a new cluster for the directory */
1658 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1659 fat_bpb->fsinfo.nextfree);
1660 if(newdir->file.firstcluster == 0)
1661 return -1;
1663 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1665 /* Clear the entire cluster */
1666 memset(buf, 0, sizeof buf);
1667 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1668 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1669 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1670 if (rc < 0)
1671 return rc * 10 - 2;
1674 /* Then add the "." entry */
1675 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1676 if (rc < 0)
1677 return rc * 10 - 3;
1678 dummyfile.firstcluster = newdir->file.firstcluster;
1679 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1681 /* and the ".." entry */
1682 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1683 if (rc < 0)
1684 return rc * 10 - 4;
1686 /* The root cluster is cluster 0 in the ".." entry */
1687 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1688 dummyfile.firstcluster = 0;
1689 else
1690 dummyfile.firstcluster = dir->file.firstcluster;
1691 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1693 /* Set the firstcluster field in the direntry */
1694 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1696 rc = flush_fat(IF_MV(fat_bpb));
1697 if (rc < 0)
1698 return rc * 10 - 5;
1700 return rc;
1703 int fat_truncate(const struct fat_file *file)
1705 /* truncate trailing clusters */
1706 long next;
1707 long last = file->lastcluster;
1708 #ifdef HAVE_MULTIVOLUME
1709 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1710 #endif
1712 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1714 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1715 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1716 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1718 if (file->lastcluster)
1719 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1721 return 0;
1724 int fat_closewrite(struct fat_file *file, long size, int attr)
1726 int rc;
1727 #ifdef HAVE_MULTIVOLUME
1728 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1729 #endif
1730 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1732 if (!size) {
1733 /* empty file */
1734 if ( file->firstcluster ) {
1735 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1736 file->firstcluster = 0;
1740 if (file->dircluster) {
1741 rc = update_short_entry(file, size, attr);
1742 if (rc < 0)
1743 return rc * 10 - 1;
1746 flush_fat(IF_MV(fat_bpb));
1748 #ifdef TEST_FAT
1749 if ( file->firstcluster ) {
1750 /* debug */
1751 #ifdef HAVE_MULTIVOLUME
1752 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1753 #else
1754 struct bpb* fat_bpb = &fat_bpbs[0];
1755 #endif
1756 long count = 0;
1757 long len;
1758 long next;
1759 for ( next = file->firstcluster; next;
1760 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1761 LDEBUGF("cluster %ld: %lx\n", count, next);
1762 count++;
1764 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1765 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1766 count, len, size );
1767 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1768 panicf("Cluster chain is too long\n");
1769 if ( len < size )
1770 panicf("Cluster chain is too short\n");
1772 #endif
1774 return 0;
1777 static int free_direntries(struct fat_file* file)
1779 unsigned char buf[SECTOR_SIZE];
1780 struct fat_file dir;
1781 int numentries = file->direntries;
1782 unsigned int entry = file->direntry - numentries + 1;
1783 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1784 int i;
1785 int rc;
1787 /* create a temporary file handle for the dir holding this file */
1788 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1789 if (rc < 0)
1790 return rc * 10 - 1;
1792 rc = fat_seek( &dir, sector );
1793 if (rc < 0)
1794 return rc * 10 - 2;
1796 rc = fat_readwrite(&dir, 1, buf, false);
1797 if (rc < 1)
1798 return rc * 10 - 3;
1800 for (i=0; i < numentries; i++) {
1801 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1802 entry, i+1, numentries);
1803 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1804 entry++;
1806 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1807 /* flush this sector */
1808 rc = fat_seek(&dir, sector);
1809 if (rc < 0)
1810 return rc * 10 - 4;
1812 rc = fat_readwrite(&dir, 1, buf, true);
1813 if (rc < 1)
1814 return rc * 10 - 5;
1816 if ( i+1 < numentries ) {
1817 /* read next sector */
1818 rc = fat_readwrite(&dir, 1, buf, false);
1819 if (rc < 1)
1820 return rc * 10 - 6;
1822 sector++;
1826 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1827 /* flush this sector */
1828 rc = fat_seek(&dir, sector);
1829 if (rc < 0)
1830 return rc * 10 - 7;
1832 rc = fat_readwrite(&dir, 1, buf, true);
1833 if (rc < 1)
1834 return rc * 10 - 8;
1837 return 0;
1840 int fat_remove(struct fat_file* file)
1842 long next, last = file->firstcluster;
1843 int rc;
1844 #ifdef HAVE_MULTIVOLUME
1845 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1846 #endif
1848 LDEBUGF("fat_remove(%lx)\n",last);
1850 while ( last ) {
1851 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1852 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1853 last = next;
1856 if ( file->dircluster ) {
1857 rc = free_direntries(file);
1858 if (rc < 0)
1859 return rc * 10 - 1;
1862 file->firstcluster = 0;
1863 file->dircluster = 0;
1865 rc = flush_fat(IF_MV(fat_bpb));
1866 if (rc < 0)
1867 return rc * 10 - 2;
1869 return 0;
1872 int fat_rename(struct fat_file* file,
1873 struct fat_dir* dir,
1874 const unsigned char* newname,
1875 long size,
1876 int attr)
1878 int rc;
1879 struct fat_dir olddir;
1880 struct fat_file newfile = *file;
1881 unsigned char buf[SECTOR_SIZE];
1882 unsigned char* entry = NULL;
1883 unsigned short* clusptr = NULL;
1884 unsigned int parentcluster;
1885 #ifdef HAVE_MULTIVOLUME
1886 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1888 if (file->volume != dir->file.volume) {
1889 DEBUGF("No rename across volumes!\n");
1890 return -1;
1892 #else
1893 struct bpb* fat_bpb = &fat_bpbs[0];
1894 #endif
1896 if ( !file->dircluster ) {
1897 DEBUGF("File has no dir cluster!\n");
1898 return -2;
1901 /* create a temporary file handle */
1902 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1903 if (rc < 0)
1904 return rc * 10 - 1;
1906 /* create new name */
1907 rc = add_dir_entry(dir, &newfile, newname, false, false);
1908 if (rc < 0)
1909 return rc * 10 - 2;
1911 /* write size and cluster link */
1912 rc = update_short_entry(&newfile, size, attr);
1913 if (rc < 0)
1914 return rc * 10 - 3;
1916 /* remove old name */
1917 rc = free_direntries(file);
1918 if (rc < 0)
1919 return rc * 10 - 4;
1921 rc = flush_fat(IF_MV(fat_bpb));
1922 if (rc < 0)
1923 return rc * 10 - 5;
1925 /* if renaming a directory, update the .. entry to make sure
1926 it points to its parent directory (we don't check if it was a move) */
1927 if(FAT_ATTR_DIRECTORY == attr) {
1928 /* open the dir that was renamed, we re-use the olddir struct */
1929 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1930 NULL);
1931 if (rc < 0)
1932 return rc * 10 - 6;
1934 /* get the first sector of the dir */
1935 rc = fat_seek(&olddir.file, 0);
1936 if (rc < 0)
1937 return rc * 10 - 7;
1939 rc = fat_readwrite(&olddir.file, 1, buf, false);
1940 if (rc < 0)
1941 return rc * 10 - 8;
1943 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1944 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1945 parentcluster = 0;
1946 else
1947 parentcluster = dir->file.firstcluster;
1949 entry = buf + DIR_ENTRY_SIZE;
1950 if(strncmp(".. ", entry, 11))
1952 /* .. entry must be second entry according to FAT spec (p.29) */
1953 DEBUGF("Second dir entry is not double-dot!\n");
1954 return rc * 10 - 9;
1956 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1957 *clusptr = htole16(parentcluster >> 16);
1959 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1960 *clusptr = htole16(parentcluster & 0xffff);
1962 /* write back this sector */
1963 rc = fat_seek(&olddir.file, 0);
1964 if (rc < 0)
1965 return rc * 10 - 7;
1967 rc = fat_readwrite(&olddir.file, 1, buf, true);
1968 if (rc < 1)
1969 return rc * 10 - 8;
1972 return 0;
1975 static long next_write_cluster(struct fat_file* file,
1976 long oldcluster,
1977 long* newsector)
1979 #ifdef HAVE_MULTIVOLUME
1980 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1981 #else
1982 struct bpb* fat_bpb = &fat_bpbs[0];
1983 #endif
1984 long cluster = 0;
1985 long sector;
1987 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
1989 if (oldcluster)
1990 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
1992 if (!cluster) {
1993 if (oldcluster > 0)
1994 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
1995 else if (oldcluster == 0)
1996 cluster = find_free_cluster(IF_MV2(fat_bpb,)
1997 fat_bpb->fsinfo.nextfree);
1998 #ifdef HAVE_FAT16SUPPORT
1999 else /* negative, pseudo-cluster of the root dir */
2000 return 0; /* impossible to append something to the root */
2001 #endif
2003 if (cluster) {
2004 if (oldcluster)
2005 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2006 else
2007 file->firstcluster = cluster;
2008 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2010 else {
2011 #ifdef TEST_FAT
2012 if (fat_bpb->fsinfo.freecount>0)
2013 panicf("There is free space, but find_free_cluster() "
2014 "didn't find it!\n");
2015 #endif
2016 DEBUGF("next_write_cluster(): Disk full!\n");
2017 return 0;
2020 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2021 if (sector<0)
2022 return 0;
2024 *newsector = sector;
2025 return cluster;
2028 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2029 unsigned long start, long count, char* buf, bool write )
2031 #ifndef HAVE_MULTIVOLUME
2032 struct bpb* fat_bpb = &fat_bpbs[0];
2033 #endif
2034 int rc;
2036 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2037 start+ fat_bpb->startsector, count, write?"write":"read");
2038 if (write) {
2039 unsigned long firstallowed;
2040 #ifdef HAVE_FAT16SUPPORT
2041 if (fat_bpb->is_fat16)
2042 firstallowed = fat_bpb->rootdirsector;
2043 else
2044 #endif
2045 firstallowed = fat_bpb->firstdatasector;
2047 if (start < firstallowed)
2048 panicf("Write %ld before data\n", firstallowed - start);
2049 if (start + count > fat_bpb->totalsectors)
2050 panicf("Write %ld after data\n",
2051 start + count - fat_bpb->totalsectors);
2052 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
2053 start + fat_bpb->startsector, count, buf);
2055 else
2056 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
2057 start + fat_bpb->startsector, count, buf);
2058 if (rc < 0) {
2059 DEBUGF( "transfer() - Couldn't %s sector %lx"
2060 " (error code %d)\n",
2061 write ? "write":"read", start, rc);
2062 return rc;
2064 return 0;
2068 long fat_readwrite( struct fat_file *file, long sectorcount,
2069 void* buf, bool write )
2071 #ifdef HAVE_MULTIVOLUME
2072 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2073 #else
2074 struct bpb* fat_bpb = &fat_bpbs[0];
2075 #endif
2076 long cluster = file->lastcluster;
2077 long sector = file->lastsector;
2078 long clusternum = file->clusternum;
2079 long numsec = file->sectornum;
2080 bool eof = file->eof;
2081 long first=0, last=0;
2082 long i;
2083 int rc;
2085 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2086 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2087 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2088 sector,numsec, eof?1:0);
2090 if ( eof && !write)
2091 return 0;
2093 /* find sequential sectors and write them all at once */
2094 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2095 numsec++;
2096 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2097 long oldcluster = cluster;
2098 long oldsector = sector;
2099 long oldnumsec = numsec;
2100 if (write)
2101 cluster = next_write_cluster(file, cluster, &sector);
2102 else {
2103 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2104 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2107 clusternum++;
2108 numsec=1;
2110 if (!cluster) {
2111 eof = true;
2112 if ( write ) {
2113 /* remember last cluster, in case
2114 we want to append to the file */
2115 sector = oldsector;
2116 cluster = oldcluster;
2117 numsec = oldnumsec;
2118 clusternum--;
2119 i = -1; /* Error code */
2120 break;
2123 else
2124 eof = false;
2126 else {
2127 if (sector)
2128 sector++;
2129 else {
2130 /* look up first sector of file */
2131 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2132 numsec=1;
2133 #ifdef HAVE_FAT16SUPPORT
2134 if (file->firstcluster < 0)
2135 { /* FAT16 root dir */
2136 sector += fat_bpb->rootdiroffset;
2137 numsec += fat_bpb->rootdiroffset;
2139 #endif
2143 if (!first)
2144 first = sector;
2146 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2147 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2148 long count = last - first + 1;
2149 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2150 if (rc < 0)
2151 return rc * 10 - 1;
2153 buf = (char *)buf + count * SECTOR_SIZE;
2154 first = sector;
2157 if ((i == sectorcount-1) && /* last sector requested */
2158 (!eof))
2160 long count = sector - first + 1;
2161 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2162 if (rc < 0)
2163 return rc * 10 - 2;
2166 last = sector;
2169 file->lastcluster = cluster;
2170 file->lastsector = sector;
2171 file->clusternum = clusternum;
2172 file->sectornum = numsec;
2173 file->eof = eof;
2175 /* if eof, don't report last block as read/written */
2176 if (eof)
2177 i--;
2179 DEBUGF("Sectors written: %ld\n", i);
2180 return i;
2183 int fat_seek(struct fat_file *file, unsigned long seeksector )
2185 #ifdef HAVE_MULTIVOLUME
2186 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2187 #else
2188 struct bpb* fat_bpb = &fat_bpbs[0];
2189 #endif
2190 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2191 long cluster = file->firstcluster;
2192 long i;
2194 #ifdef HAVE_FAT16SUPPORT
2195 if (cluster < 0) /* FAT16 root dir */
2196 seeksector += fat_bpb->rootdiroffset;
2197 #endif
2199 file->eof = false;
2200 if (seeksector) {
2201 /* we need to find the sector BEFORE the requested, since
2202 the file struct stores the last accessed sector */
2203 seeksector--;
2204 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2205 sectornum = seeksector % fat_bpb->bpb_secperclus;
2207 if (file->clusternum && clusternum >= file->clusternum)
2209 cluster = file->lastcluster;
2210 numclusters -= file->clusternum;
2213 for (i=0; i<numclusters; i++) {
2214 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2215 if (!cluster) {
2216 DEBUGF("Seeking beyond the end of the file! "
2217 "(sector %ld, cluster %ld)\n", seeksector, i);
2218 return -1;
2222 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2224 else {
2225 sectornum = -1;
2228 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2229 file->firstcluster, seeksector, cluster, sector, sectornum);
2231 file->lastcluster = cluster;
2232 file->lastsector = sector;
2233 file->clusternum = clusternum;
2234 file->sectornum = sectornum + 1;
2235 return 0;
2238 int fat_opendir(IF_MV2(int volume,)
2239 struct fat_dir *dir, unsigned long startcluster,
2240 const struct fat_dir *parent_dir)
2242 #ifdef HAVE_MULTIVOLUME
2243 struct bpb* fat_bpb = &fat_bpbs[volume];
2244 /* fixme: remove error check when done */
2245 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2247 LDEBUGF("fat_open() illegal volume %d\n", volume);
2248 return -1;
2250 #else
2251 struct bpb* fat_bpb = &fat_bpbs[0];
2252 #endif
2253 int rc;
2255 dir->entry = 0;
2256 dir->sector = 0;
2258 if (startcluster == 0)
2259 startcluster = fat_bpb->bpb_rootclus;
2261 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2262 if(rc)
2264 DEBUGF( "fat_opendir() - Couldn't open dir"
2265 " (error code %d)\n", rc);
2266 return rc * 10 - 1;
2269 return 0;
2272 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2273 * destination buffer (UTF-8 encoded). Copying is stopped when
2274 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2275 * Trailing \0 is also appended at the end of the UTF8-encoded
2276 * string.
2278 * utf16src utf16 (little endian) segment to copy
2279 * utf16count max number of the utf16-characters to copy
2280 * utf8dst where to write UTF8-encoded string to
2282 * returns the number of UTF-16 characters actually copied
2284 static int fat_copy_long_name_segment(unsigned char *utf16src,
2285 int utf16count, unsigned char *utf8dst) {
2286 int cnt = 0;
2287 while ((utf16count--) > 0) {
2288 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2289 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2290 break;
2292 utf8dst = utf8encode(ucs, utf8dst);
2293 utf16src += 2;
2294 cnt++;
2296 *utf8dst = 0;
2297 return cnt;
2300 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2302 bool done = false;
2303 int i;
2304 int rc;
2305 unsigned char firstbyte;
2306 /* Long file names are stored in special entries. Each entry holds
2307 up to 13 characters. Names can be max 255 chars (not bytes!) long
2308 hence max 20 entries are required. */
2309 int longarray[20];
2310 int longs=0;
2311 int sectoridx=0;
2312 unsigned char* cached_buf = dir->sectorcache[0];
2314 dir->entrycount = 0;
2316 while(!done)
2318 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2320 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2321 if (rc == 0) {
2322 /* eof */
2323 entry->name[0] = 0;
2324 break;
2326 if (rc < 0) {
2327 DEBUGF( "fat_getnext() - Couldn't read dir"
2328 " (error code %d)\n", rc);
2329 return rc * 10 - 1;
2331 dir->sector = dir->file.lastsector;
2334 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2335 i < DIR_ENTRIES_PER_SECTOR; i++)
2337 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2339 firstbyte = cached_buf[entrypos];
2340 dir->entry++;
2342 if (firstbyte == 0xe5) {
2343 /* free entry */
2344 sectoridx = 0;
2345 dir->entrycount = 0;
2346 continue;
2349 if (firstbyte == 0) {
2350 /* last entry */
2351 entry->name[0] = 0;
2352 dir->entrycount = 0;
2353 return 0;
2356 dir->entrycount++;
2358 /* longname entry? */
2359 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2360 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2361 longarray[longs++] = entrypos + sectoridx;
2363 else {
2364 if ( parse_direntry(entry,
2365 &cached_buf[entrypos]) ) {
2367 /* don't return volume id entry */
2368 if ( (entry->attr &
2369 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2370 == FAT_ATTR_VOLUME_ID)
2371 continue;
2373 /* replace shortname with longname? */
2374 if ( longs ) {
2375 int j;
2376 /* This should be enough to hold any name segment
2377 utf8-encoded */
2378 unsigned char shortname[13]; /* 8+3+dot+\0 */
2379 /* Add 1 for trailing \0 */
2380 unsigned char longname_utf8segm[6*4 + 1];
2381 int longname_utf8len = 0;
2382 /* Temporarily store it */
2383 strcpy(shortname, entry->name);
2384 entry->name[0] = 0;
2386 /* iterate backwards through the dir entries */
2387 for (j=longs-1; j>=0; j--) {
2388 unsigned char* ptr = cached_buf;
2389 int index = longarray[j];
2390 /* current or cached sector? */
2391 if ( sectoridx >= SECTOR_SIZE ) {
2392 if ( sectoridx >= SECTOR_SIZE*2 ) {
2393 if ( ( index >= SECTOR_SIZE ) &&
2394 ( index < SECTOR_SIZE*2 ))
2395 ptr = dir->sectorcache[1];
2396 else
2397 ptr = dir->sectorcache[2];
2399 else {
2400 if ( index < SECTOR_SIZE )
2401 ptr = dir->sectorcache[1];
2404 index &= SECTOR_SIZE-1;
2407 /* Try to append each segment of the long name.
2408 Check if we'd exceed the buffer.
2409 Also check for FAT padding characters 0xFFFF. */
2410 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2411 longname_utf8segm) == 0) break;
2412 /* logf("SG: %s, EN: %s", longname_utf8segm,
2413 entry->name); */
2414 longname_utf8len += strlen(longname_utf8segm);
2415 if (longname_utf8len < FAT_FILENAME_BYTES)
2416 strcat(entry->name, longname_utf8segm);
2417 else
2418 break;
2420 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2421 longname_utf8segm) == 0) break;
2422 /* logf("SG: %s, EN: %s", longname_utf8segm,
2423 entry->name); */
2424 longname_utf8len += strlen(longname_utf8segm);
2425 if (longname_utf8len < FAT_FILENAME_BYTES)
2426 strcat(entry->name, longname_utf8segm);
2427 else
2428 break;
2430 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2431 longname_utf8segm) == 0) break;
2432 /* logf("SG: %s, EN: %s", longname_utf8segm,
2433 entry->name); */
2434 longname_utf8len += strlen(longname_utf8segm);
2435 if (longname_utf8len < FAT_FILENAME_BYTES)
2436 strcat(entry->name, longname_utf8segm);
2437 else
2438 break;
2441 /* Does the utf8-encoded name fit into the entry? */
2442 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2443 /* Take the short DOS name. Need to utf8-encode it
2444 since it may contain chars from the upper half of
2445 the OEM code page which wouldn't be a valid utf8.
2446 Beware: this file will be shown with strange
2447 glyphs in file browser since unicode 0x80 to 0x9F
2448 are control characters. */
2449 logf("SN-DOS: %s", shortname);
2450 unsigned char *utf8;
2451 utf8 = iso_decode(shortname, entry->name, -1,
2452 strlen(shortname));
2453 *utf8 = 0;
2454 logf("SN: %s", entry->name);
2455 } else {
2456 /* logf("LN: %s", entry->name);
2457 logf("LNLen: %d (%c)", longname_utf8len,
2458 entry->name[0]); */
2461 done = true;
2462 sectoridx = 0;
2463 i++;
2464 break;
2469 /* save this sector, for longname use */
2470 if ( sectoridx )
2471 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2472 else
2473 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2474 sectoridx += SECTOR_SIZE;
2477 return 0;
2480 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2482 #ifndef HAVE_MULTIVOLUME
2483 const int volume = 0;
2484 #endif
2485 struct bpb* fat_bpb = &fat_bpbs[volume];
2486 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2489 #ifdef HAVE_MULTIVOLUME
2490 bool fat_ismounted(int volume)
2492 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2494 #endif