Fix multivolume case
[maemo-rb.git] / firmware / drivers / fat.c
blobcff11d20ccd73bc27069139e52dc28f14bbea90c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <stdbool.h>
26 #include "fat.h"
27 #include "storage.h"
28 #include "debug.h"
29 #include "panic.h"
30 #include "system.h"
31 #include "timefuncs.h"
32 #include "kernel.h"
33 #include "rbunicode.h"
34 /*#define LOGF_ENABLE*/
35 #include "logf.h"
37 #define BYTES2INT16(array,pos) \
38 (array[pos] | (array[pos+1] << 8 ))
39 #define BYTES2INT32(array,pos) \
40 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
41 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
43 #define FATTYPE_FAT12 0
44 #define FATTYPE_FAT16 1
45 #define FATTYPE_FAT32 2
47 /* BPB offsets; generic */
48 #define BS_JMPBOOT 0
49 #define BS_OEMNAME 3
50 #define BPB_BYTSPERSEC 11
51 #define BPB_SECPERCLUS 13
52 #define BPB_RSVDSECCNT 14
53 #define BPB_NUMFATS 16
54 #define BPB_ROOTENTCNT 17
55 #define BPB_TOTSEC16 19
56 #define BPB_MEDIA 21
57 #define BPB_FATSZ16 22
58 #define BPB_SECPERTRK 24
59 #define BPB_NUMHEADS 26
60 #define BPB_HIDDSEC 28
61 #define BPB_TOTSEC32 32
63 /* fat12/16 */
64 #define BS_DRVNUM 36
65 #define BS_RESERVED1 37
66 #define BS_BOOTSIG 38
67 #define BS_VOLID 39
68 #define BS_VOLLAB 43
69 #define BS_FILSYSTYPE 54
71 /* fat32 */
72 #define BPB_FATSZ32 36
73 #define BPB_EXTFLAGS 40
74 #define BPB_FSVER 42
75 #define BPB_ROOTCLUS 44
76 #define BPB_FSINFO 48
77 #define BPB_BKBOOTSEC 50
78 #define BS_32_DRVNUM 64
79 #define BS_32_BOOTSIG 66
80 #define BS_32_VOLID 67
81 #define BS_32_VOLLAB 71
82 #define BS_32_FILSYSTYPE 82
84 #define BPB_LAST_WORD 510
87 /* attributes */
88 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
90 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
91 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
92 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
94 /* NTRES flags */
95 #define FAT_NTRES_LC_NAME 0x08
96 #define FAT_NTRES_LC_EXT 0x10
98 #define FATDIR_NAME 0
99 #define FATDIR_ATTR 11
100 #define FATDIR_NTRES 12
101 #define FATDIR_CRTTIMETENTH 13
102 #define FATDIR_CRTTIME 14
103 #define FATDIR_CRTDATE 16
104 #define FATDIR_LSTACCDATE 18
105 #define FATDIR_FSTCLUSHI 20
106 #define FATDIR_WRTTIME 22
107 #define FATDIR_WRTDATE 24
108 #define FATDIR_FSTCLUSLO 26
109 #define FATDIR_FILESIZE 28
111 #define FATLONG_ORDER 0
112 #define FATLONG_TYPE 12
113 #define FATLONG_CHKSUM 13
114 #define FATLONG_LAST_LONG_ENTRY 0x40
115 #define FATLONG_NAME_BYTES_PER_ENTRY 26
116 /* at most 20 LFN entries, keep coherent with fat_dir->longname size ! */
117 #define FATLONG_MAX_ORDER 20
119 #define FATLONG_NAME_CHUNKS 3
120 static unsigned char FATLONG_NAME_POS[FATLONG_NAME_CHUNKS] = {1, 14, 28};
121 static unsigned char FATLONG_NAME_SIZE[FATLONG_NAME_CHUNKS] = {10, 12, 4};
123 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
124 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
125 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
126 #define DIR_ENTRY_SIZE 32
127 #define NAME_BYTES_PER_ENTRY 13
128 #define FAT_BAD_MARK 0x0ffffff7
129 #define FAT_EOF_MARK 0x0ffffff8
130 #define FAT_LONGNAME_PAD_BYTE 0xff
131 #define FAT_LONGNAME_PAD_UCS 0xffff
133 struct fsinfo {
134 unsigned long freecount; /* last known free cluster count */
135 unsigned long nextfree; /* first cluster to start looking for free
136 clusters, or 0xffffffff for no hint */
138 /* fsinfo offsets */
139 #define FSINFO_FREECOUNT 488
140 #define FSINFO_NEXTFREE 492
142 /* Note: This struct doesn't hold the raw values after mounting if
143 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
144 * physical sectors. */
145 struct bpb
147 int bpb_bytspersec; /* Bytes per sector, typically 512 */
148 unsigned int bpb_secperclus; /* Sectors per cluster */
149 int bpb_rsvdseccnt; /* Number of reserved sectors */
150 int bpb_numfats; /* Number of FAT structures, typically 2 */
151 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
152 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
153 int bpb_fatsz16; /* Number of used sectors per FAT structure */
154 unsigned long bpb_totsec32; /* Number of sectors on the volume
155 (new 32-bit) */
156 unsigned int last_word; /* 0xAA55 */
158 /**** FAT32 specific *****/
159 long bpb_fatsz32;
160 long bpb_rootclus;
161 long bpb_fsinfo;
163 /* variables for internal use */
164 unsigned long fatsize;
165 unsigned long totalsectors;
166 unsigned long rootdirsector;
167 unsigned long firstdatasector;
168 unsigned long startsector;
169 unsigned long dataclusters;
170 struct fsinfo fsinfo;
171 #ifdef HAVE_FAT16SUPPORT
172 int bpb_rootentcnt; /* Number of dir entries in the root */
173 /* internals for FAT16 support */
174 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
175 unsigned int rootdiroffset; /* sector offset of root dir relative to start
176 * of first pseudo cluster */
177 #endif /* #ifdef HAVE_FAT16SUPPORT */
178 #ifdef HAVE_MULTIVOLUME
179 #ifdef HAVE_MULTIDRIVE
180 int drive; /* on which physical device is this located */
181 #endif
182 bool mounted; /* flag if this volume is mounted */
183 #endif
186 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
187 static bool initialized = false;
189 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
190 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
191 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
192 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
193 long secnum, bool dirty);
194 static void create_dos_name(const unsigned char *name, unsigned char *newname);
195 static void randomize_dos_name(unsigned char *name);
196 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
197 unsigned long start);
198 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
199 long count, char* buf, bool write );
201 #define FAT_CACHE_SIZE 0x20
202 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
204 struct fat_cache_entry
206 long secnum;
207 bool inuse;
208 bool dirty;
209 #ifdef HAVE_MULTIVOLUME
210 struct bpb* fat_vol ; /* shared cache for all volumes */
211 #endif
214 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
215 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
216 static struct mutex cache_mutex SHAREDBSS_ATTR;
218 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
219 void fat_lock(void)
221 mutex_lock(&cache_mutex);
224 void fat_unlock(void)
226 mutex_unlock(&cache_mutex);
228 #endif
230 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
232 #ifndef HAVE_MULTIVOLUME
233 struct bpb* fat_bpb = &fat_bpbs[0];
234 #endif
235 #ifdef HAVE_FAT16SUPPORT
236 /* negative clusters (FAT16 root dir) don't get the 2 offset */
237 int zerocluster = cluster < 0 ? 0 : 2;
238 #else
239 const long zerocluster = 2;
240 #endif
242 if (cluster > (long)(fat_bpb->dataclusters + 1))
244 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
245 return -1;
248 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
249 + fat_bpb->firstdatasector;
252 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
254 #ifndef HAVE_MULTIVOLUME
255 const int volume = 0;
256 #endif
257 struct bpb* fat_bpb = &fat_bpbs[volume];
258 if (size)
259 *size = fat_bpb->dataclusters * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
260 if (free)
261 *free = fat_bpb->fsinfo.freecount * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
264 void fat_init(void)
266 unsigned int i;
268 if (!initialized)
270 initialized = true;
271 mutex_init(&cache_mutex);
274 #ifdef HAVE_PRIORITY_SCHEDULING
275 /* Disable this because it is dangerous due to the assumption that
276 * mutex_unlock won't yield */
277 mutex_set_preempt(&cache_mutex, false);
278 #endif
280 /* mark the FAT cache as unused */
281 for(i = 0;i < FAT_CACHE_SIZE;i++)
283 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
284 fat_cache[i].inuse = false;
285 fat_cache[i].dirty = false;
286 #ifdef HAVE_MULTIVOLUME
287 fat_cache[i].fat_vol = NULL;
288 #endif
290 #ifdef HAVE_MULTIVOLUME
291 /* mark the possible volumes as not mounted */
292 for (i=0; i<NUM_VOLUMES;i++)
294 fat_bpbs[i].mounted = false;
296 #endif
299 /* fat_mount_internal is split out of fat_mount() to avoid having both the sector
300 * buffer used here and the sector buffer used by update_fsinfo() on stack */
301 static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
303 #ifndef HAVE_MULTIVOLUME
304 const int volume = 0;
305 #endif
306 struct bpb* fat_bpb = &fat_bpbs[volume];
307 unsigned char buf[SECTOR_SIZE];
308 int rc;
309 int secmult;
310 long datasec;
311 #ifdef HAVE_FAT16SUPPORT
312 int rootdirsectors;
313 #endif
315 /* Read the sector */
316 rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
317 if(rc)
319 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
320 return rc * 10 - 1;
323 memset(fat_bpb, 0, sizeof(struct bpb));
324 fat_bpb->startsector = startsector;
325 #ifdef HAVE_MULTIDRIVE
326 fat_bpb->drive = drive;
327 #endif
329 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
330 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
331 /* Sanity check is performed later */
333 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
334 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
335 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
336 fat_bpb->bpb_media = buf[BPB_MEDIA];
337 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
338 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
339 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
340 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
341 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
343 /* calculate a few commonly used values */
344 if (fat_bpb->bpb_fatsz16 != 0)
345 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
346 else
347 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
349 if (fat_bpb->bpb_totsec16 != 0)
350 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
351 else
352 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
354 #ifdef HAVE_FAT16SUPPORT
355 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
356 if (!fat_bpb->bpb_bytspersec)
357 return -2;
358 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
359 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
360 #endif /* #ifdef HAVE_FAT16SUPPORT */
362 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
363 #ifdef HAVE_FAT16SUPPORT
364 + rootdirsectors
365 #endif
366 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
368 /* Determine FAT type */
369 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
370 if (fat_bpb->bpb_secperclus)
371 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
372 else
373 return -2;
375 #ifdef TEST_FAT
377 we are sometimes testing with "illegally small" fat32 images,
378 so we don't use the proper fat32 test case for test code
380 if ( fat_bpb->bpb_fatsz16 )
381 #else
382 if ( fat_bpb->dataclusters < 65525 )
383 #endif
384 { /* FAT16 */
385 #ifdef HAVE_FAT16SUPPORT
386 fat_bpb->is_fat16 = true;
387 if (fat_bpb->dataclusters < 4085)
388 { /* FAT12 */
389 DEBUGF("This is FAT12. Go away!\n");
390 return -2;
392 #else /* #ifdef HAVE_FAT16SUPPORT */
393 DEBUGF("This is not FAT32. Go away!\n");
394 return -2;
395 #endif /* #ifndef HAVE_FAT16SUPPORT */
398 #ifdef HAVE_FAT16SUPPORT
399 if (fat_bpb->is_fat16)
400 { /* FAT16 specific part of BPB */
401 int dirclusters;
402 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
403 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
404 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
405 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
406 /* I assign negative pseudo cluster numbers for the root directory,
407 their range is counted upward until -1. */
408 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
409 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
410 - rootdirsectors;
412 else
413 #endif /* #ifdef HAVE_FAT16SUPPORT */
414 { /* FAT32 specific part of BPB */
415 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
416 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
417 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
418 fat_bpb->bpb_rootclus);
421 rc = bpb_is_sane(IF_MV(fat_bpb));
422 if (rc < 0)
424 DEBUGF( "fat_mount() - BPB is not sane\n");
425 return rc * 10 - 3;
428 #ifdef HAVE_FAT16SUPPORT
429 if (fat_bpb->is_fat16)
431 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
432 fat_bpb->fsinfo.nextfree = 0xffffffff;
434 else
435 #endif /* #ifdef HAVE_FAT16SUPPORT */
437 /* Read the fsinfo sector */
438 rc = storage_read_sectors(IF_MD2(drive,)
439 startsector + fat_bpb->bpb_fsinfo, 1, buf);
440 if (rc < 0)
442 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
443 return rc * 10 - 4;
445 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
446 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
448 return 0;
451 int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
453 #ifndef HAVE_MULTIVOLUME
454 const int volume = 0;
455 #endif
456 struct bpb* fat_bpb = &fat_bpbs[volume];
457 int rc;
459 rc = fat_mount_internal(IF_MV2(volume,) IF_MD2(drive,) startsector);
461 if(rc!=0) return rc;
463 /* calculate freecount if unset */
464 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
466 fat_recalc_free(IF_MV(volume));
469 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
470 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
471 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
472 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
473 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
475 #ifdef HAVE_MULTIVOLUME
476 fat_bpb->mounted = true;
477 #endif
479 return 0;
482 #ifdef HAVE_HOTSWAP
483 int fat_unmount(int volume, bool flush)
485 int rc;
486 #ifdef HAVE_MULTIVOLUME
487 struct bpb* fat_bpb = &fat_bpbs[volume];
488 #else
489 (void)volume;
490 #endif
492 if(flush)
494 rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
496 else
497 { /* volume is not accessible any more, e.g. MMC removed */
498 int i;
499 mutex_lock(&cache_mutex);
500 for(i = 0;i < FAT_CACHE_SIZE;i++)
502 struct fat_cache_entry *fce = &fat_cache[i];
503 if(fce->inuse
504 #ifdef HAVE_MULTIVOLUME
505 && fce->fat_vol == fat_bpb
506 #endif
509 fce->inuse = false; /* discard all from that volume */
510 fce->dirty = false;
513 mutex_unlock(&cache_mutex);
514 rc = 0;
516 #ifdef HAVE_MULTIVOLUME
517 fat_bpb->mounted = false;
518 #endif
519 return rc;
521 #endif /* #ifdef HAVE_HOTSWAP */
523 void fat_recalc_free(IF_MV_NONVOID(int volume))
525 #ifndef HAVE_MULTIVOLUME
526 const int volume = 0;
527 #endif
528 struct bpb* fat_bpb = &fat_bpbs[volume];
529 long free = 0;
530 unsigned long i;
531 #ifdef HAVE_FAT16SUPPORT
532 if (fat_bpb->is_fat16)
534 for (i = 0; i<fat_bpb->fatsize; i++) {
535 unsigned int j;
536 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
537 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
538 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
539 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
540 break;
542 if (letoh16(fat[j]) == 0x0000) {
543 free++;
544 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
545 fat_bpb->fsinfo.nextfree = c;
550 else
551 #endif /* #ifdef HAVE_FAT16SUPPORT */
553 for (i = 0; i<fat_bpb->fatsize; i++) {
554 unsigned int j;
555 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
556 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
557 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
558 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
559 break;
561 if (!(letoh32(fat[j]) & 0x0fffffff)) {
562 free++;
563 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
564 fat_bpb->fsinfo.nextfree = c;
569 fat_bpb->fsinfo.freecount = free;
570 update_fsinfo(IF_MV(fat_bpb));
573 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
575 #ifndef HAVE_MULTIVOLUME
576 struct bpb* fat_bpb = &fat_bpbs[0];
577 #endif
578 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
580 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
581 fat_bpb->bpb_bytspersec);
582 return -1;
584 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
585 > 128L*1024L)
587 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
588 "(%d * %d = %d)\n",
589 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
590 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
591 return -2;
593 if(fat_bpb->bpb_numfats != 2)
595 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
596 fat_bpb->bpb_numfats);
598 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
600 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
601 "media type (0x%02x)\n",
602 fat_bpb->bpb_media);
604 if(fat_bpb->last_word != 0xaa55)
606 DEBUGF( "bpb_is_sane() - Error: Last word is not "
607 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
608 return -3;
611 if (fat_bpb->fsinfo.freecount >
612 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
613 fat_bpb->bpb_secperclus)
615 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
616 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
617 return -4;
620 return 0;
623 static void flush_fat_sector(struct fat_cache_entry *fce,
624 unsigned char *sectorbuf)
626 int rc;
627 long secnum;
629 /* With multivolume, use only the FAT info from the cached sector! */
630 #ifdef HAVE_MULTIVOLUME
631 secnum = fce->secnum + fce->fat_vol->startsector;
632 #else
633 secnum = fce->secnum + fat_bpbs[0].startsector;
634 #endif
636 /* Write to the first FAT */
637 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
638 secnum, 1,
639 sectorbuf);
640 if(rc < 0)
642 panicf("flush_fat_sector() - Could not write sector %ld"
643 " (error %d)\n",
644 secnum, rc);
646 #ifdef HAVE_MULTIVOLUME
647 if(fce->fat_vol->bpb_numfats > 1)
648 #else
649 if(fat_bpbs[0].bpb_numfats > 1)
650 #endif
652 /* Write to the second FAT */
653 #ifdef HAVE_MULTIVOLUME
654 secnum += fce->fat_vol->fatsize;
655 #else
656 secnum += fat_bpbs[0].fatsize;
657 #endif
658 rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
659 secnum, 1, sectorbuf);
660 if(rc < 0)
662 panicf("flush_fat_sector() - Could not write sector %ld"
663 " (error %d)\n",
664 secnum, rc);
667 fce->dirty = false;
670 /* Note: The returned pointer is only safely valid until the next
671 task switch! (Any subsequent ata read/write may yield.) */
672 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
673 long fatsector, bool dirty)
675 #ifndef HAVE_MULTIVOLUME
676 struct bpb* fat_bpb = &fat_bpbs[0];
677 #endif
678 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
679 int cache_index = secnum & FAT_CACHE_MASK;
680 struct fat_cache_entry *fce = &fat_cache[cache_index];
681 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
682 int rc;
684 mutex_lock(&cache_mutex); /* make changes atomic */
686 /* Delete the cache entry if it isn't the sector we want */
687 if(fce->inuse && (fce->secnum != secnum
688 #ifdef HAVE_MULTIVOLUME
689 || fce->fat_vol != fat_bpb
690 #endif
693 /* Write back if it is dirty */
694 if(fce->dirty)
696 flush_fat_sector(fce, sectorbuf);
698 fce->inuse = false;
701 /* Load the sector if it is not cached */
702 if(!fce->inuse)
704 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
705 secnum + fat_bpb->startsector,1,
706 sectorbuf);
707 if(rc < 0)
709 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
710 " (error %d)\n", secnum, rc);
711 mutex_unlock(&cache_mutex);
712 return NULL;
714 fce->inuse = true;
715 fce->secnum = secnum;
716 #ifdef HAVE_MULTIVOLUME
717 fce->fat_vol = fat_bpb;
718 #endif
720 if (dirty)
721 fce->dirty = true; /* dirt remains, sticky until flushed */
722 mutex_unlock(&cache_mutex);
723 return sectorbuf;
726 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
727 unsigned long startcluster)
729 #ifndef HAVE_MULTIVOLUME
730 struct bpb* fat_bpb = &fat_bpbs[0];
731 #endif
732 unsigned long sector;
733 unsigned long offset;
734 unsigned long i;
736 #ifdef HAVE_FAT16SUPPORT
737 if (fat_bpb->is_fat16)
739 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
740 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
742 for (i = 0; i<fat_bpb->fatsize; i++) {
743 unsigned int j;
744 unsigned int nr = (i + sector) % fat_bpb->fatsize;
745 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
746 if ( !fat )
747 break;
748 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
749 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
750 if (letoh16(fat[k]) == 0x0000) {
751 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
752 /* Ignore the reserved clusters 0 & 1, and also
753 cluster numbers out of bounds */
754 if ( c < 2 || c > fat_bpb->dataclusters+1 )
755 continue;
756 LDEBUGF("find_free_cluster(%lx) == %x\n",startcluster,c);
757 fat_bpb->fsinfo.nextfree = c;
758 return c;
761 offset = 0;
764 else
765 #endif /* #ifdef HAVE_FAT16SUPPORT */
767 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
768 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
770 for (i = 0; i<fat_bpb->fatsize; i++) {
771 unsigned int j;
772 unsigned long nr = (i + sector) % fat_bpb->fatsize;
773 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
774 if ( !fat )
775 break;
776 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
777 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
778 if (!(letoh32(fat[k]) & 0x0fffffff)) {
779 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
780 /* Ignore the reserved clusters 0 & 1, and also
781 cluster numbers out of bounds */
782 if ( c < 2 || c > fat_bpb->dataclusters+1 )
783 continue;
784 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
785 fat_bpb->fsinfo.nextfree = c;
786 return c;
789 offset = 0;
793 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
794 return 0; /* 0 is an illegal cluster number */
797 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
798 unsigned long val)
800 #ifndef HAVE_MULTIVOLUME
801 struct bpb* fat_bpb = &fat_bpbs[0];
802 #endif
803 #ifdef HAVE_FAT16SUPPORT
804 if (fat_bpb->is_fat16)
806 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
807 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
808 unsigned short* sec;
810 val &= 0xFFFF;
812 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
814 if (entry==val)
815 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
817 if ( entry < 2 )
818 panicf("Updating reserved FAT entry %ld.\n",entry);
820 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
821 if (!sec)
823 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
824 return -1;
827 if ( val ) {
828 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
829 fat_bpb->fsinfo.freecount--;
831 else {
832 if (letoh16(sec[offset]))
833 fat_bpb->fsinfo.freecount++;
836 LDEBUGF("update_fat_entry: %lu free clusters\n",
837 fat_bpb->fsinfo.freecount);
839 sec[offset] = htole16(val);
841 else
842 #endif /* #ifdef HAVE_FAT16SUPPORT */
844 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
845 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
846 unsigned long* sec;
848 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
850 if (entry==val)
851 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
853 if ( entry < 2 )
854 panicf("Updating reserved FAT entry %ld.\n",entry);
856 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
857 if (!sec)
859 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
860 return -1;
863 if ( val ) {
864 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
865 fat_bpb->fsinfo.freecount > 0)
866 fat_bpb->fsinfo.freecount--;
868 else {
869 if (letoh32(sec[offset]) & 0x0fffffff)
870 fat_bpb->fsinfo.freecount++;
873 LDEBUGF("update_fat_entry: %ld free clusters\n",
874 fat_bpb->fsinfo.freecount);
876 /* don't change top 4 bits */
877 sec[offset] &= htole32(0xf0000000);
878 sec[offset] |= htole32(val & 0x0fffffff);
881 return 0;
884 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
886 #ifdef HAVE_FAT16SUPPORT
887 #ifndef HAVE_MULTIVOLUME
888 struct bpb* fat_bpb = &fat_bpbs[0];
889 #endif
890 if (fat_bpb->is_fat16)
892 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
893 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
894 unsigned short* sec;
896 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
897 if (!sec)
899 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
900 return -1;
903 return letoh16(sec[offset]);
905 else
906 #endif /* #ifdef HAVE_FAT16SUPPORT */
908 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
909 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
910 unsigned long* sec;
912 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
913 if (!sec)
915 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
916 return -1;
919 return letoh32(sec[offset]) & 0x0fffffff;
923 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
925 long next_cluster;
926 long eof_mark = FAT_EOF_MARK;
928 #ifdef HAVE_FAT16SUPPORT
929 #ifndef HAVE_MULTIVOLUME
930 struct bpb* fat_bpb = &fat_bpbs[0];
931 #endif
932 if (fat_bpb->is_fat16)
934 eof_mark &= 0xFFFF; /* only 16 bit */
935 if (cluster < 0) /* FAT16 root dir */
936 return cluster + 1; /* don't use the FAT */
938 #endif
939 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
941 /* is this last cluster in chain? */
942 if ( next_cluster >= eof_mark )
943 return 0;
944 else
945 return next_cluster;
948 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
950 #ifndef HAVE_MULTIVOLUME
951 struct bpb* fat_bpb = &fat_bpbs[0];
952 #endif
953 unsigned char fsinfo[SECTOR_SIZE];
954 unsigned long* intptr;
955 int rc;
957 #ifdef HAVE_FAT16SUPPORT
958 if (fat_bpb->is_fat16)
959 return 0; /* FAT16 has no FsInfo */
960 #endif /* #ifdef HAVE_FAT16SUPPORT */
962 /* update fsinfo */
963 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
964 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
965 if (rc < 0)
967 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
968 return rc * 10 - 1;
970 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
971 *intptr = htole32(fat_bpb->fsinfo.freecount);
973 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
974 *intptr = htole32(fat_bpb->fsinfo.nextfree);
976 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
977 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
978 if (rc < 0)
980 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
981 return rc * 10 - 2;
984 return 0;
987 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
989 int i;
990 int rc;
991 unsigned char *sec;
992 LDEBUGF("flush_fat()\n");
994 mutex_lock(&cache_mutex);
995 for(i = 0;i < FAT_CACHE_SIZE;i++)
997 struct fat_cache_entry *fce = &fat_cache[i];
998 if(fce->inuse
999 #ifdef HAVE_MULTIVOLUME
1000 && fce->fat_vol == fat_bpb
1001 #endif
1002 && fce->dirty)
1004 sec = fat_cache_sectors[i];
1005 flush_fat_sector(fce, sec);
1008 mutex_unlock(&cache_mutex);
1010 rc = update_fsinfo(IF_MV(fat_bpb));
1011 if (rc < 0)
1012 return rc * 10 - 3;
1014 return 0;
1017 static void fat_time(unsigned short* date,
1018 unsigned short* time,
1019 unsigned short* tenth )
1021 #if CONFIG_RTC
1022 struct tm* tm = get_time();
1024 if (date)
1025 *date = ((tm->tm_year - 80) << 9) |
1026 ((tm->tm_mon + 1) << 5) |
1027 tm->tm_mday;
1029 if (time)
1030 *time = (tm->tm_hour << 11) |
1031 (tm->tm_min << 5) |
1032 (tm->tm_sec >> 1);
1034 if (tenth)
1035 *tenth = (tm->tm_sec & 1) * 100;
1036 #else
1037 /* non-RTC version returns an increment from the supplied time, or a
1038 * fixed standard time/date if no time given as input */
1040 /* Macros to convert a 2-digit string to a decimal constant.
1041 (YEAR), MONTH and DAY are set by the date command, which outputs
1042 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1043 misinterpretation as an octal constant. */
1044 #define S100(x) 1 ## x
1045 #define C2DIG2DEC(x) (S100(x)-100)
1046 /* The actual build date, as FAT date constant */
1047 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1048 | (C2DIG2DEC(MONTH) << 5) \
1049 | C2DIG2DEC(DAY))
1051 bool date_forced = false;
1052 bool next_day = false;
1053 unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */
1055 if (date && *date < BUILD_DATE_FAT)
1057 *date = BUILD_DATE_FAT;
1058 date_forced = true;
1061 if (time)
1063 time2 = *time << 1;
1064 if (time2 == 0 || date_forced)
1066 time2 = (11 < 6) | 11; /* set to 00:11:11 */
1068 else
1070 unsigned mins = (time2 >> 6) & 0x3f;
1071 unsigned hours = (time2 >> 12) & 0x1f;
1073 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */
1074 if (mins > 59)
1076 mins = 11; /* 00 would be a bad marker */
1077 if (++hours > 23)
1079 hours = 0;
1080 next_day = true;
1083 time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */
1085 *time = time2 >> 1;
1088 if (tenth)
1089 *tenth = (time2 & 1) * 100;
1091 if (date && next_day)
1093 static const unsigned char daysinmonth[] =
1094 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1095 unsigned day = *date & 0x1f;
1096 unsigned month = (*date >> 5) & 0x0f;
1097 unsigned year = (*date >> 9) & 0x7f;
1099 /* simplification: ignore leap years */
1100 if (++day > daysinmonth[month-1])
1102 day = 1;
1103 if (++month > 12)
1105 month = 1;
1106 year++;
1109 *date = (year << 9) | (month << 5) | day;
1112 #endif /* CONFIG_RTC */
1115 static int write_long_name(struct fat_file* file,
1116 unsigned int firstentry,
1117 unsigned int numentries,
1118 const unsigned char* name,
1119 const unsigned char* shortname,
1120 bool is_directory,
1121 unsigned char *sector_buffer)
1123 unsigned char* entry;
1124 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1125 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1126 unsigned char chksum = 0;
1127 unsigned int i, j=0;
1128 unsigned int nameidx=0, namelen = utf8length(name);
1129 int rc;
1130 unsigned short name_utf16[namelen + 1];
1132 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1133 file->firstcluster, firstentry, numentries, name);
1135 rc = fat_seek(file, sector);
1136 if (rc<0)
1137 return rc * 10 - 1;
1139 rc = fat_readwrite(file, 1, sector_buffer, false);
1140 if (rc<1)
1141 return rc * 10 - 2;
1143 /* calculate shortname checksum */
1144 for (i=11; i>0; i--)
1145 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1147 /* calc position of last name segment */
1148 if ( namelen > NAME_BYTES_PER_ENTRY )
1149 for (nameidx=0;
1150 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1151 nameidx += NAME_BYTES_PER_ENTRY);
1153 /* we need to convert the name first */
1154 /* since it is written in reverse order */
1155 for (i = 0; i <= namelen; i++)
1156 name = utf8decode(name, &name_utf16[i]);
1158 for (i=0; i < numentries; i++) {
1159 /* new sector? */
1160 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1161 /* update current sector */
1162 rc = fat_seek(file, sector);
1163 if (rc<0)
1164 return rc * 10 - 3;
1166 rc = fat_readwrite(file, 1, sector_buffer, true);
1167 if (rc<1)
1168 return rc * 10 - 4;
1170 /* read next sector */
1171 rc = fat_readwrite(file, 1, sector_buffer, false);
1172 if (rc<0) {
1173 LDEBUGF("Failed writing new sector: %d\n",rc);
1174 return rc * 10 - 5;
1176 if (rc==0)
1177 /* end of dir */
1178 memset(sector_buffer, 0, SECTOR_SIZE);
1180 sector++;
1181 idx = 0;
1184 entry = sector_buffer + idx * DIR_ENTRY_SIZE;
1186 /* verify this entry is free */
1187 if (entry[0] && entry[0] != 0xe5 )
1188 panicf("Dir entry %d in sector %x is not free! "
1189 "%02x %02x %02x %02x",
1190 idx, sector,
1191 entry[0], entry[1], entry[2], entry[3]);
1193 memset(entry, 0, DIR_ENTRY_SIZE);
1194 if ( i+1 < numentries ) {
1195 /* longname entry */
1196 unsigned int k, l = nameidx;
1198 entry[FATLONG_ORDER] = numentries-i-1;
1199 if (i==0) {
1200 /* mark this as last long entry */
1201 entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1203 /* pad name with 0xffff */
1204 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1205 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1206 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1208 /* set name */
1209 for (k=0; k<5 && l <= namelen; k++) {
1210 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1211 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1213 for (k=0; k<6 && l <= namelen; k++) {
1214 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1215 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1217 for (k=0; k<2 && l <= namelen; k++) {
1218 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1219 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1222 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1223 entry[FATDIR_FSTCLUSLO] = 0;
1224 entry[FATLONG_TYPE] = 0;
1225 entry[FATLONG_CHKSUM] = chksum;
1226 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1228 else {
1229 /* shortname entry */
1230 unsigned short date=0, time=0, tenth=0;
1231 LDEBUGF("Shortname entry: %s\n", shortname);
1232 memcpy(entry + FATDIR_NAME, shortname, 11);
1233 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1234 entry[FATDIR_NTRES] = 0;
1236 fat_time(&date, &time, &tenth);
1237 entry[FATDIR_CRTTIMETENTH] = tenth;
1238 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1239 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1240 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1241 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1242 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1244 idx++;
1245 nameidx -= NAME_BYTES_PER_ENTRY;
1248 /* update last sector */
1249 rc = fat_seek(file, sector);
1250 if (rc<0)
1251 return rc * 10 - 6;
1253 rc = fat_readwrite(file, 1, sector_buffer, true);
1254 if (rc<1)
1255 return rc * 10 - 7;
1257 return 0;
1260 static int fat_checkname(const unsigned char* newname)
1262 static const char invalid_chars[] = "\"*/:<>?\\|";
1263 int len = strlen(newname);
1264 /* More sanity checks are probably needed */
1265 if (len > 255 || newname[len - 1] == '.')
1267 return -1;
1269 while (*newname)
1271 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1272 return -1;
1273 newname++;
1275 /* check trailing space(s) */
1276 if(*(--newname) == ' ')
1277 return -1;
1279 return 0;
1282 static int add_dir_entry(struct fat_dir* dir,
1283 struct fat_file* file,
1284 const char* name,
1285 bool is_directory,
1286 bool dotdir)
1288 #ifdef HAVE_MULTIVOLUME
1289 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1290 #else
1291 struct bpb* fat_bpb = &fat_bpbs[0];
1292 #endif
1293 unsigned char buf[SECTOR_SIZE];
1294 unsigned char shortname[12];
1295 int rc;
1296 unsigned int sector;
1297 bool done = false;
1298 int entries_needed, entries_found = 0;
1299 int firstentry;
1301 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1302 name, file->firstcluster);
1304 /* Don't check dotdirs name for validity */
1305 if (dotdir == false) {
1306 rc = fat_checkname(name);
1307 if (rc < 0) {
1308 /* filename is invalid */
1309 return rc * 10 - 1;
1313 #ifdef HAVE_MULTIVOLUME
1314 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1315 #endif
1317 /* The "." and ".." directory entries must not be long names */
1318 if(dotdir) {
1319 int i;
1320 strlcpy(shortname, name, 12);
1321 for(i = strlen(shortname); i < 12; i++)
1322 shortname[i] = ' ';
1324 entries_needed = 1;
1325 } else {
1326 create_dos_name(name, shortname);
1328 /* one dir entry needed for every 13 bytes of filename,
1329 plus one entry for the short name */
1330 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1331 / NAME_BYTES_PER_ENTRY + 1;
1334 restart:
1335 firstentry = -1;
1337 rc = fat_seek(&dir->file, 0);
1338 if (rc < 0)
1339 return rc * 10 - 2;
1341 /* step 1: search for free entries and check for duplicate shortname */
1342 for (sector = 0; !done; sector++)
1344 unsigned int i;
1346 rc = fat_readwrite(&dir->file, 1, buf, false);
1347 if (rc < 0) {
1348 DEBUGF( "add_dir_entry() - Couldn't read dir"
1349 " (error code %d)\n", rc);
1350 return rc * 10 - 3;
1353 if (rc == 0) { /* current end of dir reached */
1354 LDEBUGF("End of dir on cluster boundary\n");
1355 break;
1358 /* look for free slots */
1359 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1361 switch (buf[i * DIR_ENTRY_SIZE]) {
1362 case 0:
1363 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1364 LDEBUGF("Found end of dir %d\n",
1365 sector * DIR_ENTRIES_PER_SECTOR + i);
1366 i = DIR_ENTRIES_PER_SECTOR - 1;
1367 done = true;
1368 break;
1370 case 0xe5:
1371 entries_found++;
1372 LDEBUGF("Found free entry %d (%d/%d)\n",
1373 sector * DIR_ENTRIES_PER_SECTOR + i,
1374 entries_found, entries_needed);
1375 break;
1377 default:
1378 entries_found = 0;
1380 /* check that our intended shortname doesn't already exist */
1381 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1382 /* shortname exists already, make a new one */
1383 randomize_dos_name(shortname);
1384 LDEBUGF("Duplicate shortname, changing to %s\n",
1385 shortname);
1387 /* name has changed, we need to restart search */
1388 goto restart;
1390 break;
1392 if (firstentry < 0 && (entries_found >= entries_needed))
1393 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1394 - entries_found;
1398 /* step 2: extend the dir if necessary */
1399 if (firstentry < 0)
1401 LDEBUGF("Adding new sector(s) to dir\n");
1402 rc = fat_seek(&dir->file, sector);
1403 if (rc < 0)
1404 return rc * 10 - 4;
1405 memset(buf, 0, sizeof buf);
1407 /* we must clear whole clusters */
1408 for (; (entries_found < entries_needed) ||
1409 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1411 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1412 return -5; /* dir too large -- FAT specification */
1414 rc = fat_readwrite(&dir->file, 1, buf, true);
1415 if (rc < 1) /* No more room or something went wrong */
1416 return rc * 10 - 6;
1418 entries_found += DIR_ENTRIES_PER_SECTOR;
1421 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1424 /* step 3: add entry */
1425 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1426 LDEBUGF("Adding longname to entry %d in sector %d\n",
1427 firstentry, sector);
1429 rc = write_long_name(&dir->file, firstentry,
1430 entries_needed, name,
1431 shortname, is_directory, buf);
1432 if (rc < 0)
1433 return rc * 10 - 7;
1435 /* remember where the shortname dir entry is located */
1436 file->direntry = firstentry + entries_needed - 1;
1437 file->direntries = entries_needed;
1438 file->dircluster = dir->file.firstcluster;
1439 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1440 file->direntry, file->direntries);
1442 return 0;
1445 static unsigned char char2dos(unsigned char c, int* randomize)
1447 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1449 if (c <= 0x20)
1450 c = 0; /* Illegal char, remove */
1451 else if (strchr(invalid_chars, c) != NULL)
1453 /* Illegal char, replace */
1454 c = '_';
1455 *randomize = 1; /* as per FAT spec */
1457 else
1458 c = toupper(c);
1460 return c;
1463 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1465 int i;
1466 unsigned char *ext;
1467 int randomize = 0;
1469 /* Find extension part */
1470 ext = strrchr(name, '.');
1471 if (ext == name) /* handle .dotnames */
1472 ext = NULL;
1474 /* needs to randomize? */
1475 if((ext && (strlen(ext) > 4)) ||
1476 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1477 randomize = 1;
1479 /* Name part */
1480 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1482 unsigned char c = char2dos(*name, &randomize);
1483 if (c)
1484 newname[i++] = c;
1487 /* Pad both name and extension */
1488 while (i < 11)
1489 newname[i++] = ' ';
1491 if (newname[0] == 0xe5) /* Special kanji character */
1492 newname[0] = 0x05;
1494 if (ext)
1495 { /* Extension part */
1496 ext++;
1497 for (i = 8; *ext && (i < 11); ext++)
1499 unsigned char c = char2dos(*ext, &randomize);
1500 if (c)
1501 newname[i++] = c;
1505 if(randomize)
1506 randomize_dos_name(newname);
1509 static void randomize_dos_name(unsigned char *name)
1511 unsigned char* tilde = NULL; /* ~ location */
1512 unsigned char* lastpt = NULL; /* last point of filename */
1513 unsigned char* nameptr = name; /* working copy of name pointer */
1514 unsigned char num[9]; /* holds number as string */
1515 int i = 0;
1516 int cnt = 1;
1517 int numlen;
1518 int offset;
1520 while(i++ < 8)
1522 /* hunt for ~ and where to put it */
1523 if((!tilde) && (*nameptr == '~'))
1524 tilde = nameptr;
1525 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1526 lastpt = nameptr;
1527 nameptr++;
1529 if(tilde)
1531 /* extract current count and increment */
1532 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1533 num[7-(unsigned int)(tilde-name)] = 0;
1534 cnt = atoi(num) + 1;
1536 cnt %= 10000000; /* protection */
1537 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1538 numlen = strlen(num); /* required space */
1539 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1540 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1542 memcpy(&name[offset], num, numlen);
1544 /* in special case of counter overflow: pad with spaces */
1545 for(offset = offset+numlen; offset < 8; offset++)
1546 name[offset] = ' ';
1549 static int update_short_entry( struct fat_file* file, long size, int attr )
1551 unsigned char buf[SECTOR_SIZE];
1552 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1553 unsigned char* entry =
1554 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1555 unsigned long* sizeptr;
1556 unsigned short* clusptr;
1557 struct fat_file dir;
1558 int rc;
1560 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1561 file->firstcluster, file->direntry, size);
1563 /* create a temporary file handle for the dir holding this file */
1564 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1565 if (rc < 0)
1566 return rc * 10 - 1;
1568 rc = fat_seek( &dir, sector );
1569 if (rc<0)
1570 return rc * 10 - 2;
1572 rc = fat_readwrite(&dir, 1, buf, false);
1573 if (rc < 1)
1574 return rc * 10 - 3;
1576 if (!entry[0] || entry[0] == 0xe5)
1577 panicf("Updating size on empty dir entry %d\n", file->direntry);
1579 entry[FATDIR_ATTR] = attr & 0xFF;
1581 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1582 *clusptr = htole16(file->firstcluster >> 16);
1584 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1585 *clusptr = htole16(file->firstcluster & 0xffff);
1587 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1588 *sizeptr = htole32(size);
1591 #if CONFIG_RTC
1592 unsigned short time = 0;
1593 unsigned short date = 0;
1594 #else
1595 /* get old time to increment from */
1596 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1597 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1598 #endif
1599 fat_time(&date, &time, NULL);
1600 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1601 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1602 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1605 rc = fat_seek( &dir, sector );
1606 if (rc < 0)
1607 return rc * 10 - 4;
1609 rc = fat_readwrite(&dir, 1, buf, true);
1610 if (rc < 1)
1611 return rc * 10 - 5;
1613 return 0;
1616 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1618 int i=0,j=0;
1619 unsigned char c;
1620 bool lowercase;
1622 memset(de, 0, sizeof(struct fat_direntry));
1623 de->attr = buf[FATDIR_ATTR];
1624 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1625 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1626 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1627 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1628 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1629 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1630 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1631 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1632 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1633 (the result of the shift is always considered signed) */
1635 /* fix the name */
1636 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1637 c = buf[FATDIR_NAME];
1638 if (c == 0x05) /* special kanji char */
1639 c = 0xe5;
1640 i = 0;
1641 while (c != ' ') {
1642 de->name[j++] = lowercase ? tolower(c) : c;
1643 if (++i >= 8)
1644 break;
1645 c = buf[FATDIR_NAME+i];
1647 if (buf[FATDIR_NAME+8] != ' ') {
1648 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1649 de->name[j++] = '.';
1650 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1651 de->name[j++] = lowercase ? tolower(c) : c;
1653 return 1;
1656 int fat_open(IF_MV2(int volume,)
1657 long startcluster,
1658 struct fat_file *file,
1659 const struct fat_dir* dir)
1661 /* Remember where the file's dir entry is located
1662 * Do it before assigning other fields so that fat_open
1663 * can be called with file == &dir->file (see fat_opendir) */
1664 if ( dir ) {
1665 file->direntry = dir->entry - 1;
1666 file->direntries = dir->entrycount;
1667 file->dircluster = dir->file.firstcluster;
1670 file->firstcluster = startcluster;
1671 file->lastcluster = startcluster;
1672 file->lastsector = 0;
1673 file->clusternum = 0;
1674 file->sectornum = 0;
1675 file->eof = false;
1676 #ifdef HAVE_MULTIVOLUME
1677 file->volume = volume;
1678 /* fixme: remove error check when done */
1679 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1681 LDEBUGF("fat_open() illegal volume %d\n", volume);
1682 return -1;
1684 #endif
1686 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1687 return 0;
1690 int fat_create_file(const char* name,
1691 struct fat_file* file,
1692 struct fat_dir* dir)
1694 int rc;
1696 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1697 rc = add_dir_entry(dir, file, name, false, false);
1698 if (!rc) {
1699 file->firstcluster = 0;
1700 file->lastcluster = 0;
1701 file->lastsector = 0;
1702 file->clusternum = 0;
1703 file->sectornum = 0;
1704 file->eof = false;
1707 return rc;
1710 /* noinline because this is only split out of fat_create_dir to make sure
1711 * the sector buffer doesn't remain on the stack, to avoid nasty stack
1712 * overflows later on (when flush_fat() is called */
1713 static __attribute__((noinline)) int fat_clear_cluster(int sector,
1714 struct bpb *fat_bpb)
1716 unsigned char buf[SECTOR_SIZE];
1717 int i,rc;
1718 memset(buf, 0, sizeof buf);
1719 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1720 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1721 if (rc < 0)
1722 return rc * 10 - 2;
1724 return 0;
1727 int fat_create_dir(const char* name,
1728 struct fat_dir* newdir,
1729 struct fat_dir* dir)
1731 #ifdef HAVE_MULTIVOLUME
1732 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1733 #else
1734 struct bpb* fat_bpb = &fat_bpbs[0];
1735 #endif
1736 long sector;
1737 int rc;
1738 struct fat_file dummyfile;
1740 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1742 memset(newdir, 0, sizeof(struct fat_dir));
1743 memset(&dummyfile, 0, sizeof(struct fat_file));
1745 /* First, add the entry in the parent directory */
1746 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1747 if (rc < 0)
1748 return rc * 10 - 1;
1750 /* Allocate a new cluster for the directory */
1751 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1752 fat_bpb->fsinfo.nextfree);
1753 if(newdir->file.firstcluster == 0)
1754 return -1;
1756 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1758 /* Clear the entire cluster */
1759 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1760 rc = fat_clear_cluster(sector,fat_bpb);
1761 if (rc < 0)
1762 return rc;
1765 /* Then add the "." entry */
1766 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1767 if (rc < 0)
1768 return rc * 10 - 3;
1769 dummyfile.firstcluster = newdir->file.firstcluster;
1770 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1772 /* and the ".." entry */
1773 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1774 if (rc < 0)
1775 return rc * 10 - 4;
1777 /* The root cluster is cluster 0 in the ".." entry */
1778 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1779 dummyfile.firstcluster = 0;
1780 else
1781 dummyfile.firstcluster = dir->file.firstcluster;
1782 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1784 /* Set the firstcluster field in the direntry */
1785 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1787 rc = flush_fat(IF_MV(fat_bpb));
1788 if (rc < 0)
1789 return rc * 10 - 5;
1791 return rc;
1794 int fat_truncate(const struct fat_file *file)
1796 /* truncate trailing clusters */
1797 long next;
1798 long last = file->lastcluster;
1799 #ifdef HAVE_MULTIVOLUME
1800 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1801 #endif
1803 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1805 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1806 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1807 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1809 if (file->lastcluster)
1810 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1812 return 0;
1815 int fat_closewrite(struct fat_file *file, long size, int attr)
1817 int rc;
1818 #ifdef HAVE_MULTIVOLUME
1819 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1820 #endif
1821 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1823 if (!size) {
1824 /* empty file */
1825 if ( file->firstcluster ) {
1826 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1827 file->firstcluster = 0;
1831 if (file->dircluster) {
1832 rc = update_short_entry(file, size, attr);
1833 if (rc < 0)
1834 return rc * 10 - 1;
1837 flush_fat(IF_MV(fat_bpb));
1839 #ifdef TEST_FAT
1840 if ( file->firstcluster ) {
1841 /* debug */
1842 #ifdef HAVE_MULTIVOLUME
1843 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1844 #else
1845 struct bpb* fat_bpb = &fat_bpbs[0];
1846 #endif
1847 long count = 0;
1848 long len;
1849 long next;
1850 for ( next = file->firstcluster; next;
1851 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1852 LDEBUGF("cluster %ld: %lx\n", count, next);
1853 count++;
1855 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1856 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1857 count, len, size );
1858 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1859 panicf("Cluster chain is too long\n");
1860 if ( len < size )
1861 panicf("Cluster chain is too short\n");
1863 #endif
1865 return 0;
1868 static int free_direntries(struct fat_file* file)
1870 unsigned char buf[SECTOR_SIZE];
1871 struct fat_file dir;
1872 int numentries = file->direntries;
1873 unsigned int entry = file->direntry - numentries + 1;
1874 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1875 int i;
1876 int rc;
1878 /* create a temporary file handle for the dir holding this file */
1879 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1880 if (rc < 0)
1881 return rc * 10 - 1;
1883 rc = fat_seek( &dir, sector );
1884 if (rc < 0)
1885 return rc * 10 - 2;
1887 rc = fat_readwrite(&dir, 1, buf, false);
1888 if (rc < 1)
1889 return rc * 10 - 3;
1891 for (i=0; i < numentries; i++) {
1892 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1893 entry, i+1, numentries);
1894 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1895 entry++;
1897 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1898 /* flush this sector */
1899 rc = fat_seek(&dir, sector);
1900 if (rc < 0)
1901 return rc * 10 - 4;
1903 rc = fat_readwrite(&dir, 1, buf, true);
1904 if (rc < 1)
1905 return rc * 10 - 5;
1907 if ( i+1 < numentries ) {
1908 /* read next sector */
1909 rc = fat_readwrite(&dir, 1, buf, false);
1910 if (rc < 1)
1911 return rc * 10 - 6;
1913 sector++;
1917 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1918 /* flush this sector */
1919 rc = fat_seek(&dir, sector);
1920 if (rc < 0)
1921 return rc * 10 - 7;
1923 rc = fat_readwrite(&dir, 1, buf, true);
1924 if (rc < 1)
1925 return rc * 10 - 8;
1928 return 0;
1931 int fat_remove(struct fat_file* file)
1933 long next, last = file->firstcluster;
1934 int rc;
1935 #ifdef HAVE_MULTIVOLUME
1936 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1937 #endif
1939 LDEBUGF("fat_remove(%lx)\n",last);
1941 while ( last ) {
1942 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1943 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1944 last = next;
1947 if ( file->dircluster ) {
1948 rc = free_direntries(file);
1949 if (rc < 0)
1950 return rc * 10 - 1;
1953 file->firstcluster = 0;
1954 file->dircluster = 0;
1956 rc = flush_fat(IF_MV(fat_bpb));
1957 if (rc < 0)
1958 return rc * 10 - 2;
1960 return 0;
1963 int fat_rename(struct fat_file* file,
1964 struct fat_dir* dir,
1965 const unsigned char* newname,
1966 long size,
1967 int attr)
1969 int rc;
1970 struct fat_file olddir_file;
1971 struct fat_file newfile = *file;
1972 unsigned char* entry = NULL;
1973 unsigned short* clusptr = NULL;
1974 unsigned int parentcluster;
1975 #ifdef HAVE_MULTIVOLUME
1976 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1978 if (file->volume != dir->file.volume) {
1979 DEBUGF("No rename across volumes!\n");
1980 return -1;
1982 #else
1983 struct bpb* fat_bpb = &fat_bpbs[0];
1984 #endif
1986 if ( !file->dircluster ) {
1987 DEBUGF("File has no dir cluster!\n");
1988 return -2;
1991 /* create new name */
1992 rc = add_dir_entry(dir, &newfile, newname, false, false);
1993 if (rc < 0)
1994 return rc * 10 - 2;
1996 /* write size and cluster link */
1997 rc = update_short_entry(&newfile, size, attr);
1998 if (rc < 0)
1999 return rc * 10 - 3;
2001 /* remove old name */
2002 rc = free_direntries(file);
2003 if (rc < 0)
2004 return rc * 10 - 4;
2006 rc = flush_fat(IF_MV(fat_bpb));
2007 if (rc < 0)
2008 return rc * 10 - 5;
2010 /* if renaming a directory, update the .. entry to make sure
2011 it points to its parent directory (we don't check if it was a move) */
2012 if(FAT_ATTR_DIRECTORY == attr) {
2013 unsigned char buf[SECTOR_SIZE];
2014 /* open the dir that was renamed, we re-use the olddir_file struct */
2015 rc = fat_open(IF_MV2(file->volume,) newfile.firstcluster, &olddir_file, NULL);
2016 if (rc < 0)
2017 return rc * 10 - 6;
2019 /* get the first sector of the dir */
2020 rc = fat_seek(&olddir_file, 0);
2021 if (rc < 0)
2022 return rc * 10 - 7;
2024 rc = fat_readwrite(&olddir_file, 1, buf, false);
2025 if (rc < 0)
2026 return rc * 10 - 8;
2028 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2029 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2030 parentcluster = 0;
2031 else
2032 parentcluster = dir->file.firstcluster;
2034 entry = buf + DIR_ENTRY_SIZE;
2035 if(strncmp(".. ", entry, 11))
2037 /* .. entry must be second entry according to FAT spec (p.29) */
2038 DEBUGF("Second dir entry is not double-dot!\n");
2039 return rc * 10 - 9;
2041 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2042 *clusptr = htole16(parentcluster >> 16);
2044 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
2045 *clusptr = htole16(parentcluster & 0xffff);
2047 /* write back this sector */
2048 rc = fat_seek(&olddir_file, 0);
2049 if (rc < 0)
2050 return rc * 10 - 7;
2052 rc = fat_readwrite(&olddir_file, 1, buf, true);
2053 if (rc < 1)
2054 return rc * 10 - 8;
2057 return 0;
2060 static long next_write_cluster(struct fat_file* file,
2061 long oldcluster,
2062 long* newsector)
2064 #ifdef HAVE_MULTIVOLUME
2065 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2066 #else
2067 struct bpb* fat_bpb = &fat_bpbs[0];
2068 #endif
2069 long cluster = 0;
2070 long sector;
2072 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2074 if (oldcluster)
2075 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2077 if (!cluster) {
2078 if (oldcluster > 0)
2079 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2080 else if (oldcluster == 0)
2081 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2082 fat_bpb->fsinfo.nextfree);
2083 #ifdef HAVE_FAT16SUPPORT
2084 else /* negative, pseudo-cluster of the root dir */
2085 return 0; /* impossible to append something to the root */
2086 #endif
2088 if (cluster) {
2089 if (oldcluster)
2090 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2091 else
2092 file->firstcluster = cluster;
2093 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2095 else {
2096 #ifdef TEST_FAT
2097 if (fat_bpb->fsinfo.freecount>0)
2098 panicf("There is free space, but find_free_cluster() "
2099 "didn't find it!\n");
2100 #endif
2101 DEBUGF("next_write_cluster(): Disk full!\n");
2102 return 0;
2105 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2106 if (sector<0)
2107 return 0;
2109 *newsector = sector;
2110 return cluster;
2113 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2114 unsigned long start, long count, char* buf, bool write )
2116 #ifndef HAVE_MULTIVOLUME
2117 struct bpb* fat_bpb = &fat_bpbs[0];
2118 #endif
2119 int rc;
2121 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2122 start+ fat_bpb->startsector, count, write?"write":"read");
2123 if (write) {
2124 unsigned long firstallowed;
2125 #ifdef HAVE_FAT16SUPPORT
2126 if (fat_bpb->is_fat16)
2127 firstallowed = fat_bpb->rootdirsector;
2128 else
2129 #endif
2130 firstallowed = fat_bpb->firstdatasector;
2132 if (start < firstallowed)
2133 panicf("Write %ld before data\n", firstallowed - start);
2134 if (start + count > fat_bpb->totalsectors)
2135 panicf("Write %ld after data\n",
2136 start + count - fat_bpb->totalsectors);
2137 rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2138 start + fat_bpb->startsector, count, buf);
2140 else
2141 rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2142 start + fat_bpb->startsector, count, buf);
2143 if (rc < 0) {
2144 DEBUGF( "transfer() - Couldn't %s sector %lx"
2145 " (error code %d)\n",
2146 write ? "write":"read", start, rc);
2147 return rc;
2149 return 0;
2153 long fat_readwrite( struct fat_file *file, long sectorcount,
2154 void* buf, bool write )
2156 #ifdef HAVE_MULTIVOLUME
2157 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2158 #else
2159 struct bpb* fat_bpb = &fat_bpbs[0];
2160 #endif
2161 long cluster = file->lastcluster;
2162 long sector = file->lastsector;
2163 long clusternum = file->clusternum;
2164 long numsec = file->sectornum;
2165 bool eof = file->eof;
2166 long first=0, last=0;
2167 long i;
2168 int rc;
2170 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2171 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2172 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2173 sector,numsec, eof?1:0);
2175 if ( eof && !write)
2176 return 0;
2178 /* find sequential sectors and write them all at once */
2179 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2180 numsec++;
2181 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2182 long oldcluster = cluster;
2183 long oldsector = sector;
2184 long oldnumsec = numsec;
2185 if (write)
2186 cluster = next_write_cluster(file, cluster, &sector);
2187 else {
2188 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2189 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2192 clusternum++;
2193 numsec=1;
2195 if (!cluster) {
2196 eof = true;
2197 if ( write ) {
2198 /* remember last cluster, in case
2199 we want to append to the file */
2200 sector = oldsector;
2201 cluster = oldcluster;
2202 numsec = oldnumsec;
2203 clusternum--;
2204 i = -1; /* Error code */
2205 break;
2208 else
2209 eof = false;
2211 else {
2212 if (sector)
2213 sector++;
2214 else {
2215 /* look up first sector of file */
2216 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2217 numsec=1;
2218 #ifdef HAVE_FAT16SUPPORT
2219 if (file->firstcluster < 0)
2220 { /* FAT16 root dir */
2221 sector += fat_bpb->rootdiroffset;
2222 numsec += fat_bpb->rootdiroffset;
2224 #endif
2228 if (!first)
2229 first = sector;
2231 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2232 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2233 long count = last - first + 1;
2234 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2235 if (rc < 0)
2236 return rc * 10 - 1;
2238 buf = (char *)buf + count * SECTOR_SIZE;
2239 first = sector;
2242 if ((i == sectorcount-1) && /* last sector requested */
2243 (!eof))
2245 long count = sector - first + 1;
2246 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2247 if (rc < 0)
2248 return rc * 10 - 2;
2251 last = sector;
2254 file->lastcluster = cluster;
2255 file->lastsector = sector;
2256 file->clusternum = clusternum;
2257 file->sectornum = numsec;
2258 file->eof = eof;
2260 /* if eof, don't report last block as read/written */
2261 if (eof)
2262 i--;
2264 DEBUGF("Sectors written: %ld\n", i);
2265 return i;
2268 int fat_seek(struct fat_file *file, unsigned long seeksector )
2270 #ifdef HAVE_MULTIVOLUME
2271 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2272 #else
2273 struct bpb* fat_bpb = &fat_bpbs[0];
2274 #endif
2275 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2276 long cluster = file->firstcluster;
2277 long i;
2279 #ifdef HAVE_FAT16SUPPORT
2280 if (cluster < 0) /* FAT16 root dir */
2281 seeksector += fat_bpb->rootdiroffset;
2282 #endif
2284 file->eof = false;
2285 if (seeksector) {
2286 /* we need to find the sector BEFORE the requested, since
2287 the file struct stores the last accessed sector */
2288 seeksector--;
2289 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2290 sectornum = seeksector % fat_bpb->bpb_secperclus;
2292 if (file->clusternum && clusternum >= file->clusternum)
2294 cluster = file->lastcluster;
2295 numclusters -= file->clusternum;
2298 for (i=0; i<numclusters; i++) {
2299 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2300 if (!cluster) {
2301 DEBUGF("Seeking beyond the end of the file! "
2302 "(sector %ld, cluster %ld)\n", seeksector, i);
2303 return -1;
2307 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2309 else {
2310 sectornum = -1;
2313 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2314 file->firstcluster, seeksector, cluster, sector, sectornum);
2316 file->lastcluster = cluster;
2317 file->lastsector = sector;
2318 file->clusternum = clusternum;
2319 file->sectornum = sectornum + 1;
2320 return 0;
2323 int fat_opendir(IF_MV2(int volume,)
2324 struct fat_dir *dir, unsigned long startcluster,
2325 const struct fat_dir *parent_dir)
2327 #ifdef HAVE_MULTIVOLUME
2328 struct bpb* fat_bpb = &fat_bpbs[volume];
2329 /* fixme: remove error check when done */
2330 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2332 LDEBUGF("fat_open() illegal volume %d\n", volume);
2333 return -1;
2335 #else
2336 struct bpb* fat_bpb = &fat_bpbs[0];
2337 #endif
2338 int rc;
2340 if (startcluster == 0)
2341 startcluster = fat_bpb->bpb_rootclus;
2343 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2344 if(rc)
2346 DEBUGF( "fat_opendir() - Couldn't open dir"
2347 " (error code %d)\n", rc);
2348 return rc * 10 - 1;
2351 /* assign them after fat_open call so that fat_opendir can be called with the same
2352 * fat_dir as parent and result */
2353 dir->entry = 0;
2354 dir->sector = 0;
2356 return 0;
2359 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2361 bool done = false;
2362 int i, j;
2363 int rc;
2364 int order;
2365 unsigned char firstbyte;
2366 /* Long file names are stored in special entries. Each entry holds
2367 up to 13 characters. Names can be max 255 chars (not bytes!) long */
2368 /* The number of long entries in the long name can be retrieve from the first
2369 * long entry because there are stored in reverse order and have an ordinal */
2370 int nb_longs = 0;
2371 /* The long entries are expected to be in order, so remember the last ordinal */
2372 int last_long_ord = 0;
2374 dir->entrycount = 0;
2376 while(!done)
2378 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2380 rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2381 if (rc == 0) {
2382 /* eof */
2383 entry->name[0] = 0;
2384 break;
2386 if (rc < 0) {
2387 DEBUGF( "fat_getnext() - Couldn't read dir"
2388 " (error code %d)\n", rc);
2389 return rc * 10 - 1;
2391 dir->sector = dir->file.lastsector;
2394 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2395 i < DIR_ENTRIES_PER_SECTOR; i++) {
2396 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2398 firstbyte = dir->sectorcache[entrypos];
2399 dir->entry++;
2401 if (firstbyte == 0xe5) {
2402 /* free entry */
2403 dir->entrycount = 0;
2404 continue;
2407 if (firstbyte == 0) {
2408 /* last entry */
2409 entry->name[0] = 0;
2410 dir->entrycount = 0;
2411 return 0;
2414 dir->entrycount++;
2416 /* LFN entry? */
2417 if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2418 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2419 /* extract ordinal */
2420 order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2421 /* is this entry the first long entry ? (first in order but containing last part) */
2422 if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2423 /* check that order is not too big ! (and non-zero) */
2424 if(order <= 0 || order > FATLONG_MAX_ORDER)
2425 continue; /* ignore the whole LFN, will trigger lots of warnings */
2426 nb_longs = order;
2427 last_long_ord = order;
2429 else {
2430 /* check orphan entry */
2431 if (nb_longs == 0) {
2432 logf("fat warning: orphan LFN entry");
2433 /* ignore */
2434 continue;
2437 /* check order */
2438 if (order != (last_long_ord - 1)) {
2439 logf("fat warning: wrong LFN ordinal");
2440 /* ignore the whole LFN, will trigger lots of warnings */
2441 nb_longs = 0;
2444 last_long_ord = order;
2447 /* copy part, reuse [order] for another purpose :) */
2448 order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2449 for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2450 memcpy(dir->longname + order,
2451 dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2452 FATLONG_NAME_SIZE[j]);
2453 order += FATLONG_NAME_SIZE[j];
2456 else {
2457 if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2459 /* don't return volume id entry */
2460 if ( (entry->attr &
2461 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2462 == FAT_ATTR_VOLUME_ID)
2463 continue;
2465 /* replace shortname with longname? */
2466 /* check that the long name is complete */
2467 if (nb_longs != 0 && last_long_ord == 1) {
2468 /* hold a copy of the shortname in case the long one is too long */
2469 unsigned char shortname[13]; /* 8+3+dot+\0 */
2470 int longname_utf8len = 0;
2471 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2472 * of a UTF8 encoded character in rockbox */
2473 unsigned char longname_utf8segm[4 + 1];
2474 unsigned short ucs;
2475 int segm_utf8len;
2476 /* Temporarily store short name */
2477 strcpy(shortname, entry->name);
2478 entry->name[0] = 0;
2480 /* Convert the FAT name to a utf8-encoded one.
2481 * The name is not necessary NUL-terminated ! */
2482 for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2483 ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2484 if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2485 break;
2486 /* utf8encode will return a pointer after the converted
2487 * string, subtract the pointer to the start to get the length of it */
2488 segm_utf8len = utf8encode(ucs, longname_utf8segm) - longname_utf8segm;
2490 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2491 if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2492 /* force use of short name */
2493 longname_utf8len = FAT_FILENAME_BYTES + 1;
2494 break; /* fallback later */
2496 else {
2497 longname_utf8segm[segm_utf8len] = 0;
2498 strcat(entry->name + longname_utf8len, longname_utf8segm);
2499 longname_utf8len += segm_utf8len;
2503 /* Does the utf8-encoded name fit into the entry? */
2504 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2505 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2506 /* Take the short DOS name. Need to utf8-encode it
2507 since it may contain chars from the upper half of
2508 the OEM code page which wouldn't be a valid utf8.
2509 Beware: this file will be shown with strange
2510 glyphs in file browser since unicode 0x80 to 0x9F
2511 are control characters. */
2512 logf("SN-DOS: %s", shortname);
2513 unsigned char *utf8;
2514 utf8 = iso_decode(shortname, entry->name, -1,
2515 strlen(shortname));
2516 *utf8 = 0;
2517 logf("SN: %s", entry->name);
2518 } else {
2519 logf("LN: %s", entry->name);
2520 logf("LNLen: %d", longname_utf8len);
2523 done = true;
2524 i++;
2525 break;
2530 return 0;
2533 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2535 #ifndef HAVE_MULTIVOLUME
2536 const int volume = 0;
2537 #endif
2538 struct bpb* fat_bpb = &fat_bpbs[volume];
2539 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2542 #ifdef HAVE_MULTIVOLUME
2543 bool fat_ismounted(int volume)
2545 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2547 #endif