FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / firmware / drivers / fat.c
blob578397cbe6cbd2bb38b086c21d7d6ae6de117c61
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 #include "logf.h"
36 #define BYTES2INT16(array,pos) \
37 (array[pos] | (array[pos+1] << 8 ))
38 #define BYTES2INT32(array,pos) \
39 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
40 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
42 #define FATTYPE_FAT12 0
43 #define FATTYPE_FAT16 1
44 #define FATTYPE_FAT32 2
46 /* BPB offsets; generic */
47 #define BS_JMPBOOT 0
48 #define BS_OEMNAME 3
49 #define BPB_BYTSPERSEC 11
50 #define BPB_SECPERCLUS 13
51 #define BPB_RSVDSECCNT 14
52 #define BPB_NUMFATS 16
53 #define BPB_ROOTENTCNT 17
54 #define BPB_TOTSEC16 19
55 #define BPB_MEDIA 21
56 #define BPB_FATSZ16 22
57 #define BPB_SECPERTRK 24
58 #define BPB_NUMHEADS 26
59 #define BPB_HIDDSEC 28
60 #define BPB_TOTSEC32 32
62 /* fat12/16 */
63 #define BS_DRVNUM 36
64 #define BS_RESERVED1 37
65 #define BS_BOOTSIG 38
66 #define BS_VOLID 39
67 #define BS_VOLLAB 43
68 #define BS_FILSYSTYPE 54
70 /* fat32 */
71 #define BPB_FATSZ32 36
72 #define BPB_EXTFLAGS 40
73 #define BPB_FSVER 42
74 #define BPB_ROOTCLUS 44
75 #define BPB_FSINFO 48
76 #define BPB_BKBOOTSEC 50
77 #define BS_32_DRVNUM 64
78 #define BS_32_BOOTSIG 66
79 #define BS_32_VOLID 67
80 #define BS_32_VOLLAB 71
81 #define BS_32_FILSYSTYPE 82
83 #define BPB_LAST_WORD 510
86 /* attributes */
87 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
88 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
89 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
90 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
91 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
93 /* NTRES flags */
94 #define FAT_NTRES_LC_NAME 0x08
95 #define FAT_NTRES_LC_EXT 0x10
97 #define FATDIR_NAME 0
98 #define FATDIR_ATTR 11
99 #define FATDIR_NTRES 12
100 #define FATDIR_CRTTIMETENTH 13
101 #define FATDIR_CRTTIME 14
102 #define FATDIR_CRTDATE 16
103 #define FATDIR_LSTACCDATE 18
104 #define FATDIR_FSTCLUSHI 20
105 #define FATDIR_WRTTIME 22
106 #define FATDIR_WRTDATE 24
107 #define FATDIR_FSTCLUSLO 26
108 #define FATDIR_FILESIZE 28
110 #define FATLONG_ORDER 0
111 #define FATLONG_TYPE 12
112 #define FATLONG_CHKSUM 13
114 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
115 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
116 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
117 #define DIR_ENTRY_SIZE 32
118 #define NAME_BYTES_PER_ENTRY 13
119 #define FAT_BAD_MARK 0x0ffffff7
120 #define FAT_EOF_MARK 0x0ffffff8
121 #define FAT_LONGNAME_PAD_BYTE 0xff
122 #define FAT_LONGNAME_PAD_UCS 0xffff
124 struct fsinfo {
125 unsigned long freecount; /* last known free cluster count */
126 unsigned long nextfree; /* first cluster to start looking for free
127 clusters, or 0xffffffff for no hint */
129 /* fsinfo offsets */
130 #define FSINFO_FREECOUNT 488
131 #define FSINFO_NEXTFREE 492
133 /* Note: This struct doesn't hold the raw values after mounting if
134 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
135 * physical sectors. */
136 struct bpb
138 int bpb_bytspersec; /* Bytes per sector, typically 512 */
139 unsigned int bpb_secperclus; /* Sectors per cluster */
140 int bpb_rsvdseccnt; /* Number of reserved sectors */
141 int bpb_numfats; /* Number of FAT structures, typically 2 */
142 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
143 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
144 int bpb_fatsz16; /* Number of used sectors per FAT structure */
145 unsigned long bpb_totsec32; /* Number of sectors on the volume
146 (new 32-bit) */
147 unsigned int last_word; /* 0xAA55 */
149 /**** FAT32 specific *****/
150 long bpb_fatsz32;
151 long bpb_rootclus;
152 long bpb_fsinfo;
154 /* variables for internal use */
155 unsigned long fatsize;
156 unsigned long totalsectors;
157 unsigned long rootdirsector;
158 unsigned long firstdatasector;
159 unsigned long startsector;
160 unsigned long dataclusters;
161 struct fsinfo fsinfo;
162 #ifdef HAVE_FAT16SUPPORT
163 int bpb_rootentcnt; /* Number of dir entries in the root */
164 /* internals for FAT16 support */
165 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
166 unsigned int rootdiroffset; /* sector offset of root dir relative to start
167 * of first pseudo cluster */
168 #endif /* #ifdef HAVE_FAT16SUPPORT */
169 #ifdef HAVE_MULTIVOLUME
170 #ifdef HAVE_MULTIDRIVE
171 int drive; /* on which physical device is this located */
172 #endif
173 bool mounted; /* flag if this volume is mounted */
174 #endif
177 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
178 static bool initialized = false;
180 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
181 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
182 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
183 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
184 long secnum, bool dirty);
185 static void create_dos_name(const unsigned char *name, unsigned char *newname);
186 static void randomize_dos_name(unsigned char *name);
187 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
188 unsigned long start);
189 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
190 long count, char* buf, bool write );
192 #define FAT_CACHE_SIZE 0x20
193 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
195 struct fat_cache_entry
197 long secnum;
198 bool inuse;
199 bool dirty;
200 #ifdef HAVE_MULTIVOLUME
201 struct bpb* fat_vol ; /* shared cache for all volumes */
202 #endif
205 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
206 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
207 static struct mutex cache_mutex SHAREDBSS_ATTR;
209 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
210 void fat_lock(void)
212 mutex_lock(&cache_mutex);
215 void fat_unlock(void)
217 mutex_unlock(&cache_mutex);
219 #endif
221 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
223 #ifndef HAVE_MULTIVOLUME
224 struct bpb* fat_bpb = &fat_bpbs[0];
225 #endif
226 #ifdef HAVE_FAT16SUPPORT
227 /* negative clusters (FAT16 root dir) don't get the 2 offset */
228 int zerocluster = cluster < 0 ? 0 : 2;
229 #else
230 const long zerocluster = 2;
231 #endif
233 if (cluster > (long)(fat_bpb->dataclusters + 1))
235 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
236 return -1;
239 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
240 + fat_bpb->firstdatasector;
243 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
245 #ifndef HAVE_MULTIVOLUME
246 const int volume = 0;
247 #endif
248 struct bpb* fat_bpb = &fat_bpbs[volume];
249 if (size)
250 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
251 if (free)
252 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
255 void fat_init(void)
257 unsigned int i;
259 if (!initialized)
261 initialized = true;
262 mutex_init(&cache_mutex);
265 #ifdef HAVE_PRIORITY_SCHEDULING
266 /* Disable this because it is dangerous due to the assumption that
267 * mutex_unlock won't yield */
268 mutex_set_preempt(&cache_mutex, false);
269 #endif
271 /* mark the FAT cache as unused */
272 for(i = 0;i < FAT_CACHE_SIZE;i++)
274 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
275 fat_cache[i].inuse = false;
276 fat_cache[i].dirty = false;
277 #ifdef HAVE_MULTIVOLUME
278 fat_cache[i].fat_vol = NULL;
279 #endif
281 #ifdef HAVE_MULTIVOLUME
282 /* mark the possible volumes as not mounted */
283 for (i=0; i<NUM_VOLUMES;i++)
285 fat_bpbs[i].mounted = false;
287 #endif
290 int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
292 #ifndef HAVE_MULTIVOLUME
293 const int volume = 0;
294 #endif
295 struct bpb* fat_bpb = &fat_bpbs[volume];
296 unsigned char buf[SECTOR_SIZE];
297 int rc;
298 int secmult;
299 long datasec;
300 #ifdef HAVE_FAT16SUPPORT
301 int rootdirsectors;
302 #endif
304 /* Read the sector */
305 rc = storage_read_sectors(drive, startsector,1,buf);
306 if(rc)
308 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
309 return rc * 10 - 1;
312 memset(fat_bpb, 0, sizeof(struct bpb));
313 fat_bpb->startsector = startsector;
314 #ifdef HAVE_MULTIDRIVE
315 fat_bpb->drive = drive;
316 #endif
318 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
319 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
320 /* Sanity check is performed later */
322 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
323 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
324 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
325 fat_bpb->bpb_media = buf[BPB_MEDIA];
326 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
327 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
328 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
329 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
330 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
332 /* calculate a few commonly used values */
333 if (fat_bpb->bpb_fatsz16 != 0)
334 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
335 else
336 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
338 if (fat_bpb->bpb_totsec16 != 0)
339 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
340 else
341 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
343 #ifdef HAVE_FAT16SUPPORT
344 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
345 if (!fat_bpb->bpb_bytspersec)
346 return -2;
347 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
348 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
349 #endif /* #ifdef HAVE_FAT16SUPPORT */
351 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
352 #ifdef HAVE_FAT16SUPPORT
353 + rootdirsectors
354 #endif
355 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
357 /* Determine FAT type */
358 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
359 if (fat_bpb->bpb_secperclus)
360 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
361 else
362 return -2;
364 #ifdef TEST_FAT
366 we are sometimes testing with "illegally small" fat32 images,
367 so we don't use the proper fat32 test case for test code
369 if ( fat_bpb->bpb_fatsz16 )
370 #else
371 if ( fat_bpb->dataclusters < 65525 )
372 #endif
373 { /* FAT16 */
374 #ifdef HAVE_FAT16SUPPORT
375 fat_bpb->is_fat16 = true;
376 if (fat_bpb->dataclusters < 4085)
377 { /* FAT12 */
378 DEBUGF("This is FAT12. Go away!\n");
379 return -2;
381 #else /* #ifdef HAVE_FAT16SUPPORT */
382 DEBUGF("This is not FAT32. Go away!\n");
383 return -2;
384 #endif /* #ifndef HAVE_FAT16SUPPORT */
387 #ifdef HAVE_FAT16SUPPORT
388 if (fat_bpb->is_fat16)
389 { /* FAT16 specific part of BPB */
390 int dirclusters;
391 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
392 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
393 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
394 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
395 /* I assign negative pseudo cluster numbers for the root directory,
396 their range is counted upward until -1. */
397 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
398 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
399 - rootdirsectors;
401 else
402 #endif /* #ifdef HAVE_FAT16SUPPORT */
403 { /* FAT32 specific part of BPB */
404 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
405 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
406 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
407 fat_bpb->bpb_rootclus);
410 rc = bpb_is_sane(IF_MV(fat_bpb));
411 if (rc < 0)
413 DEBUGF( "fat_mount() - BPB is not sane\n");
414 return rc * 10 - 3;
417 #ifdef HAVE_FAT16SUPPORT
418 if (fat_bpb->is_fat16)
420 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
421 fat_bpb->fsinfo.nextfree = 0xffffffff;
423 else
424 #endif /* #ifdef HAVE_FAT16SUPPORT */
426 /* Read the fsinfo sector */
427 rc = storage_read_sectors(drive,
428 startsector + fat_bpb->bpb_fsinfo, 1, buf);
429 if (rc < 0)
431 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
432 return rc * 10 - 4;
434 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
435 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
438 /* calculate freecount if unset */
439 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
441 fat_recalc_free(IF_MV(volume));
444 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
445 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
446 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
447 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
448 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
450 #ifdef HAVE_MULTIVOLUME
451 fat_bpb->mounted = true;
452 #endif
454 return 0;
457 #ifdef HAVE_HOTSWAP
458 int fat_unmount(int volume, bool flush)
460 int rc;
461 struct bpb* fat_bpb = &fat_bpbs[volume];
463 if(flush)
465 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
467 else
468 { /* volume is not accessible any more, e.g. MMC removed */
469 int i;
470 mutex_lock(&cache_mutex);
471 for(i = 0;i < FAT_CACHE_SIZE;i++)
473 struct fat_cache_entry *fce = &fat_cache[i];
474 if(fce->inuse && fce->fat_vol == fat_bpb)
476 fce->inuse = false; /* discard all from that volume */
477 fce->dirty = false;
480 mutex_unlock(&cache_mutex);
481 rc = 0;
483 fat_bpb->mounted = false;
484 return rc;
486 #endif /* #ifdef HAVE_HOTSWAP */
488 void fat_recalc_free(IF_MV_NONVOID(int volume))
490 #ifndef HAVE_MULTIVOLUME
491 const int volume = 0;
492 #endif
493 struct bpb* fat_bpb = &fat_bpbs[volume];
494 long free = 0;
495 unsigned long i;
496 #ifdef HAVE_FAT16SUPPORT
497 if (fat_bpb->is_fat16)
499 for (i = 0; i<fat_bpb->fatsize; i++) {
500 unsigned int j;
501 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
502 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
503 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
504 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
505 break;
507 if (letoh16(fat[j]) == 0x0000) {
508 free++;
509 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
510 fat_bpb->fsinfo.nextfree = c;
515 else
516 #endif /* #ifdef HAVE_FAT16SUPPORT */
518 for (i = 0; i<fat_bpb->fatsize; i++) {
519 unsigned int j;
520 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
521 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
522 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
523 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
524 break;
526 if (!(letoh32(fat[j]) & 0x0fffffff)) {
527 free++;
528 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
529 fat_bpb->fsinfo.nextfree = c;
534 fat_bpb->fsinfo.freecount = free;
535 update_fsinfo(IF_MV(fat_bpb));
538 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
540 #ifndef HAVE_MULTIVOLUME
541 struct bpb* fat_bpb = &fat_bpbs[0];
542 #endif
543 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
545 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
546 fat_bpb->bpb_bytspersec);
547 return -1;
549 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
550 > 128L*1024L)
552 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
553 "(%d * %d = %d)\n",
554 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
555 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
556 return -2;
558 if(fat_bpb->bpb_numfats != 2)
560 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
561 fat_bpb->bpb_numfats);
563 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
565 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
566 "media type (0x%02x)\n",
567 fat_bpb->bpb_media);
569 if(fat_bpb->last_word != 0xaa55)
571 DEBUGF( "bpb_is_sane() - Error: Last word is not "
572 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
573 return -3;
576 if (fat_bpb->fsinfo.freecount >
577 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
578 fat_bpb->bpb_secperclus)
580 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
581 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
582 return -4;
585 return 0;
588 static void flush_fat_sector(struct fat_cache_entry *fce,
589 unsigned char *sectorbuf)
591 int rc;
592 long secnum;
594 /* With multivolume, use only the FAT info from the cached sector! */
595 #ifdef HAVE_MULTIVOLUME
596 secnum = fce->secnum + fce->fat_vol->startsector;
597 #else
598 secnum = fce->secnum + fat_bpbs[0].startsector;
599 #endif
601 /* Write to the first FAT */
602 rc = storage_write_sectors(fce->fat_vol->drive,
603 secnum, 1,
604 sectorbuf);
605 if(rc < 0)
607 panicf("flush_fat_sector() - Could not write sector %ld"
608 " (error %d)\n",
609 secnum, rc);
611 #ifdef HAVE_MULTIVOLUME
612 if(fce->fat_vol->bpb_numfats > 1)
613 #else
614 if(fat_bpbs[0].bpb_numfats > 1)
615 #endif
617 /* Write to the second FAT */
618 #ifdef HAVE_MULTIVOLUME
619 secnum += fce->fat_vol->fatsize;
620 #else
621 secnum += fat_bpbs[0].fatsize;
622 #endif
623 rc = storage_write_sectors(fce->fat_vol->drive,
624 secnum, 1, sectorbuf);
625 if(rc < 0)
627 panicf("flush_fat_sector() - Could not write sector %ld"
628 " (error %d)\n",
629 secnum, rc);
632 fce->dirty = false;
635 /* Note: The returned pointer is only safely valid until the next
636 task switch! (Any subsequent ata read/write may yield.) */
637 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
638 long fatsector, bool dirty)
640 #ifndef HAVE_MULTIVOLUME
641 struct bpb* fat_bpb = &fat_bpbs[0];
642 #endif
643 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
644 int cache_index = secnum & FAT_CACHE_MASK;
645 struct fat_cache_entry *fce = &fat_cache[cache_index];
646 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
647 int rc;
649 mutex_lock(&cache_mutex); /* make changes atomic */
651 /* Delete the cache entry if it isn't the sector we want */
652 if(fce->inuse && (fce->secnum != secnum
653 #ifdef HAVE_MULTIVOLUME
654 || fce->fat_vol != fat_bpb
655 #endif
658 /* Write back if it is dirty */
659 if(fce->dirty)
661 flush_fat_sector(fce, sectorbuf);
663 fce->inuse = false;
666 /* Load the sector if it is not cached */
667 if(!fce->inuse)
669 rc = storage_read_sectors(fat_bpb->drive,
670 secnum + fat_bpb->startsector,1,
671 sectorbuf);
672 if(rc < 0)
674 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
675 " (error %d)\n", secnum, rc);
676 mutex_unlock(&cache_mutex);
677 return NULL;
679 fce->inuse = true;
680 fce->secnum = secnum;
681 #ifdef HAVE_MULTIVOLUME
682 fce->fat_vol = fat_bpb;
683 #endif
685 if (dirty)
686 fce->dirty = true; /* dirt remains, sticky until flushed */
687 mutex_unlock(&cache_mutex);
688 return sectorbuf;
691 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
692 unsigned long startcluster)
694 #ifndef HAVE_MULTIVOLUME
695 struct bpb* fat_bpb = &fat_bpbs[0];
696 #endif
697 unsigned long sector;
698 unsigned long offset;
699 unsigned long i;
701 #ifdef HAVE_FAT16SUPPORT
702 if (fat_bpb->is_fat16)
704 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
705 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
707 for (i = 0; i<fat_bpb->fatsize; i++) {
708 unsigned int j;
709 unsigned int nr = (i + sector) % fat_bpb->fatsize;
710 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
711 if ( !fat )
712 break;
713 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
714 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
715 if (letoh16(fat[k]) == 0x0000) {
716 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
717 /* Ignore the reserved clusters 0 & 1, and also
718 cluster numbers out of bounds */
719 if ( c < 2 || c > fat_bpb->dataclusters+1 )
720 continue;
721 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
722 fat_bpb->fsinfo.nextfree = c;
723 return c;
726 offset = 0;
729 else
730 #endif /* #ifdef HAVE_FAT16SUPPORT */
732 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
733 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
735 for (i = 0; i<fat_bpb->fatsize; i++) {
736 unsigned int j;
737 unsigned long nr = (i + sector) % fat_bpb->fatsize;
738 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
739 if ( !fat )
740 break;
741 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
742 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
743 if (!(letoh32(fat[k]) & 0x0fffffff)) {
744 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
745 /* Ignore the reserved clusters 0 & 1, and also
746 cluster numbers out of bounds */
747 if ( c < 2 || c > fat_bpb->dataclusters+1 )
748 continue;
749 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
750 fat_bpb->fsinfo.nextfree = c;
751 return c;
754 offset = 0;
758 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
759 return 0; /* 0 is an illegal cluster number */
762 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
763 unsigned long val)
765 #ifndef HAVE_MULTIVOLUME
766 struct bpb* fat_bpb = &fat_bpbs[0];
767 #endif
768 #ifdef HAVE_FAT16SUPPORT
769 if (fat_bpb->is_fat16)
771 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
772 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
773 unsigned short* sec;
775 val &= 0xFFFF;
777 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
779 if (entry==val)
780 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
782 if ( entry < 2 )
783 panicf("Updating reserved FAT entry %ld.\n",entry);
785 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
786 if (!sec)
788 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
789 return -1;
792 if ( val ) {
793 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
794 fat_bpb->fsinfo.freecount--;
796 else {
797 if (letoh16(sec[offset]))
798 fat_bpb->fsinfo.freecount++;
801 LDEBUGF("update_fat_entry: %d free clusters\n",
802 fat_bpb->fsinfo.freecount);
804 sec[offset] = htole16(val);
806 else
807 #endif /* #ifdef HAVE_FAT16SUPPORT */
809 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
810 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
811 unsigned long* sec;
813 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
815 if (entry==val)
816 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
818 if ( entry < 2 )
819 panicf("Updating reserved FAT entry %ld.\n",entry);
821 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
822 if (!sec)
824 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector);
825 return -1;
828 if ( val ) {
829 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
830 fat_bpb->fsinfo.freecount > 0)
831 fat_bpb->fsinfo.freecount--;
833 else {
834 if (letoh32(sec[offset]) & 0x0fffffff)
835 fat_bpb->fsinfo.freecount++;
838 LDEBUGF("update_fat_entry: %ld free clusters\n",
839 fat_bpb->fsinfo.freecount);
841 /* don't change top 4 bits */
842 sec[offset] &= htole32(0xf0000000);
843 sec[offset] |= htole32(val & 0x0fffffff);
846 return 0;
849 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
851 #ifdef HAVE_FAT16SUPPORT
852 #ifndef HAVE_MULTIVOLUME
853 struct bpb* fat_bpb = &fat_bpbs[0];
854 #endif
855 if (fat_bpb->is_fat16)
857 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
858 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
859 unsigned short* sec;
861 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
862 if (!sec)
864 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
865 return -1;
868 return letoh16(sec[offset]);
870 else
871 #endif /* #ifdef HAVE_FAT16SUPPORT */
873 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
874 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
875 unsigned long* sec;
877 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
878 if (!sec)
880 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
881 return -1;
884 return letoh32(sec[offset]) & 0x0fffffff;
888 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
890 long next_cluster;
891 long eof_mark = FAT_EOF_MARK;
893 #ifdef HAVE_FAT16SUPPORT
894 #ifndef HAVE_MULTIVOLUME
895 struct bpb* fat_bpb = &fat_bpbs[0];
896 #endif
897 if (fat_bpb->is_fat16)
899 eof_mark &= 0xFFFF; /* only 16 bit */
900 if (cluster < 0) /* FAT16 root dir */
901 return cluster + 1; /* don't use the FAT */
903 #endif
904 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
906 /* is this last cluster in chain? */
907 if ( next_cluster >= eof_mark )
908 return 0;
909 else
910 return next_cluster;
913 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
915 #ifndef HAVE_MULTIVOLUME
916 struct bpb* fat_bpb = &fat_bpbs[0];
917 #endif
918 unsigned char fsinfo[SECTOR_SIZE];
919 unsigned long* intptr;
920 int rc;
922 #ifdef HAVE_FAT16SUPPORT
923 if (fat_bpb->is_fat16)
924 return 0; /* FAT16 has no FsInfo */
925 #endif /* #ifdef HAVE_FAT16SUPPORT */
927 /* update fsinfo */
928 rc = storage_read_sectors(fat_bpb->drive,
929 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
930 if (rc < 0)
932 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
933 return rc * 10 - 1;
935 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
936 *intptr = htole32(fat_bpb->fsinfo.freecount);
938 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
939 *intptr = htole32(fat_bpb->fsinfo.nextfree);
941 rc = storage_write_sectors(fat_bpb->drive,
942 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
943 if (rc < 0)
945 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
946 return rc * 10 - 2;
949 return 0;
952 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
954 int i;
955 int rc;
956 unsigned char *sec;
957 LDEBUGF("flush_fat()\n");
959 mutex_lock(&cache_mutex);
960 for(i = 0;i < FAT_CACHE_SIZE;i++)
962 struct fat_cache_entry *fce = &fat_cache[i];
963 if(fce->inuse
964 #ifdef HAVE_MULTIVOLUME
965 && fce->fat_vol == fat_bpb
966 #endif
967 && fce->dirty)
969 sec = fat_cache_sectors[i];
970 flush_fat_sector(fce, sec);
973 mutex_unlock(&cache_mutex);
975 rc = update_fsinfo(IF_MV(fat_bpb));
976 if (rc < 0)
977 return rc * 10 - 3;
979 return 0;
982 static void fat_time(unsigned short* date,
983 unsigned short* time,
984 unsigned short* tenth )
986 #if CONFIG_RTC
987 struct tm* tm = get_time();
989 if (date)
990 *date = ((tm->tm_year - 80) << 9) |
991 ((tm->tm_mon + 1) << 5) |
992 tm->tm_mday;
994 if (time)
995 *time = (tm->tm_hour << 11) |
996 (tm->tm_min << 5) |
997 (tm->tm_sec >> 1);
999 if (tenth)
1000 *tenth = (tm->tm_sec & 1) * 100;
1001 #else
1002 /* non-RTC version returns an increment from the supplied time, or a
1003 * fixed standard time/date if no time given as input */
1005 /* Macros to convert a 2-digit string to a decimal constant.
1006 (YEAR), MONTH and DAY are set by the date command, which outputs
1007 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1008 misinterpretation as an octal constant. */
1009 #define S100(x) 1 ## x
1010 #define C2DIG2DEC(x) (S100(x)-100)
1011 /* The actual build date, as FAT date constant */
1012 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1013 | (C2DIG2DEC(MONTH) << 5) \
1014 | C2DIG2DEC(DAY))
1016 bool date_forced = false;
1017 bool next_day = false;
1018 unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */
1020 if (date && *date < BUILD_DATE_FAT)
1022 *date = BUILD_DATE_FAT;
1023 date_forced = true;
1026 if (time)
1028 time2 = *time << 1;
1029 if (time2 == 0 || date_forced)
1031 time2 = (11 < 6) | 11; /* set to 00:11:11 */
1033 else
1035 unsigned mins = (time2 >> 6) & 0x3f;
1036 unsigned hours = (time2 >> 12) & 0x1f;
1038 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */
1039 if (mins > 59)
1041 mins = 11; /* 00 would be a bad marker */
1042 if (++hours > 23)
1044 hours = 0;
1045 next_day = true;
1048 time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */
1050 *time = time2 >> 1;
1053 if (tenth)
1054 *tenth = (time2 & 1) * 100;
1056 if (date && next_day)
1058 static const unsigned char daysinmonth[] =
1059 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1060 unsigned day = *date & 0x1f;
1061 unsigned month = (*date >> 5) & 0x0f;
1062 unsigned year = (*date >> 9) & 0x7f;
1064 /* simplification: ignore leap years */
1065 if (++day > daysinmonth[month-1])
1067 day = 1;
1068 if (++month > 12)
1070 month = 1;
1071 year++;
1074 *date = (year << 9) | (month << 5) | day;
1077 #endif /* CONFIG_RTC */
1080 static int write_long_name(struct fat_file* file,
1081 unsigned int firstentry,
1082 unsigned int numentries,
1083 const unsigned char* name,
1084 const unsigned char* shortname,
1085 bool is_directory)
1087 unsigned char buf[SECTOR_SIZE];
1088 unsigned char* entry;
1089 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1090 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1091 unsigned char chksum = 0;
1092 unsigned int i, j=0;
1093 unsigned int nameidx=0, namelen = utf8length(name);
1094 int rc;
1095 unsigned short name_utf16[namelen + 1];
1097 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1098 file->firstcluster, firstentry, numentries, name);
1100 rc = fat_seek(file, sector);
1101 if (rc<0)
1102 return rc * 10 - 1;
1104 rc = fat_readwrite(file, 1, buf, false);
1105 if (rc<1)
1106 return rc * 10 - 2;
1108 /* calculate shortname checksum */
1109 for (i=11; i>0; i--)
1110 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1112 /* calc position of last name segment */
1113 if ( namelen > NAME_BYTES_PER_ENTRY )
1114 for (nameidx=0;
1115 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1116 nameidx += NAME_BYTES_PER_ENTRY);
1118 /* we need to convert the name first */
1119 /* since it is written in reverse order */
1120 for (i = 0; i <= namelen; i++)
1121 name = utf8decode(name, &name_utf16[i]);
1123 for (i=0; i < numentries; i++) {
1124 /* new sector? */
1125 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1126 /* update current sector */
1127 rc = fat_seek(file, sector);
1128 if (rc<0)
1129 return rc * 10 - 3;
1131 rc = fat_readwrite(file, 1, buf, true);
1132 if (rc<1)
1133 return rc * 10 - 4;
1135 /* read next sector */
1136 rc = fat_readwrite(file, 1, buf, false);
1137 if (rc<0) {
1138 LDEBUGF("Failed writing new sector: %d\n",rc);
1139 return rc * 10 - 5;
1141 if (rc==0)
1142 /* end of dir */
1143 memset(buf, 0, sizeof buf);
1145 sector++;
1146 idx = 0;
1149 entry = buf + idx * DIR_ENTRY_SIZE;
1151 /* verify this entry is free */
1152 if (entry[0] && entry[0] != 0xe5 )
1153 panicf("Dir entry %d in sector %x is not free! "
1154 "%02x %02x %02x %02x",
1155 idx, sector,
1156 entry[0], entry[1], entry[2], entry[3]);
1158 memset(entry, 0, DIR_ENTRY_SIZE);
1159 if ( i+1 < numentries ) {
1160 /* longname entry */
1161 unsigned int k, l = nameidx;
1163 entry[FATLONG_ORDER] = numentries-i-1;
1164 if (i==0) {
1165 /* mark this as last long entry */
1166 entry[FATLONG_ORDER] |= 0x40;
1168 /* pad name with 0xffff */
1169 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1170 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1171 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1173 /* set name */
1174 for (k=0; k<5 && l <= namelen; k++) {
1175 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1176 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1178 for (k=0; k<6 && l <= namelen; k++) {
1179 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1180 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1182 for (k=0; k<2 && l <= namelen; k++) {
1183 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1184 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1187 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1188 entry[FATDIR_FSTCLUSLO] = 0;
1189 entry[FATLONG_TYPE] = 0;
1190 entry[FATLONG_CHKSUM] = chksum;
1191 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1193 else {
1194 /* shortname entry */
1195 unsigned short date=0, time=0, tenth=0;
1196 LDEBUGF("Shortname entry: %s\n", shortname);
1197 memcpy(entry + FATDIR_NAME, shortname, 11);
1198 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1199 entry[FATDIR_NTRES] = 0;
1201 fat_time(&date, &time, &tenth);
1202 entry[FATDIR_CRTTIMETENTH] = tenth;
1203 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1204 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1205 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1206 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1207 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1209 idx++;
1210 nameidx -= NAME_BYTES_PER_ENTRY;
1213 /* update last sector */
1214 rc = fat_seek(file, sector);
1215 if (rc<0)
1216 return rc * 10 - 6;
1218 rc = fat_readwrite(file, 1, buf, true);
1219 if (rc<1)
1220 return rc * 10 - 7;
1222 return 0;
1225 static int fat_checkname(const unsigned char* newname)
1227 static const char invalid_chars[] = "\"*/:<>?\\|";
1228 int len = strlen(newname);
1229 /* More sanity checks are probably needed */
1230 if (len > 255 || newname[len - 1] == '.')
1232 return -1;
1234 while (*newname)
1236 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1237 return -1;
1238 newname++;
1240 /* check trailing space(s) */
1241 if(*(--newname) == ' ')
1242 return -1;
1244 return 0;
1247 static int add_dir_entry(struct fat_dir* dir,
1248 struct fat_file* file,
1249 const char* name,
1250 bool is_directory,
1251 bool dotdir)
1253 #ifdef HAVE_MULTIVOLUME
1254 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1255 #else
1256 struct bpb* fat_bpb = &fat_bpbs[0];
1257 #endif
1258 unsigned char buf[SECTOR_SIZE];
1259 unsigned char shortname[12];
1260 int rc;
1261 unsigned int sector;
1262 bool done = false;
1263 int entries_needed, entries_found = 0;
1264 int firstentry;
1266 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1267 name, file->firstcluster);
1269 /* Don't check dotdirs name for validity */
1270 if (dotdir == false) {
1271 rc = fat_checkname(name);
1272 if (rc < 0) {
1273 /* filename is invalid */
1274 return rc * 10 - 1;
1278 #ifdef HAVE_MULTIVOLUME
1279 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1280 #endif
1282 /* The "." and ".." directory entries must not be long names */
1283 if(dotdir) {
1284 int i;
1285 strlcpy(shortname, name, 12);
1286 for(i = strlen(shortname); i < 12; i++)
1287 shortname[i] = ' ';
1289 entries_needed = 1;
1290 } else {
1291 create_dos_name(name, shortname);
1293 /* one dir entry needed for every 13 bytes of filename,
1294 plus one entry for the short name */
1295 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1296 / NAME_BYTES_PER_ENTRY + 1;
1299 restart:
1300 firstentry = -1;
1302 rc = fat_seek(&dir->file, 0);
1303 if (rc < 0)
1304 return rc * 10 - 2;
1306 /* step 1: search for free entries and check for duplicate shortname */
1307 for (sector = 0; !done; sector++)
1309 unsigned int i;
1311 rc = fat_readwrite(&dir->file, 1, buf, false);
1312 if (rc < 0) {
1313 DEBUGF( "add_dir_entry() - Couldn't read dir"
1314 " (error code %d)\n", rc);
1315 return rc * 10 - 3;
1318 if (rc == 0) { /* current end of dir reached */
1319 LDEBUGF("End of dir on cluster boundary\n");
1320 break;
1323 /* look for free slots */
1324 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1326 switch (buf[i * DIR_ENTRY_SIZE]) {
1327 case 0:
1328 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1329 LDEBUGF("Found end of dir %d\n",
1330 sector * DIR_ENTRIES_PER_SECTOR + i);
1331 i = DIR_ENTRIES_PER_SECTOR - 1;
1332 done = true;
1333 break;
1335 case 0xe5:
1336 entries_found++;
1337 LDEBUGF("Found free entry %d (%d/%d)\n",
1338 sector * DIR_ENTRIES_PER_SECTOR + i,
1339 entries_found, entries_needed);
1340 break;
1342 default:
1343 entries_found = 0;
1345 /* check that our intended shortname doesn't already exist */
1346 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1347 /* shortname exists already, make a new one */
1348 randomize_dos_name(shortname);
1349 LDEBUGF("Duplicate shortname, changing to %s\n",
1350 shortname);
1352 /* name has changed, we need to restart search */
1353 goto restart;
1355 break;
1357 if (firstentry < 0 && (entries_found >= entries_needed))
1358 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1359 - entries_found;
1363 /* step 2: extend the dir if necessary */
1364 if (firstentry < 0)
1366 LDEBUGF("Adding new sector(s) to dir\n");
1367 rc = fat_seek(&dir->file, sector);
1368 if (rc < 0)
1369 return rc * 10 - 4;
1370 memset(buf, 0, sizeof buf);
1372 /* we must clear whole clusters */
1373 for (; (entries_found < entries_needed) ||
1374 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1376 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1377 return -5; /* dir too large -- FAT specification */
1379 rc = fat_readwrite(&dir->file, 1, buf, true);
1380 if (rc < 1) /* No more room or something went wrong */
1381 return rc * 10 - 6;
1383 entries_found += DIR_ENTRIES_PER_SECTOR;
1386 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1389 /* step 3: add entry */
1390 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1391 LDEBUGF("Adding longname to entry %d in sector %d\n",
1392 firstentry, sector);
1394 rc = write_long_name(&dir->file, firstentry,
1395 entries_needed, name, shortname, is_directory);
1396 if (rc < 0)
1397 return rc * 10 - 7;
1399 /* remember where the shortname dir entry is located */
1400 file->direntry = firstentry + entries_needed - 1;
1401 file->direntries = entries_needed;
1402 file->dircluster = dir->file.firstcluster;
1403 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1404 file->direntry, file->direntries);
1406 return 0;
1409 static unsigned char char2dos(unsigned char c, int* randomize)
1411 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1413 if (c <= 0x20)
1414 c = 0; /* Illegal char, remove */
1415 else if (strchr(invalid_chars, c) != NULL)
1417 /* Illegal char, replace */
1418 c = '_';
1419 *randomize = 1; /* as per FAT spec */
1421 else
1422 c = toupper(c);
1424 return c;
1427 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1429 int i;
1430 unsigned char *ext;
1431 int randomize = 0;
1433 /* Find extension part */
1434 ext = strrchr(name, '.');
1435 if (ext == name) /* handle .dotnames */
1436 ext = NULL;
1438 /* needs to randomize? */
1439 if((ext && (strlen(ext) > 4)) ||
1440 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1441 randomize = 1;
1443 /* Name part */
1444 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1446 unsigned char c = char2dos(*name, &randomize);
1447 if (c)
1448 newname[i++] = c;
1451 /* Pad both name and extension */
1452 while (i < 11)
1453 newname[i++] = ' ';
1455 if (newname[0] == 0xe5) /* Special kanji character */
1456 newname[0] = 0x05;
1458 if (ext)
1459 { /* Extension part */
1460 ext++;
1461 for (i = 8; *ext && (i < 11); ext++)
1463 unsigned char c = char2dos(*ext, &randomize);
1464 if (c)
1465 newname[i++] = c;
1469 if(randomize)
1470 randomize_dos_name(newname);
1473 static void randomize_dos_name(unsigned char *name)
1475 unsigned char* tilde = NULL; /* ~ location */
1476 unsigned char* lastpt = NULL; /* last point of filename */
1477 unsigned char* nameptr = name; /* working copy of name pointer */
1478 unsigned char num[9]; /* holds number as string */
1479 int i = 0;
1480 int cnt = 1;
1481 int numlen;
1482 int offset;
1484 while(i++ < 8)
1486 /* hunt for ~ and where to put it */
1487 if((!tilde) && (*nameptr == '~'))
1488 tilde = nameptr;
1489 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1490 lastpt = nameptr;
1491 nameptr++;
1493 if(tilde)
1495 /* extract current count and increment */
1496 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1497 num[7-(unsigned int)(tilde-name)] = 0;
1498 cnt = atoi(num) + 1;
1500 cnt %= 10000000; /* protection */
1501 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1502 numlen = strlen(num); /* required space */
1503 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1504 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1506 memcpy(&name[offset], num, numlen);
1508 /* in special case of counter overflow: pad with spaces */
1509 for(offset = offset+numlen; offset < 8; offset++)
1510 name[offset] = ' ';
1513 static int update_short_entry( struct fat_file* file, long size, int attr )
1515 unsigned char buf[SECTOR_SIZE];
1516 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1517 unsigned char* entry =
1518 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1519 unsigned long* sizeptr;
1520 unsigned short* clusptr;
1521 struct fat_file dir;
1522 int rc;
1524 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1525 file->firstcluster, file->direntry, size);
1527 /* create a temporary file handle for the dir holding this file */
1528 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1529 if (rc < 0)
1530 return rc * 10 - 1;
1532 rc = fat_seek( &dir, sector );
1533 if (rc<0)
1534 return rc * 10 - 2;
1536 rc = fat_readwrite(&dir, 1, buf, false);
1537 if (rc < 1)
1538 return rc * 10 - 3;
1540 if (!entry[0] || entry[0] == 0xe5)
1541 panicf("Updating size on empty dir entry %d\n", file->direntry);
1543 entry[FATDIR_ATTR] = attr & 0xFF;
1545 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1546 *clusptr = htole16(file->firstcluster >> 16);
1548 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1549 *clusptr = htole16(file->firstcluster & 0xffff);
1551 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1552 *sizeptr = htole32(size);
1555 #if CONFIG_RTC
1556 unsigned short time = 0;
1557 unsigned short date = 0;
1558 #else
1559 /* get old time to increment from */
1560 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1561 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1562 #endif
1563 fat_time(&date, &time, NULL);
1564 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1565 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1566 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1569 rc = fat_seek( &dir, sector );
1570 if (rc < 0)
1571 return rc * 10 - 4;
1573 rc = fat_readwrite(&dir, 1, buf, true);
1574 if (rc < 1)
1575 return rc * 10 - 5;
1577 return 0;
1580 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1582 int i=0,j=0;
1583 unsigned char c;
1584 bool lowercase;
1586 memset(de, 0, sizeof(struct fat_direntry));
1587 de->attr = buf[FATDIR_ATTR];
1588 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1589 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1590 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1591 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1592 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1593 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1594 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1595 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1596 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1597 (the result of the shift is always considered signed) */
1599 /* fix the name */
1600 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1601 c = buf[FATDIR_NAME];
1602 if (c == 0x05) /* special kanji char */
1603 c = 0xe5;
1604 i = 0;
1605 while (c != ' ') {
1606 de->name[j++] = lowercase ? tolower(c) : c;
1607 if (++i >= 8)
1608 break;
1609 c = buf[FATDIR_NAME+i];
1611 if (buf[FATDIR_NAME+8] != ' ') {
1612 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1613 de->name[j++] = '.';
1614 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1615 de->name[j++] = lowercase ? tolower(c) : c;
1617 return 1;
1620 int fat_open(IF_MV2(int volume,)
1621 long startcluster,
1622 struct fat_file *file,
1623 const struct fat_dir* dir)
1625 file->firstcluster = startcluster;
1626 file->lastcluster = startcluster;
1627 file->lastsector = 0;
1628 file->clusternum = 0;
1629 file->sectornum = 0;
1630 file->eof = false;
1631 #ifdef HAVE_MULTIVOLUME
1632 file->volume = volume;
1633 /* fixme: remove error check when done */
1634 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1636 LDEBUGF("fat_open() illegal volume %d\n", volume);
1637 return -1;
1639 #endif
1641 /* remember where the file's dir entry is located */
1642 if ( dir ) {
1643 file->direntry = dir->entry - 1;
1644 file->direntries = dir->entrycount;
1645 file->dircluster = dir->file.firstcluster;
1647 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1648 return 0;
1651 int fat_create_file(const char* name,
1652 struct fat_file* file,
1653 struct fat_dir* dir)
1655 int rc;
1657 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1658 rc = add_dir_entry(dir, file, name, false, false);
1659 if (!rc) {
1660 file->firstcluster = 0;
1661 file->lastcluster = 0;
1662 file->lastsector = 0;
1663 file->clusternum = 0;
1664 file->sectornum = 0;
1665 file->eof = false;
1668 return rc;
1671 int fat_create_dir(const char* name,
1672 struct fat_dir* newdir,
1673 struct fat_dir* dir)
1675 #ifdef HAVE_MULTIVOLUME
1676 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1677 #else
1678 struct bpb* fat_bpb = &fat_bpbs[0];
1679 #endif
1680 unsigned char buf[SECTOR_SIZE];
1681 int i;
1682 long sector;
1683 int rc;
1684 struct fat_file dummyfile;
1686 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1688 memset(newdir, 0, sizeof(struct fat_dir));
1689 memset(&dummyfile, 0, sizeof(struct fat_file));
1691 /* First, add the entry in the parent directory */
1692 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1693 if (rc < 0)
1694 return rc * 10 - 1;
1696 /* Allocate a new cluster for the directory */
1697 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1698 fat_bpb->fsinfo.nextfree);
1699 if(newdir->file.firstcluster == 0)
1700 return -1;
1702 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1704 /* Clear the entire cluster */
1705 memset(buf, 0, sizeof buf);
1706 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1707 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1708 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1709 if (rc < 0)
1710 return rc * 10 - 2;
1713 /* Then add the "." entry */
1714 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1715 if (rc < 0)
1716 return rc * 10 - 3;
1717 dummyfile.firstcluster = newdir->file.firstcluster;
1718 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1720 /* and the ".." entry */
1721 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1722 if (rc < 0)
1723 return rc * 10 - 4;
1725 /* The root cluster is cluster 0 in the ".." entry */
1726 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1727 dummyfile.firstcluster = 0;
1728 else
1729 dummyfile.firstcluster = dir->file.firstcluster;
1730 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1732 /* Set the firstcluster field in the direntry */
1733 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1735 rc = flush_fat(IF_MV(fat_bpb));
1736 if (rc < 0)
1737 return rc * 10 - 5;
1739 return rc;
1742 int fat_truncate(const struct fat_file *file)
1744 /* truncate trailing clusters */
1745 long next;
1746 long last = file->lastcluster;
1747 #ifdef HAVE_MULTIVOLUME
1748 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1749 #endif
1751 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1753 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1754 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1755 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1757 if (file->lastcluster)
1758 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1760 return 0;
1763 int fat_closewrite(struct fat_file *file, long size, int attr)
1765 int rc;
1766 #ifdef HAVE_MULTIVOLUME
1767 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1768 #endif
1769 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1771 if (!size) {
1772 /* empty file */
1773 if ( file->firstcluster ) {
1774 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1775 file->firstcluster = 0;
1779 if (file->dircluster) {
1780 rc = update_short_entry(file, size, attr);
1781 if (rc < 0)
1782 return rc * 10 - 1;
1785 flush_fat(IF_MV(fat_bpb));
1787 #ifdef TEST_FAT
1788 if ( file->firstcluster ) {
1789 /* debug */
1790 #ifdef HAVE_MULTIVOLUME
1791 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1792 #else
1793 struct bpb* fat_bpb = &fat_bpbs[0];
1794 #endif
1795 long count = 0;
1796 long len;
1797 long next;
1798 for ( next = file->firstcluster; next;
1799 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1800 LDEBUGF("cluster %ld: %lx\n", count, next);
1801 count++;
1803 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1804 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1805 count, len, size );
1806 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1807 panicf("Cluster chain is too long\n");
1808 if ( len < size )
1809 panicf("Cluster chain is too short\n");
1811 #endif
1813 return 0;
1816 static int free_direntries(struct fat_file* file)
1818 unsigned char buf[SECTOR_SIZE];
1819 struct fat_file dir;
1820 int numentries = file->direntries;
1821 unsigned int entry = file->direntry - numentries + 1;
1822 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1823 int i;
1824 int rc;
1826 /* create a temporary file handle for the dir holding this file */
1827 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1828 if (rc < 0)
1829 return rc * 10 - 1;
1831 rc = fat_seek( &dir, sector );
1832 if (rc < 0)
1833 return rc * 10 - 2;
1835 rc = fat_readwrite(&dir, 1, buf, false);
1836 if (rc < 1)
1837 return rc * 10 - 3;
1839 for (i=0; i < numentries; i++) {
1840 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1841 entry, i+1, numentries);
1842 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1843 entry++;
1845 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1846 /* flush this sector */
1847 rc = fat_seek(&dir, sector);
1848 if (rc < 0)
1849 return rc * 10 - 4;
1851 rc = fat_readwrite(&dir, 1, buf, true);
1852 if (rc < 1)
1853 return rc * 10 - 5;
1855 if ( i+1 < numentries ) {
1856 /* read next sector */
1857 rc = fat_readwrite(&dir, 1, buf, false);
1858 if (rc < 1)
1859 return rc * 10 - 6;
1861 sector++;
1865 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1866 /* flush this sector */
1867 rc = fat_seek(&dir, sector);
1868 if (rc < 0)
1869 return rc * 10 - 7;
1871 rc = fat_readwrite(&dir, 1, buf, true);
1872 if (rc < 1)
1873 return rc * 10 - 8;
1876 return 0;
1879 int fat_remove(struct fat_file* file)
1881 long next, last = file->firstcluster;
1882 int rc;
1883 #ifdef HAVE_MULTIVOLUME
1884 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1885 #endif
1887 LDEBUGF("fat_remove(%lx)\n",last);
1889 while ( last ) {
1890 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1891 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1892 last = next;
1895 if ( file->dircluster ) {
1896 rc = free_direntries(file);
1897 if (rc < 0)
1898 return rc * 10 - 1;
1901 file->firstcluster = 0;
1902 file->dircluster = 0;
1904 rc = flush_fat(IF_MV(fat_bpb));
1905 if (rc < 0)
1906 return rc * 10 - 2;
1908 return 0;
1911 int fat_rename(struct fat_file* file,
1912 struct fat_dir* dir,
1913 const unsigned char* newname,
1914 long size,
1915 int attr)
1917 int rc;
1918 struct fat_dir olddir;
1919 struct fat_file newfile = *file;
1920 unsigned char buf[SECTOR_SIZE];
1921 unsigned char* entry = NULL;
1922 unsigned short* clusptr = NULL;
1923 unsigned int parentcluster;
1924 #ifdef HAVE_MULTIVOLUME
1925 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1927 if (file->volume != dir->file.volume) {
1928 DEBUGF("No rename across volumes!\n");
1929 return -1;
1931 #else
1932 struct bpb* fat_bpb = &fat_bpbs[0];
1933 #endif
1935 if ( !file->dircluster ) {
1936 DEBUGF("File has no dir cluster!\n");
1937 return -2;
1940 /* create a temporary file handle */
1941 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1942 if (rc < 0)
1943 return rc * 10 - 1;
1945 /* create new name */
1946 rc = add_dir_entry(dir, &newfile, newname, false, false);
1947 if (rc < 0)
1948 return rc * 10 - 2;
1950 /* write size and cluster link */
1951 rc = update_short_entry(&newfile, size, attr);
1952 if (rc < 0)
1953 return rc * 10 - 3;
1955 /* remove old name */
1956 rc = free_direntries(file);
1957 if (rc < 0)
1958 return rc * 10 - 4;
1960 rc = flush_fat(IF_MV(fat_bpb));
1961 if (rc < 0)
1962 return rc * 10 - 5;
1964 /* if renaming a directory, update the .. entry to make sure
1965 it points to its parent directory (we don't check if it was a move) */
1966 if(FAT_ATTR_DIRECTORY == attr) {
1967 /* open the dir that was renamed, we re-use the olddir struct */
1968 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1969 NULL);
1970 if (rc < 0)
1971 return rc * 10 - 6;
1973 /* get the first sector of the dir */
1974 rc = fat_seek(&olddir.file, 0);
1975 if (rc < 0)
1976 return rc * 10 - 7;
1978 rc = fat_readwrite(&olddir.file, 1, buf, false);
1979 if (rc < 0)
1980 return rc * 10 - 8;
1982 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1983 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1984 parentcluster = 0;
1985 else
1986 parentcluster = dir->file.firstcluster;
1988 entry = buf + DIR_ENTRY_SIZE;
1989 if(strncmp(".. ", entry, 11))
1991 /* .. entry must be second entry according to FAT spec (p.29) */
1992 DEBUGF("Second dir entry is not double-dot!\n");
1993 return rc * 10 - 9;
1995 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1996 *clusptr = htole16(parentcluster >> 16);
1998 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1999 *clusptr = htole16(parentcluster & 0xffff);
2001 /* write back this sector */
2002 rc = fat_seek(&olddir.file, 0);
2003 if (rc < 0)
2004 return rc * 10 - 7;
2006 rc = fat_readwrite(&olddir.file, 1, buf, true);
2007 if (rc < 1)
2008 return rc * 10 - 8;
2011 return 0;
2014 static long next_write_cluster(struct fat_file* file,
2015 long oldcluster,
2016 long* newsector)
2018 #ifdef HAVE_MULTIVOLUME
2019 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2020 #else
2021 struct bpb* fat_bpb = &fat_bpbs[0];
2022 #endif
2023 long cluster = 0;
2024 long sector;
2026 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2028 if (oldcluster)
2029 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2031 if (!cluster) {
2032 if (oldcluster > 0)
2033 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2034 else if (oldcluster == 0)
2035 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2036 fat_bpb->fsinfo.nextfree);
2037 #ifdef HAVE_FAT16SUPPORT
2038 else /* negative, pseudo-cluster of the root dir */
2039 return 0; /* impossible to append something to the root */
2040 #endif
2042 if (cluster) {
2043 if (oldcluster)
2044 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2045 else
2046 file->firstcluster = cluster;
2047 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2049 else {
2050 #ifdef TEST_FAT
2051 if (fat_bpb->fsinfo.freecount>0)
2052 panicf("There is free space, but find_free_cluster() "
2053 "didn't find it!\n");
2054 #endif
2055 DEBUGF("next_write_cluster(): Disk full!\n");
2056 return 0;
2059 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2060 if (sector<0)
2061 return 0;
2063 *newsector = sector;
2064 return cluster;
2067 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2068 unsigned long start, long count, char* buf, bool write )
2070 #ifndef HAVE_MULTIVOLUME
2071 struct bpb* fat_bpb = &fat_bpbs[0];
2072 #endif
2073 int rc;
2075 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2076 start+ fat_bpb->startsector, count, write?"write":"read");
2077 if (write) {
2078 unsigned long firstallowed;
2079 #ifdef HAVE_FAT16SUPPORT
2080 if (fat_bpb->is_fat16)
2081 firstallowed = fat_bpb->rootdirsector;
2082 else
2083 #endif
2084 firstallowed = fat_bpb->firstdatasector;
2086 if (start < firstallowed)
2087 panicf("Write %ld before data\n", firstallowed - start);
2088 if (start + count > fat_bpb->totalsectors)
2089 panicf("Write %ld after data\n",
2090 start + count - fat_bpb->totalsectors);
2091 rc = storage_write_sectors(fat_bpb->drive,
2092 start + fat_bpb->startsector, count, buf);
2094 else
2095 rc = storage_read_sectors(fat_bpb->drive,
2096 start + fat_bpb->startsector, count, buf);
2097 if (rc < 0) {
2098 DEBUGF( "transfer() - Couldn't %s sector %lx"
2099 " (error code %d)\n",
2100 write ? "write":"read", start, rc);
2101 return rc;
2103 return 0;
2107 long fat_readwrite( struct fat_file *file, long sectorcount,
2108 void* buf, bool write )
2110 #ifdef HAVE_MULTIVOLUME
2111 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2112 #else
2113 struct bpb* fat_bpb = &fat_bpbs[0];
2114 #endif
2115 long cluster = file->lastcluster;
2116 long sector = file->lastsector;
2117 long clusternum = file->clusternum;
2118 long numsec = file->sectornum;
2119 bool eof = file->eof;
2120 long first=0, last=0;
2121 long i;
2122 int rc;
2124 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2125 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2126 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2127 sector,numsec, eof?1:0);
2129 if ( eof && !write)
2130 return 0;
2132 /* find sequential sectors and write them all at once */
2133 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2134 numsec++;
2135 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2136 long oldcluster = cluster;
2137 long oldsector = sector;
2138 long oldnumsec = numsec;
2139 if (write)
2140 cluster = next_write_cluster(file, cluster, &sector);
2141 else {
2142 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2143 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2146 clusternum++;
2147 numsec=1;
2149 if (!cluster) {
2150 eof = true;
2151 if ( write ) {
2152 /* remember last cluster, in case
2153 we want to append to the file */
2154 sector = oldsector;
2155 cluster = oldcluster;
2156 numsec = oldnumsec;
2157 clusternum--;
2158 i = -1; /* Error code */
2159 break;
2162 else
2163 eof = false;
2165 else {
2166 if (sector)
2167 sector++;
2168 else {
2169 /* look up first sector of file */
2170 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2171 numsec=1;
2172 #ifdef HAVE_FAT16SUPPORT
2173 if (file->firstcluster < 0)
2174 { /* FAT16 root dir */
2175 sector += fat_bpb->rootdiroffset;
2176 numsec += fat_bpb->rootdiroffset;
2178 #endif
2182 if (!first)
2183 first = sector;
2185 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2186 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2187 long count = last - first + 1;
2188 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2189 if (rc < 0)
2190 return rc * 10 - 1;
2192 buf = (char *)buf + count * SECTOR_SIZE;
2193 first = sector;
2196 if ((i == sectorcount-1) && /* last sector requested */
2197 (!eof))
2199 long count = sector - first + 1;
2200 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2201 if (rc < 0)
2202 return rc * 10 - 2;
2205 last = sector;
2208 file->lastcluster = cluster;
2209 file->lastsector = sector;
2210 file->clusternum = clusternum;
2211 file->sectornum = numsec;
2212 file->eof = eof;
2214 /* if eof, don't report last block as read/written */
2215 if (eof)
2216 i--;
2218 DEBUGF("Sectors written: %ld\n", i);
2219 return i;
2222 int fat_seek(struct fat_file *file, unsigned long seeksector )
2224 #ifdef HAVE_MULTIVOLUME
2225 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2226 #else
2227 struct bpb* fat_bpb = &fat_bpbs[0];
2228 #endif
2229 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2230 long cluster = file->firstcluster;
2231 long i;
2233 #ifdef HAVE_FAT16SUPPORT
2234 if (cluster < 0) /* FAT16 root dir */
2235 seeksector += fat_bpb->rootdiroffset;
2236 #endif
2238 file->eof = false;
2239 if (seeksector) {
2240 /* we need to find the sector BEFORE the requested, since
2241 the file struct stores the last accessed sector */
2242 seeksector--;
2243 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2244 sectornum = seeksector % fat_bpb->bpb_secperclus;
2246 if (file->clusternum && clusternum >= file->clusternum)
2248 cluster = file->lastcluster;
2249 numclusters -= file->clusternum;
2252 for (i=0; i<numclusters; i++) {
2253 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2254 if (!cluster) {
2255 DEBUGF("Seeking beyond the end of the file! "
2256 "(sector %ld, cluster %ld)\n", seeksector, i);
2257 return -1;
2261 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2263 else {
2264 sectornum = -1;
2267 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2268 file->firstcluster, seeksector, cluster, sector, sectornum);
2270 file->lastcluster = cluster;
2271 file->lastsector = sector;
2272 file->clusternum = clusternum;
2273 file->sectornum = sectornum + 1;
2274 return 0;
2277 int fat_opendir(IF_MV2(int volume,)
2278 struct fat_dir *dir, unsigned long startcluster,
2279 const struct fat_dir *parent_dir)
2281 #ifdef HAVE_MULTIVOLUME
2282 struct bpb* fat_bpb = &fat_bpbs[volume];
2283 /* fixme: remove error check when done */
2284 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2286 LDEBUGF("fat_open() illegal volume %d\n", volume);
2287 return -1;
2289 #else
2290 struct bpb* fat_bpb = &fat_bpbs[0];
2291 #endif
2292 int rc;
2294 dir->entry = 0;
2295 dir->sector = 0;
2297 if (startcluster == 0)
2298 startcluster = fat_bpb->bpb_rootclus;
2300 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2301 if(rc)
2303 DEBUGF( "fat_opendir() - Couldn't open dir"
2304 " (error code %d)\n", rc);
2305 return rc * 10 - 1;
2308 return 0;
2311 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2312 * destination buffer (UTF-8 encoded). Copying is stopped when
2313 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2314 * Trailing \0 is also appended at the end of the UTF8-encoded
2315 * string.
2317 * utf16src utf16 (little endian) segment to copy
2318 * utf16count max number of the utf16-characters to copy
2319 * utf8dst where to write UTF8-encoded string to
2321 * returns the number of UTF-16 characters actually copied
2323 static int fat_copy_long_name_segment(unsigned char *utf16src,
2324 int utf16count, unsigned char *utf8dst) {
2325 int cnt = 0;
2326 while ((utf16count--) > 0) {
2327 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2328 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2329 break;
2331 utf8dst = utf8encode(ucs, utf8dst);
2332 utf16src += 2;
2333 cnt++;
2335 *utf8dst = 0;
2336 return cnt;
2339 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2341 bool done = false;
2342 int i;
2343 int rc;
2344 unsigned char firstbyte;
2345 /* Long file names are stored in special entries. Each entry holds
2346 up to 13 characters. Names can be max 255 chars (not bytes!) long
2347 hence max 20 entries are required. */
2348 int longarray[20];
2349 int longs=0;
2350 int sectoridx=0;
2351 unsigned char* cached_buf = dir->sectorcache[0];
2353 dir->entrycount = 0;
2355 while(!done)
2357 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2359 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2360 if (rc == 0) {
2361 /* eof */
2362 entry->name[0] = 0;
2363 break;
2365 if (rc < 0) {
2366 DEBUGF( "fat_getnext() - Couldn't read dir"
2367 " (error code %d)\n", rc);
2368 return rc * 10 - 1;
2370 dir->sector = dir->file.lastsector;
2373 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2374 i < DIR_ENTRIES_PER_SECTOR; i++)
2376 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2378 firstbyte = cached_buf[entrypos];
2379 dir->entry++;
2381 if (firstbyte == 0xe5) {
2382 /* free entry */
2383 sectoridx = 0;
2384 dir->entrycount = 0;
2385 continue;
2388 if (firstbyte == 0) {
2389 /* last entry */
2390 entry->name[0] = 0;
2391 dir->entrycount = 0;
2392 return 0;
2395 dir->entrycount++;
2397 /* longname entry? */
2398 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2399 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2400 longarray[longs++] = entrypos + sectoridx;
2402 else {
2403 if ( parse_direntry(entry,
2404 &cached_buf[entrypos]) ) {
2406 /* don't return volume id entry */
2407 if ( (entry->attr &
2408 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2409 == FAT_ATTR_VOLUME_ID)
2410 continue;
2412 /* replace shortname with longname? */
2413 if ( longs ) {
2414 int j;
2415 /* This should be enough to hold any name segment
2416 utf8-encoded */
2417 unsigned char shortname[13]; /* 8+3+dot+\0 */
2418 /* Add 1 for trailing \0 */
2419 unsigned char longname_utf8segm[6*4 + 1];
2420 int longname_utf8len = 0;
2421 /* Temporarily store it */
2422 strcpy(shortname, entry->name);
2423 entry->name[0] = 0;
2425 /* iterate backwards through the dir entries */
2426 for (j=longs-1; j>=0; j--) {
2427 unsigned char* ptr = cached_buf;
2428 int index = longarray[j];
2429 /* current or cached sector? */
2430 if ( sectoridx >= SECTOR_SIZE ) {
2431 if ( sectoridx >= SECTOR_SIZE*2 ) {
2432 if ( ( index >= SECTOR_SIZE ) &&
2433 ( index < SECTOR_SIZE*2 ))
2434 ptr = dir->sectorcache[1];
2435 else
2436 ptr = dir->sectorcache[2];
2438 else {
2439 if ( index < SECTOR_SIZE )
2440 ptr = dir->sectorcache[1];
2443 index &= SECTOR_SIZE-1;
2446 /* Try to append each segment of the long name.
2447 Check if we'd exceed the buffer.
2448 Also check for FAT padding characters 0xFFFF. */
2449 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2450 longname_utf8segm) == 0) break;
2451 /* logf("SG: %s, EN: %s", longname_utf8segm,
2452 entry->name); */
2453 longname_utf8len += strlen(longname_utf8segm);
2454 if (longname_utf8len < FAT_FILENAME_BYTES)
2455 strcat(entry->name, longname_utf8segm);
2456 else
2457 break;
2459 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2460 longname_utf8segm) == 0) break;
2461 /* logf("SG: %s, EN: %s", longname_utf8segm,
2462 entry->name); */
2463 longname_utf8len += strlen(longname_utf8segm);
2464 if (longname_utf8len < FAT_FILENAME_BYTES)
2465 strcat(entry->name, longname_utf8segm);
2466 else
2467 break;
2469 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2470 longname_utf8segm) == 0) break;
2471 /* logf("SG: %s, EN: %s", longname_utf8segm,
2472 entry->name); */
2473 longname_utf8len += strlen(longname_utf8segm);
2474 if (longname_utf8len < FAT_FILENAME_BYTES)
2475 strcat(entry->name, longname_utf8segm);
2476 else
2477 break;
2480 /* Does the utf8-encoded name fit into the entry? */
2481 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2482 /* Take the short DOS name. Need to utf8-encode it
2483 since it may contain chars from the upper half of
2484 the OEM code page which wouldn't be a valid utf8.
2485 Beware: this file will be shown with strange
2486 glyphs in file browser since unicode 0x80 to 0x9F
2487 are control characters. */
2488 logf("SN-DOS: %s", shortname);
2489 unsigned char *utf8;
2490 utf8 = iso_decode(shortname, entry->name, -1,
2491 strlen(shortname));
2492 *utf8 = 0;
2493 logf("SN: %s", entry->name);
2494 } else {
2495 /* logf("LN: %s", entry->name);
2496 logf("LNLen: %d (%c)", longname_utf8len,
2497 entry->name[0]); */
2500 done = true;
2501 sectoridx = 0;
2502 i++;
2503 break;
2508 /* save this sector, for longname use */
2509 if ( sectoridx )
2510 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2511 else
2512 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2513 sectoridx += SECTOR_SIZE;
2516 return 0;
2519 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2521 #ifndef HAVE_MULTIVOLUME
2522 const int volume = 0;
2523 #endif
2524 struct bpb* fat_bpb = &fat_bpbs[volume];
2525 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2528 #ifdef HAVE_MULTIVOLUME
2529 bool fat_ismounted(int volume)
2531 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2533 #endif