Android: Partly revert r29569 and only call the new getJavaEnvironment() when needed.
[maemo-rb.git] / firmware / drivers / fat.c
bloba4eb24ce7fb9688a85674abcc1d3ef720a805f38
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 "storage.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 /*#define LOGF_ENABLE*/
35 #include "logf.h"
37 #define BYTES2INT16(array,pos) \
38 (array[pos] | (array[pos+1] << 8 ))
39 #define BYTES2INT32(array,pos) \
40 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
41 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
43 #define FATTYPE_FAT12 0
44 #define FATTYPE_FAT16 1
45 #define FATTYPE_FAT32 2
47 /* BPB offsets; generic */
48 #define BS_JMPBOOT 0
49 #define BS_OEMNAME 3
50 #define BPB_BYTSPERSEC 11
51 #define BPB_SECPERCLUS 13
52 #define BPB_RSVDSECCNT 14
53 #define BPB_NUMFATS 16
54 #define BPB_ROOTENTCNT 17
55 #define BPB_TOTSEC16 19
56 #define BPB_MEDIA 21
57 #define BPB_FATSZ16 22
58 #define BPB_SECPERTRK 24
59 #define BPB_NUMHEADS 26
60 #define BPB_HIDDSEC 28
61 #define BPB_TOTSEC32 32
63 /* fat12/16 */
64 #define BS_DRVNUM 36
65 #define BS_RESERVED1 37
66 #define BS_BOOTSIG 38
67 #define BS_VOLID 39
68 #define BS_VOLLAB 43
69 #define BS_FILSYSTYPE 54
71 /* fat32 */
72 #define BPB_FATSZ32 36
73 #define BPB_EXTFLAGS 40
74 #define BPB_FSVER 42
75 #define BPB_ROOTCLUS 44
76 #define BPB_FSINFO 48
77 #define BPB_BKBOOTSEC 50
78 #define BS_32_DRVNUM 64
79 #define BS_32_BOOTSIG 66
80 #define BS_32_VOLID 67
81 #define BS_32_VOLLAB 71
82 #define BS_32_FILSYSTYPE 82
84 #define BPB_LAST_WORD 510
87 /* attributes */
88 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
90 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
91 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
92 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
94 /* NTRES flags */
95 #define FAT_NTRES_LC_NAME 0x08
96 #define FAT_NTRES_LC_EXT 0x10
98 #define FATDIR_NAME 0
99 #define FATDIR_ATTR 11
100 #define FATDIR_NTRES 12
101 #define FATDIR_CRTTIMETENTH 13
102 #define FATDIR_CRTTIME 14
103 #define FATDIR_CRTDATE 16
104 #define FATDIR_LSTACCDATE 18
105 #define FATDIR_FSTCLUSHI 20
106 #define FATDIR_WRTTIME 22
107 #define FATDIR_WRTDATE 24
108 #define FATDIR_FSTCLUSLO 26
109 #define FATDIR_FILESIZE 28
111 #define FATLONG_ORDER 0
112 #define FATLONG_TYPE 12
113 #define FATLONG_CHKSUM 13
114 #define FATLONG_LAST_LONG_ENTRY 0x40
115 #define FATLONG_NAME_BYTES_PER_ENTRY 26
116 /* at most 20 LFN entries, keep coherent with fat_dir->longname size ! */
117 #define FATLONG_MAX_ORDER 20
119 #define FATLONG_NAME_CHUNKS 3
120 static unsigned char FATLONG_NAME_POS[FATLONG_NAME_CHUNKS] = {1, 14, 28};
121 static unsigned char FATLONG_NAME_SIZE[FATLONG_NAME_CHUNKS] = {10, 12, 4};
123 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
124 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
125 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
126 #define DIR_ENTRY_SIZE 32
127 #define NAME_BYTES_PER_ENTRY 13
128 #define FAT_BAD_MARK 0x0ffffff7
129 #define FAT_EOF_MARK 0x0ffffff8
130 #define FAT_LONGNAME_PAD_BYTE 0xff
131 #define FAT_LONGNAME_PAD_UCS 0xffff
133 struct fsinfo {
134 unsigned long freecount; /* last known free cluster count */
135 unsigned long nextfree; /* first cluster to start looking for free
136 clusters, or 0xffffffff for no hint */
138 /* fsinfo offsets */
139 #define FSINFO_FREECOUNT 488
140 #define FSINFO_NEXTFREE 492
142 /* Note: This struct doesn't hold the raw values after mounting if
143 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
144 * physical sectors. */
145 struct bpb
147 int bpb_bytspersec; /* Bytes per sector, typically 512 */
148 unsigned int bpb_secperclus; /* Sectors per cluster */
149 int bpb_rsvdseccnt; /* Number of reserved sectors */
150 int bpb_numfats; /* Number of FAT structures, typically 2 */
151 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
152 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
153 int bpb_fatsz16; /* Number of used sectors per FAT structure */
154 unsigned long bpb_totsec32; /* Number of sectors on the volume
155 (new 32-bit) */
156 unsigned int last_word; /* 0xAA55 */
158 /**** FAT32 specific *****/
159 long bpb_fatsz32;
160 long bpb_rootclus;
161 long bpb_fsinfo;
163 /* variables for internal use */
164 unsigned long fatsize;
165 unsigned long totalsectors;
166 unsigned long rootdirsector;
167 unsigned long firstdatasector;
168 unsigned long startsector;
169 unsigned long dataclusters;
170 struct fsinfo fsinfo;
171 #ifdef HAVE_FAT16SUPPORT
172 int bpb_rootentcnt; /* Number of dir entries in the root */
173 /* internals for FAT16 support */
174 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
175 unsigned int rootdiroffset; /* sector offset of root dir relative to start
176 * of first pseudo cluster */
177 #endif /* #ifdef HAVE_FAT16SUPPORT */
178 #ifdef HAVE_MULTIVOLUME
179 #ifdef HAVE_MULTIDRIVE
180 int drive; /* on which physical device is this located */
181 #endif
182 bool mounted; /* flag if this volume is mounted */
183 #endif
186 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
187 static bool initialized = false;
189 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
190 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
191 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
192 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
193 long secnum, bool dirty);
194 static void create_dos_name(const unsigned char *name, unsigned char *newname);
195 static void randomize_dos_name(unsigned char *name);
196 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
197 unsigned long start);
198 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
199 long count, char* buf, bool write );
201 #define FAT_CACHE_SIZE 0x20
202 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
204 struct fat_cache_entry
206 long secnum;
207 bool inuse;
208 bool dirty;
209 #ifdef HAVE_MULTIVOLUME
210 struct bpb* fat_vol ; /* shared cache for all volumes */
211 #endif
214 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE] CACHEALIGN_ATTR;
215 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
216 static struct mutex cache_mutex SHAREDBSS_ATTR;
217 static struct mutex tempbuf_mutex;
218 static char fat_tempbuf[SECTOR_SIZE] CACHEALIGN_ATTR;
219 static bool tempbuf_locked;
221 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
222 void fat_lock(void)
224 mutex_lock(&cache_mutex);
227 void fat_unlock(void)
229 mutex_unlock(&cache_mutex);
231 #endif
233 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
235 #ifndef HAVE_MULTIVOLUME
236 struct bpb* fat_bpb = &fat_bpbs[0];
237 #endif
238 #ifdef HAVE_FAT16SUPPORT
239 /* negative clusters (FAT16 root dir) don't get the 2 offset */
240 int zerocluster = cluster < 0 ? 0 : 2;
241 #else
242 const long zerocluster = 2;
243 #endif
245 if (cluster > (long)(fat_bpb->dataclusters + 1))
247 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
248 return -1;
251 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
252 + fat_bpb->firstdatasector;
255 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
257 #ifndef HAVE_MULTIVOLUME
258 const int volume = 0;
259 #endif
260 struct bpb* fat_bpb = &fat_bpbs[volume];
261 if (size)
262 *size = fat_bpb->dataclusters * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
263 if (free)
264 *free = fat_bpb->fsinfo.freecount * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
267 void fat_init(void)
269 unsigned int i;
271 if (!initialized)
273 initialized = true;
274 mutex_init(&cache_mutex);
275 mutex_init(&tempbuf_mutex);
276 tempbuf_locked = false;
279 #ifdef HAVE_PRIORITY_SCHEDULING
280 /* Disable this because it is dangerous due to the assumption that
281 * mutex_unlock won't yield */
282 mutex_set_preempt(&cache_mutex, false);
283 #endif
285 /* mark the FAT cache as unused */
286 for(i = 0;i < FAT_CACHE_SIZE;i++)
288 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
289 fat_cache[i].inuse = false;
290 fat_cache[i].dirty = false;
291 #ifdef HAVE_MULTIVOLUME
292 fat_cache[i].fat_vol = NULL;
293 #endif
295 #ifdef HAVE_MULTIVOLUME
296 /* mark the possible volumes as not mounted */
297 for (i=0; i<NUM_VOLUMES;i++)
299 fat_bpbs[i].mounted = false;
301 #endif
304 /* fat_mount_internal is split out of fat_mount() to avoid having both the sector
305 * buffer used here and the sector buffer used by update_fsinfo() on stack */
306 static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
308 #ifndef HAVE_MULTIVOLUME
309 const int volume = 0;
310 #endif
311 struct bpb* fat_bpb = &fat_bpbs[volume];
312 int rc;
313 int secmult;
314 long datasec;
315 #ifdef HAVE_FAT16SUPPORT
316 int rootdirsectors;
317 #endif
319 unsigned char* buf = fat_get_sector_buffer();
320 /* Read the sector */
321 rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
322 if(rc)
324 fat_release_sector_buffer();
325 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
326 return rc * 10 - 1;
329 memset(fat_bpb, 0, sizeof(struct bpb));
330 fat_bpb->startsector = startsector;
331 #ifdef HAVE_MULTIDRIVE
332 fat_bpb->drive = drive;
333 #endif
335 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
336 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
337 /* Sanity check is performed later */
339 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
340 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
341 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
342 fat_bpb->bpb_media = buf[BPB_MEDIA];
343 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
344 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
345 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
346 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
347 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
349 /* calculate a few commonly used values */
350 if (fat_bpb->bpb_fatsz16 != 0)
351 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
352 else
353 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
355 if (fat_bpb->bpb_totsec16 != 0)
356 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
357 else
358 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
360 #ifdef HAVE_FAT16SUPPORT
361 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
362 if (!fat_bpb->bpb_bytspersec)
364 fat_release_sector_buffer();
365 return -2;
367 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
368 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
369 #endif /* #ifdef HAVE_FAT16SUPPORT */
371 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
372 #ifdef HAVE_FAT16SUPPORT
373 + rootdirsectors
374 #endif
375 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
377 /* Determine FAT type */
378 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
379 if (fat_bpb->bpb_secperclus)
380 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
381 else
383 fat_release_sector_buffer();
384 return -2;
387 #ifdef TEST_FAT
389 we are sometimes testing with "illegally small" fat32 images,
390 so we don't use the proper fat32 test case for test code
392 if ( fat_bpb->bpb_fatsz16 )
393 #else
394 if ( fat_bpb->dataclusters < 65525 )
395 #endif
396 { /* FAT16 */
397 #ifdef HAVE_FAT16SUPPORT
398 fat_bpb->is_fat16 = true;
399 if (fat_bpb->dataclusters < 4085)
400 { /* FAT12 */
401 fat_release_sector_buffer();
402 DEBUGF("This is FAT12. Go away!\n");
403 return -2;
405 #else /* #ifdef HAVE_FAT16SUPPORT */
406 fat_release_sector_buffer();
407 DEBUGF("This is not FAT32. Go away!\n");
408 return -2;
409 #endif /* #ifndef HAVE_FAT16SUPPORT */
412 #ifdef HAVE_FAT16SUPPORT
413 if (fat_bpb->is_fat16)
414 { /* FAT16 specific part of BPB */
415 int dirclusters;
416 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
417 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
418 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
419 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
420 /* I assign negative pseudo cluster numbers for the root directory,
421 their range is counted upward until -1. */
422 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
423 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
424 - rootdirsectors;
426 else
427 #endif /* #ifdef HAVE_FAT16SUPPORT */
428 { /* FAT32 specific part of BPB */
429 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
430 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
431 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
432 fat_bpb->bpb_rootclus);
435 rc = bpb_is_sane(IF_MV(fat_bpb));
436 if (rc < 0)
438 fat_release_sector_buffer();
439 DEBUGF( "fat_mount() - BPB is not sane\n");
440 return rc * 10 - 3;
443 #ifdef HAVE_FAT16SUPPORT
444 if (fat_bpb->is_fat16)
446 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
447 fat_bpb->fsinfo.nextfree = 0xffffffff;
449 else
450 #endif /* #ifdef HAVE_FAT16SUPPORT */
452 /* Read the fsinfo sector */
453 rc = storage_read_sectors(IF_MD2(drive,)
454 startsector + fat_bpb->bpb_fsinfo, 1, buf);
455 if (rc < 0)
457 fat_release_sector_buffer();
458 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
459 return rc * 10 - 4;
461 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
462 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
464 fat_release_sector_buffer();
465 return 0;
468 void* fat_get_sector_buffer()
470 mutex_lock(&tempbuf_mutex);
471 if (tempbuf_locked)
472 panicf("FAT: Tried to lock temporary sector buffer twice!");
473 tempbuf_locked = true;
474 return fat_tempbuf;
477 void fat_release_sector_buffer()
479 tempbuf_locked = false;
480 mutex_unlock(&tempbuf_mutex);
483 #ifdef MAX_LOG_SECTOR_SIZE
484 int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume))
486 #ifdef HAVE_MULTIVOLUME
487 if(!fat_bpbs[volume].mounted)
488 return 0;
489 return fat_bpbs[volume].bpb_bytspersec;
490 #else
491 return fat_bpbs[0].bpb_bytspersec;
492 #endif
494 #endif
496 int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
498 #ifndef HAVE_MULTIVOLUME
499 const int volume = 0;
500 #endif
501 struct bpb* fat_bpb = &fat_bpbs[volume];
502 int rc;
504 rc = fat_mount_internal(IF_MV2(volume,) IF_MD2(drive,) startsector);
506 if(rc!=0) return rc;
508 /* calculate freecount if unset */
509 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
511 fat_recalc_free(IF_MV(volume));
514 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
515 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
516 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
517 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
518 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
520 #ifdef HAVE_MULTIVOLUME
521 fat_bpb->mounted = true;
522 #endif
524 return 0;
527 int fat_unmount(int volume, bool flush)
529 int rc;
530 #ifdef HAVE_MULTIVOLUME
531 struct bpb* fat_bpb = &fat_bpbs[volume];
532 #else
533 (void)volume;
534 #endif
536 if(flush)
538 rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
540 else
541 { /* volume is not accessible any more, e.g. MMC removed */
542 int i;
543 mutex_lock(&cache_mutex);
544 for(i = 0;i < FAT_CACHE_SIZE;i++)
546 struct fat_cache_entry *fce = &fat_cache[i];
547 if(fce->inuse
548 #ifdef HAVE_MULTIVOLUME
549 && fce->fat_vol == fat_bpb
550 #endif
553 fce->inuse = false; /* discard all from that volume */
554 fce->dirty = false;
557 mutex_unlock(&cache_mutex);
558 rc = 0;
560 #ifdef HAVE_MULTIVOLUME
561 fat_bpb->mounted = false;
562 #endif
563 return rc;
566 void fat_recalc_free(IF_MV_NONVOID(int volume))
568 #ifndef HAVE_MULTIVOLUME
569 const int volume = 0;
570 #endif
571 struct bpb* fat_bpb = &fat_bpbs[volume];
572 long free = 0;
573 unsigned long i;
574 #ifdef HAVE_FAT16SUPPORT
575 if (fat_bpb->is_fat16)
577 for (i = 0; i<fat_bpb->fatsize; i++) {
578 unsigned int j;
579 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
580 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
581 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
582 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
583 break;
585 if (letoh16(fat[j]) == 0x0000) {
586 free++;
587 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
588 fat_bpb->fsinfo.nextfree = c;
593 else
594 #endif /* #ifdef HAVE_FAT16SUPPORT */
596 for (i = 0; i<fat_bpb->fatsize; i++) {
597 unsigned int j;
598 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
599 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
600 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
601 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
602 break;
604 if (!(letoh32(fat[j]) & 0x0fffffff)) {
605 free++;
606 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
607 fat_bpb->fsinfo.nextfree = c;
612 fat_bpb->fsinfo.freecount = free;
613 update_fsinfo(IF_MV(fat_bpb));
616 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
618 #ifndef HAVE_MULTIVOLUME
619 struct bpb* fat_bpb = &fat_bpbs[0];
620 #endif
621 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
623 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
624 fat_bpb->bpb_bytspersec);
625 return -1;
627 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
628 > 128L*1024L)
630 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
631 "(%d * %d = %d)\n",
632 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
633 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
634 return -2;
636 if(fat_bpb->bpb_numfats != 2)
638 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
639 fat_bpb->bpb_numfats);
641 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
643 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
644 "media type (0x%02x)\n",
645 fat_bpb->bpb_media);
647 if(fat_bpb->last_word != 0xaa55)
649 DEBUGF( "bpb_is_sane() - Error: Last word is not "
650 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
651 return -3;
654 if (fat_bpb->fsinfo.freecount >
655 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
656 fat_bpb->bpb_secperclus)
658 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
659 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
660 return -4;
663 return 0;
666 static void flush_fat_sector(struct fat_cache_entry *fce,
667 unsigned char *sectorbuf)
669 int rc;
670 long secnum;
672 /* With multivolume, use only the FAT info from the cached sector! */
673 #ifdef HAVE_MULTIVOLUME
674 secnum = fce->secnum + fce->fat_vol->startsector;
675 #else
676 secnum = fce->secnum + fat_bpbs[0].startsector;
677 #endif
679 /* Write to the first FAT */
680 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
681 secnum, 1,
682 sectorbuf);
683 if(rc < 0)
685 panicf("flush_fat_sector() - Could not write sector %ld"
686 " (error %d)\n",
687 secnum, rc);
689 #ifdef HAVE_MULTIVOLUME
690 if(fce->fat_vol->bpb_numfats > 1)
691 #else
692 if(fat_bpbs[0].bpb_numfats > 1)
693 #endif
695 /* Write to the second FAT */
696 #ifdef HAVE_MULTIVOLUME
697 secnum += fce->fat_vol->fatsize;
698 #else
699 secnum += fat_bpbs[0].fatsize;
700 #endif
701 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
702 secnum, 1, sectorbuf);
703 if(rc < 0)
705 panicf("flush_fat_sector() - Could not write sector %ld"
706 " (error %d)\n",
707 secnum, rc);
710 fce->dirty = false;
713 /* Note: The returned pointer is only safely valid until the next
714 task switch! (Any subsequent ata read/write may yield.) */
715 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
716 long fatsector, bool dirty)
718 #ifndef HAVE_MULTIVOLUME
719 struct bpb* fat_bpb = &fat_bpbs[0];
720 #endif
721 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
722 int cache_index = secnum & FAT_CACHE_MASK;
723 struct fat_cache_entry *fce = &fat_cache[cache_index];
724 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
725 int rc;
727 mutex_lock(&cache_mutex); /* make changes atomic */
729 /* Delete the cache entry if it isn't the sector we want */
730 if(fce->inuse && (fce->secnum != secnum
731 #ifdef HAVE_MULTIVOLUME
732 || fce->fat_vol != fat_bpb
733 #endif
736 /* Write back if it is dirty */
737 if(fce->dirty)
739 flush_fat_sector(fce, sectorbuf);
741 fce->inuse = false;
744 /* Load the sector if it is not cached */
745 if(!fce->inuse)
747 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
748 secnum + fat_bpb->startsector,1,
749 sectorbuf);
750 if(rc < 0)
752 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
753 " (error %d)\n", secnum, rc);
754 mutex_unlock(&cache_mutex);
755 return NULL;
757 fce->inuse = true;
758 fce->secnum = secnum;
759 #ifdef HAVE_MULTIVOLUME
760 fce->fat_vol = fat_bpb;
761 #endif
763 if (dirty)
764 fce->dirty = true; /* dirt remains, sticky until flushed */
765 mutex_unlock(&cache_mutex);
766 return sectorbuf;
769 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
770 unsigned long startcluster)
772 #ifndef HAVE_MULTIVOLUME
773 struct bpb* fat_bpb = &fat_bpbs[0];
774 #endif
775 unsigned long sector;
776 unsigned long offset;
777 unsigned long i;
779 #ifdef HAVE_FAT16SUPPORT
780 if (fat_bpb->is_fat16)
782 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
783 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
785 for (i = 0; i<fat_bpb->fatsize; i++) {
786 unsigned int j;
787 unsigned int nr = (i + sector) % fat_bpb->fatsize;
788 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
789 if ( !fat )
790 break;
791 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
792 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
793 if (letoh16(fat[k]) == 0x0000) {
794 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
795 /* Ignore the reserved clusters 0 & 1, and also
796 cluster numbers out of bounds */
797 if ( c < 2 || c > fat_bpb->dataclusters+1 )
798 continue;
799 LDEBUGF("find_free_cluster(%lx) == %x\n",startcluster,c);
800 fat_bpb->fsinfo.nextfree = c;
801 return c;
804 offset = 0;
807 else
808 #endif /* #ifdef HAVE_FAT16SUPPORT */
810 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
811 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
813 for (i = 0; i<fat_bpb->fatsize; i++) {
814 unsigned int j;
815 unsigned long nr = (i + sector) % fat_bpb->fatsize;
816 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
817 if ( !fat )
818 break;
819 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
820 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
821 if (!(letoh32(fat[k]) & 0x0fffffff)) {
822 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
823 /* Ignore the reserved clusters 0 & 1, and also
824 cluster numbers out of bounds */
825 if ( c < 2 || c > fat_bpb->dataclusters+1 )
826 continue;
827 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
828 fat_bpb->fsinfo.nextfree = c;
829 return c;
832 offset = 0;
836 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
837 return 0; /* 0 is an illegal cluster number */
840 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
841 unsigned long val)
843 #ifndef HAVE_MULTIVOLUME
844 struct bpb* fat_bpb = &fat_bpbs[0];
845 #endif
846 #ifdef HAVE_FAT16SUPPORT
847 if (fat_bpb->is_fat16)
849 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
850 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
851 unsigned short* sec;
853 val &= 0xFFFF;
855 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
857 if (entry==val)
858 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
860 if ( entry < 2 )
861 panicf("Updating reserved FAT entry %ld.\n",entry);
863 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
864 if (!sec)
866 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
867 return -1;
870 if ( val ) {
871 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
872 fat_bpb->fsinfo.freecount--;
874 else {
875 if (letoh16(sec[offset]))
876 fat_bpb->fsinfo.freecount++;
879 LDEBUGF("update_fat_entry: %lu free clusters\n",
880 fat_bpb->fsinfo.freecount);
882 sec[offset] = htole16(val);
884 else
885 #endif /* #ifdef HAVE_FAT16SUPPORT */
887 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
888 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
889 unsigned long* sec;
891 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
893 if (entry==val)
894 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
896 if ( entry < 2 )
897 panicf("Updating reserved FAT entry %ld.\n",entry);
899 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
900 if (!sec)
902 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
903 return -1;
906 if ( val ) {
907 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
908 fat_bpb->fsinfo.freecount > 0)
909 fat_bpb->fsinfo.freecount--;
911 else {
912 if (letoh32(sec[offset]) & 0x0fffffff)
913 fat_bpb->fsinfo.freecount++;
916 LDEBUGF("update_fat_entry: %ld free clusters\n",
917 fat_bpb->fsinfo.freecount);
919 /* don't change top 4 bits */
920 sec[offset] &= htole32(0xf0000000);
921 sec[offset] |= htole32(val & 0x0fffffff);
924 return 0;
927 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
929 #ifdef HAVE_FAT16SUPPORT
930 #ifndef HAVE_MULTIVOLUME
931 struct bpb* fat_bpb = &fat_bpbs[0];
932 #endif
933 if (fat_bpb->is_fat16)
935 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
936 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
937 unsigned short* sec;
939 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
940 if (!sec)
942 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
943 return -1;
946 return letoh16(sec[offset]);
948 else
949 #endif /* #ifdef HAVE_FAT16SUPPORT */
951 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
952 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
953 unsigned long* sec;
955 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
956 if (!sec)
958 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
959 return -1;
962 return letoh32(sec[offset]) & 0x0fffffff;
966 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
968 long next_cluster;
969 long eof_mark = FAT_EOF_MARK;
971 #ifdef HAVE_FAT16SUPPORT
972 #ifndef HAVE_MULTIVOLUME
973 struct bpb* fat_bpb = &fat_bpbs[0];
974 #endif
975 if (fat_bpb->is_fat16)
977 eof_mark &= 0xFFFF; /* only 16 bit */
978 if (cluster < 0) /* FAT16 root dir */
979 return cluster + 1; /* don't use the FAT */
981 #endif
982 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
984 /* is this last cluster in chain? */
985 if ( next_cluster >= eof_mark )
986 return 0;
987 else
988 return next_cluster;
991 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
993 #ifndef HAVE_MULTIVOLUME
994 struct bpb* fat_bpb = &fat_bpbs[0];
995 #endif
996 unsigned long* intptr;
997 int rc;
999 #ifdef HAVE_FAT16SUPPORT
1000 if (fat_bpb->is_fat16)
1001 return 0; /* FAT16 has no FsInfo */
1002 #endif /* #ifdef HAVE_FAT16SUPPORT */
1004 unsigned char* fsinfo = fat_get_sector_buffer();
1005 /* update fsinfo */
1006 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
1007 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
1008 if (rc < 0)
1010 fat_release_sector_buffer();
1011 DEBUGF( "update_fsinfo() - Couldn't read FSInfo (error code %d)", rc);
1012 return rc * 10 - 1;
1014 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
1015 *intptr = htole32(fat_bpb->fsinfo.freecount);
1017 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
1018 *intptr = htole32(fat_bpb->fsinfo.nextfree);
1020 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
1021 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
1022 fat_release_sector_buffer();
1023 if (rc < 0)
1025 DEBUGF( "update_fsinfo() - Couldn't write FSInfo (error code %d)", rc);
1026 return rc * 10 - 2;
1029 return 0;
1032 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
1034 int i;
1035 int rc;
1036 unsigned char *sec;
1037 LDEBUGF("flush_fat()\n");
1039 mutex_lock(&cache_mutex);
1040 for(i = 0;i < FAT_CACHE_SIZE;i++)
1042 struct fat_cache_entry *fce = &fat_cache[i];
1043 if(fce->inuse
1044 #ifdef HAVE_MULTIVOLUME
1045 && fce->fat_vol == fat_bpb
1046 #endif
1047 && fce->dirty)
1049 sec = fat_cache_sectors[i];
1050 flush_fat_sector(fce, sec);
1053 mutex_unlock(&cache_mutex);
1055 rc = update_fsinfo(IF_MV(fat_bpb));
1056 if (rc < 0)
1057 return rc * 10 - 3;
1059 return 0;
1062 static void fat_time(unsigned short* date,
1063 unsigned short* time,
1064 unsigned short* tenth )
1066 #if CONFIG_RTC
1067 struct tm* tm = get_time();
1069 if (date)
1070 *date = ((tm->tm_year - 80) << 9) |
1071 ((tm->tm_mon + 1) << 5) |
1072 tm->tm_mday;
1074 if (time)
1075 *time = (tm->tm_hour << 11) |
1076 (tm->tm_min << 5) |
1077 (tm->tm_sec >> 1);
1079 if (tenth)
1080 *tenth = (tm->tm_sec & 1) * 100;
1081 #else
1082 /* non-RTC version returns an increment from the supplied time, or a
1083 * fixed standard time/date if no time given as input */
1085 /* Macros to convert a 2-digit string to a decimal constant.
1086 (YEAR), MONTH and DAY are set by the date command, which outputs
1087 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1088 misinterpretation as an octal constant. */
1089 #define S100(x) 1 ## x
1090 #define C2DIG2DEC(x) (S100(x)-100)
1091 /* The actual build date, as FAT date constant */
1092 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1093 | (C2DIG2DEC(MONTH) << 5) \
1094 | C2DIG2DEC(DAY))
1096 bool date_forced = false;
1097 bool next_day = false;
1098 unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */
1100 if (date && *date < BUILD_DATE_FAT)
1102 *date = BUILD_DATE_FAT;
1103 date_forced = true;
1106 if (time)
1108 time2 = *time << 1;
1109 if (time2 == 0 || date_forced)
1111 time2 = (11 < 6) | 11; /* set to 00:11:11 */
1113 else
1115 unsigned mins = (time2 >> 6) & 0x3f;
1116 unsigned hours = (time2 >> 12) & 0x1f;
1118 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */
1119 if (mins > 59)
1121 mins = 11; /* 00 would be a bad marker */
1122 if (++hours > 23)
1124 hours = 0;
1125 next_day = true;
1128 time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */
1130 *time = time2 >> 1;
1133 if (tenth)
1134 *tenth = (time2 & 1) * 100;
1136 if (date && next_day)
1138 static const unsigned char daysinmonth[] =
1139 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1140 unsigned day = *date & 0x1f;
1141 unsigned month = (*date >> 5) & 0x0f;
1142 unsigned year = (*date >> 9) & 0x7f;
1144 /* simplification: ignore leap years */
1145 if (++day > daysinmonth[month-1])
1147 day = 1;
1148 if (++month > 12)
1150 month = 1;
1151 year++;
1154 *date = (year << 9) | (month << 5) | day;
1157 #endif /* CONFIG_RTC */
1160 static int write_long_name(struct fat_file* file,
1161 unsigned int firstentry,
1162 unsigned int numentries,
1163 const unsigned char* name,
1164 const unsigned char* shortname,
1165 bool is_directory)
1167 unsigned char* entry;
1168 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1169 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1170 unsigned char chksum = 0;
1171 unsigned int i, j=0;
1172 unsigned int nameidx=0, namelen = utf8length(name);
1173 int rc;
1174 unsigned short name_utf16[namelen + 1];
1176 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1177 file->firstcluster, firstentry, numentries, name);
1179 rc = fat_seek(file, sector);
1180 if (rc<0)
1181 return rc * 10 - 1;
1183 unsigned char* buf = fat_get_sector_buffer();
1184 rc = fat_readwrite(file, 1, buf, false);
1185 if (rc<1)
1187 fat_release_sector_buffer();
1188 return rc * 10 - 2;
1191 /* calculate shortname checksum */
1192 for (i=11; i>0; i--)
1193 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1195 /* calc position of last name segment */
1196 if ( namelen > NAME_BYTES_PER_ENTRY )
1197 for (nameidx=0;
1198 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1199 nameidx += NAME_BYTES_PER_ENTRY);
1201 /* we need to convert the name first */
1202 /* since it is written in reverse order */
1203 for (i = 0; i <= namelen; i++)
1204 name = utf8decode(name, &name_utf16[i]);
1206 for (i=0; i < numentries; i++) {
1207 /* new sector? */
1208 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1209 /* update current sector */
1210 rc = fat_seek(file, sector);
1211 if (rc<0)
1213 fat_release_sector_buffer();
1214 return rc * 10 - 3;
1217 rc = fat_readwrite(file, 1, buf, true);
1218 if (rc<1)
1220 fat_release_sector_buffer();
1221 return rc * 10 - 4;
1224 /* read next sector */
1225 rc = fat_readwrite(file, 1, buf, false);
1226 if (rc<0) {
1227 fat_release_sector_buffer();
1228 LDEBUGF("Failed writing new sector: %d\n",rc);
1229 return rc * 10 - 5;
1231 if (rc==0)
1232 /* end of dir */
1233 memset(buf, 0, SECTOR_SIZE);
1235 sector++;
1236 idx = 0;
1239 entry = buf + idx * DIR_ENTRY_SIZE;
1241 /* verify this entry is free */
1242 if (entry[0] && entry[0] != 0xe5 )
1244 fat_release_sector_buffer();
1245 panicf("Dir entry %d in sector %x is not free! "
1246 "%02x %02x %02x %02x",
1247 idx, sector,
1248 entry[0], entry[1], entry[2], entry[3]);
1251 memset(entry, 0, DIR_ENTRY_SIZE);
1252 if ( i+1 < numentries ) {
1253 /* longname entry */
1254 unsigned int k, l = nameidx;
1256 entry[FATLONG_ORDER] = numentries-i-1;
1257 if (i==0) {
1258 /* mark this as last long entry */
1259 entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1261 /* pad name with 0xffff */
1262 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1263 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1264 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1266 /* set name */
1267 for (k=0; k<5 && l <= namelen; k++) {
1268 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1269 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1271 for (k=0; k<6 && l <= namelen; k++) {
1272 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1273 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1275 for (k=0; k<2 && l <= namelen; k++) {
1276 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1277 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1280 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1281 entry[FATDIR_FSTCLUSLO] = 0;
1282 entry[FATLONG_TYPE] = 0;
1283 entry[FATLONG_CHKSUM] = chksum;
1284 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1286 else {
1287 /* shortname entry */
1288 unsigned short date=0, time=0, tenth=0;
1289 LDEBUGF("Shortname entry: %s\n", shortname);
1290 memcpy(entry + FATDIR_NAME, shortname, 11);
1291 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1292 entry[FATDIR_NTRES] = 0;
1294 fat_time(&date, &time, &tenth);
1295 entry[FATDIR_CRTTIMETENTH] = tenth;
1296 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1297 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1298 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1299 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1300 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1302 idx++;
1303 nameidx -= NAME_BYTES_PER_ENTRY;
1306 /* update last sector */
1307 rc = fat_seek(file, sector);
1308 if (rc<0)
1310 fat_release_sector_buffer();
1311 return rc * 10 - 6;
1314 rc = fat_readwrite(file, 1, buf, true);
1315 fat_release_sector_buffer();
1316 if (rc<1)
1317 return rc * 10 - 7;
1319 return 0;
1322 static int fat_checkname(const unsigned char* newname)
1324 static const char invalid_chars[] = "\"*/:<>?\\|";
1325 int len = strlen(newname);
1326 /* More sanity checks are probably needed */
1327 if (len > 255 || newname[len - 1] == '.')
1329 return -1;
1331 while (*newname)
1333 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1334 return -1;
1335 newname++;
1337 /* check trailing space(s) */
1338 if(*(--newname) == ' ')
1339 return -1;
1341 return 0;
1344 static int add_dir_entry(struct fat_dir* dir,
1345 struct fat_file* file,
1346 const char* name,
1347 bool is_directory,
1348 bool dotdir)
1350 #ifdef HAVE_MULTIVOLUME
1351 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1352 #else
1353 struct bpb* fat_bpb = &fat_bpbs[0];
1354 #endif
1355 unsigned char shortname[12];
1356 int rc;
1357 unsigned int sector;
1358 bool done = false;
1359 int entries_needed, entries_found = 0;
1360 int firstentry;
1362 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1363 name, file->firstcluster);
1365 /* Don't check dotdirs name for validity */
1366 if (dotdir == false) {
1367 rc = fat_checkname(name);
1368 if (rc < 0) {
1369 /* filename is invalid */
1370 return rc * 10 - 1;
1374 #ifdef HAVE_MULTIVOLUME
1375 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1376 #endif
1378 /* The "." and ".." directory entries must not be long names */
1379 if(dotdir) {
1380 int i;
1381 strlcpy(shortname, name, 12);
1382 for(i = strlen(shortname); i < 12; i++)
1383 shortname[i] = ' ';
1385 entries_needed = 1;
1386 } else {
1387 create_dos_name(name, shortname);
1389 /* one dir entry needed for every 13 bytes of filename,
1390 plus one entry for the short name */
1391 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1392 / NAME_BYTES_PER_ENTRY + 1;
1395 unsigned char* buf = fat_get_sector_buffer();
1396 restart:
1397 firstentry = -1;
1399 rc = fat_seek(&dir->file, 0);
1400 if (rc < 0)
1402 fat_release_sector_buffer();
1403 return rc * 10 - 2;
1406 /* step 1: search for free entries and check for duplicate shortname */
1407 for (sector = 0; !done; sector++)
1409 unsigned int i;
1411 rc = fat_readwrite(&dir->file, 1, buf, false);
1412 if (rc < 0) {
1413 fat_release_sector_buffer();
1414 DEBUGF( "add_dir_entry() - Couldn't read dir"
1415 " (error code %d)\n", rc);
1416 return rc * 10 - 3;
1419 if (rc == 0) { /* current end of dir reached */
1420 LDEBUGF("End of dir on cluster boundary\n");
1421 break;
1424 /* look for free slots */
1425 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1427 switch (buf[i * DIR_ENTRY_SIZE]) {
1428 case 0:
1429 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1430 LDEBUGF("Found end of dir %d\n",
1431 sector * DIR_ENTRIES_PER_SECTOR + i);
1432 i = DIR_ENTRIES_PER_SECTOR - 1;
1433 done = true;
1434 break;
1436 case 0xe5:
1437 entries_found++;
1438 LDEBUGF("Found free entry %d (%d/%d)\n",
1439 sector * DIR_ENTRIES_PER_SECTOR + i,
1440 entries_found, entries_needed);
1441 break;
1443 default:
1444 entries_found = 0;
1446 /* check that our intended shortname doesn't already exist */
1447 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1448 /* shortname exists already, make a new one */
1449 randomize_dos_name(shortname);
1450 LDEBUGF("Duplicate shortname, changing to %s\n",
1451 shortname);
1453 /* name has changed, we need to restart search */
1454 goto restart;
1456 break;
1458 if (firstentry < 0 && (entries_found >= entries_needed))
1459 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1460 - entries_found;
1464 /* step 2: extend the dir if necessary */
1465 if (firstentry < 0)
1467 LDEBUGF("Adding new sector(s) to dir\n");
1468 rc = fat_seek(&dir->file, sector);
1469 if (rc < 0)
1471 fat_release_sector_buffer();
1472 return rc * 10 - 4;
1474 memset(buf, 0, SECTOR_SIZE);
1476 /* we must clear whole clusters */
1477 for (; (entries_found < entries_needed) ||
1478 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1480 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1482 fat_release_sector_buffer();
1483 return -5; /* dir too large -- FAT specification */
1486 rc = fat_readwrite(&dir->file, 1, buf, true);
1487 if (rc < 1) /* No more room or something went wrong */
1489 fat_release_sector_buffer();
1490 return rc * 10 - 6;
1493 entries_found += DIR_ENTRIES_PER_SECTOR;
1496 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1498 fat_release_sector_buffer();
1500 /* step 3: add entry */
1501 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1502 LDEBUGF("Adding longname to entry %d in sector %d\n",
1503 firstentry, sector);
1505 rc = write_long_name(&dir->file, firstentry,
1506 entries_needed, name,
1507 shortname, is_directory);
1508 if (rc < 0)
1509 return rc * 10 - 7;
1511 /* remember where the shortname dir entry is located */
1512 file->direntry = firstentry + entries_needed - 1;
1513 file->direntries = entries_needed;
1514 file->dircluster = dir->file.firstcluster;
1515 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1516 file->direntry, file->direntries);
1518 return 0;
1521 static unsigned char char2dos(unsigned char c, int* randomize)
1523 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1525 if (c <= 0x20)
1526 c = 0; /* Illegal char, remove */
1527 else if (strchr(invalid_chars, c) != NULL)
1529 /* Illegal char, replace */
1530 c = '_';
1531 *randomize = 1; /* as per FAT spec */
1533 else
1534 c = toupper(c);
1536 return c;
1539 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1541 int i;
1542 unsigned char *ext;
1543 int randomize = 0;
1545 /* Find extension part */
1546 ext = strrchr(name, '.');
1547 if (ext == name) /* handle .dotnames */
1548 ext = NULL;
1550 /* needs to randomize? */
1551 if((ext && (strlen(ext) > 4)) ||
1552 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1553 randomize = 1;
1555 /* Name part */
1556 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1558 unsigned char c = char2dos(*name, &randomize);
1559 if (c)
1560 newname[i++] = c;
1563 /* Pad both name and extension */
1564 while (i < 11)
1565 newname[i++] = ' ';
1567 if (newname[0] == 0xe5) /* Special kanji character */
1568 newname[0] = 0x05;
1570 if (ext)
1571 { /* Extension part */
1572 ext++;
1573 for (i = 8; *ext && (i < 11); ext++)
1575 unsigned char c = char2dos(*ext, &randomize);
1576 if (c)
1577 newname[i++] = c;
1581 if(randomize)
1582 randomize_dos_name(newname);
1585 static void randomize_dos_name(unsigned char *name)
1587 unsigned char* tilde = NULL; /* ~ location */
1588 unsigned char* lastpt = NULL; /* last point of filename */
1589 unsigned char* nameptr = name; /* working copy of name pointer */
1590 unsigned char num[9]; /* holds number as string */
1591 int i = 0;
1592 int cnt = 1;
1593 int numlen;
1594 int offset;
1596 while(i++ < 8)
1598 /* hunt for ~ and where to put it */
1599 if((!tilde) && (*nameptr == '~'))
1600 tilde = nameptr;
1601 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1602 lastpt = nameptr;
1603 nameptr++;
1605 if(tilde)
1607 /* extract current count and increment */
1608 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1609 num[7-(unsigned int)(tilde-name)] = 0;
1610 cnt = atoi(num) + 1;
1612 cnt %= 10000000; /* protection */
1613 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1614 numlen = strlen(num); /* required space */
1615 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1616 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1618 memcpy(&name[offset], num, numlen);
1620 /* in special case of counter overflow: pad with spaces */
1621 for(offset = offset+numlen; offset < 8; offset++)
1622 name[offset] = ' ';
1625 static int update_short_entry( struct fat_file* file, long size, int attr )
1627 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1628 unsigned long* sizeptr;
1629 unsigned short* clusptr;
1630 struct fat_file dir;
1631 int rc;
1633 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1634 file->firstcluster, file->direntry, size);
1636 /* create a temporary file handle for the dir holding this file */
1637 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1638 if (rc < 0)
1639 return rc * 10 - 1;
1641 rc = fat_seek( &dir, sector );
1642 if (rc<0)
1643 return rc * 10 - 2;
1645 unsigned char* buf = fat_get_sector_buffer();
1646 unsigned char* entry =
1647 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1648 rc = fat_readwrite(&dir, 1, buf, false);
1649 if (rc < 1)
1651 fat_release_sector_buffer();
1652 return rc * 10 - 3;
1655 if (!entry[0] || entry[0] == 0xe5)
1657 fat_release_sector_buffer();
1658 panicf("Updating size on empty dir entry %d\n", file->direntry);
1661 entry[FATDIR_ATTR] = attr & 0xFF;
1663 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1664 *clusptr = htole16(file->firstcluster >> 16);
1666 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1667 *clusptr = htole16(file->firstcluster & 0xffff);
1669 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1670 *sizeptr = htole32(size);
1673 #if CONFIG_RTC
1674 unsigned short time = 0;
1675 unsigned short date = 0;
1676 #else
1677 /* get old time to increment from */
1678 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1679 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1680 #endif
1681 fat_time(&date, &time, NULL);
1682 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1683 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1684 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1687 rc = fat_seek( &dir, sector );
1688 if (rc < 0)
1690 fat_release_sector_buffer();
1691 return rc * 10 - 4;
1694 rc = fat_readwrite(&dir, 1, buf, true);
1695 fat_release_sector_buffer();
1696 if (rc < 1)
1697 return rc * 10 - 5;
1699 return 0;
1702 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1704 int i=0,j=0;
1705 unsigned char c;
1706 bool lowercase;
1708 memset(de, 0, sizeof(struct fat_direntry));
1709 de->attr = buf[FATDIR_ATTR];
1710 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1711 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1712 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1713 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1714 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1715 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1716 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1717 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1718 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1719 (the result of the shift is always considered signed) */
1721 /* fix the name */
1722 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1723 c = buf[FATDIR_NAME];
1724 if (c == 0x05) /* special kanji char */
1725 c = 0xe5;
1726 i = 0;
1727 while (c != ' ') {
1728 de->name[j++] = lowercase ? tolower(c) : c;
1729 if (++i >= 8)
1730 break;
1731 c = buf[FATDIR_NAME+i];
1733 if (buf[FATDIR_NAME+8] != ' ') {
1734 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1735 de->name[j++] = '.';
1736 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1737 de->name[j++] = lowercase ? tolower(c) : c;
1739 return 1;
1742 int fat_open(IF_MV2(int volume,)
1743 long startcluster,
1744 struct fat_file *file,
1745 const struct fat_dir* dir)
1747 /* Remember where the file's dir entry is located
1748 * Do it before assigning other fields so that fat_open
1749 * can be called with file == &dir->file (see fat_opendir) */
1750 if ( dir ) {
1751 file->direntry = dir->entry - 1;
1752 file->direntries = dir->entrycount;
1753 file->dircluster = dir->file.firstcluster;
1756 file->firstcluster = startcluster;
1757 file->lastcluster = startcluster;
1758 file->lastsector = 0;
1759 file->clusternum = 0;
1760 file->sectornum = 0;
1761 file->eof = false;
1762 #ifdef HAVE_MULTIVOLUME
1763 file->volume = volume;
1764 /* fixme: remove error check when done */
1765 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1767 LDEBUGF("fat_open() illegal volume %d\n", volume);
1768 return -1;
1770 #endif
1772 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1773 return 0;
1776 int fat_create_file(const char* name,
1777 struct fat_file* file,
1778 struct fat_dir* dir)
1780 int rc;
1782 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1783 rc = add_dir_entry(dir, file, name, false, false);
1784 if (!rc) {
1785 file->firstcluster = 0;
1786 file->lastcluster = 0;
1787 file->lastsector = 0;
1788 file->clusternum = 0;
1789 file->sectornum = 0;
1790 file->eof = false;
1793 return rc;
1796 /* noinline because this is only split out of fat_create_dir to make sure
1797 * the sector buffer doesn't remain on the stack, to avoid nasty stack
1798 * overflows later on (when flush_fat() is called) */
1799 static __attribute__((noinline)) int fat_clear_cluster(int sector,
1800 struct bpb *fat_bpb)
1802 unsigned char* buf = fat_get_sector_buffer();
1803 int i,rc;
1804 memset(buf, 0, SECTOR_SIZE);
1805 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1806 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1807 if (rc < 0)
1809 fat_release_sector_buffer();
1810 return rc * 10 - 2;
1813 fat_release_sector_buffer();
1814 return 0;
1817 int fat_create_dir(const char* name,
1818 struct fat_dir* newdir,
1819 struct fat_dir* dir)
1821 #ifdef HAVE_MULTIVOLUME
1822 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1823 #else
1824 struct bpb* fat_bpb = &fat_bpbs[0];
1825 #endif
1826 long sector;
1827 int rc;
1828 struct fat_file dummyfile;
1830 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1832 memset(newdir, 0, sizeof(struct fat_dir));
1833 memset(&dummyfile, 0, sizeof(struct fat_file));
1835 /* First, add the entry in the parent directory */
1836 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1837 if (rc < 0)
1838 return rc * 10 - 1;
1840 /* Allocate a new cluster for the directory */
1841 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1842 fat_bpb->fsinfo.nextfree);
1843 if(newdir->file.firstcluster == 0)
1844 return -1;
1846 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1848 /* Clear the entire cluster */
1849 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1850 rc = fat_clear_cluster(sector,fat_bpb);
1851 if (rc < 0)
1852 return rc;
1855 /* Then add the "." entry */
1856 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1857 if (rc < 0)
1858 return rc * 10 - 3;
1859 dummyfile.firstcluster = newdir->file.firstcluster;
1860 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1862 /* and the ".." entry */
1863 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1864 if (rc < 0)
1865 return rc * 10 - 4;
1867 /* The root cluster is cluster 0 in the ".." entry */
1868 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1869 dummyfile.firstcluster = 0;
1870 else
1871 dummyfile.firstcluster = dir->file.firstcluster;
1872 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1874 /* Set the firstcluster field in the direntry */
1875 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1877 rc = flush_fat(IF_MV(fat_bpb));
1878 if (rc < 0)
1879 return rc * 10 - 5;
1881 return rc;
1884 int fat_truncate(const struct fat_file *file)
1886 /* truncate trailing clusters */
1887 long next;
1888 long last = file->lastcluster;
1889 #ifdef HAVE_MULTIVOLUME
1890 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1891 #endif
1893 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1895 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1896 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1897 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1899 if (file->lastcluster)
1900 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1902 return 0;
1905 int fat_closewrite(struct fat_file *file, long size, int attr)
1907 int rc;
1908 #ifdef HAVE_MULTIVOLUME
1909 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1910 #endif
1911 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1913 if (!size) {
1914 /* empty file */
1915 if ( file->firstcluster ) {
1916 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1917 file->firstcluster = 0;
1921 if (file->dircluster) {
1922 rc = update_short_entry(file, size, attr);
1923 if (rc < 0)
1924 return rc * 10 - 1;
1927 flush_fat(IF_MV(fat_bpb));
1929 #ifdef TEST_FAT
1930 if ( file->firstcluster ) {
1931 /* debug */
1932 #ifdef HAVE_MULTIVOLUME
1933 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1934 #else
1935 struct bpb* fat_bpb = &fat_bpbs[0];
1936 #endif
1937 long count = 0;
1938 long len;
1939 long next;
1940 for ( next = file->firstcluster; next;
1941 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1942 LDEBUGF("cluster %ld: %lx\n", count, next);
1943 count++;
1945 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1946 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1947 count, len, size );
1948 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1949 panicf("Cluster chain is too long\n");
1950 if ( len < size )
1951 panicf("Cluster chain is too short\n");
1953 #endif
1955 return 0;
1958 static int free_direntries(struct fat_file* file)
1960 struct fat_file dir;
1961 int numentries = file->direntries;
1962 unsigned int entry = file->direntry - numentries + 1;
1963 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1964 int i;
1965 int rc;
1967 /* create a temporary file handle for the dir holding this file */
1968 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1969 if (rc < 0)
1970 return rc * 10 - 1;
1972 rc = fat_seek( &dir, sector );
1973 if (rc < 0)
1974 return rc * 10 - 2;
1976 unsigned char* buf = fat_get_sector_buffer();
1977 rc = fat_readwrite(&dir, 1, buf, false);
1978 if (rc < 1)
1980 fat_release_sector_buffer();
1981 return rc * 10 - 3;
1984 for (i=0; i < numentries; i++) {
1985 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1986 entry, i+1, numentries);
1987 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1988 entry++;
1990 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1991 /* flush this sector */
1992 rc = fat_seek(&dir, sector);
1993 if (rc < 0)
1995 fat_release_sector_buffer();
1996 return rc * 10 - 4;
1999 rc = fat_readwrite(&dir, 1, buf, true);
2000 if (rc < 1)
2002 fat_release_sector_buffer();
2003 return rc * 10 - 5;
2006 if ( i+1 < numentries ) {
2007 /* read next sector */
2008 rc = fat_readwrite(&dir, 1, buf, false);
2009 if (rc < 1)
2011 fat_release_sector_buffer();
2012 return rc * 10 - 6;
2015 sector++;
2019 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
2020 /* flush this sector */
2021 rc = fat_seek(&dir, sector);
2022 if (rc < 0)
2024 fat_release_sector_buffer();
2025 return rc * 10 - 7;
2028 rc = fat_readwrite(&dir, 1, buf, true);
2029 if (rc < 1)
2031 fat_release_sector_buffer();
2032 return rc * 10 - 8;
2035 fat_release_sector_buffer();
2037 return 0;
2040 int fat_remove(struct fat_file* file)
2042 long next, last = file->firstcluster;
2043 int rc;
2044 #ifdef HAVE_MULTIVOLUME
2045 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2046 #endif
2048 LDEBUGF("fat_remove(%lx)\n",last);
2050 while ( last ) {
2051 next = get_next_cluster(IF_MV2(fat_bpb,) last);
2052 update_fat_entry(IF_MV2(fat_bpb,) last,0);
2053 last = next;
2056 if ( file->dircluster ) {
2057 rc = free_direntries(file);
2058 if (rc < 0)
2059 return rc * 10 - 1;
2062 file->firstcluster = 0;
2063 file->dircluster = 0;
2065 rc = flush_fat(IF_MV(fat_bpb));
2066 if (rc < 0)
2067 return rc * 10 - 2;
2069 return 0;
2072 int fat_rename(struct fat_file* file,
2073 struct fat_dir* dir,
2074 const unsigned char* newname,
2075 long size,
2076 int attr)
2078 int rc;
2079 struct fat_file olddir_file;
2080 struct fat_file newfile = *file;
2081 unsigned char* entry = NULL;
2082 unsigned short* clusptr = NULL;
2083 unsigned int parentcluster;
2084 #ifdef HAVE_MULTIVOLUME
2085 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2087 if (file->volume != dir->file.volume) {
2088 DEBUGF("No rename across volumes!\n");
2089 return -1;
2091 #else
2092 struct bpb* fat_bpb = &fat_bpbs[0];
2093 #endif
2095 if ( !file->dircluster ) {
2096 DEBUGF("File has no dir cluster!\n");
2097 return -2;
2100 /* create new name */
2101 rc = add_dir_entry(dir, &newfile, newname, false, false);
2102 if (rc < 0)
2103 return rc * 10 - 2;
2105 /* write size and cluster link */
2106 rc = update_short_entry(&newfile, size, attr);
2107 if (rc < 0)
2108 return rc * 10 - 3;
2110 /* remove old name */
2111 rc = free_direntries(file);
2112 if (rc < 0)
2113 return rc * 10 - 4;
2115 rc = flush_fat(IF_MV(fat_bpb));
2116 if (rc < 0)
2117 return rc * 10 - 5;
2119 /* if renaming a directory, update the .. entry to make sure
2120 it points to its parent directory (we don't check if it was a move) */
2121 if(FAT_ATTR_DIRECTORY == attr) {
2122 /* open the dir that was renamed, we re-use the olddir_file struct */
2123 rc = fat_open(IF_MV2(file->volume,) newfile.firstcluster, &olddir_file, NULL);
2124 if (rc < 0)
2125 return rc * 10 - 6;
2127 /* get the first sector of the dir */
2128 rc = fat_seek(&olddir_file, 0);
2129 if (rc < 0)
2130 return rc * 10 - 7;
2132 unsigned char* buf = fat_get_sector_buffer();
2133 rc = fat_readwrite(&olddir_file, 1, buf, false);
2134 if (rc < 0)
2136 fat_release_sector_buffer();
2137 return rc * 10 - 8;
2140 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2141 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2142 parentcluster = 0;
2143 else
2144 parentcluster = dir->file.firstcluster;
2146 entry = buf + DIR_ENTRY_SIZE;
2147 if(strncmp(".. ", entry, 11))
2149 fat_release_sector_buffer();
2150 /* .. entry must be second entry according to FAT spec (p.29) */
2151 DEBUGF("Second dir entry is not double-dot!\n");
2152 return rc * 10 - 9;
2154 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2155 *clusptr = htole16(parentcluster >> 16);
2157 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
2158 *clusptr = htole16(parentcluster & 0xffff);
2160 /* write back this sector */
2161 rc = fat_seek(&olddir_file, 0);
2162 if (rc < 0)
2164 fat_release_sector_buffer();
2165 return rc * 10 - 7;
2168 rc = fat_readwrite(&olddir_file, 1, buf, true);
2169 fat_release_sector_buffer();
2170 if (rc < 1)
2171 return rc * 10 - 8;
2174 return 0;
2177 static long next_write_cluster(struct fat_file* file,
2178 long oldcluster,
2179 long* newsector)
2181 #ifdef HAVE_MULTIVOLUME
2182 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2183 #else
2184 struct bpb* fat_bpb = &fat_bpbs[0];
2185 #endif
2186 long cluster = 0;
2187 long sector;
2189 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2191 if (oldcluster)
2192 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2194 if (!cluster) {
2195 if (oldcluster > 0)
2196 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2197 else if (oldcluster == 0)
2198 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2199 fat_bpb->fsinfo.nextfree);
2200 #ifdef HAVE_FAT16SUPPORT
2201 else /* negative, pseudo-cluster of the root dir */
2202 return 0; /* impossible to append something to the root */
2203 #endif
2205 if (cluster) {
2206 if (oldcluster)
2207 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2208 else
2209 file->firstcluster = cluster;
2210 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2212 else {
2213 #ifdef TEST_FAT
2214 if (fat_bpb->fsinfo.freecount>0)
2215 panicf("There is free space, but find_free_cluster() "
2216 "didn't find it!\n");
2217 #endif
2218 DEBUGF("next_write_cluster(): Disk full!\n");
2219 return 0;
2222 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2223 if (sector<0)
2224 return 0;
2226 *newsector = sector;
2227 return cluster;
2230 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2231 unsigned long start, long count, char* buf, bool write )
2233 #ifndef HAVE_MULTIVOLUME
2234 struct bpb* fat_bpb = &fat_bpbs[0];
2235 #endif
2236 int rc;
2238 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2239 start+ fat_bpb->startsector, count, write?"write":"read");
2240 if (write) {
2241 unsigned long firstallowed;
2242 #ifdef HAVE_FAT16SUPPORT
2243 if (fat_bpb->is_fat16)
2244 firstallowed = fat_bpb->rootdirsector;
2245 else
2246 #endif
2247 firstallowed = fat_bpb->firstdatasector;
2249 if (start < firstallowed)
2250 panicf("Write %ld before data\n", firstallowed - start);
2251 if (start + count > fat_bpb->totalsectors)
2252 panicf("Write %ld after data\n",
2253 start + count - fat_bpb->totalsectors);
2254 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2255 start + fat_bpb->startsector, count, buf);
2257 else
2258 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2259 start + fat_bpb->startsector, count, buf);
2260 if (rc < 0) {
2261 DEBUGF( "transfer() - Couldn't %s sector %lx"
2262 " (error code %d)\n",
2263 write ? "write":"read", start, rc);
2264 return rc;
2266 return 0;
2270 long fat_readwrite( struct fat_file *file, long sectorcount,
2271 void* buf, bool write )
2273 #ifdef HAVE_MULTIVOLUME
2274 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2275 #else
2276 struct bpb* fat_bpb = &fat_bpbs[0];
2277 #endif
2278 long cluster = file->lastcluster;
2279 long sector = file->lastsector;
2280 long clusternum = file->clusternum;
2281 long numsec = file->sectornum;
2282 bool eof = file->eof;
2283 long first=0, last=0;
2284 long i;
2285 int rc;
2287 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2288 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2289 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2290 sector,numsec, eof?1:0);
2292 if ( eof && !write)
2293 return 0;
2295 /* find sequential sectors and write them all at once */
2296 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2297 numsec++;
2298 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2299 long oldcluster = cluster;
2300 long oldsector = sector;
2301 long oldnumsec = numsec;
2302 if (write)
2303 cluster = next_write_cluster(file, cluster, &sector);
2304 else {
2305 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2306 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2309 clusternum++;
2310 numsec=1;
2312 if (!cluster) {
2313 eof = true;
2314 if ( write ) {
2315 /* remember last cluster, in case
2316 we want to append to the file */
2317 sector = oldsector;
2318 cluster = oldcluster;
2319 numsec = oldnumsec;
2320 clusternum--;
2321 i = -1; /* Error code */
2322 break;
2325 else
2326 eof = false;
2328 else {
2329 if (sector)
2330 sector++;
2331 else {
2332 /* look up first sector of file */
2333 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2334 numsec=1;
2335 #ifdef HAVE_FAT16SUPPORT
2336 if (file->firstcluster < 0)
2337 { /* FAT16 root dir */
2338 sector += fat_bpb->rootdiroffset;
2339 numsec += fat_bpb->rootdiroffset;
2341 #endif
2345 if (!first)
2346 first = sector;
2348 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2349 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2350 long count = last - first + 1;
2351 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2352 if (rc < 0)
2353 return rc * 10 - 1;
2355 buf = (char *)buf + count * SECTOR_SIZE;
2356 first = sector;
2359 if ((i == sectorcount-1) && /* last sector requested */
2360 (!eof))
2362 long count = sector - first + 1;
2363 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2364 if (rc < 0)
2365 return rc * 10 - 2;
2368 last = sector;
2371 file->lastcluster = cluster;
2372 file->lastsector = sector;
2373 file->clusternum = clusternum;
2374 file->sectornum = numsec;
2375 file->eof = eof;
2377 /* if eof, don't report last block as read/written */
2378 if (eof)
2379 i--;
2381 DEBUGF("Sectors written: %ld\n", i);
2382 return i;
2385 int fat_seek(struct fat_file *file, unsigned long seeksector )
2387 #ifdef HAVE_MULTIVOLUME
2388 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2389 #else
2390 struct bpb* fat_bpb = &fat_bpbs[0];
2391 #endif
2392 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2393 long cluster = file->firstcluster;
2394 long i;
2396 #ifdef HAVE_FAT16SUPPORT
2397 if (cluster < 0) /* FAT16 root dir */
2398 seeksector += fat_bpb->rootdiroffset;
2399 #endif
2401 file->eof = false;
2402 if (seeksector) {
2403 /* we need to find the sector BEFORE the requested, since
2404 the file struct stores the last accessed sector */
2405 seeksector--;
2406 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2407 sectornum = seeksector % fat_bpb->bpb_secperclus;
2409 if (file->clusternum && clusternum >= file->clusternum)
2411 cluster = file->lastcluster;
2412 numclusters -= file->clusternum;
2415 for (i=0; i<numclusters; i++) {
2416 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2417 if (!cluster) {
2418 DEBUGF("Seeking beyond the end of the file! "
2419 "(sector %ld, cluster %ld)\n", seeksector, i);
2420 return -1;
2424 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2426 else {
2427 sectornum = -1;
2430 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2431 file->firstcluster, seeksector, cluster, sector, sectornum);
2433 file->lastcluster = cluster;
2434 file->lastsector = sector;
2435 file->clusternum = clusternum;
2436 file->sectornum = sectornum + 1;
2437 return 0;
2440 int fat_opendir(IF_MV2(int volume,)
2441 struct fat_dir *dir, unsigned long startcluster,
2442 const struct fat_dir *parent_dir)
2444 #ifdef HAVE_MULTIVOLUME
2445 struct bpb* fat_bpb = &fat_bpbs[volume];
2446 /* fixme: remove error check when done */
2447 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2449 LDEBUGF("fat_open() illegal volume %d\n", volume);
2450 return -1;
2452 #else
2453 struct bpb* fat_bpb = &fat_bpbs[0];
2454 #endif
2455 int rc;
2457 if (startcluster == 0)
2458 startcluster = fat_bpb->bpb_rootclus;
2460 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2461 if(rc)
2463 DEBUGF( "fat_opendir() - Couldn't open dir"
2464 " (error code %d)\n", rc);
2465 return rc * 10 - 1;
2468 /* assign them after fat_open call so that fat_opendir can be called with the same
2469 * fat_dir as parent and result */
2470 dir->entry = 0;
2471 dir->sector = 0;
2473 return 0;
2476 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2478 bool done = false;
2479 int i, j;
2480 int rc;
2481 int order;
2482 unsigned char firstbyte;
2483 /* Long file names are stored in special entries. Each entry holds
2484 up to 13 characters. Names can be max 255 chars (not bytes!) long */
2485 /* The number of long entries in the long name can be retrieve from the first
2486 * long entry because there are stored in reverse order and have an ordinal */
2487 int nb_longs = 0;
2488 /* The long entries are expected to be in order, so remember the last ordinal */
2489 int last_long_ord = 0;
2491 dir->entrycount = 0;
2493 while(!done)
2495 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2497 rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2498 if (rc == 0) {
2499 /* eof */
2500 entry->name[0] = 0;
2501 break;
2503 if (rc < 0) {
2504 DEBUGF( "fat_getnext() - Couldn't read dir"
2505 " (error code %d)\n", rc);
2506 return rc * 10 - 1;
2508 dir->sector = dir->file.lastsector;
2511 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2512 i < DIR_ENTRIES_PER_SECTOR; i++) {
2513 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2515 firstbyte = dir->sectorcache[entrypos];
2516 dir->entry++;
2518 if (firstbyte == 0xe5) {
2519 /* free entry */
2520 dir->entrycount = 0;
2521 continue;
2524 if (firstbyte == 0) {
2525 /* last entry */
2526 entry->name[0] = 0;
2527 dir->entrycount = 0;
2528 return 0;
2531 dir->entrycount++;
2533 /* LFN entry? */
2534 if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2535 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2536 /* extract ordinal */
2537 order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2538 /* is this entry the first long entry ? (first in order but containing last part) */
2539 if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2540 /* check that order is not too big ! (and non-zero) */
2541 if(order <= 0 || order > FATLONG_MAX_ORDER)
2542 continue; /* ignore the whole LFN, will trigger lots of warnings */
2543 nb_longs = order;
2544 last_long_ord = order;
2546 else {
2547 /* check orphan entry */
2548 if (nb_longs == 0) {
2549 logf("fat warning: orphan LFN entry");
2550 /* ignore */
2551 continue;
2554 /* check order */
2555 if (order != (last_long_ord - 1)) {
2556 logf("fat warning: wrong LFN ordinal");
2557 /* ignore the whole LFN, will trigger lots of warnings */
2558 nb_longs = 0;
2561 last_long_ord = order;
2564 /* copy part, reuse [order] for another purpose :) */
2565 order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2566 for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2567 memcpy(dir->longname + order,
2568 dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2569 FATLONG_NAME_SIZE[j]);
2570 order += FATLONG_NAME_SIZE[j];
2573 else {
2574 if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2576 /* don't return volume id entry */
2577 if ( (entry->attr &
2578 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2579 == FAT_ATTR_VOLUME_ID)
2580 continue;
2582 /* replace shortname with longname? */
2583 /* check that the long name is complete */
2584 if (nb_longs != 0 && last_long_ord == 1) {
2585 /* hold a copy of the shortname in case the long one is too long */
2586 unsigned char shortname[13]; /* 8+3+dot+\0 */
2587 int longname_utf8len = 0;
2588 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2589 * of a UTF8 encoded character in rockbox */
2590 unsigned char longname_utf8segm[4 + 1];
2591 unsigned short ucs;
2592 int segm_utf8len;
2593 /* Temporarily store short name */
2594 strcpy(shortname, entry->name);
2595 entry->name[0] = 0;
2597 /* Convert the FAT name to a utf8-encoded one.
2598 * The name is not necessary NUL-terminated ! */
2599 for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2600 ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2601 if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2602 break;
2603 /* utf8encode will return a pointer after the converted
2604 * string, subtract the pointer to the start to get the length of it */
2605 segm_utf8len = utf8encode(ucs, longname_utf8segm) - longname_utf8segm;
2607 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2608 if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2609 /* force use of short name */
2610 longname_utf8len = FAT_FILENAME_BYTES + 1;
2611 break; /* fallback later */
2613 else {
2614 longname_utf8segm[segm_utf8len] = 0;
2615 strcat(entry->name + longname_utf8len, longname_utf8segm);
2616 longname_utf8len += segm_utf8len;
2620 /* Does the utf8-encoded name fit into the entry? */
2621 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2622 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2623 /* Take the short DOS name. Need to utf8-encode it
2624 since it may contain chars from the upper half of
2625 the OEM code page which wouldn't be a valid utf8.
2626 Beware: this file will be shown with strange
2627 glyphs in file browser since unicode 0x80 to 0x9F
2628 are control characters. */
2629 logf("SN-DOS: %s", shortname);
2630 unsigned char *utf8;
2631 utf8 = iso_decode(shortname, entry->name, -1,
2632 strlen(shortname));
2633 *utf8 = 0;
2634 logf("SN: %s", entry->name);
2635 } else {
2636 logf("LN: %s", entry->name);
2637 logf("LNLen: %d", longname_utf8len);
2640 done = true;
2641 i++;
2642 break;
2647 return 0;
2650 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2652 #ifndef HAVE_MULTIVOLUME
2653 const int volume = 0;
2654 #endif
2655 struct bpb* fat_bpb = &fat_bpbs[volume];
2656 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2659 #ifdef HAVE_MULTIVOLUME
2660 bool fat_ismounted(int volume)
2662 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2664 #endif