Temporary fix for FS#7257 and FS#7261 - playback resumes while paused when seeking
[kugel-rb.git] / firmware / drivers / fat.c
blob999e6f1c9b8c2d8acf37ba92021214c042bbe5ee
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"
33 #include "atoi.h"
35 #define BYTES2INT16(array,pos) \
36 (array[pos] | (array[pos+1] << 8 ))
37 #define BYTES2INT32(array,pos) \
38 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
39 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
41 #define FATTYPE_FAT12 0
42 #define FATTYPE_FAT16 1
43 #define FATTYPE_FAT32 2
45 /* BPB offsets; generic */
46 #define BS_JMPBOOT 0
47 #define BS_OEMNAME 3
48 #define BPB_BYTSPERSEC 11
49 #define BPB_SECPERCLUS 13
50 #define BPB_RSVDSECCNT 14
51 #define BPB_NUMFATS 16
52 #define BPB_ROOTENTCNT 17
53 #define BPB_TOTSEC16 19
54 #define BPB_MEDIA 21
55 #define BPB_FATSZ16 22
56 #define BPB_SECPERTRK 24
57 #define BPB_NUMHEADS 26
58 #define BPB_HIDDSEC 28
59 #define BPB_TOTSEC32 32
61 /* fat12/16 */
62 #define BS_DRVNUM 36
63 #define BS_RESERVED1 37
64 #define BS_BOOTSIG 38
65 #define BS_VOLID 39
66 #define BS_VOLLAB 43
67 #define BS_FILSYSTYPE 54
69 /* fat32 */
70 #define BPB_FATSZ32 36
71 #define BPB_EXTFLAGS 40
72 #define BPB_FSVER 42
73 #define BPB_ROOTCLUS 44
74 #define BPB_FSINFO 48
75 #define BPB_BKBOOTSEC 50
76 #define BS_32_DRVNUM 64
77 #define BS_32_BOOTSIG 66
78 #define BS_32_VOLID 67
79 #define BS_32_VOLLAB 71
80 #define BS_32_FILSYSTYPE 82
82 #define BPB_LAST_WORD 510
85 /* attributes */
86 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
87 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
88 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
90 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
92 /* NTRES flags */
93 #define FAT_NTRES_LC_NAME 0x08
94 #define FAT_NTRES_LC_EXT 0x10
96 #define FATDIR_NAME 0
97 #define FATDIR_ATTR 11
98 #define FATDIR_NTRES 12
99 #define FATDIR_CRTTIMETENTH 13
100 #define FATDIR_CRTTIME 14
101 #define FATDIR_CRTDATE 16
102 #define FATDIR_LSTACCDATE 18
103 #define FATDIR_FSTCLUSHI 20
104 #define FATDIR_WRTTIME 22
105 #define FATDIR_WRTDATE 24
106 #define FATDIR_FSTCLUSLO 26
107 #define FATDIR_FILESIZE 28
109 #define FATLONG_ORDER 0
110 #define FATLONG_TYPE 12
111 #define FATLONG_CHKSUM 13
113 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
114 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
115 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
116 #define DIR_ENTRY_SIZE 32
117 #define NAME_BYTES_PER_ENTRY 13
118 #define FAT_BAD_MARK 0x0ffffff7
119 #define FAT_EOF_MARK 0x0ffffff8
120 #define FAT_LONGNAME_PAD_BYTE 0xff
121 #define FAT_LONGNAME_PAD_UCS 0xffff
123 struct fsinfo {
124 unsigned long freecount; /* last known free cluster count */
125 unsigned long nextfree; /* first cluster to start looking for free
126 clusters, or 0xffffffff for no hint */
128 /* fsinfo offsets */
129 #define FSINFO_FREECOUNT 488
130 #define FSINFO_NEXTFREE 492
132 /* Note: This struct doesn't hold the raw values after mounting if
133 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
134 * physical sectors. */
135 struct bpb
137 int bpb_bytspersec; /* Bytes per sector, typically 512 */
138 unsigned int bpb_secperclus; /* Sectors per cluster */
139 int bpb_rsvdseccnt; /* Number of reserved sectors */
140 int bpb_numfats; /* Number of FAT structures, typically 2 */
141 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
142 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
143 int bpb_fatsz16; /* Number of used sectors per FAT structure */
144 unsigned long bpb_totsec32; /* Number of sectors on the volume
145 (new 32-bit) */
146 unsigned int last_word; /* 0xAA55 */
148 /**** FAT32 specific *****/
149 long bpb_fatsz32;
150 long bpb_rootclus;
151 long bpb_fsinfo;
153 /* variables for internal use */
154 unsigned long fatsize;
155 unsigned long totalsectors;
156 unsigned long rootdirsector;
157 unsigned long firstdatasector;
158 unsigned long startsector;
159 unsigned long dataclusters;
160 struct fsinfo fsinfo;
161 #ifdef HAVE_FAT16SUPPORT
162 int bpb_rootentcnt; /* Number of dir entries in the root */
163 /* internals for FAT16 support */
164 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
165 unsigned int rootdiroffset; /* sector offset of root dir relative to start
166 * of first pseudo cluster */
167 #endif /* #ifdef HAVE_FAT16SUPPORT */
168 #ifdef HAVE_MULTIVOLUME
169 int drive; /* on which physical device is this located */
170 bool mounted; /* flag if this volume is mounted */
171 #endif
174 static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
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,) long secnum, bool dirty);
180 static void create_dos_name(const unsigned char *name, unsigned char *newname);
181 static void randomize_dos_name(unsigned char *name);
182 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned long start);
183 static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start, long count, char* buf, bool write );
185 #define FAT_CACHE_SIZE 0x20
186 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
188 struct fat_cache_entry
190 long secnum;
191 bool inuse;
192 bool dirty;
193 #ifdef HAVE_MULTIVOLUME
194 struct bpb* fat_vol ; /* shared cache for all volumes */
195 #endif
198 static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
199 static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
200 static struct mutex cache_mutex;
202 static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
204 #ifndef HAVE_MULTIVOLUME
205 struct bpb* fat_bpb = &fat_bpbs[0];
206 #endif
207 #ifdef HAVE_FAT16SUPPORT
208 /* negative clusters (FAT16 root dir) don't get the 2 offset */
209 int zerocluster = cluster < 0 ? 0 : 2;
210 #else
211 const long zerocluster = 2;
212 #endif
214 if (cluster > (long)(fat_bpb->dataclusters + 1))
216 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
217 return -1;
220 return (cluster - zerocluster) * fat_bpb->bpb_secperclus
221 + fat_bpb->firstdatasector;
224 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
226 #ifndef HAVE_MULTIVOLUME
227 const int volume = 0;
228 #endif
229 struct bpb* fat_bpb = &fat_bpbs[volume];
230 if (size)
231 *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
232 if (free)
233 *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
236 void fat_init(void)
238 unsigned int i;
240 mutex_init(&cache_mutex);
242 /* mark the FAT cache as unused */
243 for(i = 0;i < FAT_CACHE_SIZE;i++)
245 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
246 fat_cache[i].inuse = false;
247 fat_cache[i].dirty = false;
248 #ifdef HAVE_MULTIVOLUME
249 fat_cache[i].fat_vol = NULL;
250 #endif
252 #ifdef HAVE_MULTIVOLUME
253 /* mark the possible volumes as not mounted */
254 for (i=0; i<NUM_VOLUMES;i++)
256 fat_bpbs[i].mounted = false;
258 #endif
261 int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
263 #ifndef HAVE_MULTIVOLUME
264 const int volume = 0;
265 #endif
266 struct bpb* fat_bpb = &fat_bpbs[volume];
267 unsigned char buf[SECTOR_SIZE];
268 int rc;
269 int secmult;
270 long datasec;
271 #ifdef HAVE_FAT16SUPPORT
272 int rootdirsectors;
273 #endif
275 /* Read the sector */
276 rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
277 if(rc)
279 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
280 return rc * 10 - 1;
283 memset(fat_bpb, 0, sizeof(struct bpb));
284 fat_bpb->startsector = startsector;
285 #ifdef HAVE_MULTIVOLUME
286 fat_bpb->drive = drive;
287 #endif
289 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
290 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
291 /* Sanity check is performed later */
293 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
294 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
295 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
296 fat_bpb->bpb_media = buf[BPB_MEDIA];
297 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
298 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
299 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
300 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
301 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
303 /* calculate a few commonly used values */
304 if (fat_bpb->bpb_fatsz16 != 0)
305 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
306 else
307 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
309 if (fat_bpb->bpb_totsec16 != 0)
310 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
311 else
312 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
314 #ifdef HAVE_FAT16SUPPORT
315 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
316 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
317 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
318 #endif /* #ifdef HAVE_FAT16SUPPORT */
320 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
321 #ifdef HAVE_FAT16SUPPORT
322 + rootdirsectors
323 #endif
324 + fat_bpb->bpb_numfats * fat_bpb->fatsize;
326 /* Determine FAT type */
327 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
328 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
330 #ifdef TEST_FAT
332 we are sometimes testing with "illegally small" fat32 images,
333 so we don't use the proper fat32 test case for test code
335 if ( fat_bpb->bpb_fatsz16 )
336 #else
337 if ( fat_bpb->dataclusters < 65525 )
338 #endif
339 { /* FAT16 */
340 #ifdef HAVE_FAT16SUPPORT
341 fat_bpb->is_fat16 = true;
342 if (fat_bpb->dataclusters < 4085)
343 { /* FAT12 */
344 DEBUGF("This is FAT12. Go away!\n");
345 return -2;
347 #else /* #ifdef HAVE_FAT16SUPPORT */
348 DEBUGF("This is not FAT32. Go away!\n");
349 return -2;
350 #endif /* #ifndef HAVE_FAT16SUPPORT */
353 #ifdef HAVE_FAT16SUPPORT
354 if (fat_bpb->is_fat16)
355 { /* FAT16 specific part of BPB */
356 int dirclusters;
357 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
358 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
359 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
360 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
361 /* I assign negative pseudo cluster numbers for the root directory,
362 their range is counted upward until -1. */
363 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
364 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
365 - rootdirsectors;
367 else
368 #endif /* #ifdef HAVE_FAT16SUPPORT */
369 { /* FAT32 specific part of BPB */
370 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
371 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
372 fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,) fat_bpb->bpb_rootclus);
375 rc = bpb_is_sane(IF_MV(fat_bpb));
376 if (rc < 0)
378 DEBUGF( "fat_mount() - BPB is not sane\n");
379 return rc * 10 - 3;
382 #ifdef HAVE_FAT16SUPPORT
383 if (fat_bpb->is_fat16)
385 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
386 fat_bpb->fsinfo.nextfree = 0xffffffff;
388 else
389 #endif /* #ifdef HAVE_FAT16SUPPORT */
391 /* Read the fsinfo sector */
392 rc = ata_read_sectors(IF_MV2(drive,)
393 startsector + fat_bpb->bpb_fsinfo, 1, buf);
394 if (rc < 0)
396 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
397 return rc * 10 - 4;
399 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
400 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
403 /* calculate freecount if unset */
404 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
406 fat_recalc_free(IF_MV(volume));
409 LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
410 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
411 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
412 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
413 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);
415 #ifdef HAVE_MULTIVOLUME
416 fat_bpb->mounted = true;
417 #endif
419 return 0;
422 #ifdef HAVE_HOTSWAP
423 int fat_unmount(int volume, bool flush)
425 int rc;
426 struct bpb* fat_bpb = &fat_bpbs[volume];
428 if(flush)
430 rc = flush_fat(fat_bpb); /* the clean way, while still alive */
432 else
433 { /* volume is not accessible any more, e.g. MMC removed */
434 int i;
435 mutex_lock(&cache_mutex);
436 for(i = 0;i < FAT_CACHE_SIZE;i++)
438 struct fat_cache_entry *fce = &fat_cache[i];
439 if(fce->inuse && fce->fat_vol == fat_bpb)
441 fce->inuse = false; /* discard all from that volume */
442 fce->dirty = false;
445 mutex_unlock(&cache_mutex);
446 rc = 0;
448 fat_bpb->mounted = false;
449 return rc;
451 #endif /* #ifdef HAVE_HOTSWAP */
453 void fat_recalc_free(IF_MV_NONVOID(int volume))
455 #ifndef HAVE_MULTIVOLUME
456 const int volume = 0;
457 #endif
458 struct bpb* fat_bpb = &fat_bpbs[volume];
459 long free = 0;
460 unsigned long i;
461 #ifdef HAVE_FAT16SUPPORT
462 if (fat_bpb->is_fat16)
464 for (i = 0; i<fat_bpb->fatsize; i++) {
465 unsigned int j;
466 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
467 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
468 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
469 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
470 break;
472 if (letoh16(fat[j]) == 0x0000) {
473 free++;
474 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
475 fat_bpb->fsinfo.nextfree = c;
480 else
481 #endif /* #ifdef HAVE_FAT16SUPPORT */
483 for (i = 0; i<fat_bpb->fatsize; i++) {
484 unsigned int j;
485 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
486 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
487 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
488 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
489 break;
491 if (!(letoh32(fat[j]) & 0x0fffffff)) {
492 free++;
493 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
494 fat_bpb->fsinfo.nextfree = c;
499 fat_bpb->fsinfo.freecount = free;
500 update_fsinfo(IF_MV(fat_bpb));
503 static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
505 #ifndef HAVE_MULTIVOLUME
506 struct bpb* fat_bpb = &fat_bpbs[0];
507 #endif
508 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
510 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
511 fat_bpb->bpb_bytspersec);
512 return -1;
514 if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec > 128L*1024L)
516 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
517 "(%d * %d = %d)\n",
518 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
519 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
520 return -2;
522 if(fat_bpb->bpb_numfats != 2)
524 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
525 fat_bpb->bpb_numfats);
527 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
529 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
530 "media type (0x%02x)\n",
531 fat_bpb->bpb_media);
533 if(fat_bpb->last_word != 0xaa55)
535 DEBUGF( "bpb_is_sane() - Error: Last word is not "
536 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
537 return -3;
540 if (fat_bpb->fsinfo.freecount >
541 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
542 fat_bpb->bpb_secperclus)
544 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
545 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
546 return -4;
549 return 0;
552 static void flush_fat_sector(struct fat_cache_entry *fce,
553 unsigned char *sectorbuf)
555 int rc;
556 long secnum;
558 /* With multivolume, use only the FAT info from the cached sector! */
559 #ifdef HAVE_MULTIVOLUME
560 secnum = fce->secnum + fce->fat_vol->startsector;
561 #else
562 secnum = fce->secnum + fat_bpbs[0].startsector;
563 #endif
565 /* Write to the first FAT */
566 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
567 secnum, 1,
568 sectorbuf);
569 if(rc < 0)
571 panicf("flush_fat_sector() - Could not write sector %ld"
572 " (error %d)\n",
573 secnum, rc);
575 #ifdef HAVE_MULTIVOLUME
576 if(fce->fat_vol->bpb_numfats > 1)
577 #else
578 if(fat_bpbs[0].bpb_numfats > 1)
579 #endif
581 /* Write to the second FAT */
582 #ifdef HAVE_MULTIVOLUME
583 secnum += fce->fat_vol->fatsize;
584 #else
585 secnum += fat_bpbs[0].fatsize;
586 #endif
587 rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
588 secnum, 1, sectorbuf);
589 if(rc < 0)
591 panicf("flush_fat_sector() - Could not write sector %ld"
592 " (error %d)\n",
593 secnum, rc);
596 fce->dirty = false;
599 /* Note: The returned pointer is only safely valid until the next
600 task switch! (Any subsequent ata read/write may yield.) */
601 static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
602 long fatsector, bool dirty)
604 #ifndef HAVE_MULTIVOLUME
605 struct bpb* fat_bpb = &fat_bpbs[0];
606 #endif
607 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
608 int cache_index = secnum & FAT_CACHE_MASK;
609 struct fat_cache_entry *fce = &fat_cache[cache_index];
610 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
611 int rc;
613 mutex_lock(&cache_mutex); /* make changes atomic */
615 /* Delete the cache entry if it isn't the sector we want */
616 if(fce->inuse && (fce->secnum != secnum
617 #ifdef HAVE_MULTIVOLUME
618 || fce->fat_vol != fat_bpb
619 #endif
622 /* Write back if it is dirty */
623 if(fce->dirty)
625 flush_fat_sector(fce, sectorbuf);
627 fce->inuse = false;
630 /* Load the sector if it is not cached */
631 if(!fce->inuse)
633 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
634 secnum + fat_bpb->startsector,1,
635 sectorbuf);
636 if(rc < 0)
638 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
639 " (error %d)\n", secnum, rc);
640 mutex_unlock(&cache_mutex);
641 return NULL;
643 fce->inuse = true;
644 fce->secnum = secnum;
645 #ifdef HAVE_MULTIVOLUME
646 fce->fat_vol = fat_bpb;
647 #endif
649 if (dirty)
650 fce->dirty = true; /* dirt remains, sticky until flushed */
651 mutex_unlock(&cache_mutex);
652 return sectorbuf;
655 static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned long startcluster)
657 #ifndef HAVE_MULTIVOLUME
658 struct bpb* fat_bpb = &fat_bpbs[0];
659 #endif
660 unsigned long sector;
661 unsigned long offset;
662 unsigned long i;
664 #ifdef HAVE_FAT16SUPPORT
665 if (fat_bpb->is_fat16)
667 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
668 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
670 for (i = 0; i<fat_bpb->fatsize; i++) {
671 unsigned int j;
672 unsigned int nr = (i + sector) % fat_bpb->fatsize;
673 unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
674 if ( !fat )
675 break;
676 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
677 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
678 if (letoh16(fat[k]) == 0x0000) {
679 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
680 /* Ignore the reserved clusters 0 & 1, and also
681 cluster numbers out of bounds */
682 if ( c < 2 || c > fat_bpb->dataclusters+1 )
683 continue;
684 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
685 fat_bpb->fsinfo.nextfree = c;
686 return c;
689 offset = 0;
692 else
693 #endif /* #ifdef HAVE_FAT16SUPPORT */
695 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
696 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
698 for (i = 0; i<fat_bpb->fatsize; i++) {
699 unsigned int j;
700 unsigned long nr = (i + sector) % fat_bpb->fatsize;
701 unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
702 if ( !fat )
703 break;
704 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
705 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
706 if (!(letoh32(fat[k]) & 0x0fffffff)) {
707 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
708 /* Ignore the reserved clusters 0 & 1, and also
709 cluster numbers out of bounds */
710 if ( c < 2 || c > fat_bpb->dataclusters+1 )
711 continue;
712 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
713 fat_bpb->fsinfo.nextfree = c;
714 return c;
717 offset = 0;
721 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
722 return 0; /* 0 is an illegal cluster number */
725 static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry, unsigned long val)
727 #ifndef HAVE_MULTIVOLUME
728 struct bpb* fat_bpb = &fat_bpbs[0];
729 #endif
730 #ifdef HAVE_FAT16SUPPORT
731 if (fat_bpb->is_fat16)
733 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
734 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
735 unsigned short* sec;
737 val &= 0xFFFF;
739 LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
741 if (entry==val)
742 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
744 if ( entry < 2 )
745 panicf("Updating reserved FAT entry %ld.\n",entry);
747 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
748 if (!sec)
750 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
751 return -1;
754 if ( val ) {
755 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
756 fat_bpb->fsinfo.freecount--;
758 else {
759 if (letoh16(sec[offset]))
760 fat_bpb->fsinfo.freecount++;
763 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
765 sec[offset] = htole16(val);
767 else
768 #endif /* #ifdef HAVE_FAT16SUPPORT */
770 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
771 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
772 unsigned long* sec;
774 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
776 if (entry==val)
777 panicf("Creating FAT loop: %lx,%lx\n",entry,val);
779 if ( entry < 2 )
780 panicf("Updating reserved FAT entry %ld.\n",entry);
782 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
783 if (!sec)
785 DEBUGF( "update_fat_entry() - Could not cache sector %ld\n", sector);
786 return -1;
789 if ( val ) {
790 if (!(letoh32(sec[offset]) & 0x0fffffff) &&
791 fat_bpb->fsinfo.freecount > 0)
792 fat_bpb->fsinfo.freecount--;
794 else {
795 if (letoh32(sec[offset]) & 0x0fffffff)
796 fat_bpb->fsinfo.freecount++;
799 LDEBUGF("update_fat_entry: %ld free clusters\n", fat_bpb->fsinfo.freecount);
801 /* don't change top 4 bits */
802 sec[offset] &= htole32(0xf0000000);
803 sec[offset] |= htole32(val & 0x0fffffff);
806 return 0;
809 static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
811 #ifdef HAVE_FAT16SUPPORT
812 #ifndef HAVE_MULTIVOLUME
813 struct bpb* fat_bpb = &fat_bpbs[0];
814 #endif
815 if (fat_bpb->is_fat16)
817 int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
818 int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
819 unsigned short* sec;
821 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
822 if (!sec)
824 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
825 return -1;
828 return letoh16(sec[offset]);
830 else
831 #endif /* #ifdef HAVE_FAT16SUPPORT */
833 long sector = entry / CLUSTERS_PER_FAT_SECTOR;
834 int offset = entry % CLUSTERS_PER_FAT_SECTOR;
835 unsigned long* sec;
837 sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
838 if (!sec)
840 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
841 return -1;
844 return letoh32(sec[offset]) & 0x0fffffff;
848 static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
850 long next_cluster;
851 long eof_mark = FAT_EOF_MARK;
853 #ifdef HAVE_FAT16SUPPORT
854 #ifndef HAVE_MULTIVOLUME
855 struct bpb* fat_bpb = &fat_bpbs[0];
856 #endif
857 if (fat_bpb->is_fat16)
859 eof_mark &= 0xFFFF; /* only 16 bit */
860 if (cluster < 0) /* FAT16 root dir */
861 return cluster + 1; /* don't use the FAT */
863 #endif
864 next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
866 /* is this last cluster in chain? */
867 if ( next_cluster >= eof_mark )
868 return 0;
869 else
870 return next_cluster;
873 static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
875 #ifndef HAVE_MULTIVOLUME
876 struct bpb* fat_bpb = &fat_bpbs[0];
877 #endif
878 unsigned char fsinfo[SECTOR_SIZE];
879 unsigned long* intptr;
880 int rc;
882 #ifdef HAVE_FAT16SUPPORT
883 if (fat_bpb->is_fat16)
884 return 0; /* FAT16 has no FsInfo */
885 #endif /* #ifdef HAVE_FAT16SUPPORT */
887 /* update fsinfo */
888 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
889 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
890 if (rc < 0)
892 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
893 return rc * 10 - 1;
895 intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
896 *intptr = htole32(fat_bpb->fsinfo.freecount);
898 intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
899 *intptr = htole32(fat_bpb->fsinfo.nextfree);
901 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
902 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
903 if (rc < 0)
905 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
906 return rc * 10 - 2;
909 return 0;
912 static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
914 int i;
915 int rc;
916 unsigned char *sec;
917 LDEBUGF("flush_fat()\n");
919 mutex_lock(&cache_mutex);
920 for(i = 0;i < FAT_CACHE_SIZE;i++)
922 struct fat_cache_entry *fce = &fat_cache[i];
923 if(fce->inuse
924 #ifdef HAVE_MULTIVOLUME
925 && fce->fat_vol == fat_bpb
926 #endif
927 && fce->dirty)
929 sec = fat_cache_sectors[i];
930 flush_fat_sector(fce, sec);
933 mutex_unlock(&cache_mutex);
935 rc = update_fsinfo(IF_MV(fat_bpb));
936 if (rc < 0)
937 return rc * 10 - 3;
939 return 0;
942 static void fat_time(unsigned short* date,
943 unsigned short* time,
944 unsigned short* tenth )
946 #if CONFIG_RTC
947 struct tm* tm = get_time();
949 if (date)
950 *date = ((tm->tm_year - 80) << 9) |
951 ((tm->tm_mon + 1) << 5) |
952 tm->tm_mday;
954 if (time)
955 *time = (tm->tm_hour << 11) |
956 (tm->tm_min << 5) |
957 (tm->tm_sec >> 1);
959 if (tenth)
960 *tenth = (tm->tm_sec & 1) * 100;
961 #else
962 /* non-RTC version returns an increment from the supplied time, or a
963 * fixed standard time/date if no time given as input */
964 bool next_day = false;
966 if (time)
968 if (0 == *time)
970 /* set to 00:15:00 */
971 *time = (15 << 5);
973 else
975 unsigned short mins = (*time >> 5) & 0x003F;
976 unsigned short hours = (*time >> 11) & 0x001F;
977 if ((mins += 10) >= 60)
979 mins = 0;
980 hours++;
982 if ((++hours) >= 24)
984 hours = hours - 24;
985 next_day = true;
987 *time = (hours << 11) | (mins << 5);
991 if (date)
993 if (0 == *date)
995 /* Macros to convert a 2-digit string to a decimal constant.
996 (YEAR), MONTH and DAY are set by the date command, which outputs
997 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
998 misinterpretation as an octal constant. */
999 #define S100(x) 1 ## x
1000 #define C2DIG2DEC(x) (S100(x)-100)
1001 /* set to build date */
1002 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1003 | C2DIG2DEC(DAY);
1005 else
1007 unsigned short day = *date & 0x001F;
1008 unsigned short month = (*date >> 5) & 0x000F;
1009 unsigned short year = (*date >> 9) & 0x007F;
1010 if (next_day)
1012 /* do a very simple day increment - never go above 28 days */
1013 if (++day > 28)
1015 day = 1;
1016 if (++month > 12)
1018 month = 1;
1019 year++;
1022 *date = (year << 9) | (month << 5) | day;
1026 if (tenth)
1027 *tenth = 0;
1028 #endif /* CONFIG_RTC */
1031 static int write_long_name(struct fat_file* file,
1032 unsigned int firstentry,
1033 unsigned int numentries,
1034 const unsigned char* name,
1035 const unsigned char* shortname,
1036 bool is_directory)
1038 unsigned char buf[SECTOR_SIZE];
1039 unsigned char* entry;
1040 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1041 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1042 unsigned char chksum = 0;
1043 unsigned int i, j=0;
1044 unsigned int nameidx=0, namelen = utf8length(name);
1045 int rc;
1046 unsigned short name_utf16[namelen + 1];
1048 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1049 file->firstcluster, firstentry, numentries, name);
1051 rc = fat_seek(file, sector);
1052 if (rc<0)
1053 return rc * 10 - 1;
1055 rc = fat_readwrite(file, 1, buf, false);
1056 if (rc<1)
1057 return rc * 10 - 2;
1059 /* calculate shortname checksum */
1060 for (i=11; i>0; i--)
1061 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1063 /* calc position of last name segment */
1064 if ( namelen > NAME_BYTES_PER_ENTRY )
1065 for (nameidx=0;
1066 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1067 nameidx += NAME_BYTES_PER_ENTRY);
1069 /* we need to convert the name first */
1070 /* since it is written in reverse order */
1071 for (i = 0; i <= namelen; i++)
1072 name = utf8decode(name, &name_utf16[i]);
1074 for (i=0; i < numentries; i++) {
1075 /* new sector? */
1076 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1077 /* update current sector */
1078 rc = fat_seek(file, sector);
1079 if (rc<0)
1080 return rc * 10 - 3;
1082 rc = fat_readwrite(file, 1, buf, true);
1083 if (rc<1)
1084 return rc * 10 - 4;
1086 /* read next sector */
1087 rc = fat_readwrite(file, 1, buf, false);
1088 if (rc<0) {
1089 LDEBUGF("Failed writing new sector: %d\n",rc);
1090 return rc * 10 - 5;
1092 if (rc==0)
1093 /* end of dir */
1094 memset(buf, 0, sizeof buf);
1096 sector++;
1097 idx = 0;
1100 entry = buf + idx * DIR_ENTRY_SIZE;
1102 /* verify this entry is free */
1103 if (entry[0] && entry[0] != 0xe5 )
1104 panicf("Dir entry %d in sector %x is not free! "
1105 "%02x %02x %02x %02x",
1106 idx, sector,
1107 entry[0], entry[1], entry[2], entry[3]);
1109 memset(entry, 0, DIR_ENTRY_SIZE);
1110 if ( i+1 < numentries ) {
1111 /* longname entry */
1112 unsigned int k, l = nameidx;
1114 entry[FATLONG_ORDER] = numentries-i-1;
1115 if (i==0) {
1116 /* mark this as last long entry */
1117 entry[FATLONG_ORDER] |= 0x40;
1119 /* pad name with 0xffff */
1120 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1121 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1122 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1124 /* set name */
1125 for (k=0; k<5 && l <= namelen; k++) {
1126 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1127 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1129 for (k=0; k<6 && l <= namelen; k++) {
1130 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1131 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1133 for (k=0; k<2 && l <= namelen; k++) {
1134 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1135 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1138 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1139 entry[FATDIR_FSTCLUSLO] = 0;
1140 entry[FATLONG_TYPE] = 0;
1141 entry[FATLONG_CHKSUM] = chksum;
1142 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1144 else {
1145 /* shortname entry */
1146 unsigned short date=0, time=0, tenth=0;
1147 LDEBUGF("Shortname entry: %s\n", shortname);
1148 strncpy(entry + FATDIR_NAME, shortname, 11);
1149 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1150 entry[FATDIR_NTRES] = 0;
1152 fat_time(&date, &time, &tenth);
1153 entry[FATDIR_CRTTIMETENTH] = tenth;
1154 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1155 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1156 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1157 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1158 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1160 idx++;
1161 nameidx -= NAME_BYTES_PER_ENTRY;
1164 /* update last sector */
1165 rc = fat_seek(file, sector);
1166 if (rc<0)
1167 return rc * 10 - 6;
1169 rc = fat_readwrite(file, 1, buf, true);
1170 if (rc<1)
1171 return rc * 10 - 7;
1173 return 0;
1176 static int fat_checkname(const unsigned char* newname)
1178 static const char invalid_chars[] = "\"*/:<>?\\|";
1179 int len = strlen(newname);
1180 /* More sanity checks are probably needed */
1181 if (len > 255 || newname[len - 1] == '.')
1183 return -1;
1185 while (*newname)
1187 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1188 return -1;
1189 newname++;
1191 return 0;
1194 static int add_dir_entry(struct fat_dir* dir,
1195 struct fat_file* file,
1196 const char* name,
1197 bool is_directory,
1198 bool dotdir)
1200 #ifdef HAVE_MULTIVOLUME
1201 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1202 #else
1203 struct bpb* fat_bpb = &fat_bpbs[0];
1204 #endif
1205 unsigned char buf[SECTOR_SIZE];
1206 unsigned char shortname[12];
1207 int rc;
1208 unsigned int sector;
1209 bool done = false;
1210 int entries_needed, entries_found = 0;
1211 int firstentry;
1213 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1214 name, file->firstcluster);
1216 /* Don't check dotdirs name for validity */
1217 if (dotdir == false) {
1218 rc = fat_checkname(name);
1219 if (rc < 0) {
1220 /* filename is invalid */
1221 return rc * 10 - 1;
1225 #ifdef HAVE_MULTIVOLUME
1226 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1227 #endif
1229 /* The "." and ".." directory entries must not be long names */
1230 if(dotdir) {
1231 int i;
1232 strncpy(shortname, name, 12);
1233 for(i = strlen(shortname); i < 12; i++)
1234 shortname[i] = ' ';
1236 entries_needed = 1;
1237 } else {
1238 create_dos_name(name, shortname);
1240 /* one dir entry needed for every 13 bytes of filename,
1241 plus one entry for the short name */
1242 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1243 / NAME_BYTES_PER_ENTRY + 1;
1246 restart:
1247 firstentry = -1;
1249 rc = fat_seek(&dir->file, 0);
1250 if (rc < 0)
1251 return rc * 10 - 2;
1253 /* step 1: search for free entries and check for duplicate shortname */
1254 for (sector = 0; !done; sector++)
1256 unsigned int i;
1258 rc = fat_readwrite(&dir->file, 1, buf, false);
1259 if (rc < 0) {
1260 DEBUGF( "add_dir_entry() - Couldn't read dir"
1261 " (error code %d)\n", rc);
1262 return rc * 10 - 3;
1265 if (rc == 0) { /* current end of dir reached */
1266 LDEBUGF("End of dir on cluster boundary\n");
1267 break;
1270 /* look for free slots */
1271 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1273 switch (buf[i * DIR_ENTRY_SIZE]) {
1274 case 0:
1275 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1276 LDEBUGF("Found end of dir %d\n",
1277 sector * DIR_ENTRIES_PER_SECTOR + i);
1278 i = DIR_ENTRIES_PER_SECTOR - 1;
1279 done = true;
1280 break;
1282 case 0xe5:
1283 entries_found++;
1284 LDEBUGF("Found free entry %d (%d/%d)\n",
1285 sector * DIR_ENTRIES_PER_SECTOR + i,
1286 entries_found, entries_needed);
1287 break;
1289 default:
1290 entries_found = 0;
1292 /* check that our intended shortname doesn't already exist */
1293 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1294 /* shortname exists already, make a new one */
1295 randomize_dos_name(shortname);
1296 LDEBUGF("Duplicate shortname, changing to %s\n",
1297 shortname);
1299 /* name has changed, we need to restart search */
1300 goto restart;
1302 break;
1304 if (firstentry < 0 && (entries_found >= entries_needed))
1305 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1306 - entries_found;
1310 /* step 2: extend the dir if necessary */
1311 if (firstentry < 0)
1313 LDEBUGF("Adding new sector(s) to dir\n");
1314 rc = fat_seek(&dir->file, sector);
1315 if (rc < 0)
1316 return rc * 10 - 4;
1317 memset(buf, 0, sizeof buf);
1319 /* we must clear whole clusters */
1320 for (; (entries_found < entries_needed) ||
1321 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1323 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1324 return -5; /* dir too large -- FAT specification */
1326 rc = fat_readwrite(&dir->file, 1, buf, true);
1327 if (rc < 1) /* No more room or something went wrong */
1328 return rc * 10 - 6;
1330 entries_found += DIR_ENTRIES_PER_SECTOR;
1333 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1336 /* step 3: add entry */
1337 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1338 LDEBUGF("Adding longname to entry %d in sector %d\n",
1339 firstentry, sector);
1341 rc = write_long_name(&dir->file, firstentry,
1342 entries_needed, name, shortname, is_directory);
1343 if (rc < 0)
1344 return rc * 10 - 7;
1346 /* remember where the shortname dir entry is located */
1347 file->direntry = firstentry + entries_needed - 1;
1348 file->direntries = entries_needed;
1349 file->dircluster = dir->file.firstcluster;
1350 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1351 file->direntry, file->direntries);
1353 return 0;
1356 static unsigned char char2dos(unsigned char c, int* randomize)
1358 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1360 if (c <= 0x20)
1361 c = 0; /* Illegal char, remove */
1362 else if (strchr(invalid_chars, c) != NULL)
1364 /* Illegal char, replace */
1365 c = '_';
1366 *randomize = 1; /* as per FAT spec */
1368 else
1369 c = toupper(c);
1371 return c;
1374 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1376 int i;
1377 unsigned char *ext;
1378 int randomize = 0;
1380 /* Find extension part */
1381 ext = strrchr(name, '.');
1382 if (ext == name) /* handle .dotnames */
1383 ext = NULL;
1385 /* needs to randomize? */
1386 if((ext && (strlen(ext) > 4)) ||
1387 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1388 randomize = 1;
1390 /* Name part */
1391 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1393 unsigned char c = char2dos(*name, &randomize);
1394 if (c)
1395 newname[i++] = c;
1398 /* Pad both name and extension */
1399 while (i < 11)
1400 newname[i++] = ' ';
1402 if (newname[0] == 0xe5) /* Special kanji character */
1403 newname[0] = 0x05;
1405 if (ext)
1406 { /* Extension part */
1407 ext++;
1408 for (i = 8; *ext && (i < 11); ext++)
1410 unsigned char c = char2dos(*ext, &randomize);
1411 if (c)
1412 newname[i++] = c;
1416 if(randomize)
1417 randomize_dos_name(newname);
1420 static void randomize_dos_name(unsigned char *name)
1422 unsigned char* tilde = NULL; /* ~ location */
1423 unsigned char* lastpt = NULL; /* last point of filename */
1424 unsigned char* nameptr = name; /* working copy of name pointer */
1425 unsigned char num[9]; /* holds number as string */
1426 int i = 0;
1427 int cnt = 1;
1428 int numlen;
1429 int offset;
1431 while(i++ < 8)
1433 /* hunt for ~ and where to put it */
1434 if((!tilde) && (*nameptr == '~'))
1435 tilde = nameptr;
1436 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1437 lastpt = nameptr;
1438 nameptr++;
1440 if(tilde)
1442 /* extract current count and increment */
1443 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1444 num[7-(unsigned int)(tilde-name)] = 0;
1445 cnt = atoi(num) + 1;
1447 cnt %= 10000000; /* protection */
1448 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1449 numlen = strlen(num); /* required space */
1450 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1451 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1453 memcpy(&name[offset], num, numlen);
1455 /* in special case of counter overflow: pad with spaces */
1456 for(offset = offset+numlen; offset < 8; offset++)
1457 name[offset] = ' ';
1460 static int update_short_entry( struct fat_file* file, long size, int attr )
1462 unsigned char buf[SECTOR_SIZE];
1463 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1464 unsigned char* entry =
1465 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1466 unsigned long* sizeptr;
1467 unsigned short* clusptr;
1468 struct fat_file dir;
1469 int rc;
1471 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1472 file->firstcluster, file->direntry, size);
1474 /* create a temporary file handle for the dir holding this file */
1475 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1476 if (rc < 0)
1477 return rc * 10 - 1;
1479 rc = fat_seek( &dir, sector );
1480 if (rc<0)
1481 return rc * 10 - 2;
1483 rc = fat_readwrite(&dir, 1, buf, false);
1484 if (rc < 1)
1485 return rc * 10 - 3;
1487 if (!entry[0] || entry[0] == 0xe5)
1488 panicf("Updating size on empty dir entry %d\n", file->direntry);
1490 entry[FATDIR_ATTR] = attr & 0xFF;
1492 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1493 *clusptr = htole16(file->firstcluster >> 16);
1495 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1496 *clusptr = htole16(file->firstcluster & 0xffff);
1498 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1499 *sizeptr = htole32(size);
1502 #if CONFIG_RTC
1503 unsigned short time = 0;
1504 unsigned short date = 0;
1505 #else
1506 /* get old time to increment from */
1507 unsigned short time = htole16(*(unsigned short*)(entry + FATDIR_WRTTIME));
1508 unsigned short date = htole16(*(unsigned short*)(entry + FATDIR_WRTDATE));
1509 #endif
1510 fat_time(&date, &time, NULL);
1511 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1512 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1513 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1516 rc = fat_seek( &dir, sector );
1517 if (rc < 0)
1518 return rc * 10 - 4;
1520 rc = fat_readwrite(&dir, 1, buf, true);
1521 if (rc < 1)
1522 return rc * 10 - 5;
1524 return 0;
1527 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1529 int i=0,j=0;
1530 unsigned char c;
1531 bool lowercase;
1533 memset(de, 0, sizeof(struct fat_direntry));
1534 de->attr = buf[FATDIR_ATTR];
1535 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1536 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1537 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1538 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1539 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1540 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1541 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1542 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1543 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1544 (the result of the shift is always considered signed) */
1546 /* fix the name */
1547 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1548 c = buf[FATDIR_NAME];
1549 if (c == 0x05) /* special kanji char */
1550 c = 0xe5;
1551 i = 0;
1552 while (c != ' ') {
1553 de->name[j++] = lowercase ? tolower(c) : c;
1554 if (++i >= 8)
1555 break;
1556 c = buf[FATDIR_NAME+i];
1558 if (buf[FATDIR_NAME+8] != ' ') {
1559 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1560 de->name[j++] = '.';
1561 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1562 de->name[j++] = lowercase ? tolower(c) : c;
1564 return 1;
1567 int fat_open(IF_MV2(int volume,)
1568 long startcluster,
1569 struct fat_file *file,
1570 const struct fat_dir* dir)
1572 file->firstcluster = startcluster;
1573 file->lastcluster = startcluster;
1574 file->lastsector = 0;
1575 file->clusternum = 0;
1576 file->sectornum = 0;
1577 file->eof = false;
1578 #ifdef HAVE_MULTIVOLUME
1579 file->volume = volume;
1580 /* fixme: remove error check when done */
1581 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1583 LDEBUGF("fat_open() illegal volume %d\n", volume);
1584 return -1;
1586 #endif
1588 /* remember where the file's dir entry is located */
1589 if ( dir ) {
1590 file->direntry = dir->entry - 1;
1591 file->direntries = dir->entrycount;
1592 file->dircluster = dir->file.firstcluster;
1594 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1595 return 0;
1598 int fat_create_file(const char* name,
1599 struct fat_file* file,
1600 struct fat_dir* dir)
1602 int rc;
1604 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1605 rc = add_dir_entry(dir, file, name, false, false);
1606 if (!rc) {
1607 file->firstcluster = 0;
1608 file->lastcluster = 0;
1609 file->lastsector = 0;
1610 file->clusternum = 0;
1611 file->sectornum = 0;
1612 file->eof = false;
1615 return rc;
1618 int fat_create_dir(const char* name,
1619 struct fat_dir* newdir,
1620 struct fat_dir* dir)
1622 #ifdef HAVE_MULTIVOLUME
1623 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1624 #else
1625 struct bpb* fat_bpb = &fat_bpbs[0];
1626 #endif
1627 unsigned char buf[SECTOR_SIZE];
1628 int i;
1629 long sector;
1630 int rc;
1631 struct fat_file dummyfile;
1633 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1635 memset(newdir, 0, sizeof(struct fat_dir));
1636 memset(&dummyfile, 0, sizeof(struct fat_file));
1638 /* First, add the entry in the parent directory */
1639 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1640 if (rc < 0)
1641 return rc * 10 - 1;
1643 /* Allocate a new cluster for the directory */
1644 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
1645 if(newdir->file.firstcluster == 0)
1646 return -1;
1648 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1650 /* Clear the entire cluster */
1651 memset(buf, 0, sizeof buf);
1652 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1653 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1654 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1655 if (rc < 0)
1656 return rc * 10 - 2;
1659 /* Then add the "." entry */
1660 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1661 if (rc < 0)
1662 return rc * 10 - 3;
1663 dummyfile.firstcluster = newdir->file.firstcluster;
1664 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1666 /* and the ".." entry */
1667 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1668 if (rc < 0)
1669 return rc * 10 - 4;
1671 /* The root cluster is cluster 0 in the ".." entry */
1672 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1673 dummyfile.firstcluster = 0;
1674 else
1675 dummyfile.firstcluster = dir->file.firstcluster;
1676 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1678 /* Set the firstcluster field in the direntry */
1679 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1681 rc = flush_fat(IF_MV(fat_bpb));
1682 if (rc < 0)
1683 return rc * 10 - 5;
1685 return rc;
1688 int fat_truncate(const struct fat_file *file)
1690 /* truncate trailing clusters */
1691 long next;
1692 long last = file->lastcluster;
1693 #ifdef HAVE_MULTIVOLUME
1694 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1695 #endif
1697 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1699 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1700 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1701 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1703 if (file->lastcluster)
1704 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1706 return 0;
1709 int fat_closewrite(struct fat_file *file, long size, int attr)
1711 int rc;
1712 #ifdef HAVE_MULTIVOLUME
1713 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1714 #endif
1715 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1717 if (!size) {
1718 /* empty file */
1719 if ( file->firstcluster ) {
1720 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1721 file->firstcluster = 0;
1725 if (file->dircluster) {
1726 rc = update_short_entry(file, size, attr);
1727 if (rc < 0)
1728 return rc * 10 - 1;
1731 flush_fat(IF_MV(fat_bpb));
1733 #ifdef TEST_FAT
1734 if ( file->firstcluster ) {
1735 /* debug */
1736 #ifdef HAVE_MULTIVOLUME
1737 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1738 #else
1739 struct bpb* fat_bpb = &fat_bpbs[0];
1740 #endif
1741 long count = 0;
1742 long len;
1743 long next;
1744 for ( next = file->firstcluster; next;
1745 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1746 LDEBUGF("cluster %ld: %lx\n", count, next);
1747 count++;
1749 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1750 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1751 count, len, size );
1752 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1753 panicf("Cluster chain is too long\n");
1754 if ( len < size )
1755 panicf("Cluster chain is too short\n");
1757 #endif
1759 return 0;
1762 static int free_direntries(struct fat_file* file)
1764 unsigned char buf[SECTOR_SIZE];
1765 struct fat_file dir;
1766 int numentries = file->direntries;
1767 unsigned int entry = file->direntry - numentries + 1;
1768 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1769 int i;
1770 int rc;
1772 /* create a temporary file handle for the dir holding this file */
1773 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1774 if (rc < 0)
1775 return rc * 10 - 1;
1777 rc = fat_seek( &dir, sector );
1778 if (rc < 0)
1779 return rc * 10 - 2;
1781 rc = fat_readwrite(&dir, 1, buf, false);
1782 if (rc < 1)
1783 return rc * 10 - 3;
1785 for (i=0; i < numentries; i++) {
1786 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1787 entry, i+1, numentries);
1788 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1789 entry++;
1791 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1792 /* flush this sector */
1793 rc = fat_seek(&dir, sector);
1794 if (rc < 0)
1795 return rc * 10 - 4;
1797 rc = fat_readwrite(&dir, 1, buf, true);
1798 if (rc < 1)
1799 return rc * 10 - 5;
1801 if ( i+1 < numentries ) {
1802 /* read next sector */
1803 rc = fat_readwrite(&dir, 1, buf, false);
1804 if (rc < 1)
1805 return rc * 10 - 6;
1807 sector++;
1811 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1812 /* flush this sector */
1813 rc = fat_seek(&dir, sector);
1814 if (rc < 0)
1815 return rc * 10 - 7;
1817 rc = fat_readwrite(&dir, 1, buf, true);
1818 if (rc < 1)
1819 return rc * 10 - 8;
1822 return 0;
1825 int fat_remove(struct fat_file* file)
1827 long next, last = file->firstcluster;
1828 int rc;
1829 #ifdef HAVE_MULTIVOLUME
1830 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1831 #endif
1833 LDEBUGF("fat_remove(%lx)\n",last);
1835 while ( last ) {
1836 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1837 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1838 last = next;
1841 if ( file->dircluster ) {
1842 rc = free_direntries(file);
1843 if (rc < 0)
1844 return rc * 10 - 1;
1847 file->firstcluster = 0;
1848 file->dircluster = 0;
1850 rc = flush_fat(IF_MV(fat_bpb));
1851 if (rc < 0)
1852 return rc * 10 - 2;
1854 return 0;
1857 int fat_rename(struct fat_file* file,
1858 struct fat_dir* dir,
1859 const unsigned char* newname,
1860 long size,
1861 int attr)
1863 int rc;
1864 struct fat_dir olddir;
1865 struct fat_file newfile = *file;
1866 #ifdef HAVE_MULTIVOLUME
1867 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1869 if (file->volume != dir->file.volume) {
1870 DEBUGF("No rename across volumes!\n");
1871 return -1;
1873 #endif
1875 if ( !file->dircluster ) {
1876 DEBUGF("File has no dir cluster!\n");
1877 return -2;
1880 /* create a temporary file handle */
1881 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1882 if (rc < 0)
1883 return rc * 10 - 3;
1885 /* create new name */
1886 rc = add_dir_entry(dir, &newfile, newname, false, false);
1887 if (rc < 0)
1888 return rc * 10 - 4;
1890 /* write size and cluster link */
1891 rc = update_short_entry(&newfile, size, attr);
1892 if (rc < 0)
1893 return rc * 10 - 5;
1895 /* remove old name */
1896 rc = free_direntries(file);
1897 if (rc < 0)
1898 return rc * 10 - 6;
1900 rc = flush_fat(IF_MV(fat_bpb));
1901 if (rc < 0)
1902 return rc * 10 - 7;
1904 return 0;
1907 static long next_write_cluster(struct fat_file* file,
1908 long oldcluster,
1909 long* newsector)
1911 #ifdef HAVE_MULTIVOLUME
1912 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1913 #else
1914 struct bpb* fat_bpb = &fat_bpbs[0];
1915 #endif
1916 long cluster = 0;
1917 long sector;
1919 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
1921 if (oldcluster)
1922 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
1924 if (!cluster) {
1925 if (oldcluster > 0)
1926 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
1927 else if (oldcluster == 0)
1928 cluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
1929 #ifdef HAVE_FAT16SUPPORT
1930 else /* negative, pseudo-cluster of the root dir */
1931 return 0; /* impossible to append something to the root */
1932 #endif
1934 if (cluster) {
1935 if (oldcluster)
1936 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
1937 else
1938 file->firstcluster = cluster;
1939 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
1941 else {
1942 #ifdef TEST_FAT
1943 if (fat_bpb->fsinfo.freecount>0)
1944 panicf("There is free space, but find_free_cluster() "
1945 "didn't find it!\n");
1946 #endif
1947 DEBUGF("next_write_cluster(): Disk full!\n");
1948 return 0;
1951 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
1952 if (sector<0)
1953 return 0;
1955 *newsector = sector;
1956 return cluster;
1959 static int transfer(IF_MV2(struct bpb* fat_bpb,)
1960 unsigned long start, long count, char* buf, bool write )
1962 #ifndef HAVE_MULTIVOLUME
1963 struct bpb* fat_bpb = &fat_bpbs[0];
1964 #endif
1965 int rc;
1967 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
1968 start+ fat_bpb->startsector, count, write?"write":"read");
1969 if (write) {
1970 unsigned long firstallowed;
1971 #ifdef HAVE_FAT16SUPPORT
1972 if (fat_bpb->is_fat16)
1973 firstallowed = fat_bpb->rootdirsector;
1974 else
1975 #endif
1976 firstallowed = fat_bpb->firstdatasector;
1978 if (start < firstallowed)
1979 panicf("Write %ld before data\n", firstallowed - start);
1980 if (start + count > fat_bpb->totalsectors)
1981 panicf("Write %ld after data\n",
1982 start + count - fat_bpb->totalsectors);
1983 rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
1984 start + fat_bpb->startsector, count, buf);
1986 else
1987 rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
1988 start + fat_bpb->startsector, count, buf);
1989 if (rc < 0) {
1990 DEBUGF( "transfer() - Couldn't %s sector %lx"
1991 " (error code %d)\n",
1992 write ? "write":"read", start, rc);
1993 return rc;
1995 return 0;
1999 long fat_readwrite( struct fat_file *file, long sectorcount,
2000 void* buf, bool write )
2002 #ifdef HAVE_MULTIVOLUME
2003 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2004 #else
2005 struct bpb* fat_bpb = &fat_bpbs[0];
2006 #endif
2007 long cluster = file->lastcluster;
2008 long sector = file->lastsector;
2009 long clusternum = file->clusternum;
2010 long numsec = file->sectornum;
2011 bool eof = file->eof;
2012 long first=0, last=0;
2013 long i;
2014 int rc;
2016 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2017 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2018 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2019 sector,numsec, eof?1:0);
2021 if ( eof && !write)
2022 return 0;
2024 /* find sequential sectors and write them all at once */
2025 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2026 numsec++;
2027 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2028 long oldcluster = cluster;
2029 if (write)
2030 cluster = next_write_cluster(file, cluster, &sector);
2031 else {
2032 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2033 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2036 clusternum++;
2037 numsec=1;
2039 if (!cluster) {
2040 eof = true;
2041 if ( write ) {
2042 /* remember last cluster, in case
2043 we want to append to the file */
2044 cluster = oldcluster;
2045 clusternum--;
2046 i = -1; /* Error code */
2047 break;
2050 else
2051 eof = false;
2053 else {
2054 if (sector)
2055 sector++;
2056 else {
2057 /* look up first sector of file */
2058 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2059 numsec=1;
2060 #ifdef HAVE_FAT16SUPPORT
2061 if (file->firstcluster < 0)
2062 { /* FAT16 root dir */
2063 sector += fat_bpb->rootdiroffset;
2064 numsec += fat_bpb->rootdiroffset;
2066 #endif
2070 if (!first)
2071 first = sector;
2073 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2074 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2075 long count = last - first + 1;
2076 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2077 if (rc < 0)
2078 return rc * 10 - 1;
2080 buf = (char *)buf + count * SECTOR_SIZE;
2081 first = sector;
2084 if ((i == sectorcount-1) && /* last sector requested */
2085 (!eof))
2087 long count = sector - first + 1;
2088 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2089 if (rc < 0)
2090 return rc * 10 - 2;
2093 last = sector;
2096 file->lastcluster = cluster;
2097 file->lastsector = sector;
2098 file->clusternum = clusternum;
2099 file->sectornum = numsec;
2100 file->eof = eof;
2102 /* if eof, don't report last block as read/written */
2103 if (eof)
2104 i--;
2106 DEBUGF("Sectors written: %ld\n", i);
2107 return i;
2110 int fat_seek(struct fat_file *file, unsigned long seeksector )
2112 #ifdef HAVE_MULTIVOLUME
2113 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2114 #else
2115 struct bpb* fat_bpb = &fat_bpbs[0];
2116 #endif
2117 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2118 long cluster = file->firstcluster;
2119 long i;
2121 #ifdef HAVE_FAT16SUPPORT
2122 if (cluster < 0) /* FAT16 root dir */
2123 seeksector += fat_bpb->rootdiroffset;
2124 #endif
2126 file->eof = false;
2127 if (seeksector) {
2128 /* we need to find the sector BEFORE the requested, since
2129 the file struct stores the last accessed sector */
2130 seeksector--;
2131 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2132 sectornum = seeksector % fat_bpb->bpb_secperclus;
2134 if (file->clusternum && clusternum >= file->clusternum)
2136 cluster = file->lastcluster;
2137 numclusters -= file->clusternum;
2140 for (i=0; i<numclusters; i++) {
2141 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2142 if (!cluster) {
2143 DEBUGF("Seeking beyond the end of the file! "
2144 "(sector %ld, cluster %ld)\n", seeksector, i);
2145 return -1;
2149 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2151 else {
2152 sectornum = -1;
2155 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2156 file->firstcluster, seeksector, cluster, sector, sectornum);
2158 file->lastcluster = cluster;
2159 file->lastsector = sector;
2160 file->clusternum = clusternum;
2161 file->sectornum = sectornum + 1;
2162 return 0;
2165 int fat_opendir(IF_MV2(int volume,)
2166 struct fat_dir *dir, unsigned long startcluster,
2167 const struct fat_dir *parent_dir)
2169 #ifdef HAVE_MULTIVOLUME
2170 struct bpb* fat_bpb = &fat_bpbs[volume];
2171 /* fixme: remove error check when done */
2172 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2174 LDEBUGF("fat_open() illegal volume %d\n", volume);
2175 return -1;
2177 #else
2178 struct bpb* fat_bpb = &fat_bpbs[0];
2179 #endif
2180 int rc;
2182 dir->entry = 0;
2183 dir->sector = 0;
2185 if (startcluster == 0)
2186 startcluster = fat_bpb->bpb_rootclus;
2188 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2189 if(rc)
2191 DEBUGF( "fat_opendir() - Couldn't open dir"
2192 " (error code %d)\n", rc);
2193 return rc * 10 - 1;
2196 return 0;
2199 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2200 * destination buffer (UTF-8 encoded). Copying is stopped when
2201 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2202 * Trailing \0 is also appended at the end of the UTF8-encoded
2203 * string.
2205 * utf16src utf16 (little endian) segment to copy
2206 * utf16count max number of the utf16-characters to copy
2207 * utf8dst where to write UTF8-encoded string to
2209 * returns the number of UTF-16 characters actually copied
2211 static int fat_copy_long_name_segment(unsigned char *utf16src,
2212 int utf16count, unsigned char *utf8dst) {
2213 int cnt = 0;
2214 while ((utf16count--) > 0) {
2215 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2216 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2217 break;
2219 utf8dst = utf8encode(ucs, utf8dst);
2220 utf16src += 2;
2221 cnt++;
2223 *utf8dst = 0;
2224 return cnt;
2227 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2229 bool done = false;
2230 int i;
2231 int rc;
2232 unsigned char firstbyte;
2233 /* Long file names are stored in special entries. Each entry holds
2234 up to 13 characters. Names can be max 255 chars (not bytes!) long
2235 hence max 20 entries are required. */
2236 int longarray[20];
2237 int longs=0;
2238 int sectoridx=0;
2239 unsigned char* cached_buf = dir->sectorcache[0];
2241 dir->entrycount = 0;
2243 while(!done)
2245 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2247 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2248 if (rc == 0) {
2249 /* eof */
2250 entry->name[0] = 0;
2251 break;
2253 if (rc < 0) {
2254 DEBUGF( "fat_getnext() - Couldn't read dir"
2255 " (error code %d)\n", rc);
2256 return rc * 10 - 1;
2258 dir->sector = dir->file.lastsector;
2261 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2262 i < DIR_ENTRIES_PER_SECTOR; i++)
2264 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2266 firstbyte = cached_buf[entrypos];
2267 dir->entry++;
2269 if (firstbyte == 0xe5) {
2270 /* free entry */
2271 sectoridx = 0;
2272 dir->entrycount = 0;
2273 continue;
2276 if (firstbyte == 0) {
2277 /* last entry */
2278 entry->name[0] = 0;
2279 dir->entrycount = 0;
2280 return 0;
2283 dir->entrycount++;
2285 /* longname entry? */
2286 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2287 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2288 longarray[longs++] = entrypos + sectoridx;
2290 else {
2291 if ( parse_direntry(entry,
2292 &cached_buf[entrypos]) ) {
2294 /* don't return volume id entry */
2295 if ( (entry->attr &
2296 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2297 == FAT_ATTR_VOLUME_ID)
2298 continue;
2300 /* replace shortname with longname? */
2301 if ( longs ) {
2302 int j;
2303 /* This should be enough to hold any name segment utf8-encoded */
2304 unsigned char shortname[13]; /* 8+3+dot+\0 */
2305 unsigned char longname_utf8segm[6*4 + 1]; /* Add 1 for trailing \0 */
2306 int longname_utf8len = 0;
2308 strcpy(shortname, entry->name); /* Temporarily store it */
2309 entry->name[0] = 0;
2311 /* iterate backwards through the dir entries */
2312 for (j=longs-1; j>=0; j--) {
2313 unsigned char* ptr = cached_buf;
2314 int index = longarray[j];
2315 /* current or cached sector? */
2316 if ( sectoridx >= SECTOR_SIZE ) {
2317 if ( sectoridx >= SECTOR_SIZE*2 ) {
2318 if ( ( index >= SECTOR_SIZE ) &&
2319 ( index < SECTOR_SIZE*2 ))
2320 ptr = dir->sectorcache[1];
2321 else
2322 ptr = dir->sectorcache[2];
2324 else {
2325 if ( index < SECTOR_SIZE )
2326 ptr = dir->sectorcache[1];
2329 index &= SECTOR_SIZE-1;
2332 /* Try to append each segment of the long name. Check if we'd
2333 exceed the buffer. Also check for FAT padding characters 0xFFFF. */
2334 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2335 longname_utf8segm) == 0) break;
2336 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2337 longname_utf8len += strlen(longname_utf8segm);
2338 if (longname_utf8len < FAT_FILENAME_BYTES)
2339 strcat(entry->name, longname_utf8segm);
2340 else
2341 break;
2343 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2344 longname_utf8segm) == 0) break;
2345 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2346 longname_utf8len += strlen(longname_utf8segm);
2347 if (longname_utf8len < FAT_FILENAME_BYTES)
2348 strcat(entry->name, longname_utf8segm);
2349 else
2350 break;
2352 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2353 longname_utf8segm) == 0) break;
2354 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2355 longname_utf8len += strlen(longname_utf8segm);
2356 if (longname_utf8len < FAT_FILENAME_BYTES)
2357 strcat(entry->name, longname_utf8segm);
2358 else
2359 break;
2362 /* Does the utf8-encoded name fit into the entry? */
2363 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2364 /* Take the short DOS name. Need to utf8-encode it since
2365 it may contain chars from the upper half of the OEM
2366 code page which wouldn't be a valid utf8. Beware: this
2367 file will be shown with strange glyphs in file browser
2368 since unicode 0x80 to 0x9F are control characters. */
2369 logf("SN-DOS: %s", shortname);
2370 unsigned char *utf8;
2371 utf8 = iso_decode(shortname, entry->name, -1, strlen(shortname));
2372 *utf8 = 0;
2373 logf("SN: %s", entry->name);
2374 } else {
2375 // logf("LN: %s", entry->name);
2376 // logf("LNLen: %d (%c)", longname_utf8len, entry->name[0]);
2379 done = true;
2380 sectoridx = 0;
2381 i++;
2382 break;
2387 /* save this sector, for longname use */
2388 if ( sectoridx )
2389 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2390 else
2391 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2392 sectoridx += SECTOR_SIZE;
2395 return 0;
2398 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2400 #ifndef HAVE_MULTIVOLUME
2401 const int volume = 0;
2402 #endif
2403 struct bpb* fat_bpb = &fat_bpbs[volume];
2404 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2407 #ifdef HAVE_MULTIVOLUME
2408 bool fat_ismounted(int volume)
2410 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2412 #endif