Wheel acceleration for e200. A general acceleration interface intended for use on...
[Rockbox.git] / firmware / drivers / fat.c
blobf117119258a93e9e2982bf0094f33a08c62fb8e0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <stdbool.h>
24 #include "fat.h"
25 #include "ata.h"
26 #include "debug.h"
27 #include "panic.h"
28 #include "system.h"
29 #include "timefuncs.h"
30 #include "kernel.h"
31 #include "rbunicode.h"
32 #include "logf.h"
33 #include "atoi.h"
35 #define BYTES2INT16(array,pos) \
36 (array[pos] | (array[pos+1] << 8 ))
37 #define BYTES2INT32(array,pos) \
38 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
39 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
41 #define FATTYPE_FAT12 0
42 #define FATTYPE_FAT16 1
43 #define FATTYPE_FAT32 2
45 /* BPB offsets; generic */
46 #define BS_JMPBOOT 0
47 #define BS_OEMNAME 3
48 #define BPB_BYTSPERSEC 11
49 #define BPB_SECPERCLUS 13
50 #define BPB_RSVDSECCNT 14
51 #define BPB_NUMFATS 16
52 #define BPB_ROOTENTCNT 17
53 #define BPB_TOTSEC16 19
54 #define BPB_MEDIA 21
55 #define BPB_FATSZ16 22
56 #define BPB_SECPERTRK 24
57 #define BPB_NUMHEADS 26
58 #define BPB_HIDDSEC 28
59 #define BPB_TOTSEC32 32
61 /* fat12/16 */
62 #define BS_DRVNUM 36
63 #define BS_RESERVED1 37
64 #define BS_BOOTSIG 38
65 #define BS_VOLID 39
66 #define BS_VOLLAB 43
67 #define BS_FILSYSTYPE 54
69 /* fat32 */
70 #define BPB_FATSZ32 36
71 #define BPB_EXTFLAGS 40
72 #define BPB_FSVER 42
73 #define BPB_ROOTCLUS 44
74 #define BPB_FSINFO 48
75 #define BPB_BKBOOTSEC 50
76 #define BS_32_DRVNUM 64
77 #define BS_32_BOOTSIG 66
78 #define BS_32_VOLID 67
79 #define BS_32_VOLLAB 71
80 #define BS_32_FILSYSTYPE 82
82 #define BPB_LAST_WORD 510
85 /* attributes */
86 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
87 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
88 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
90 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
92 /* NTRES flags */
93 #define FAT_NTRES_LC_NAME 0x08
94 #define FAT_NTRES_LC_EXT 0x10
96 #define FATDIR_NAME 0
97 #define FATDIR_ATTR 11
98 #define FATDIR_NTRES 12
99 #define FATDIR_CRTTIMETENTH 13
100 #define FATDIR_CRTTIME 14
101 #define FATDIR_CRTDATE 16
102 #define FATDIR_LSTACCDATE 18
103 #define FATDIR_FSTCLUSHI 20
104 #define FATDIR_WRTTIME 22
105 #define FATDIR_WRTDATE 24
106 #define FATDIR_FSTCLUSLO 26
107 #define FATDIR_FILESIZE 28
109 #define FATLONG_ORDER 0
110 #define FATLONG_TYPE 12
111 #define FATLONG_CHKSUM 13
113 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
114 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
115 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
116 #define DIR_ENTRY_SIZE 32
117 #define NAME_BYTES_PER_ENTRY 13
118 #define FAT_BAD_MARK 0x0ffffff7
119 #define FAT_EOF_MARK 0x0ffffff8
120 #define FAT_LONGNAME_PAD_BYTE 0xff
121 #define FAT_LONGNAME_PAD_UCS 0xffff
123 struct fsinfo {
124 unsigned long freecount; /* last known free cluster count */
125 unsigned long nextfree; /* first cluster to start looking for free
126 clusters, or 0xffffffff for no hint */
128 /* fsinfo offsets */
129 #define FSINFO_FREECOUNT 488
130 #define FSINFO_NEXTFREE 492
132 /* Note: This struct doesn't hold the raw values after mounting if
133 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
134 * physical sectors. */
135 struct bpb
137 int bpb_bytspersec; /* Bytes per sector, typically 512 */
138 unsigned int bpb_secperclus; /* Sectors per cluster */
139 int bpb_rsvdseccnt; /* Number of reserved sectors */
140 int bpb_numfats; /* Number of FAT structures, typically 2 */
141 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
142 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
143 int bpb_fatsz16; /* Number of used sectors per FAT structure */
144 unsigned long bpb_totsec32; /* Number of sectors on the volume
145 (new 32-bit) */
146 unsigned int last_word; /* 0xAA55 */
148 /**** FAT32 specific *****/
149 long bpb_fatsz32;
150 long bpb_rootclus;
151 long bpb_fsinfo;
153 /* variables for internal use */
154 unsigned long fatsize;
155 unsigned long totalsectors;
156 unsigned long rootdirsector;
157 unsigned long firstdatasector;
158 unsigned long startsector;
159 unsigned long dataclusters;
160 struct fsinfo fsinfo;
161 #ifdef HAVE_FAT16SUPPORT
162 int bpb_rootentcnt; /* Number of dir entries in the root */
163 /* internals for FAT16 support */
164 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
165 unsigned int rootdiroffset; /* sector offset of root dir relative to start
166 * of first pseudo cluster */
167 #endif /* #ifdef HAVE_FAT16SUPPORT */
168 #ifdef HAVE_MULTIVOLUME
169 int drive; /* on which physical device is this located */
170 bool mounted; /* flag if this volume is mounted */
171 #endif
174 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
176 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
177 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
178 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
179 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,) long secnum, bool dirty);
180 static void create_dos_name(const unsigned char *name, unsigned char *newname);
181 static void randomize_dos_name(unsigned char *name);
182 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned long start);
183 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start, long count, char* buf, bool write );
185 #define FAT_CACHE_SIZE 0x20
186 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
188 struct fat_cache_entry
190 long secnum;
191 bool inuse;
192 bool dirty;
193 #ifdef HAVE_MULTIVOLUME
194 struct bpb* fat_vol ; /* shared cache for all volumes */
195 #endif
198 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
199 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
200 static struct mutex cache_mutex;
202 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
204 #ifndef HAVE_MULTIVOLUME
205 struct bpb* fat_bpb = &fat_bpbs[0];
206 #endif
207 #ifdef HAVE_FAT16SUPPORT
208 /* negative clusters (FAT16 root dir) don't get the 2 offset */
209 int zerocluster = cluster < 0 ? 0 : 2;
210 #else
211 const long zerocluster = 2;
212 #endif
214 if (cluster > (long)(fat_bpb->dataclusters + 1))
216 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
217 return -1;
220 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
221 + fat_bpb->firstdatasector;
224 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
226 #ifndef HAVE_MULTIVOLUME
227 const int volume = 0;
228 #endif
229 struct bpb* fat_bpb = &fat_bpbs[volume];
230 if (size)
231 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
232 if (free)
233 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
236 void fat_init(void)
238 unsigned int i;
240 mutex_init(&cache_mutex);
242 /* mark the FAT cache as unused */
243 for(i = 0;i < FAT_CACHE_SIZE;i++)
245 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
246 fat_cache[i].inuse = false;
247 fat_cache[i].dirty = false;
248 #ifdef HAVE_MULTIVOLUME
249 fat_cache[i].fat_vol = NULL;
250 #endif
252 #ifdef HAVE_MULTIVOLUME
253 /* mark the possible volumes as not mounted */
254 for (i=0; i<NUM_VOLUMES;i++)
256 fat_bpbs[i].mounted = false;
258 #endif
261 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
263 #ifndef HAVE_MULTIVOLUME
264 const int volume = 0;
265 #endif
266 struct bpb* fat_bpb = &fat_bpbs[volume];
267 unsigned char buf[SECTOR_SIZE];
268 int rc;
269 int secmult;
270 long datasec;
271 #ifdef HAVE_FAT16SUPPORT
272 int rootdirsectors;
273 #endif
275 /* Read the sector */
276 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
277 if(rc)
279 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
280 return rc * 10 - 1;
283 memset(fat_bpb, 0, sizeof(struct bpb));
284 fat_bpb->startsector = startsector;
285 #ifdef HAVE_MULTIVOLUME
286 fat_bpb->drive = drive;
287 #endif
289 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
290 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
291 /* Sanity check is performed later */
293 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
294 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
295 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
296 fat_bpb->bpb_media = buf[BPB_MEDIA];
297 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
298 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
299 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
300 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
301 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
303 /* calculate a few commonly used values */
304 if (fat_bpb->bpb_fatsz16 != 0)
305 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
306 else
307 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
309 if (fat_bpb->bpb_totsec16 != 0)
310 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
311 else
312 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
314 #ifdef HAVE_FAT16SUPPORT
315 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
316 if (!fat_bpb->bpb_bytspersec)
317 return -2;
318 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
319 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
320 #endif /* #ifdef HAVE_FAT16SUPPORT */
322 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
323 #ifdef HAVE_FAT16SUPPORT
324 + rootdirsectors
325 #endif
326 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
328 /* Determine FAT type */
329 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
330 if (fat_bpb->bpb_secperclus)
331 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
332 else
333 return -2;
335 #ifdef TEST_FAT
337 we are sometimes testing with "illegally small" fat32 images,
338 so we don't use the proper fat32 test case for test code
340 if ( fat_bpb->bpb_fatsz16 )
341 #else
342 if ( fat_bpb->dataclusters < 65525 )
343 #endif
344 { /* FAT16 */
345 #ifdef HAVE_FAT16SUPPORT
346 fat_bpb->is_fat16 = true;
347 if (fat_bpb->dataclusters < 4085)
348 { /* FAT12 */
349 DEBUGF("This is FAT12. Go away!\n");
350 return -2;
352 #else /* #ifdef HAVE_FAT16SUPPORT */
353 DEBUGF("This is not FAT32. Go away!\n");
354 return -2;
355 #endif /* #ifndef HAVE_FAT16SUPPORT */
358 #ifdef HAVE_FAT16SUPPORT
359 if (fat_bpb->is_fat16)
360 { /* FAT16 specific part of BPB */
361 int dirclusters;
362 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
363 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
364 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
365 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
366 /* I assign negative pseudo cluster numbers for the root directory,
367 their range is counted upward until -1. */
368 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
369 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
370 - rootdirsectors;
372 else
373 #endif /* #ifdef HAVE_FAT16SUPPORT */
374 { /* FAT32 specific part of BPB */
375 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
376 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
377 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,) fat_bpb->bpb_rootclus);
380 rc = bpb_is_sane(IF_MV(fat_bpb));
381 if (rc < 0)
383 DEBUGF( "fat_mount() - BPB is not sane\n");
384 return rc * 10 - 3;
387 #ifdef HAVE_FAT16SUPPORT
388 if (fat_bpb->is_fat16)
390 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
391 fat_bpb->fsinfo.nextfree = 0xffffffff;
393 else
394 #endif /* #ifdef HAVE_FAT16SUPPORT */
396 /* Read the fsinfo sector */
397 rc = ata_read_sectors(IF_MV2(drive,)
398 startsector + fat_bpb->bpb_fsinfo, 1, buf);
399 if (rc < 0)
401 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
402 return rc * 10 - 4;
404 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
405 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
408 /* calculate freecount if unset */
409 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
411 fat_recalc_free(IF_MV(volume));
414 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
415 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
416 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
417 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
418 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
420 #ifdef HAVE_MULTIVOLUME
421 fat_bpb->mounted = true;
422 #endif
424 return 0;
427 #ifdef HAVE_HOTSWAP
428 int fat_unmount(int volume, bool flush)
430 int rc;
431 struct bpb* fat_bpb = &fat_bpbs[volume];
433 if(flush)
435 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
437 else
438 { /* volume is not accessible any more, e.g. MMC removed */
439 int i;
440 mutex_lock(&cache_mutex);
441 for(i = 0;i < FAT_CACHE_SIZE;i++)
443 struct fat_cache_entry *fce = &fat_cache[i];
444 if(fce->inuse && fce->fat_vol == fat_bpb)
446 fce->inuse = false; /* discard all from that volume */
447 fce->dirty = false;
450 mutex_unlock(&cache_mutex);
451 rc = 0;
453 fat_bpb->mounted = false;
454 return rc;
456 #endif /* #ifdef HAVE_HOTSWAP */
458 void fat_recalc_free(IF_MV_NONVOID(int volume))
460 #ifndef HAVE_MULTIVOLUME
461 const int volume = 0;
462 #endif
463 struct bpb* fat_bpb = &fat_bpbs[volume];
464 long free = 0;
465 unsigned long i;
466 #ifdef HAVE_FAT16SUPPORT
467 if (fat_bpb->is_fat16)
469 for (i = 0; i<fat_bpb->fatsize; i++) {
470 unsigned int j;
471 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
472 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
473 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
474 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
475 break;
477 if (letoh16(fat[j]) == 0x0000) {
478 free++;
479 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
480 fat_bpb->fsinfo.nextfree = c;
485 else
486 #endif /* #ifdef HAVE_FAT16SUPPORT */
488 for (i = 0; i<fat_bpb->fatsize; i++) {
489 unsigned int j;
490 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
491 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
492 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
493 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
494 break;
496 if (!(letoh32(fat[j]) & 0x0fffffff)) {
497 free++;
498 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
499 fat_bpb->fsinfo.nextfree = c;
504 fat_bpb->fsinfo.freecount = free;
505 update_fsinfo(IF_MV(fat_bpb));
508 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
510 #ifndef HAVE_MULTIVOLUME
511 struct bpb* fat_bpb = &fat_bpbs[0];
512 #endif
513 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
515 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
516 fat_bpb->bpb_bytspersec);
517 return -1;
519 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec > 128L*1024L)
521 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
522 "(%d * %d = %d)\n",
523 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
524 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
525 return -2;
527 if(fat_bpb->bpb_numfats != 2)
529 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
530 fat_bpb->bpb_numfats);
532 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
534 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
535 "media type (0x%02x)\n",
536 fat_bpb->bpb_media);
538 if(fat_bpb->last_word != 0xaa55)
540 DEBUGF( "bpb_is_sane() - Error: Last word is not "
541 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
542 return -3;
545 if (fat_bpb->fsinfo.freecount >
546 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
547 fat_bpb->bpb_secperclus)
549 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
550 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
551 return -4;
554 return 0;
557 static void flush_fat_sector(struct fat_cache_entry *fce,
558 unsigned char *sectorbuf)
560 int rc;
561 long secnum;
563 /* With multivolume, use only the FAT info from the cached sector! */
564 #ifdef HAVE_MULTIVOLUME
565 secnum = fce->secnum + fce->fat_vol->startsector;
566 #else
567 secnum = fce->secnum + fat_bpbs[0].startsector;
568 #endif
570 /* Write to the first FAT */
571 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
572 secnum, 1,
573 sectorbuf);
574 if(rc < 0)
576 panicf("flush_fat_sector() - Could not write sector %ld"
577 " (error %d)\n",
578 secnum, rc);
580 #ifdef HAVE_MULTIVOLUME
581 if(fce->fat_vol->bpb_numfats > 1)
582 #else
583 if(fat_bpbs[0].bpb_numfats > 1)
584 #endif
586 /* Write to the second FAT */
587 #ifdef HAVE_MULTIVOLUME
588 secnum += fce->fat_vol->fatsize;
589 #else
590 secnum += fat_bpbs[0].fatsize;
591 #endif
592 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
593 secnum, 1, sectorbuf);
594 if(rc < 0)
596 panicf("flush_fat_sector() - Could not write sector %ld"
597 " (error %d)\n",
598 secnum, rc);
601 fce->dirty = false;
604 /* Note: The returned pointer is only safely valid until the next
605 task switch! (Any subsequent ata read/write may yield.) */
606 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
607 long fatsector, bool dirty)
609 #ifndef HAVE_MULTIVOLUME
610 struct bpb* fat_bpb = &fat_bpbs[0];
611 #endif
612 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
613 int cache_index = secnum & FAT_CACHE_MASK;
614 struct fat_cache_entry *fce = &fat_cache[cache_index];
615 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
616 int rc;
618 mutex_lock(&cache_mutex); /* make changes atomic */
620 /* Delete the cache entry if it isn't the sector we want */
621 if(fce->inuse && (fce->secnum != secnum
622 #ifdef HAVE_MULTIVOLUME
623 || fce->fat_vol != fat_bpb
624 #endif
627 /* Write back if it is dirty */
628 if(fce->dirty)
630 flush_fat_sector(fce, sectorbuf);
632 fce->inuse = false;
635 /* Load the sector if it is not cached */
636 if(!fce->inuse)
638 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
639 secnum + fat_bpb->startsector,1,
640 sectorbuf);
641 if(rc < 0)
643 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
644 " (error %d)\n", secnum, rc);
645 mutex_unlock(&cache_mutex);
646 return NULL;
648 fce->inuse = true;
649 fce->secnum = secnum;
650 #ifdef HAVE_MULTIVOLUME
651 fce->fat_vol = fat_bpb;
652 #endif
654 if (dirty)
655 fce->dirty = true; /* dirt remains, sticky until flushed */
656 mutex_unlock(&cache_mutex);
657 return sectorbuf;
660 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned long startcluster)
662 #ifndef HAVE_MULTIVOLUME
663 struct bpb* fat_bpb = &fat_bpbs[0];
664 #endif
665 unsigned long sector;
666 unsigned long offset;
667 unsigned long i;
669 #ifdef HAVE_FAT16SUPPORT
670 if (fat_bpb->is_fat16)
672 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
673 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
675 for (i = 0; i<fat_bpb->fatsize; i++) {
676 unsigned int j;
677 unsigned int nr = (i + sector) % fat_bpb->fatsize;
678 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
679 if ( !fat )
680 break;
681 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
682 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
683 if (letoh16(fat[k]) == 0x0000) {
684 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
685 /* Ignore the reserved clusters 0 & 1, and also
686 cluster numbers out of bounds */
687 if ( c < 2 || c > fat_bpb->dataclusters+1 )
688 continue;
689 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
690 fat_bpb->fsinfo.nextfree = c;
691 return c;
694 offset = 0;
697 else
698 #endif /* #ifdef HAVE_FAT16SUPPORT */
700 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
701 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
703 for (i = 0; i<fat_bpb->fatsize; i++) {
704 unsigned int j;
705 unsigned long nr = (i + sector) % fat_bpb->fatsize;
706 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
707 if ( !fat )
708 break;
709 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
710 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
711 if (!(letoh32(fat[k]) & 0x0fffffff)) {
712 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
713 /* Ignore the reserved clusters 0 & 1, and also
714 cluster numbers out of bounds */
715 if ( c < 2 || c > fat_bpb->dataclusters+1 )
716 continue;
717 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
718 fat_bpb->fsinfo.nextfree = c;
719 return c;
722 offset = 0;
726 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
727 return 0; /* 0 is an illegal cluster number */
730 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry, unsigned long val)
732 #ifndef HAVE_MULTIVOLUME
733 struct bpb* fat_bpb = &fat_bpbs[0];
734 #endif
735 #ifdef HAVE_FAT16SUPPORT
736 if (fat_bpb->is_fat16)
738 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
739 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
740 unsigned short* sec;
742 val &= 0xFFFF;
744 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
746 if (entry==val)
747 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
749 if ( entry < 2 )
750 panicf("Updating reserved FAT entry %ld.\n",entry);
752 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
753 if (!sec)
755 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
756 return -1;
759 if ( val ) {
760 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
761 fat_bpb->fsinfo.freecount--;
763 else {
764 if (letoh16(sec[offset]))
765 fat_bpb->fsinfo.freecount++;
768 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
770 sec[offset] = htole16(val);
772 else
773 #endif /* #ifdef HAVE_FAT16SUPPORT */
775 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
776 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
777 unsigned long* sec;
779 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
781 if (entry==val)
782 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
784 if ( entry < 2 )
785 panicf("Updating reserved FAT entry %ld.\n",entry);
787 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
788 if (!sec)
790 DEBUGF( "update_fat_entry() - Could not cache sector %ld\n", sector);
791 return -1;
794 if ( val ) {
795 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
796 fat_bpb->fsinfo.freecount > 0)
797 fat_bpb->fsinfo.freecount--;
799 else {
800 if (letoh32(sec[offset]) & 0x0fffffff)
801 fat_bpb->fsinfo.freecount++;
804 LDEBUGF("update_fat_entry: %ld free clusters\n", fat_bpb->fsinfo.freecount);
806 /* don't change top 4 bits */
807 sec[offset] &= htole32(0xf0000000);
808 sec[offset] |= htole32(val & 0x0fffffff);
811 return 0;
814 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
816 #ifdef HAVE_FAT16SUPPORT
817 #ifndef HAVE_MULTIVOLUME
818 struct bpb* fat_bpb = &fat_bpbs[0];
819 #endif
820 if (fat_bpb->is_fat16)
822 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
823 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
824 unsigned short* sec;
826 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
827 if (!sec)
829 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
830 return -1;
833 return letoh16(sec[offset]);
835 else
836 #endif /* #ifdef HAVE_FAT16SUPPORT */
838 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
839 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
840 unsigned long* sec;
842 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
843 if (!sec)
845 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
846 return -1;
849 return letoh32(sec[offset]) & 0x0fffffff;
853 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
855 long next_cluster;
856 long eof_mark = FAT_EOF_MARK;
858 #ifdef HAVE_FAT16SUPPORT
859 #ifndef HAVE_MULTIVOLUME
860 struct bpb* fat_bpb = &fat_bpbs[0];
861 #endif
862 if (fat_bpb->is_fat16)
864 eof_mark &= 0xFFFF; /* only 16 bit */
865 if (cluster < 0) /* FAT16 root dir */
866 return cluster + 1; /* don't use the FAT */
868 #endif
869 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
871 /* is this last cluster in chain? */
872 if ( next_cluster >= eof_mark )
873 return 0;
874 else
875 return next_cluster;
878 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
880 #ifndef HAVE_MULTIVOLUME
881 struct bpb* fat_bpb = &fat_bpbs[0];
882 #endif
883 unsigned char fsinfo[SECTOR_SIZE];
884 unsigned long* intptr;
885 int rc;
887 #ifdef HAVE_FAT16SUPPORT
888 if (fat_bpb->is_fat16)
889 return 0; /* FAT16 has no FsInfo */
890 #endif /* #ifdef HAVE_FAT16SUPPORT */
892 /* update fsinfo */
893 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
894 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
895 if (rc < 0)
897 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
898 return rc * 10 - 1;
900 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
901 *intptr = htole32(fat_bpb->fsinfo.freecount);
903 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
904 *intptr = htole32(fat_bpb->fsinfo.nextfree);
906 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
907 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
908 if (rc < 0)
910 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
911 return rc * 10 - 2;
914 return 0;
917 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
919 int i;
920 int rc;
921 unsigned char *sec;
922 LDEBUGF("flush_fat()\n");
924 mutex_lock(&cache_mutex);
925 for(i = 0;i < FAT_CACHE_SIZE;i++)
927 struct fat_cache_entry *fce = &fat_cache[i];
928 if(fce->inuse
929 #ifdef HAVE_MULTIVOLUME
930 && fce->fat_vol == fat_bpb
931 #endif
932 && fce->dirty)
934 sec = fat_cache_sectors[i];
935 flush_fat_sector(fce, sec);
938 mutex_unlock(&cache_mutex);
940 rc = update_fsinfo(IF_MV(fat_bpb));
941 if (rc < 0)
942 return rc * 10 - 3;
944 return 0;
947 static void fat_time(unsigned short* date,
948 unsigned short* time,
949 unsigned short* tenth )
951 #if CONFIG_RTC
952 struct tm* tm = get_time();
954 if (date)
955 *date = ((tm->tm_year - 80) << 9) |
956 ((tm->tm_mon + 1) << 5) |
957 tm->tm_mday;
959 if (time)
960 *time = (tm->tm_hour << 11) |
961 (tm->tm_min << 5) |
962 (tm->tm_sec >> 1);
964 if (tenth)
965 *tenth = (tm->tm_sec & 1) * 100;
966 #else
967 /* non-RTC version returns an increment from the supplied time, or a
968 * fixed standard time/date if no time given as input */
969 bool next_day = false;
971 if (time)
973 if (0 == *time)
975 /* set to 00:15:00 */
976 *time = (15 << 5);
978 else
980 unsigned short mins = (*time >> 5) & 0x003F;
981 unsigned short hours = (*time >> 11) & 0x001F;
982 if ((mins += 10) >= 60)
984 mins = 0;
985 hours++;
987 if ((++hours) >= 24)
989 hours = hours - 24;
990 next_day = true;
992 *time = (hours << 11) | (mins << 5);
996 if (date)
998 if (0 == *date)
1000 /* Macros to convert a 2-digit string to a decimal constant.
1001 (YEAR), MONTH and DAY are set by the date command, which outputs
1002 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1003 misinterpretation as an octal constant. */
1004 #define S100(x) 1 ## x
1005 #define C2DIG2DEC(x) (S100(x)-100)
1006 /* set to build date */
1007 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1008 | C2DIG2DEC(DAY);
1010 else
1012 unsigned short day = *date & 0x001F;
1013 unsigned short month = (*date >> 5) & 0x000F;
1014 unsigned short year = (*date >> 9) & 0x007F;
1015 if (next_day)
1017 /* do a very simple day increment - never go above 28 days */
1018 if (++day > 28)
1020 day = 1;
1021 if (++month > 12)
1023 month = 1;
1024 year++;
1027 *date = (year << 9) | (month << 5) | day;
1031 if (tenth)
1032 *tenth = 0;
1033 #endif /* CONFIG_RTC */
1036 static int write_long_name(struct fat_file* file,
1037 unsigned int firstentry,
1038 unsigned int numentries,
1039 const unsigned char* name,
1040 const unsigned char* shortname,
1041 bool is_directory)
1043 unsigned char buf[SECTOR_SIZE];
1044 unsigned char* entry;
1045 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1046 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1047 unsigned char chksum = 0;
1048 unsigned int i, j=0;
1049 unsigned int nameidx=0, namelen = utf8length(name);
1050 int rc;
1051 unsigned short name_utf16[namelen + 1];
1053 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1054 file->firstcluster, firstentry, numentries, name);
1056 rc = fat_seek(file, sector);
1057 if (rc<0)
1058 return rc * 10 - 1;
1060 rc = fat_readwrite(file, 1, buf, false);
1061 if (rc<1)
1062 return rc * 10 - 2;
1064 /* calculate shortname checksum */
1065 for (i=11; i>0; i--)
1066 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1068 /* calc position of last name segment */
1069 if ( namelen > NAME_BYTES_PER_ENTRY )
1070 for (nameidx=0;
1071 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1072 nameidx += NAME_BYTES_PER_ENTRY);
1074 /* we need to convert the name first */
1075 /* since it is written in reverse order */
1076 for (i = 0; i <= namelen; i++)
1077 name = utf8decode(name, &name_utf16[i]);
1079 for (i=0; i < numentries; i++) {
1080 /* new sector? */
1081 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1082 /* update current sector */
1083 rc = fat_seek(file, sector);
1084 if (rc<0)
1085 return rc * 10 - 3;
1087 rc = fat_readwrite(file, 1, buf, true);
1088 if (rc<1)
1089 return rc * 10 - 4;
1091 /* read next sector */
1092 rc = fat_readwrite(file, 1, buf, false);
1093 if (rc<0) {
1094 LDEBUGF("Failed writing new sector: %d\n",rc);
1095 return rc * 10 - 5;
1097 if (rc==0)
1098 /* end of dir */
1099 memset(buf, 0, sizeof buf);
1101 sector++;
1102 idx = 0;
1105 entry = buf + idx * DIR_ENTRY_SIZE;
1107 /* verify this entry is free */
1108 if (entry[0] && entry[0] != 0xe5 )
1109 panicf("Dir entry %d in sector %x is not free! "
1110 "%02x %02x %02x %02x",
1111 idx, sector,
1112 entry[0], entry[1], entry[2], entry[3]);
1114 memset(entry, 0, DIR_ENTRY_SIZE);
1115 if ( i+1 < numentries ) {
1116 /* longname entry */
1117 unsigned int k, l = nameidx;
1119 entry[FATLONG_ORDER] = numentries-i-1;
1120 if (i==0) {
1121 /* mark this as last long entry */
1122 entry[FATLONG_ORDER] |= 0x40;
1124 /* pad name with 0xffff */
1125 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1126 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1127 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1129 /* set name */
1130 for (k=0; k<5 && l <= namelen; k++) {
1131 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1132 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1134 for (k=0; k<6 && l <= namelen; k++) {
1135 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1136 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1138 for (k=0; k<2 && l <= namelen; k++) {
1139 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1140 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1143 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1144 entry[FATDIR_FSTCLUSLO] = 0;
1145 entry[FATLONG_TYPE] = 0;
1146 entry[FATLONG_CHKSUM] = chksum;
1147 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1149 else {
1150 /* shortname entry */
1151 unsigned short date=0, time=0, tenth=0;
1152 LDEBUGF("Shortname entry: %s\n", shortname);
1153 strncpy(entry + FATDIR_NAME, shortname, 11);
1154 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1155 entry[FATDIR_NTRES] = 0;
1157 fat_time(&date, &time, &tenth);
1158 entry[FATDIR_CRTTIMETENTH] = tenth;
1159 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1160 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1161 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1162 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1163 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1165 idx++;
1166 nameidx -= NAME_BYTES_PER_ENTRY;
1169 /* update last sector */
1170 rc = fat_seek(file, sector);
1171 if (rc<0)
1172 return rc * 10 - 6;
1174 rc = fat_readwrite(file, 1, buf, true);
1175 if (rc<1)
1176 return rc * 10 - 7;
1178 return 0;
1181 static int fat_checkname(const unsigned char* newname)
1183 static const char invalid_chars[] = "\"*/:<>?\\|";
1184 int len = strlen(newname);
1185 /* More sanity checks are probably needed */
1186 if (len > 255 || newname[len - 1] == '.')
1188 return -1;
1190 while (*newname)
1192 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1193 return -1;
1194 newname++;
1196 return 0;
1199 static int add_dir_entry(struct fat_dir* dir,
1200 struct fat_file* file,
1201 const char* name,
1202 bool is_directory,
1203 bool dotdir)
1205 #ifdef HAVE_MULTIVOLUME
1206 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1207 #else
1208 struct bpb* fat_bpb = &fat_bpbs[0];
1209 #endif
1210 unsigned char buf[SECTOR_SIZE];
1211 unsigned char shortname[12];
1212 int rc;
1213 unsigned int sector;
1214 bool done = false;
1215 int entries_needed, entries_found = 0;
1216 int firstentry;
1218 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1219 name, file->firstcluster);
1221 /* Don't check dotdirs name for validity */
1222 if (dotdir == false) {
1223 rc = fat_checkname(name);
1224 if (rc < 0) {
1225 /* filename is invalid */
1226 return rc * 10 - 1;
1230 #ifdef HAVE_MULTIVOLUME
1231 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1232 #endif
1234 /* The "." and ".." directory entries must not be long names */
1235 if(dotdir) {
1236 int i;
1237 strncpy(shortname, name, 12);
1238 for(i = strlen(shortname); i < 12; i++)
1239 shortname[i] = ' ';
1241 entries_needed = 1;
1242 } else {
1243 create_dos_name(name, shortname);
1245 /* one dir entry needed for every 13 bytes of filename,
1246 plus one entry for the short name */
1247 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1248 / NAME_BYTES_PER_ENTRY + 1;
1251 restart:
1252 firstentry = -1;
1254 rc = fat_seek(&dir->file, 0);
1255 if (rc < 0)
1256 return rc * 10 - 2;
1258 /* step 1: search for free entries and check for duplicate shortname */
1259 for (sector = 0; !done; sector++)
1261 unsigned int i;
1263 rc = fat_readwrite(&dir->file, 1, buf, false);
1264 if (rc < 0) {
1265 DEBUGF( "add_dir_entry() - Couldn't read dir"
1266 " (error code %d)\n", rc);
1267 return rc * 10 - 3;
1270 if (rc == 0) { /* current end of dir reached */
1271 LDEBUGF("End of dir on cluster boundary\n");
1272 break;
1275 /* look for free slots */
1276 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1278 switch (buf[i * DIR_ENTRY_SIZE]) {
1279 case 0:
1280 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1281 LDEBUGF("Found end of dir %d\n",
1282 sector * DIR_ENTRIES_PER_SECTOR + i);
1283 i = DIR_ENTRIES_PER_SECTOR - 1;
1284 done = true;
1285 break;
1287 case 0xe5:
1288 entries_found++;
1289 LDEBUGF("Found free entry %d (%d/%d)\n",
1290 sector * DIR_ENTRIES_PER_SECTOR + i,
1291 entries_found, entries_needed);
1292 break;
1294 default:
1295 entries_found = 0;
1297 /* check that our intended shortname doesn't already exist */
1298 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1299 /* shortname exists already, make a new one */
1300 randomize_dos_name(shortname);
1301 LDEBUGF("Duplicate shortname, changing to %s\n",
1302 shortname);
1304 /* name has changed, we need to restart search */
1305 goto restart;
1307 break;
1309 if (firstentry < 0 && (entries_found >= entries_needed))
1310 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1311 - entries_found;
1315 /* step 2: extend the dir if necessary */
1316 if (firstentry < 0)
1318 LDEBUGF("Adding new sector(s) to dir\n");
1319 rc = fat_seek(&dir->file, sector);
1320 if (rc < 0)
1321 return rc * 10 - 4;
1322 memset(buf, 0, sizeof buf);
1324 /* we must clear whole clusters */
1325 for (; (entries_found < entries_needed) ||
1326 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1328 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1329 return -5; /* dir too large -- FAT specification */
1331 rc = fat_readwrite(&dir->file, 1, buf, true);
1332 if (rc < 1) /* No more room or something went wrong */
1333 return rc * 10 - 6;
1335 entries_found += DIR_ENTRIES_PER_SECTOR;
1338 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1341 /* step 3: add entry */
1342 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1343 LDEBUGF("Adding longname to entry %d in sector %d\n",
1344 firstentry, sector);
1346 rc = write_long_name(&dir->file, firstentry,
1347 entries_needed, name, shortname, is_directory);
1348 if (rc < 0)
1349 return rc * 10 - 7;
1351 /* remember where the shortname dir entry is located */
1352 file->direntry = firstentry + entries_needed - 1;
1353 file->direntries = entries_needed;
1354 file->dircluster = dir->file.firstcluster;
1355 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1356 file->direntry, file->direntries);
1358 return 0;
1361 static unsigned char char2dos(unsigned char c, int* randomize)
1363 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1365 if (c <= 0x20)
1366 c = 0; /* Illegal char, remove */
1367 else if (strchr(invalid_chars, c) != NULL)
1369 /* Illegal char, replace */
1370 c = '_';
1371 *randomize = 1; /* as per FAT spec */
1373 else
1374 c = toupper(c);
1376 return c;
1379 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1381 int i;
1382 unsigned char *ext;
1383 int randomize = 0;
1385 /* Find extension part */
1386 ext = strrchr(name, '.');
1387 if (ext == name) /* handle .dotnames */
1388 ext = NULL;
1390 /* needs to randomize? */
1391 if((ext && (strlen(ext) > 4)) ||
1392 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1393 randomize = 1;
1395 /* Name part */
1396 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1398 unsigned char c = char2dos(*name, &randomize);
1399 if (c)
1400 newname[i++] = c;
1403 /* Pad both name and extension */
1404 while (i < 11)
1405 newname[i++] = ' ';
1407 if (newname[0] == 0xe5) /* Special kanji character */
1408 newname[0] = 0x05;
1410 if (ext)
1411 { /* Extension part */
1412 ext++;
1413 for (i = 8; *ext && (i < 11); ext++)
1415 unsigned char c = char2dos(*ext, &randomize);
1416 if (c)
1417 newname[i++] = c;
1421 if(randomize)
1422 randomize_dos_name(newname);
1425 static void randomize_dos_name(unsigned char *name)
1427 unsigned char* tilde = NULL; /* ~ location */
1428 unsigned char* lastpt = NULL; /* last point of filename */
1429 unsigned char* nameptr = name; /* working copy of name pointer */
1430 unsigned char num[9]; /* holds number as string */
1431 int i = 0;
1432 int cnt = 1;
1433 int numlen;
1434 int offset;
1436 while(i++ < 8)
1438 /* hunt for ~ and where to put it */
1439 if((!tilde) && (*nameptr == '~'))
1440 tilde = nameptr;
1441 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1442 lastpt = nameptr;
1443 nameptr++;
1445 if(tilde)
1447 /* extract current count and increment */
1448 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1449 num[7-(unsigned int)(tilde-name)] = 0;
1450 cnt = atoi(num) + 1;
1452 cnt %= 10000000; /* protection */
1453 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1454 numlen = strlen(num); /* required space */
1455 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1456 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1458 memcpy(&name[offset], num, numlen);
1460 /* in special case of counter overflow: pad with spaces */
1461 for(offset = offset+numlen; offset < 8; offset++)
1462 name[offset] = ' ';
1465 static int update_short_entry( struct fat_file* file, long size, int attr )
1467 unsigned char buf[SECTOR_SIZE];
1468 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1469 unsigned char* entry =
1470 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1471 unsigned long* sizeptr;
1472 unsigned short* clusptr;
1473 struct fat_file dir;
1474 int rc;
1476 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1477 file->firstcluster, file->direntry, size);
1479 /* create a temporary file handle for the dir holding this file */
1480 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1481 if (rc < 0)
1482 return rc * 10 - 1;
1484 rc = fat_seek( &dir, sector );
1485 if (rc<0)
1486 return rc * 10 - 2;
1488 rc = fat_readwrite(&dir, 1, buf, false);
1489 if (rc < 1)
1490 return rc * 10 - 3;
1492 if (!entry[0] || entry[0] == 0xe5)
1493 panicf("Updating size on empty dir entry %d\n", file->direntry);
1495 entry[FATDIR_ATTR] = attr & 0xFF;
1497 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1498 *clusptr = htole16(file->firstcluster >> 16);
1500 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1501 *clusptr = htole16(file->firstcluster & 0xffff);
1503 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1504 *sizeptr = htole32(size);
1507 #if CONFIG_RTC
1508 unsigned short time = 0;
1509 unsigned short date = 0;
1510 #else
1511 /* get old time to increment from */
1512 unsigned short time = htole16(*(unsigned short*)(entry + FATDIR_WRTTIME));
1513 unsigned short date = htole16(*(unsigned short*)(entry + FATDIR_WRTDATE));
1514 #endif
1515 fat_time(&date, &time, NULL);
1516 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1517 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1518 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1521 rc = fat_seek( &dir, sector );
1522 if (rc < 0)
1523 return rc * 10 - 4;
1525 rc = fat_readwrite(&dir, 1, buf, true);
1526 if (rc < 1)
1527 return rc * 10 - 5;
1529 return 0;
1532 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1534 int i=0,j=0;
1535 unsigned char c;
1536 bool lowercase;
1538 memset(de, 0, sizeof(struct fat_direntry));
1539 de->attr = buf[FATDIR_ATTR];
1540 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1541 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1542 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1543 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1544 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1545 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1546 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1547 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1548 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1549 (the result of the shift is always considered signed) */
1551 /* fix the name */
1552 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1553 c = buf[FATDIR_NAME];
1554 if (c == 0x05) /* special kanji char */
1555 c = 0xe5;
1556 i = 0;
1557 while (c != ' ') {
1558 de->name[j++] = lowercase ? tolower(c) : c;
1559 if (++i >= 8)
1560 break;
1561 c = buf[FATDIR_NAME+i];
1563 if (buf[FATDIR_NAME+8] != ' ') {
1564 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1565 de->name[j++] = '.';
1566 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1567 de->name[j++] = lowercase ? tolower(c) : c;
1569 return 1;
1572 int fat_open(IF_MV2(int volume,)
1573 long startcluster,
1574 struct fat_file *file,
1575 const struct fat_dir* dir)
1577 file->firstcluster = startcluster;
1578 file->lastcluster = startcluster;
1579 file->lastsector = 0;
1580 file->clusternum = 0;
1581 file->sectornum = 0;
1582 file->eof = false;
1583 #ifdef HAVE_MULTIVOLUME
1584 file->volume = volume;
1585 /* fixme: remove error check when done */
1586 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1588 LDEBUGF("fat_open() illegal volume %d\n", volume);
1589 return -1;
1591 #endif
1593 /* remember where the file's dir entry is located */
1594 if ( dir ) {
1595 file->direntry = dir->entry - 1;
1596 file->direntries = dir->entrycount;
1597 file->dircluster = dir->file.firstcluster;
1599 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1600 return 0;
1603 int fat_create_file(const char* name,
1604 struct fat_file* file,
1605 struct fat_dir* dir)
1607 int rc;
1609 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1610 rc = add_dir_entry(dir, file, name, false, false);
1611 if (!rc) {
1612 file->firstcluster = 0;
1613 file->lastcluster = 0;
1614 file->lastsector = 0;
1615 file->clusternum = 0;
1616 file->sectornum = 0;
1617 file->eof = false;
1620 return rc;
1623 int fat_create_dir(const char* name,
1624 struct fat_dir* newdir,
1625 struct fat_dir* dir)
1627 #ifdef HAVE_MULTIVOLUME
1628 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1629 #else
1630 struct bpb* fat_bpb = &fat_bpbs[0];
1631 #endif
1632 unsigned char buf[SECTOR_SIZE];
1633 int i;
1634 long sector;
1635 int rc;
1636 struct fat_file dummyfile;
1638 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1640 memset(newdir, 0, sizeof(struct fat_dir));
1641 memset(&dummyfile, 0, sizeof(struct fat_file));
1643 /* First, add the entry in the parent directory */
1644 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1645 if (rc < 0)
1646 return rc * 10 - 1;
1648 /* Allocate a new cluster for the directory */
1649 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
1650 if(newdir->file.firstcluster == 0)
1651 return -1;
1653 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1655 /* Clear the entire cluster */
1656 memset(buf, 0, sizeof buf);
1657 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1658 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1659 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1660 if (rc < 0)
1661 return rc * 10 - 2;
1664 /* Then add the "." entry */
1665 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1666 if (rc < 0)
1667 return rc * 10 - 3;
1668 dummyfile.firstcluster = newdir->file.firstcluster;
1669 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1671 /* and the ".." entry */
1672 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1673 if (rc < 0)
1674 return rc * 10 - 4;
1676 /* The root cluster is cluster 0 in the ".." entry */
1677 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1678 dummyfile.firstcluster = 0;
1679 else
1680 dummyfile.firstcluster = dir->file.firstcluster;
1681 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1683 /* Set the firstcluster field in the direntry */
1684 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1686 rc = flush_fat(IF_MV(fat_bpb));
1687 if (rc < 0)
1688 return rc * 10 - 5;
1690 return rc;
1693 int fat_truncate(const struct fat_file *file)
1695 /* truncate trailing clusters */
1696 long next;
1697 long last = file->lastcluster;
1698 #ifdef HAVE_MULTIVOLUME
1699 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1700 #endif
1702 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1704 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1705 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1706 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1708 if (file->lastcluster)
1709 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1711 return 0;
1714 int fat_closewrite(struct fat_file *file, long size, int attr)
1716 int rc;
1717 #ifdef HAVE_MULTIVOLUME
1718 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1719 #endif
1720 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1722 if (!size) {
1723 /* empty file */
1724 if ( file->firstcluster ) {
1725 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1726 file->firstcluster = 0;
1730 if (file->dircluster) {
1731 rc = update_short_entry(file, size, attr);
1732 if (rc < 0)
1733 return rc * 10 - 1;
1736 flush_fat(IF_MV(fat_bpb));
1738 #ifdef TEST_FAT
1739 if ( file->firstcluster ) {
1740 /* debug */
1741 #ifdef HAVE_MULTIVOLUME
1742 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1743 #else
1744 struct bpb* fat_bpb = &fat_bpbs[0];
1745 #endif
1746 long count = 0;
1747 long len;
1748 long next;
1749 for ( next = file->firstcluster; next;
1750 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1751 LDEBUGF("cluster %ld: %lx\n", count, next);
1752 count++;
1754 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1755 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1756 count, len, size );
1757 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1758 panicf("Cluster chain is too long\n");
1759 if ( len < size )
1760 panicf("Cluster chain is too short\n");
1762 #endif
1764 return 0;
1767 static int free_direntries(struct fat_file* file)
1769 unsigned char buf[SECTOR_SIZE];
1770 struct fat_file dir;
1771 int numentries = file->direntries;
1772 unsigned int entry = file->direntry - numentries + 1;
1773 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1774 int i;
1775 int rc;
1777 /* create a temporary file handle for the dir holding this file */
1778 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1779 if (rc < 0)
1780 return rc * 10 - 1;
1782 rc = fat_seek( &dir, sector );
1783 if (rc < 0)
1784 return rc * 10 - 2;
1786 rc = fat_readwrite(&dir, 1, buf, false);
1787 if (rc < 1)
1788 return rc * 10 - 3;
1790 for (i=0; i < numentries; i++) {
1791 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1792 entry, i+1, numentries);
1793 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1794 entry++;
1796 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1797 /* flush this sector */
1798 rc = fat_seek(&dir, sector);
1799 if (rc < 0)
1800 return rc * 10 - 4;
1802 rc = fat_readwrite(&dir, 1, buf, true);
1803 if (rc < 1)
1804 return rc * 10 - 5;
1806 if ( i+1 < numentries ) {
1807 /* read next sector */
1808 rc = fat_readwrite(&dir, 1, buf, false);
1809 if (rc < 1)
1810 return rc * 10 - 6;
1812 sector++;
1816 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1817 /* flush this sector */
1818 rc = fat_seek(&dir, sector);
1819 if (rc < 0)
1820 return rc * 10 - 7;
1822 rc = fat_readwrite(&dir, 1, buf, true);
1823 if (rc < 1)
1824 return rc * 10 - 8;
1827 return 0;
1830 int fat_remove(struct fat_file* file)
1832 long next, last = file->firstcluster;
1833 int rc;
1834 #ifdef HAVE_MULTIVOLUME
1835 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1836 #endif
1838 LDEBUGF("fat_remove(%lx)\n",last);
1840 while ( last ) {
1841 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1842 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1843 last = next;
1846 if ( file->dircluster ) {
1847 rc = free_direntries(file);
1848 if (rc < 0)
1849 return rc * 10 - 1;
1852 file->firstcluster = 0;
1853 file->dircluster = 0;
1855 rc = flush_fat(IF_MV(fat_bpb));
1856 if (rc < 0)
1857 return rc * 10 - 2;
1859 return 0;
1862 int fat_rename(struct fat_file* file,
1863 struct fat_dir* dir,
1864 const unsigned char* newname,
1865 long size,
1866 int attr)
1868 int rc;
1869 struct fat_dir olddir;
1870 struct fat_file newfile = *file;
1871 unsigned char buf[SECTOR_SIZE];
1872 unsigned char* entry = NULL;
1873 unsigned short* clusptr = NULL;
1874 unsigned int parentcluster;
1875 #ifdef HAVE_MULTIVOLUME
1876 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1878 if (file->volume != dir->file.volume) {
1879 DEBUGF("No rename across volumes!\n");
1880 return -1;
1882 #else
1883 struct bpb* fat_bpb = &fat_bpbs[0];
1884 #endif
1886 if ( !file->dircluster ) {
1887 DEBUGF("File has no dir cluster!\n");
1888 return -2;
1891 /* create a temporary file handle */
1892 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1893 if (rc < 0)
1894 return rc * 10 - 1;
1896 /* create new name */
1897 rc = add_dir_entry(dir, &newfile, newname, false, false);
1898 if (rc < 0)
1899 return rc * 10 - 2;
1901 /* write size and cluster link */
1902 rc = update_short_entry(&newfile, size, attr);
1903 if (rc < 0)
1904 return rc * 10 - 3;
1906 /* remove old name */
1907 rc = free_direntries(file);
1908 if (rc < 0)
1909 return rc * 10 - 4;
1911 rc = flush_fat(IF_MV(fat_bpb));
1912 if (rc < 0)
1913 return rc * 10 - 5;
1915 /* if renaming a directory, update the .. entry to make sure
1916 it points to its parent directory (we don't check if it was a move) */
1917 if(FAT_ATTR_DIRECTORY == attr) {
1918 /* open the dir that was renamed, we re-use the olddir struct */
1919 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1920 NULL);
1921 if (rc < 0)
1922 return rc * 10 - 6;
1924 /* get the first sector of the dir */
1925 rc = fat_seek(&olddir.file, 0);
1926 if (rc < 0)
1927 return rc * 10 - 7;
1929 rc = fat_readwrite(&olddir.file, 1, buf, false);
1930 if (rc < 0)
1931 return rc * 10 - 8;
1933 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1934 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1935 parentcluster = 0;
1936 else
1937 parentcluster = dir->file.firstcluster;
1939 entry = buf + DIR_ENTRY_SIZE;
1940 if(strncmp(".. ", entry, 11))
1942 /* .. entry must be second entry according to FAT spec (p.29) */
1943 DEBUGF("Second dir entry is not double-dot!\n");
1944 return rc * 10 - 9;
1946 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1947 *clusptr = htole16(parentcluster >> 16);
1949 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1950 *clusptr = htole16(parentcluster & 0xffff);
1952 /* write back this sector */
1953 rc = fat_seek(&olddir.file, 0);
1954 if (rc < 0)
1955 return rc * 10 - 7;
1957 rc = fat_readwrite(&olddir.file, 1, buf, true);
1958 if (rc < 1)
1959 return rc * 10 - 8;
1962 return 0;
1965 static long next_write_cluster(struct fat_file* file,
1966 long oldcluster,
1967 long* newsector)
1969 #ifdef HAVE_MULTIVOLUME
1970 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1971 #else
1972 struct bpb* fat_bpb = &fat_bpbs[0];
1973 #endif
1974 long cluster = 0;
1975 long sector;
1977 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
1979 if (oldcluster)
1980 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
1982 if (!cluster) {
1983 if (oldcluster > 0)
1984 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
1985 else if (oldcluster == 0)
1986 cluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
1987 #ifdef HAVE_FAT16SUPPORT
1988 else /* negative, pseudo-cluster of the root dir */
1989 return 0; /* impossible to append something to the root */
1990 #endif
1992 if (cluster) {
1993 if (oldcluster)
1994 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
1995 else
1996 file->firstcluster = cluster;
1997 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
1999 else {
2000 #ifdef TEST_FAT
2001 if (fat_bpb->fsinfo.freecount>0)
2002 panicf("There is free space, but find_free_cluster() "
2003 "didn't find it!\n");
2004 #endif
2005 DEBUGF("next_write_cluster(): Disk full!\n");
2006 return 0;
2009 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2010 if (sector<0)
2011 return 0;
2013 *newsector = sector;
2014 return cluster;
2017 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2018 unsigned long start, long count, char* buf, bool write )
2020 #ifndef HAVE_MULTIVOLUME
2021 struct bpb* fat_bpb = &fat_bpbs[0];
2022 #endif
2023 int rc;
2025 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2026 start+ fat_bpb->startsector, count, write?"write":"read");
2027 if (write) {
2028 unsigned long firstallowed;
2029 #ifdef HAVE_FAT16SUPPORT
2030 if (fat_bpb->is_fat16)
2031 firstallowed = fat_bpb->rootdirsector;
2032 else
2033 #endif
2034 firstallowed = fat_bpb->firstdatasector;
2036 if (start < firstallowed)
2037 panicf("Write %ld before data\n", firstallowed - start);
2038 if (start + count > fat_bpb->totalsectors)
2039 panicf("Write %ld after data\n",
2040 start + count - fat_bpb->totalsectors);
2041 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
2042 start + fat_bpb->startsector, count, buf);
2044 else
2045 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
2046 start + fat_bpb->startsector, count, buf);
2047 if (rc < 0) {
2048 DEBUGF( "transfer() - Couldn't %s sector %lx"
2049 " (error code %d)\n",
2050 write ? "write":"read", start, rc);
2051 return rc;
2053 return 0;
2057 long fat_readwrite( struct fat_file *file, long sectorcount,
2058 void* buf, bool write )
2060 #ifdef HAVE_MULTIVOLUME
2061 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2062 #else
2063 struct bpb* fat_bpb = &fat_bpbs[0];
2064 #endif
2065 long cluster = file->lastcluster;
2066 long sector = file->lastsector;
2067 long clusternum = file->clusternum;
2068 long numsec = file->sectornum;
2069 bool eof = file->eof;
2070 long first=0, last=0;
2071 long i;
2072 int rc;
2074 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2075 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2076 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2077 sector,numsec, eof?1:0);
2079 if ( eof && !write)
2080 return 0;
2082 /* find sequential sectors and write them all at once */
2083 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2084 numsec++;
2085 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2086 long oldcluster = cluster;
2087 if (write)
2088 cluster = next_write_cluster(file, cluster, &sector);
2089 else {
2090 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2091 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2094 clusternum++;
2095 numsec=1;
2097 if (!cluster) {
2098 eof = true;
2099 if ( write ) {
2100 /* remember last cluster, in case
2101 we want to append to the file */
2102 cluster = oldcluster;
2103 clusternum--;
2104 i = -1; /* Error code */
2105 break;
2108 else
2109 eof = false;
2111 else {
2112 if (sector)
2113 sector++;
2114 else {
2115 /* look up first sector of file */
2116 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2117 numsec=1;
2118 #ifdef HAVE_FAT16SUPPORT
2119 if (file->firstcluster < 0)
2120 { /* FAT16 root dir */
2121 sector += fat_bpb->rootdiroffset;
2122 numsec += fat_bpb->rootdiroffset;
2124 #endif
2128 if (!first)
2129 first = sector;
2131 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2132 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2133 long count = last - first + 1;
2134 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2135 if (rc < 0)
2136 return rc * 10 - 1;
2138 buf = (char *)buf + count * SECTOR_SIZE;
2139 first = sector;
2142 if ((i == sectorcount-1) && /* last sector requested */
2143 (!eof))
2145 long count = sector - first + 1;
2146 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2147 if (rc < 0)
2148 return rc * 10 - 2;
2151 last = sector;
2154 file->lastcluster = cluster;
2155 file->lastsector = sector;
2156 file->clusternum = clusternum;
2157 file->sectornum = numsec;
2158 file->eof = eof;
2160 /* if eof, don't report last block as read/written */
2161 if (eof)
2162 i--;
2164 DEBUGF("Sectors written: %ld\n", i);
2165 return i;
2168 int fat_seek(struct fat_file *file, unsigned long seeksector )
2170 #ifdef HAVE_MULTIVOLUME
2171 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2172 #else
2173 struct bpb* fat_bpb = &fat_bpbs[0];
2174 #endif
2175 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2176 long cluster = file->firstcluster;
2177 long i;
2179 #ifdef HAVE_FAT16SUPPORT
2180 if (cluster < 0) /* FAT16 root dir */
2181 seeksector += fat_bpb->rootdiroffset;
2182 #endif
2184 file->eof = false;
2185 if (seeksector) {
2186 /* we need to find the sector BEFORE the requested, since
2187 the file struct stores the last accessed sector */
2188 seeksector--;
2189 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2190 sectornum = seeksector % fat_bpb->bpb_secperclus;
2192 if (file->clusternum && clusternum >= file->clusternum)
2194 cluster = file->lastcluster;
2195 numclusters -= file->clusternum;
2198 for (i=0; i<numclusters; i++) {
2199 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2200 if (!cluster) {
2201 DEBUGF("Seeking beyond the end of the file! "
2202 "(sector %ld, cluster %ld)\n", seeksector, i);
2203 return -1;
2207 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2209 else {
2210 sectornum = -1;
2213 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2214 file->firstcluster, seeksector, cluster, sector, sectornum);
2216 file->lastcluster = cluster;
2217 file->lastsector = sector;
2218 file->clusternum = clusternum;
2219 file->sectornum = sectornum + 1;
2220 return 0;
2223 int fat_opendir(IF_MV2(int volume,)
2224 struct fat_dir *dir, unsigned long startcluster,
2225 const struct fat_dir *parent_dir)
2227 #ifdef HAVE_MULTIVOLUME
2228 struct bpb* fat_bpb = &fat_bpbs[volume];
2229 /* fixme: remove error check when done */
2230 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2232 LDEBUGF("fat_open() illegal volume %d\n", volume);
2233 return -1;
2235 #else
2236 struct bpb* fat_bpb = &fat_bpbs[0];
2237 #endif
2238 int rc;
2240 dir->entry = 0;
2241 dir->sector = 0;
2243 if (startcluster == 0)
2244 startcluster = fat_bpb->bpb_rootclus;
2246 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2247 if(rc)
2249 DEBUGF( "fat_opendir() - Couldn't open dir"
2250 " (error code %d)\n", rc);
2251 return rc * 10 - 1;
2254 return 0;
2257 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2258 * destination buffer (UTF-8 encoded). Copying is stopped when
2259 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2260 * Trailing \0 is also appended at the end of the UTF8-encoded
2261 * string.
2263 * utf16src utf16 (little endian) segment to copy
2264 * utf16count max number of the utf16-characters to copy
2265 * utf8dst where to write UTF8-encoded string to
2267 * returns the number of UTF-16 characters actually copied
2269 static int fat_copy_long_name_segment(unsigned char *utf16src,
2270 int utf16count, unsigned char *utf8dst) {
2271 int cnt = 0;
2272 while ((utf16count--) > 0) {
2273 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2274 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2275 break;
2277 utf8dst = utf8encode(ucs, utf8dst);
2278 utf16src += 2;
2279 cnt++;
2281 *utf8dst = 0;
2282 return cnt;
2285 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2287 bool done = false;
2288 int i;
2289 int rc;
2290 unsigned char firstbyte;
2291 /* Long file names are stored in special entries. Each entry holds
2292 up to 13 characters. Names can be max 255 chars (not bytes!) long
2293 hence max 20 entries are required. */
2294 int longarray[20];
2295 int longs=0;
2296 int sectoridx=0;
2297 unsigned char* cached_buf = dir->sectorcache[0];
2299 dir->entrycount = 0;
2301 while(!done)
2303 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2305 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2306 if (rc == 0) {
2307 /* eof */
2308 entry->name[0] = 0;
2309 break;
2311 if (rc < 0) {
2312 DEBUGF( "fat_getnext() - Couldn't read dir"
2313 " (error code %d)\n", rc);
2314 return rc * 10 - 1;
2316 dir->sector = dir->file.lastsector;
2319 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2320 i < DIR_ENTRIES_PER_SECTOR; i++)
2322 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2324 firstbyte = cached_buf[entrypos];
2325 dir->entry++;
2327 if (firstbyte == 0xe5) {
2328 /* free entry */
2329 sectoridx = 0;
2330 dir->entrycount = 0;
2331 continue;
2334 if (firstbyte == 0) {
2335 /* last entry */
2336 entry->name[0] = 0;
2337 dir->entrycount = 0;
2338 return 0;
2341 dir->entrycount++;
2343 /* longname entry? */
2344 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2345 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2346 longarray[longs++] = entrypos + sectoridx;
2348 else {
2349 if ( parse_direntry(entry,
2350 &cached_buf[entrypos]) ) {
2352 /* don't return volume id entry */
2353 if ( (entry->attr &
2354 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2355 == FAT_ATTR_VOLUME_ID)
2356 continue;
2358 /* replace shortname with longname? */
2359 if ( longs ) {
2360 int j;
2361 /* This should be enough to hold any name segment utf8-encoded */
2362 unsigned char shortname[13]; /* 8+3+dot+\0 */
2363 unsigned char longname_utf8segm[6*4 + 1]; /* Add 1 for trailing \0 */
2364 int longname_utf8len = 0;
2366 strcpy(shortname, entry->name); /* Temporarily store it */
2367 entry->name[0] = 0;
2369 /* iterate backwards through the dir entries */
2370 for (j=longs-1; j>=0; j--) {
2371 unsigned char* ptr = cached_buf;
2372 int index = longarray[j];
2373 /* current or cached sector? */
2374 if ( sectoridx >= SECTOR_SIZE ) {
2375 if ( sectoridx >= SECTOR_SIZE*2 ) {
2376 if ( ( index >= SECTOR_SIZE ) &&
2377 ( index < SECTOR_SIZE*2 ))
2378 ptr = dir->sectorcache[1];
2379 else
2380 ptr = dir->sectorcache[2];
2382 else {
2383 if ( index < SECTOR_SIZE )
2384 ptr = dir->sectorcache[1];
2387 index &= SECTOR_SIZE-1;
2390 /* Try to append each segment of the long name. Check if we'd
2391 exceed the buffer. Also check for FAT padding characters 0xFFFF. */
2392 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2393 longname_utf8segm) == 0) break;
2394 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2395 longname_utf8len += strlen(longname_utf8segm);
2396 if (longname_utf8len < FAT_FILENAME_BYTES)
2397 strcat(entry->name, longname_utf8segm);
2398 else
2399 break;
2401 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2402 longname_utf8segm) == 0) break;
2403 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2404 longname_utf8len += strlen(longname_utf8segm);
2405 if (longname_utf8len < FAT_FILENAME_BYTES)
2406 strcat(entry->name, longname_utf8segm);
2407 else
2408 break;
2410 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2411 longname_utf8segm) == 0) break;
2412 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2413 longname_utf8len += strlen(longname_utf8segm);
2414 if (longname_utf8len < FAT_FILENAME_BYTES)
2415 strcat(entry->name, longname_utf8segm);
2416 else
2417 break;
2420 /* Does the utf8-encoded name fit into the entry? */
2421 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2422 /* Take the short DOS name. Need to utf8-encode it since
2423 it may contain chars from the upper half of the OEM
2424 code page which wouldn't be a valid utf8. Beware: this
2425 file will be shown with strange glyphs in file browser
2426 since unicode 0x80 to 0x9F are control characters. */
2427 logf("SN-DOS: %s", shortname);
2428 unsigned char *utf8;
2429 utf8 = iso_decode(shortname, entry->name, -1, strlen(shortname));
2430 *utf8 = 0;
2431 logf("SN: %s", entry->name);
2432 } else {
2433 // logf("LN: %s", entry->name);
2434 // logf("LNLen: %d (%c)", longname_utf8len, entry->name[0]);
2437 done = true;
2438 sectoridx = 0;
2439 i++;
2440 break;
2445 /* save this sector, for longname use */
2446 if ( sectoridx )
2447 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2448 else
2449 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2450 sectoridx += SECTOR_SIZE;
2453 return 0;
2456 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2458 #ifndef HAVE_MULTIVOLUME
2459 const int volume = 0;
2460 #endif
2461 struct bpb* fat_bpb = &fat_bpbs[volume];
2462 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2465 #ifdef HAVE_MULTIVOLUME
2466 bool fat_ismounted(int volume)
2468 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2470 #endif