Redo raising the priority of the codec (and voice) thread to fix audio dropouts under...
[kugel-rb.git] / firmware / drivers / fat.c
bloba99341d58fe62d71c8859697321b8eb36ddc8473
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];
215 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
216 static struct mutex cache_mutex SHAREDBSS_ATTR;
218 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
219 void fat_lock(void)
221 mutex_lock(&cache_mutex);
224 void fat_unlock(void)
226 mutex_unlock(&cache_mutex);
228 #endif
230 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
232 #ifndef HAVE_MULTIVOLUME
233 struct bpb* fat_bpb = &fat_bpbs[0];
234 #endif
235 #ifdef HAVE_FAT16SUPPORT
236 /* negative clusters (FAT16 root dir) don't get the 2 offset */
237 int zerocluster = cluster < 0 ? 0 : 2;
238 #else
239 const long zerocluster = 2;
240 #endif
242 if (cluster > (long)(fat_bpb->dataclusters + 1))
244 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
245 return -1;
248 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
249 + fat_bpb->firstdatasector;
252 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
254 #ifndef HAVE_MULTIVOLUME
255 const int volume = 0;
256 #endif
257 struct bpb* fat_bpb = &fat_bpbs[volume];
258 if (size)
259 *size = fat_bpb->dataclusters * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
260 if (free)
261 *free = fat_bpb->fsinfo.freecount * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
264 void fat_init(void)
266 unsigned int i;
268 if (!initialized)
270 initialized = true;
271 mutex_init(&cache_mutex);
274 #ifdef HAVE_PRIORITY_SCHEDULING
275 /* Disable this because it is dangerous due to the assumption that
276 * mutex_unlock won't yield */
277 mutex_set_preempt(&cache_mutex, false);
278 #endif
280 /* mark the FAT cache as unused */
281 for(i = 0;i < FAT_CACHE_SIZE;i++)
283 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
284 fat_cache[i].inuse = false;
285 fat_cache[i].dirty = false;
286 #ifdef HAVE_MULTIVOLUME
287 fat_cache[i].fat_vol = NULL;
288 #endif
290 #ifdef HAVE_MULTIVOLUME
291 /* mark the possible volumes as not mounted */
292 for (i=0; i<NUM_VOLUMES;i++)
294 fat_bpbs[i].mounted = false;
296 #endif
299 /* fat_mount_internal is split out of fat_mount() to avoid having both the sector
300 * buffer used here and the sector buffer used by update_fsinfo() on stack */
301 static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
303 #ifndef HAVE_MULTIVOLUME
304 const int volume = 0;
305 #endif
306 struct bpb* fat_bpb = &fat_bpbs[volume];
307 unsigned char buf[SECTOR_SIZE];
308 int rc;
309 int secmult;
310 long datasec;
311 #ifdef HAVE_FAT16SUPPORT
312 int rootdirsectors;
313 #endif
315 /* Read the sector */
316 rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
317 if(rc)
319 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
320 return rc * 10 - 1;
323 memset(fat_bpb, 0, sizeof(struct bpb));
324 fat_bpb->startsector = startsector;
325 #ifdef HAVE_MULTIDRIVE
326 fat_bpb->drive = drive;
327 #endif
329 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
330 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
331 /* Sanity check is performed later */
333 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
334 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
335 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
336 fat_bpb->bpb_media = buf[BPB_MEDIA];
337 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
338 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
339 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
340 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
341 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
343 /* calculate a few commonly used values */
344 if (fat_bpb->bpb_fatsz16 != 0)
345 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
346 else
347 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
349 if (fat_bpb->bpb_totsec16 != 0)
350 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
351 else
352 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
354 #ifdef HAVE_FAT16SUPPORT
355 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
356 if (!fat_bpb->bpb_bytspersec)
357 return -2;
358 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
359 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
360 #endif /* #ifdef HAVE_FAT16SUPPORT */
362 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
363 #ifdef HAVE_FAT16SUPPORT
364 + rootdirsectors
365 #endif
366 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
368 /* Determine FAT type */
369 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
370 if (fat_bpb->bpb_secperclus)
371 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
372 else
373 return -2;
375 #ifdef TEST_FAT
377 we are sometimes testing with "illegally small" fat32 images,
378 so we don't use the proper fat32 test case for test code
380 if ( fat_bpb->bpb_fatsz16 )
381 #else
382 if ( fat_bpb->dataclusters < 65525 )
383 #endif
384 { /* FAT16 */
385 #ifdef HAVE_FAT16SUPPORT
386 fat_bpb->is_fat16 = true;
387 if (fat_bpb->dataclusters < 4085)
388 { /* FAT12 */
389 DEBUGF("This is FAT12. Go away!\n");
390 return -2;
392 #else /* #ifdef HAVE_FAT16SUPPORT */
393 DEBUGF("This is not FAT32. Go away!\n");
394 return -2;
395 #endif /* #ifndef HAVE_FAT16SUPPORT */
398 #ifdef HAVE_FAT16SUPPORT
399 if (fat_bpb->is_fat16)
400 { /* FAT16 specific part of BPB */
401 int dirclusters;
402 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
403 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
404 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
405 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
406 /* I assign negative pseudo cluster numbers for the root directory,
407 their range is counted upward until -1. */
408 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
409 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
410 - rootdirsectors;
412 else
413 #endif /* #ifdef HAVE_FAT16SUPPORT */
414 { /* FAT32 specific part of BPB */
415 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
416 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
417 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
418 fat_bpb->bpb_rootclus);
421 rc = bpb_is_sane(IF_MV(fat_bpb));
422 if (rc < 0)
424 DEBUGF( "fat_mount() - BPB is not sane\n");
425 return rc * 10 - 3;
428 #ifdef HAVE_FAT16SUPPORT
429 if (fat_bpb->is_fat16)
431 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
432 fat_bpb->fsinfo.nextfree = 0xffffffff;
434 else
435 #endif /* #ifdef HAVE_FAT16SUPPORT */
437 /* Read the fsinfo sector */
438 rc = storage_read_sectors(IF_MD2(drive,)
439 startsector + fat_bpb->bpb_fsinfo, 1, buf);
440 if (rc < 0)
442 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
443 return rc * 10 - 4;
445 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
446 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
448 return 0;
451 int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
453 #ifndef HAVE_MULTIVOLUME
454 const int volume = 0;
455 #endif
456 struct bpb* fat_bpb = &fat_bpbs[volume];
457 int rc;
459 rc = fat_mount_internal(IF_MV2(volume,) IF_MD2(drive,) startsector);
461 if(rc!=0) return rc;
463 /* calculate freecount if unset */
464 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
466 fat_recalc_free(IF_MV(volume));
469 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
470 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
471 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
472 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
473 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
475 #ifdef HAVE_MULTIVOLUME
476 fat_bpb->mounted = true;
477 #endif
479 return 0;
482 int fat_unmount(int volume, bool flush)
484 int rc;
485 #ifdef HAVE_MULTIVOLUME
486 struct bpb* fat_bpb = &fat_bpbs[volume];
487 #else
488 (void)volume;
489 #endif
491 if(flush)
493 rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
495 else
496 { /* volume is not accessible any more, e.g. MMC removed */
497 int i;
498 mutex_lock(&cache_mutex);
499 for(i = 0;i < FAT_CACHE_SIZE;i++)
501 struct fat_cache_entry *fce = &fat_cache[i];
502 if(fce->inuse
503 #ifdef HAVE_MULTIVOLUME
504 && fce->fat_vol == fat_bpb
505 #endif
508 fce->inuse = false; /* discard all from that volume */
509 fce->dirty = false;
512 mutex_unlock(&cache_mutex);
513 rc = 0;
515 #ifdef HAVE_MULTIVOLUME
516 fat_bpb->mounted = false;
517 #endif
518 return rc;
521 void fat_recalc_free(IF_MV_NONVOID(int volume))
523 #ifndef HAVE_MULTIVOLUME
524 const int volume = 0;
525 #endif
526 struct bpb* fat_bpb = &fat_bpbs[volume];
527 long free = 0;
528 unsigned long i;
529 #ifdef HAVE_FAT16SUPPORT
530 if (fat_bpb->is_fat16)
532 for (i = 0; i<fat_bpb->fatsize; i++) {
533 unsigned int j;
534 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
535 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
536 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
537 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
538 break;
540 if (letoh16(fat[j]) == 0x0000) {
541 free++;
542 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
543 fat_bpb->fsinfo.nextfree = c;
548 else
549 #endif /* #ifdef HAVE_FAT16SUPPORT */
551 for (i = 0; i<fat_bpb->fatsize; i++) {
552 unsigned int j;
553 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
554 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
555 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
556 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
557 break;
559 if (!(letoh32(fat[j]) & 0x0fffffff)) {
560 free++;
561 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
562 fat_bpb->fsinfo.nextfree = c;
567 fat_bpb->fsinfo.freecount = free;
568 update_fsinfo(IF_MV(fat_bpb));
571 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
573 #ifndef HAVE_MULTIVOLUME
574 struct bpb* fat_bpb = &fat_bpbs[0];
575 #endif
576 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
578 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
579 fat_bpb->bpb_bytspersec);
580 return -1;
582 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
583 > 128L*1024L)
585 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
586 "(%d * %d = %d)\n",
587 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
588 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
589 return -2;
591 if(fat_bpb->bpb_numfats != 2)
593 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
594 fat_bpb->bpb_numfats);
596 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
598 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
599 "media type (0x%02x)\n",
600 fat_bpb->bpb_media);
602 if(fat_bpb->last_word != 0xaa55)
604 DEBUGF( "bpb_is_sane() - Error: Last word is not "
605 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
606 return -3;
609 if (fat_bpb->fsinfo.freecount >
610 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
611 fat_bpb->bpb_secperclus)
613 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
614 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
615 return -4;
618 return 0;
621 static void flush_fat_sector(struct fat_cache_entry *fce,
622 unsigned char *sectorbuf)
624 int rc;
625 long secnum;
627 /* With multivolume, use only the FAT info from the cached sector! */
628 #ifdef HAVE_MULTIVOLUME
629 secnum = fce->secnum + fce->fat_vol->startsector;
630 #else
631 secnum = fce->secnum + fat_bpbs[0].startsector;
632 #endif
634 /* Write to the first FAT */
635 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
636 secnum, 1,
637 sectorbuf);
638 if(rc < 0)
640 panicf("flush_fat_sector() - Could not write sector %ld"
641 " (error %d)\n",
642 secnum, rc);
644 #ifdef HAVE_MULTIVOLUME
645 if(fce->fat_vol->bpb_numfats > 1)
646 #else
647 if(fat_bpbs[0].bpb_numfats > 1)
648 #endif
650 /* Write to the second FAT */
651 #ifdef HAVE_MULTIVOLUME
652 secnum += fce->fat_vol->fatsize;
653 #else
654 secnum += fat_bpbs[0].fatsize;
655 #endif
656 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
657 secnum, 1, sectorbuf);
658 if(rc < 0)
660 panicf("flush_fat_sector() - Could not write sector %ld"
661 " (error %d)\n",
662 secnum, rc);
665 fce->dirty = false;
668 /* Note: The returned pointer is only safely valid until the next
669 task switch! (Any subsequent ata read/write may yield.) */
670 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
671 long fatsector, bool dirty)
673 #ifndef HAVE_MULTIVOLUME
674 struct bpb* fat_bpb = &fat_bpbs[0];
675 #endif
676 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
677 int cache_index = secnum & FAT_CACHE_MASK;
678 struct fat_cache_entry *fce = &fat_cache[cache_index];
679 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
680 int rc;
682 mutex_lock(&cache_mutex); /* make changes atomic */
684 /* Delete the cache entry if it isn't the sector we want */
685 if(fce->inuse && (fce->secnum != secnum
686 #ifdef HAVE_MULTIVOLUME
687 || fce->fat_vol != fat_bpb
688 #endif
691 /* Write back if it is dirty */
692 if(fce->dirty)
694 flush_fat_sector(fce, sectorbuf);
696 fce->inuse = false;
699 /* Load the sector if it is not cached */
700 if(!fce->inuse)
702 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
703 secnum + fat_bpb->startsector,1,
704 sectorbuf);
705 if(rc < 0)
707 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
708 " (error %d)\n", secnum, rc);
709 mutex_unlock(&cache_mutex);
710 return NULL;
712 fce->inuse = true;
713 fce->secnum = secnum;
714 #ifdef HAVE_MULTIVOLUME
715 fce->fat_vol = fat_bpb;
716 #endif
718 if (dirty)
719 fce->dirty = true; /* dirt remains, sticky until flushed */
720 mutex_unlock(&cache_mutex);
721 return sectorbuf;
724 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
725 unsigned long startcluster)
727 #ifndef HAVE_MULTIVOLUME
728 struct bpb* fat_bpb = &fat_bpbs[0];
729 #endif
730 unsigned long sector;
731 unsigned long offset;
732 unsigned long i;
734 #ifdef HAVE_FAT16SUPPORT
735 if (fat_bpb->is_fat16)
737 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
738 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
740 for (i = 0; i<fat_bpb->fatsize; i++) {
741 unsigned int j;
742 unsigned int nr = (i + sector) % fat_bpb->fatsize;
743 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
744 if ( !fat )
745 break;
746 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
747 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
748 if (letoh16(fat[k]) == 0x0000) {
749 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
750 /* Ignore the reserved clusters 0 & 1, and also
751 cluster numbers out of bounds */
752 if ( c < 2 || c > fat_bpb->dataclusters+1 )
753 continue;
754 LDEBUGF("find_free_cluster(%lx) == %x\n",startcluster,c);
755 fat_bpb->fsinfo.nextfree = c;
756 return c;
759 offset = 0;
762 else
763 #endif /* #ifdef HAVE_FAT16SUPPORT */
765 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
766 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
768 for (i = 0; i<fat_bpb->fatsize; i++) {
769 unsigned int j;
770 unsigned long nr = (i + sector) % fat_bpb->fatsize;
771 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
772 if ( !fat )
773 break;
774 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
775 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
776 if (!(letoh32(fat[k]) & 0x0fffffff)) {
777 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
778 /* Ignore the reserved clusters 0 & 1, and also
779 cluster numbers out of bounds */
780 if ( c < 2 || c > fat_bpb->dataclusters+1 )
781 continue;
782 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
783 fat_bpb->fsinfo.nextfree = c;
784 return c;
787 offset = 0;
791 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
792 return 0; /* 0 is an illegal cluster number */
795 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
796 unsigned long val)
798 #ifndef HAVE_MULTIVOLUME
799 struct bpb* fat_bpb = &fat_bpbs[0];
800 #endif
801 #ifdef HAVE_FAT16SUPPORT
802 if (fat_bpb->is_fat16)
804 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
805 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
806 unsigned short* sec;
808 val &= 0xFFFF;
810 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
812 if (entry==val)
813 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
815 if ( entry < 2 )
816 panicf("Updating reserved FAT entry %ld.\n",entry);
818 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
819 if (!sec)
821 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
822 return -1;
825 if ( val ) {
826 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
827 fat_bpb->fsinfo.freecount--;
829 else {
830 if (letoh16(sec[offset]))
831 fat_bpb->fsinfo.freecount++;
834 LDEBUGF("update_fat_entry: %lu free clusters\n",
835 fat_bpb->fsinfo.freecount);
837 sec[offset] = htole16(val);
839 else
840 #endif /* #ifdef HAVE_FAT16SUPPORT */
842 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
843 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
844 unsigned long* sec;
846 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
848 if (entry==val)
849 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
851 if ( entry < 2 )
852 panicf("Updating reserved FAT entry %ld.\n",entry);
854 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
855 if (!sec)
857 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
858 return -1;
861 if ( val ) {
862 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
863 fat_bpb->fsinfo.freecount > 0)
864 fat_bpb->fsinfo.freecount--;
866 else {
867 if (letoh32(sec[offset]) & 0x0fffffff)
868 fat_bpb->fsinfo.freecount++;
871 LDEBUGF("update_fat_entry: %ld free clusters\n",
872 fat_bpb->fsinfo.freecount);
874 /* don't change top 4 bits */
875 sec[offset] &= htole32(0xf0000000);
876 sec[offset] |= htole32(val & 0x0fffffff);
879 return 0;
882 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
884 #ifdef HAVE_FAT16SUPPORT
885 #ifndef HAVE_MULTIVOLUME
886 struct bpb* fat_bpb = &fat_bpbs[0];
887 #endif
888 if (fat_bpb->is_fat16)
890 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
891 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
892 unsigned short* sec;
894 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
895 if (!sec)
897 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
898 return -1;
901 return letoh16(sec[offset]);
903 else
904 #endif /* #ifdef HAVE_FAT16SUPPORT */
906 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
907 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
908 unsigned long* sec;
910 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
911 if (!sec)
913 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
914 return -1;
917 return letoh32(sec[offset]) & 0x0fffffff;
921 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
923 long next_cluster;
924 long eof_mark = FAT_EOF_MARK;
926 #ifdef HAVE_FAT16SUPPORT
927 #ifndef HAVE_MULTIVOLUME
928 struct bpb* fat_bpb = &fat_bpbs[0];
929 #endif
930 if (fat_bpb->is_fat16)
932 eof_mark &= 0xFFFF; /* only 16 bit */
933 if (cluster < 0) /* FAT16 root dir */
934 return cluster + 1; /* don't use the FAT */
936 #endif
937 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
939 /* is this last cluster in chain? */
940 if ( next_cluster >= eof_mark )
941 return 0;
942 else
943 return next_cluster;
946 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
948 #ifndef HAVE_MULTIVOLUME
949 struct bpb* fat_bpb = &fat_bpbs[0];
950 #endif
951 unsigned char fsinfo[SECTOR_SIZE];
952 unsigned long* intptr;
953 int rc;
955 #ifdef HAVE_FAT16SUPPORT
956 if (fat_bpb->is_fat16)
957 return 0; /* FAT16 has no FsInfo */
958 #endif /* #ifdef HAVE_FAT16SUPPORT */
960 /* update fsinfo */
961 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
962 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
963 if (rc < 0)
965 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
966 return rc * 10 - 1;
968 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
969 *intptr = htole32(fat_bpb->fsinfo.freecount);
971 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
972 *intptr = htole32(fat_bpb->fsinfo.nextfree);
974 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
975 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
976 if (rc < 0)
978 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
979 return rc * 10 - 2;
982 return 0;
985 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
987 int i;
988 int rc;
989 unsigned char *sec;
990 LDEBUGF("flush_fat()\n");
992 mutex_lock(&cache_mutex);
993 for(i = 0;i < FAT_CACHE_SIZE;i++)
995 struct fat_cache_entry *fce = &fat_cache[i];
996 if(fce->inuse
997 #ifdef HAVE_MULTIVOLUME
998 && fce->fat_vol == fat_bpb
999 #endif
1000 && fce->dirty)
1002 sec = fat_cache_sectors[i];
1003 flush_fat_sector(fce, sec);
1006 mutex_unlock(&cache_mutex);
1008 rc = update_fsinfo(IF_MV(fat_bpb));
1009 if (rc < 0)
1010 return rc * 10 - 3;
1012 return 0;
1015 static void fat_time(unsigned short* date,
1016 unsigned short* time,
1017 unsigned short* tenth )
1019 #if CONFIG_RTC
1020 struct tm* tm = get_time();
1022 if (date)
1023 *date = ((tm->tm_year - 80) << 9) |
1024 ((tm->tm_mon + 1) << 5) |
1025 tm->tm_mday;
1027 if (time)
1028 *time = (tm->tm_hour << 11) |
1029 (tm->tm_min << 5) |
1030 (tm->tm_sec >> 1);
1032 if (tenth)
1033 *tenth = (tm->tm_sec & 1) * 100;
1034 #else
1035 /* non-RTC version returns an increment from the supplied time, or a
1036 * fixed standard time/date if no time given as input */
1038 /* Macros to convert a 2-digit string to a decimal constant.
1039 (YEAR), MONTH and DAY are set by the date command, which outputs
1040 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1041 misinterpretation as an octal constant. */
1042 #define S100(x) 1 ## x
1043 #define C2DIG2DEC(x) (S100(x)-100)
1044 /* The actual build date, as FAT date constant */
1045 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1046 | (C2DIG2DEC(MONTH) << 5) \
1047 | C2DIG2DEC(DAY))
1049 bool date_forced = false;
1050 bool next_day = false;
1051 unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */
1053 if (date && *date < BUILD_DATE_FAT)
1055 *date = BUILD_DATE_FAT;
1056 date_forced = true;
1059 if (time)
1061 time2 = *time << 1;
1062 if (time2 == 0 || date_forced)
1064 time2 = (11 < 6) | 11; /* set to 00:11:11 */
1066 else
1068 unsigned mins = (time2 >> 6) & 0x3f;
1069 unsigned hours = (time2 >> 12) & 0x1f;
1071 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */
1072 if (mins > 59)
1074 mins = 11; /* 00 would be a bad marker */
1075 if (++hours > 23)
1077 hours = 0;
1078 next_day = true;
1081 time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */
1083 *time = time2 >> 1;
1086 if (tenth)
1087 *tenth = (time2 & 1) * 100;
1089 if (date && next_day)
1091 static const unsigned char daysinmonth[] =
1092 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1093 unsigned day = *date & 0x1f;
1094 unsigned month = (*date >> 5) & 0x0f;
1095 unsigned year = (*date >> 9) & 0x7f;
1097 /* simplification: ignore leap years */
1098 if (++day > daysinmonth[month-1])
1100 day = 1;
1101 if (++month > 12)
1103 month = 1;
1104 year++;
1107 *date = (year << 9) | (month << 5) | day;
1110 #endif /* CONFIG_RTC */
1113 static int write_long_name(struct fat_file* file,
1114 unsigned int firstentry,
1115 unsigned int numentries,
1116 const unsigned char* name,
1117 const unsigned char* shortname,
1118 bool is_directory,
1119 unsigned char *sector_buffer)
1121 unsigned char* entry;
1122 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1123 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1124 unsigned char chksum = 0;
1125 unsigned int i, j=0;
1126 unsigned int nameidx=0, namelen = utf8length(name);
1127 int rc;
1128 unsigned short name_utf16[namelen + 1];
1130 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1131 file->firstcluster, firstentry, numentries, name);
1133 rc = fat_seek(file, sector);
1134 if (rc<0)
1135 return rc * 10 - 1;
1137 rc = fat_readwrite(file, 1, sector_buffer, false);
1138 if (rc<1)
1139 return rc * 10 - 2;
1141 /* calculate shortname checksum */
1142 for (i=11; i>0; i--)
1143 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1145 /* calc position of last name segment */
1146 if ( namelen > NAME_BYTES_PER_ENTRY )
1147 for (nameidx=0;
1148 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1149 nameidx += NAME_BYTES_PER_ENTRY);
1151 /* we need to convert the name first */
1152 /* since it is written in reverse order */
1153 for (i = 0; i <= namelen; i++)
1154 name = utf8decode(name, &name_utf16[i]);
1156 for (i=0; i < numentries; i++) {
1157 /* new sector? */
1158 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1159 /* update current sector */
1160 rc = fat_seek(file, sector);
1161 if (rc<0)
1162 return rc * 10 - 3;
1164 rc = fat_readwrite(file, 1, sector_buffer, true);
1165 if (rc<1)
1166 return rc * 10 - 4;
1168 /* read next sector */
1169 rc = fat_readwrite(file, 1, sector_buffer, false);
1170 if (rc<0) {
1171 LDEBUGF("Failed writing new sector: %d\n",rc);
1172 return rc * 10 - 5;
1174 if (rc==0)
1175 /* end of dir */
1176 memset(sector_buffer, 0, SECTOR_SIZE);
1178 sector++;
1179 idx = 0;
1182 entry = sector_buffer + idx * DIR_ENTRY_SIZE;
1184 /* verify this entry is free */
1185 if (entry[0] && entry[0] != 0xe5 )
1186 panicf("Dir entry %d in sector %x is not free! "
1187 "%02x %02x %02x %02x",
1188 idx, sector,
1189 entry[0], entry[1], entry[2], entry[3]);
1191 memset(entry, 0, DIR_ENTRY_SIZE);
1192 if ( i+1 < numentries ) {
1193 /* longname entry */
1194 unsigned int k, l = nameidx;
1196 entry[FATLONG_ORDER] = numentries-i-1;
1197 if (i==0) {
1198 /* mark this as last long entry */
1199 entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1201 /* pad name with 0xffff */
1202 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1203 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1204 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1206 /* set name */
1207 for (k=0; k<5 && l <= namelen; k++) {
1208 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1209 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1211 for (k=0; k<6 && l <= namelen; k++) {
1212 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1213 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1215 for (k=0; k<2 && l <= namelen; k++) {
1216 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1217 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1220 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1221 entry[FATDIR_FSTCLUSLO] = 0;
1222 entry[FATLONG_TYPE] = 0;
1223 entry[FATLONG_CHKSUM] = chksum;
1224 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1226 else {
1227 /* shortname entry */
1228 unsigned short date=0, time=0, tenth=0;
1229 LDEBUGF("Shortname entry: %s\n", shortname);
1230 memcpy(entry + FATDIR_NAME, shortname, 11);
1231 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1232 entry[FATDIR_NTRES] = 0;
1234 fat_time(&date, &time, &tenth);
1235 entry[FATDIR_CRTTIMETENTH] = tenth;
1236 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1237 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1238 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1239 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1240 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1242 idx++;
1243 nameidx -= NAME_BYTES_PER_ENTRY;
1246 /* update last sector */
1247 rc = fat_seek(file, sector);
1248 if (rc<0)
1249 return rc * 10 - 6;
1251 rc = fat_readwrite(file, 1, sector_buffer, true);
1252 if (rc<1)
1253 return rc * 10 - 7;
1255 return 0;
1258 static int fat_checkname(const unsigned char* newname)
1260 static const char invalid_chars[] = "\"*/:<>?\\|";
1261 int len = strlen(newname);
1262 /* More sanity checks are probably needed */
1263 if (len > 255 || newname[len - 1] == '.')
1265 return -1;
1267 while (*newname)
1269 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1270 return -1;
1271 newname++;
1273 /* check trailing space(s) */
1274 if(*(--newname) == ' ')
1275 return -1;
1277 return 0;
1280 static int add_dir_entry(struct fat_dir* dir,
1281 struct fat_file* file,
1282 const char* name,
1283 bool is_directory,
1284 bool dotdir)
1286 #ifdef HAVE_MULTIVOLUME
1287 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1288 #else
1289 struct bpb* fat_bpb = &fat_bpbs[0];
1290 #endif
1291 unsigned char buf[SECTOR_SIZE];
1292 unsigned char shortname[12];
1293 int rc;
1294 unsigned int sector;
1295 bool done = false;
1296 int entries_needed, entries_found = 0;
1297 int firstentry;
1299 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1300 name, file->firstcluster);
1302 /* Don't check dotdirs name for validity */
1303 if (dotdir == false) {
1304 rc = fat_checkname(name);
1305 if (rc < 0) {
1306 /* filename is invalid */
1307 return rc * 10 - 1;
1311 #ifdef HAVE_MULTIVOLUME
1312 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1313 #endif
1315 /* The "." and ".." directory entries must not be long names */
1316 if(dotdir) {
1317 int i;
1318 strlcpy(shortname, name, 12);
1319 for(i = strlen(shortname); i < 12; i++)
1320 shortname[i] = ' ';
1322 entries_needed = 1;
1323 } else {
1324 create_dos_name(name, shortname);
1326 /* one dir entry needed for every 13 bytes of filename,
1327 plus one entry for the short name */
1328 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1329 / NAME_BYTES_PER_ENTRY + 1;
1332 restart:
1333 firstentry = -1;
1335 rc = fat_seek(&dir->file, 0);
1336 if (rc < 0)
1337 return rc * 10 - 2;
1339 /* step 1: search for free entries and check for duplicate shortname */
1340 for (sector = 0; !done; sector++)
1342 unsigned int i;
1344 rc = fat_readwrite(&dir->file, 1, buf, false);
1345 if (rc < 0) {
1346 DEBUGF( "add_dir_entry() - Couldn't read dir"
1347 " (error code %d)\n", rc);
1348 return rc * 10 - 3;
1351 if (rc == 0) { /* current end of dir reached */
1352 LDEBUGF("End of dir on cluster boundary\n");
1353 break;
1356 /* look for free slots */
1357 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1359 switch (buf[i * DIR_ENTRY_SIZE]) {
1360 case 0:
1361 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1362 LDEBUGF("Found end of dir %d\n",
1363 sector * DIR_ENTRIES_PER_SECTOR + i);
1364 i = DIR_ENTRIES_PER_SECTOR - 1;
1365 done = true;
1366 break;
1368 case 0xe5:
1369 entries_found++;
1370 LDEBUGF("Found free entry %d (%d/%d)\n",
1371 sector * DIR_ENTRIES_PER_SECTOR + i,
1372 entries_found, entries_needed);
1373 break;
1375 default:
1376 entries_found = 0;
1378 /* check that our intended shortname doesn't already exist */
1379 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1380 /* shortname exists already, make a new one */
1381 randomize_dos_name(shortname);
1382 LDEBUGF("Duplicate shortname, changing to %s\n",
1383 shortname);
1385 /* name has changed, we need to restart search */
1386 goto restart;
1388 break;
1390 if (firstentry < 0 && (entries_found >= entries_needed))
1391 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1392 - entries_found;
1396 /* step 2: extend the dir if necessary */
1397 if (firstentry < 0)
1399 LDEBUGF("Adding new sector(s) to dir\n");
1400 rc = fat_seek(&dir->file, sector);
1401 if (rc < 0)
1402 return rc * 10 - 4;
1403 memset(buf, 0, sizeof buf);
1405 /* we must clear whole clusters */
1406 for (; (entries_found < entries_needed) ||
1407 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1409 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1410 return -5; /* dir too large -- FAT specification */
1412 rc = fat_readwrite(&dir->file, 1, buf, true);
1413 if (rc < 1) /* No more room or something went wrong */
1414 return rc * 10 - 6;
1416 entries_found += DIR_ENTRIES_PER_SECTOR;
1419 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1422 /* step 3: add entry */
1423 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1424 LDEBUGF("Adding longname to entry %d in sector %d\n",
1425 firstentry, sector);
1427 rc = write_long_name(&dir->file, firstentry,
1428 entries_needed, name,
1429 shortname, is_directory, buf);
1430 if (rc < 0)
1431 return rc * 10 - 7;
1433 /* remember where the shortname dir entry is located */
1434 file->direntry = firstentry + entries_needed - 1;
1435 file->direntries = entries_needed;
1436 file->dircluster = dir->file.firstcluster;
1437 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1438 file->direntry, file->direntries);
1440 return 0;
1443 static unsigned char char2dos(unsigned char c, int* randomize)
1445 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1447 if (c <= 0x20)
1448 c = 0; /* Illegal char, remove */
1449 else if (strchr(invalid_chars, c) != NULL)
1451 /* Illegal char, replace */
1452 c = '_';
1453 *randomize = 1; /* as per FAT spec */
1455 else
1456 c = toupper(c);
1458 return c;
1461 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1463 int i;
1464 unsigned char *ext;
1465 int randomize = 0;
1467 /* Find extension part */
1468 ext = strrchr(name, '.');
1469 if (ext == name) /* handle .dotnames */
1470 ext = NULL;
1472 /* needs to randomize? */
1473 if((ext && (strlen(ext) > 4)) ||
1474 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1475 randomize = 1;
1477 /* Name part */
1478 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1480 unsigned char c = char2dos(*name, &randomize);
1481 if (c)
1482 newname[i++] = c;
1485 /* Pad both name and extension */
1486 while (i < 11)
1487 newname[i++] = ' ';
1489 if (newname[0] == 0xe5) /* Special kanji character */
1490 newname[0] = 0x05;
1492 if (ext)
1493 { /* Extension part */
1494 ext++;
1495 for (i = 8; *ext && (i < 11); ext++)
1497 unsigned char c = char2dos(*ext, &randomize);
1498 if (c)
1499 newname[i++] = c;
1503 if(randomize)
1504 randomize_dos_name(newname);
1507 static void randomize_dos_name(unsigned char *name)
1509 unsigned char* tilde = NULL; /* ~ location */
1510 unsigned char* lastpt = NULL; /* last point of filename */
1511 unsigned char* nameptr = name; /* working copy of name pointer */
1512 unsigned char num[9]; /* holds number as string */
1513 int i = 0;
1514 int cnt = 1;
1515 int numlen;
1516 int offset;
1518 while(i++ < 8)
1520 /* hunt for ~ and where to put it */
1521 if((!tilde) && (*nameptr == '~'))
1522 tilde = nameptr;
1523 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1524 lastpt = nameptr;
1525 nameptr++;
1527 if(tilde)
1529 /* extract current count and increment */
1530 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1531 num[7-(unsigned int)(tilde-name)] = 0;
1532 cnt = atoi(num) + 1;
1534 cnt %= 10000000; /* protection */
1535 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1536 numlen = strlen(num); /* required space */
1537 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1538 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1540 memcpy(&name[offset], num, numlen);
1542 /* in special case of counter overflow: pad with spaces */
1543 for(offset = offset+numlen; offset < 8; offset++)
1544 name[offset] = ' ';
1547 static int update_short_entry( struct fat_file* file, long size, int attr )
1549 unsigned char buf[SECTOR_SIZE];
1550 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1551 unsigned char* entry =
1552 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1553 unsigned long* sizeptr;
1554 unsigned short* clusptr;
1555 struct fat_file dir;
1556 int rc;
1558 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1559 file->firstcluster, file->direntry, size);
1561 /* create a temporary file handle for the dir holding this file */
1562 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1563 if (rc < 0)
1564 return rc * 10 - 1;
1566 rc = fat_seek( &dir, sector );
1567 if (rc<0)
1568 return rc * 10 - 2;
1570 rc = fat_readwrite(&dir, 1, buf, false);
1571 if (rc < 1)
1572 return rc * 10 - 3;
1574 if (!entry[0] || entry[0] == 0xe5)
1575 panicf("Updating size on empty dir entry %d\n", file->direntry);
1577 entry[FATDIR_ATTR] = attr & 0xFF;
1579 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1580 *clusptr = htole16(file->firstcluster >> 16);
1582 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1583 *clusptr = htole16(file->firstcluster & 0xffff);
1585 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1586 *sizeptr = htole32(size);
1589 #if CONFIG_RTC
1590 unsigned short time = 0;
1591 unsigned short date = 0;
1592 #else
1593 /* get old time to increment from */
1594 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1595 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1596 #endif
1597 fat_time(&date, &time, NULL);
1598 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1599 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1600 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1603 rc = fat_seek( &dir, sector );
1604 if (rc < 0)
1605 return rc * 10 - 4;
1607 rc = fat_readwrite(&dir, 1, buf, true);
1608 if (rc < 1)
1609 return rc * 10 - 5;
1611 return 0;
1614 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1616 int i=0,j=0;
1617 unsigned char c;
1618 bool lowercase;
1620 memset(de, 0, sizeof(struct fat_direntry));
1621 de->attr = buf[FATDIR_ATTR];
1622 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1623 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1624 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1625 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1626 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1627 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1628 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1629 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1630 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1631 (the result of the shift is always considered signed) */
1633 /* fix the name */
1634 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1635 c = buf[FATDIR_NAME];
1636 if (c == 0x05) /* special kanji char */
1637 c = 0xe5;
1638 i = 0;
1639 while (c != ' ') {
1640 de->name[j++] = lowercase ? tolower(c) : c;
1641 if (++i >= 8)
1642 break;
1643 c = buf[FATDIR_NAME+i];
1645 if (buf[FATDIR_NAME+8] != ' ') {
1646 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1647 de->name[j++] = '.';
1648 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1649 de->name[j++] = lowercase ? tolower(c) : c;
1651 return 1;
1654 int fat_open(IF_MV2(int volume,)
1655 long startcluster,
1656 struct fat_file *file,
1657 const struct fat_dir* dir)
1659 /* Remember where the file's dir entry is located
1660 * Do it before assigning other fields so that fat_open
1661 * can be called with file == &dir->file (see fat_opendir) */
1662 if ( dir ) {
1663 file->direntry = dir->entry - 1;
1664 file->direntries = dir->entrycount;
1665 file->dircluster = dir->file.firstcluster;
1668 file->firstcluster = startcluster;
1669 file->lastcluster = startcluster;
1670 file->lastsector = 0;
1671 file->clusternum = 0;
1672 file->sectornum = 0;
1673 file->eof = false;
1674 #ifdef HAVE_MULTIVOLUME
1675 file->volume = volume;
1676 /* fixme: remove error check when done */
1677 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1679 LDEBUGF("fat_open() illegal volume %d\n", volume);
1680 return -1;
1682 #endif
1684 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1685 return 0;
1688 int fat_create_file(const char* name,
1689 struct fat_file* file,
1690 struct fat_dir* dir)
1692 int rc;
1694 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1695 rc = add_dir_entry(dir, file, name, false, false);
1696 if (!rc) {
1697 file->firstcluster = 0;
1698 file->lastcluster = 0;
1699 file->lastsector = 0;
1700 file->clusternum = 0;
1701 file->sectornum = 0;
1702 file->eof = false;
1705 return rc;
1708 /* noinline because this is only split out of fat_create_dir to make sure
1709 * the sector buffer doesn't remain on the stack, to avoid nasty stack
1710 * overflows later on (when flush_fat() is called */
1711 static __attribute__((noinline)) int fat_clear_cluster(int sector,
1712 struct bpb *fat_bpb)
1714 unsigned char buf[SECTOR_SIZE];
1715 int i,rc;
1716 memset(buf, 0, sizeof buf);
1717 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1718 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1719 if (rc < 0)
1720 return rc * 10 - 2;
1722 return 0;
1725 int fat_create_dir(const char* name,
1726 struct fat_dir* newdir,
1727 struct fat_dir* dir)
1729 #ifdef HAVE_MULTIVOLUME
1730 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1731 #else
1732 struct bpb* fat_bpb = &fat_bpbs[0];
1733 #endif
1734 long sector;
1735 int rc;
1736 struct fat_file dummyfile;
1738 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1740 memset(newdir, 0, sizeof(struct fat_dir));
1741 memset(&dummyfile, 0, sizeof(struct fat_file));
1743 /* First, add the entry in the parent directory */
1744 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1745 if (rc < 0)
1746 return rc * 10 - 1;
1748 /* Allocate a new cluster for the directory */
1749 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1750 fat_bpb->fsinfo.nextfree);
1751 if(newdir->file.firstcluster == 0)
1752 return -1;
1754 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1756 /* Clear the entire cluster */
1757 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1758 rc = fat_clear_cluster(sector,fat_bpb);
1759 if (rc < 0)
1760 return rc;
1763 /* Then add the "." entry */
1764 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1765 if (rc < 0)
1766 return rc * 10 - 3;
1767 dummyfile.firstcluster = newdir->file.firstcluster;
1768 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1770 /* and the ".." entry */
1771 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1772 if (rc < 0)
1773 return rc * 10 - 4;
1775 /* The root cluster is cluster 0 in the ".." entry */
1776 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1777 dummyfile.firstcluster = 0;
1778 else
1779 dummyfile.firstcluster = dir->file.firstcluster;
1780 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1782 /* Set the firstcluster field in the direntry */
1783 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1785 rc = flush_fat(IF_MV(fat_bpb));
1786 if (rc < 0)
1787 return rc * 10 - 5;
1789 return rc;
1792 int fat_truncate(const struct fat_file *file)
1794 /* truncate trailing clusters */
1795 long next;
1796 long last = file->lastcluster;
1797 #ifdef HAVE_MULTIVOLUME
1798 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1799 #endif
1801 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1803 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1804 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1805 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1807 if (file->lastcluster)
1808 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1810 return 0;
1813 int fat_closewrite(struct fat_file *file, long size, int attr)
1815 int rc;
1816 #ifdef HAVE_MULTIVOLUME
1817 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1818 #endif
1819 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1821 if (!size) {
1822 /* empty file */
1823 if ( file->firstcluster ) {
1824 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1825 file->firstcluster = 0;
1829 if (file->dircluster) {
1830 rc = update_short_entry(file, size, attr);
1831 if (rc < 0)
1832 return rc * 10 - 1;
1835 flush_fat(IF_MV(fat_bpb));
1837 #ifdef TEST_FAT
1838 if ( file->firstcluster ) {
1839 /* debug */
1840 #ifdef HAVE_MULTIVOLUME
1841 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1842 #else
1843 struct bpb* fat_bpb = &fat_bpbs[0];
1844 #endif
1845 long count = 0;
1846 long len;
1847 long next;
1848 for ( next = file->firstcluster; next;
1849 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1850 LDEBUGF("cluster %ld: %lx\n", count, next);
1851 count++;
1853 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1854 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1855 count, len, size );
1856 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1857 panicf("Cluster chain is too long\n");
1858 if ( len < size )
1859 panicf("Cluster chain is too short\n");
1861 #endif
1863 return 0;
1866 static int free_direntries(struct fat_file* file)
1868 unsigned char buf[SECTOR_SIZE];
1869 struct fat_file dir;
1870 int numentries = file->direntries;
1871 unsigned int entry = file->direntry - numentries + 1;
1872 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1873 int i;
1874 int rc;
1876 /* create a temporary file handle for the dir holding this file */
1877 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1878 if (rc < 0)
1879 return rc * 10 - 1;
1881 rc = fat_seek( &dir, sector );
1882 if (rc < 0)
1883 return rc * 10 - 2;
1885 rc = fat_readwrite(&dir, 1, buf, false);
1886 if (rc < 1)
1887 return rc * 10 - 3;
1889 for (i=0; i < numentries; i++) {
1890 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1891 entry, i+1, numentries);
1892 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1893 entry++;
1895 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1896 /* flush this sector */
1897 rc = fat_seek(&dir, sector);
1898 if (rc < 0)
1899 return rc * 10 - 4;
1901 rc = fat_readwrite(&dir, 1, buf, true);
1902 if (rc < 1)
1903 return rc * 10 - 5;
1905 if ( i+1 < numentries ) {
1906 /* read next sector */
1907 rc = fat_readwrite(&dir, 1, buf, false);
1908 if (rc < 1)
1909 return rc * 10 - 6;
1911 sector++;
1915 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1916 /* flush this sector */
1917 rc = fat_seek(&dir, sector);
1918 if (rc < 0)
1919 return rc * 10 - 7;
1921 rc = fat_readwrite(&dir, 1, buf, true);
1922 if (rc < 1)
1923 return rc * 10 - 8;
1926 return 0;
1929 int fat_remove(struct fat_file* file)
1931 long next, last = file->firstcluster;
1932 int rc;
1933 #ifdef HAVE_MULTIVOLUME
1934 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1935 #endif
1937 LDEBUGF("fat_remove(%lx)\n",last);
1939 while ( last ) {
1940 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1941 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1942 last = next;
1945 if ( file->dircluster ) {
1946 rc = free_direntries(file);
1947 if (rc < 0)
1948 return rc * 10 - 1;
1951 file->firstcluster = 0;
1952 file->dircluster = 0;
1954 rc = flush_fat(IF_MV(fat_bpb));
1955 if (rc < 0)
1956 return rc * 10 - 2;
1958 return 0;
1961 int fat_rename(struct fat_file* file,
1962 struct fat_dir* dir,
1963 const unsigned char* newname,
1964 long size,
1965 int attr)
1967 int rc;
1968 struct fat_file olddir_file;
1969 struct fat_file newfile = *file;
1970 unsigned char* entry = NULL;
1971 unsigned short* clusptr = NULL;
1972 unsigned int parentcluster;
1973 #ifdef HAVE_MULTIVOLUME
1974 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1976 if (file->volume != dir->file.volume) {
1977 DEBUGF("No rename across volumes!\n");
1978 return -1;
1980 #else
1981 struct bpb* fat_bpb = &fat_bpbs[0];
1982 #endif
1984 if ( !file->dircluster ) {
1985 DEBUGF("File has no dir cluster!\n");
1986 return -2;
1989 /* create new name */
1990 rc = add_dir_entry(dir, &newfile, newname, false, false);
1991 if (rc < 0)
1992 return rc * 10 - 2;
1994 /* write size and cluster link */
1995 rc = update_short_entry(&newfile, size, attr);
1996 if (rc < 0)
1997 return rc * 10 - 3;
1999 /* remove old name */
2000 rc = free_direntries(file);
2001 if (rc < 0)
2002 return rc * 10 - 4;
2004 rc = flush_fat(IF_MV(fat_bpb));
2005 if (rc < 0)
2006 return rc * 10 - 5;
2008 /* if renaming a directory, update the .. entry to make sure
2009 it points to its parent directory (we don't check if it was a move) */
2010 if(FAT_ATTR_DIRECTORY == attr) {
2011 unsigned char buf[SECTOR_SIZE];
2012 /* open the dir that was renamed, we re-use the olddir_file struct */
2013 rc = fat_open(IF_MV2(file->volume,) newfile.firstcluster, &olddir_file, NULL);
2014 if (rc < 0)
2015 return rc * 10 - 6;
2017 /* get the first sector of the dir */
2018 rc = fat_seek(&olddir_file, 0);
2019 if (rc < 0)
2020 return rc * 10 - 7;
2022 rc = fat_readwrite(&olddir_file, 1, buf, false);
2023 if (rc < 0)
2024 return rc * 10 - 8;
2026 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2027 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2028 parentcluster = 0;
2029 else
2030 parentcluster = dir->file.firstcluster;
2032 entry = buf + DIR_ENTRY_SIZE;
2033 if(strncmp(".. ", entry, 11))
2035 /* .. entry must be second entry according to FAT spec (p.29) */
2036 DEBUGF("Second dir entry is not double-dot!\n");
2037 return rc * 10 - 9;
2039 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2040 *clusptr = htole16(parentcluster >> 16);
2042 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
2043 *clusptr = htole16(parentcluster & 0xffff);
2045 /* write back this sector */
2046 rc = fat_seek(&olddir_file, 0);
2047 if (rc < 0)
2048 return rc * 10 - 7;
2050 rc = fat_readwrite(&olddir_file, 1, buf, true);
2051 if (rc < 1)
2052 return rc * 10 - 8;
2055 return 0;
2058 static long next_write_cluster(struct fat_file* file,
2059 long oldcluster,
2060 long* newsector)
2062 #ifdef HAVE_MULTIVOLUME
2063 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2064 #else
2065 struct bpb* fat_bpb = &fat_bpbs[0];
2066 #endif
2067 long cluster = 0;
2068 long sector;
2070 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2072 if (oldcluster)
2073 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2075 if (!cluster) {
2076 if (oldcluster > 0)
2077 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2078 else if (oldcluster == 0)
2079 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2080 fat_bpb->fsinfo.nextfree);
2081 #ifdef HAVE_FAT16SUPPORT
2082 else /* negative, pseudo-cluster of the root dir */
2083 return 0; /* impossible to append something to the root */
2084 #endif
2086 if (cluster) {
2087 if (oldcluster)
2088 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2089 else
2090 file->firstcluster = cluster;
2091 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2093 else {
2094 #ifdef TEST_FAT
2095 if (fat_bpb->fsinfo.freecount>0)
2096 panicf("There is free space, but find_free_cluster() "
2097 "didn't find it!\n");
2098 #endif
2099 DEBUGF("next_write_cluster(): Disk full!\n");
2100 return 0;
2103 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2104 if (sector<0)
2105 return 0;
2107 *newsector = sector;
2108 return cluster;
2111 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2112 unsigned long start, long count, char* buf, bool write )
2114 #ifndef HAVE_MULTIVOLUME
2115 struct bpb* fat_bpb = &fat_bpbs[0];
2116 #endif
2117 int rc;
2119 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2120 start+ fat_bpb->startsector, count, write?"write":"read");
2121 if (write) {
2122 unsigned long firstallowed;
2123 #ifdef HAVE_FAT16SUPPORT
2124 if (fat_bpb->is_fat16)
2125 firstallowed = fat_bpb->rootdirsector;
2126 else
2127 #endif
2128 firstallowed = fat_bpb->firstdatasector;
2130 if (start < firstallowed)
2131 panicf("Write %ld before data\n", firstallowed - start);
2132 if (start + count > fat_bpb->totalsectors)
2133 panicf("Write %ld after data\n",
2134 start + count - fat_bpb->totalsectors);
2135 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2136 start + fat_bpb->startsector, count, buf);
2138 else
2139 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2140 start + fat_bpb->startsector, count, buf);
2141 if (rc < 0) {
2142 DEBUGF( "transfer() - Couldn't %s sector %lx"
2143 " (error code %d)\n",
2144 write ? "write":"read", start, rc);
2145 return rc;
2147 return 0;
2151 long fat_readwrite( struct fat_file *file, long sectorcount,
2152 void* buf, bool write )
2154 #ifdef HAVE_MULTIVOLUME
2155 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2156 #else
2157 struct bpb* fat_bpb = &fat_bpbs[0];
2158 #endif
2159 long cluster = file->lastcluster;
2160 long sector = file->lastsector;
2161 long clusternum = file->clusternum;
2162 long numsec = file->sectornum;
2163 bool eof = file->eof;
2164 long first=0, last=0;
2165 long i;
2166 int rc;
2168 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2169 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2170 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2171 sector,numsec, eof?1:0);
2173 if ( eof && !write)
2174 return 0;
2176 /* find sequential sectors and write them all at once */
2177 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2178 numsec++;
2179 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2180 long oldcluster = cluster;
2181 long oldsector = sector;
2182 long oldnumsec = numsec;
2183 if (write)
2184 cluster = next_write_cluster(file, cluster, &sector);
2185 else {
2186 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2187 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2190 clusternum++;
2191 numsec=1;
2193 if (!cluster) {
2194 eof = true;
2195 if ( write ) {
2196 /* remember last cluster, in case
2197 we want to append to the file */
2198 sector = oldsector;
2199 cluster = oldcluster;
2200 numsec = oldnumsec;
2201 clusternum--;
2202 i = -1; /* Error code */
2203 break;
2206 else
2207 eof = false;
2209 else {
2210 if (sector)
2211 sector++;
2212 else {
2213 /* look up first sector of file */
2214 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2215 numsec=1;
2216 #ifdef HAVE_FAT16SUPPORT
2217 if (file->firstcluster < 0)
2218 { /* FAT16 root dir */
2219 sector += fat_bpb->rootdiroffset;
2220 numsec += fat_bpb->rootdiroffset;
2222 #endif
2226 if (!first)
2227 first = sector;
2229 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2230 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2231 long count = last - first + 1;
2232 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2233 if (rc < 0)
2234 return rc * 10 - 1;
2236 buf = (char *)buf + count * SECTOR_SIZE;
2237 first = sector;
2240 if ((i == sectorcount-1) && /* last sector requested */
2241 (!eof))
2243 long count = sector - first + 1;
2244 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2245 if (rc < 0)
2246 return rc * 10 - 2;
2249 last = sector;
2252 file->lastcluster = cluster;
2253 file->lastsector = sector;
2254 file->clusternum = clusternum;
2255 file->sectornum = numsec;
2256 file->eof = eof;
2258 /* if eof, don't report last block as read/written */
2259 if (eof)
2260 i--;
2262 DEBUGF("Sectors written: %ld\n", i);
2263 return i;
2266 int fat_seek(struct fat_file *file, unsigned long seeksector )
2268 #ifdef HAVE_MULTIVOLUME
2269 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2270 #else
2271 struct bpb* fat_bpb = &fat_bpbs[0];
2272 #endif
2273 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2274 long cluster = file->firstcluster;
2275 long i;
2277 #ifdef HAVE_FAT16SUPPORT
2278 if (cluster < 0) /* FAT16 root dir */
2279 seeksector += fat_bpb->rootdiroffset;
2280 #endif
2282 file->eof = false;
2283 if (seeksector) {
2284 /* we need to find the sector BEFORE the requested, since
2285 the file struct stores the last accessed sector */
2286 seeksector--;
2287 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2288 sectornum = seeksector % fat_bpb->bpb_secperclus;
2290 if (file->clusternum && clusternum >= file->clusternum)
2292 cluster = file->lastcluster;
2293 numclusters -= file->clusternum;
2296 for (i=0; i<numclusters; i++) {
2297 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2298 if (!cluster) {
2299 DEBUGF("Seeking beyond the end of the file! "
2300 "(sector %ld, cluster %ld)\n", seeksector, i);
2301 return -1;
2305 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2307 else {
2308 sectornum = -1;
2311 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2312 file->firstcluster, seeksector, cluster, sector, sectornum);
2314 file->lastcluster = cluster;
2315 file->lastsector = sector;
2316 file->clusternum = clusternum;
2317 file->sectornum = sectornum + 1;
2318 return 0;
2321 int fat_opendir(IF_MV2(int volume,)
2322 struct fat_dir *dir, unsigned long startcluster,
2323 const struct fat_dir *parent_dir)
2325 #ifdef HAVE_MULTIVOLUME
2326 struct bpb* fat_bpb = &fat_bpbs[volume];
2327 /* fixme: remove error check when done */
2328 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2330 LDEBUGF("fat_open() illegal volume %d\n", volume);
2331 return -1;
2333 #else
2334 struct bpb* fat_bpb = &fat_bpbs[0];
2335 #endif
2336 int rc;
2338 if (startcluster == 0)
2339 startcluster = fat_bpb->bpb_rootclus;
2341 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2342 if(rc)
2344 DEBUGF( "fat_opendir() - Couldn't open dir"
2345 " (error code %d)\n", rc);
2346 return rc * 10 - 1;
2349 /* assign them after fat_open call so that fat_opendir can be called with the same
2350 * fat_dir as parent and result */
2351 dir->entry = 0;
2352 dir->sector = 0;
2354 return 0;
2357 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2359 bool done = false;
2360 int i, j;
2361 int rc;
2362 int order;
2363 unsigned char firstbyte;
2364 /* Long file names are stored in special entries. Each entry holds
2365 up to 13 characters. Names can be max 255 chars (not bytes!) long */
2366 /* The number of long entries in the long name can be retrieve from the first
2367 * long entry because there are stored in reverse order and have an ordinal */
2368 int nb_longs = 0;
2369 /* The long entries are expected to be in order, so remember the last ordinal */
2370 int last_long_ord = 0;
2372 dir->entrycount = 0;
2374 while(!done)
2376 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2378 rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2379 if (rc == 0) {
2380 /* eof */
2381 entry->name[0] = 0;
2382 break;
2384 if (rc < 0) {
2385 DEBUGF( "fat_getnext() - Couldn't read dir"
2386 " (error code %d)\n", rc);
2387 return rc * 10 - 1;
2389 dir->sector = dir->file.lastsector;
2392 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2393 i < DIR_ENTRIES_PER_SECTOR; i++) {
2394 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2396 firstbyte = dir->sectorcache[entrypos];
2397 dir->entry++;
2399 if (firstbyte == 0xe5) {
2400 /* free entry */
2401 dir->entrycount = 0;
2402 continue;
2405 if (firstbyte == 0) {
2406 /* last entry */
2407 entry->name[0] = 0;
2408 dir->entrycount = 0;
2409 return 0;
2412 dir->entrycount++;
2414 /* LFN entry? */
2415 if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2416 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2417 /* extract ordinal */
2418 order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2419 /* is this entry the first long entry ? (first in order but containing last part) */
2420 if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2421 /* check that order is not too big ! (and non-zero) */
2422 if(order <= 0 || order > FATLONG_MAX_ORDER)
2423 continue; /* ignore the whole LFN, will trigger lots of warnings */
2424 nb_longs = order;
2425 last_long_ord = order;
2427 else {
2428 /* check orphan entry */
2429 if (nb_longs == 0) {
2430 logf("fat warning: orphan LFN entry");
2431 /* ignore */
2432 continue;
2435 /* check order */
2436 if (order != (last_long_ord - 1)) {
2437 logf("fat warning: wrong LFN ordinal");
2438 /* ignore the whole LFN, will trigger lots of warnings */
2439 nb_longs = 0;
2442 last_long_ord = order;
2445 /* copy part, reuse [order] for another purpose :) */
2446 order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2447 for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2448 memcpy(dir->longname + order,
2449 dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2450 FATLONG_NAME_SIZE[j]);
2451 order += FATLONG_NAME_SIZE[j];
2454 else {
2455 if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2457 /* don't return volume id entry */
2458 if ( (entry->attr &
2459 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2460 == FAT_ATTR_VOLUME_ID)
2461 continue;
2463 /* replace shortname with longname? */
2464 /* check that the long name is complete */
2465 if (nb_longs != 0 && last_long_ord == 1) {
2466 /* hold a copy of the shortname in case the long one is too long */
2467 unsigned char shortname[13]; /* 8+3+dot+\0 */
2468 int longname_utf8len = 0;
2469 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2470 * of a UTF8 encoded character in rockbox */
2471 unsigned char longname_utf8segm[4 + 1];
2472 unsigned short ucs;
2473 int segm_utf8len;
2474 /* Temporarily store short name */
2475 strcpy(shortname, entry->name);
2476 entry->name[0] = 0;
2478 /* Convert the FAT name to a utf8-encoded one.
2479 * The name is not necessary NUL-terminated ! */
2480 for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2481 ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2482 if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2483 break;
2484 /* utf8encode will return a pointer after the converted
2485 * string, subtract the pointer to the start to get the length of it */
2486 segm_utf8len = utf8encode(ucs, longname_utf8segm) - longname_utf8segm;
2488 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2489 if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2490 /* force use of short name */
2491 longname_utf8len = FAT_FILENAME_BYTES + 1;
2492 break; /* fallback later */
2494 else {
2495 longname_utf8segm[segm_utf8len] = 0;
2496 strcat(entry->name + longname_utf8len, longname_utf8segm);
2497 longname_utf8len += segm_utf8len;
2501 /* Does the utf8-encoded name fit into the entry? */
2502 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2503 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2504 /* Take the short DOS name. Need to utf8-encode it
2505 since it may contain chars from the upper half of
2506 the OEM code page which wouldn't be a valid utf8.
2507 Beware: this file will be shown with strange
2508 glyphs in file browser since unicode 0x80 to 0x9F
2509 are control characters. */
2510 logf("SN-DOS: %s", shortname);
2511 unsigned char *utf8;
2512 utf8 = iso_decode(shortname, entry->name, -1,
2513 strlen(shortname));
2514 *utf8 = 0;
2515 logf("SN: %s", entry->name);
2516 } else {
2517 logf("LN: %s", entry->name);
2518 logf("LNLen: %d", longname_utf8len);
2521 done = true;
2522 i++;
2523 break;
2528 return 0;
2531 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2533 #ifndef HAVE_MULTIVOLUME
2534 const int volume = 0;
2535 #endif
2536 struct bpb* fat_bpb = &fat_bpbs[volume];
2537 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2540 #ifdef HAVE_MULTIVOLUME
2541 bool fat_ismounted(int volume)
2543 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2545 #endif