Get a good start on cleaning up powermgmt.c
[kugel-rb.git] / firmware / drivers / fat.c
blob0ff47a82b5542c77d758b3648746fa79254274fa
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <stdbool.h>
24 #include "fat.h"
25 #include "ata.h"
26 #include "debug.h"
27 #include "panic.h"
28 #include "system.h"
29 #include "timefuncs.h"
30 #include "kernel.h"
31 #include "rbunicode.h"
32 #include "logf.h"
34 #define BYTES2INT16(array,pos) \
35 (array[pos] | (array[pos+1] << 8 ))
36 #define BYTES2INT32(array,pos) \
37 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
38 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
40 #define FATTYPE_FAT12 0
41 #define FATTYPE_FAT16 1
42 #define FATTYPE_FAT32 2
44 /* BPB offsets; generic */
45 #define BS_JMPBOOT 0
46 #define BS_OEMNAME 3
47 #define BPB_BYTSPERSEC 11
48 #define BPB_SECPERCLUS 13
49 #define BPB_RSVDSECCNT 14
50 #define BPB_NUMFATS 16
51 #define BPB_ROOTENTCNT 17
52 #define BPB_TOTSEC16 19
53 #define BPB_MEDIA 21
54 #define BPB_FATSZ16 22
55 #define BPB_SECPERTRK 24
56 #define BPB_NUMHEADS 26
57 #define BPB_HIDDSEC 28
58 #define BPB_TOTSEC32 32
60 /* fat12/16 */
61 #define BS_DRVNUM 36
62 #define BS_RESERVED1 37
63 #define BS_BOOTSIG 38
64 #define BS_VOLID 39
65 #define BS_VOLLAB 43
66 #define BS_FILSYSTYPE 54
68 /* fat32 */
69 #define BPB_FATSZ32 36
70 #define BPB_EXTFLAGS 40
71 #define BPB_FSVER 42
72 #define BPB_ROOTCLUS 44
73 #define BPB_FSINFO 48
74 #define BPB_BKBOOTSEC 50
75 #define BS_32_DRVNUM 64
76 #define BS_32_BOOTSIG 66
77 #define BS_32_VOLID 67
78 #define BS_32_VOLLAB 71
79 #define BS_32_FILSYSTYPE 82
81 #define BPB_LAST_WORD 510
84 /* attributes */
85 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
86 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
87 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
88 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
89 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
91 /* NTRES flags */
92 #define FAT_NTRES_LC_NAME 0x08
93 #define FAT_NTRES_LC_EXT 0x10
95 #define FATDIR_NAME 0
96 #define FATDIR_ATTR 11
97 #define FATDIR_NTRES 12
98 #define FATDIR_CRTTIMETENTH 13
99 #define FATDIR_CRTTIME 14
100 #define FATDIR_CRTDATE 16
101 #define FATDIR_LSTACCDATE 18
102 #define FATDIR_FSTCLUSHI 20
103 #define FATDIR_WRTTIME 22
104 #define FATDIR_WRTDATE 24
105 #define FATDIR_FSTCLUSLO 26
106 #define FATDIR_FILESIZE 28
108 #define FATLONG_ORDER 0
109 #define FATLONG_TYPE 12
110 #define FATLONG_CHKSUM 13
112 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
113 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
114 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
115 #define DIR_ENTRY_SIZE 32
116 #define NAME_BYTES_PER_ENTRY 13
117 #define FAT_BAD_MARK 0x0ffffff7
118 #define FAT_EOF_MARK 0x0ffffff8
119 #define FAT_LONGNAME_PAD_BYTE 0xff
120 #define FAT_LONGNAME_PAD_UCS 0xffff
122 struct fsinfo {
123 unsigned long freecount; /* last known free cluster count */
124 unsigned long nextfree; /* first cluster to start looking for free
125 clusters, or 0xffffffff for no hint */
127 /* fsinfo offsets */
128 #define FSINFO_FREECOUNT 488
129 #define FSINFO_NEXTFREE 492
131 /* Note: This struct doesn't hold the raw values after mounting if
132 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
133 * physical sectors. */
134 struct bpb
136 int bpb_bytspersec; /* Bytes per sector, typically 512 */
137 unsigned int bpb_secperclus; /* Sectors per cluster */
138 int bpb_rsvdseccnt; /* Number of reserved sectors */
139 int bpb_numfats; /* Number of FAT structures, typically 2 */
140 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
141 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
142 int bpb_fatsz16; /* Number of used sectors per FAT structure */
143 unsigned long bpb_totsec32; /* Number of sectors on the volume
144 (new 32-bit) */
145 unsigned int last_word; /* 0xAA55 */
147 /**** FAT32 specific *****/
148 long bpb_fatsz32;
149 long bpb_rootclus;
150 long bpb_fsinfo;
152 /* variables for internal use */
153 unsigned long fatsize;
154 unsigned long totalsectors;
155 unsigned long rootdirsector;
156 unsigned long firstdatasector;
157 unsigned long startsector;
158 unsigned long dataclusters;
159 struct fsinfo fsinfo;
160 #ifdef HAVE_FAT16SUPPORT
161 int bpb_rootentcnt; /* Number of dir entries in the root */
162 /* internals for FAT16 support */
163 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
164 unsigned int rootdiroffset; /* sector offset of root dir relative to start
165 * of first pseudo cluster */
166 #endif /* #ifdef HAVE_FAT16SUPPORT */
167 #ifdef HAVE_MULTIVOLUME
168 int drive; /* on which physical device is this located */
169 bool mounted; /* flag if this volume is mounted */
170 #endif
173 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
174 static bool initialized = false;
176 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
177 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
178 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
179 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
180 long secnum, bool dirty);
181 static void create_dos_name(const unsigned char *name, unsigned char *newname);
182 static void randomize_dos_name(unsigned char *name);
183 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
184 unsigned long start);
185 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
186 long count, char* buf, bool write );
188 #define FAT_CACHE_SIZE 0x20
189 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
191 struct fat_cache_entry
193 long secnum;
194 bool inuse;
195 bool dirty;
196 #ifdef HAVE_MULTIVOLUME
197 struct bpb* fat_vol ; /* shared cache for all volumes */
198 #endif
201 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
202 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
203 static struct mutex cache_mutex SHAREDBSS_ATTR;
205 #if defined(HAVE_HOTSWAP) && !defined(HAVE_MMC) /* A better condition ?? */
206 void fat_lock(void)
208 mutex_lock(&cache_mutex);
211 void fat_unlock(void)
213 mutex_unlock(&cache_mutex);
215 #endif
217 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
219 #ifndef HAVE_MULTIVOLUME
220 struct bpb* fat_bpb = &fat_bpbs[0];
221 #endif
222 #ifdef HAVE_FAT16SUPPORT
223 /* negative clusters (FAT16 root dir) don't get the 2 offset */
224 int zerocluster = cluster < 0 ? 0 : 2;
225 #else
226 const long zerocluster = 2;
227 #endif
229 if (cluster > (long)(fat_bpb->dataclusters + 1))
231 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
232 return -1;
235 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
236 + fat_bpb->firstdatasector;
239 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
241 #ifndef HAVE_MULTIVOLUME
242 const int volume = 0;
243 #endif
244 struct bpb* fat_bpb = &fat_bpbs[volume];
245 if (size)
246 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
247 if (free)
248 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
251 void fat_init(void)
253 unsigned int i;
255 if (!initialized)
257 initialized = true;
258 mutex_init(&cache_mutex);
261 #ifdef HAVE_PRIORITY_SCHEDULING
262 /* Disable this because it is dangerous due to the assumption that
263 * mutex_unlock won't yield */
264 mutex_set_preempt(&cache_mutex, false);
265 #endif
267 /* mark the FAT cache as unused */
268 for(i = 0;i < FAT_CACHE_SIZE;i++)
270 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
271 fat_cache[i].inuse = false;
272 fat_cache[i].dirty = false;
273 #ifdef HAVE_MULTIVOLUME
274 fat_cache[i].fat_vol = NULL;
275 #endif
277 #ifdef HAVE_MULTIVOLUME
278 /* mark the possible volumes as not mounted */
279 for (i=0; i<NUM_VOLUMES;i++)
281 fat_bpbs[i].mounted = false;
283 #endif
286 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
288 #ifndef HAVE_MULTIVOLUME
289 const int volume = 0;
290 #endif
291 struct bpb* fat_bpb = &fat_bpbs[volume];
292 unsigned char buf[SECTOR_SIZE];
293 int rc;
294 int secmult;
295 long datasec;
296 #ifdef HAVE_FAT16SUPPORT
297 int rootdirsectors;
298 #endif
300 /* Read the sector */
301 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
302 if(rc)
304 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
305 return rc * 10 - 1;
308 memset(fat_bpb, 0, sizeof(struct bpb));
309 fat_bpb->startsector = startsector;
310 #ifdef HAVE_MULTIVOLUME
311 fat_bpb->drive = drive;
312 #endif
314 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
315 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
316 /* Sanity check is performed later */
318 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
319 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
320 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
321 fat_bpb->bpb_media = buf[BPB_MEDIA];
322 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
323 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
324 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
325 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
326 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
328 /* calculate a few commonly used values */
329 if (fat_bpb->bpb_fatsz16 != 0)
330 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
331 else
332 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
334 if (fat_bpb->bpb_totsec16 != 0)
335 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
336 else
337 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
339 #ifdef HAVE_FAT16SUPPORT
340 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
341 if (!fat_bpb->bpb_bytspersec)
342 return -2;
343 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
344 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
345 #endif /* #ifdef HAVE_FAT16SUPPORT */
347 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
348 #ifdef HAVE_FAT16SUPPORT
349 + rootdirsectors
350 #endif
351 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
353 /* Determine FAT type */
354 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
355 if (fat_bpb->bpb_secperclus)
356 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
357 else
358 return -2;
360 #ifdef TEST_FAT
362 we are sometimes testing with "illegally small" fat32 images,
363 so we don't use the proper fat32 test case for test code
365 if ( fat_bpb->bpb_fatsz16 )
366 #else
367 if ( fat_bpb->dataclusters < 65525 )
368 #endif
369 { /* FAT16 */
370 #ifdef HAVE_FAT16SUPPORT
371 fat_bpb->is_fat16 = true;
372 if (fat_bpb->dataclusters < 4085)
373 { /* FAT12 */
374 DEBUGF("This is FAT12. Go away!\n");
375 return -2;
377 #else /* #ifdef HAVE_FAT16SUPPORT */
378 DEBUGF("This is not FAT32. Go away!\n");
379 return -2;
380 #endif /* #ifndef HAVE_FAT16SUPPORT */
383 #ifdef HAVE_FAT16SUPPORT
384 if (fat_bpb->is_fat16)
385 { /* FAT16 specific part of BPB */
386 int dirclusters;
387 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
388 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
389 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
390 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
391 /* I assign negative pseudo cluster numbers for the root directory,
392 their range is counted upward until -1. */
393 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
394 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
395 - rootdirsectors;
397 else
398 #endif /* #ifdef HAVE_FAT16SUPPORT */
399 { /* FAT32 specific part of BPB */
400 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
401 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
402 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
403 fat_bpb->bpb_rootclus);
406 rc = bpb_is_sane(IF_MV(fat_bpb));
407 if (rc < 0)
409 DEBUGF( "fat_mount() - BPB is not sane\n");
410 return rc * 10 - 3;
413 #ifdef HAVE_FAT16SUPPORT
414 if (fat_bpb->is_fat16)
416 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
417 fat_bpb->fsinfo.nextfree = 0xffffffff;
419 else
420 #endif /* #ifdef HAVE_FAT16SUPPORT */
422 /* Read the fsinfo sector */
423 rc = ata_read_sectors(IF_MV2(drive,)
424 startsector + fat_bpb->bpb_fsinfo, 1, buf);
425 if (rc < 0)
427 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
428 return rc * 10 - 4;
430 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
431 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
434 /* calculate freecount if unset */
435 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
437 fat_recalc_free(IF_MV(volume));
440 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
441 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
442 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
443 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
444 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
446 #ifdef HAVE_MULTIVOLUME
447 fat_bpb->mounted = true;
448 #endif
450 return 0;
453 #ifdef HAVE_HOTSWAP
454 int fat_unmount(int volume, bool flush)
456 int rc;
457 struct bpb* fat_bpb = &fat_bpbs[volume];
459 if(flush)
461 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
463 else
464 { /* volume is not accessible any more, e.g. MMC removed */
465 int i;
466 mutex_lock(&cache_mutex);
467 for(i = 0;i < FAT_CACHE_SIZE;i++)
469 struct fat_cache_entry *fce = &fat_cache[i];
470 if(fce->inuse && fce->fat_vol == fat_bpb)
472 fce->inuse = false; /* discard all from that volume */
473 fce->dirty = false;
476 mutex_unlock(&cache_mutex);
477 rc = 0;
479 fat_bpb->mounted = false;
480 return rc;
482 #endif /* #ifdef HAVE_HOTSWAP */
484 void fat_recalc_free(IF_MV_NONVOID(int volume))
486 #ifndef HAVE_MULTIVOLUME
487 const int volume = 0;
488 #endif
489 struct bpb* fat_bpb = &fat_bpbs[volume];
490 long free = 0;
491 unsigned long i;
492 #ifdef HAVE_FAT16SUPPORT
493 if (fat_bpb->is_fat16)
495 for (i = 0; i<fat_bpb->fatsize; i++) {
496 unsigned int j;
497 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
498 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
499 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
500 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
501 break;
503 if (letoh16(fat[j]) == 0x0000) {
504 free++;
505 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
506 fat_bpb->fsinfo.nextfree = c;
511 else
512 #endif /* #ifdef HAVE_FAT16SUPPORT */
514 for (i = 0; i<fat_bpb->fatsize; i++) {
515 unsigned int j;
516 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
517 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
518 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
519 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
520 break;
522 if (!(letoh32(fat[j]) & 0x0fffffff)) {
523 free++;
524 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
525 fat_bpb->fsinfo.nextfree = c;
530 fat_bpb->fsinfo.freecount = free;
531 update_fsinfo(IF_MV(fat_bpb));
534 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
536 #ifndef HAVE_MULTIVOLUME
537 struct bpb* fat_bpb = &fat_bpbs[0];
538 #endif
539 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
541 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
542 fat_bpb->bpb_bytspersec);
543 return -1;
545 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
546 > 128L*1024L)
548 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
549 "(%d * %d = %d)\n",
550 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
551 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
552 return -2;
554 if(fat_bpb->bpb_numfats != 2)
556 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
557 fat_bpb->bpb_numfats);
559 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
561 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
562 "media type (0x%02x)\n",
563 fat_bpb->bpb_media);
565 if(fat_bpb->last_word != 0xaa55)
567 DEBUGF( "bpb_is_sane() - Error: Last word is not "
568 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
569 return -3;
572 if (fat_bpb->fsinfo.freecount >
573 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
574 fat_bpb->bpb_secperclus)
576 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
577 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
578 return -4;
581 return 0;
584 static void flush_fat_sector(struct fat_cache_entry *fce,
585 unsigned char *sectorbuf)
587 int rc;
588 long secnum;
590 /* With multivolume, use only the FAT info from the cached sector! */
591 #ifdef HAVE_MULTIVOLUME
592 secnum = fce->secnum + fce->fat_vol->startsector;
593 #else
594 secnum = fce->secnum + fat_bpbs[0].startsector;
595 #endif
597 /* Write to the first FAT */
598 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
599 secnum, 1,
600 sectorbuf);
601 if(rc < 0)
603 panicf("flush_fat_sector() - Could not write sector %ld"
604 " (error %d)\n",
605 secnum, rc);
607 #ifdef HAVE_MULTIVOLUME
608 if(fce->fat_vol->bpb_numfats > 1)
609 #else
610 if(fat_bpbs[0].bpb_numfats > 1)
611 #endif
613 /* Write to the second FAT */
614 #ifdef HAVE_MULTIVOLUME
615 secnum += fce->fat_vol->fatsize;
616 #else
617 secnum += fat_bpbs[0].fatsize;
618 #endif
619 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
620 secnum, 1, sectorbuf);
621 if(rc < 0)
623 panicf("flush_fat_sector() - Could not write sector %ld"
624 " (error %d)\n",
625 secnum, rc);
628 fce->dirty = false;
631 /* Note: The returned pointer is only safely valid until the next
632 task switch! (Any subsequent ata read/write may yield.) */
633 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
634 long fatsector, bool dirty)
636 #ifndef HAVE_MULTIVOLUME
637 struct bpb* fat_bpb = &fat_bpbs[0];
638 #endif
639 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
640 int cache_index = secnum & FAT_CACHE_MASK;
641 struct fat_cache_entry *fce = &fat_cache[cache_index];
642 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
643 int rc;
645 mutex_lock(&cache_mutex); /* make changes atomic */
647 /* Delete the cache entry if it isn't the sector we want */
648 if(fce->inuse && (fce->secnum != secnum
649 #ifdef HAVE_MULTIVOLUME
650 || fce->fat_vol != fat_bpb
651 #endif
654 /* Write back if it is dirty */
655 if(fce->dirty)
657 flush_fat_sector(fce, sectorbuf);
659 fce->inuse = false;
662 /* Load the sector if it is not cached */
663 if(!fce->inuse)
665 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
666 secnum + fat_bpb->startsector,1,
667 sectorbuf);
668 if(rc < 0)
670 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
671 " (error %d)\n", secnum, rc);
672 mutex_unlock(&cache_mutex);
673 return NULL;
675 fce->inuse = true;
676 fce->secnum = secnum;
677 #ifdef HAVE_MULTIVOLUME
678 fce->fat_vol = fat_bpb;
679 #endif
681 if (dirty)
682 fce->dirty = true; /* dirt remains, sticky until flushed */
683 mutex_unlock(&cache_mutex);
684 return sectorbuf;
687 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
688 unsigned long startcluster)
690 #ifndef HAVE_MULTIVOLUME
691 struct bpb* fat_bpb = &fat_bpbs[0];
692 #endif
693 unsigned long sector;
694 unsigned long offset;
695 unsigned long i;
697 #ifdef HAVE_FAT16SUPPORT
698 if (fat_bpb->is_fat16)
700 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
701 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
703 for (i = 0; i<fat_bpb->fatsize; i++) {
704 unsigned int j;
705 unsigned int nr = (i + sector) % fat_bpb->fatsize;
706 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
707 if ( !fat )
708 break;
709 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
710 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
711 if (letoh16(fat[k]) == 0x0000) {
712 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
713 /* Ignore the reserved clusters 0 & 1, and also
714 cluster numbers out of bounds */
715 if ( c < 2 || c > fat_bpb->dataclusters+1 )
716 continue;
717 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
718 fat_bpb->fsinfo.nextfree = c;
719 return c;
722 offset = 0;
725 else
726 #endif /* #ifdef HAVE_FAT16SUPPORT */
728 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
729 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
731 for (i = 0; i<fat_bpb->fatsize; i++) {
732 unsigned int j;
733 unsigned long nr = (i + sector) % fat_bpb->fatsize;
734 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
735 if ( !fat )
736 break;
737 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
738 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
739 if (!(letoh32(fat[k]) & 0x0fffffff)) {
740 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
741 /* Ignore the reserved clusters 0 & 1, and also
742 cluster numbers out of bounds */
743 if ( c < 2 || c > fat_bpb->dataclusters+1 )
744 continue;
745 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
746 fat_bpb->fsinfo.nextfree = c;
747 return c;
750 offset = 0;
754 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
755 return 0; /* 0 is an illegal cluster number */
758 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
759 unsigned long val)
761 #ifndef HAVE_MULTIVOLUME
762 struct bpb* fat_bpb = &fat_bpbs[0];
763 #endif
764 #ifdef HAVE_FAT16SUPPORT
765 if (fat_bpb->is_fat16)
767 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
768 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
769 unsigned short* sec;
771 val &= 0xFFFF;
773 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
775 if (entry==val)
776 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
778 if ( entry < 2 )
779 panicf("Updating reserved FAT entry %ld.\n",entry);
781 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
782 if (!sec)
784 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
785 return -1;
788 if ( val ) {
789 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
790 fat_bpb->fsinfo.freecount--;
792 else {
793 if (letoh16(sec[offset]))
794 fat_bpb->fsinfo.freecount++;
797 LDEBUGF("update_fat_entry: %d free clusters\n",
798 fat_bpb->fsinfo.freecount);
800 sec[offset] = htole16(val);
802 else
803 #endif /* #ifdef HAVE_FAT16SUPPORT */
805 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
806 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
807 unsigned long* sec;
809 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
811 if (entry==val)
812 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
814 if ( entry < 2 )
815 panicf("Updating reserved FAT entry %ld.\n",entry);
817 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
818 if (!sec)
820 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
821 return -1;
824 if ( val ) {
825 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
826 fat_bpb->fsinfo.freecount > 0)
827 fat_bpb->fsinfo.freecount--;
829 else {
830 if (letoh32(sec[offset]) & 0x0fffffff)
831 fat_bpb->fsinfo.freecount++;
834 LDEBUGF("update_fat_entry: %ld free clusters\n",
835 fat_bpb->fsinfo.freecount);
837 /* don't change top 4 bits */
838 sec[offset] &= htole32(0xf0000000);
839 sec[offset] |= htole32(val & 0x0fffffff);
842 return 0;
845 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
847 #ifdef HAVE_FAT16SUPPORT
848 #ifndef HAVE_MULTIVOLUME
849 struct bpb* fat_bpb = &fat_bpbs[0];
850 #endif
851 if (fat_bpb->is_fat16)
853 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
854 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
855 unsigned short* sec;
857 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
858 if (!sec)
860 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
861 return -1;
864 return letoh16(sec[offset]);
866 else
867 #endif /* #ifdef HAVE_FAT16SUPPORT */
869 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
870 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
871 unsigned long* sec;
873 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
874 if (!sec)
876 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
877 return -1;
880 return letoh32(sec[offset]) & 0x0fffffff;
884 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
886 long next_cluster;
887 long eof_mark = FAT_EOF_MARK;
889 #ifdef HAVE_FAT16SUPPORT
890 #ifndef HAVE_MULTIVOLUME
891 struct bpb* fat_bpb = &fat_bpbs[0];
892 #endif
893 if (fat_bpb->is_fat16)
895 eof_mark &= 0xFFFF; /* only 16 bit */
896 if (cluster < 0) /* FAT16 root dir */
897 return cluster + 1; /* don't use the FAT */
899 #endif
900 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
902 /* is this last cluster in chain? */
903 if ( next_cluster >= eof_mark )
904 return 0;
905 else
906 return next_cluster;
909 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
911 #ifndef HAVE_MULTIVOLUME
912 struct bpb* fat_bpb = &fat_bpbs[0];
913 #endif
914 unsigned char fsinfo[SECTOR_SIZE];
915 unsigned long* intptr;
916 int rc;
918 #ifdef HAVE_FAT16SUPPORT
919 if (fat_bpb->is_fat16)
920 return 0; /* FAT16 has no FsInfo */
921 #endif /* #ifdef HAVE_FAT16SUPPORT */
923 /* update fsinfo */
924 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
925 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
926 if (rc < 0)
928 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
929 return rc * 10 - 1;
931 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
932 *intptr = htole32(fat_bpb->fsinfo.freecount);
934 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
935 *intptr = htole32(fat_bpb->fsinfo.nextfree);
937 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
938 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
939 if (rc < 0)
941 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
942 return rc * 10 - 2;
945 return 0;
948 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
950 int i;
951 int rc;
952 unsigned char *sec;
953 LDEBUGF("flush_fat()\n");
955 mutex_lock(&cache_mutex);
956 for(i = 0;i < FAT_CACHE_SIZE;i++)
958 struct fat_cache_entry *fce = &fat_cache[i];
959 if(fce->inuse
960 #ifdef HAVE_MULTIVOLUME
961 && fce->fat_vol == fat_bpb
962 #endif
963 && fce->dirty)
965 sec = fat_cache_sectors[i];
966 flush_fat_sector(fce, sec);
969 mutex_unlock(&cache_mutex);
971 rc = update_fsinfo(IF_MV(fat_bpb));
972 if (rc < 0)
973 return rc * 10 - 3;
975 return 0;
978 static void fat_time(unsigned short* date,
979 unsigned short* time,
980 unsigned short* tenth )
982 #if CONFIG_RTC
983 struct tm* tm = get_time();
985 if (date)
986 *date = ((tm->tm_year - 80) << 9) |
987 ((tm->tm_mon + 1) << 5) |
988 tm->tm_mday;
990 if (time)
991 *time = (tm->tm_hour << 11) |
992 (tm->tm_min << 5) |
993 (tm->tm_sec >> 1);
995 if (tenth)
996 *tenth = (tm->tm_sec & 1) * 100;
997 #else
998 /* non-RTC version returns an increment from the supplied time, or a
999 * fixed standard time/date if no time given as input */
1000 bool next_day = false;
1002 if (time)
1004 if (0 == *time)
1006 /* set to 00:15:00 */
1007 *time = (15 << 5);
1009 else
1011 unsigned short mins = (*time >> 5) & 0x003F;
1012 unsigned short hours = (*time >> 11) & 0x001F;
1013 if ((mins += 10) >= 60)
1015 mins = 0;
1016 hours++;
1018 if ((++hours) >= 24)
1020 hours = hours - 24;
1021 next_day = true;
1023 *time = (hours << 11) | (mins << 5);
1027 if (date)
1029 if (0 == *date)
1031 /* Macros to convert a 2-digit string to a decimal constant.
1032 (YEAR), MONTH and DAY are set by the date command, which outputs
1033 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1034 misinterpretation as an octal constant. */
1035 #define S100(x) 1 ## x
1036 #define C2DIG2DEC(x) (S100(x)-100)
1037 /* set to build date */
1038 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1039 | C2DIG2DEC(DAY);
1041 else
1043 unsigned short day = *date & 0x001F;
1044 unsigned short month = (*date >> 5) & 0x000F;
1045 unsigned short year = (*date >> 9) & 0x007F;
1046 if (next_day)
1048 /* do a very simple day increment - never go above 28 days */
1049 if (++day > 28)
1051 day = 1;
1052 if (++month > 12)
1054 month = 1;
1055 year++;
1058 *date = (year << 9) | (month << 5) | day;
1062 if (tenth)
1063 *tenth = 0;
1064 #endif /* CONFIG_RTC */
1067 static int write_long_name(struct fat_file* file,
1068 unsigned int firstentry,
1069 unsigned int numentries,
1070 const unsigned char* name,
1071 const unsigned char* shortname,
1072 bool is_directory)
1074 unsigned char buf[SECTOR_SIZE];
1075 unsigned char* entry;
1076 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1077 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1078 unsigned char chksum = 0;
1079 unsigned int i, j=0;
1080 unsigned int nameidx=0, namelen = utf8length(name);
1081 int rc;
1082 unsigned short name_utf16[namelen + 1];
1084 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1085 file->firstcluster, firstentry, numentries, name);
1087 rc = fat_seek(file, sector);
1088 if (rc<0)
1089 return rc * 10 - 1;
1091 rc = fat_readwrite(file, 1, buf, false);
1092 if (rc<1)
1093 return rc * 10 - 2;
1095 /* calculate shortname checksum */
1096 for (i=11; i>0; i--)
1097 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1099 /* calc position of last name segment */
1100 if ( namelen > NAME_BYTES_PER_ENTRY )
1101 for (nameidx=0;
1102 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1103 nameidx += NAME_BYTES_PER_ENTRY);
1105 /* we need to convert the name first */
1106 /* since it is written in reverse order */
1107 for (i = 0; i <= namelen; i++)
1108 name = utf8decode(name, &name_utf16[i]);
1110 for (i=0; i < numentries; i++) {
1111 /* new sector? */
1112 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1113 /* update current sector */
1114 rc = fat_seek(file, sector);
1115 if (rc<0)
1116 return rc * 10 - 3;
1118 rc = fat_readwrite(file, 1, buf, true);
1119 if (rc<1)
1120 return rc * 10 - 4;
1122 /* read next sector */
1123 rc = fat_readwrite(file, 1, buf, false);
1124 if (rc<0) {
1125 LDEBUGF("Failed writing new sector: %d\n",rc);
1126 return rc * 10 - 5;
1128 if (rc==0)
1129 /* end of dir */
1130 memset(buf, 0, sizeof buf);
1132 sector++;
1133 idx = 0;
1136 entry = buf + idx * DIR_ENTRY_SIZE;
1138 /* verify this entry is free */
1139 if (entry[0] && entry[0] != 0xe5 )
1140 panicf("Dir entry %d in sector %x is not free! "
1141 "%02x %02x %02x %02x",
1142 idx, sector,
1143 entry[0], entry[1], entry[2], entry[3]);
1145 memset(entry, 0, DIR_ENTRY_SIZE);
1146 if ( i+1 < numentries ) {
1147 /* longname entry */
1148 unsigned int k, l = nameidx;
1150 entry[FATLONG_ORDER] = numentries-i-1;
1151 if (i==0) {
1152 /* mark this as last long entry */
1153 entry[FATLONG_ORDER] |= 0x40;
1155 /* pad name with 0xffff */
1156 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1157 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1158 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1160 /* set name */
1161 for (k=0; k<5 && l <= namelen; k++) {
1162 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1163 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1165 for (k=0; k<6 && l <= namelen; k++) {
1166 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1167 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1169 for (k=0; k<2 && l <= namelen; k++) {
1170 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1171 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1174 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1175 entry[FATDIR_FSTCLUSLO] = 0;
1176 entry[FATLONG_TYPE] = 0;
1177 entry[FATLONG_CHKSUM] = chksum;
1178 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1180 else {
1181 /* shortname entry */
1182 unsigned short date=0, time=0, tenth=0;
1183 LDEBUGF("Shortname entry: %s\n", shortname);
1184 strncpy(entry + FATDIR_NAME, shortname, 11);
1185 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1186 entry[FATDIR_NTRES] = 0;
1188 fat_time(&date, &time, &tenth);
1189 entry[FATDIR_CRTTIMETENTH] = tenth;
1190 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1191 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1192 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1193 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1194 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1196 idx++;
1197 nameidx -= NAME_BYTES_PER_ENTRY;
1200 /* update last sector */
1201 rc = fat_seek(file, sector);
1202 if (rc<0)
1203 return rc * 10 - 6;
1205 rc = fat_readwrite(file, 1, buf, true);
1206 if (rc<1)
1207 return rc * 10 - 7;
1209 return 0;
1212 static int fat_checkname(const unsigned char* newname)
1214 static const char invalid_chars[] = "\"*/:<>?\\|";
1215 int len = strlen(newname);
1216 /* More sanity checks are probably needed */
1217 if (len > 255 || newname[len - 1] == '.')
1219 return -1;
1221 while (*newname)
1223 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1224 return -1;
1225 newname++;
1227 /* check trailing space(s) */
1228 if(*(--newname) == ' ')
1229 return -1;
1231 return 0;
1234 static int add_dir_entry(struct fat_dir* dir,
1235 struct fat_file* file,
1236 const char* name,
1237 bool is_directory,
1238 bool dotdir)
1240 #ifdef HAVE_MULTIVOLUME
1241 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1242 #else
1243 struct bpb* fat_bpb = &fat_bpbs[0];
1244 #endif
1245 unsigned char buf[SECTOR_SIZE];
1246 unsigned char shortname[12];
1247 int rc;
1248 unsigned int sector;
1249 bool done = false;
1250 int entries_needed, entries_found = 0;
1251 int firstentry;
1253 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1254 name, file->firstcluster);
1256 /* Don't check dotdirs name for validity */
1257 if (dotdir == false) {
1258 rc = fat_checkname(name);
1259 if (rc < 0) {
1260 /* filename is invalid */
1261 return rc * 10 - 1;
1265 #ifdef HAVE_MULTIVOLUME
1266 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1267 #endif
1269 /* The "." and ".." directory entries must not be long names */
1270 if(dotdir) {
1271 int i;
1272 strncpy(shortname, name, 12);
1273 for(i = strlen(shortname); i < 12; i++)
1274 shortname[i] = ' ';
1276 entries_needed = 1;
1277 } else {
1278 create_dos_name(name, shortname);
1280 /* one dir entry needed for every 13 bytes of filename,
1281 plus one entry for the short name */
1282 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1283 / NAME_BYTES_PER_ENTRY + 1;
1286 restart:
1287 firstentry = -1;
1289 rc = fat_seek(&dir->file, 0);
1290 if (rc < 0)
1291 return rc * 10 - 2;
1293 /* step 1: search for free entries and check for duplicate shortname */
1294 for (sector = 0; !done; sector++)
1296 unsigned int i;
1298 rc = fat_readwrite(&dir->file, 1, buf, false);
1299 if (rc < 0) {
1300 DEBUGF( "add_dir_entry() - Couldn't read dir"
1301 " (error code %d)\n", rc);
1302 return rc * 10 - 3;
1305 if (rc == 0) { /* current end of dir reached */
1306 LDEBUGF("End of dir on cluster boundary\n");
1307 break;
1310 /* look for free slots */
1311 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1313 switch (buf[i * DIR_ENTRY_SIZE]) {
1314 case 0:
1315 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1316 LDEBUGF("Found end of dir %d\n",
1317 sector * DIR_ENTRIES_PER_SECTOR + i);
1318 i = DIR_ENTRIES_PER_SECTOR - 1;
1319 done = true;
1320 break;
1322 case 0xe5:
1323 entries_found++;
1324 LDEBUGF("Found free entry %d (%d/%d)\n",
1325 sector * DIR_ENTRIES_PER_SECTOR + i,
1326 entries_found, entries_needed);
1327 break;
1329 default:
1330 entries_found = 0;
1332 /* check that our intended shortname doesn't already exist */
1333 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1334 /* shortname exists already, make a new one */
1335 randomize_dos_name(shortname);
1336 LDEBUGF("Duplicate shortname, changing to %s\n",
1337 shortname);
1339 /* name has changed, we need to restart search */
1340 goto restart;
1342 break;
1344 if (firstentry < 0 && (entries_found >= entries_needed))
1345 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1346 - entries_found;
1350 /* step 2: extend the dir if necessary */
1351 if (firstentry < 0)
1353 LDEBUGF("Adding new sector(s) to dir\n");
1354 rc = fat_seek(&dir->file, sector);
1355 if (rc < 0)
1356 return rc * 10 - 4;
1357 memset(buf, 0, sizeof buf);
1359 /* we must clear whole clusters */
1360 for (; (entries_found < entries_needed) ||
1361 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1363 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1364 return -5; /* dir too large -- FAT specification */
1366 rc = fat_readwrite(&dir->file, 1, buf, true);
1367 if (rc < 1) /* No more room or something went wrong */
1368 return rc * 10 - 6;
1370 entries_found += DIR_ENTRIES_PER_SECTOR;
1373 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1376 /* step 3: add entry */
1377 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1378 LDEBUGF("Adding longname to entry %d in sector %d\n",
1379 firstentry, sector);
1381 rc = write_long_name(&dir->file, firstentry,
1382 entries_needed, name, shortname, is_directory);
1383 if (rc < 0)
1384 return rc * 10 - 7;
1386 /* remember where the shortname dir entry is located */
1387 file->direntry = firstentry + entries_needed - 1;
1388 file->direntries = entries_needed;
1389 file->dircluster = dir->file.firstcluster;
1390 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1391 file->direntry, file->direntries);
1393 return 0;
1396 static unsigned char char2dos(unsigned char c, int* randomize)
1398 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1400 if (c <= 0x20)
1401 c = 0; /* Illegal char, remove */
1402 else if (strchr(invalid_chars, c) != NULL)
1404 /* Illegal char, replace */
1405 c = '_';
1406 *randomize = 1; /* as per FAT spec */
1408 else
1409 c = toupper(c);
1411 return c;
1414 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1416 int i;
1417 unsigned char *ext;
1418 int randomize = 0;
1420 /* Find extension part */
1421 ext = strrchr(name, '.');
1422 if (ext == name) /* handle .dotnames */
1423 ext = NULL;
1425 /* needs to randomize? */
1426 if((ext && (strlen(ext) > 4)) ||
1427 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1428 randomize = 1;
1430 /* Name part */
1431 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1433 unsigned char c = char2dos(*name, &randomize);
1434 if (c)
1435 newname[i++] = c;
1438 /* Pad both name and extension */
1439 while (i < 11)
1440 newname[i++] = ' ';
1442 if (newname[0] == 0xe5) /* Special kanji character */
1443 newname[0] = 0x05;
1445 if (ext)
1446 { /* Extension part */
1447 ext++;
1448 for (i = 8; *ext && (i < 11); ext++)
1450 unsigned char c = char2dos(*ext, &randomize);
1451 if (c)
1452 newname[i++] = c;
1456 if(randomize)
1457 randomize_dos_name(newname);
1460 static void randomize_dos_name(unsigned char *name)
1462 unsigned char* tilde = NULL; /* ~ location */
1463 unsigned char* lastpt = NULL; /* last point of filename */
1464 unsigned char* nameptr = name; /* working copy of name pointer */
1465 unsigned char num[9]; /* holds number as string */
1466 int i = 0;
1467 int cnt = 1;
1468 int numlen;
1469 int offset;
1471 while(i++ < 8)
1473 /* hunt for ~ and where to put it */
1474 if((!tilde) && (*nameptr == '~'))
1475 tilde = nameptr;
1476 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1477 lastpt = nameptr;
1478 nameptr++;
1480 if(tilde)
1482 /* extract current count and increment */
1483 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1484 num[7-(unsigned int)(tilde-name)] = 0;
1485 cnt = atoi(num) + 1;
1487 cnt %= 10000000; /* protection */
1488 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1489 numlen = strlen(num); /* required space */
1490 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1491 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1493 memcpy(&name[offset], num, numlen);
1495 /* in special case of counter overflow: pad with spaces */
1496 for(offset = offset+numlen; offset < 8; offset++)
1497 name[offset] = ' ';
1500 static int update_short_entry( struct fat_file* file, long size, int attr )
1502 unsigned char buf[SECTOR_SIZE];
1503 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1504 unsigned char* entry =
1505 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1506 unsigned long* sizeptr;
1507 unsigned short* clusptr;
1508 struct fat_file dir;
1509 int rc;
1511 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1512 file->firstcluster, file->direntry, size);
1514 /* create a temporary file handle for the dir holding this file */
1515 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1516 if (rc < 0)
1517 return rc * 10 - 1;
1519 rc = fat_seek( &dir, sector );
1520 if (rc<0)
1521 return rc * 10 - 2;
1523 rc = fat_readwrite(&dir, 1, buf, false);
1524 if (rc < 1)
1525 return rc * 10 - 3;
1527 if (!entry[0] || entry[0] == 0xe5)
1528 panicf("Updating size on empty dir entry %d\n", file->direntry);
1530 entry[FATDIR_ATTR] = attr & 0xFF;
1532 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1533 *clusptr = htole16(file->firstcluster >> 16);
1535 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1536 *clusptr = htole16(file->firstcluster & 0xffff);
1538 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1539 *sizeptr = htole32(size);
1542 #if CONFIG_RTC
1543 unsigned short time = 0;
1544 unsigned short date = 0;
1545 #else
1546 /* get old time to increment from */
1547 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1548 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1549 #endif
1550 fat_time(&date, &time, NULL);
1551 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1552 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1553 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1556 rc = fat_seek( &dir, sector );
1557 if (rc < 0)
1558 return rc * 10 - 4;
1560 rc = fat_readwrite(&dir, 1, buf, true);
1561 if (rc < 1)
1562 return rc * 10 - 5;
1564 return 0;
1567 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1569 int i=0,j=0;
1570 unsigned char c;
1571 bool lowercase;
1573 memset(de, 0, sizeof(struct fat_direntry));
1574 de->attr = buf[FATDIR_ATTR];
1575 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1576 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1577 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1578 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1579 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1580 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1581 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1582 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1583 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1584 (the result of the shift is always considered signed) */
1586 /* fix the name */
1587 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1588 c = buf[FATDIR_NAME];
1589 if (c == 0x05) /* special kanji char */
1590 c = 0xe5;
1591 i = 0;
1592 while (c != ' ') {
1593 de->name[j++] = lowercase ? tolower(c) : c;
1594 if (++i >= 8)
1595 break;
1596 c = buf[FATDIR_NAME+i];
1598 if (buf[FATDIR_NAME+8] != ' ') {
1599 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1600 de->name[j++] = '.';
1601 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1602 de->name[j++] = lowercase ? tolower(c) : c;
1604 return 1;
1607 int fat_open(IF_MV2(int volume,)
1608 long startcluster,
1609 struct fat_file *file,
1610 const struct fat_dir* dir)
1612 file->firstcluster = startcluster;
1613 file->lastcluster = startcluster;
1614 file->lastsector = 0;
1615 file->clusternum = 0;
1616 file->sectornum = 0;
1617 file->eof = false;
1618 #ifdef HAVE_MULTIVOLUME
1619 file->volume = volume;
1620 /* fixme: remove error check when done */
1621 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1623 LDEBUGF("fat_open() illegal volume %d\n", volume);
1624 return -1;
1626 #endif
1628 /* remember where the file's dir entry is located */
1629 if ( dir ) {
1630 file->direntry = dir->entry - 1;
1631 file->direntries = dir->entrycount;
1632 file->dircluster = dir->file.firstcluster;
1634 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1635 return 0;
1638 int fat_create_file(const char* name,
1639 struct fat_file* file,
1640 struct fat_dir* dir)
1642 int rc;
1644 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1645 rc = add_dir_entry(dir, file, name, false, false);
1646 if (!rc) {
1647 file->firstcluster = 0;
1648 file->lastcluster = 0;
1649 file->lastsector = 0;
1650 file->clusternum = 0;
1651 file->sectornum = 0;
1652 file->eof = false;
1655 return rc;
1658 int fat_create_dir(const char* name,
1659 struct fat_dir* newdir,
1660 struct fat_dir* dir)
1662 #ifdef HAVE_MULTIVOLUME
1663 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1664 #else
1665 struct bpb* fat_bpb = &fat_bpbs[0];
1666 #endif
1667 unsigned char buf[SECTOR_SIZE];
1668 int i;
1669 long sector;
1670 int rc;
1671 struct fat_file dummyfile;
1673 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1675 memset(newdir, 0, sizeof(struct fat_dir));
1676 memset(&dummyfile, 0, sizeof(struct fat_file));
1678 /* First, add the entry in the parent directory */
1679 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1680 if (rc < 0)
1681 return rc * 10 - 1;
1683 /* Allocate a new cluster for the directory */
1684 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1685 fat_bpb->fsinfo.nextfree);
1686 if(newdir->file.firstcluster == 0)
1687 return -1;
1689 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1691 /* Clear the entire cluster */
1692 memset(buf, 0, sizeof buf);
1693 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1694 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1695 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1696 if (rc < 0)
1697 return rc * 10 - 2;
1700 /* Then add the "." entry */
1701 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1702 if (rc < 0)
1703 return rc * 10 - 3;
1704 dummyfile.firstcluster = newdir->file.firstcluster;
1705 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1707 /* and the ".." entry */
1708 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1709 if (rc < 0)
1710 return rc * 10 - 4;
1712 /* The root cluster is cluster 0 in the ".." entry */
1713 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1714 dummyfile.firstcluster = 0;
1715 else
1716 dummyfile.firstcluster = dir->file.firstcluster;
1717 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1719 /* Set the firstcluster field in the direntry */
1720 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1722 rc = flush_fat(IF_MV(fat_bpb));
1723 if (rc < 0)
1724 return rc * 10 - 5;
1726 return rc;
1729 int fat_truncate(const struct fat_file *file)
1731 /* truncate trailing clusters */
1732 long next;
1733 long last = file->lastcluster;
1734 #ifdef HAVE_MULTIVOLUME
1735 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1736 #endif
1738 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1740 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1741 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1742 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1744 if (file->lastcluster)
1745 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1747 return 0;
1750 int fat_closewrite(struct fat_file *file, long size, int attr)
1752 int rc;
1753 #ifdef HAVE_MULTIVOLUME
1754 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1755 #endif
1756 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1758 if (!size) {
1759 /* empty file */
1760 if ( file->firstcluster ) {
1761 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1762 file->firstcluster = 0;
1766 if (file->dircluster) {
1767 rc = update_short_entry(file, size, attr);
1768 if (rc < 0)
1769 return rc * 10 - 1;
1772 flush_fat(IF_MV(fat_bpb));
1774 #ifdef TEST_FAT
1775 if ( file->firstcluster ) {
1776 /* debug */
1777 #ifdef HAVE_MULTIVOLUME
1778 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1779 #else
1780 struct bpb* fat_bpb = &fat_bpbs[0];
1781 #endif
1782 long count = 0;
1783 long len;
1784 long next;
1785 for ( next = file->firstcluster; next;
1786 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1787 LDEBUGF("cluster %ld: %lx\n", count, next);
1788 count++;
1790 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1791 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1792 count, len, size );
1793 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1794 panicf("Cluster chain is too long\n");
1795 if ( len < size )
1796 panicf("Cluster chain is too short\n");
1798 #endif
1800 return 0;
1803 static int free_direntries(struct fat_file* file)
1805 unsigned char buf[SECTOR_SIZE];
1806 struct fat_file dir;
1807 int numentries = file->direntries;
1808 unsigned int entry = file->direntry - numentries + 1;
1809 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1810 int i;
1811 int rc;
1813 /* create a temporary file handle for the dir holding this file */
1814 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1815 if (rc < 0)
1816 return rc * 10 - 1;
1818 rc = fat_seek( &dir, sector );
1819 if (rc < 0)
1820 return rc * 10 - 2;
1822 rc = fat_readwrite(&dir, 1, buf, false);
1823 if (rc < 1)
1824 return rc * 10 - 3;
1826 for (i=0; i < numentries; i++) {
1827 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1828 entry, i+1, numentries);
1829 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1830 entry++;
1832 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1833 /* flush this sector */
1834 rc = fat_seek(&dir, sector);
1835 if (rc < 0)
1836 return rc * 10 - 4;
1838 rc = fat_readwrite(&dir, 1, buf, true);
1839 if (rc < 1)
1840 return rc * 10 - 5;
1842 if ( i+1 < numentries ) {
1843 /* read next sector */
1844 rc = fat_readwrite(&dir, 1, buf, false);
1845 if (rc < 1)
1846 return rc * 10 - 6;
1848 sector++;
1852 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1853 /* flush this sector */
1854 rc = fat_seek(&dir, sector);
1855 if (rc < 0)
1856 return rc * 10 - 7;
1858 rc = fat_readwrite(&dir, 1, buf, true);
1859 if (rc < 1)
1860 return rc * 10 - 8;
1863 return 0;
1866 int fat_remove(struct fat_file* file)
1868 long next, last = file->firstcluster;
1869 int rc;
1870 #ifdef HAVE_MULTIVOLUME
1871 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1872 #endif
1874 LDEBUGF("fat_remove(%lx)\n",last);
1876 while ( last ) {
1877 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1878 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1879 last = next;
1882 if ( file->dircluster ) {
1883 rc = free_direntries(file);
1884 if (rc < 0)
1885 return rc * 10 - 1;
1888 file->firstcluster = 0;
1889 file->dircluster = 0;
1891 rc = flush_fat(IF_MV(fat_bpb));
1892 if (rc < 0)
1893 return rc * 10 - 2;
1895 return 0;
1898 int fat_rename(struct fat_file* file,
1899 struct fat_dir* dir,
1900 const unsigned char* newname,
1901 long size,
1902 int attr)
1904 int rc;
1905 struct fat_dir olddir;
1906 struct fat_file newfile = *file;
1907 unsigned char buf[SECTOR_SIZE];
1908 unsigned char* entry = NULL;
1909 unsigned short* clusptr = NULL;
1910 unsigned int parentcluster;
1911 #ifdef HAVE_MULTIVOLUME
1912 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1914 if (file->volume != dir->file.volume) {
1915 DEBUGF("No rename across volumes!\n");
1916 return -1;
1918 #else
1919 struct bpb* fat_bpb = &fat_bpbs[0];
1920 #endif
1922 if ( !file->dircluster ) {
1923 DEBUGF("File has no dir cluster!\n");
1924 return -2;
1927 /* create a temporary file handle */
1928 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1929 if (rc < 0)
1930 return rc * 10 - 1;
1932 /* create new name */
1933 rc = add_dir_entry(dir, &newfile, newname, false, false);
1934 if (rc < 0)
1935 return rc * 10 - 2;
1937 /* write size and cluster link */
1938 rc = update_short_entry(&newfile, size, attr);
1939 if (rc < 0)
1940 return rc * 10 - 3;
1942 /* remove old name */
1943 rc = free_direntries(file);
1944 if (rc < 0)
1945 return rc * 10 - 4;
1947 rc = flush_fat(IF_MV(fat_bpb));
1948 if (rc < 0)
1949 return rc * 10 - 5;
1951 /* if renaming a directory, update the .. entry to make sure
1952 it points to its parent directory (we don't check if it was a move) */
1953 if(FAT_ATTR_DIRECTORY == attr) {
1954 /* open the dir that was renamed, we re-use the olddir struct */
1955 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1956 NULL);
1957 if (rc < 0)
1958 return rc * 10 - 6;
1960 /* get the first sector of the dir */
1961 rc = fat_seek(&olddir.file, 0);
1962 if (rc < 0)
1963 return rc * 10 - 7;
1965 rc = fat_readwrite(&olddir.file, 1, buf, false);
1966 if (rc < 0)
1967 return rc * 10 - 8;
1969 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1970 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1971 parentcluster = 0;
1972 else
1973 parentcluster = dir->file.firstcluster;
1975 entry = buf + DIR_ENTRY_SIZE;
1976 if(strncmp(".. ", entry, 11))
1978 /* .. entry must be second entry according to FAT spec (p.29) */
1979 DEBUGF("Second dir entry is not double-dot!\n");
1980 return rc * 10 - 9;
1982 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1983 *clusptr = htole16(parentcluster >> 16);
1985 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1986 *clusptr = htole16(parentcluster & 0xffff);
1988 /* write back this sector */
1989 rc = fat_seek(&olddir.file, 0);
1990 if (rc < 0)
1991 return rc * 10 - 7;
1993 rc = fat_readwrite(&olddir.file, 1, buf, true);
1994 if (rc < 1)
1995 return rc * 10 - 8;
1998 return 0;
2001 static long next_write_cluster(struct fat_file* file,
2002 long oldcluster,
2003 long* newsector)
2005 #ifdef HAVE_MULTIVOLUME
2006 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2007 #else
2008 struct bpb* fat_bpb = &fat_bpbs[0];
2009 #endif
2010 long cluster = 0;
2011 long sector;
2013 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2015 if (oldcluster)
2016 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2018 if (!cluster) {
2019 if (oldcluster > 0)
2020 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2021 else if (oldcluster == 0)
2022 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2023 fat_bpb->fsinfo.nextfree);
2024 #ifdef HAVE_FAT16SUPPORT
2025 else /* negative, pseudo-cluster of the root dir */
2026 return 0; /* impossible to append something to the root */
2027 #endif
2029 if (cluster) {
2030 if (oldcluster)
2031 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2032 else
2033 file->firstcluster = cluster;
2034 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2036 else {
2037 #ifdef TEST_FAT
2038 if (fat_bpb->fsinfo.freecount>0)
2039 panicf("There is free space, but find_free_cluster() "
2040 "didn't find it!\n");
2041 #endif
2042 DEBUGF("next_write_cluster(): Disk full!\n");
2043 return 0;
2046 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2047 if (sector<0)
2048 return 0;
2050 *newsector = sector;
2051 return cluster;
2054 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2055 unsigned long start, long count, char* buf, bool write )
2057 #ifndef HAVE_MULTIVOLUME
2058 struct bpb* fat_bpb = &fat_bpbs[0];
2059 #endif
2060 int rc;
2062 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2063 start+ fat_bpb->startsector, count, write?"write":"read");
2064 if (write) {
2065 unsigned long firstallowed;
2066 #ifdef HAVE_FAT16SUPPORT
2067 if (fat_bpb->is_fat16)
2068 firstallowed = fat_bpb->rootdirsector;
2069 else
2070 #endif
2071 firstallowed = fat_bpb->firstdatasector;
2073 if (start < firstallowed)
2074 panicf("Write %ld before data\n", firstallowed - start);
2075 if (start + count > fat_bpb->totalsectors)
2076 panicf("Write %ld after data\n",
2077 start + count - fat_bpb->totalsectors);
2078 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
2079 start + fat_bpb->startsector, count, buf);
2081 else
2082 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
2083 start + fat_bpb->startsector, count, buf);
2084 if (rc < 0) {
2085 DEBUGF( "transfer() - Couldn't %s sector %lx"
2086 " (error code %d)\n",
2087 write ? "write":"read", start, rc);
2088 return rc;
2090 return 0;
2094 long fat_readwrite( struct fat_file *file, long sectorcount,
2095 void* buf, bool write )
2097 #ifdef HAVE_MULTIVOLUME
2098 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2099 #else
2100 struct bpb* fat_bpb = &fat_bpbs[0];
2101 #endif
2102 long cluster = file->lastcluster;
2103 long sector = file->lastsector;
2104 long clusternum = file->clusternum;
2105 long numsec = file->sectornum;
2106 bool eof = file->eof;
2107 long first=0, last=0;
2108 long i;
2109 int rc;
2111 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2112 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2113 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2114 sector,numsec, eof?1:0);
2116 if ( eof && !write)
2117 return 0;
2119 /* find sequential sectors and write them all at once */
2120 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2121 numsec++;
2122 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2123 long oldcluster = cluster;
2124 long oldsector = sector;
2125 long oldnumsec = numsec;
2126 if (write)
2127 cluster = next_write_cluster(file, cluster, &sector);
2128 else {
2129 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2130 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2133 clusternum++;
2134 numsec=1;
2136 if (!cluster) {
2137 eof = true;
2138 if ( write ) {
2139 /* remember last cluster, in case
2140 we want to append to the file */
2141 sector = oldsector;
2142 cluster = oldcluster;
2143 numsec = oldnumsec;
2144 clusternum--;
2145 i = -1; /* Error code */
2146 break;
2149 else
2150 eof = false;
2152 else {
2153 if (sector)
2154 sector++;
2155 else {
2156 /* look up first sector of file */
2157 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2158 numsec=1;
2159 #ifdef HAVE_FAT16SUPPORT
2160 if (file->firstcluster < 0)
2161 { /* FAT16 root dir */
2162 sector += fat_bpb->rootdiroffset;
2163 numsec += fat_bpb->rootdiroffset;
2165 #endif
2169 if (!first)
2170 first = sector;
2172 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2173 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2174 long count = last - first + 1;
2175 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2176 if (rc < 0)
2177 return rc * 10 - 1;
2179 buf = (char *)buf + count * SECTOR_SIZE;
2180 first = sector;
2183 if ((i == sectorcount-1) && /* last sector requested */
2184 (!eof))
2186 long count = sector - first + 1;
2187 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2188 if (rc < 0)
2189 return rc * 10 - 2;
2192 last = sector;
2195 file->lastcluster = cluster;
2196 file->lastsector = sector;
2197 file->clusternum = clusternum;
2198 file->sectornum = numsec;
2199 file->eof = eof;
2201 /* if eof, don't report last block as read/written */
2202 if (eof)
2203 i--;
2205 DEBUGF("Sectors written: %ld\n", i);
2206 return i;
2209 int fat_seek(struct fat_file *file, unsigned long seeksector )
2211 #ifdef HAVE_MULTIVOLUME
2212 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2213 #else
2214 struct bpb* fat_bpb = &fat_bpbs[0];
2215 #endif
2216 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2217 long cluster = file->firstcluster;
2218 long i;
2220 #ifdef HAVE_FAT16SUPPORT
2221 if (cluster < 0) /* FAT16 root dir */
2222 seeksector += fat_bpb->rootdiroffset;
2223 #endif
2225 file->eof = false;
2226 if (seeksector) {
2227 /* we need to find the sector BEFORE the requested, since
2228 the file struct stores the last accessed sector */
2229 seeksector--;
2230 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2231 sectornum = seeksector % fat_bpb->bpb_secperclus;
2233 if (file->clusternum && clusternum >= file->clusternum)
2235 cluster = file->lastcluster;
2236 numclusters -= file->clusternum;
2239 for (i=0; i<numclusters; i++) {
2240 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2241 if (!cluster) {
2242 DEBUGF("Seeking beyond the end of the file! "
2243 "(sector %ld, cluster %ld)\n", seeksector, i);
2244 return -1;
2248 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2250 else {
2251 sectornum = -1;
2254 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2255 file->firstcluster, seeksector, cluster, sector, sectornum);
2257 file->lastcluster = cluster;
2258 file->lastsector = sector;
2259 file->clusternum = clusternum;
2260 file->sectornum = sectornum + 1;
2261 return 0;
2264 int fat_opendir(IF_MV2(int volume,)
2265 struct fat_dir *dir, unsigned long startcluster,
2266 const struct fat_dir *parent_dir)
2268 #ifdef HAVE_MULTIVOLUME
2269 struct bpb* fat_bpb = &fat_bpbs[volume];
2270 /* fixme: remove error check when done */
2271 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2273 LDEBUGF("fat_open() illegal volume %d\n", volume);
2274 return -1;
2276 #else
2277 struct bpb* fat_bpb = &fat_bpbs[0];
2278 #endif
2279 int rc;
2281 dir->entry = 0;
2282 dir->sector = 0;
2284 if (startcluster == 0)
2285 startcluster = fat_bpb->bpb_rootclus;
2287 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2288 if(rc)
2290 DEBUGF( "fat_opendir() - Couldn't open dir"
2291 " (error code %d)\n", rc);
2292 return rc * 10 - 1;
2295 return 0;
2298 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2299 * destination buffer (UTF-8 encoded). Copying is stopped when
2300 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2301 * Trailing \0 is also appended at the end of the UTF8-encoded
2302 * string.
2304 * utf16src utf16 (little endian) segment to copy
2305 * utf16count max number of the utf16-characters to copy
2306 * utf8dst where to write UTF8-encoded string to
2308 * returns the number of UTF-16 characters actually copied
2310 static int fat_copy_long_name_segment(unsigned char *utf16src,
2311 int utf16count, unsigned char *utf8dst) {
2312 int cnt = 0;
2313 while ((utf16count--) > 0) {
2314 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2315 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2316 break;
2318 utf8dst = utf8encode(ucs, utf8dst);
2319 utf16src += 2;
2320 cnt++;
2322 *utf8dst = 0;
2323 return cnt;
2326 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2328 bool done = false;
2329 int i;
2330 int rc;
2331 unsigned char firstbyte;
2332 /* Long file names are stored in special entries. Each entry holds
2333 up to 13 characters. Names can be max 255 chars (not bytes!) long
2334 hence max 20 entries are required. */
2335 int longarray[20];
2336 int longs=0;
2337 int sectoridx=0;
2338 unsigned char* cached_buf = dir->sectorcache[0];
2340 dir->entrycount = 0;
2342 while(!done)
2344 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2346 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2347 if (rc == 0) {
2348 /* eof */
2349 entry->name[0] = 0;
2350 break;
2352 if (rc < 0) {
2353 DEBUGF( "fat_getnext() - Couldn't read dir"
2354 " (error code %d)\n", rc);
2355 return rc * 10 - 1;
2357 dir->sector = dir->file.lastsector;
2360 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2361 i < DIR_ENTRIES_PER_SECTOR; i++)
2363 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2365 firstbyte = cached_buf[entrypos];
2366 dir->entry++;
2368 if (firstbyte == 0xe5) {
2369 /* free entry */
2370 sectoridx = 0;
2371 dir->entrycount = 0;
2372 continue;
2375 if (firstbyte == 0) {
2376 /* last entry */
2377 entry->name[0] = 0;
2378 dir->entrycount = 0;
2379 return 0;
2382 dir->entrycount++;
2384 /* longname entry? */
2385 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2386 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2387 longarray[longs++] = entrypos + sectoridx;
2389 else {
2390 if ( parse_direntry(entry,
2391 &cached_buf[entrypos]) ) {
2393 /* don't return volume id entry */
2394 if ( (entry->attr &
2395 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2396 == FAT_ATTR_VOLUME_ID)
2397 continue;
2399 /* replace shortname with longname? */
2400 if ( longs ) {
2401 int j;
2402 /* This should be enough to hold any name segment
2403 utf8-encoded */
2404 unsigned char shortname[13]; /* 8+3+dot+\0 */
2405 /* Add 1 for trailing \0 */
2406 unsigned char longname_utf8segm[6*4 + 1];
2407 int longname_utf8len = 0;
2408 /* Temporarily store it */
2409 strcpy(shortname, entry->name);
2410 entry->name[0] = 0;
2412 /* iterate backwards through the dir entries */
2413 for (j=longs-1; j>=0; j--) {
2414 unsigned char* ptr = cached_buf;
2415 int index = longarray[j];
2416 /* current or cached sector? */
2417 if ( sectoridx >= SECTOR_SIZE ) {
2418 if ( sectoridx >= SECTOR_SIZE*2 ) {
2419 if ( ( index >= SECTOR_SIZE ) &&
2420 ( index < SECTOR_SIZE*2 ))
2421 ptr = dir->sectorcache[1];
2422 else
2423 ptr = dir->sectorcache[2];
2425 else {
2426 if ( index < SECTOR_SIZE )
2427 ptr = dir->sectorcache[1];
2430 index &= SECTOR_SIZE-1;
2433 /* Try to append each segment of the long name.
2434 Check if we'd exceed the buffer.
2435 Also check for FAT padding characters 0xFFFF. */
2436 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2437 longname_utf8segm) == 0) break;
2438 /* logf("SG: %s, EN: %s", longname_utf8segm,
2439 entry->name); */
2440 longname_utf8len += strlen(longname_utf8segm);
2441 if (longname_utf8len < FAT_FILENAME_BYTES)
2442 strcat(entry->name, longname_utf8segm);
2443 else
2444 break;
2446 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2447 longname_utf8segm) == 0) break;
2448 /* logf("SG: %s, EN: %s", longname_utf8segm,
2449 entry->name); */
2450 longname_utf8len += strlen(longname_utf8segm);
2451 if (longname_utf8len < FAT_FILENAME_BYTES)
2452 strcat(entry->name, longname_utf8segm);
2453 else
2454 break;
2456 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2457 longname_utf8segm) == 0) break;
2458 /* logf("SG: %s, EN: %s", longname_utf8segm,
2459 entry->name); */
2460 longname_utf8len += strlen(longname_utf8segm);
2461 if (longname_utf8len < FAT_FILENAME_BYTES)
2462 strcat(entry->name, longname_utf8segm);
2463 else
2464 break;
2467 /* Does the utf8-encoded name fit into the entry? */
2468 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2469 /* Take the short DOS name. Need to utf8-encode it
2470 since it may contain chars from the upper half of
2471 the OEM code page which wouldn't be a valid utf8.
2472 Beware: this file will be shown with strange
2473 glyphs in file browser since unicode 0x80 to 0x9F
2474 are control characters. */
2475 logf("SN-DOS: %s", shortname);
2476 unsigned char *utf8;
2477 utf8 = iso_decode(shortname, entry->name, -1,
2478 strlen(shortname));
2479 *utf8 = 0;
2480 logf("SN: %s", entry->name);
2481 } else {
2482 /* logf("LN: %s", entry->name);
2483 logf("LNLen: %d (%c)", longname_utf8len,
2484 entry->name[0]); */
2487 done = true;
2488 sectoridx = 0;
2489 i++;
2490 break;
2495 /* save this sector, for longname use */
2496 if ( sectoridx )
2497 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2498 else
2499 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2500 sectoridx += SECTOR_SIZE;
2503 return 0;
2506 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2508 #ifndef HAVE_MULTIVOLUME
2509 const int volume = 0;
2510 #endif
2511 struct bpb* fat_bpb = &fat_bpbs[volume];
2512 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2515 #ifdef HAVE_MULTIVOLUME
2516 bool fat_ismounted(int volume)
2518 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2520 #endif