Trim down peak calculation a bit.
[kugel-rb.git] / firmware / drivers / fat.c
blobf93b32f83283a4e248cdec35efd9cec6ec6f8804
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 int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
301 #ifndef HAVE_MULTIVOLUME
302 const int volume = 0;
303 #endif
304 struct bpb* fat_bpb = &fat_bpbs[volume];
305 unsigned char buf[SECTOR_SIZE];
306 int rc;
307 int secmult;
308 long datasec;
309 #ifdef HAVE_FAT16SUPPORT
310 int rootdirsectors;
311 #endif
313 /* Read the sector */
314 rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
315 if(rc)
317 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
318 return rc * 10 - 1;
321 memset(fat_bpb, 0, sizeof(struct bpb));
322 fat_bpb->startsector = startsector;
323 #ifdef HAVE_MULTIDRIVE
324 fat_bpb->drive = drive;
325 #endif
327 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
328 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
329 /* Sanity check is performed later */
331 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
332 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
333 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
334 fat_bpb->bpb_media = buf[BPB_MEDIA];
335 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
336 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
337 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
338 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
339 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
341 /* calculate a few commonly used values */
342 if (fat_bpb->bpb_fatsz16 != 0)
343 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
344 else
345 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
347 if (fat_bpb->bpb_totsec16 != 0)
348 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
349 else
350 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
352 #ifdef HAVE_FAT16SUPPORT
353 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
354 if (!fat_bpb->bpb_bytspersec)
355 return -2;
356 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
357 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
358 #endif /* #ifdef HAVE_FAT16SUPPORT */
360 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
361 #ifdef HAVE_FAT16SUPPORT
362 + rootdirsectors
363 #endif
364 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
366 /* Determine FAT type */
367 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
368 if (fat_bpb->bpb_secperclus)
369 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
370 else
371 return -2;
373 #ifdef TEST_FAT
375 we are sometimes testing with "illegally small" fat32 images,
376 so we don't use the proper fat32 test case for test code
378 if ( fat_bpb->bpb_fatsz16 )
379 #else
380 if ( fat_bpb->dataclusters < 65525 )
381 #endif
382 { /* FAT16 */
383 #ifdef HAVE_FAT16SUPPORT
384 fat_bpb->is_fat16 = true;
385 if (fat_bpb->dataclusters < 4085)
386 { /* FAT12 */
387 DEBUGF("This is FAT12. Go away!\n");
388 return -2;
390 #else /* #ifdef HAVE_FAT16SUPPORT */
391 DEBUGF("This is not FAT32. Go away!\n");
392 return -2;
393 #endif /* #ifndef HAVE_FAT16SUPPORT */
396 #ifdef HAVE_FAT16SUPPORT
397 if (fat_bpb->is_fat16)
398 { /* FAT16 specific part of BPB */
399 int dirclusters;
400 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
401 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
402 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
403 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
404 /* I assign negative pseudo cluster numbers for the root directory,
405 their range is counted upward until -1. */
406 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
407 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
408 - rootdirsectors;
410 else
411 #endif /* #ifdef HAVE_FAT16SUPPORT */
412 { /* FAT32 specific part of BPB */
413 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
414 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
415 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
416 fat_bpb->bpb_rootclus);
419 rc = bpb_is_sane(IF_MV(fat_bpb));
420 if (rc < 0)
422 DEBUGF( "fat_mount() - BPB is not sane\n");
423 return rc * 10 - 3;
426 #ifdef HAVE_FAT16SUPPORT
427 if (fat_bpb->is_fat16)
429 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
430 fat_bpb->fsinfo.nextfree = 0xffffffff;
432 else
433 #endif /* #ifdef HAVE_FAT16SUPPORT */
435 /* Read the fsinfo sector */
436 rc = storage_read_sectors(IF_MD2(drive,)
437 startsector + fat_bpb->bpb_fsinfo, 1, buf);
438 if (rc < 0)
440 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
441 return rc * 10 - 4;
443 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
444 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
447 /* calculate freecount if unset */
448 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
450 fat_recalc_free(IF_MV(volume));
453 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
454 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
455 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
456 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
457 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
459 #ifdef HAVE_MULTIVOLUME
460 fat_bpb->mounted = true;
461 #endif
463 return 0;
466 #ifdef HAVE_HOTSWAP
467 int fat_unmount(int volume, bool flush)
469 int rc;
470 #ifdef HAVE_MULTIVOLUME
471 struct bpb* fat_bpb = &fat_bpbs[volume];
472 #else
473 (void)volume;
474 #endif
476 if(flush)
478 rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
480 else
481 { /* volume is not accessible any more, e.g. MMC removed */
482 int i;
483 mutex_lock(&cache_mutex);
484 for(i = 0;i < FAT_CACHE_SIZE;i++)
486 struct fat_cache_entry *fce = &fat_cache[i];
487 if(fce->inuse
488 #ifdef HAVE_MULTIVOLUME
489 && fce->fat_vol == fat_bpb
490 #endif
493 fce->inuse = false; /* discard all from that volume */
494 fce->dirty = false;
497 mutex_unlock(&cache_mutex);
498 rc = 0;
500 #ifdef HAVE_MULTIVOLUME
501 fat_bpb->mounted = false;
502 #endif
503 return rc;
505 #endif /* #ifdef HAVE_HOTSWAP */
507 void fat_recalc_free(IF_MV_NONVOID(int volume))
509 #ifndef HAVE_MULTIVOLUME
510 const int volume = 0;
511 #endif
512 struct bpb* fat_bpb = &fat_bpbs[volume];
513 long free = 0;
514 unsigned long i;
515 #ifdef HAVE_FAT16SUPPORT
516 if (fat_bpb->is_fat16)
518 for (i = 0; i<fat_bpb->fatsize; i++) {
519 unsigned int j;
520 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
521 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
522 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
523 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
524 break;
526 if (letoh16(fat[j]) == 0x0000) {
527 free++;
528 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
529 fat_bpb->fsinfo.nextfree = c;
534 else
535 #endif /* #ifdef HAVE_FAT16SUPPORT */
537 for (i = 0; i<fat_bpb->fatsize; i++) {
538 unsigned int j;
539 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
540 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
541 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
542 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
543 break;
545 if (!(letoh32(fat[j]) & 0x0fffffff)) {
546 free++;
547 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
548 fat_bpb->fsinfo.nextfree = c;
553 fat_bpb->fsinfo.freecount = free;
554 update_fsinfo(IF_MV(fat_bpb));
557 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
559 #ifndef HAVE_MULTIVOLUME
560 struct bpb* fat_bpb = &fat_bpbs[0];
561 #endif
562 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
564 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
565 fat_bpb->bpb_bytspersec);
566 return -1;
568 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
569 > 128L*1024L)
571 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
572 "(%d * %d = %d)\n",
573 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
574 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
575 return -2;
577 if(fat_bpb->bpb_numfats != 2)
579 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
580 fat_bpb->bpb_numfats);
582 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
584 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
585 "media type (0x%02x)\n",
586 fat_bpb->bpb_media);
588 if(fat_bpb->last_word != 0xaa55)
590 DEBUGF( "bpb_is_sane() - Error: Last word is not "
591 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
592 return -3;
595 if (fat_bpb->fsinfo.freecount >
596 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
597 fat_bpb->bpb_secperclus)
599 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
600 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
601 return -4;
604 return 0;
607 static void flush_fat_sector(struct fat_cache_entry *fce,
608 unsigned char *sectorbuf)
610 int rc;
611 long secnum;
613 /* With multivolume, use only the FAT info from the cached sector! */
614 #ifdef HAVE_MULTIVOLUME
615 secnum = fce->secnum + fce->fat_vol->startsector;
616 #else
617 secnum = fce->secnum + fat_bpbs[0].startsector;
618 #endif
620 /* Write to the first FAT */
621 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
622 secnum, 1,
623 sectorbuf);
624 if(rc < 0)
626 panicf("flush_fat_sector() - Could not write sector %ld"
627 " (error %d)\n",
628 secnum, rc);
630 #ifdef HAVE_MULTIVOLUME
631 if(fce->fat_vol->bpb_numfats > 1)
632 #else
633 if(fat_bpbs[0].bpb_numfats > 1)
634 #endif
636 /* Write to the second FAT */
637 #ifdef HAVE_MULTIVOLUME
638 secnum += fce->fat_vol->fatsize;
639 #else
640 secnum += fat_bpbs[0].fatsize;
641 #endif
642 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
643 secnum, 1, sectorbuf);
644 if(rc < 0)
646 panicf("flush_fat_sector() - Could not write sector %ld"
647 " (error %d)\n",
648 secnum, rc);
651 fce->dirty = false;
654 /* Note: The returned pointer is only safely valid until the next
655 task switch! (Any subsequent ata read/write may yield.) */
656 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
657 long fatsector, bool dirty)
659 #ifndef HAVE_MULTIVOLUME
660 struct bpb* fat_bpb = &fat_bpbs[0];
661 #endif
662 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
663 int cache_index = secnum & FAT_CACHE_MASK;
664 struct fat_cache_entry *fce = &fat_cache[cache_index];
665 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
666 int rc;
668 mutex_lock(&cache_mutex); /* make changes atomic */
670 /* Delete the cache entry if it isn't the sector we want */
671 if(fce->inuse && (fce->secnum != secnum
672 #ifdef HAVE_MULTIVOLUME
673 || fce->fat_vol != fat_bpb
674 #endif
677 /* Write back if it is dirty */
678 if(fce->dirty)
680 flush_fat_sector(fce, sectorbuf);
682 fce->inuse = false;
685 /* Load the sector if it is not cached */
686 if(!fce->inuse)
688 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
689 secnum + fat_bpb->startsector,1,
690 sectorbuf);
691 if(rc < 0)
693 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
694 " (error %d)\n", secnum, rc);
695 mutex_unlock(&cache_mutex);
696 return NULL;
698 fce->inuse = true;
699 fce->secnum = secnum;
700 #ifdef HAVE_MULTIVOLUME
701 fce->fat_vol = fat_bpb;
702 #endif
704 if (dirty)
705 fce->dirty = true; /* dirt remains, sticky until flushed */
706 mutex_unlock(&cache_mutex);
707 return sectorbuf;
710 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
711 unsigned long startcluster)
713 #ifndef HAVE_MULTIVOLUME
714 struct bpb* fat_bpb = &fat_bpbs[0];
715 #endif
716 unsigned long sector;
717 unsigned long offset;
718 unsigned long i;
720 #ifdef HAVE_FAT16SUPPORT
721 if (fat_bpb->is_fat16)
723 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
724 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
726 for (i = 0; i<fat_bpb->fatsize; i++) {
727 unsigned int j;
728 unsigned int nr = (i + sector) % fat_bpb->fatsize;
729 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
730 if ( !fat )
731 break;
732 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
733 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
734 if (letoh16(fat[k]) == 0x0000) {
735 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
736 /* Ignore the reserved clusters 0 & 1, and also
737 cluster numbers out of bounds */
738 if ( c < 2 || c > fat_bpb->dataclusters+1 )
739 continue;
740 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
741 fat_bpb->fsinfo.nextfree = c;
742 return c;
745 offset = 0;
748 else
749 #endif /* #ifdef HAVE_FAT16SUPPORT */
751 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
752 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
754 for (i = 0; i<fat_bpb->fatsize; i++) {
755 unsigned int j;
756 unsigned long nr = (i + sector) % fat_bpb->fatsize;
757 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
758 if ( !fat )
759 break;
760 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
761 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
762 if (!(letoh32(fat[k]) & 0x0fffffff)) {
763 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
764 /* Ignore the reserved clusters 0 & 1, and also
765 cluster numbers out of bounds */
766 if ( c < 2 || c > fat_bpb->dataclusters+1 )
767 continue;
768 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
769 fat_bpb->fsinfo.nextfree = c;
770 return c;
773 offset = 0;
777 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
778 return 0; /* 0 is an illegal cluster number */
781 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
782 unsigned long val)
784 #ifndef HAVE_MULTIVOLUME
785 struct bpb* fat_bpb = &fat_bpbs[0];
786 #endif
787 #ifdef HAVE_FAT16SUPPORT
788 if (fat_bpb->is_fat16)
790 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
791 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
792 unsigned short* sec;
794 val &= 0xFFFF;
796 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
798 if (entry==val)
799 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
801 if ( entry < 2 )
802 panicf("Updating reserved FAT entry %ld.\n",entry);
804 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
805 if (!sec)
807 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
808 return -1;
811 if ( val ) {
812 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
813 fat_bpb->fsinfo.freecount--;
815 else {
816 if (letoh16(sec[offset]))
817 fat_bpb->fsinfo.freecount++;
820 LDEBUGF("update_fat_entry: %d free clusters\n",
821 fat_bpb->fsinfo.freecount);
823 sec[offset] = htole16(val);
825 else
826 #endif /* #ifdef HAVE_FAT16SUPPORT */
828 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
829 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
830 unsigned long* sec;
832 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
834 if (entry==val)
835 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
837 if ( entry < 2 )
838 panicf("Updating reserved FAT entry %ld.\n",entry);
840 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
841 if (!sec)
843 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
844 return -1;
847 if ( val ) {
848 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
849 fat_bpb->fsinfo.freecount > 0)
850 fat_bpb->fsinfo.freecount--;
852 else {
853 if (letoh32(sec[offset]) & 0x0fffffff)
854 fat_bpb->fsinfo.freecount++;
857 LDEBUGF("update_fat_entry: %ld free clusters\n",
858 fat_bpb->fsinfo.freecount);
860 /* don't change top 4 bits */
861 sec[offset] &= htole32(0xf0000000);
862 sec[offset] |= htole32(val & 0x0fffffff);
865 return 0;
868 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
870 #ifdef HAVE_FAT16SUPPORT
871 #ifndef HAVE_MULTIVOLUME
872 struct bpb* fat_bpb = &fat_bpbs[0];
873 #endif
874 if (fat_bpb->is_fat16)
876 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
877 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
878 unsigned short* sec;
880 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
881 if (!sec)
883 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
884 return -1;
887 return letoh16(sec[offset]);
889 else
890 #endif /* #ifdef HAVE_FAT16SUPPORT */
892 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
893 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
894 unsigned long* sec;
896 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
897 if (!sec)
899 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
900 return -1;
903 return letoh32(sec[offset]) & 0x0fffffff;
907 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
909 long next_cluster;
910 long eof_mark = FAT_EOF_MARK;
912 #ifdef HAVE_FAT16SUPPORT
913 #ifndef HAVE_MULTIVOLUME
914 struct bpb* fat_bpb = &fat_bpbs[0];
915 #endif
916 if (fat_bpb->is_fat16)
918 eof_mark &= 0xFFFF; /* only 16 bit */
919 if (cluster < 0) /* FAT16 root dir */
920 return cluster + 1; /* don't use the FAT */
922 #endif
923 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
925 /* is this last cluster in chain? */
926 if ( next_cluster >= eof_mark )
927 return 0;
928 else
929 return next_cluster;
932 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
934 #ifndef HAVE_MULTIVOLUME
935 struct bpb* fat_bpb = &fat_bpbs[0];
936 #endif
937 unsigned char fsinfo[SECTOR_SIZE];
938 unsigned long* intptr;
939 int rc;
941 #ifdef HAVE_FAT16SUPPORT
942 if (fat_bpb->is_fat16)
943 return 0; /* FAT16 has no FsInfo */
944 #endif /* #ifdef HAVE_FAT16SUPPORT */
946 /* update fsinfo */
947 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
948 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
949 if (rc < 0)
951 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
952 return rc * 10 - 1;
954 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
955 *intptr = htole32(fat_bpb->fsinfo.freecount);
957 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
958 *intptr = htole32(fat_bpb->fsinfo.nextfree);
960 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
961 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
962 if (rc < 0)
964 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
965 return rc * 10 - 2;
968 return 0;
971 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
973 int i;
974 int rc;
975 unsigned char *sec;
976 LDEBUGF("flush_fat()\n");
978 mutex_lock(&cache_mutex);
979 for(i = 0;i < FAT_CACHE_SIZE;i++)
981 struct fat_cache_entry *fce = &fat_cache[i];
982 if(fce->inuse
983 #ifdef HAVE_MULTIVOLUME
984 && fce->fat_vol == fat_bpb
985 #endif
986 && fce->dirty)
988 sec = fat_cache_sectors[i];
989 flush_fat_sector(fce, sec);
992 mutex_unlock(&cache_mutex);
994 rc = update_fsinfo(IF_MV(fat_bpb));
995 if (rc < 0)
996 return rc * 10 - 3;
998 return 0;
1001 static void fat_time(unsigned short* date,
1002 unsigned short* time,
1003 unsigned short* tenth )
1005 #if CONFIG_RTC
1006 struct tm* tm = get_time();
1008 if (date)
1009 *date = ((tm->tm_year - 80) << 9) |
1010 ((tm->tm_mon + 1) << 5) |
1011 tm->tm_mday;
1013 if (time)
1014 *time = (tm->tm_hour << 11) |
1015 (tm->tm_min << 5) |
1016 (tm->tm_sec >> 1);
1018 if (tenth)
1019 *tenth = (tm->tm_sec & 1) * 100;
1020 #else
1021 /* non-RTC version returns an increment from the supplied time, or a
1022 * fixed standard time/date if no time given as input */
1024 /* Macros to convert a 2-digit string to a decimal constant.
1025 (YEAR), MONTH and DAY are set by the date command, which outputs
1026 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1027 misinterpretation as an octal constant. */
1028 #define S100(x) 1 ## x
1029 #define C2DIG2DEC(x) (S100(x)-100)
1030 /* The actual build date, as FAT date constant */
1031 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1032 | (C2DIG2DEC(MONTH) << 5) \
1033 | C2DIG2DEC(DAY))
1035 bool date_forced = false;
1036 bool next_day = false;
1037 unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */
1039 if (date && *date < BUILD_DATE_FAT)
1041 *date = BUILD_DATE_FAT;
1042 date_forced = true;
1045 if (time)
1047 time2 = *time << 1;
1048 if (time2 == 0 || date_forced)
1050 time2 = (11 < 6) | 11; /* set to 00:11:11 */
1052 else
1054 unsigned mins = (time2 >> 6) & 0x3f;
1055 unsigned hours = (time2 >> 12) & 0x1f;
1057 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */
1058 if (mins > 59)
1060 mins = 11; /* 00 would be a bad marker */
1061 if (++hours > 23)
1063 hours = 0;
1064 next_day = true;
1067 time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */
1069 *time = time2 >> 1;
1072 if (tenth)
1073 *tenth = (time2 & 1) * 100;
1075 if (date && next_day)
1077 static const unsigned char daysinmonth[] =
1078 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1079 unsigned day = *date & 0x1f;
1080 unsigned month = (*date >> 5) & 0x0f;
1081 unsigned year = (*date >> 9) & 0x7f;
1083 /* simplification: ignore leap years */
1084 if (++day > daysinmonth[month-1])
1086 day = 1;
1087 if (++month > 12)
1089 month = 1;
1090 year++;
1093 *date = (year << 9) | (month << 5) | day;
1096 #endif /* CONFIG_RTC */
1099 static int write_long_name(struct fat_file* file,
1100 unsigned int firstentry,
1101 unsigned int numentries,
1102 const unsigned char* name,
1103 const unsigned char* shortname,
1104 bool is_directory)
1106 unsigned char buf[SECTOR_SIZE];
1107 unsigned char* entry;
1108 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1109 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1110 unsigned char chksum = 0;
1111 unsigned int i, j=0;
1112 unsigned int nameidx=0, namelen = utf8length(name);
1113 int rc;
1114 unsigned short name_utf16[namelen + 1];
1116 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1117 file->firstcluster, firstentry, numentries, name);
1119 rc = fat_seek(file, sector);
1120 if (rc<0)
1121 return rc * 10 - 1;
1123 rc = fat_readwrite(file, 1, buf, false);
1124 if (rc<1)
1125 return rc * 10 - 2;
1127 /* calculate shortname checksum */
1128 for (i=11; i>0; i--)
1129 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1131 /* calc position of last name segment */
1132 if ( namelen > NAME_BYTES_PER_ENTRY )
1133 for (nameidx=0;
1134 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1135 nameidx += NAME_BYTES_PER_ENTRY);
1137 /* we need to convert the name first */
1138 /* since it is written in reverse order */
1139 for (i = 0; i <= namelen; i++)
1140 name = utf8decode(name, &name_utf16[i]);
1142 for (i=0; i < numentries; i++) {
1143 /* new sector? */
1144 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1145 /* update current sector */
1146 rc = fat_seek(file, sector);
1147 if (rc<0)
1148 return rc * 10 - 3;
1150 rc = fat_readwrite(file, 1, buf, true);
1151 if (rc<1)
1152 return rc * 10 - 4;
1154 /* read next sector */
1155 rc = fat_readwrite(file, 1, buf, false);
1156 if (rc<0) {
1157 LDEBUGF("Failed writing new sector: %d\n",rc);
1158 return rc * 10 - 5;
1160 if (rc==0)
1161 /* end of dir */
1162 memset(buf, 0, sizeof buf);
1164 sector++;
1165 idx = 0;
1168 entry = buf + idx * DIR_ENTRY_SIZE;
1170 /* verify this entry is free */
1171 if (entry[0] && entry[0] != 0xe5 )
1172 panicf("Dir entry %d in sector %x is not free! "
1173 "%02x %02x %02x %02x",
1174 idx, sector,
1175 entry[0], entry[1], entry[2], entry[3]);
1177 memset(entry, 0, DIR_ENTRY_SIZE);
1178 if ( i+1 < numentries ) {
1179 /* longname entry */
1180 unsigned int k, l = nameidx;
1182 entry[FATLONG_ORDER] = numentries-i-1;
1183 if (i==0) {
1184 /* mark this as last long entry */
1185 entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1187 /* pad name with 0xffff */
1188 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1189 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1190 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1192 /* set name */
1193 for (k=0; k<5 && l <= namelen; k++) {
1194 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1195 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1197 for (k=0; k<6 && l <= namelen; k++) {
1198 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1199 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1201 for (k=0; k<2 && l <= namelen; k++) {
1202 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1203 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1206 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1207 entry[FATDIR_FSTCLUSLO] = 0;
1208 entry[FATLONG_TYPE] = 0;
1209 entry[FATLONG_CHKSUM] = chksum;
1210 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1212 else {
1213 /* shortname entry */
1214 unsigned short date=0, time=0, tenth=0;
1215 LDEBUGF("Shortname entry: %s\n", shortname);
1216 memcpy(entry + FATDIR_NAME, shortname, 11);
1217 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1218 entry[FATDIR_NTRES] = 0;
1220 fat_time(&date, &time, &tenth);
1221 entry[FATDIR_CRTTIMETENTH] = tenth;
1222 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1223 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1224 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1225 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1226 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1228 idx++;
1229 nameidx -= NAME_BYTES_PER_ENTRY;
1232 /* update last sector */
1233 rc = fat_seek(file, sector);
1234 if (rc<0)
1235 return rc * 10 - 6;
1237 rc = fat_readwrite(file, 1, buf, true);
1238 if (rc<1)
1239 return rc * 10 - 7;
1241 return 0;
1244 static int fat_checkname(const unsigned char* newname)
1246 static const char invalid_chars[] = "\"*/:<>?\\|";
1247 int len = strlen(newname);
1248 /* More sanity checks are probably needed */
1249 if (len > 255 || newname[len - 1] == '.')
1251 return -1;
1253 while (*newname)
1255 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1256 return -1;
1257 newname++;
1259 /* check trailing space(s) */
1260 if(*(--newname) == ' ')
1261 return -1;
1263 return 0;
1266 static int add_dir_entry(struct fat_dir* dir,
1267 struct fat_file* file,
1268 const char* name,
1269 bool is_directory,
1270 bool dotdir)
1272 #ifdef HAVE_MULTIVOLUME
1273 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1274 #else
1275 struct bpb* fat_bpb = &fat_bpbs[0];
1276 #endif
1277 unsigned char buf[SECTOR_SIZE];
1278 unsigned char shortname[12];
1279 int rc;
1280 unsigned int sector;
1281 bool done = false;
1282 int entries_needed, entries_found = 0;
1283 int firstentry;
1285 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1286 name, file->firstcluster);
1288 /* Don't check dotdirs name for validity */
1289 if (dotdir == false) {
1290 rc = fat_checkname(name);
1291 if (rc < 0) {
1292 /* filename is invalid */
1293 return rc * 10 - 1;
1297 #ifdef HAVE_MULTIVOLUME
1298 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1299 #endif
1301 /* The "." and ".." directory entries must not be long names */
1302 if(dotdir) {
1303 int i;
1304 strlcpy(shortname, name, 12);
1305 for(i = strlen(shortname); i < 12; i++)
1306 shortname[i] = ' ';
1308 entries_needed = 1;
1309 } else {
1310 create_dos_name(name, shortname);
1312 /* one dir entry needed for every 13 bytes of filename,
1313 plus one entry for the short name */
1314 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1315 / NAME_BYTES_PER_ENTRY + 1;
1318 restart:
1319 firstentry = -1;
1321 rc = fat_seek(&dir->file, 0);
1322 if (rc < 0)
1323 return rc * 10 - 2;
1325 /* step 1: search for free entries and check for duplicate shortname */
1326 for (sector = 0; !done; sector++)
1328 unsigned int i;
1330 rc = fat_readwrite(&dir->file, 1, buf, false);
1331 if (rc < 0) {
1332 DEBUGF( "add_dir_entry() - Couldn't read dir"
1333 " (error code %d)\n", rc);
1334 return rc * 10 - 3;
1337 if (rc == 0) { /* current end of dir reached */
1338 LDEBUGF("End of dir on cluster boundary\n");
1339 break;
1342 /* look for free slots */
1343 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1345 switch (buf[i * DIR_ENTRY_SIZE]) {
1346 case 0:
1347 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1348 LDEBUGF("Found end of dir %d\n",
1349 sector * DIR_ENTRIES_PER_SECTOR + i);
1350 i = DIR_ENTRIES_PER_SECTOR - 1;
1351 done = true;
1352 break;
1354 case 0xe5:
1355 entries_found++;
1356 LDEBUGF("Found free entry %d (%d/%d)\n",
1357 sector * DIR_ENTRIES_PER_SECTOR + i,
1358 entries_found, entries_needed);
1359 break;
1361 default:
1362 entries_found = 0;
1364 /* check that our intended shortname doesn't already exist */
1365 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1366 /* shortname exists already, make a new one */
1367 randomize_dos_name(shortname);
1368 LDEBUGF("Duplicate shortname, changing to %s\n",
1369 shortname);
1371 /* name has changed, we need to restart search */
1372 goto restart;
1374 break;
1376 if (firstentry < 0 && (entries_found >= entries_needed))
1377 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1378 - entries_found;
1382 /* step 2: extend the dir if necessary */
1383 if (firstentry < 0)
1385 LDEBUGF("Adding new sector(s) to dir\n");
1386 rc = fat_seek(&dir->file, sector);
1387 if (rc < 0)
1388 return rc * 10 - 4;
1389 memset(buf, 0, sizeof buf);
1391 /* we must clear whole clusters */
1392 for (; (entries_found < entries_needed) ||
1393 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1395 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1396 return -5; /* dir too large -- FAT specification */
1398 rc = fat_readwrite(&dir->file, 1, buf, true);
1399 if (rc < 1) /* No more room or something went wrong */
1400 return rc * 10 - 6;
1402 entries_found += DIR_ENTRIES_PER_SECTOR;
1405 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1408 /* step 3: add entry */
1409 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1410 LDEBUGF("Adding longname to entry %d in sector %d\n",
1411 firstentry, sector);
1413 rc = write_long_name(&dir->file, firstentry,
1414 entries_needed, name, shortname, is_directory);
1415 if (rc < 0)
1416 return rc * 10 - 7;
1418 /* remember where the shortname dir entry is located */
1419 file->direntry = firstentry + entries_needed - 1;
1420 file->direntries = entries_needed;
1421 file->dircluster = dir->file.firstcluster;
1422 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1423 file->direntry, file->direntries);
1425 return 0;
1428 static unsigned char char2dos(unsigned char c, int* randomize)
1430 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1432 if (c <= 0x20)
1433 c = 0; /* Illegal char, remove */
1434 else if (strchr(invalid_chars, c) != NULL)
1436 /* Illegal char, replace */
1437 c = '_';
1438 *randomize = 1; /* as per FAT spec */
1440 else
1441 c = toupper(c);
1443 return c;
1446 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1448 int i;
1449 unsigned char *ext;
1450 int randomize = 0;
1452 /* Find extension part */
1453 ext = strrchr(name, '.');
1454 if (ext == name) /* handle .dotnames */
1455 ext = NULL;
1457 /* needs to randomize? */
1458 if((ext && (strlen(ext) > 4)) ||
1459 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1460 randomize = 1;
1462 /* Name part */
1463 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1465 unsigned char c = char2dos(*name, &randomize);
1466 if (c)
1467 newname[i++] = c;
1470 /* Pad both name and extension */
1471 while (i < 11)
1472 newname[i++] = ' ';
1474 if (newname[0] == 0xe5) /* Special kanji character */
1475 newname[0] = 0x05;
1477 if (ext)
1478 { /* Extension part */
1479 ext++;
1480 for (i = 8; *ext && (i < 11); ext++)
1482 unsigned char c = char2dos(*ext, &randomize);
1483 if (c)
1484 newname[i++] = c;
1488 if(randomize)
1489 randomize_dos_name(newname);
1492 static void randomize_dos_name(unsigned char *name)
1494 unsigned char* tilde = NULL; /* ~ location */
1495 unsigned char* lastpt = NULL; /* last point of filename */
1496 unsigned char* nameptr = name; /* working copy of name pointer */
1497 unsigned char num[9]; /* holds number as string */
1498 int i = 0;
1499 int cnt = 1;
1500 int numlen;
1501 int offset;
1503 while(i++ < 8)
1505 /* hunt for ~ and where to put it */
1506 if((!tilde) && (*nameptr == '~'))
1507 tilde = nameptr;
1508 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1509 lastpt = nameptr;
1510 nameptr++;
1512 if(tilde)
1514 /* extract current count and increment */
1515 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1516 num[7-(unsigned int)(tilde-name)] = 0;
1517 cnt = atoi(num) + 1;
1519 cnt %= 10000000; /* protection */
1520 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1521 numlen = strlen(num); /* required space */
1522 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1523 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1525 memcpy(&name[offset], num, numlen);
1527 /* in special case of counter overflow: pad with spaces */
1528 for(offset = offset+numlen; offset < 8; offset++)
1529 name[offset] = ' ';
1532 static int update_short_entry( struct fat_file* file, long size, int attr )
1534 unsigned char buf[SECTOR_SIZE];
1535 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1536 unsigned char* entry =
1537 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1538 unsigned long* sizeptr;
1539 unsigned short* clusptr;
1540 struct fat_file dir;
1541 int rc;
1543 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1544 file->firstcluster, file->direntry, size);
1546 /* create a temporary file handle for the dir holding this file */
1547 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1548 if (rc < 0)
1549 return rc * 10 - 1;
1551 rc = fat_seek( &dir, sector );
1552 if (rc<0)
1553 return rc * 10 - 2;
1555 rc = fat_readwrite(&dir, 1, buf, false);
1556 if (rc < 1)
1557 return rc * 10 - 3;
1559 if (!entry[0] || entry[0] == 0xe5)
1560 panicf("Updating size on empty dir entry %d\n", file->direntry);
1562 entry[FATDIR_ATTR] = attr & 0xFF;
1564 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1565 *clusptr = htole16(file->firstcluster >> 16);
1567 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1568 *clusptr = htole16(file->firstcluster & 0xffff);
1570 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1571 *sizeptr = htole32(size);
1574 #if CONFIG_RTC
1575 unsigned short time = 0;
1576 unsigned short date = 0;
1577 #else
1578 /* get old time to increment from */
1579 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1580 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1581 #endif
1582 fat_time(&date, &time, NULL);
1583 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1584 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1585 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1588 rc = fat_seek( &dir, sector );
1589 if (rc < 0)
1590 return rc * 10 - 4;
1592 rc = fat_readwrite(&dir, 1, buf, true);
1593 if (rc < 1)
1594 return rc * 10 - 5;
1596 return 0;
1599 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1601 int i=0,j=0;
1602 unsigned char c;
1603 bool lowercase;
1605 memset(de, 0, sizeof(struct fat_direntry));
1606 de->attr = buf[FATDIR_ATTR];
1607 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1608 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1609 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1610 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1611 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1612 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1613 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1614 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1615 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1616 (the result of the shift is always considered signed) */
1618 /* fix the name */
1619 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1620 c = buf[FATDIR_NAME];
1621 if (c == 0x05) /* special kanji char */
1622 c = 0xe5;
1623 i = 0;
1624 while (c != ' ') {
1625 de->name[j++] = lowercase ? tolower(c) : c;
1626 if (++i >= 8)
1627 break;
1628 c = buf[FATDIR_NAME+i];
1630 if (buf[FATDIR_NAME+8] != ' ') {
1631 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1632 de->name[j++] = '.';
1633 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1634 de->name[j++] = lowercase ? tolower(c) : c;
1636 return 1;
1639 int fat_open(IF_MV2(int volume,)
1640 long startcluster,
1641 struct fat_file *file,
1642 const struct fat_dir* dir)
1644 /* Remember where the file's dir entry is located
1645 * Do it before assigning other fields so that fat_open
1646 * can be called with file == &dir->file (see fat_opendir) */
1647 if ( dir ) {
1648 file->direntry = dir->entry - 1;
1649 file->direntries = dir->entrycount;
1650 file->dircluster = dir->file.firstcluster;
1653 file->firstcluster = startcluster;
1654 file->lastcluster = startcluster;
1655 file->lastsector = 0;
1656 file->clusternum = 0;
1657 file->sectornum = 0;
1658 file->eof = false;
1659 #ifdef HAVE_MULTIVOLUME
1660 file->volume = volume;
1661 /* fixme: remove error check when done */
1662 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1664 LDEBUGF("fat_open() illegal volume %d\n", volume);
1665 return -1;
1667 #endif
1669 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1670 return 0;
1673 int fat_create_file(const char* name,
1674 struct fat_file* file,
1675 struct fat_dir* dir)
1677 int rc;
1679 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1680 rc = add_dir_entry(dir, file, name, false, false);
1681 if (!rc) {
1682 file->firstcluster = 0;
1683 file->lastcluster = 0;
1684 file->lastsector = 0;
1685 file->clusternum = 0;
1686 file->sectornum = 0;
1687 file->eof = false;
1690 return rc;
1693 int fat_create_dir(const char* name,
1694 struct fat_dir* newdir,
1695 struct fat_dir* dir)
1697 #ifdef HAVE_MULTIVOLUME
1698 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1699 #else
1700 struct bpb* fat_bpb = &fat_bpbs[0];
1701 #endif
1702 unsigned char buf[SECTOR_SIZE];
1703 int i;
1704 long sector;
1705 int rc;
1706 struct fat_file dummyfile;
1708 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1710 memset(newdir, 0, sizeof(struct fat_dir));
1711 memset(&dummyfile, 0, sizeof(struct fat_file));
1713 /* First, add the entry in the parent directory */
1714 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1715 if (rc < 0)
1716 return rc * 10 - 1;
1718 /* Allocate a new cluster for the directory */
1719 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1720 fat_bpb->fsinfo.nextfree);
1721 if(newdir->file.firstcluster == 0)
1722 return -1;
1724 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1726 /* Clear the entire cluster */
1727 memset(buf, 0, sizeof buf);
1728 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1729 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1730 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1731 if (rc < 0)
1732 return rc * 10 - 2;
1735 /* Then add the "." entry */
1736 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1737 if (rc < 0)
1738 return rc * 10 - 3;
1739 dummyfile.firstcluster = newdir->file.firstcluster;
1740 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1742 /* and the ".." entry */
1743 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1744 if (rc < 0)
1745 return rc * 10 - 4;
1747 /* The root cluster is cluster 0 in the ".." entry */
1748 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1749 dummyfile.firstcluster = 0;
1750 else
1751 dummyfile.firstcluster = dir->file.firstcluster;
1752 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1754 /* Set the firstcluster field in the direntry */
1755 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1757 rc = flush_fat(IF_MV(fat_bpb));
1758 if (rc < 0)
1759 return rc * 10 - 5;
1761 return rc;
1764 int fat_truncate(const struct fat_file *file)
1766 /* truncate trailing clusters */
1767 long next;
1768 long last = file->lastcluster;
1769 #ifdef HAVE_MULTIVOLUME
1770 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1771 #endif
1773 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1775 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1776 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1777 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1779 if (file->lastcluster)
1780 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1782 return 0;
1785 int fat_closewrite(struct fat_file *file, long size, int attr)
1787 int rc;
1788 #ifdef HAVE_MULTIVOLUME
1789 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1790 #endif
1791 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1793 if (!size) {
1794 /* empty file */
1795 if ( file->firstcluster ) {
1796 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1797 file->firstcluster = 0;
1801 if (file->dircluster) {
1802 rc = update_short_entry(file, size, attr);
1803 if (rc < 0)
1804 return rc * 10 - 1;
1807 flush_fat(IF_MV(fat_bpb));
1809 #ifdef TEST_FAT
1810 if ( file->firstcluster ) {
1811 /* debug */
1812 #ifdef HAVE_MULTIVOLUME
1813 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1814 #else
1815 struct bpb* fat_bpb = &fat_bpbs[0];
1816 #endif
1817 long count = 0;
1818 long len;
1819 long next;
1820 for ( next = file->firstcluster; next;
1821 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1822 LDEBUGF("cluster %ld: %lx\n", count, next);
1823 count++;
1825 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1826 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1827 count, len, size );
1828 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1829 panicf("Cluster chain is too long\n");
1830 if ( len < size )
1831 panicf("Cluster chain is too short\n");
1833 #endif
1835 return 0;
1838 static int free_direntries(struct fat_file* file)
1840 unsigned char buf[SECTOR_SIZE];
1841 struct fat_file dir;
1842 int numentries = file->direntries;
1843 unsigned int entry = file->direntry - numentries + 1;
1844 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1845 int i;
1846 int rc;
1848 /* create a temporary file handle for the dir holding this file */
1849 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1850 if (rc < 0)
1851 return rc * 10 - 1;
1853 rc = fat_seek( &dir, sector );
1854 if (rc < 0)
1855 return rc * 10 - 2;
1857 rc = fat_readwrite(&dir, 1, buf, false);
1858 if (rc < 1)
1859 return rc * 10 - 3;
1861 for (i=0; i < numentries; i++) {
1862 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1863 entry, i+1, numentries);
1864 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1865 entry++;
1867 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1868 /* flush this sector */
1869 rc = fat_seek(&dir, sector);
1870 if (rc < 0)
1871 return rc * 10 - 4;
1873 rc = fat_readwrite(&dir, 1, buf, true);
1874 if (rc < 1)
1875 return rc * 10 - 5;
1877 if ( i+1 < numentries ) {
1878 /* read next sector */
1879 rc = fat_readwrite(&dir, 1, buf, false);
1880 if (rc < 1)
1881 return rc * 10 - 6;
1883 sector++;
1887 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1888 /* flush this sector */
1889 rc = fat_seek(&dir, sector);
1890 if (rc < 0)
1891 return rc * 10 - 7;
1893 rc = fat_readwrite(&dir, 1, buf, true);
1894 if (rc < 1)
1895 return rc * 10 - 8;
1898 return 0;
1901 int fat_remove(struct fat_file* file)
1903 long next, last = file->firstcluster;
1904 int rc;
1905 #ifdef HAVE_MULTIVOLUME
1906 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1907 #endif
1909 LDEBUGF("fat_remove(%lx)\n",last);
1911 while ( last ) {
1912 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1913 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1914 last = next;
1917 if ( file->dircluster ) {
1918 rc = free_direntries(file);
1919 if (rc < 0)
1920 return rc * 10 - 1;
1923 file->firstcluster = 0;
1924 file->dircluster = 0;
1926 rc = flush_fat(IF_MV(fat_bpb));
1927 if (rc < 0)
1928 return rc * 10 - 2;
1930 return 0;
1933 int fat_rename(struct fat_file* file,
1934 struct fat_dir* dir,
1935 const unsigned char* newname,
1936 long size,
1937 int attr)
1939 int rc;
1940 struct fat_dir olddir;
1941 struct fat_file newfile = *file;
1942 unsigned char buf[SECTOR_SIZE];
1943 unsigned char* entry = NULL;
1944 unsigned short* clusptr = NULL;
1945 unsigned int parentcluster;
1946 #ifdef HAVE_MULTIVOLUME
1947 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1949 if (file->volume != dir->file.volume) {
1950 DEBUGF("No rename across volumes!\n");
1951 return -1;
1953 #else
1954 struct bpb* fat_bpb = &fat_bpbs[0];
1955 #endif
1957 if ( !file->dircluster ) {
1958 DEBUGF("File has no dir cluster!\n");
1959 return -2;
1962 /* create a temporary file handle */
1963 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1964 if (rc < 0)
1965 return rc * 10 - 1;
1967 /* create new name */
1968 rc = add_dir_entry(dir, &newfile, newname, false, false);
1969 if (rc < 0)
1970 return rc * 10 - 2;
1972 /* write size and cluster link */
1973 rc = update_short_entry(&newfile, size, attr);
1974 if (rc < 0)
1975 return rc * 10 - 3;
1977 /* remove old name */
1978 rc = free_direntries(file);
1979 if (rc < 0)
1980 return rc * 10 - 4;
1982 rc = flush_fat(IF_MV(fat_bpb));
1983 if (rc < 0)
1984 return rc * 10 - 5;
1986 /* if renaming a directory, update the .. entry to make sure
1987 it points to its parent directory (we don't check if it was a move) */
1988 if(FAT_ATTR_DIRECTORY == attr) {
1989 /* open the dir that was renamed, we re-use the olddir struct */
1990 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1991 NULL);
1992 if (rc < 0)
1993 return rc * 10 - 6;
1995 /* get the first sector of the dir */
1996 rc = fat_seek(&olddir.file, 0);
1997 if (rc < 0)
1998 return rc * 10 - 7;
2000 rc = fat_readwrite(&olddir.file, 1, buf, false);
2001 if (rc < 0)
2002 return rc * 10 - 8;
2004 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2005 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2006 parentcluster = 0;
2007 else
2008 parentcluster = dir->file.firstcluster;
2010 entry = buf + DIR_ENTRY_SIZE;
2011 if(strncmp(".. ", entry, 11))
2013 /* .. entry must be second entry according to FAT spec (p.29) */
2014 DEBUGF("Second dir entry is not double-dot!\n");
2015 return rc * 10 - 9;
2017 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2018 *clusptr = htole16(parentcluster >> 16);
2020 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
2021 *clusptr = htole16(parentcluster & 0xffff);
2023 /* write back this sector */
2024 rc = fat_seek(&olddir.file, 0);
2025 if (rc < 0)
2026 return rc * 10 - 7;
2028 rc = fat_readwrite(&olddir.file, 1, buf, true);
2029 if (rc < 1)
2030 return rc * 10 - 8;
2033 return 0;
2036 static long next_write_cluster(struct fat_file* file,
2037 long oldcluster,
2038 long* newsector)
2040 #ifdef HAVE_MULTIVOLUME
2041 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2042 #else
2043 struct bpb* fat_bpb = &fat_bpbs[0];
2044 #endif
2045 long cluster = 0;
2046 long sector;
2048 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2050 if (oldcluster)
2051 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2053 if (!cluster) {
2054 if (oldcluster > 0)
2055 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2056 else if (oldcluster == 0)
2057 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2058 fat_bpb->fsinfo.nextfree);
2059 #ifdef HAVE_FAT16SUPPORT
2060 else /* negative, pseudo-cluster of the root dir */
2061 return 0; /* impossible to append something to the root */
2062 #endif
2064 if (cluster) {
2065 if (oldcluster)
2066 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2067 else
2068 file->firstcluster = cluster;
2069 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2071 else {
2072 #ifdef TEST_FAT
2073 if (fat_bpb->fsinfo.freecount>0)
2074 panicf("There is free space, but find_free_cluster() "
2075 "didn't find it!\n");
2076 #endif
2077 DEBUGF("next_write_cluster(): Disk full!\n");
2078 return 0;
2081 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2082 if (sector<0)
2083 return 0;
2085 *newsector = sector;
2086 return cluster;
2089 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2090 unsigned long start, long count, char* buf, bool write )
2092 #ifndef HAVE_MULTIVOLUME
2093 struct bpb* fat_bpb = &fat_bpbs[0];
2094 #endif
2095 int rc;
2097 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2098 start+ fat_bpb->startsector, count, write?"write":"read");
2099 if (write) {
2100 unsigned long firstallowed;
2101 #ifdef HAVE_FAT16SUPPORT
2102 if (fat_bpb->is_fat16)
2103 firstallowed = fat_bpb->rootdirsector;
2104 else
2105 #endif
2106 firstallowed = fat_bpb->firstdatasector;
2108 if (start < firstallowed)
2109 panicf("Write %ld before data\n", firstallowed - start);
2110 if (start + count > fat_bpb->totalsectors)
2111 panicf("Write %ld after data\n",
2112 start + count - fat_bpb->totalsectors);
2113 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2114 start + fat_bpb->startsector, count, buf);
2116 else
2117 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2118 start + fat_bpb->startsector, count, buf);
2119 if (rc < 0) {
2120 DEBUGF( "transfer() - Couldn't %s sector %lx"
2121 " (error code %d)\n",
2122 write ? "write":"read", start, rc);
2123 return rc;
2125 return 0;
2129 long fat_readwrite( struct fat_file *file, long sectorcount,
2130 void* buf, bool write )
2132 #ifdef HAVE_MULTIVOLUME
2133 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2134 #else
2135 struct bpb* fat_bpb = &fat_bpbs[0];
2136 #endif
2137 long cluster = file->lastcluster;
2138 long sector = file->lastsector;
2139 long clusternum = file->clusternum;
2140 long numsec = file->sectornum;
2141 bool eof = file->eof;
2142 long first=0, last=0;
2143 long i;
2144 int rc;
2146 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2147 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2148 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2149 sector,numsec, eof?1:0);
2151 if ( eof && !write)
2152 return 0;
2154 /* find sequential sectors and write them all at once */
2155 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2156 numsec++;
2157 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2158 long oldcluster = cluster;
2159 long oldsector = sector;
2160 long oldnumsec = numsec;
2161 if (write)
2162 cluster = next_write_cluster(file, cluster, &sector);
2163 else {
2164 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2165 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2168 clusternum++;
2169 numsec=1;
2171 if (!cluster) {
2172 eof = true;
2173 if ( write ) {
2174 /* remember last cluster, in case
2175 we want to append to the file */
2176 sector = oldsector;
2177 cluster = oldcluster;
2178 numsec = oldnumsec;
2179 clusternum--;
2180 i = -1; /* Error code */
2181 break;
2184 else
2185 eof = false;
2187 else {
2188 if (sector)
2189 sector++;
2190 else {
2191 /* look up first sector of file */
2192 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2193 numsec=1;
2194 #ifdef HAVE_FAT16SUPPORT
2195 if (file->firstcluster < 0)
2196 { /* FAT16 root dir */
2197 sector += fat_bpb->rootdiroffset;
2198 numsec += fat_bpb->rootdiroffset;
2200 #endif
2204 if (!first)
2205 first = sector;
2207 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2208 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2209 long count = last - first + 1;
2210 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2211 if (rc < 0)
2212 return rc * 10 - 1;
2214 buf = (char *)buf + count * SECTOR_SIZE;
2215 first = sector;
2218 if ((i == sectorcount-1) && /* last sector requested */
2219 (!eof))
2221 long count = sector - first + 1;
2222 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2223 if (rc < 0)
2224 return rc * 10 - 2;
2227 last = sector;
2230 file->lastcluster = cluster;
2231 file->lastsector = sector;
2232 file->clusternum = clusternum;
2233 file->sectornum = numsec;
2234 file->eof = eof;
2236 /* if eof, don't report last block as read/written */
2237 if (eof)
2238 i--;
2240 DEBUGF("Sectors written: %ld\n", i);
2241 return i;
2244 int fat_seek(struct fat_file *file, unsigned long seeksector )
2246 #ifdef HAVE_MULTIVOLUME
2247 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2248 #else
2249 struct bpb* fat_bpb = &fat_bpbs[0];
2250 #endif
2251 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2252 long cluster = file->firstcluster;
2253 long i;
2255 #ifdef HAVE_FAT16SUPPORT
2256 if (cluster < 0) /* FAT16 root dir */
2257 seeksector += fat_bpb->rootdiroffset;
2258 #endif
2260 file->eof = false;
2261 if (seeksector) {
2262 /* we need to find the sector BEFORE the requested, since
2263 the file struct stores the last accessed sector */
2264 seeksector--;
2265 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2266 sectornum = seeksector % fat_bpb->bpb_secperclus;
2268 if (file->clusternum && clusternum >= file->clusternum)
2270 cluster = file->lastcluster;
2271 numclusters -= file->clusternum;
2274 for (i=0; i<numclusters; i++) {
2275 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2276 if (!cluster) {
2277 DEBUGF("Seeking beyond the end of the file! "
2278 "(sector %ld, cluster %ld)\n", seeksector, i);
2279 return -1;
2283 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2285 else {
2286 sectornum = -1;
2289 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2290 file->firstcluster, seeksector, cluster, sector, sectornum);
2292 file->lastcluster = cluster;
2293 file->lastsector = sector;
2294 file->clusternum = clusternum;
2295 file->sectornum = sectornum + 1;
2296 return 0;
2299 int fat_opendir(IF_MV2(int volume,)
2300 struct fat_dir *dir, unsigned long startcluster,
2301 const struct fat_dir *parent_dir)
2303 #ifdef HAVE_MULTIVOLUME
2304 struct bpb* fat_bpb = &fat_bpbs[volume];
2305 /* fixme: remove error check when done */
2306 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2308 LDEBUGF("fat_open() illegal volume %d\n", volume);
2309 return -1;
2311 #else
2312 struct bpb* fat_bpb = &fat_bpbs[0];
2313 #endif
2314 int rc;
2316 if (startcluster == 0)
2317 startcluster = fat_bpb->bpb_rootclus;
2319 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2320 if(rc)
2322 DEBUGF( "fat_opendir() - Couldn't open dir"
2323 " (error code %d)\n", rc);
2324 return rc * 10 - 1;
2327 /* assign them after fat_open call so that fat_opendir can be called with the same
2328 * fat_dir as parent and result */
2329 dir->entry = 0;
2330 dir->sector = 0;
2332 return 0;
2335 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2337 bool done = false;
2338 int i, j;
2339 int rc;
2340 int order;
2341 unsigned char firstbyte;
2342 /* Long file names are stored in special entries. Each entry holds
2343 up to 13 characters. Names can be max 255 chars (not bytes!) long */
2344 /* The number of long entries in the long name can be retrieve from the first
2345 * long entry because there are stored in reverse order and have an ordinal */
2346 int nb_longs = 0;
2347 /* The long entries are expected to be in order, so remember the last ordinal */
2348 int last_long_ord = 0;
2350 dir->entrycount = 0;
2352 while(!done)
2354 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2356 rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2357 if (rc == 0) {
2358 /* eof */
2359 entry->name[0] = 0;
2360 break;
2362 if (rc < 0) {
2363 DEBUGF( "fat_getnext() - Couldn't read dir"
2364 " (error code %d)\n", rc);
2365 return rc * 10 - 1;
2367 dir->sector = dir->file.lastsector;
2370 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2371 i < DIR_ENTRIES_PER_SECTOR; i++) {
2372 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2374 firstbyte = dir->sectorcache[entrypos];
2375 dir->entry++;
2377 if (firstbyte == 0xe5) {
2378 /* free entry */
2379 dir->entrycount = 0;
2380 continue;
2383 if (firstbyte == 0) {
2384 /* last entry */
2385 entry->name[0] = 0;
2386 dir->entrycount = 0;
2387 return 0;
2390 dir->entrycount++;
2392 /* LFN entry? */
2393 if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2394 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2395 /* extract ordinal */
2396 order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2397 /* is this entry the first long entry ? (first in order but containing last part) */
2398 if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2399 /* check that order is not too big ! (and non-zero) */
2400 if(order <= 0 || order > FATLONG_MAX_ORDER)
2401 continue; /* ignore the whole LFN, will trigger lots of warnings */
2402 nb_longs = order;
2403 last_long_ord = order;
2405 else {
2406 /* check orphan entry */
2407 if (nb_longs == 0) {
2408 logf("fat warning: orphan LFN entry");
2409 /* ignore */
2410 continue;
2413 /* check order */
2414 if (order != (last_long_ord - 1)) {
2415 logf("fat warning: wrong LFN ordinal");
2416 /* ignore the whole LFN, will trigger lots of warnings */
2417 nb_longs = 0;
2420 last_long_ord = order;
2423 /* copy part, reuse [order] for another purpose :) */
2424 order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2425 for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2426 memcpy(dir->longname + order,
2427 dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2428 FATLONG_NAME_SIZE[j]);
2429 order += FATLONG_NAME_SIZE[j];
2432 else {
2433 if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2435 /* don't return volume id entry */
2436 if ( (entry->attr &
2437 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2438 == FAT_ATTR_VOLUME_ID)
2439 continue;
2441 /* replace shortname with longname? */
2442 /* check that the long name is complete */
2443 if (nb_longs != 0 && last_long_ord == 1) {
2444 /* hold a copy of the shortname in case the long one is too long */
2445 unsigned char shortname[13]; /* 8+3+dot+\0 */
2446 int longname_utf8len = 0;
2447 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2448 * of a UTF8 encoded character in rockbox */
2449 unsigned char longname_utf8segm[4 + 1];
2450 unsigned short ucs;
2451 int segm_utf8len;
2452 /* Temporarily store short name */
2453 strcpy(shortname, entry->name);
2454 entry->name[0] = 0;
2456 /* Convert the FAT name to a utf8-encoded one.
2457 * The name is not necessary NUL-terminated ! */
2458 for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2459 ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2460 if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2461 break;
2462 /* utf8encode will return a pointer after the converted
2463 * string, subtract the pointer to the start to get the length of it */
2464 segm_utf8len = utf8encode(ucs, longname_utf8segm) - longname_utf8segm;
2466 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2467 if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2468 /* force use of short name */
2469 longname_utf8len = FAT_FILENAME_BYTES + 1;
2470 break; /* fallback later */
2472 else {
2473 longname_utf8segm[segm_utf8len] = 0;
2474 strcat(entry->name + longname_utf8len, longname_utf8segm);
2475 longname_utf8len += segm_utf8len;
2479 /* Does the utf8-encoded name fit into the entry? */
2480 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2481 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2482 /* Take the short DOS name. Need to utf8-encode it
2483 since it may contain chars from the upper half of
2484 the OEM code page which wouldn't be a valid utf8.
2485 Beware: this file will be shown with strange
2486 glyphs in file browser since unicode 0x80 to 0x9F
2487 are control characters. */
2488 logf("SN-DOS: %s", shortname);
2489 unsigned char *utf8;
2490 utf8 = iso_decode(shortname, entry->name, -1,
2491 strlen(shortname));
2492 *utf8 = 0;
2493 logf("SN: %s", entry->name);
2494 } else {
2495 logf("LN: %s", entry->name);
2496 logf("LNLen: %d", longname_utf8len);
2499 done = true;
2500 i++;
2501 break;
2506 return 0;
2509 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2511 #ifndef HAVE_MULTIVOLUME
2512 const int volume = 0;
2513 #endif
2514 struct bpb* fat_bpb = &fat_bpbs[volume];
2515 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2518 #ifdef HAVE_MULTIVOLUME
2519 bool fat_ismounted(int volume)
2521 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2523 #endif