Fix corrupted metadata on manual track change on hwcodec.
[kugel-rb.git] / firmware / drivers / fat.c
blobf055f4b1700fe4e41dcc3ddbc8cfdffbb09c5667
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 #ifdef MAX_LOG_SECTOR_SIZE
452 int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume))
454 #ifdef HAVE_MULTIVOLUME
455 if(!fat_bpbs[volume].mounted)
456 return 0;
457 return fat_bpbs[volume].bpb_bytspersec;
458 #else
459 return fat_bpbs[0].bpb_bytspersec;
460 #endif
462 #endif
464 int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
466 #ifndef HAVE_MULTIVOLUME
467 const int volume = 0;
468 #endif
469 struct bpb* fat_bpb = &fat_bpbs[volume];
470 int rc;
472 rc = fat_mount_internal(IF_MV2(volume,) IF_MD2(drive,) startsector);
474 if(rc!=0) return rc;
476 /* calculate freecount if unset */
477 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
479 fat_recalc_free(IF_MV(volume));
482 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
483 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
484 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
485 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
486 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
488 #ifdef HAVE_MULTIVOLUME
489 fat_bpb->mounted = true;
490 #endif
492 return 0;
495 int fat_unmount(int volume, bool flush)
497 int rc;
498 #ifdef HAVE_MULTIVOLUME
499 struct bpb* fat_bpb = &fat_bpbs[volume];
500 #else
501 (void)volume;
502 #endif
504 if(flush)
506 rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
508 else
509 { /* volume is not accessible any more, e.g. MMC removed */
510 int i;
511 mutex_lock(&cache_mutex);
512 for(i = 0;i < FAT_CACHE_SIZE;i++)
514 struct fat_cache_entry *fce = &fat_cache[i];
515 if(fce->inuse
516 #ifdef HAVE_MULTIVOLUME
517 && fce->fat_vol == fat_bpb
518 #endif
521 fce->inuse = false; /* discard all from that volume */
522 fce->dirty = false;
525 mutex_unlock(&cache_mutex);
526 rc = 0;
528 #ifdef HAVE_MULTIVOLUME
529 fat_bpb->mounted = false;
530 #endif
531 return rc;
534 void fat_recalc_free(IF_MV_NONVOID(int volume))
536 #ifndef HAVE_MULTIVOLUME
537 const int volume = 0;
538 #endif
539 struct bpb* fat_bpb = &fat_bpbs[volume];
540 long free = 0;
541 unsigned long i;
542 #ifdef HAVE_FAT16SUPPORT
543 if (fat_bpb->is_fat16)
545 for (i = 0; i<fat_bpb->fatsize; i++) {
546 unsigned int j;
547 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
548 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
549 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
550 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
551 break;
553 if (letoh16(fat[j]) == 0x0000) {
554 free++;
555 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
556 fat_bpb->fsinfo.nextfree = c;
561 else
562 #endif /* #ifdef HAVE_FAT16SUPPORT */
564 for (i = 0; i<fat_bpb->fatsize; i++) {
565 unsigned int j;
566 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
567 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
568 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
569 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
570 break;
572 if (!(letoh32(fat[j]) & 0x0fffffff)) {
573 free++;
574 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
575 fat_bpb->fsinfo.nextfree = c;
580 fat_bpb->fsinfo.freecount = free;
581 update_fsinfo(IF_MV(fat_bpb));
584 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
586 #ifndef HAVE_MULTIVOLUME
587 struct bpb* fat_bpb = &fat_bpbs[0];
588 #endif
589 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
591 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
592 fat_bpb->bpb_bytspersec);
593 return -1;
595 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
596 > 128L*1024L)
598 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
599 "(%d * %d = %d)\n",
600 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
601 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
602 return -2;
604 if(fat_bpb->bpb_numfats != 2)
606 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
607 fat_bpb->bpb_numfats);
609 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
611 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
612 "media type (0x%02x)\n",
613 fat_bpb->bpb_media);
615 if(fat_bpb->last_word != 0xaa55)
617 DEBUGF( "bpb_is_sane() - Error: Last word is not "
618 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
619 return -3;
622 if (fat_bpb->fsinfo.freecount >
623 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
624 fat_bpb->bpb_secperclus)
626 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
627 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
628 return -4;
631 return 0;
634 static void flush_fat_sector(struct fat_cache_entry *fce,
635 unsigned char *sectorbuf)
637 int rc;
638 long secnum;
640 /* With multivolume, use only the FAT info from the cached sector! */
641 #ifdef HAVE_MULTIVOLUME
642 secnum = fce->secnum + fce->fat_vol->startsector;
643 #else
644 secnum = fce->secnum + fat_bpbs[0].startsector;
645 #endif
647 /* Write to the first FAT */
648 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
649 secnum, 1,
650 sectorbuf);
651 if(rc < 0)
653 panicf("flush_fat_sector() - Could not write sector %ld"
654 " (error %d)\n",
655 secnum, rc);
657 #ifdef HAVE_MULTIVOLUME
658 if(fce->fat_vol->bpb_numfats > 1)
659 #else
660 if(fat_bpbs[0].bpb_numfats > 1)
661 #endif
663 /* Write to the second FAT */
664 #ifdef HAVE_MULTIVOLUME
665 secnum += fce->fat_vol->fatsize;
666 #else
667 secnum += fat_bpbs[0].fatsize;
668 #endif
669 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
670 secnum, 1, sectorbuf);
671 if(rc < 0)
673 panicf("flush_fat_sector() - Could not write sector %ld"
674 " (error %d)\n",
675 secnum, rc);
678 fce->dirty = false;
681 /* Note: The returned pointer is only safely valid until the next
682 task switch! (Any subsequent ata read/write may yield.) */
683 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
684 long fatsector, bool dirty)
686 #ifndef HAVE_MULTIVOLUME
687 struct bpb* fat_bpb = &fat_bpbs[0];
688 #endif
689 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
690 int cache_index = secnum & FAT_CACHE_MASK;
691 struct fat_cache_entry *fce = &fat_cache[cache_index];
692 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
693 int rc;
695 mutex_lock(&cache_mutex); /* make changes atomic */
697 /* Delete the cache entry if it isn't the sector we want */
698 if(fce->inuse && (fce->secnum != secnum
699 #ifdef HAVE_MULTIVOLUME
700 || fce->fat_vol != fat_bpb
701 #endif
704 /* Write back if it is dirty */
705 if(fce->dirty)
707 flush_fat_sector(fce, sectorbuf);
709 fce->inuse = false;
712 /* Load the sector if it is not cached */
713 if(!fce->inuse)
715 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
716 secnum + fat_bpb->startsector,1,
717 sectorbuf);
718 if(rc < 0)
720 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
721 " (error %d)\n", secnum, rc);
722 mutex_unlock(&cache_mutex);
723 return NULL;
725 fce->inuse = true;
726 fce->secnum = secnum;
727 #ifdef HAVE_MULTIVOLUME
728 fce->fat_vol = fat_bpb;
729 #endif
731 if (dirty)
732 fce->dirty = true; /* dirt remains, sticky until flushed */
733 mutex_unlock(&cache_mutex);
734 return sectorbuf;
737 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
738 unsigned long startcluster)
740 #ifndef HAVE_MULTIVOLUME
741 struct bpb* fat_bpb = &fat_bpbs[0];
742 #endif
743 unsigned long sector;
744 unsigned long offset;
745 unsigned long i;
747 #ifdef HAVE_FAT16SUPPORT
748 if (fat_bpb->is_fat16)
750 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
751 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
753 for (i = 0; i<fat_bpb->fatsize; i++) {
754 unsigned int j;
755 unsigned int nr = (i + sector) % fat_bpb->fatsize;
756 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
757 if ( !fat )
758 break;
759 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
760 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
761 if (letoh16(fat[k]) == 0x0000) {
762 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
763 /* Ignore the reserved clusters 0 & 1, and also
764 cluster numbers out of bounds */
765 if ( c < 2 || c > fat_bpb->dataclusters+1 )
766 continue;
767 LDEBUGF("find_free_cluster(%lx) == %x\n",startcluster,c);
768 fat_bpb->fsinfo.nextfree = c;
769 return c;
772 offset = 0;
775 else
776 #endif /* #ifdef HAVE_FAT16SUPPORT */
778 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
779 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
781 for (i = 0; i<fat_bpb->fatsize; i++) {
782 unsigned int j;
783 unsigned long nr = (i + sector) % fat_bpb->fatsize;
784 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
785 if ( !fat )
786 break;
787 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
788 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
789 if (!(letoh32(fat[k]) & 0x0fffffff)) {
790 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
791 /* Ignore the reserved clusters 0 & 1, and also
792 cluster numbers out of bounds */
793 if ( c < 2 || c > fat_bpb->dataclusters+1 )
794 continue;
795 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
796 fat_bpb->fsinfo.nextfree = c;
797 return c;
800 offset = 0;
804 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
805 return 0; /* 0 is an illegal cluster number */
808 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
809 unsigned long val)
811 #ifndef HAVE_MULTIVOLUME
812 struct bpb* fat_bpb = &fat_bpbs[0];
813 #endif
814 #ifdef HAVE_FAT16SUPPORT
815 if (fat_bpb->is_fat16)
817 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
818 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
819 unsigned short* sec;
821 val &= 0xFFFF;
823 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
825 if (entry==val)
826 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
828 if ( entry < 2 )
829 panicf("Updating reserved FAT entry %ld.\n",entry);
831 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
832 if (!sec)
834 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
835 return -1;
838 if ( val ) {
839 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
840 fat_bpb->fsinfo.freecount--;
842 else {
843 if (letoh16(sec[offset]))
844 fat_bpb->fsinfo.freecount++;
847 LDEBUGF("update_fat_entry: %lu free clusters\n",
848 fat_bpb->fsinfo.freecount);
850 sec[offset] = htole16(val);
852 else
853 #endif /* #ifdef HAVE_FAT16SUPPORT */
855 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
856 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
857 unsigned long* sec;
859 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
861 if (entry==val)
862 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
864 if ( entry < 2 )
865 panicf("Updating reserved FAT entry %ld.\n",entry);
867 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
868 if (!sec)
870 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
871 return -1;
874 if ( val ) {
875 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
876 fat_bpb->fsinfo.freecount > 0)
877 fat_bpb->fsinfo.freecount--;
879 else {
880 if (letoh32(sec[offset]) & 0x0fffffff)
881 fat_bpb->fsinfo.freecount++;
884 LDEBUGF("update_fat_entry: %ld free clusters\n",
885 fat_bpb->fsinfo.freecount);
887 /* don't change top 4 bits */
888 sec[offset] &= htole32(0xf0000000);
889 sec[offset] |= htole32(val & 0x0fffffff);
892 return 0;
895 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
897 #ifdef HAVE_FAT16SUPPORT
898 #ifndef HAVE_MULTIVOLUME
899 struct bpb* fat_bpb = &fat_bpbs[0];
900 #endif
901 if (fat_bpb->is_fat16)
903 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
904 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
905 unsigned short* sec;
907 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
908 if (!sec)
910 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
911 return -1;
914 return letoh16(sec[offset]);
916 else
917 #endif /* #ifdef HAVE_FAT16SUPPORT */
919 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
920 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
921 unsigned long* sec;
923 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
924 if (!sec)
926 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
927 return -1;
930 return letoh32(sec[offset]) & 0x0fffffff;
934 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
936 long next_cluster;
937 long eof_mark = FAT_EOF_MARK;
939 #ifdef HAVE_FAT16SUPPORT
940 #ifndef HAVE_MULTIVOLUME
941 struct bpb* fat_bpb = &fat_bpbs[0];
942 #endif
943 if (fat_bpb->is_fat16)
945 eof_mark &= 0xFFFF; /* only 16 bit */
946 if (cluster < 0) /* FAT16 root dir */
947 return cluster + 1; /* don't use the FAT */
949 #endif
950 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
952 /* is this last cluster in chain? */
953 if ( next_cluster >= eof_mark )
954 return 0;
955 else
956 return next_cluster;
959 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
961 #ifndef HAVE_MULTIVOLUME
962 struct bpb* fat_bpb = &fat_bpbs[0];
963 #endif
964 unsigned char fsinfo[SECTOR_SIZE];
965 unsigned long* intptr;
966 int rc;
968 #ifdef HAVE_FAT16SUPPORT
969 if (fat_bpb->is_fat16)
970 return 0; /* FAT16 has no FsInfo */
971 #endif /* #ifdef HAVE_FAT16SUPPORT */
973 /* update fsinfo */
974 rc = storage_read_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 read FSInfo (error code %d)\n", rc);
979 return rc * 10 - 1;
981 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
982 *intptr = htole32(fat_bpb->fsinfo.freecount);
984 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
985 *intptr = htole32(fat_bpb->fsinfo.nextfree);
987 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
988 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
989 if (rc < 0)
991 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
992 return rc * 10 - 2;
995 return 0;
998 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
1000 int i;
1001 int rc;
1002 unsigned char *sec;
1003 LDEBUGF("flush_fat()\n");
1005 mutex_lock(&cache_mutex);
1006 for(i = 0;i < FAT_CACHE_SIZE;i++)
1008 struct fat_cache_entry *fce = &fat_cache[i];
1009 if(fce->inuse
1010 #ifdef HAVE_MULTIVOLUME
1011 && fce->fat_vol == fat_bpb
1012 #endif
1013 && fce->dirty)
1015 sec = fat_cache_sectors[i];
1016 flush_fat_sector(fce, sec);
1019 mutex_unlock(&cache_mutex);
1021 rc = update_fsinfo(IF_MV(fat_bpb));
1022 if (rc < 0)
1023 return rc * 10 - 3;
1025 return 0;
1028 static void fat_time(unsigned short* date,
1029 unsigned short* time,
1030 unsigned short* tenth )
1032 #if CONFIG_RTC
1033 struct tm* tm = get_time();
1035 if (date)
1036 *date = ((tm->tm_year - 80) << 9) |
1037 ((tm->tm_mon + 1) << 5) |
1038 tm->tm_mday;
1040 if (time)
1041 *time = (tm->tm_hour << 11) |
1042 (tm->tm_min << 5) |
1043 (tm->tm_sec >> 1);
1045 if (tenth)
1046 *tenth = (tm->tm_sec & 1) * 100;
1047 #else
1048 /* non-RTC version returns an increment from the supplied time, or a
1049 * fixed standard time/date if no time given as input */
1051 /* Macros to convert a 2-digit string to a decimal constant.
1052 (YEAR), MONTH and DAY are set by the date command, which outputs
1053 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1054 misinterpretation as an octal constant. */
1055 #define S100(x) 1 ## x
1056 #define C2DIG2DEC(x) (S100(x)-100)
1057 /* The actual build date, as FAT date constant */
1058 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1059 | (C2DIG2DEC(MONTH) << 5) \
1060 | C2DIG2DEC(DAY))
1062 bool date_forced = false;
1063 bool next_day = false;
1064 unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */
1066 if (date && *date < BUILD_DATE_FAT)
1068 *date = BUILD_DATE_FAT;
1069 date_forced = true;
1072 if (time)
1074 time2 = *time << 1;
1075 if (time2 == 0 || date_forced)
1077 time2 = (11 < 6) | 11; /* set to 00:11:11 */
1079 else
1081 unsigned mins = (time2 >> 6) & 0x3f;
1082 unsigned hours = (time2 >> 12) & 0x1f;
1084 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */
1085 if (mins > 59)
1087 mins = 11; /* 00 would be a bad marker */
1088 if (++hours > 23)
1090 hours = 0;
1091 next_day = true;
1094 time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */
1096 *time = time2 >> 1;
1099 if (tenth)
1100 *tenth = (time2 & 1) * 100;
1102 if (date && next_day)
1104 static const unsigned char daysinmonth[] =
1105 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1106 unsigned day = *date & 0x1f;
1107 unsigned month = (*date >> 5) & 0x0f;
1108 unsigned year = (*date >> 9) & 0x7f;
1110 /* simplification: ignore leap years */
1111 if (++day > daysinmonth[month-1])
1113 day = 1;
1114 if (++month > 12)
1116 month = 1;
1117 year++;
1120 *date = (year << 9) | (month << 5) | day;
1123 #endif /* CONFIG_RTC */
1126 static int write_long_name(struct fat_file* file,
1127 unsigned int firstentry,
1128 unsigned int numentries,
1129 const unsigned char* name,
1130 const unsigned char* shortname,
1131 bool is_directory,
1132 unsigned char *sector_buffer)
1134 unsigned char* entry;
1135 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1136 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1137 unsigned char chksum = 0;
1138 unsigned int i, j=0;
1139 unsigned int nameidx=0, namelen = utf8length(name);
1140 int rc;
1141 unsigned short name_utf16[namelen + 1];
1143 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1144 file->firstcluster, firstentry, numentries, name);
1146 rc = fat_seek(file, sector);
1147 if (rc<0)
1148 return rc * 10 - 1;
1150 rc = fat_readwrite(file, 1, sector_buffer, false);
1151 if (rc<1)
1152 return rc * 10 - 2;
1154 /* calculate shortname checksum */
1155 for (i=11; i>0; i--)
1156 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1158 /* calc position of last name segment */
1159 if ( namelen > NAME_BYTES_PER_ENTRY )
1160 for (nameidx=0;
1161 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1162 nameidx += NAME_BYTES_PER_ENTRY);
1164 /* we need to convert the name first */
1165 /* since it is written in reverse order */
1166 for (i = 0; i <= namelen; i++)
1167 name = utf8decode(name, &name_utf16[i]);
1169 for (i=0; i < numentries; i++) {
1170 /* new sector? */
1171 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1172 /* update current sector */
1173 rc = fat_seek(file, sector);
1174 if (rc<0)
1175 return rc * 10 - 3;
1177 rc = fat_readwrite(file, 1, sector_buffer, true);
1178 if (rc<1)
1179 return rc * 10 - 4;
1181 /* read next sector */
1182 rc = fat_readwrite(file, 1, sector_buffer, false);
1183 if (rc<0) {
1184 LDEBUGF("Failed writing new sector: %d\n",rc);
1185 return rc * 10 - 5;
1187 if (rc==0)
1188 /* end of dir */
1189 memset(sector_buffer, 0, SECTOR_SIZE);
1191 sector++;
1192 idx = 0;
1195 entry = sector_buffer + idx * DIR_ENTRY_SIZE;
1197 /* verify this entry is free */
1198 if (entry[0] && entry[0] != 0xe5 )
1199 panicf("Dir entry %d in sector %x is not free! "
1200 "%02x %02x %02x %02x",
1201 idx, sector,
1202 entry[0], entry[1], entry[2], entry[3]);
1204 memset(entry, 0, DIR_ENTRY_SIZE);
1205 if ( i+1 < numentries ) {
1206 /* longname entry */
1207 unsigned int k, l = nameidx;
1209 entry[FATLONG_ORDER] = numentries-i-1;
1210 if (i==0) {
1211 /* mark this as last long entry */
1212 entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1214 /* pad name with 0xffff */
1215 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1216 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1217 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1219 /* set name */
1220 for (k=0; k<5 && l <= namelen; k++) {
1221 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1222 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1224 for (k=0; k<6 && l <= namelen; k++) {
1225 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1226 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1228 for (k=0; k<2 && l <= namelen; k++) {
1229 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1230 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1233 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1234 entry[FATDIR_FSTCLUSLO] = 0;
1235 entry[FATLONG_TYPE] = 0;
1236 entry[FATLONG_CHKSUM] = chksum;
1237 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1239 else {
1240 /* shortname entry */
1241 unsigned short date=0, time=0, tenth=0;
1242 LDEBUGF("Shortname entry: %s\n", shortname);
1243 memcpy(entry + FATDIR_NAME, shortname, 11);
1244 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1245 entry[FATDIR_NTRES] = 0;
1247 fat_time(&date, &time, &tenth);
1248 entry[FATDIR_CRTTIMETENTH] = tenth;
1249 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1250 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1251 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1252 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1253 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1255 idx++;
1256 nameidx -= NAME_BYTES_PER_ENTRY;
1259 /* update last sector */
1260 rc = fat_seek(file, sector);
1261 if (rc<0)
1262 return rc * 10 - 6;
1264 rc = fat_readwrite(file, 1, sector_buffer, true);
1265 if (rc<1)
1266 return rc * 10 - 7;
1268 return 0;
1271 static int fat_checkname(const unsigned char* newname)
1273 static const char invalid_chars[] = "\"*/:<>?\\|";
1274 int len = strlen(newname);
1275 /* More sanity checks are probably needed */
1276 if (len > 255 || newname[len - 1] == '.')
1278 return -1;
1280 while (*newname)
1282 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1283 return -1;
1284 newname++;
1286 /* check trailing space(s) */
1287 if(*(--newname) == ' ')
1288 return -1;
1290 return 0;
1293 static int add_dir_entry(struct fat_dir* dir,
1294 struct fat_file* file,
1295 const char* name,
1296 bool is_directory,
1297 bool dotdir)
1299 #ifdef HAVE_MULTIVOLUME
1300 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1301 #else
1302 struct bpb* fat_bpb = &fat_bpbs[0];
1303 #endif
1304 unsigned char buf[SECTOR_SIZE];
1305 unsigned char shortname[12];
1306 int rc;
1307 unsigned int sector;
1308 bool done = false;
1309 int entries_needed, entries_found = 0;
1310 int firstentry;
1312 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1313 name, file->firstcluster);
1315 /* Don't check dotdirs name for validity */
1316 if (dotdir == false) {
1317 rc = fat_checkname(name);
1318 if (rc < 0) {
1319 /* filename is invalid */
1320 return rc * 10 - 1;
1324 #ifdef HAVE_MULTIVOLUME
1325 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1326 #endif
1328 /* The "." and ".." directory entries must not be long names */
1329 if(dotdir) {
1330 int i;
1331 strlcpy(shortname, name, 12);
1332 for(i = strlen(shortname); i < 12; i++)
1333 shortname[i] = ' ';
1335 entries_needed = 1;
1336 } else {
1337 create_dos_name(name, shortname);
1339 /* one dir entry needed for every 13 bytes of filename,
1340 plus one entry for the short name */
1341 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1342 / NAME_BYTES_PER_ENTRY + 1;
1345 restart:
1346 firstentry = -1;
1348 rc = fat_seek(&dir->file, 0);
1349 if (rc < 0)
1350 return rc * 10 - 2;
1352 /* step 1: search for free entries and check for duplicate shortname */
1353 for (sector = 0; !done; sector++)
1355 unsigned int i;
1357 rc = fat_readwrite(&dir->file, 1, buf, false);
1358 if (rc < 0) {
1359 DEBUGF( "add_dir_entry() - Couldn't read dir"
1360 " (error code %d)\n", rc);
1361 return rc * 10 - 3;
1364 if (rc == 0) { /* current end of dir reached */
1365 LDEBUGF("End of dir on cluster boundary\n");
1366 break;
1369 /* look for free slots */
1370 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1372 switch (buf[i * DIR_ENTRY_SIZE]) {
1373 case 0:
1374 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1375 LDEBUGF("Found end of dir %d\n",
1376 sector * DIR_ENTRIES_PER_SECTOR + i);
1377 i = DIR_ENTRIES_PER_SECTOR - 1;
1378 done = true;
1379 break;
1381 case 0xe5:
1382 entries_found++;
1383 LDEBUGF("Found free entry %d (%d/%d)\n",
1384 sector * DIR_ENTRIES_PER_SECTOR + i,
1385 entries_found, entries_needed);
1386 break;
1388 default:
1389 entries_found = 0;
1391 /* check that our intended shortname doesn't already exist */
1392 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1393 /* shortname exists already, make a new one */
1394 randomize_dos_name(shortname);
1395 LDEBUGF("Duplicate shortname, changing to %s\n",
1396 shortname);
1398 /* name has changed, we need to restart search */
1399 goto restart;
1401 break;
1403 if (firstentry < 0 && (entries_found >= entries_needed))
1404 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1405 - entries_found;
1409 /* step 2: extend the dir if necessary */
1410 if (firstentry < 0)
1412 LDEBUGF("Adding new sector(s) to dir\n");
1413 rc = fat_seek(&dir->file, sector);
1414 if (rc < 0)
1415 return rc * 10 - 4;
1416 memset(buf, 0, sizeof buf);
1418 /* we must clear whole clusters */
1419 for (; (entries_found < entries_needed) ||
1420 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1422 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1423 return -5; /* dir too large -- FAT specification */
1425 rc = fat_readwrite(&dir->file, 1, buf, true);
1426 if (rc < 1) /* No more room or something went wrong */
1427 return rc * 10 - 6;
1429 entries_found += DIR_ENTRIES_PER_SECTOR;
1432 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1435 /* step 3: add entry */
1436 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1437 LDEBUGF("Adding longname to entry %d in sector %d\n",
1438 firstentry, sector);
1440 rc = write_long_name(&dir->file, firstentry,
1441 entries_needed, name,
1442 shortname, is_directory, buf);
1443 if (rc < 0)
1444 return rc * 10 - 7;
1446 /* remember where the shortname dir entry is located */
1447 file->direntry = firstentry + entries_needed - 1;
1448 file->direntries = entries_needed;
1449 file->dircluster = dir->file.firstcluster;
1450 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1451 file->direntry, file->direntries);
1453 return 0;
1456 static unsigned char char2dos(unsigned char c, int* randomize)
1458 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1460 if (c <= 0x20)
1461 c = 0; /* Illegal char, remove */
1462 else if (strchr(invalid_chars, c) != NULL)
1464 /* Illegal char, replace */
1465 c = '_';
1466 *randomize = 1; /* as per FAT spec */
1468 else
1469 c = toupper(c);
1471 return c;
1474 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1476 int i;
1477 unsigned char *ext;
1478 int randomize = 0;
1480 /* Find extension part */
1481 ext = strrchr(name, '.');
1482 if (ext == name) /* handle .dotnames */
1483 ext = NULL;
1485 /* needs to randomize? */
1486 if((ext && (strlen(ext) > 4)) ||
1487 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1488 randomize = 1;
1490 /* Name part */
1491 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1493 unsigned char c = char2dos(*name, &randomize);
1494 if (c)
1495 newname[i++] = c;
1498 /* Pad both name and extension */
1499 while (i < 11)
1500 newname[i++] = ' ';
1502 if (newname[0] == 0xe5) /* Special kanji character */
1503 newname[0] = 0x05;
1505 if (ext)
1506 { /* Extension part */
1507 ext++;
1508 for (i = 8; *ext && (i < 11); ext++)
1510 unsigned char c = char2dos(*ext, &randomize);
1511 if (c)
1512 newname[i++] = c;
1516 if(randomize)
1517 randomize_dos_name(newname);
1520 static void randomize_dos_name(unsigned char *name)
1522 unsigned char* tilde = NULL; /* ~ location */
1523 unsigned char* lastpt = NULL; /* last point of filename */
1524 unsigned char* nameptr = name; /* working copy of name pointer */
1525 unsigned char num[9]; /* holds number as string */
1526 int i = 0;
1527 int cnt = 1;
1528 int numlen;
1529 int offset;
1531 while(i++ < 8)
1533 /* hunt for ~ and where to put it */
1534 if((!tilde) && (*nameptr == '~'))
1535 tilde = nameptr;
1536 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1537 lastpt = nameptr;
1538 nameptr++;
1540 if(tilde)
1542 /* extract current count and increment */
1543 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1544 num[7-(unsigned int)(tilde-name)] = 0;
1545 cnt = atoi(num) + 1;
1547 cnt %= 10000000; /* protection */
1548 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1549 numlen = strlen(num); /* required space */
1550 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1551 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1553 memcpy(&name[offset], num, numlen);
1555 /* in special case of counter overflow: pad with spaces */
1556 for(offset = offset+numlen; offset < 8; offset++)
1557 name[offset] = ' ';
1560 static int update_short_entry( struct fat_file* file, long size, int attr )
1562 unsigned char buf[SECTOR_SIZE];
1563 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1564 unsigned char* entry =
1565 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1566 unsigned long* sizeptr;
1567 unsigned short* clusptr;
1568 struct fat_file dir;
1569 int rc;
1571 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1572 file->firstcluster, file->direntry, size);
1574 /* create a temporary file handle for the dir holding this file */
1575 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1576 if (rc < 0)
1577 return rc * 10 - 1;
1579 rc = fat_seek( &dir, sector );
1580 if (rc<0)
1581 return rc * 10 - 2;
1583 rc = fat_readwrite(&dir, 1, buf, false);
1584 if (rc < 1)
1585 return rc * 10 - 3;
1587 if (!entry[0] || entry[0] == 0xe5)
1588 panicf("Updating size on empty dir entry %d\n", file->direntry);
1590 entry[FATDIR_ATTR] = attr & 0xFF;
1592 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1593 *clusptr = htole16(file->firstcluster >> 16);
1595 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1596 *clusptr = htole16(file->firstcluster & 0xffff);
1598 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1599 *sizeptr = htole32(size);
1602 #if CONFIG_RTC
1603 unsigned short time = 0;
1604 unsigned short date = 0;
1605 #else
1606 /* get old time to increment from */
1607 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1608 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1609 #endif
1610 fat_time(&date, &time, NULL);
1611 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1612 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1613 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1616 rc = fat_seek( &dir, sector );
1617 if (rc < 0)
1618 return rc * 10 - 4;
1620 rc = fat_readwrite(&dir, 1, buf, true);
1621 if (rc < 1)
1622 return rc * 10 - 5;
1624 return 0;
1627 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1629 int i=0,j=0;
1630 unsigned char c;
1631 bool lowercase;
1633 memset(de, 0, sizeof(struct fat_direntry));
1634 de->attr = buf[FATDIR_ATTR];
1635 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1636 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1637 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1638 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1639 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1640 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1641 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1642 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1643 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1644 (the result of the shift is always considered signed) */
1646 /* fix the name */
1647 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1648 c = buf[FATDIR_NAME];
1649 if (c == 0x05) /* special kanji char */
1650 c = 0xe5;
1651 i = 0;
1652 while (c != ' ') {
1653 de->name[j++] = lowercase ? tolower(c) : c;
1654 if (++i >= 8)
1655 break;
1656 c = buf[FATDIR_NAME+i];
1658 if (buf[FATDIR_NAME+8] != ' ') {
1659 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1660 de->name[j++] = '.';
1661 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1662 de->name[j++] = lowercase ? tolower(c) : c;
1664 return 1;
1667 int fat_open(IF_MV2(int volume,)
1668 long startcluster,
1669 struct fat_file *file,
1670 const struct fat_dir* dir)
1672 /* Remember where the file's dir entry is located
1673 * Do it before assigning other fields so that fat_open
1674 * can be called with file == &dir->file (see fat_opendir) */
1675 if ( dir ) {
1676 file->direntry = dir->entry - 1;
1677 file->direntries = dir->entrycount;
1678 file->dircluster = dir->file.firstcluster;
1681 file->firstcluster = startcluster;
1682 file->lastcluster = startcluster;
1683 file->lastsector = 0;
1684 file->clusternum = 0;
1685 file->sectornum = 0;
1686 file->eof = false;
1687 #ifdef HAVE_MULTIVOLUME
1688 file->volume = volume;
1689 /* fixme: remove error check when done */
1690 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1692 LDEBUGF("fat_open() illegal volume %d\n", volume);
1693 return -1;
1695 #endif
1697 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1698 return 0;
1701 int fat_create_file(const char* name,
1702 struct fat_file* file,
1703 struct fat_dir* dir)
1705 int rc;
1707 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1708 rc = add_dir_entry(dir, file, name, false, false);
1709 if (!rc) {
1710 file->firstcluster = 0;
1711 file->lastcluster = 0;
1712 file->lastsector = 0;
1713 file->clusternum = 0;
1714 file->sectornum = 0;
1715 file->eof = false;
1718 return rc;
1721 /* noinline because this is only split out of fat_create_dir to make sure
1722 * the sector buffer doesn't remain on the stack, to avoid nasty stack
1723 * overflows later on (when flush_fat() is called */
1724 static __attribute__((noinline)) int fat_clear_cluster(int sector,
1725 struct bpb *fat_bpb)
1727 unsigned char buf[SECTOR_SIZE];
1728 int i,rc;
1729 memset(buf, 0, sizeof buf);
1730 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1731 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1732 if (rc < 0)
1733 return rc * 10 - 2;
1735 return 0;
1738 int fat_create_dir(const char* name,
1739 struct fat_dir* newdir,
1740 struct fat_dir* dir)
1742 #ifdef HAVE_MULTIVOLUME
1743 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1744 #else
1745 struct bpb* fat_bpb = &fat_bpbs[0];
1746 #endif
1747 long sector;
1748 int rc;
1749 struct fat_file dummyfile;
1751 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1753 memset(newdir, 0, sizeof(struct fat_dir));
1754 memset(&dummyfile, 0, sizeof(struct fat_file));
1756 /* First, add the entry in the parent directory */
1757 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1758 if (rc < 0)
1759 return rc * 10 - 1;
1761 /* Allocate a new cluster for the directory */
1762 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1763 fat_bpb->fsinfo.nextfree);
1764 if(newdir->file.firstcluster == 0)
1765 return -1;
1767 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1769 /* Clear the entire cluster */
1770 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1771 rc = fat_clear_cluster(sector,fat_bpb);
1772 if (rc < 0)
1773 return rc;
1776 /* Then add the "." entry */
1777 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1778 if (rc < 0)
1779 return rc * 10 - 3;
1780 dummyfile.firstcluster = newdir->file.firstcluster;
1781 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1783 /* and the ".." entry */
1784 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1785 if (rc < 0)
1786 return rc * 10 - 4;
1788 /* The root cluster is cluster 0 in the ".." entry */
1789 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1790 dummyfile.firstcluster = 0;
1791 else
1792 dummyfile.firstcluster = dir->file.firstcluster;
1793 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1795 /* Set the firstcluster field in the direntry */
1796 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1798 rc = flush_fat(IF_MV(fat_bpb));
1799 if (rc < 0)
1800 return rc * 10 - 5;
1802 return rc;
1805 int fat_truncate(const struct fat_file *file)
1807 /* truncate trailing clusters */
1808 long next;
1809 long last = file->lastcluster;
1810 #ifdef HAVE_MULTIVOLUME
1811 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1812 #endif
1814 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1816 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1817 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1818 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1820 if (file->lastcluster)
1821 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1823 return 0;
1826 int fat_closewrite(struct fat_file *file, long size, int attr)
1828 int rc;
1829 #ifdef HAVE_MULTIVOLUME
1830 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1831 #endif
1832 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1834 if (!size) {
1835 /* empty file */
1836 if ( file->firstcluster ) {
1837 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1838 file->firstcluster = 0;
1842 if (file->dircluster) {
1843 rc = update_short_entry(file, size, attr);
1844 if (rc < 0)
1845 return rc * 10 - 1;
1848 flush_fat(IF_MV(fat_bpb));
1850 #ifdef TEST_FAT
1851 if ( file->firstcluster ) {
1852 /* debug */
1853 #ifdef HAVE_MULTIVOLUME
1854 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1855 #else
1856 struct bpb* fat_bpb = &fat_bpbs[0];
1857 #endif
1858 long count = 0;
1859 long len;
1860 long next;
1861 for ( next = file->firstcluster; next;
1862 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1863 LDEBUGF("cluster %ld: %lx\n", count, next);
1864 count++;
1866 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1867 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1868 count, len, size );
1869 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1870 panicf("Cluster chain is too long\n");
1871 if ( len < size )
1872 panicf("Cluster chain is too short\n");
1874 #endif
1876 return 0;
1879 static int free_direntries(struct fat_file* file)
1881 unsigned char buf[SECTOR_SIZE];
1882 struct fat_file dir;
1883 int numentries = file->direntries;
1884 unsigned int entry = file->direntry - numentries + 1;
1885 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1886 int i;
1887 int rc;
1889 /* create a temporary file handle for the dir holding this file */
1890 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1891 if (rc < 0)
1892 return rc * 10 - 1;
1894 rc = fat_seek( &dir, sector );
1895 if (rc < 0)
1896 return rc * 10 - 2;
1898 rc = fat_readwrite(&dir, 1, buf, false);
1899 if (rc < 1)
1900 return rc * 10 - 3;
1902 for (i=0; i < numentries; i++) {
1903 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1904 entry, i+1, numentries);
1905 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1906 entry++;
1908 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1909 /* flush this sector */
1910 rc = fat_seek(&dir, sector);
1911 if (rc < 0)
1912 return rc * 10 - 4;
1914 rc = fat_readwrite(&dir, 1, buf, true);
1915 if (rc < 1)
1916 return rc * 10 - 5;
1918 if ( i+1 < numentries ) {
1919 /* read next sector */
1920 rc = fat_readwrite(&dir, 1, buf, false);
1921 if (rc < 1)
1922 return rc * 10 - 6;
1924 sector++;
1928 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1929 /* flush this sector */
1930 rc = fat_seek(&dir, sector);
1931 if (rc < 0)
1932 return rc * 10 - 7;
1934 rc = fat_readwrite(&dir, 1, buf, true);
1935 if (rc < 1)
1936 return rc * 10 - 8;
1939 return 0;
1942 int fat_remove(struct fat_file* file)
1944 long next, last = file->firstcluster;
1945 int rc;
1946 #ifdef HAVE_MULTIVOLUME
1947 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1948 #endif
1950 LDEBUGF("fat_remove(%lx)\n",last);
1952 while ( last ) {
1953 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1954 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1955 last = next;
1958 if ( file->dircluster ) {
1959 rc = free_direntries(file);
1960 if (rc < 0)
1961 return rc * 10 - 1;
1964 file->firstcluster = 0;
1965 file->dircluster = 0;
1967 rc = flush_fat(IF_MV(fat_bpb));
1968 if (rc < 0)
1969 return rc * 10 - 2;
1971 return 0;
1974 int fat_rename(struct fat_file* file,
1975 struct fat_dir* dir,
1976 const unsigned char* newname,
1977 long size,
1978 int attr)
1980 int rc;
1981 struct fat_file olddir_file;
1982 struct fat_file newfile = *file;
1983 unsigned char* entry = NULL;
1984 unsigned short* clusptr = NULL;
1985 unsigned int parentcluster;
1986 #ifdef HAVE_MULTIVOLUME
1987 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1989 if (file->volume != dir->file.volume) {
1990 DEBUGF("No rename across volumes!\n");
1991 return -1;
1993 #else
1994 struct bpb* fat_bpb = &fat_bpbs[0];
1995 #endif
1997 if ( !file->dircluster ) {
1998 DEBUGF("File has no dir cluster!\n");
1999 return -2;
2002 /* create new name */
2003 rc = add_dir_entry(dir, &newfile, newname, false, false);
2004 if (rc < 0)
2005 return rc * 10 - 2;
2007 /* write size and cluster link */
2008 rc = update_short_entry(&newfile, size, attr);
2009 if (rc < 0)
2010 return rc * 10 - 3;
2012 /* remove old name */
2013 rc = free_direntries(file);
2014 if (rc < 0)
2015 return rc * 10 - 4;
2017 rc = flush_fat(IF_MV(fat_bpb));
2018 if (rc < 0)
2019 return rc * 10 - 5;
2021 /* if renaming a directory, update the .. entry to make sure
2022 it points to its parent directory (we don't check if it was a move) */
2023 if(FAT_ATTR_DIRECTORY == attr) {
2024 unsigned char buf[SECTOR_SIZE];
2025 /* open the dir that was renamed, we re-use the olddir_file struct */
2026 rc = fat_open(IF_MV2(file->volume,) newfile.firstcluster, &olddir_file, NULL);
2027 if (rc < 0)
2028 return rc * 10 - 6;
2030 /* get the first sector of the dir */
2031 rc = fat_seek(&olddir_file, 0);
2032 if (rc < 0)
2033 return rc * 10 - 7;
2035 rc = fat_readwrite(&olddir_file, 1, buf, false);
2036 if (rc < 0)
2037 return rc * 10 - 8;
2039 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2040 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2041 parentcluster = 0;
2042 else
2043 parentcluster = dir->file.firstcluster;
2045 entry = buf + DIR_ENTRY_SIZE;
2046 if(strncmp(".. ", entry, 11))
2048 /* .. entry must be second entry according to FAT spec (p.29) */
2049 DEBUGF("Second dir entry is not double-dot!\n");
2050 return rc * 10 - 9;
2052 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2053 *clusptr = htole16(parentcluster >> 16);
2055 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
2056 *clusptr = htole16(parentcluster & 0xffff);
2058 /* write back this sector */
2059 rc = fat_seek(&olddir_file, 0);
2060 if (rc < 0)
2061 return rc * 10 - 7;
2063 rc = fat_readwrite(&olddir_file, 1, buf, true);
2064 if (rc < 1)
2065 return rc * 10 - 8;
2068 return 0;
2071 static long next_write_cluster(struct fat_file* file,
2072 long oldcluster,
2073 long* newsector)
2075 #ifdef HAVE_MULTIVOLUME
2076 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2077 #else
2078 struct bpb* fat_bpb = &fat_bpbs[0];
2079 #endif
2080 long cluster = 0;
2081 long sector;
2083 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2085 if (oldcluster)
2086 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2088 if (!cluster) {
2089 if (oldcluster > 0)
2090 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2091 else if (oldcluster == 0)
2092 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2093 fat_bpb->fsinfo.nextfree);
2094 #ifdef HAVE_FAT16SUPPORT
2095 else /* negative, pseudo-cluster of the root dir */
2096 return 0; /* impossible to append something to the root */
2097 #endif
2099 if (cluster) {
2100 if (oldcluster)
2101 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2102 else
2103 file->firstcluster = cluster;
2104 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2106 else {
2107 #ifdef TEST_FAT
2108 if (fat_bpb->fsinfo.freecount>0)
2109 panicf("There is free space, but find_free_cluster() "
2110 "didn't find it!\n");
2111 #endif
2112 DEBUGF("next_write_cluster(): Disk full!\n");
2113 return 0;
2116 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2117 if (sector<0)
2118 return 0;
2120 *newsector = sector;
2121 return cluster;
2124 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2125 unsigned long start, long count, char* buf, bool write )
2127 #ifndef HAVE_MULTIVOLUME
2128 struct bpb* fat_bpb = &fat_bpbs[0];
2129 #endif
2130 int rc;
2132 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2133 start+ fat_bpb->startsector, count, write?"write":"read");
2134 if (write) {
2135 unsigned long firstallowed;
2136 #ifdef HAVE_FAT16SUPPORT
2137 if (fat_bpb->is_fat16)
2138 firstallowed = fat_bpb->rootdirsector;
2139 else
2140 #endif
2141 firstallowed = fat_bpb->firstdatasector;
2143 if (start < firstallowed)
2144 panicf("Write %ld before data\n", firstallowed - start);
2145 if (start + count > fat_bpb->totalsectors)
2146 panicf("Write %ld after data\n",
2147 start + count - fat_bpb->totalsectors);
2148 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2149 start + fat_bpb->startsector, count, buf);
2151 else
2152 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2153 start + fat_bpb->startsector, count, buf);
2154 if (rc < 0) {
2155 DEBUGF( "transfer() - Couldn't %s sector %lx"
2156 " (error code %d)\n",
2157 write ? "write":"read", start, rc);
2158 return rc;
2160 return 0;
2164 long fat_readwrite( struct fat_file *file, long sectorcount,
2165 void* buf, bool write )
2167 #ifdef HAVE_MULTIVOLUME
2168 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2169 #else
2170 struct bpb* fat_bpb = &fat_bpbs[0];
2171 #endif
2172 long cluster = file->lastcluster;
2173 long sector = file->lastsector;
2174 long clusternum = file->clusternum;
2175 long numsec = file->sectornum;
2176 bool eof = file->eof;
2177 long first=0, last=0;
2178 long i;
2179 int rc;
2181 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2182 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2183 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2184 sector,numsec, eof?1:0);
2186 if ( eof && !write)
2187 return 0;
2189 /* find sequential sectors and write them all at once */
2190 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2191 numsec++;
2192 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2193 long oldcluster = cluster;
2194 long oldsector = sector;
2195 long oldnumsec = numsec;
2196 if (write)
2197 cluster = next_write_cluster(file, cluster, &sector);
2198 else {
2199 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2200 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2203 clusternum++;
2204 numsec=1;
2206 if (!cluster) {
2207 eof = true;
2208 if ( write ) {
2209 /* remember last cluster, in case
2210 we want to append to the file */
2211 sector = oldsector;
2212 cluster = oldcluster;
2213 numsec = oldnumsec;
2214 clusternum--;
2215 i = -1; /* Error code */
2216 break;
2219 else
2220 eof = false;
2222 else {
2223 if (sector)
2224 sector++;
2225 else {
2226 /* look up first sector of file */
2227 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2228 numsec=1;
2229 #ifdef HAVE_FAT16SUPPORT
2230 if (file->firstcluster < 0)
2231 { /* FAT16 root dir */
2232 sector += fat_bpb->rootdiroffset;
2233 numsec += fat_bpb->rootdiroffset;
2235 #endif
2239 if (!first)
2240 first = sector;
2242 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2243 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2244 long count = last - first + 1;
2245 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2246 if (rc < 0)
2247 return rc * 10 - 1;
2249 buf = (char *)buf + count * SECTOR_SIZE;
2250 first = sector;
2253 if ((i == sectorcount-1) && /* last sector requested */
2254 (!eof))
2256 long count = sector - first + 1;
2257 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2258 if (rc < 0)
2259 return rc * 10 - 2;
2262 last = sector;
2265 file->lastcluster = cluster;
2266 file->lastsector = sector;
2267 file->clusternum = clusternum;
2268 file->sectornum = numsec;
2269 file->eof = eof;
2271 /* if eof, don't report last block as read/written */
2272 if (eof)
2273 i--;
2275 DEBUGF("Sectors written: %ld\n", i);
2276 return i;
2279 int fat_seek(struct fat_file *file, unsigned long seeksector )
2281 #ifdef HAVE_MULTIVOLUME
2282 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2283 #else
2284 struct bpb* fat_bpb = &fat_bpbs[0];
2285 #endif
2286 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2287 long cluster = file->firstcluster;
2288 long i;
2290 #ifdef HAVE_FAT16SUPPORT
2291 if (cluster < 0) /* FAT16 root dir */
2292 seeksector += fat_bpb->rootdiroffset;
2293 #endif
2295 file->eof = false;
2296 if (seeksector) {
2297 /* we need to find the sector BEFORE the requested, since
2298 the file struct stores the last accessed sector */
2299 seeksector--;
2300 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2301 sectornum = seeksector % fat_bpb->bpb_secperclus;
2303 if (file->clusternum && clusternum >= file->clusternum)
2305 cluster = file->lastcluster;
2306 numclusters -= file->clusternum;
2309 for (i=0; i<numclusters; i++) {
2310 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2311 if (!cluster) {
2312 DEBUGF("Seeking beyond the end of the file! "
2313 "(sector %ld, cluster %ld)\n", seeksector, i);
2314 return -1;
2318 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2320 else {
2321 sectornum = -1;
2324 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2325 file->firstcluster, seeksector, cluster, sector, sectornum);
2327 file->lastcluster = cluster;
2328 file->lastsector = sector;
2329 file->clusternum = clusternum;
2330 file->sectornum = sectornum + 1;
2331 return 0;
2334 int fat_opendir(IF_MV2(int volume,)
2335 struct fat_dir *dir, unsigned long startcluster,
2336 const struct fat_dir *parent_dir)
2338 #ifdef HAVE_MULTIVOLUME
2339 struct bpb* fat_bpb = &fat_bpbs[volume];
2340 /* fixme: remove error check when done */
2341 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2343 LDEBUGF("fat_open() illegal volume %d\n", volume);
2344 return -1;
2346 #else
2347 struct bpb* fat_bpb = &fat_bpbs[0];
2348 #endif
2349 int rc;
2351 if (startcluster == 0)
2352 startcluster = fat_bpb->bpb_rootclus;
2354 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2355 if(rc)
2357 DEBUGF( "fat_opendir() - Couldn't open dir"
2358 " (error code %d)\n", rc);
2359 return rc * 10 - 1;
2362 /* assign them after fat_open call so that fat_opendir can be called with the same
2363 * fat_dir as parent and result */
2364 dir->entry = 0;
2365 dir->sector = 0;
2367 return 0;
2370 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2372 bool done = false;
2373 int i, j;
2374 int rc;
2375 int order;
2376 unsigned char firstbyte;
2377 /* Long file names are stored in special entries. Each entry holds
2378 up to 13 characters. Names can be max 255 chars (not bytes!) long */
2379 /* The number of long entries in the long name can be retrieve from the first
2380 * long entry because there are stored in reverse order and have an ordinal */
2381 int nb_longs = 0;
2382 /* The long entries are expected to be in order, so remember the last ordinal */
2383 int last_long_ord = 0;
2385 dir->entrycount = 0;
2387 while(!done)
2389 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2391 rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2392 if (rc == 0) {
2393 /* eof */
2394 entry->name[0] = 0;
2395 break;
2397 if (rc < 0) {
2398 DEBUGF( "fat_getnext() - Couldn't read dir"
2399 " (error code %d)\n", rc);
2400 return rc * 10 - 1;
2402 dir->sector = dir->file.lastsector;
2405 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2406 i < DIR_ENTRIES_PER_SECTOR; i++) {
2407 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2409 firstbyte = dir->sectorcache[entrypos];
2410 dir->entry++;
2412 if (firstbyte == 0xe5) {
2413 /* free entry */
2414 dir->entrycount = 0;
2415 continue;
2418 if (firstbyte == 0) {
2419 /* last entry */
2420 entry->name[0] = 0;
2421 dir->entrycount = 0;
2422 return 0;
2425 dir->entrycount++;
2427 /* LFN entry? */
2428 if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2429 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2430 /* extract ordinal */
2431 order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2432 /* is this entry the first long entry ? (first in order but containing last part) */
2433 if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2434 /* check that order is not too big ! (and non-zero) */
2435 if(order <= 0 || order > FATLONG_MAX_ORDER)
2436 continue; /* ignore the whole LFN, will trigger lots of warnings */
2437 nb_longs = order;
2438 last_long_ord = order;
2440 else {
2441 /* check orphan entry */
2442 if (nb_longs == 0) {
2443 logf("fat warning: orphan LFN entry");
2444 /* ignore */
2445 continue;
2448 /* check order */
2449 if (order != (last_long_ord - 1)) {
2450 logf("fat warning: wrong LFN ordinal");
2451 /* ignore the whole LFN, will trigger lots of warnings */
2452 nb_longs = 0;
2455 last_long_ord = order;
2458 /* copy part, reuse [order] for another purpose :) */
2459 order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2460 for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2461 memcpy(dir->longname + order,
2462 dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2463 FATLONG_NAME_SIZE[j]);
2464 order += FATLONG_NAME_SIZE[j];
2467 else {
2468 if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2470 /* don't return volume id entry */
2471 if ( (entry->attr &
2472 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2473 == FAT_ATTR_VOLUME_ID)
2474 continue;
2476 /* replace shortname with longname? */
2477 /* check that the long name is complete */
2478 if (nb_longs != 0 && last_long_ord == 1) {
2479 /* hold a copy of the shortname in case the long one is too long */
2480 unsigned char shortname[13]; /* 8+3+dot+\0 */
2481 int longname_utf8len = 0;
2482 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2483 * of a UTF8 encoded character in rockbox */
2484 unsigned char longname_utf8segm[4 + 1];
2485 unsigned short ucs;
2486 int segm_utf8len;
2487 /* Temporarily store short name */
2488 strcpy(shortname, entry->name);
2489 entry->name[0] = 0;
2491 /* Convert the FAT name to a utf8-encoded one.
2492 * The name is not necessary NUL-terminated ! */
2493 for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2494 ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2495 if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2496 break;
2497 /* utf8encode will return a pointer after the converted
2498 * string, subtract the pointer to the start to get the length of it */
2499 segm_utf8len = utf8encode(ucs, longname_utf8segm) - longname_utf8segm;
2501 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2502 if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2503 /* force use of short name */
2504 longname_utf8len = FAT_FILENAME_BYTES + 1;
2505 break; /* fallback later */
2507 else {
2508 longname_utf8segm[segm_utf8len] = 0;
2509 strcat(entry->name + longname_utf8len, longname_utf8segm);
2510 longname_utf8len += segm_utf8len;
2514 /* Does the utf8-encoded name fit into the entry? */
2515 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2516 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2517 /* Take the short DOS name. Need to utf8-encode it
2518 since it may contain chars from the upper half of
2519 the OEM code page which wouldn't be a valid utf8.
2520 Beware: this file will be shown with strange
2521 glyphs in file browser since unicode 0x80 to 0x9F
2522 are control characters. */
2523 logf("SN-DOS: %s", shortname);
2524 unsigned char *utf8;
2525 utf8 = iso_decode(shortname, entry->name, -1,
2526 strlen(shortname));
2527 *utf8 = 0;
2528 logf("SN: %s", entry->name);
2529 } else {
2530 logf("LN: %s", entry->name);
2531 logf("LNLen: %d", longname_utf8len);
2534 done = true;
2535 i++;
2536 break;
2541 return 0;
2544 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2546 #ifndef HAVE_MULTIVOLUME
2547 const int volume = 0;
2548 #endif
2549 struct bpb* fat_bpb = &fat_bpbs[volume];
2550 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2553 #ifdef HAVE_MULTIVOLUME
2554 bool fat_ismounted(int volume)
2556 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2558 #endif