Hopefully fix FS#8506 (OF cant be loaded on some PP targets). also hopefully fixes...
[Rockbox.git] / firmware / drivers / fat.c
blob002e1004050917fadd3193912b09d151dc3040b3
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 */
175 static bool initialized = false;
177 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
178 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
179 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
180 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
181 long secnum, bool dirty);
182 static void create_dos_name(const unsigned char *name, unsigned char *newname);
183 static void randomize_dos_name(unsigned char *name);
184 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
185 unsigned long start);
186 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
187 long count, char* buf, bool write );
189 #define FAT_CACHE_SIZE 0x20
190 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
192 struct fat_cache_entry
194 long secnum;
195 bool inuse;
196 bool dirty;
197 #ifdef HAVE_MULTIVOLUME
198 struct bpb* fat_vol ; /* shared cache for all volumes */
199 #endif
202 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
203 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
204 static struct mutex cache_mutex SHAREDBSS_ATTR;
206 #if defined(HAVE_HOTSWAP) && !defined(HAVE_MMC) /* A better condition ?? */
207 void fat_lock(void)
209 mutex_lock(&cache_mutex);
212 void fat_unlock(void)
214 mutex_unlock(&cache_mutex);
216 #endif
218 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
220 #ifndef HAVE_MULTIVOLUME
221 struct bpb* fat_bpb = &fat_bpbs[0];
222 #endif
223 #ifdef HAVE_FAT16SUPPORT
224 /* negative clusters (FAT16 root dir) don't get the 2 offset */
225 int zerocluster = cluster < 0 ? 0 : 2;
226 #else
227 const long zerocluster = 2;
228 #endif
230 if (cluster > (long)(fat_bpb->dataclusters + 1))
232 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
233 return -1;
236 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
237 + fat_bpb->firstdatasector;
240 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
242 #ifndef HAVE_MULTIVOLUME
243 const int volume = 0;
244 #endif
245 struct bpb* fat_bpb = &fat_bpbs[volume];
246 if (size)
247 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
248 if (free)
249 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
252 void fat_init(void)
254 unsigned int i;
256 if (!initialized)
258 initialized = true;
259 mutex_init(&cache_mutex);
262 #ifdef HAVE_PRIORITY_SCHEDULING
263 /* Disable this because it is dangerous due to the assumption that
264 * mutex_unlock won't yield */
265 mutex_set_preempt(&cache_mutex, false);
266 #endif
268 /* mark the FAT cache as unused */
269 for(i = 0;i < FAT_CACHE_SIZE;i++)
271 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
272 fat_cache[i].inuse = false;
273 fat_cache[i].dirty = false;
274 #ifdef HAVE_MULTIVOLUME
275 fat_cache[i].fat_vol = NULL;
276 #endif
278 #ifdef HAVE_MULTIVOLUME
279 /* mark the possible volumes as not mounted */
280 for (i=0; i<NUM_VOLUMES;i++)
282 fat_bpbs[i].mounted = false;
284 #endif
287 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
289 #ifndef HAVE_MULTIVOLUME
290 const int volume = 0;
291 #endif
292 struct bpb* fat_bpb = &fat_bpbs[volume];
293 unsigned char buf[SECTOR_SIZE];
294 int rc;
295 int secmult;
296 long datasec;
297 #ifdef HAVE_FAT16SUPPORT
298 int rootdirsectors;
299 #endif
301 /* Read the sector */
302 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
303 if(rc)
305 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
306 return rc * 10 - 1;
309 memset(fat_bpb, 0, sizeof(struct bpb));
310 fat_bpb->startsector = startsector;
311 #ifdef HAVE_MULTIVOLUME
312 fat_bpb->drive = drive;
313 #endif
315 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
316 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
317 /* Sanity check is performed later */
319 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
320 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
321 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
322 fat_bpb->bpb_media = buf[BPB_MEDIA];
323 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
324 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
325 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
326 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
327 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
329 /* calculate a few commonly used values */
330 if (fat_bpb->bpb_fatsz16 != 0)
331 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
332 else
333 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
335 if (fat_bpb->bpb_totsec16 != 0)
336 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
337 else
338 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
340 #ifdef HAVE_FAT16SUPPORT
341 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
342 if (!fat_bpb->bpb_bytspersec)
343 return -2;
344 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
345 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
346 #endif /* #ifdef HAVE_FAT16SUPPORT */
348 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
349 #ifdef HAVE_FAT16SUPPORT
350 + rootdirsectors
351 #endif
352 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
354 /* Determine FAT type */
355 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
356 if (fat_bpb->bpb_secperclus)
357 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
358 else
359 return -2;
361 #ifdef TEST_FAT
363 we are sometimes testing with "illegally small" fat32 images,
364 so we don't use the proper fat32 test case for test code
366 if ( fat_bpb->bpb_fatsz16 )
367 #else
368 if ( fat_bpb->dataclusters < 65525 )
369 #endif
370 { /* FAT16 */
371 #ifdef HAVE_FAT16SUPPORT
372 fat_bpb->is_fat16 = true;
373 if (fat_bpb->dataclusters < 4085)
374 { /* FAT12 */
375 DEBUGF("This is FAT12. Go away!\n");
376 return -2;
378 #else /* #ifdef HAVE_FAT16SUPPORT */
379 DEBUGF("This is not FAT32. Go away!\n");
380 return -2;
381 #endif /* #ifndef HAVE_FAT16SUPPORT */
384 #ifdef HAVE_FAT16SUPPORT
385 if (fat_bpb->is_fat16)
386 { /* FAT16 specific part of BPB */
387 int dirclusters;
388 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
389 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
390 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
391 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
392 /* I assign negative pseudo cluster numbers for the root directory,
393 their range is counted upward until -1. */
394 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
395 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
396 - rootdirsectors;
398 else
399 #endif /* #ifdef HAVE_FAT16SUPPORT */
400 { /* FAT32 specific part of BPB */
401 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
402 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
403 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
404 fat_bpb->bpb_rootclus);
407 rc = bpb_is_sane(IF_MV(fat_bpb));
408 if (rc < 0)
410 DEBUGF( "fat_mount() - BPB is not sane\n");
411 return rc * 10 - 3;
414 #ifdef HAVE_FAT16SUPPORT
415 if (fat_bpb->is_fat16)
417 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
418 fat_bpb->fsinfo.nextfree = 0xffffffff;
420 else
421 #endif /* #ifdef HAVE_FAT16SUPPORT */
423 /* Read the fsinfo sector */
424 rc = ata_read_sectors(IF_MV2(drive,)
425 startsector + fat_bpb->bpb_fsinfo, 1, buf);
426 if (rc < 0)
428 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
429 return rc * 10 - 4;
431 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
432 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
435 /* calculate freecount if unset */
436 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
438 fat_recalc_free(IF_MV(volume));
441 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
442 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
443 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
444 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
445 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
447 #ifdef HAVE_MULTIVOLUME
448 fat_bpb->mounted = true;
449 #endif
451 return 0;
454 #ifdef HAVE_HOTSWAP
455 int fat_unmount(int volume, bool flush)
457 int rc;
458 struct bpb* fat_bpb = &fat_bpbs[volume];
460 if(flush)
462 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
464 else
465 { /* volume is not accessible any more, e.g. MMC removed */
466 int i;
467 mutex_lock(&cache_mutex);
468 for(i = 0;i < FAT_CACHE_SIZE;i++)
470 struct fat_cache_entry *fce = &fat_cache[i];
471 if(fce->inuse && fce->fat_vol == fat_bpb)
473 fce->inuse = false; /* discard all from that volume */
474 fce->dirty = false;
477 mutex_unlock(&cache_mutex);
478 rc = 0;
480 fat_bpb->mounted = false;
481 return rc;
483 #endif /* #ifdef HAVE_HOTSWAP */
485 void fat_recalc_free(IF_MV_NONVOID(int volume))
487 #ifndef HAVE_MULTIVOLUME
488 const int volume = 0;
489 #endif
490 struct bpb* fat_bpb = &fat_bpbs[volume];
491 long free = 0;
492 unsigned long i;
493 #ifdef HAVE_FAT16SUPPORT
494 if (fat_bpb->is_fat16)
496 for (i = 0; i<fat_bpb->fatsize; i++) {
497 unsigned int j;
498 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
499 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
500 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
501 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
502 break;
504 if (letoh16(fat[j]) == 0x0000) {
505 free++;
506 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
507 fat_bpb->fsinfo.nextfree = c;
512 else
513 #endif /* #ifdef HAVE_FAT16SUPPORT */
515 for (i = 0; i<fat_bpb->fatsize; i++) {
516 unsigned int j;
517 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
518 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
519 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
520 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
521 break;
523 if (!(letoh32(fat[j]) & 0x0fffffff)) {
524 free++;
525 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
526 fat_bpb->fsinfo.nextfree = c;
531 fat_bpb->fsinfo.freecount = free;
532 update_fsinfo(IF_MV(fat_bpb));
535 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
537 #ifndef HAVE_MULTIVOLUME
538 struct bpb* fat_bpb = &fat_bpbs[0];
539 #endif
540 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
542 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
543 fat_bpb->bpb_bytspersec);
544 return -1;
546 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
547 > 128L*1024L)
549 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
550 "(%d * %d = %d)\n",
551 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
552 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
553 return -2;
555 if(fat_bpb->bpb_numfats != 2)
557 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
558 fat_bpb->bpb_numfats);
560 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
562 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
563 "media type (0x%02x)\n",
564 fat_bpb->bpb_media);
566 if(fat_bpb->last_word != 0xaa55)
568 DEBUGF( "bpb_is_sane() - Error: Last word is not "
569 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
570 return -3;
573 if (fat_bpb->fsinfo.freecount >
574 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
575 fat_bpb->bpb_secperclus)
577 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
578 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
579 return -4;
582 return 0;
585 static void flush_fat_sector(struct fat_cache_entry *fce,
586 unsigned char *sectorbuf)
588 int rc;
589 long secnum;
591 /* With multivolume, use only the FAT info from the cached sector! */
592 #ifdef HAVE_MULTIVOLUME
593 secnum = fce->secnum + fce->fat_vol->startsector;
594 #else
595 secnum = fce->secnum + fat_bpbs[0].startsector;
596 #endif
598 /* Write to the first FAT */
599 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
600 secnum, 1,
601 sectorbuf);
602 if(rc < 0)
604 panicf("flush_fat_sector() - Could not write sector %ld"
605 " (error %d)\n",
606 secnum, rc);
608 #ifdef HAVE_MULTIVOLUME
609 if(fce->fat_vol->bpb_numfats > 1)
610 #else
611 if(fat_bpbs[0].bpb_numfats > 1)
612 #endif
614 /* Write to the second FAT */
615 #ifdef HAVE_MULTIVOLUME
616 secnum += fce->fat_vol->fatsize;
617 #else
618 secnum += fat_bpbs[0].fatsize;
619 #endif
620 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
621 secnum, 1, sectorbuf);
622 if(rc < 0)
624 panicf("flush_fat_sector() - Could not write sector %ld"
625 " (error %d)\n",
626 secnum, rc);
629 fce->dirty = false;
632 /* Note: The returned pointer is only safely valid until the next
633 task switch! (Any subsequent ata read/write may yield.) */
634 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
635 long fatsector, bool dirty)
637 #ifndef HAVE_MULTIVOLUME
638 struct bpb* fat_bpb = &fat_bpbs[0];
639 #endif
640 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
641 int cache_index = secnum & FAT_CACHE_MASK;
642 struct fat_cache_entry *fce = &fat_cache[cache_index];
643 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
644 int rc;
646 mutex_lock(&cache_mutex); /* make changes atomic */
648 /* Delete the cache entry if it isn't the sector we want */
649 if(fce->inuse && (fce->secnum != secnum
650 #ifdef HAVE_MULTIVOLUME
651 || fce->fat_vol != fat_bpb
652 #endif
655 /* Write back if it is dirty */
656 if(fce->dirty)
658 flush_fat_sector(fce, sectorbuf);
660 fce->inuse = false;
663 /* Load the sector if it is not cached */
664 if(!fce->inuse)
666 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
667 secnum + fat_bpb->startsector,1,
668 sectorbuf);
669 if(rc < 0)
671 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
672 " (error %d)\n", secnum, rc);
673 mutex_unlock(&cache_mutex);
674 return NULL;
676 fce->inuse = true;
677 fce->secnum = secnum;
678 #ifdef HAVE_MULTIVOLUME
679 fce->fat_vol = fat_bpb;
680 #endif
682 if (dirty)
683 fce->dirty = true; /* dirt remains, sticky until flushed */
684 mutex_unlock(&cache_mutex);
685 return sectorbuf;
688 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
689 unsigned long startcluster)
691 #ifndef HAVE_MULTIVOLUME
692 struct bpb* fat_bpb = &fat_bpbs[0];
693 #endif
694 unsigned long sector;
695 unsigned long offset;
696 unsigned long i;
698 #ifdef HAVE_FAT16SUPPORT
699 if (fat_bpb->is_fat16)
701 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
702 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
704 for (i = 0; i<fat_bpb->fatsize; i++) {
705 unsigned int j;
706 unsigned int nr = (i + sector) % fat_bpb->fatsize;
707 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
708 if ( !fat )
709 break;
710 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
711 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
712 if (letoh16(fat[k]) == 0x0000) {
713 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
714 /* Ignore the reserved clusters 0 & 1, and also
715 cluster numbers out of bounds */
716 if ( c < 2 || c > fat_bpb->dataclusters+1 )
717 continue;
718 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
719 fat_bpb->fsinfo.nextfree = c;
720 return c;
723 offset = 0;
726 else
727 #endif /* #ifdef HAVE_FAT16SUPPORT */
729 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
730 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
732 for (i = 0; i<fat_bpb->fatsize; i++) {
733 unsigned int j;
734 unsigned long nr = (i + sector) % fat_bpb->fatsize;
735 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
736 if ( !fat )
737 break;
738 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
739 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
740 if (!(letoh32(fat[k]) & 0x0fffffff)) {
741 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
742 /* Ignore the reserved clusters 0 & 1, and also
743 cluster numbers out of bounds */
744 if ( c < 2 || c > fat_bpb->dataclusters+1 )
745 continue;
746 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
747 fat_bpb->fsinfo.nextfree = c;
748 return c;
751 offset = 0;
755 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
756 return 0; /* 0 is an illegal cluster number */
759 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
760 unsigned long val)
762 #ifndef HAVE_MULTIVOLUME
763 struct bpb* fat_bpb = &fat_bpbs[0];
764 #endif
765 #ifdef HAVE_FAT16SUPPORT
766 if (fat_bpb->is_fat16)
768 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
769 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
770 unsigned short* sec;
772 val &= 0xFFFF;
774 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
776 if (entry==val)
777 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
779 if ( entry < 2 )
780 panicf("Updating reserved FAT entry %ld.\n",entry);
782 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
783 if (!sec)
785 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
786 return -1;
789 if ( val ) {
790 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
791 fat_bpb->fsinfo.freecount--;
793 else {
794 if (letoh16(sec[offset]))
795 fat_bpb->fsinfo.freecount++;
798 LDEBUGF("update_fat_entry: %d free clusters\n",
799 fat_bpb->fsinfo.freecount);
801 sec[offset] = htole16(val);
803 else
804 #endif /* #ifdef HAVE_FAT16SUPPORT */
806 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
807 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
808 unsigned long* sec;
810 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
812 if (entry==val)
813 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
815 if ( entry < 2 )
816 panicf("Updating reserved FAT entry %ld.\n",entry);
818 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
819 if (!sec)
821 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
822 return -1;
825 if ( val ) {
826 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
827 fat_bpb->fsinfo.freecount > 0)
828 fat_bpb->fsinfo.freecount--;
830 else {
831 if (letoh32(sec[offset]) & 0x0fffffff)
832 fat_bpb->fsinfo.freecount++;
835 LDEBUGF("update_fat_entry: %ld free clusters\n",
836 fat_bpb->fsinfo.freecount);
838 /* don't change top 4 bits */
839 sec[offset] &= htole32(0xf0000000);
840 sec[offset] |= htole32(val & 0x0fffffff);
843 return 0;
846 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
848 #ifdef HAVE_FAT16SUPPORT
849 #ifndef HAVE_MULTIVOLUME
850 struct bpb* fat_bpb = &fat_bpbs[0];
851 #endif
852 if (fat_bpb->is_fat16)
854 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
855 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
856 unsigned short* sec;
858 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
859 if (!sec)
861 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
862 return -1;
865 return letoh16(sec[offset]);
867 else
868 #endif /* #ifdef HAVE_FAT16SUPPORT */
870 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
871 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
872 unsigned long* sec;
874 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
875 if (!sec)
877 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
878 return -1;
881 return letoh32(sec[offset]) & 0x0fffffff;
885 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
887 long next_cluster;
888 long eof_mark = FAT_EOF_MARK;
890 #ifdef HAVE_FAT16SUPPORT
891 #ifndef HAVE_MULTIVOLUME
892 struct bpb* fat_bpb = &fat_bpbs[0];
893 #endif
894 if (fat_bpb->is_fat16)
896 eof_mark &= 0xFFFF; /* only 16 bit */
897 if (cluster < 0) /* FAT16 root dir */
898 return cluster + 1; /* don't use the FAT */
900 #endif
901 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
903 /* is this last cluster in chain? */
904 if ( next_cluster >= eof_mark )
905 return 0;
906 else
907 return next_cluster;
910 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
912 #ifndef HAVE_MULTIVOLUME
913 struct bpb* fat_bpb = &fat_bpbs[0];
914 #endif
915 unsigned char fsinfo[SECTOR_SIZE];
916 unsigned long* intptr;
917 int rc;
919 #ifdef HAVE_FAT16SUPPORT
920 if (fat_bpb->is_fat16)
921 return 0; /* FAT16 has no FsInfo */
922 #endif /* #ifdef HAVE_FAT16SUPPORT */
924 /* update fsinfo */
925 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
926 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
927 if (rc < 0)
929 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
930 return rc * 10 - 1;
932 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
933 *intptr = htole32(fat_bpb->fsinfo.freecount);
935 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
936 *intptr = htole32(fat_bpb->fsinfo.nextfree);
938 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
939 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
940 if (rc < 0)
942 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
943 return rc * 10 - 2;
946 return 0;
949 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
951 int i;
952 int rc;
953 unsigned char *sec;
954 LDEBUGF("flush_fat()\n");
956 mutex_lock(&cache_mutex);
957 for(i = 0;i < FAT_CACHE_SIZE;i++)
959 struct fat_cache_entry *fce = &fat_cache[i];
960 if(fce->inuse
961 #ifdef HAVE_MULTIVOLUME
962 && fce->fat_vol == fat_bpb
963 #endif
964 && fce->dirty)
966 sec = fat_cache_sectors[i];
967 flush_fat_sector(fce, sec);
970 mutex_unlock(&cache_mutex);
972 rc = update_fsinfo(IF_MV(fat_bpb));
973 if (rc < 0)
974 return rc * 10 - 3;
976 return 0;
979 static void fat_time(unsigned short* date,
980 unsigned short* time,
981 unsigned short* tenth )
983 #if CONFIG_RTC
984 struct tm* tm = get_time();
986 if (date)
987 *date = ((tm->tm_year - 80) << 9) |
988 ((tm->tm_mon + 1) << 5) |
989 tm->tm_mday;
991 if (time)
992 *time = (tm->tm_hour << 11) |
993 (tm->tm_min << 5) |
994 (tm->tm_sec >> 1);
996 if (tenth)
997 *tenth = (tm->tm_sec & 1) * 100;
998 #else
999 /* non-RTC version returns an increment from the supplied time, or a
1000 * fixed standard time/date if no time given as input */
1001 bool next_day = false;
1003 if (time)
1005 if (0 == *time)
1007 /* set to 00:15:00 */
1008 *time = (15 << 5);
1010 else
1012 unsigned short mins = (*time >> 5) & 0x003F;
1013 unsigned short hours = (*time >> 11) & 0x001F;
1014 if ((mins += 10) >= 60)
1016 mins = 0;
1017 hours++;
1019 if ((++hours) >= 24)
1021 hours = hours - 24;
1022 next_day = true;
1024 *time = (hours << 11) | (mins << 5);
1028 if (date)
1030 if (0 == *date)
1032 /* Macros to convert a 2-digit string to a decimal constant.
1033 (YEAR), MONTH and DAY are set by the date command, which outputs
1034 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1035 misinterpretation as an octal constant. */
1036 #define S100(x) 1 ## x
1037 #define C2DIG2DEC(x) (S100(x)-100)
1038 /* set to build date */
1039 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1040 | C2DIG2DEC(DAY);
1042 else
1044 unsigned short day = *date & 0x001F;
1045 unsigned short month = (*date >> 5) & 0x000F;
1046 unsigned short year = (*date >> 9) & 0x007F;
1047 if (next_day)
1049 /* do a very simple day increment - never go above 28 days */
1050 if (++day > 28)
1052 day = 1;
1053 if (++month > 12)
1055 month = 1;
1056 year++;
1059 *date = (year << 9) | (month << 5) | day;
1063 if (tenth)
1064 *tenth = 0;
1065 #endif /* CONFIG_RTC */
1068 static int write_long_name(struct fat_file* file,
1069 unsigned int firstentry,
1070 unsigned int numentries,
1071 const unsigned char* name,
1072 const unsigned char* shortname,
1073 bool is_directory)
1075 unsigned char buf[SECTOR_SIZE];
1076 unsigned char* entry;
1077 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1078 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1079 unsigned char chksum = 0;
1080 unsigned int i, j=0;
1081 unsigned int nameidx=0, namelen = utf8length(name);
1082 int rc;
1083 unsigned short name_utf16[namelen + 1];
1085 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1086 file->firstcluster, firstentry, numentries, name);
1088 rc = fat_seek(file, sector);
1089 if (rc<0)
1090 return rc * 10 - 1;
1092 rc = fat_readwrite(file, 1, buf, false);
1093 if (rc<1)
1094 return rc * 10 - 2;
1096 /* calculate shortname checksum */
1097 for (i=11; i>0; i--)
1098 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1100 /* calc position of last name segment */
1101 if ( namelen > NAME_BYTES_PER_ENTRY )
1102 for (nameidx=0;
1103 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1104 nameidx += NAME_BYTES_PER_ENTRY);
1106 /* we need to convert the name first */
1107 /* since it is written in reverse order */
1108 for (i = 0; i <= namelen; i++)
1109 name = utf8decode(name, &name_utf16[i]);
1111 for (i=0; i < numentries; i++) {
1112 /* new sector? */
1113 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1114 /* update current sector */
1115 rc = fat_seek(file, sector);
1116 if (rc<0)
1117 return rc * 10 - 3;
1119 rc = fat_readwrite(file, 1, buf, true);
1120 if (rc<1)
1121 return rc * 10 - 4;
1123 /* read next sector */
1124 rc = fat_readwrite(file, 1, buf, false);
1125 if (rc<0) {
1126 LDEBUGF("Failed writing new sector: %d\n",rc);
1127 return rc * 10 - 5;
1129 if (rc==0)
1130 /* end of dir */
1131 memset(buf, 0, sizeof buf);
1133 sector++;
1134 idx = 0;
1137 entry = buf + idx * DIR_ENTRY_SIZE;
1139 /* verify this entry is free */
1140 if (entry[0] && entry[0] != 0xe5 )
1141 panicf("Dir entry %d in sector %x is not free! "
1142 "%02x %02x %02x %02x",
1143 idx, sector,
1144 entry[0], entry[1], entry[2], entry[3]);
1146 memset(entry, 0, DIR_ENTRY_SIZE);
1147 if ( i+1 < numentries ) {
1148 /* longname entry */
1149 unsigned int k, l = nameidx;
1151 entry[FATLONG_ORDER] = numentries-i-1;
1152 if (i==0) {
1153 /* mark this as last long entry */
1154 entry[FATLONG_ORDER] |= 0x40;
1156 /* pad name with 0xffff */
1157 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1158 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1159 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1161 /* set name */
1162 for (k=0; k<5 && l <= namelen; k++) {
1163 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1164 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1166 for (k=0; k<6 && l <= namelen; k++) {
1167 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1168 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1170 for (k=0; k<2 && l <= namelen; k++) {
1171 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1172 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1175 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1176 entry[FATDIR_FSTCLUSLO] = 0;
1177 entry[FATLONG_TYPE] = 0;
1178 entry[FATLONG_CHKSUM] = chksum;
1179 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1181 else {
1182 /* shortname entry */
1183 unsigned short date=0, time=0, tenth=0;
1184 LDEBUGF("Shortname entry: %s\n", shortname);
1185 strncpy(entry + FATDIR_NAME, shortname, 11);
1186 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1187 entry[FATDIR_NTRES] = 0;
1189 fat_time(&date, &time, &tenth);
1190 entry[FATDIR_CRTTIMETENTH] = tenth;
1191 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1192 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1193 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1194 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1195 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1197 idx++;
1198 nameidx -= NAME_BYTES_PER_ENTRY;
1201 /* update last sector */
1202 rc = fat_seek(file, sector);
1203 if (rc<0)
1204 return rc * 10 - 6;
1206 rc = fat_readwrite(file, 1, buf, true);
1207 if (rc<1)
1208 return rc * 10 - 7;
1210 return 0;
1213 static int fat_checkname(const unsigned char* newname)
1215 static const char invalid_chars[] = "\"*/:<>?\\|";
1216 int len = strlen(newname);
1217 /* More sanity checks are probably needed */
1218 if (len > 255 || newname[len - 1] == '.')
1220 return -1;
1222 while (*newname)
1224 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1225 return -1;
1226 newname++;
1228 /* check trailing space(s) */
1229 if(*(--newname) == ' ')
1230 return -1;
1232 return 0;
1235 static int add_dir_entry(struct fat_dir* dir,
1236 struct fat_file* file,
1237 const char* name,
1238 bool is_directory,
1239 bool dotdir)
1241 #ifdef HAVE_MULTIVOLUME
1242 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1243 #else
1244 struct bpb* fat_bpb = &fat_bpbs[0];
1245 #endif
1246 unsigned char buf[SECTOR_SIZE];
1247 unsigned char shortname[12];
1248 int rc;
1249 unsigned int sector;
1250 bool done = false;
1251 int entries_needed, entries_found = 0;
1252 int firstentry;
1254 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1255 name, file->firstcluster);
1257 /* Don't check dotdirs name for validity */
1258 if (dotdir == false) {
1259 rc = fat_checkname(name);
1260 if (rc < 0) {
1261 /* filename is invalid */
1262 return rc * 10 - 1;
1266 #ifdef HAVE_MULTIVOLUME
1267 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1268 #endif
1270 /* The "." and ".." directory entries must not be long names */
1271 if(dotdir) {
1272 int i;
1273 strncpy(shortname, name, 12);
1274 for(i = strlen(shortname); i < 12; i++)
1275 shortname[i] = ' ';
1277 entries_needed = 1;
1278 } else {
1279 create_dos_name(name, shortname);
1281 /* one dir entry needed for every 13 bytes of filename,
1282 plus one entry for the short name */
1283 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1284 / NAME_BYTES_PER_ENTRY + 1;
1287 restart:
1288 firstentry = -1;
1290 rc = fat_seek(&dir->file, 0);
1291 if (rc < 0)
1292 return rc * 10 - 2;
1294 /* step 1: search for free entries and check for duplicate shortname */
1295 for (sector = 0; !done; sector++)
1297 unsigned int i;
1299 rc = fat_readwrite(&dir->file, 1, buf, false);
1300 if (rc < 0) {
1301 DEBUGF( "add_dir_entry() - Couldn't read dir"
1302 " (error code %d)\n", rc);
1303 return rc * 10 - 3;
1306 if (rc == 0) { /* current end of dir reached */
1307 LDEBUGF("End of dir on cluster boundary\n");
1308 break;
1311 /* look for free slots */
1312 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1314 switch (buf[i * DIR_ENTRY_SIZE]) {
1315 case 0:
1316 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1317 LDEBUGF("Found end of dir %d\n",
1318 sector * DIR_ENTRIES_PER_SECTOR + i);
1319 i = DIR_ENTRIES_PER_SECTOR - 1;
1320 done = true;
1321 break;
1323 case 0xe5:
1324 entries_found++;
1325 LDEBUGF("Found free entry %d (%d/%d)\n",
1326 sector * DIR_ENTRIES_PER_SECTOR + i,
1327 entries_found, entries_needed);
1328 break;
1330 default:
1331 entries_found = 0;
1333 /* check that our intended shortname doesn't already exist */
1334 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1335 /* shortname exists already, make a new one */
1336 randomize_dos_name(shortname);
1337 LDEBUGF("Duplicate shortname, changing to %s\n",
1338 shortname);
1340 /* name has changed, we need to restart search */
1341 goto restart;
1343 break;
1345 if (firstentry < 0 && (entries_found >= entries_needed))
1346 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1347 - entries_found;
1351 /* step 2: extend the dir if necessary */
1352 if (firstentry < 0)
1354 LDEBUGF("Adding new sector(s) to dir\n");
1355 rc = fat_seek(&dir->file, sector);
1356 if (rc < 0)
1357 return rc * 10 - 4;
1358 memset(buf, 0, sizeof buf);
1360 /* we must clear whole clusters */
1361 for (; (entries_found < entries_needed) ||
1362 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1364 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1365 return -5; /* dir too large -- FAT specification */
1367 rc = fat_readwrite(&dir->file, 1, buf, true);
1368 if (rc < 1) /* No more room or something went wrong */
1369 return rc * 10 - 6;
1371 entries_found += DIR_ENTRIES_PER_SECTOR;
1374 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1377 /* step 3: add entry */
1378 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1379 LDEBUGF("Adding longname to entry %d in sector %d\n",
1380 firstentry, sector);
1382 rc = write_long_name(&dir->file, firstentry,
1383 entries_needed, name, shortname, is_directory);
1384 if (rc < 0)
1385 return rc * 10 - 7;
1387 /* remember where the shortname dir entry is located */
1388 file->direntry = firstentry + entries_needed - 1;
1389 file->direntries = entries_needed;
1390 file->dircluster = dir->file.firstcluster;
1391 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1392 file->direntry, file->direntries);
1394 return 0;
1397 static unsigned char char2dos(unsigned char c, int* randomize)
1399 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1401 if (c <= 0x20)
1402 c = 0; /* Illegal char, remove */
1403 else if (strchr(invalid_chars, c) != NULL)
1405 /* Illegal char, replace */
1406 c = '_';
1407 *randomize = 1; /* as per FAT spec */
1409 else
1410 c = toupper(c);
1412 return c;
1415 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1417 int i;
1418 unsigned char *ext;
1419 int randomize = 0;
1421 /* Find extension part */
1422 ext = strrchr(name, '.');
1423 if (ext == name) /* handle .dotnames */
1424 ext = NULL;
1426 /* needs to randomize? */
1427 if((ext && (strlen(ext) > 4)) ||
1428 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1429 randomize = 1;
1431 /* Name part */
1432 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1434 unsigned char c = char2dos(*name, &randomize);
1435 if (c)
1436 newname[i++] = c;
1439 /* Pad both name and extension */
1440 while (i < 11)
1441 newname[i++] = ' ';
1443 if (newname[0] == 0xe5) /* Special kanji character */
1444 newname[0] = 0x05;
1446 if (ext)
1447 { /* Extension part */
1448 ext++;
1449 for (i = 8; *ext && (i < 11); ext++)
1451 unsigned char c = char2dos(*ext, &randomize);
1452 if (c)
1453 newname[i++] = c;
1457 if(randomize)
1458 randomize_dos_name(newname);
1461 static void randomize_dos_name(unsigned char *name)
1463 unsigned char* tilde = NULL; /* ~ location */
1464 unsigned char* lastpt = NULL; /* last point of filename */
1465 unsigned char* nameptr = name; /* working copy of name pointer */
1466 unsigned char num[9]; /* holds number as string */
1467 int i = 0;
1468 int cnt = 1;
1469 int numlen;
1470 int offset;
1472 while(i++ < 8)
1474 /* hunt for ~ and where to put it */
1475 if((!tilde) && (*nameptr == '~'))
1476 tilde = nameptr;
1477 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1478 lastpt = nameptr;
1479 nameptr++;
1481 if(tilde)
1483 /* extract current count and increment */
1484 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1485 num[7-(unsigned int)(tilde-name)] = 0;
1486 cnt = atoi(num) + 1;
1488 cnt %= 10000000; /* protection */
1489 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1490 numlen = strlen(num); /* required space */
1491 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1492 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1494 memcpy(&name[offset], num, numlen);
1496 /* in special case of counter overflow: pad with spaces */
1497 for(offset = offset+numlen; offset < 8; offset++)
1498 name[offset] = ' ';
1501 static int update_short_entry( struct fat_file* file, long size, int attr )
1503 unsigned char buf[SECTOR_SIZE];
1504 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1505 unsigned char* entry =
1506 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1507 unsigned long* sizeptr;
1508 unsigned short* clusptr;
1509 struct fat_file dir;
1510 int rc;
1512 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1513 file->firstcluster, file->direntry, size);
1515 /* create a temporary file handle for the dir holding this file */
1516 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1517 if (rc < 0)
1518 return rc * 10 - 1;
1520 rc = fat_seek( &dir, sector );
1521 if (rc<0)
1522 return rc * 10 - 2;
1524 rc = fat_readwrite(&dir, 1, buf, false);
1525 if (rc < 1)
1526 return rc * 10 - 3;
1528 if (!entry[0] || entry[0] == 0xe5)
1529 panicf("Updating size on empty dir entry %d\n", file->direntry);
1531 entry[FATDIR_ATTR] = attr & 0xFF;
1533 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1534 *clusptr = htole16(file->firstcluster >> 16);
1536 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1537 *clusptr = htole16(file->firstcluster & 0xffff);
1539 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1540 *sizeptr = htole32(size);
1543 #if CONFIG_RTC
1544 unsigned short time = 0;
1545 unsigned short date = 0;
1546 #else
1547 /* get old time to increment from */
1548 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1549 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1550 #endif
1551 fat_time(&date, &time, NULL);
1552 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1553 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1554 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1557 rc = fat_seek( &dir, sector );
1558 if (rc < 0)
1559 return rc * 10 - 4;
1561 rc = fat_readwrite(&dir, 1, buf, true);
1562 if (rc < 1)
1563 return rc * 10 - 5;
1565 return 0;
1568 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1570 int i=0,j=0;
1571 unsigned char c;
1572 bool lowercase;
1574 memset(de, 0, sizeof(struct fat_direntry));
1575 de->attr = buf[FATDIR_ATTR];
1576 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1577 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1578 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1579 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1580 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1581 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1582 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1583 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1584 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1585 (the result of the shift is always considered signed) */
1587 /* fix the name */
1588 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1589 c = buf[FATDIR_NAME];
1590 if (c == 0x05) /* special kanji char */
1591 c = 0xe5;
1592 i = 0;
1593 while (c != ' ') {
1594 de->name[j++] = lowercase ? tolower(c) : c;
1595 if (++i >= 8)
1596 break;
1597 c = buf[FATDIR_NAME+i];
1599 if (buf[FATDIR_NAME+8] != ' ') {
1600 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1601 de->name[j++] = '.';
1602 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1603 de->name[j++] = lowercase ? tolower(c) : c;
1605 return 1;
1608 int fat_open(IF_MV2(int volume,)
1609 long startcluster,
1610 struct fat_file *file,
1611 const struct fat_dir* dir)
1613 file->firstcluster = startcluster;
1614 file->lastcluster = startcluster;
1615 file->lastsector = 0;
1616 file->clusternum = 0;
1617 file->sectornum = 0;
1618 file->eof = false;
1619 #ifdef HAVE_MULTIVOLUME
1620 file->volume = volume;
1621 /* fixme: remove error check when done */
1622 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1624 LDEBUGF("fat_open() illegal volume %d\n", volume);
1625 return -1;
1627 #endif
1629 /* remember where the file's dir entry is located */
1630 if ( dir ) {
1631 file->direntry = dir->entry - 1;
1632 file->direntries = dir->entrycount;
1633 file->dircluster = dir->file.firstcluster;
1635 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1636 return 0;
1639 int fat_create_file(const char* name,
1640 struct fat_file* file,
1641 struct fat_dir* dir)
1643 int rc;
1645 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1646 rc = add_dir_entry(dir, file, name, false, false);
1647 if (!rc) {
1648 file->firstcluster = 0;
1649 file->lastcluster = 0;
1650 file->lastsector = 0;
1651 file->clusternum = 0;
1652 file->sectornum = 0;
1653 file->eof = false;
1656 return rc;
1659 int fat_create_dir(const char* name,
1660 struct fat_dir* newdir,
1661 struct fat_dir* dir)
1663 #ifdef HAVE_MULTIVOLUME
1664 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1665 #else
1666 struct bpb* fat_bpb = &fat_bpbs[0];
1667 #endif
1668 unsigned char buf[SECTOR_SIZE];
1669 int i;
1670 long sector;
1671 int rc;
1672 struct fat_file dummyfile;
1674 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1676 memset(newdir, 0, sizeof(struct fat_dir));
1677 memset(&dummyfile, 0, sizeof(struct fat_file));
1679 /* First, add the entry in the parent directory */
1680 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1681 if (rc < 0)
1682 return rc * 10 - 1;
1684 /* Allocate a new cluster for the directory */
1685 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1686 fat_bpb->fsinfo.nextfree);
1687 if(newdir->file.firstcluster == 0)
1688 return -1;
1690 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1692 /* Clear the entire cluster */
1693 memset(buf, 0, sizeof buf);
1694 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1695 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1696 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1697 if (rc < 0)
1698 return rc * 10 - 2;
1701 /* Then add the "." entry */
1702 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1703 if (rc < 0)
1704 return rc * 10 - 3;
1705 dummyfile.firstcluster = newdir->file.firstcluster;
1706 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1708 /* and the ".." entry */
1709 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1710 if (rc < 0)
1711 return rc * 10 - 4;
1713 /* The root cluster is cluster 0 in the ".." entry */
1714 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1715 dummyfile.firstcluster = 0;
1716 else
1717 dummyfile.firstcluster = dir->file.firstcluster;
1718 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1720 /* Set the firstcluster field in the direntry */
1721 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1723 rc = flush_fat(IF_MV(fat_bpb));
1724 if (rc < 0)
1725 return rc * 10 - 5;
1727 return rc;
1730 int fat_truncate(const struct fat_file *file)
1732 /* truncate trailing clusters */
1733 long next;
1734 long last = file->lastcluster;
1735 #ifdef HAVE_MULTIVOLUME
1736 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1737 #endif
1739 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1741 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1742 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1743 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1745 if (file->lastcluster)
1746 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1748 return 0;
1751 int fat_closewrite(struct fat_file *file, long size, int attr)
1753 int rc;
1754 #ifdef HAVE_MULTIVOLUME
1755 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1756 #endif
1757 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1759 if (!size) {
1760 /* empty file */
1761 if ( file->firstcluster ) {
1762 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1763 file->firstcluster = 0;
1767 if (file->dircluster) {
1768 rc = update_short_entry(file, size, attr);
1769 if (rc < 0)
1770 return rc * 10 - 1;
1773 flush_fat(IF_MV(fat_bpb));
1775 #ifdef TEST_FAT
1776 if ( file->firstcluster ) {
1777 /* debug */
1778 #ifdef HAVE_MULTIVOLUME
1779 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1780 #else
1781 struct bpb* fat_bpb = &fat_bpbs[0];
1782 #endif
1783 long count = 0;
1784 long len;
1785 long next;
1786 for ( next = file->firstcluster; next;
1787 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1788 LDEBUGF("cluster %ld: %lx\n", count, next);
1789 count++;
1791 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1792 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1793 count, len, size );
1794 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1795 panicf("Cluster chain is too long\n");
1796 if ( len < size )
1797 panicf("Cluster chain is too short\n");
1799 #endif
1801 return 0;
1804 static int free_direntries(struct fat_file* file)
1806 unsigned char buf[SECTOR_SIZE];
1807 struct fat_file dir;
1808 int numentries = file->direntries;
1809 unsigned int entry = file->direntry - numentries + 1;
1810 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1811 int i;
1812 int rc;
1814 /* create a temporary file handle for the dir holding this file */
1815 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1816 if (rc < 0)
1817 return rc * 10 - 1;
1819 rc = fat_seek( &dir, sector );
1820 if (rc < 0)
1821 return rc * 10 - 2;
1823 rc = fat_readwrite(&dir, 1, buf, false);
1824 if (rc < 1)
1825 return rc * 10 - 3;
1827 for (i=0; i < numentries; i++) {
1828 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1829 entry, i+1, numentries);
1830 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1831 entry++;
1833 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1834 /* flush this sector */
1835 rc = fat_seek(&dir, sector);
1836 if (rc < 0)
1837 return rc * 10 - 4;
1839 rc = fat_readwrite(&dir, 1, buf, true);
1840 if (rc < 1)
1841 return rc * 10 - 5;
1843 if ( i+1 < numentries ) {
1844 /* read next sector */
1845 rc = fat_readwrite(&dir, 1, buf, false);
1846 if (rc < 1)
1847 return rc * 10 - 6;
1849 sector++;
1853 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1854 /* flush this sector */
1855 rc = fat_seek(&dir, sector);
1856 if (rc < 0)
1857 return rc * 10 - 7;
1859 rc = fat_readwrite(&dir, 1, buf, true);
1860 if (rc < 1)
1861 return rc * 10 - 8;
1864 return 0;
1867 int fat_remove(struct fat_file* file)
1869 long next, last = file->firstcluster;
1870 int rc;
1871 #ifdef HAVE_MULTIVOLUME
1872 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1873 #endif
1875 LDEBUGF("fat_remove(%lx)\n",last);
1877 while ( last ) {
1878 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1879 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1880 last = next;
1883 if ( file->dircluster ) {
1884 rc = free_direntries(file);
1885 if (rc < 0)
1886 return rc * 10 - 1;
1889 file->firstcluster = 0;
1890 file->dircluster = 0;
1892 rc = flush_fat(IF_MV(fat_bpb));
1893 if (rc < 0)
1894 return rc * 10 - 2;
1896 return 0;
1899 int fat_rename(struct fat_file* file,
1900 struct fat_dir* dir,
1901 const unsigned char* newname,
1902 long size,
1903 int attr)
1905 int rc;
1906 struct fat_dir olddir;
1907 struct fat_file newfile = *file;
1908 unsigned char buf[SECTOR_SIZE];
1909 unsigned char* entry = NULL;
1910 unsigned short* clusptr = NULL;
1911 unsigned int parentcluster;
1912 #ifdef HAVE_MULTIVOLUME
1913 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1915 if (file->volume != dir->file.volume) {
1916 DEBUGF("No rename across volumes!\n");
1917 return -1;
1919 #else
1920 struct bpb* fat_bpb = &fat_bpbs[0];
1921 #endif
1923 if ( !file->dircluster ) {
1924 DEBUGF("File has no dir cluster!\n");
1925 return -2;
1928 /* create a temporary file handle */
1929 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1930 if (rc < 0)
1931 return rc * 10 - 1;
1933 /* create new name */
1934 rc = add_dir_entry(dir, &newfile, newname, false, false);
1935 if (rc < 0)
1936 return rc * 10 - 2;
1938 /* write size and cluster link */
1939 rc = update_short_entry(&newfile, size, attr);
1940 if (rc < 0)
1941 return rc * 10 - 3;
1943 /* remove old name */
1944 rc = free_direntries(file);
1945 if (rc < 0)
1946 return rc * 10 - 4;
1948 rc = flush_fat(IF_MV(fat_bpb));
1949 if (rc < 0)
1950 return rc * 10 - 5;
1952 /* if renaming a directory, update the .. entry to make sure
1953 it points to its parent directory (we don't check if it was a move) */
1954 if(FAT_ATTR_DIRECTORY == attr) {
1955 /* open the dir that was renamed, we re-use the olddir struct */
1956 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1957 NULL);
1958 if (rc < 0)
1959 return rc * 10 - 6;
1961 /* get the first sector of the dir */
1962 rc = fat_seek(&olddir.file, 0);
1963 if (rc < 0)
1964 return rc * 10 - 7;
1966 rc = fat_readwrite(&olddir.file, 1, buf, false);
1967 if (rc < 0)
1968 return rc * 10 - 8;
1970 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1971 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1972 parentcluster = 0;
1973 else
1974 parentcluster = dir->file.firstcluster;
1976 entry = buf + DIR_ENTRY_SIZE;
1977 if(strncmp(".. ", entry, 11))
1979 /* .. entry must be second entry according to FAT spec (p.29) */
1980 DEBUGF("Second dir entry is not double-dot!\n");
1981 return rc * 10 - 9;
1983 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1984 *clusptr = htole16(parentcluster >> 16);
1986 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1987 *clusptr = htole16(parentcluster & 0xffff);
1989 /* write back this sector */
1990 rc = fat_seek(&olddir.file, 0);
1991 if (rc < 0)
1992 return rc * 10 - 7;
1994 rc = fat_readwrite(&olddir.file, 1, buf, true);
1995 if (rc < 1)
1996 return rc * 10 - 8;
1999 return 0;
2002 static long next_write_cluster(struct fat_file* file,
2003 long oldcluster,
2004 long* newsector)
2006 #ifdef HAVE_MULTIVOLUME
2007 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2008 #else
2009 struct bpb* fat_bpb = &fat_bpbs[0];
2010 #endif
2011 long cluster = 0;
2012 long sector;
2014 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2016 if (oldcluster)
2017 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2019 if (!cluster) {
2020 if (oldcluster > 0)
2021 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2022 else if (oldcluster == 0)
2023 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2024 fat_bpb->fsinfo.nextfree);
2025 #ifdef HAVE_FAT16SUPPORT
2026 else /* negative, pseudo-cluster of the root dir */
2027 return 0; /* impossible to append something to the root */
2028 #endif
2030 if (cluster) {
2031 if (oldcluster)
2032 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2033 else
2034 file->firstcluster = cluster;
2035 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2037 else {
2038 #ifdef TEST_FAT
2039 if (fat_bpb->fsinfo.freecount>0)
2040 panicf("There is free space, but find_free_cluster() "
2041 "didn't find it!\n");
2042 #endif
2043 DEBUGF("next_write_cluster(): Disk full!\n");
2044 return 0;
2047 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2048 if (sector<0)
2049 return 0;
2051 *newsector = sector;
2052 return cluster;
2055 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2056 unsigned long start, long count, char* buf, bool write )
2058 #ifndef HAVE_MULTIVOLUME
2059 struct bpb* fat_bpb = &fat_bpbs[0];
2060 #endif
2061 int rc;
2063 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2064 start+ fat_bpb->startsector, count, write?"write":"read");
2065 if (write) {
2066 unsigned long firstallowed;
2067 #ifdef HAVE_FAT16SUPPORT
2068 if (fat_bpb->is_fat16)
2069 firstallowed = fat_bpb->rootdirsector;
2070 else
2071 #endif
2072 firstallowed = fat_bpb->firstdatasector;
2074 if (start < firstallowed)
2075 panicf("Write %ld before data\n", firstallowed - start);
2076 if (start + count > fat_bpb->totalsectors)
2077 panicf("Write %ld after data\n",
2078 start + count - fat_bpb->totalsectors);
2079 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
2080 start + fat_bpb->startsector, count, buf);
2082 else
2083 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
2084 start + fat_bpb->startsector, count, buf);
2085 if (rc < 0) {
2086 DEBUGF( "transfer() - Couldn't %s sector %lx"
2087 " (error code %d)\n",
2088 write ? "write":"read", start, rc);
2089 return rc;
2091 return 0;
2095 long fat_readwrite( struct fat_file *file, long sectorcount,
2096 void* buf, bool write )
2098 #ifdef HAVE_MULTIVOLUME
2099 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2100 #else
2101 struct bpb* fat_bpb = &fat_bpbs[0];
2102 #endif
2103 long cluster = file->lastcluster;
2104 long sector = file->lastsector;
2105 long clusternum = file->clusternum;
2106 long numsec = file->sectornum;
2107 bool eof = file->eof;
2108 long first=0, last=0;
2109 long i;
2110 int rc;
2112 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2113 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2114 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2115 sector,numsec, eof?1:0);
2117 if ( eof && !write)
2118 return 0;
2120 /* find sequential sectors and write them all at once */
2121 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2122 numsec++;
2123 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2124 long oldcluster = cluster;
2125 long oldsector = sector;
2126 long oldnumsec = numsec;
2127 if (write)
2128 cluster = next_write_cluster(file, cluster, &sector);
2129 else {
2130 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2131 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2134 clusternum++;
2135 numsec=1;
2137 if (!cluster) {
2138 eof = true;
2139 if ( write ) {
2140 /* remember last cluster, in case
2141 we want to append to the file */
2142 sector = oldsector;
2143 cluster = oldcluster;
2144 numsec = oldnumsec;
2145 clusternum--;
2146 i = -1; /* Error code */
2147 break;
2150 else
2151 eof = false;
2153 else {
2154 if (sector)
2155 sector++;
2156 else {
2157 /* look up first sector of file */
2158 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2159 numsec=1;
2160 #ifdef HAVE_FAT16SUPPORT
2161 if (file->firstcluster < 0)
2162 { /* FAT16 root dir */
2163 sector += fat_bpb->rootdiroffset;
2164 numsec += fat_bpb->rootdiroffset;
2166 #endif
2170 if (!first)
2171 first = sector;
2173 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2174 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2175 long count = last - first + 1;
2176 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2177 if (rc < 0)
2178 return rc * 10 - 1;
2180 buf = (char *)buf + count * SECTOR_SIZE;
2181 first = sector;
2184 if ((i == sectorcount-1) && /* last sector requested */
2185 (!eof))
2187 long count = sector - first + 1;
2188 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2189 if (rc < 0)
2190 return rc * 10 - 2;
2193 last = sector;
2196 file->lastcluster = cluster;
2197 file->lastsector = sector;
2198 file->clusternum = clusternum;
2199 file->sectornum = numsec;
2200 file->eof = eof;
2202 /* if eof, don't report last block as read/written */
2203 if (eof)
2204 i--;
2206 DEBUGF("Sectors written: %ld\n", i);
2207 return i;
2210 int fat_seek(struct fat_file *file, unsigned long seeksector )
2212 #ifdef HAVE_MULTIVOLUME
2213 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2214 #else
2215 struct bpb* fat_bpb = &fat_bpbs[0];
2216 #endif
2217 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2218 long cluster = file->firstcluster;
2219 long i;
2221 #ifdef HAVE_FAT16SUPPORT
2222 if (cluster < 0) /* FAT16 root dir */
2223 seeksector += fat_bpb->rootdiroffset;
2224 #endif
2226 file->eof = false;
2227 if (seeksector) {
2228 /* we need to find the sector BEFORE the requested, since
2229 the file struct stores the last accessed sector */
2230 seeksector--;
2231 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2232 sectornum = seeksector % fat_bpb->bpb_secperclus;
2234 if (file->clusternum && clusternum >= file->clusternum)
2236 cluster = file->lastcluster;
2237 numclusters -= file->clusternum;
2240 for (i=0; i<numclusters; i++) {
2241 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2242 if (!cluster) {
2243 DEBUGF("Seeking beyond the end of the file! "
2244 "(sector %ld, cluster %ld)\n", seeksector, i);
2245 return -1;
2249 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2251 else {
2252 sectornum = -1;
2255 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2256 file->firstcluster, seeksector, cluster, sector, sectornum);
2258 file->lastcluster = cluster;
2259 file->lastsector = sector;
2260 file->clusternum = clusternum;
2261 file->sectornum = sectornum + 1;
2262 return 0;
2265 int fat_opendir(IF_MV2(int volume,)
2266 struct fat_dir *dir, unsigned long startcluster,
2267 const struct fat_dir *parent_dir)
2269 #ifdef HAVE_MULTIVOLUME
2270 struct bpb* fat_bpb = &fat_bpbs[volume];
2271 /* fixme: remove error check when done */
2272 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2274 LDEBUGF("fat_open() illegal volume %d\n", volume);
2275 return -1;
2277 #else
2278 struct bpb* fat_bpb = &fat_bpbs[0];
2279 #endif
2280 int rc;
2282 dir->entry = 0;
2283 dir->sector = 0;
2285 if (startcluster == 0)
2286 startcluster = fat_bpb->bpb_rootclus;
2288 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2289 if(rc)
2291 DEBUGF( "fat_opendir() - Couldn't open dir"
2292 " (error code %d)\n", rc);
2293 return rc * 10 - 1;
2296 return 0;
2299 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2300 * destination buffer (UTF-8 encoded). Copying is stopped when
2301 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2302 * Trailing \0 is also appended at the end of the UTF8-encoded
2303 * string.
2305 * utf16src utf16 (little endian) segment to copy
2306 * utf16count max number of the utf16-characters to copy
2307 * utf8dst where to write UTF8-encoded string to
2309 * returns the number of UTF-16 characters actually copied
2311 static int fat_copy_long_name_segment(unsigned char *utf16src,
2312 int utf16count, unsigned char *utf8dst) {
2313 int cnt = 0;
2314 while ((utf16count--) > 0) {
2315 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2316 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2317 break;
2319 utf8dst = utf8encode(ucs, utf8dst);
2320 utf16src += 2;
2321 cnt++;
2323 *utf8dst = 0;
2324 return cnt;
2327 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2329 bool done = false;
2330 int i;
2331 int rc;
2332 unsigned char firstbyte;
2333 /* Long file names are stored in special entries. Each entry holds
2334 up to 13 characters. Names can be max 255 chars (not bytes!) long
2335 hence max 20 entries are required. */
2336 int longarray[20];
2337 int longs=0;
2338 int sectoridx=0;
2339 unsigned char* cached_buf = dir->sectorcache[0];
2341 dir->entrycount = 0;
2343 while(!done)
2345 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2347 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2348 if (rc == 0) {
2349 /* eof */
2350 entry->name[0] = 0;
2351 break;
2353 if (rc < 0) {
2354 DEBUGF( "fat_getnext() - Couldn't read dir"
2355 " (error code %d)\n", rc);
2356 return rc * 10 - 1;
2358 dir->sector = dir->file.lastsector;
2361 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2362 i < DIR_ENTRIES_PER_SECTOR; i++)
2364 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2366 firstbyte = cached_buf[entrypos];
2367 dir->entry++;
2369 if (firstbyte == 0xe5) {
2370 /* free entry */
2371 sectoridx = 0;
2372 dir->entrycount = 0;
2373 continue;
2376 if (firstbyte == 0) {
2377 /* last entry */
2378 entry->name[0] = 0;
2379 dir->entrycount = 0;
2380 return 0;
2383 dir->entrycount++;
2385 /* longname entry? */
2386 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2387 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2388 longarray[longs++] = entrypos + sectoridx;
2390 else {
2391 if ( parse_direntry(entry,
2392 &cached_buf[entrypos]) ) {
2394 /* don't return volume id entry */
2395 if ( (entry->attr &
2396 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2397 == FAT_ATTR_VOLUME_ID)
2398 continue;
2400 /* replace shortname with longname? */
2401 if ( longs ) {
2402 int j;
2403 /* This should be enough to hold any name segment
2404 utf8-encoded */
2405 unsigned char shortname[13]; /* 8+3+dot+\0 */
2406 /* Add 1 for trailing \0 */
2407 unsigned char longname_utf8segm[6*4 + 1];
2408 int longname_utf8len = 0;
2409 /* Temporarily store it */
2410 strcpy(shortname, entry->name);
2411 entry->name[0] = 0;
2413 /* iterate backwards through the dir entries */
2414 for (j=longs-1; j>=0; j--) {
2415 unsigned char* ptr = cached_buf;
2416 int index = longarray[j];
2417 /* current or cached sector? */
2418 if ( sectoridx >= SECTOR_SIZE ) {
2419 if ( sectoridx >= SECTOR_SIZE*2 ) {
2420 if ( ( index >= SECTOR_SIZE ) &&
2421 ( index < SECTOR_SIZE*2 ))
2422 ptr = dir->sectorcache[1];
2423 else
2424 ptr = dir->sectorcache[2];
2426 else {
2427 if ( index < SECTOR_SIZE )
2428 ptr = dir->sectorcache[1];
2431 index &= SECTOR_SIZE-1;
2434 /* Try to append each segment of the long name.
2435 Check if we'd exceed the buffer.
2436 Also check for FAT padding characters 0xFFFF. */
2437 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2438 longname_utf8segm) == 0) break;
2439 /* logf("SG: %s, EN: %s", longname_utf8segm,
2440 entry->name); */
2441 longname_utf8len += strlen(longname_utf8segm);
2442 if (longname_utf8len < FAT_FILENAME_BYTES)
2443 strcat(entry->name, longname_utf8segm);
2444 else
2445 break;
2447 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2448 longname_utf8segm) == 0) break;
2449 /* logf("SG: %s, EN: %s", longname_utf8segm,
2450 entry->name); */
2451 longname_utf8len += strlen(longname_utf8segm);
2452 if (longname_utf8len < FAT_FILENAME_BYTES)
2453 strcat(entry->name, longname_utf8segm);
2454 else
2455 break;
2457 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2458 longname_utf8segm) == 0) break;
2459 /* logf("SG: %s, EN: %s", longname_utf8segm,
2460 entry->name); */
2461 longname_utf8len += strlen(longname_utf8segm);
2462 if (longname_utf8len < FAT_FILENAME_BYTES)
2463 strcat(entry->name, longname_utf8segm);
2464 else
2465 break;
2468 /* Does the utf8-encoded name fit into the entry? */
2469 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2470 /* Take the short DOS name. Need to utf8-encode it
2471 since it may contain chars from the upper half of
2472 the OEM code page which wouldn't be a valid utf8.
2473 Beware: this file will be shown with strange
2474 glyphs in file browser since unicode 0x80 to 0x9F
2475 are control characters. */
2476 logf("SN-DOS: %s", shortname);
2477 unsigned char *utf8;
2478 utf8 = iso_decode(shortname, entry->name, -1,
2479 strlen(shortname));
2480 *utf8 = 0;
2481 logf("SN: %s", entry->name);
2482 } else {
2483 /* logf("LN: %s", entry->name);
2484 logf("LNLen: %d (%c)", longname_utf8len,
2485 entry->name[0]); */
2488 done = true;
2489 sectoridx = 0;
2490 i++;
2491 break;
2496 /* save this sector, for longname use */
2497 if ( sectoridx )
2498 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2499 else
2500 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2501 sectoridx += SECTOR_SIZE;
2504 return 0;
2507 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2509 #ifndef HAVE_MULTIVOLUME
2510 const int volume = 0;
2511 #endif
2512 struct bpb* fat_bpb = &fat_bpbs[volume];
2513 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2516 #ifdef HAVE_MULTIVOLUME
2517 bool fat_ismounted(int volume)
2519 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2521 #endif