Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / firmware / drivers / fat.c
blob3130a3e2b4c25bc5c9c999465e160c127dd23684
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <stdbool.h>
26 #include "fat.h"
27 #include "ata.h"
28 #include "debug.h"
29 #include "panic.h"
30 #include "system.h"
31 #include "timefuncs.h"
32 #include "kernel.h"
33 #include "rbunicode.h"
34 #include "logf.h"
36 #define BYTES2INT16(array,pos) \
37 (array[pos] | (array[pos+1] << 8 ))
38 #define BYTES2INT32(array,pos) \
39 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
40 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
42 #define FATTYPE_FAT12 0
43 #define FATTYPE_FAT16 1
44 #define FATTYPE_FAT32 2
46 /* BPB offsets; generic */
47 #define BS_JMPBOOT 0
48 #define BS_OEMNAME 3
49 #define BPB_BYTSPERSEC 11
50 #define BPB_SECPERCLUS 13
51 #define BPB_RSVDSECCNT 14
52 #define BPB_NUMFATS 16
53 #define BPB_ROOTENTCNT 17
54 #define BPB_TOTSEC16 19
55 #define BPB_MEDIA 21
56 #define BPB_FATSZ16 22
57 #define BPB_SECPERTRK 24
58 #define BPB_NUMHEADS 26
59 #define BPB_HIDDSEC 28
60 #define BPB_TOTSEC32 32
62 /* fat12/16 */
63 #define BS_DRVNUM 36
64 #define BS_RESERVED1 37
65 #define BS_BOOTSIG 38
66 #define BS_VOLID 39
67 #define BS_VOLLAB 43
68 #define BS_FILSYSTYPE 54
70 /* fat32 */
71 #define BPB_FATSZ32 36
72 #define BPB_EXTFLAGS 40
73 #define BPB_FSVER 42
74 #define BPB_ROOTCLUS 44
75 #define BPB_FSINFO 48
76 #define BPB_BKBOOTSEC 50
77 #define BS_32_DRVNUM 64
78 #define BS_32_BOOTSIG 66
79 #define BS_32_VOLID 67
80 #define BS_32_VOLLAB 71
81 #define BS_32_FILSYSTYPE 82
83 #define BPB_LAST_WORD 510
86 /* attributes */
87 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
88 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
89 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
90 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
91 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
93 /* NTRES flags */
94 #define FAT_NTRES_LC_NAME 0x08
95 #define FAT_NTRES_LC_EXT 0x10
97 #define FATDIR_NAME 0
98 #define FATDIR_ATTR 11
99 #define FATDIR_NTRES 12
100 #define FATDIR_CRTTIMETENTH 13
101 #define FATDIR_CRTTIME 14
102 #define FATDIR_CRTDATE 16
103 #define FATDIR_LSTACCDATE 18
104 #define FATDIR_FSTCLUSHI 20
105 #define FATDIR_WRTTIME 22
106 #define FATDIR_WRTDATE 24
107 #define FATDIR_FSTCLUSLO 26
108 #define FATDIR_FILESIZE 28
110 #define FATLONG_ORDER 0
111 #define FATLONG_TYPE 12
112 #define FATLONG_CHKSUM 13
114 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
115 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
116 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
117 #define DIR_ENTRY_SIZE 32
118 #define NAME_BYTES_PER_ENTRY 13
119 #define FAT_BAD_MARK 0x0ffffff7
120 #define FAT_EOF_MARK 0x0ffffff8
121 #define FAT_LONGNAME_PAD_BYTE 0xff
122 #define FAT_LONGNAME_PAD_UCS 0xffff
124 struct fsinfo {
125 unsigned long freecount; /* last known free cluster count */
126 unsigned long nextfree; /* first cluster to start looking for free
127 clusters, or 0xffffffff for no hint */
129 /* fsinfo offsets */
130 #define FSINFO_FREECOUNT 488
131 #define FSINFO_NEXTFREE 492
133 /* Note: This struct doesn't hold the raw values after mounting if
134 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
135 * physical sectors. */
136 struct bpb
138 int bpb_bytspersec; /* Bytes per sector, typically 512 */
139 unsigned int bpb_secperclus; /* Sectors per cluster */
140 int bpb_rsvdseccnt; /* Number of reserved sectors */
141 int bpb_numfats; /* Number of FAT structures, typically 2 */
142 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
143 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
144 int bpb_fatsz16; /* Number of used sectors per FAT structure */
145 unsigned long bpb_totsec32; /* Number of sectors on the volume
146 (new 32-bit) */
147 unsigned int last_word; /* 0xAA55 */
149 /**** FAT32 specific *****/
150 long bpb_fatsz32;
151 long bpb_rootclus;
152 long bpb_fsinfo;
154 /* variables for internal use */
155 unsigned long fatsize;
156 unsigned long totalsectors;
157 unsigned long rootdirsector;
158 unsigned long firstdatasector;
159 unsigned long startsector;
160 unsigned long dataclusters;
161 struct fsinfo fsinfo;
162 #ifdef HAVE_FAT16SUPPORT
163 int bpb_rootentcnt; /* Number of dir entries in the root */
164 /* internals for FAT16 support */
165 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
166 unsigned int rootdiroffset; /* sector offset of root dir relative to start
167 * of first pseudo cluster */
168 #endif /* #ifdef HAVE_FAT16SUPPORT */
169 #ifdef HAVE_MULTIVOLUME
170 int drive; /* on which physical device is this located */
171 bool mounted; /* flag if this volume is mounted */
172 #endif
175 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
176 static bool initialized = false;
178 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
179 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
180 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
181 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
182 long secnum, bool dirty);
183 static void create_dos_name(const unsigned char *name, unsigned char *newname);
184 static void randomize_dos_name(unsigned char *name);
185 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
186 unsigned long start);
187 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
188 long count, char* buf, bool write );
190 #define FAT_CACHE_SIZE 0x20
191 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
193 struct fat_cache_entry
195 long secnum;
196 bool inuse;
197 bool dirty;
198 #ifdef HAVE_MULTIVOLUME
199 struct bpb* fat_vol ; /* shared cache for all volumes */
200 #endif
203 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
204 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
205 static struct mutex cache_mutex SHAREDBSS_ATTR;
207 #if defined(HAVE_HOTSWAP) && !defined(HAVE_MMC) /* A better condition ?? */
208 void fat_lock(void)
210 mutex_lock(&cache_mutex);
213 void fat_unlock(void)
215 mutex_unlock(&cache_mutex);
217 #endif
219 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
221 #ifndef HAVE_MULTIVOLUME
222 struct bpb* fat_bpb = &fat_bpbs[0];
223 #endif
224 #ifdef HAVE_FAT16SUPPORT
225 /* negative clusters (FAT16 root dir) don't get the 2 offset */
226 int zerocluster = cluster < 0 ? 0 : 2;
227 #else
228 const long zerocluster = 2;
229 #endif
231 if (cluster > (long)(fat_bpb->dataclusters + 1))
233 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
234 return -1;
237 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
238 + fat_bpb->firstdatasector;
241 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
243 #ifndef HAVE_MULTIVOLUME
244 const int volume = 0;
245 #endif
246 struct bpb* fat_bpb = &fat_bpbs[volume];
247 if (size)
248 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
249 if (free)
250 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
253 void fat_init(void)
255 unsigned int i;
257 if (!initialized)
259 initialized = true;
260 mutex_init(&cache_mutex);
263 #ifdef HAVE_PRIORITY_SCHEDULING
264 /* Disable this because it is dangerous due to the assumption that
265 * mutex_unlock won't yield */
266 mutex_set_preempt(&cache_mutex, false);
267 #endif
269 /* mark the FAT cache as unused */
270 for(i = 0;i < FAT_CACHE_SIZE;i++)
272 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
273 fat_cache[i].inuse = false;
274 fat_cache[i].dirty = false;
275 #ifdef HAVE_MULTIVOLUME
276 fat_cache[i].fat_vol = NULL;
277 #endif
279 #ifdef HAVE_MULTIVOLUME
280 /* mark the possible volumes as not mounted */
281 for (i=0; i<NUM_VOLUMES;i++)
283 fat_bpbs[i].mounted = false;
285 #endif
288 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
290 #ifndef HAVE_MULTIVOLUME
291 const int volume = 0;
292 #endif
293 struct bpb* fat_bpb = &fat_bpbs[volume];
294 unsigned char buf[SECTOR_SIZE];
295 int rc;
296 int secmult;
297 long datasec;
298 #ifdef HAVE_FAT16SUPPORT
299 int rootdirsectors;
300 #endif
302 /* Read the sector */
303 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
304 if(rc)
306 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
307 return rc * 10 - 1;
310 memset(fat_bpb, 0, sizeof(struct bpb));
311 fat_bpb->startsector = startsector;
312 #ifdef HAVE_MULTIVOLUME
313 fat_bpb->drive = drive;
314 #endif
316 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
317 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
318 /* Sanity check is performed later */
320 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
321 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
322 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
323 fat_bpb->bpb_media = buf[BPB_MEDIA];
324 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
325 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
326 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
327 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
328 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
330 /* calculate a few commonly used values */
331 if (fat_bpb->bpb_fatsz16 != 0)
332 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
333 else
334 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
336 if (fat_bpb->bpb_totsec16 != 0)
337 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
338 else
339 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
341 #ifdef HAVE_FAT16SUPPORT
342 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
343 if (!fat_bpb->bpb_bytspersec)
344 return -2;
345 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
346 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
347 #endif /* #ifdef HAVE_FAT16SUPPORT */
349 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
350 #ifdef HAVE_FAT16SUPPORT
351 + rootdirsectors
352 #endif
353 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
355 /* Determine FAT type */
356 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
357 if (fat_bpb->bpb_secperclus)
358 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
359 else
360 return -2;
362 #ifdef TEST_FAT
364 we are sometimes testing with "illegally small" fat32 images,
365 so we don't use the proper fat32 test case for test code
367 if ( fat_bpb->bpb_fatsz16 )
368 #else
369 if ( fat_bpb->dataclusters < 65525 )
370 #endif
371 { /* FAT16 */
372 #ifdef HAVE_FAT16SUPPORT
373 fat_bpb->is_fat16 = true;
374 if (fat_bpb->dataclusters < 4085)
375 { /* FAT12 */
376 DEBUGF("This is FAT12. Go away!\n");
377 return -2;
379 #else /* #ifdef HAVE_FAT16SUPPORT */
380 DEBUGF("This is not FAT32. Go away!\n");
381 return -2;
382 #endif /* #ifndef HAVE_FAT16SUPPORT */
385 #ifdef HAVE_FAT16SUPPORT
386 if (fat_bpb->is_fat16)
387 { /* FAT16 specific part of BPB */
388 int dirclusters;
389 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
390 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
391 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
392 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
393 /* I assign negative pseudo cluster numbers for the root directory,
394 their range is counted upward until -1. */
395 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
396 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
397 - rootdirsectors;
399 else
400 #endif /* #ifdef HAVE_FAT16SUPPORT */
401 { /* FAT32 specific part of BPB */
402 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
403 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
404 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
405 fat_bpb->bpb_rootclus);
408 rc = bpb_is_sane(IF_MV(fat_bpb));
409 if (rc < 0)
411 DEBUGF( "fat_mount() - BPB is not sane\n");
412 return rc * 10 - 3;
415 #ifdef HAVE_FAT16SUPPORT
416 if (fat_bpb->is_fat16)
418 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
419 fat_bpb->fsinfo.nextfree = 0xffffffff;
421 else
422 #endif /* #ifdef HAVE_FAT16SUPPORT */
424 /* Read the fsinfo sector */
425 rc = ata_read_sectors(IF_MV2(drive,)
426 startsector + fat_bpb->bpb_fsinfo, 1, buf);
427 if (rc < 0)
429 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
430 return rc * 10 - 4;
432 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
433 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
436 /* calculate freecount if unset */
437 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
439 fat_recalc_free(IF_MV(volume));
442 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
443 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
444 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
445 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
446 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
448 #ifdef HAVE_MULTIVOLUME
449 fat_bpb->mounted = true;
450 #endif
452 return 0;
455 #ifdef HAVE_HOTSWAP
456 int fat_unmount(int volume, bool flush)
458 int rc;
459 struct bpb* fat_bpb = &fat_bpbs[volume];
461 if(flush)
463 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
465 else
466 { /* volume is not accessible any more, e.g. MMC removed */
467 int i;
468 mutex_lock(&cache_mutex);
469 for(i = 0;i < FAT_CACHE_SIZE;i++)
471 struct fat_cache_entry *fce = &fat_cache[i];
472 if(fce->inuse && fce->fat_vol == fat_bpb)
474 fce->inuse = false; /* discard all from that volume */
475 fce->dirty = false;
478 mutex_unlock(&cache_mutex);
479 rc = 0;
481 fat_bpb->mounted = false;
482 return rc;
484 #endif /* #ifdef HAVE_HOTSWAP */
486 void fat_recalc_free(IF_MV_NONVOID(int volume))
488 #ifndef HAVE_MULTIVOLUME
489 const int volume = 0;
490 #endif
491 struct bpb* fat_bpb = &fat_bpbs[volume];
492 long free = 0;
493 unsigned long i;
494 #ifdef HAVE_FAT16SUPPORT
495 if (fat_bpb->is_fat16)
497 for (i = 0; i<fat_bpb->fatsize; i++) {
498 unsigned int j;
499 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
500 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
501 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
502 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
503 break;
505 if (letoh16(fat[j]) == 0x0000) {
506 free++;
507 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
508 fat_bpb->fsinfo.nextfree = c;
513 else
514 #endif /* #ifdef HAVE_FAT16SUPPORT */
516 for (i = 0; i<fat_bpb->fatsize; i++) {
517 unsigned int j;
518 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
519 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
520 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
521 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
522 break;
524 if (!(letoh32(fat[j]) & 0x0fffffff)) {
525 free++;
526 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
527 fat_bpb->fsinfo.nextfree = c;
532 fat_bpb->fsinfo.freecount = free;
533 update_fsinfo(IF_MV(fat_bpb));
536 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
538 #ifndef HAVE_MULTIVOLUME
539 struct bpb* fat_bpb = &fat_bpbs[0];
540 #endif
541 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
543 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
544 fat_bpb->bpb_bytspersec);
545 return -1;
547 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
548 > 128L*1024L)
550 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
551 "(%d * %d = %d)\n",
552 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
553 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
554 return -2;
556 if(fat_bpb->bpb_numfats != 2)
558 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
559 fat_bpb->bpb_numfats);
561 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
563 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
564 "media type (0x%02x)\n",
565 fat_bpb->bpb_media);
567 if(fat_bpb->last_word != 0xaa55)
569 DEBUGF( "bpb_is_sane() - Error: Last word is not "
570 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
571 return -3;
574 if (fat_bpb->fsinfo.freecount >
575 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
576 fat_bpb->bpb_secperclus)
578 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
579 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
580 return -4;
583 return 0;
586 static void flush_fat_sector(struct fat_cache_entry *fce,
587 unsigned char *sectorbuf)
589 int rc;
590 long secnum;
592 /* With multivolume, use only the FAT info from the cached sector! */
593 #ifdef HAVE_MULTIVOLUME
594 secnum = fce->secnum + fce->fat_vol->startsector;
595 #else
596 secnum = fce->secnum + fat_bpbs[0].startsector;
597 #endif
599 /* Write to the first FAT */
600 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
601 secnum, 1,
602 sectorbuf);
603 if(rc < 0)
605 panicf("flush_fat_sector() - Could not write sector %ld"
606 " (error %d)\n",
607 secnum, rc);
609 #ifdef HAVE_MULTIVOLUME
610 if(fce->fat_vol->bpb_numfats > 1)
611 #else
612 if(fat_bpbs[0].bpb_numfats > 1)
613 #endif
615 /* Write to the second FAT */
616 #ifdef HAVE_MULTIVOLUME
617 secnum += fce->fat_vol->fatsize;
618 #else
619 secnum += fat_bpbs[0].fatsize;
620 #endif
621 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
622 secnum, 1, sectorbuf);
623 if(rc < 0)
625 panicf("flush_fat_sector() - Could not write sector %ld"
626 " (error %d)\n",
627 secnum, rc);
630 fce->dirty = false;
633 /* Note: The returned pointer is only safely valid until the next
634 task switch! (Any subsequent ata read/write may yield.) */
635 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
636 long fatsector, bool dirty)
638 #ifndef HAVE_MULTIVOLUME
639 struct bpb* fat_bpb = &fat_bpbs[0];
640 #endif
641 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
642 int cache_index = secnum & FAT_CACHE_MASK;
643 struct fat_cache_entry *fce = &fat_cache[cache_index];
644 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
645 int rc;
647 mutex_lock(&cache_mutex); /* make changes atomic */
649 /* Delete the cache entry if it isn't the sector we want */
650 if(fce->inuse && (fce->secnum != secnum
651 #ifdef HAVE_MULTIVOLUME
652 || fce->fat_vol != fat_bpb
653 #endif
656 /* Write back if it is dirty */
657 if(fce->dirty)
659 flush_fat_sector(fce, sectorbuf);
661 fce->inuse = false;
664 /* Load the sector if it is not cached */
665 if(!fce->inuse)
667 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
668 secnum + fat_bpb->startsector,1,
669 sectorbuf);
670 if(rc < 0)
672 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
673 " (error %d)\n", secnum, rc);
674 mutex_unlock(&cache_mutex);
675 return NULL;
677 fce->inuse = true;
678 fce->secnum = secnum;
679 #ifdef HAVE_MULTIVOLUME
680 fce->fat_vol = fat_bpb;
681 #endif
683 if (dirty)
684 fce->dirty = true; /* dirt remains, sticky until flushed */
685 mutex_unlock(&cache_mutex);
686 return sectorbuf;
689 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
690 unsigned long startcluster)
692 #ifndef HAVE_MULTIVOLUME
693 struct bpb* fat_bpb = &fat_bpbs[0];
694 #endif
695 unsigned long sector;
696 unsigned long offset;
697 unsigned long i;
699 #ifdef HAVE_FAT16SUPPORT
700 if (fat_bpb->is_fat16)
702 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
703 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
705 for (i = 0; i<fat_bpb->fatsize; i++) {
706 unsigned int j;
707 unsigned int nr = (i + sector) % fat_bpb->fatsize;
708 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
709 if ( !fat )
710 break;
711 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
712 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
713 if (letoh16(fat[k]) == 0x0000) {
714 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
715 /* Ignore the reserved clusters 0 & 1, and also
716 cluster numbers out of bounds */
717 if ( c < 2 || c > fat_bpb->dataclusters+1 )
718 continue;
719 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
720 fat_bpb->fsinfo.nextfree = c;
721 return c;
724 offset = 0;
727 else
728 #endif /* #ifdef HAVE_FAT16SUPPORT */
730 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
731 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
733 for (i = 0; i<fat_bpb->fatsize; i++) {
734 unsigned int j;
735 unsigned long nr = (i + sector) % fat_bpb->fatsize;
736 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
737 if ( !fat )
738 break;
739 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
740 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
741 if (!(letoh32(fat[k]) & 0x0fffffff)) {
742 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
743 /* Ignore the reserved clusters 0 & 1, and also
744 cluster numbers out of bounds */
745 if ( c < 2 || c > fat_bpb->dataclusters+1 )
746 continue;
747 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
748 fat_bpb->fsinfo.nextfree = c;
749 return c;
752 offset = 0;
756 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
757 return 0; /* 0 is an illegal cluster number */
760 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
761 unsigned long val)
763 #ifndef HAVE_MULTIVOLUME
764 struct bpb* fat_bpb = &fat_bpbs[0];
765 #endif
766 #ifdef HAVE_FAT16SUPPORT
767 if (fat_bpb->is_fat16)
769 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
770 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
771 unsigned short* sec;
773 val &= 0xFFFF;
775 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
777 if (entry==val)
778 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
780 if ( entry < 2 )
781 panicf("Updating reserved FAT entry %ld.\n",entry);
783 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
784 if (!sec)
786 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
787 return -1;
790 if ( val ) {
791 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
792 fat_bpb->fsinfo.freecount--;
794 else {
795 if (letoh16(sec[offset]))
796 fat_bpb->fsinfo.freecount++;
799 LDEBUGF("update_fat_entry: %d free clusters\n",
800 fat_bpb->fsinfo.freecount);
802 sec[offset] = htole16(val);
804 else
805 #endif /* #ifdef HAVE_FAT16SUPPORT */
807 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
808 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
809 unsigned long* sec;
811 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
813 if (entry==val)
814 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
816 if ( entry < 2 )
817 panicf("Updating reserved FAT entry %ld.\n",entry);
819 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
820 if (!sec)
822 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
823 return -1;
826 if ( val ) {
827 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
828 fat_bpb->fsinfo.freecount > 0)
829 fat_bpb->fsinfo.freecount--;
831 else {
832 if (letoh32(sec[offset]) & 0x0fffffff)
833 fat_bpb->fsinfo.freecount++;
836 LDEBUGF("update_fat_entry: %ld free clusters\n",
837 fat_bpb->fsinfo.freecount);
839 /* don't change top 4 bits */
840 sec[offset] &= htole32(0xf0000000);
841 sec[offset] |= htole32(val & 0x0fffffff);
844 return 0;
847 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
849 #ifdef HAVE_FAT16SUPPORT
850 #ifndef HAVE_MULTIVOLUME
851 struct bpb* fat_bpb = &fat_bpbs[0];
852 #endif
853 if (fat_bpb->is_fat16)
855 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
856 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
857 unsigned short* sec;
859 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
860 if (!sec)
862 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
863 return -1;
866 return letoh16(sec[offset]);
868 else
869 #endif /* #ifdef HAVE_FAT16SUPPORT */
871 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
872 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
873 unsigned long* sec;
875 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
876 if (!sec)
878 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
879 return -1;
882 return letoh32(sec[offset]) & 0x0fffffff;
886 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
888 long next_cluster;
889 long eof_mark = FAT_EOF_MARK;
891 #ifdef HAVE_FAT16SUPPORT
892 #ifndef HAVE_MULTIVOLUME
893 struct bpb* fat_bpb = &fat_bpbs[0];
894 #endif
895 if (fat_bpb->is_fat16)
897 eof_mark &= 0xFFFF; /* only 16 bit */
898 if (cluster < 0) /* FAT16 root dir */
899 return cluster + 1; /* don't use the FAT */
901 #endif
902 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
904 /* is this last cluster in chain? */
905 if ( next_cluster >= eof_mark )
906 return 0;
907 else
908 return next_cluster;
911 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
913 #ifndef HAVE_MULTIVOLUME
914 struct bpb* fat_bpb = &fat_bpbs[0];
915 #endif
916 unsigned char fsinfo[SECTOR_SIZE];
917 unsigned long* intptr;
918 int rc;
920 #ifdef HAVE_FAT16SUPPORT
921 if (fat_bpb->is_fat16)
922 return 0; /* FAT16 has no FsInfo */
923 #endif /* #ifdef HAVE_FAT16SUPPORT */
925 /* update fsinfo */
926 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
927 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
928 if (rc < 0)
930 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
931 return rc * 10 - 1;
933 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
934 *intptr = htole32(fat_bpb->fsinfo.freecount);
936 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
937 *intptr = htole32(fat_bpb->fsinfo.nextfree);
939 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
940 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
941 if (rc < 0)
943 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
944 return rc * 10 - 2;
947 return 0;
950 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
952 int i;
953 int rc;
954 unsigned char *sec;
955 LDEBUGF("flush_fat()\n");
957 mutex_lock(&cache_mutex);
958 for(i = 0;i < FAT_CACHE_SIZE;i++)
960 struct fat_cache_entry *fce = &fat_cache[i];
961 if(fce->inuse
962 #ifdef HAVE_MULTIVOLUME
963 && fce->fat_vol == fat_bpb
964 #endif
965 && fce->dirty)
967 sec = fat_cache_sectors[i];
968 flush_fat_sector(fce, sec);
971 mutex_unlock(&cache_mutex);
973 rc = update_fsinfo(IF_MV(fat_bpb));
974 if (rc < 0)
975 return rc * 10 - 3;
977 return 0;
980 static void fat_time(unsigned short* date,
981 unsigned short* time,
982 unsigned short* tenth )
984 #if CONFIG_RTC
985 struct tm* tm = get_time();
987 if (date)
988 *date = ((tm->tm_year - 80) << 9) |
989 ((tm->tm_mon + 1) << 5) |
990 tm->tm_mday;
992 if (time)
993 *time = (tm->tm_hour << 11) |
994 (tm->tm_min << 5) |
995 (tm->tm_sec >> 1);
997 if (tenth)
998 *tenth = (tm->tm_sec & 1) * 100;
999 #else
1000 /* non-RTC version returns an increment from the supplied time, or a
1001 * fixed standard time/date if no time given as input */
1002 bool next_day = false;
1004 if (time)
1006 if (0 == *time)
1008 /* set to 00:15:00 */
1009 *time = (15 << 5);
1011 else
1013 unsigned short mins = (*time >> 5) & 0x003F;
1014 unsigned short hours = (*time >> 11) & 0x001F;
1015 if ((mins += 10) >= 60)
1017 mins = 0;
1018 hours++;
1020 if ((++hours) >= 24)
1022 hours = hours - 24;
1023 next_day = true;
1025 *time = (hours << 11) | (mins << 5);
1029 if (date)
1031 if (0 == *date)
1033 /* Macros to convert a 2-digit string to a decimal constant.
1034 (YEAR), MONTH and DAY are set by the date command, which outputs
1035 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1036 misinterpretation as an octal constant. */
1037 #define S100(x) 1 ## x
1038 #define C2DIG2DEC(x) (S100(x)-100)
1039 /* set to build date */
1040 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1041 | C2DIG2DEC(DAY);
1043 else
1045 unsigned short day = *date & 0x001F;
1046 unsigned short month = (*date >> 5) & 0x000F;
1047 unsigned short year = (*date >> 9) & 0x007F;
1048 if (next_day)
1050 /* do a very simple day increment - never go above 28 days */
1051 if (++day > 28)
1053 day = 1;
1054 if (++month > 12)
1056 month = 1;
1057 year++;
1060 *date = (year << 9) | (month << 5) | day;
1064 if (tenth)
1065 *tenth = 0;
1066 #endif /* CONFIG_RTC */
1069 static int write_long_name(struct fat_file* file,
1070 unsigned int firstentry,
1071 unsigned int numentries,
1072 const unsigned char* name,
1073 const unsigned char* shortname,
1074 bool is_directory)
1076 unsigned char buf[SECTOR_SIZE];
1077 unsigned char* entry;
1078 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1079 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1080 unsigned char chksum = 0;
1081 unsigned int i, j=0;
1082 unsigned int nameidx=0, namelen = utf8length(name);
1083 int rc;
1084 unsigned short name_utf16[namelen + 1];
1086 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1087 file->firstcluster, firstentry, numentries, name);
1089 rc = fat_seek(file, sector);
1090 if (rc<0)
1091 return rc * 10 - 1;
1093 rc = fat_readwrite(file, 1, buf, false);
1094 if (rc<1)
1095 return rc * 10 - 2;
1097 /* calculate shortname checksum */
1098 for (i=11; i>0; i--)
1099 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1101 /* calc position of last name segment */
1102 if ( namelen > NAME_BYTES_PER_ENTRY )
1103 for (nameidx=0;
1104 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1105 nameidx += NAME_BYTES_PER_ENTRY);
1107 /* we need to convert the name first */
1108 /* since it is written in reverse order */
1109 for (i = 0; i <= namelen; i++)
1110 name = utf8decode(name, &name_utf16[i]);
1112 for (i=0; i < numentries; i++) {
1113 /* new sector? */
1114 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1115 /* update current sector */
1116 rc = fat_seek(file, sector);
1117 if (rc<0)
1118 return rc * 10 - 3;
1120 rc = fat_readwrite(file, 1, buf, true);
1121 if (rc<1)
1122 return rc * 10 - 4;
1124 /* read next sector */
1125 rc = fat_readwrite(file, 1, buf, false);
1126 if (rc<0) {
1127 LDEBUGF("Failed writing new sector: %d\n",rc);
1128 return rc * 10 - 5;
1130 if (rc==0)
1131 /* end of dir */
1132 memset(buf, 0, sizeof buf);
1134 sector++;
1135 idx = 0;
1138 entry = buf + idx * DIR_ENTRY_SIZE;
1140 /* verify this entry is free */
1141 if (entry[0] && entry[0] != 0xe5 )
1142 panicf("Dir entry %d in sector %x is not free! "
1143 "%02x %02x %02x %02x",
1144 idx, sector,
1145 entry[0], entry[1], entry[2], entry[3]);
1147 memset(entry, 0, DIR_ENTRY_SIZE);
1148 if ( i+1 < numentries ) {
1149 /* longname entry */
1150 unsigned int k, l = nameidx;
1152 entry[FATLONG_ORDER] = numentries-i-1;
1153 if (i==0) {
1154 /* mark this as last long entry */
1155 entry[FATLONG_ORDER] |= 0x40;
1157 /* pad name with 0xffff */
1158 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1159 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1160 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1162 /* set name */
1163 for (k=0; k<5 && l <= namelen; k++) {
1164 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1165 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1167 for (k=0; k<6 && l <= namelen; k++) {
1168 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1169 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1171 for (k=0; k<2 && l <= namelen; k++) {
1172 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1173 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1176 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1177 entry[FATDIR_FSTCLUSLO] = 0;
1178 entry[FATLONG_TYPE] = 0;
1179 entry[FATLONG_CHKSUM] = chksum;
1180 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1182 else {
1183 /* shortname entry */
1184 unsigned short date=0, time=0, tenth=0;
1185 LDEBUGF("Shortname entry: %s\n", shortname);
1186 strncpy(entry + FATDIR_NAME, shortname, 11);
1187 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1188 entry[FATDIR_NTRES] = 0;
1190 fat_time(&date, &time, &tenth);
1191 entry[FATDIR_CRTTIMETENTH] = tenth;
1192 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1193 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1194 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1195 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1196 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1198 idx++;
1199 nameidx -= NAME_BYTES_PER_ENTRY;
1202 /* update last sector */
1203 rc = fat_seek(file, sector);
1204 if (rc<0)
1205 return rc * 10 - 6;
1207 rc = fat_readwrite(file, 1, buf, true);
1208 if (rc<1)
1209 return rc * 10 - 7;
1211 return 0;
1214 static int fat_checkname(const unsigned char* newname)
1216 static const char invalid_chars[] = "\"*/:<>?\\|";
1217 int len = strlen(newname);
1218 /* More sanity checks are probably needed */
1219 if (len > 255 || newname[len - 1] == '.')
1221 return -1;
1223 while (*newname)
1225 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1226 return -1;
1227 newname++;
1229 /* check trailing space(s) */
1230 if(*(--newname) == ' ')
1231 return -1;
1233 return 0;
1236 static int add_dir_entry(struct fat_dir* dir,
1237 struct fat_file* file,
1238 const char* name,
1239 bool is_directory,
1240 bool dotdir)
1242 #ifdef HAVE_MULTIVOLUME
1243 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1244 #else
1245 struct bpb* fat_bpb = &fat_bpbs[0];
1246 #endif
1247 unsigned char buf[SECTOR_SIZE];
1248 unsigned char shortname[12];
1249 int rc;
1250 unsigned int sector;
1251 bool done = false;
1252 int entries_needed, entries_found = 0;
1253 int firstentry;
1255 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1256 name, file->firstcluster);
1258 /* Don't check dotdirs name for validity */
1259 if (dotdir == false) {
1260 rc = fat_checkname(name);
1261 if (rc < 0) {
1262 /* filename is invalid */
1263 return rc * 10 - 1;
1267 #ifdef HAVE_MULTIVOLUME
1268 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1269 #endif
1271 /* The "." and ".." directory entries must not be long names */
1272 if(dotdir) {
1273 int i;
1274 strncpy(shortname, name, 12);
1275 for(i = strlen(shortname); i < 12; i++)
1276 shortname[i] = ' ';
1278 entries_needed = 1;
1279 } else {
1280 create_dos_name(name, shortname);
1282 /* one dir entry needed for every 13 bytes of filename,
1283 plus one entry for the short name */
1284 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1285 / NAME_BYTES_PER_ENTRY + 1;
1288 restart:
1289 firstentry = -1;
1291 rc = fat_seek(&dir->file, 0);
1292 if (rc < 0)
1293 return rc * 10 - 2;
1295 /* step 1: search for free entries and check for duplicate shortname */
1296 for (sector = 0; !done; sector++)
1298 unsigned int i;
1300 rc = fat_readwrite(&dir->file, 1, buf, false);
1301 if (rc < 0) {
1302 DEBUGF( "add_dir_entry() - Couldn't read dir"
1303 " (error code %d)\n", rc);
1304 return rc * 10 - 3;
1307 if (rc == 0) { /* current end of dir reached */
1308 LDEBUGF("End of dir on cluster boundary\n");
1309 break;
1312 /* look for free slots */
1313 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1315 switch (buf[i * DIR_ENTRY_SIZE]) {
1316 case 0:
1317 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1318 LDEBUGF("Found end of dir %d\n",
1319 sector * DIR_ENTRIES_PER_SECTOR + i);
1320 i = DIR_ENTRIES_PER_SECTOR - 1;
1321 done = true;
1322 break;
1324 case 0xe5:
1325 entries_found++;
1326 LDEBUGF("Found free entry %d (%d/%d)\n",
1327 sector * DIR_ENTRIES_PER_SECTOR + i,
1328 entries_found, entries_needed);
1329 break;
1331 default:
1332 entries_found = 0;
1334 /* check that our intended shortname doesn't already exist */
1335 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1336 /* shortname exists already, make a new one */
1337 randomize_dos_name(shortname);
1338 LDEBUGF("Duplicate shortname, changing to %s\n",
1339 shortname);
1341 /* name has changed, we need to restart search */
1342 goto restart;
1344 break;
1346 if (firstentry < 0 && (entries_found >= entries_needed))
1347 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1348 - entries_found;
1352 /* step 2: extend the dir if necessary */
1353 if (firstentry < 0)
1355 LDEBUGF("Adding new sector(s) to dir\n");
1356 rc = fat_seek(&dir->file, sector);
1357 if (rc < 0)
1358 return rc * 10 - 4;
1359 memset(buf, 0, sizeof buf);
1361 /* we must clear whole clusters */
1362 for (; (entries_found < entries_needed) ||
1363 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1365 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1366 return -5; /* dir too large -- FAT specification */
1368 rc = fat_readwrite(&dir->file, 1, buf, true);
1369 if (rc < 1) /* No more room or something went wrong */
1370 return rc * 10 - 6;
1372 entries_found += DIR_ENTRIES_PER_SECTOR;
1375 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1378 /* step 3: add entry */
1379 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1380 LDEBUGF("Adding longname to entry %d in sector %d\n",
1381 firstentry, sector);
1383 rc = write_long_name(&dir->file, firstentry,
1384 entries_needed, name, shortname, is_directory);
1385 if (rc < 0)
1386 return rc * 10 - 7;
1388 /* remember where the shortname dir entry is located */
1389 file->direntry = firstentry + entries_needed - 1;
1390 file->direntries = entries_needed;
1391 file->dircluster = dir->file.firstcluster;
1392 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1393 file->direntry, file->direntries);
1395 return 0;
1398 static unsigned char char2dos(unsigned char c, int* randomize)
1400 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1402 if (c <= 0x20)
1403 c = 0; /* Illegal char, remove */
1404 else if (strchr(invalid_chars, c) != NULL)
1406 /* Illegal char, replace */
1407 c = '_';
1408 *randomize = 1; /* as per FAT spec */
1410 else
1411 c = toupper(c);
1413 return c;
1416 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1418 int i;
1419 unsigned char *ext;
1420 int randomize = 0;
1422 /* Find extension part */
1423 ext = strrchr(name, '.');
1424 if (ext == name) /* handle .dotnames */
1425 ext = NULL;
1427 /* needs to randomize? */
1428 if((ext && (strlen(ext) > 4)) ||
1429 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1430 randomize = 1;
1432 /* Name part */
1433 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1435 unsigned char c = char2dos(*name, &randomize);
1436 if (c)
1437 newname[i++] = c;
1440 /* Pad both name and extension */
1441 while (i < 11)
1442 newname[i++] = ' ';
1444 if (newname[0] == 0xe5) /* Special kanji character */
1445 newname[0] = 0x05;
1447 if (ext)
1448 { /* Extension part */
1449 ext++;
1450 for (i = 8; *ext && (i < 11); ext++)
1452 unsigned char c = char2dos(*ext, &randomize);
1453 if (c)
1454 newname[i++] = c;
1458 if(randomize)
1459 randomize_dos_name(newname);
1462 static void randomize_dos_name(unsigned char *name)
1464 unsigned char* tilde = NULL; /* ~ location */
1465 unsigned char* lastpt = NULL; /* last point of filename */
1466 unsigned char* nameptr = name; /* working copy of name pointer */
1467 unsigned char num[9]; /* holds number as string */
1468 int i = 0;
1469 int cnt = 1;
1470 int numlen;
1471 int offset;
1473 while(i++ < 8)
1475 /* hunt for ~ and where to put it */
1476 if((!tilde) && (*nameptr == '~'))
1477 tilde = nameptr;
1478 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1479 lastpt = nameptr;
1480 nameptr++;
1482 if(tilde)
1484 /* extract current count and increment */
1485 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1486 num[7-(unsigned int)(tilde-name)] = 0;
1487 cnt = atoi(num) + 1;
1489 cnt %= 10000000; /* protection */
1490 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1491 numlen = strlen(num); /* required space */
1492 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1493 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1495 memcpy(&name[offset], num, numlen);
1497 /* in special case of counter overflow: pad with spaces */
1498 for(offset = offset+numlen; offset < 8; offset++)
1499 name[offset] = ' ';
1502 static int update_short_entry( struct fat_file* file, long size, int attr )
1504 unsigned char buf[SECTOR_SIZE];
1505 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1506 unsigned char* entry =
1507 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1508 unsigned long* sizeptr;
1509 unsigned short* clusptr;
1510 struct fat_file dir;
1511 int rc;
1513 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1514 file->firstcluster, file->direntry, size);
1516 /* create a temporary file handle for the dir holding this file */
1517 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1518 if (rc < 0)
1519 return rc * 10 - 1;
1521 rc = fat_seek( &dir, sector );
1522 if (rc<0)
1523 return rc * 10 - 2;
1525 rc = fat_readwrite(&dir, 1, buf, false);
1526 if (rc < 1)
1527 return rc * 10 - 3;
1529 if (!entry[0] || entry[0] == 0xe5)
1530 panicf("Updating size on empty dir entry %d\n", file->direntry);
1532 entry[FATDIR_ATTR] = attr & 0xFF;
1534 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1535 *clusptr = htole16(file->firstcluster >> 16);
1537 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1538 *clusptr = htole16(file->firstcluster & 0xffff);
1540 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1541 *sizeptr = htole32(size);
1544 #if CONFIG_RTC
1545 unsigned short time = 0;
1546 unsigned short date = 0;
1547 #else
1548 /* get old time to increment from */
1549 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1550 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1551 #endif
1552 fat_time(&date, &time, NULL);
1553 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1554 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1555 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1558 rc = fat_seek( &dir, sector );
1559 if (rc < 0)
1560 return rc * 10 - 4;
1562 rc = fat_readwrite(&dir, 1, buf, true);
1563 if (rc < 1)
1564 return rc * 10 - 5;
1566 return 0;
1569 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1571 int i=0,j=0;
1572 unsigned char c;
1573 bool lowercase;
1575 memset(de, 0, sizeof(struct fat_direntry));
1576 de->attr = buf[FATDIR_ATTR];
1577 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1578 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1579 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1580 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1581 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1582 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1583 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1584 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1585 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1586 (the result of the shift is always considered signed) */
1588 /* fix the name */
1589 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1590 c = buf[FATDIR_NAME];
1591 if (c == 0x05) /* special kanji char */
1592 c = 0xe5;
1593 i = 0;
1594 while (c != ' ') {
1595 de->name[j++] = lowercase ? tolower(c) : c;
1596 if (++i >= 8)
1597 break;
1598 c = buf[FATDIR_NAME+i];
1600 if (buf[FATDIR_NAME+8] != ' ') {
1601 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1602 de->name[j++] = '.';
1603 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1604 de->name[j++] = lowercase ? tolower(c) : c;
1606 return 1;
1609 int fat_open(IF_MV2(int volume,)
1610 long startcluster,
1611 struct fat_file *file,
1612 const struct fat_dir* dir)
1614 file->firstcluster = startcluster;
1615 file->lastcluster = startcluster;
1616 file->lastsector = 0;
1617 file->clusternum = 0;
1618 file->sectornum = 0;
1619 file->eof = false;
1620 #ifdef HAVE_MULTIVOLUME
1621 file->volume = volume;
1622 /* fixme: remove error check when done */
1623 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1625 LDEBUGF("fat_open() illegal volume %d\n", volume);
1626 return -1;
1628 #endif
1630 /* remember where the file's dir entry is located */
1631 if ( dir ) {
1632 file->direntry = dir->entry - 1;
1633 file->direntries = dir->entrycount;
1634 file->dircluster = dir->file.firstcluster;
1636 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1637 return 0;
1640 int fat_create_file(const char* name,
1641 struct fat_file* file,
1642 struct fat_dir* dir)
1644 int rc;
1646 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1647 rc = add_dir_entry(dir, file, name, false, false);
1648 if (!rc) {
1649 file->firstcluster = 0;
1650 file->lastcluster = 0;
1651 file->lastsector = 0;
1652 file->clusternum = 0;
1653 file->sectornum = 0;
1654 file->eof = false;
1657 return rc;
1660 int fat_create_dir(const char* name,
1661 struct fat_dir* newdir,
1662 struct fat_dir* dir)
1664 #ifdef HAVE_MULTIVOLUME
1665 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1666 #else
1667 struct bpb* fat_bpb = &fat_bpbs[0];
1668 #endif
1669 unsigned char buf[SECTOR_SIZE];
1670 int i;
1671 long sector;
1672 int rc;
1673 struct fat_file dummyfile;
1675 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1677 memset(newdir, 0, sizeof(struct fat_dir));
1678 memset(&dummyfile, 0, sizeof(struct fat_file));
1680 /* First, add the entry in the parent directory */
1681 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1682 if (rc < 0)
1683 return rc * 10 - 1;
1685 /* Allocate a new cluster for the directory */
1686 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1687 fat_bpb->fsinfo.nextfree);
1688 if(newdir->file.firstcluster == 0)
1689 return -1;
1691 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1693 /* Clear the entire cluster */
1694 memset(buf, 0, sizeof buf);
1695 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1696 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1697 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1698 if (rc < 0)
1699 return rc * 10 - 2;
1702 /* Then add the "." entry */
1703 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1704 if (rc < 0)
1705 return rc * 10 - 3;
1706 dummyfile.firstcluster = newdir->file.firstcluster;
1707 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1709 /* and the ".." entry */
1710 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1711 if (rc < 0)
1712 return rc * 10 - 4;
1714 /* The root cluster is cluster 0 in the ".." entry */
1715 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1716 dummyfile.firstcluster = 0;
1717 else
1718 dummyfile.firstcluster = dir->file.firstcluster;
1719 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1721 /* Set the firstcluster field in the direntry */
1722 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1724 rc = flush_fat(IF_MV(fat_bpb));
1725 if (rc < 0)
1726 return rc * 10 - 5;
1728 return rc;
1731 int fat_truncate(const struct fat_file *file)
1733 /* truncate trailing clusters */
1734 long next;
1735 long last = file->lastcluster;
1736 #ifdef HAVE_MULTIVOLUME
1737 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1738 #endif
1740 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1742 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1743 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1744 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1746 if (file->lastcluster)
1747 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1749 return 0;
1752 int fat_closewrite(struct fat_file *file, long size, int attr)
1754 int rc;
1755 #ifdef HAVE_MULTIVOLUME
1756 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1757 #endif
1758 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1760 if (!size) {
1761 /* empty file */
1762 if ( file->firstcluster ) {
1763 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1764 file->firstcluster = 0;
1768 if (file->dircluster) {
1769 rc = update_short_entry(file, size, attr);
1770 if (rc < 0)
1771 return rc * 10 - 1;
1774 flush_fat(IF_MV(fat_bpb));
1776 #ifdef TEST_FAT
1777 if ( file->firstcluster ) {
1778 /* debug */
1779 #ifdef HAVE_MULTIVOLUME
1780 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1781 #else
1782 struct bpb* fat_bpb = &fat_bpbs[0];
1783 #endif
1784 long count = 0;
1785 long len;
1786 long next;
1787 for ( next = file->firstcluster; next;
1788 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1789 LDEBUGF("cluster %ld: %lx\n", count, next);
1790 count++;
1792 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1793 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1794 count, len, size );
1795 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1796 panicf("Cluster chain is too long\n");
1797 if ( len < size )
1798 panicf("Cluster chain is too short\n");
1800 #endif
1802 return 0;
1805 static int free_direntries(struct fat_file* file)
1807 unsigned char buf[SECTOR_SIZE];
1808 struct fat_file dir;
1809 int numentries = file->direntries;
1810 unsigned int entry = file->direntry - numentries + 1;
1811 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1812 int i;
1813 int rc;
1815 /* create a temporary file handle for the dir holding this file */
1816 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1817 if (rc < 0)
1818 return rc * 10 - 1;
1820 rc = fat_seek( &dir, sector );
1821 if (rc < 0)
1822 return rc * 10 - 2;
1824 rc = fat_readwrite(&dir, 1, buf, false);
1825 if (rc < 1)
1826 return rc * 10 - 3;
1828 for (i=0; i < numentries; i++) {
1829 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1830 entry, i+1, numentries);
1831 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1832 entry++;
1834 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1835 /* flush this sector */
1836 rc = fat_seek(&dir, sector);
1837 if (rc < 0)
1838 return rc * 10 - 4;
1840 rc = fat_readwrite(&dir, 1, buf, true);
1841 if (rc < 1)
1842 return rc * 10 - 5;
1844 if ( i+1 < numentries ) {
1845 /* read next sector */
1846 rc = fat_readwrite(&dir, 1, buf, false);
1847 if (rc < 1)
1848 return rc * 10 - 6;
1850 sector++;
1854 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1855 /* flush this sector */
1856 rc = fat_seek(&dir, sector);
1857 if (rc < 0)
1858 return rc * 10 - 7;
1860 rc = fat_readwrite(&dir, 1, buf, true);
1861 if (rc < 1)
1862 return rc * 10 - 8;
1865 return 0;
1868 int fat_remove(struct fat_file* file)
1870 long next, last = file->firstcluster;
1871 int rc;
1872 #ifdef HAVE_MULTIVOLUME
1873 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1874 #endif
1876 LDEBUGF("fat_remove(%lx)\n",last);
1878 while ( last ) {
1879 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1880 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1881 last = next;
1884 if ( file->dircluster ) {
1885 rc = free_direntries(file);
1886 if (rc < 0)
1887 return rc * 10 - 1;
1890 file->firstcluster = 0;
1891 file->dircluster = 0;
1893 rc = flush_fat(IF_MV(fat_bpb));
1894 if (rc < 0)
1895 return rc * 10 - 2;
1897 return 0;
1900 int fat_rename(struct fat_file* file,
1901 struct fat_dir* dir,
1902 const unsigned char* newname,
1903 long size,
1904 int attr)
1906 int rc;
1907 struct fat_dir olddir;
1908 struct fat_file newfile = *file;
1909 unsigned char buf[SECTOR_SIZE];
1910 unsigned char* entry = NULL;
1911 unsigned short* clusptr = NULL;
1912 unsigned int parentcluster;
1913 #ifdef HAVE_MULTIVOLUME
1914 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1916 if (file->volume != dir->file.volume) {
1917 DEBUGF("No rename across volumes!\n");
1918 return -1;
1920 #else
1921 struct bpb* fat_bpb = &fat_bpbs[0];
1922 #endif
1924 if ( !file->dircluster ) {
1925 DEBUGF("File has no dir cluster!\n");
1926 return -2;
1929 /* create a temporary file handle */
1930 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1931 if (rc < 0)
1932 return rc * 10 - 1;
1934 /* create new name */
1935 rc = add_dir_entry(dir, &newfile, newname, false, false);
1936 if (rc < 0)
1937 return rc * 10 - 2;
1939 /* write size and cluster link */
1940 rc = update_short_entry(&newfile, size, attr);
1941 if (rc < 0)
1942 return rc * 10 - 3;
1944 /* remove old name */
1945 rc = free_direntries(file);
1946 if (rc < 0)
1947 return rc * 10 - 4;
1949 rc = flush_fat(IF_MV(fat_bpb));
1950 if (rc < 0)
1951 return rc * 10 - 5;
1953 /* if renaming a directory, update the .. entry to make sure
1954 it points to its parent directory (we don't check if it was a move) */
1955 if(FAT_ATTR_DIRECTORY == attr) {
1956 /* open the dir that was renamed, we re-use the olddir struct */
1957 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1958 NULL);
1959 if (rc < 0)
1960 return rc * 10 - 6;
1962 /* get the first sector of the dir */
1963 rc = fat_seek(&olddir.file, 0);
1964 if (rc < 0)
1965 return rc * 10 - 7;
1967 rc = fat_readwrite(&olddir.file, 1, buf, false);
1968 if (rc < 0)
1969 return rc * 10 - 8;
1971 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1972 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1973 parentcluster = 0;
1974 else
1975 parentcluster = dir->file.firstcluster;
1977 entry = buf + DIR_ENTRY_SIZE;
1978 if(strncmp(".. ", entry, 11))
1980 /* .. entry must be second entry according to FAT spec (p.29) */
1981 DEBUGF("Second dir entry is not double-dot!\n");
1982 return rc * 10 - 9;
1984 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1985 *clusptr = htole16(parentcluster >> 16);
1987 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1988 *clusptr = htole16(parentcluster & 0xffff);
1990 /* write back this sector */
1991 rc = fat_seek(&olddir.file, 0);
1992 if (rc < 0)
1993 return rc * 10 - 7;
1995 rc = fat_readwrite(&olddir.file, 1, buf, true);
1996 if (rc < 1)
1997 return rc * 10 - 8;
2000 return 0;
2003 static long next_write_cluster(struct fat_file* file,
2004 long oldcluster,
2005 long* newsector)
2007 #ifdef HAVE_MULTIVOLUME
2008 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2009 #else
2010 struct bpb* fat_bpb = &fat_bpbs[0];
2011 #endif
2012 long cluster = 0;
2013 long sector;
2015 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2017 if (oldcluster)
2018 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2020 if (!cluster) {
2021 if (oldcluster > 0)
2022 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2023 else if (oldcluster == 0)
2024 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2025 fat_bpb->fsinfo.nextfree);
2026 #ifdef HAVE_FAT16SUPPORT
2027 else /* negative, pseudo-cluster of the root dir */
2028 return 0; /* impossible to append something to the root */
2029 #endif
2031 if (cluster) {
2032 if (oldcluster)
2033 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2034 else
2035 file->firstcluster = cluster;
2036 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2038 else {
2039 #ifdef TEST_FAT
2040 if (fat_bpb->fsinfo.freecount>0)
2041 panicf("There is free space, but find_free_cluster() "
2042 "didn't find it!\n");
2043 #endif
2044 DEBUGF("next_write_cluster(): Disk full!\n");
2045 return 0;
2048 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2049 if (sector<0)
2050 return 0;
2052 *newsector = sector;
2053 return cluster;
2056 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2057 unsigned long start, long count, char* buf, bool write )
2059 #ifndef HAVE_MULTIVOLUME
2060 struct bpb* fat_bpb = &fat_bpbs[0];
2061 #endif
2062 int rc;
2064 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2065 start+ fat_bpb->startsector, count, write?"write":"read");
2066 if (write) {
2067 unsigned long firstallowed;
2068 #ifdef HAVE_FAT16SUPPORT
2069 if (fat_bpb->is_fat16)
2070 firstallowed = fat_bpb->rootdirsector;
2071 else
2072 #endif
2073 firstallowed = fat_bpb->firstdatasector;
2075 if (start < firstallowed)
2076 panicf("Write %ld before data\n", firstallowed - start);
2077 if (start + count > fat_bpb->totalsectors)
2078 panicf("Write %ld after data\n",
2079 start + count - fat_bpb->totalsectors);
2080 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
2081 start + fat_bpb->startsector, count, buf);
2083 else
2084 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
2085 start + fat_bpb->startsector, count, buf);
2086 if (rc < 0) {
2087 DEBUGF( "transfer() - Couldn't %s sector %lx"
2088 " (error code %d)\n",
2089 write ? "write":"read", start, rc);
2090 return rc;
2092 return 0;
2096 long fat_readwrite( struct fat_file *file, long sectorcount,
2097 void* buf, bool write )
2099 #ifdef HAVE_MULTIVOLUME
2100 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2101 #else
2102 struct bpb* fat_bpb = &fat_bpbs[0];
2103 #endif
2104 long cluster = file->lastcluster;
2105 long sector = file->lastsector;
2106 long clusternum = file->clusternum;
2107 long numsec = file->sectornum;
2108 bool eof = file->eof;
2109 long first=0, last=0;
2110 long i;
2111 int rc;
2113 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2114 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2115 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2116 sector,numsec, eof?1:0);
2118 if ( eof && !write)
2119 return 0;
2121 /* find sequential sectors and write them all at once */
2122 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2123 numsec++;
2124 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2125 long oldcluster = cluster;
2126 long oldsector = sector;
2127 long oldnumsec = numsec;
2128 if (write)
2129 cluster = next_write_cluster(file, cluster, &sector);
2130 else {
2131 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2132 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2135 clusternum++;
2136 numsec=1;
2138 if (!cluster) {
2139 eof = true;
2140 if ( write ) {
2141 /* remember last cluster, in case
2142 we want to append to the file */
2143 sector = oldsector;
2144 cluster = oldcluster;
2145 numsec = oldnumsec;
2146 clusternum--;
2147 i = -1; /* Error code */
2148 break;
2151 else
2152 eof = false;
2154 else {
2155 if (sector)
2156 sector++;
2157 else {
2158 /* look up first sector of file */
2159 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2160 numsec=1;
2161 #ifdef HAVE_FAT16SUPPORT
2162 if (file->firstcluster < 0)
2163 { /* FAT16 root dir */
2164 sector += fat_bpb->rootdiroffset;
2165 numsec += fat_bpb->rootdiroffset;
2167 #endif
2171 if (!first)
2172 first = sector;
2174 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2175 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2176 long count = last - first + 1;
2177 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2178 if (rc < 0)
2179 return rc * 10 - 1;
2181 buf = (char *)buf + count * SECTOR_SIZE;
2182 first = sector;
2185 if ((i == sectorcount-1) && /* last sector requested */
2186 (!eof))
2188 long count = sector - first + 1;
2189 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2190 if (rc < 0)
2191 return rc * 10 - 2;
2194 last = sector;
2197 file->lastcluster = cluster;
2198 file->lastsector = sector;
2199 file->clusternum = clusternum;
2200 file->sectornum = numsec;
2201 file->eof = eof;
2203 /* if eof, don't report last block as read/written */
2204 if (eof)
2205 i--;
2207 DEBUGF("Sectors written: %ld\n", i);
2208 return i;
2211 int fat_seek(struct fat_file *file, unsigned long seeksector )
2213 #ifdef HAVE_MULTIVOLUME
2214 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2215 #else
2216 struct bpb* fat_bpb = &fat_bpbs[0];
2217 #endif
2218 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2219 long cluster = file->firstcluster;
2220 long i;
2222 #ifdef HAVE_FAT16SUPPORT
2223 if (cluster < 0) /* FAT16 root dir */
2224 seeksector += fat_bpb->rootdiroffset;
2225 #endif
2227 file->eof = false;
2228 if (seeksector) {
2229 /* we need to find the sector BEFORE the requested, since
2230 the file struct stores the last accessed sector */
2231 seeksector--;
2232 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2233 sectornum = seeksector % fat_bpb->bpb_secperclus;
2235 if (file->clusternum && clusternum >= file->clusternum)
2237 cluster = file->lastcluster;
2238 numclusters -= file->clusternum;
2241 for (i=0; i<numclusters; i++) {
2242 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2243 if (!cluster) {
2244 DEBUGF("Seeking beyond the end of the file! "
2245 "(sector %ld, cluster %ld)\n", seeksector, i);
2246 return -1;
2250 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2252 else {
2253 sectornum = -1;
2256 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2257 file->firstcluster, seeksector, cluster, sector, sectornum);
2259 file->lastcluster = cluster;
2260 file->lastsector = sector;
2261 file->clusternum = clusternum;
2262 file->sectornum = sectornum + 1;
2263 return 0;
2266 int fat_opendir(IF_MV2(int volume,)
2267 struct fat_dir *dir, unsigned long startcluster,
2268 const struct fat_dir *parent_dir)
2270 #ifdef HAVE_MULTIVOLUME
2271 struct bpb* fat_bpb = &fat_bpbs[volume];
2272 /* fixme: remove error check when done */
2273 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2275 LDEBUGF("fat_open() illegal volume %d\n", volume);
2276 return -1;
2278 #else
2279 struct bpb* fat_bpb = &fat_bpbs[0];
2280 #endif
2281 int rc;
2283 dir->entry = 0;
2284 dir->sector = 0;
2286 if (startcluster == 0)
2287 startcluster = fat_bpb->bpb_rootclus;
2289 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2290 if(rc)
2292 DEBUGF( "fat_opendir() - Couldn't open dir"
2293 " (error code %d)\n", rc);
2294 return rc * 10 - 1;
2297 return 0;
2300 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2301 * destination buffer (UTF-8 encoded). Copying is stopped when
2302 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2303 * Trailing \0 is also appended at the end of the UTF8-encoded
2304 * string.
2306 * utf16src utf16 (little endian) segment to copy
2307 * utf16count max number of the utf16-characters to copy
2308 * utf8dst where to write UTF8-encoded string to
2310 * returns the number of UTF-16 characters actually copied
2312 static int fat_copy_long_name_segment(unsigned char *utf16src,
2313 int utf16count, unsigned char *utf8dst) {
2314 int cnt = 0;
2315 while ((utf16count--) > 0) {
2316 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2317 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2318 break;
2320 utf8dst = utf8encode(ucs, utf8dst);
2321 utf16src += 2;
2322 cnt++;
2324 *utf8dst = 0;
2325 return cnt;
2328 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2330 bool done = false;
2331 int i;
2332 int rc;
2333 unsigned char firstbyte;
2334 /* Long file names are stored in special entries. Each entry holds
2335 up to 13 characters. Names can be max 255 chars (not bytes!) long
2336 hence max 20 entries are required. */
2337 int longarray[20];
2338 int longs=0;
2339 int sectoridx=0;
2340 unsigned char* cached_buf = dir->sectorcache[0];
2342 dir->entrycount = 0;
2344 while(!done)
2346 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2348 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2349 if (rc == 0) {
2350 /* eof */
2351 entry->name[0] = 0;
2352 break;
2354 if (rc < 0) {
2355 DEBUGF( "fat_getnext() - Couldn't read dir"
2356 " (error code %d)\n", rc);
2357 return rc * 10 - 1;
2359 dir->sector = dir->file.lastsector;
2362 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2363 i < DIR_ENTRIES_PER_SECTOR; i++)
2365 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2367 firstbyte = cached_buf[entrypos];
2368 dir->entry++;
2370 if (firstbyte == 0xe5) {
2371 /* free entry */
2372 sectoridx = 0;
2373 dir->entrycount = 0;
2374 continue;
2377 if (firstbyte == 0) {
2378 /* last entry */
2379 entry->name[0] = 0;
2380 dir->entrycount = 0;
2381 return 0;
2384 dir->entrycount++;
2386 /* longname entry? */
2387 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2388 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2389 longarray[longs++] = entrypos + sectoridx;
2391 else {
2392 if ( parse_direntry(entry,
2393 &cached_buf[entrypos]) ) {
2395 /* don't return volume id entry */
2396 if ( (entry->attr &
2397 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2398 == FAT_ATTR_VOLUME_ID)
2399 continue;
2401 /* replace shortname with longname? */
2402 if ( longs ) {
2403 int j;
2404 /* This should be enough to hold any name segment
2405 utf8-encoded */
2406 unsigned char shortname[13]; /* 8+3+dot+\0 */
2407 /* Add 1 for trailing \0 */
2408 unsigned char longname_utf8segm[6*4 + 1];
2409 int longname_utf8len = 0;
2410 /* Temporarily store it */
2411 strcpy(shortname, entry->name);
2412 entry->name[0] = 0;
2414 /* iterate backwards through the dir entries */
2415 for (j=longs-1; j>=0; j--) {
2416 unsigned char* ptr = cached_buf;
2417 int index = longarray[j];
2418 /* current or cached sector? */
2419 if ( sectoridx >= SECTOR_SIZE ) {
2420 if ( sectoridx >= SECTOR_SIZE*2 ) {
2421 if ( ( index >= SECTOR_SIZE ) &&
2422 ( index < SECTOR_SIZE*2 ))
2423 ptr = dir->sectorcache[1];
2424 else
2425 ptr = dir->sectorcache[2];
2427 else {
2428 if ( index < SECTOR_SIZE )
2429 ptr = dir->sectorcache[1];
2432 index &= SECTOR_SIZE-1;
2435 /* Try to append each segment of the long name.
2436 Check if we'd exceed the buffer.
2437 Also check for FAT padding characters 0xFFFF. */
2438 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2439 longname_utf8segm) == 0) break;
2440 /* logf("SG: %s, EN: %s", longname_utf8segm,
2441 entry->name); */
2442 longname_utf8len += strlen(longname_utf8segm);
2443 if (longname_utf8len < FAT_FILENAME_BYTES)
2444 strcat(entry->name, longname_utf8segm);
2445 else
2446 break;
2448 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2449 longname_utf8segm) == 0) break;
2450 /* logf("SG: %s, EN: %s", longname_utf8segm,
2451 entry->name); */
2452 longname_utf8len += strlen(longname_utf8segm);
2453 if (longname_utf8len < FAT_FILENAME_BYTES)
2454 strcat(entry->name, longname_utf8segm);
2455 else
2456 break;
2458 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2459 longname_utf8segm) == 0) break;
2460 /* logf("SG: %s, EN: %s", longname_utf8segm,
2461 entry->name); */
2462 longname_utf8len += strlen(longname_utf8segm);
2463 if (longname_utf8len < FAT_FILENAME_BYTES)
2464 strcat(entry->name, longname_utf8segm);
2465 else
2466 break;
2469 /* Does the utf8-encoded name fit into the entry? */
2470 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2471 /* Take the short DOS name. Need to utf8-encode it
2472 since it may contain chars from the upper half of
2473 the OEM code page which wouldn't be a valid utf8.
2474 Beware: this file will be shown with strange
2475 glyphs in file browser since unicode 0x80 to 0x9F
2476 are control characters. */
2477 logf("SN-DOS: %s", shortname);
2478 unsigned char *utf8;
2479 utf8 = iso_decode(shortname, entry->name, -1,
2480 strlen(shortname));
2481 *utf8 = 0;
2482 logf("SN: %s", entry->name);
2483 } else {
2484 /* logf("LN: %s", entry->name);
2485 logf("LNLen: %d (%c)", longname_utf8len,
2486 entry->name[0]); */
2489 done = true;
2490 sectoridx = 0;
2491 i++;
2492 break;
2497 /* save this sector, for longname use */
2498 if ( sectoridx )
2499 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2500 else
2501 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2502 sectoridx += SECTOR_SIZE;
2505 return 0;
2508 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2510 #ifndef HAVE_MULTIVOLUME
2511 const int volume = 0;
2512 #endif
2513 struct bpb* fat_bpb = &fat_bpbs[volume];
2514 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2517 #ifdef HAVE_MULTIVOLUME
2518 bool fat_ismounted(int volume)
2520 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2522 #endif