Add backdrop functions to the multiscreen api and add a enum backdrop_type parameter...
[kugel-rb.git] / firmware / drivers / fat.c
blobe319669e97ae5ec105f054cf360264cc67818134
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 */
1004 bool next_day = false;
1006 if (time)
1008 if (0 == *time)
1010 /* set to 00:15:00 */
1011 *time = (15 << 5);
1013 else
1015 unsigned short mins = (*time >> 5) & 0x003F;
1016 unsigned short hours = (*time >> 11) & 0x001F;
1017 if ((mins += 10) >= 60)
1019 mins = 0;
1020 hours++;
1022 if ((++hours) >= 24)
1024 hours = hours - 24;
1025 next_day = true;
1027 *time = (hours << 11) | (mins << 5);
1031 if (date)
1033 if (0 == *date)
1035 /* Macros to convert a 2-digit string to a decimal constant.
1036 (YEAR), MONTH and DAY are set by the date command, which outputs
1037 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1038 misinterpretation as an octal constant. */
1039 #define S100(x) 1 ## x
1040 #define C2DIG2DEC(x) (S100(x)-100)
1041 /* set to build date */
1042 *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
1043 | C2DIG2DEC(DAY);
1045 else
1047 unsigned short day = *date & 0x001F;
1048 unsigned short month = (*date >> 5) & 0x000F;
1049 unsigned short year = (*date >> 9) & 0x007F;
1050 if (next_day)
1052 /* do a very simple day increment - never go above 28 days */
1053 if (++day > 28)
1055 day = 1;
1056 if (++month > 12)
1058 month = 1;
1059 year++;
1062 *date = (year << 9) | (month << 5) | day;
1066 if (tenth)
1067 *tenth = 0;
1068 #endif /* CONFIG_RTC */
1071 static int write_long_name(struct fat_file* file,
1072 unsigned int firstentry,
1073 unsigned int numentries,
1074 const unsigned char* name,
1075 const unsigned char* shortname,
1076 bool is_directory)
1078 unsigned char buf[SECTOR_SIZE];
1079 unsigned char* entry;
1080 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1081 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1082 unsigned char chksum = 0;
1083 unsigned int i, j=0;
1084 unsigned int nameidx=0, namelen = utf8length(name);
1085 int rc;
1086 unsigned short name_utf16[namelen + 1];
1088 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1089 file->firstcluster, firstentry, numentries, name);
1091 rc = fat_seek(file, sector);
1092 if (rc<0)
1093 return rc * 10 - 1;
1095 rc = fat_readwrite(file, 1, buf, false);
1096 if (rc<1)
1097 return rc * 10 - 2;
1099 /* calculate shortname checksum */
1100 for (i=11; i>0; i--)
1101 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1103 /* calc position of last name segment */
1104 if ( namelen > NAME_BYTES_PER_ENTRY )
1105 for (nameidx=0;
1106 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1107 nameidx += NAME_BYTES_PER_ENTRY);
1109 /* we need to convert the name first */
1110 /* since it is written in reverse order */
1111 for (i = 0; i <= namelen; i++)
1112 name = utf8decode(name, &name_utf16[i]);
1114 for (i=0; i < numentries; i++) {
1115 /* new sector? */
1116 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1117 /* update current sector */
1118 rc = fat_seek(file, sector);
1119 if (rc<0)
1120 return rc * 10 - 3;
1122 rc = fat_readwrite(file, 1, buf, true);
1123 if (rc<1)
1124 return rc * 10 - 4;
1126 /* read next sector */
1127 rc = fat_readwrite(file, 1, buf, false);
1128 if (rc<0) {
1129 LDEBUGF("Failed writing new sector: %d\n",rc);
1130 return rc * 10 - 5;
1132 if (rc==0)
1133 /* end of dir */
1134 memset(buf, 0, sizeof buf);
1136 sector++;
1137 idx = 0;
1140 entry = buf + idx * DIR_ENTRY_SIZE;
1142 /* verify this entry is free */
1143 if (entry[0] && entry[0] != 0xe5 )
1144 panicf("Dir entry %d in sector %x is not free! "
1145 "%02x %02x %02x %02x",
1146 idx, sector,
1147 entry[0], entry[1], entry[2], entry[3]);
1149 memset(entry, 0, DIR_ENTRY_SIZE);
1150 if ( i+1 < numentries ) {
1151 /* longname entry */
1152 unsigned int k, l = nameidx;
1154 entry[FATLONG_ORDER] = numentries-i-1;
1155 if (i==0) {
1156 /* mark this as last long entry */
1157 entry[FATLONG_ORDER] |= 0x40;
1159 /* pad name with 0xffff */
1160 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1161 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1162 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1164 /* set name */
1165 for (k=0; k<5 && l <= namelen; k++) {
1166 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1167 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1169 for (k=0; k<6 && l <= namelen; k++) {
1170 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1171 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1173 for (k=0; k<2 && l <= namelen; k++) {
1174 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1175 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1178 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1179 entry[FATDIR_FSTCLUSLO] = 0;
1180 entry[FATLONG_TYPE] = 0;
1181 entry[FATLONG_CHKSUM] = chksum;
1182 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
1184 else {
1185 /* shortname entry */
1186 unsigned short date=0, time=0, tenth=0;
1187 LDEBUGF("Shortname entry: %s\n", shortname);
1188 memcpy(entry + FATDIR_NAME, shortname, 11);
1189 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1190 entry[FATDIR_NTRES] = 0;
1192 fat_time(&date, &time, &tenth);
1193 entry[FATDIR_CRTTIMETENTH] = tenth;
1194 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1195 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1196 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1197 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1198 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1200 idx++;
1201 nameidx -= NAME_BYTES_PER_ENTRY;
1204 /* update last sector */
1205 rc = fat_seek(file, sector);
1206 if (rc<0)
1207 return rc * 10 - 6;
1209 rc = fat_readwrite(file, 1, buf, true);
1210 if (rc<1)
1211 return rc * 10 - 7;
1213 return 0;
1216 static int fat_checkname(const unsigned char* newname)
1218 static const char invalid_chars[] = "\"*/:<>?\\|";
1219 int len = strlen(newname);
1220 /* More sanity checks are probably needed */
1221 if (len > 255 || newname[len - 1] == '.')
1223 return -1;
1225 while (*newname)
1227 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1228 return -1;
1229 newname++;
1231 /* check trailing space(s) */
1232 if(*(--newname) == ' ')
1233 return -1;
1235 return 0;
1238 static int add_dir_entry(struct fat_dir* dir,
1239 struct fat_file* file,
1240 const char* name,
1241 bool is_directory,
1242 bool dotdir)
1244 #ifdef HAVE_MULTIVOLUME
1245 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1246 #else
1247 struct bpb* fat_bpb = &fat_bpbs[0];
1248 #endif
1249 unsigned char buf[SECTOR_SIZE];
1250 unsigned char shortname[12];
1251 int rc;
1252 unsigned int sector;
1253 bool done = false;
1254 int entries_needed, entries_found = 0;
1255 int firstentry;
1257 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1258 name, file->firstcluster);
1260 /* Don't check dotdirs name for validity */
1261 if (dotdir == false) {
1262 rc = fat_checkname(name);
1263 if (rc < 0) {
1264 /* filename is invalid */
1265 return rc * 10 - 1;
1269 #ifdef HAVE_MULTIVOLUME
1270 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1271 #endif
1273 /* The "." and ".." directory entries must not be long names */
1274 if(dotdir) {
1275 int i;
1276 strlcpy(shortname, name, 12);
1277 for(i = strlen(shortname); i < 12; i++)
1278 shortname[i] = ' ';
1280 entries_needed = 1;
1281 } else {
1282 create_dos_name(name, shortname);
1284 /* one dir entry needed for every 13 bytes of filename,
1285 plus one entry for the short name */
1286 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1287 / NAME_BYTES_PER_ENTRY + 1;
1290 restart:
1291 firstentry = -1;
1293 rc = fat_seek(&dir->file, 0);
1294 if (rc < 0)
1295 return rc * 10 - 2;
1297 /* step 1: search for free entries and check for duplicate shortname */
1298 for (sector = 0; !done; sector++)
1300 unsigned int i;
1302 rc = fat_readwrite(&dir->file, 1, buf, false);
1303 if (rc < 0) {
1304 DEBUGF( "add_dir_entry() - Couldn't read dir"
1305 " (error code %d)\n", rc);
1306 return rc * 10 - 3;
1309 if (rc == 0) { /* current end of dir reached */
1310 LDEBUGF("End of dir on cluster boundary\n");
1311 break;
1314 /* look for free slots */
1315 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1317 switch (buf[i * DIR_ENTRY_SIZE]) {
1318 case 0:
1319 entries_found += DIR_ENTRIES_PER_SECTOR - i;
1320 LDEBUGF("Found end of dir %d\n",
1321 sector * DIR_ENTRIES_PER_SECTOR + i);
1322 i = DIR_ENTRIES_PER_SECTOR - 1;
1323 done = true;
1324 break;
1326 case 0xe5:
1327 entries_found++;
1328 LDEBUGF("Found free entry %d (%d/%d)\n",
1329 sector * DIR_ENTRIES_PER_SECTOR + i,
1330 entries_found, entries_needed);
1331 break;
1333 default:
1334 entries_found = 0;
1336 /* check that our intended shortname doesn't already exist */
1337 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1338 /* shortname exists already, make a new one */
1339 randomize_dos_name(shortname);
1340 LDEBUGF("Duplicate shortname, changing to %s\n",
1341 shortname);
1343 /* name has changed, we need to restart search */
1344 goto restart;
1346 break;
1348 if (firstentry < 0 && (entries_found >= entries_needed))
1349 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1350 - entries_found;
1354 /* step 2: extend the dir if necessary */
1355 if (firstentry < 0)
1357 LDEBUGF("Adding new sector(s) to dir\n");
1358 rc = fat_seek(&dir->file, sector);
1359 if (rc < 0)
1360 return rc * 10 - 4;
1361 memset(buf, 0, sizeof buf);
1363 /* we must clear whole clusters */
1364 for (; (entries_found < entries_needed) ||
1365 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1367 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1368 return -5; /* dir too large -- FAT specification */
1370 rc = fat_readwrite(&dir->file, 1, buf, true);
1371 if (rc < 1) /* No more room or something went wrong */
1372 return rc * 10 - 6;
1374 entries_found += DIR_ENTRIES_PER_SECTOR;
1377 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1380 /* step 3: add entry */
1381 sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1382 LDEBUGF("Adding longname to entry %d in sector %d\n",
1383 firstentry, sector);
1385 rc = write_long_name(&dir->file, firstentry,
1386 entries_needed, name, shortname, is_directory);
1387 if (rc < 0)
1388 return rc * 10 - 7;
1390 /* remember where the shortname dir entry is located */
1391 file->direntry = firstentry + entries_needed - 1;
1392 file->direntries = entries_needed;
1393 file->dircluster = dir->file.firstcluster;
1394 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1395 file->direntry, file->direntries);
1397 return 0;
1400 static unsigned char char2dos(unsigned char c, int* randomize)
1402 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1404 if (c <= 0x20)
1405 c = 0; /* Illegal char, remove */
1406 else if (strchr(invalid_chars, c) != NULL)
1408 /* Illegal char, replace */
1409 c = '_';
1410 *randomize = 1; /* as per FAT spec */
1412 else
1413 c = toupper(c);
1415 return c;
1418 static void create_dos_name(const unsigned char *name, unsigned char *newname)
1420 int i;
1421 unsigned char *ext;
1422 int randomize = 0;
1424 /* Find extension part */
1425 ext = strrchr(name, '.');
1426 if (ext == name) /* handle .dotnames */
1427 ext = NULL;
1429 /* needs to randomize? */
1430 if((ext && (strlen(ext) > 4)) ||
1431 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1432 randomize = 1;
1434 /* Name part */
1435 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1437 unsigned char c = char2dos(*name, &randomize);
1438 if (c)
1439 newname[i++] = c;
1442 /* Pad both name and extension */
1443 while (i < 11)
1444 newname[i++] = ' ';
1446 if (newname[0] == 0xe5) /* Special kanji character */
1447 newname[0] = 0x05;
1449 if (ext)
1450 { /* Extension part */
1451 ext++;
1452 for (i = 8; *ext && (i < 11); ext++)
1454 unsigned char c = char2dos(*ext, &randomize);
1455 if (c)
1456 newname[i++] = c;
1460 if(randomize)
1461 randomize_dos_name(newname);
1464 static void randomize_dos_name(unsigned char *name)
1466 unsigned char* tilde = NULL; /* ~ location */
1467 unsigned char* lastpt = NULL; /* last point of filename */
1468 unsigned char* nameptr = name; /* working copy of name pointer */
1469 unsigned char num[9]; /* holds number as string */
1470 int i = 0;
1471 int cnt = 1;
1472 int numlen;
1473 int offset;
1475 while(i++ < 8)
1477 /* hunt for ~ and where to put it */
1478 if((!tilde) && (*nameptr == '~'))
1479 tilde = nameptr;
1480 if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1481 lastpt = nameptr;
1482 nameptr++;
1484 if(tilde)
1486 /* extract current count and increment */
1487 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1488 num[7-(unsigned int)(tilde-name)] = 0;
1489 cnt = atoi(num) + 1;
1491 cnt %= 10000000; /* protection */
1492 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1493 numlen = strlen(num); /* required space */
1494 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1495 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1497 memcpy(&name[offset], num, numlen);
1499 /* in special case of counter overflow: pad with spaces */
1500 for(offset = offset+numlen; offset < 8; offset++)
1501 name[offset] = ' ';
1504 static int update_short_entry( struct fat_file* file, long size, int attr )
1506 unsigned char buf[SECTOR_SIZE];
1507 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1508 unsigned char* entry =
1509 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1510 unsigned long* sizeptr;
1511 unsigned short* clusptr;
1512 struct fat_file dir;
1513 int rc;
1515 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1516 file->firstcluster, file->direntry, size);
1518 /* create a temporary file handle for the dir holding this file */
1519 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1520 if (rc < 0)
1521 return rc * 10 - 1;
1523 rc = fat_seek( &dir, sector );
1524 if (rc<0)
1525 return rc * 10 - 2;
1527 rc = fat_readwrite(&dir, 1, buf, false);
1528 if (rc < 1)
1529 return rc * 10 - 3;
1531 if (!entry[0] || entry[0] == 0xe5)
1532 panicf("Updating size on empty dir entry %d\n", file->direntry);
1534 entry[FATDIR_ATTR] = attr & 0xFF;
1536 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1537 *clusptr = htole16(file->firstcluster >> 16);
1539 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1540 *clusptr = htole16(file->firstcluster & 0xffff);
1542 sizeptr = (long*)(entry + FATDIR_FILESIZE);
1543 *sizeptr = htole32(size);
1546 #if CONFIG_RTC
1547 unsigned short time = 0;
1548 unsigned short date = 0;
1549 #else
1550 /* get old time to increment from */
1551 unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1552 unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1553 #endif
1554 fat_time(&date, &time, NULL);
1555 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1556 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1557 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1560 rc = fat_seek( &dir, sector );
1561 if (rc < 0)
1562 return rc * 10 - 4;
1564 rc = fat_readwrite(&dir, 1, buf, true);
1565 if (rc < 1)
1566 return rc * 10 - 5;
1568 return 0;
1571 static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1573 int i=0,j=0;
1574 unsigned char c;
1575 bool lowercase;
1577 memset(de, 0, sizeof(struct fat_direntry));
1578 de->attr = buf[FATDIR_ATTR];
1579 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1580 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1581 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1582 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1583 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1584 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1585 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1586 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1587 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1588 (the result of the shift is always considered signed) */
1590 /* fix the name */
1591 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1592 c = buf[FATDIR_NAME];
1593 if (c == 0x05) /* special kanji char */
1594 c = 0xe5;
1595 i = 0;
1596 while (c != ' ') {
1597 de->name[j++] = lowercase ? tolower(c) : c;
1598 if (++i >= 8)
1599 break;
1600 c = buf[FATDIR_NAME+i];
1602 if (buf[FATDIR_NAME+8] != ' ') {
1603 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1604 de->name[j++] = '.';
1605 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1606 de->name[j++] = lowercase ? tolower(c) : c;
1608 return 1;
1611 int fat_open(IF_MV2(int volume,)
1612 long startcluster,
1613 struct fat_file *file,
1614 const struct fat_dir* dir)
1616 file->firstcluster = startcluster;
1617 file->lastcluster = startcluster;
1618 file->lastsector = 0;
1619 file->clusternum = 0;
1620 file->sectornum = 0;
1621 file->eof = false;
1622 #ifdef HAVE_MULTIVOLUME
1623 file->volume = volume;
1624 /* fixme: remove error check when done */
1625 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1627 LDEBUGF("fat_open() illegal volume %d\n", volume);
1628 return -1;
1630 #endif
1632 /* remember where the file's dir entry is located */
1633 if ( dir ) {
1634 file->direntry = dir->entry - 1;
1635 file->direntries = dir->entrycount;
1636 file->dircluster = dir->file.firstcluster;
1638 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
1639 return 0;
1642 int fat_create_file(const char* name,
1643 struct fat_file* file,
1644 struct fat_dir* dir)
1646 int rc;
1648 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
1649 rc = add_dir_entry(dir, file, name, false, false);
1650 if (!rc) {
1651 file->firstcluster = 0;
1652 file->lastcluster = 0;
1653 file->lastsector = 0;
1654 file->clusternum = 0;
1655 file->sectornum = 0;
1656 file->eof = false;
1659 return rc;
1662 int fat_create_dir(const char* name,
1663 struct fat_dir* newdir,
1664 struct fat_dir* dir)
1666 #ifdef HAVE_MULTIVOLUME
1667 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1668 #else
1669 struct bpb* fat_bpb = &fat_bpbs[0];
1670 #endif
1671 unsigned char buf[SECTOR_SIZE];
1672 int i;
1673 long sector;
1674 int rc;
1675 struct fat_file dummyfile;
1677 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
1679 memset(newdir, 0, sizeof(struct fat_dir));
1680 memset(&dummyfile, 0, sizeof(struct fat_file));
1682 /* First, add the entry in the parent directory */
1683 rc = add_dir_entry(dir, &newdir->file, name, true, false);
1684 if (rc < 0)
1685 return rc * 10 - 1;
1687 /* Allocate a new cluster for the directory */
1688 newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1689 fat_bpb->fsinfo.nextfree);
1690 if(newdir->file.firstcluster == 0)
1691 return -1;
1693 update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1695 /* Clear the entire cluster */
1696 memset(buf, 0, sizeof buf);
1697 sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1698 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1699 rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1700 if (rc < 0)
1701 return rc * 10 - 2;
1704 /* Then add the "." entry */
1705 rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1706 if (rc < 0)
1707 return rc * 10 - 3;
1708 dummyfile.firstcluster = newdir->file.firstcluster;
1709 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1711 /* and the ".." entry */
1712 rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1713 if (rc < 0)
1714 return rc * 10 - 4;
1716 /* The root cluster is cluster 0 in the ".." entry */
1717 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1718 dummyfile.firstcluster = 0;
1719 else
1720 dummyfile.firstcluster = dir->file.firstcluster;
1721 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1723 /* Set the firstcluster field in the direntry */
1724 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1726 rc = flush_fat(IF_MV(fat_bpb));
1727 if (rc < 0)
1728 return rc * 10 - 5;
1730 return rc;
1733 int fat_truncate(const struct fat_file *file)
1735 /* truncate trailing clusters */
1736 long next;
1737 long last = file->lastcluster;
1738 #ifdef HAVE_MULTIVOLUME
1739 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1740 #endif
1742 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last);
1744 for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1745 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1746 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1748 if (file->lastcluster)
1749 update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1751 return 0;
1754 int fat_closewrite(struct fat_file *file, long size, int attr)
1756 int rc;
1757 #ifdef HAVE_MULTIVOLUME
1758 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1759 #endif
1760 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1762 if (!size) {
1763 /* empty file */
1764 if ( file->firstcluster ) {
1765 update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1766 file->firstcluster = 0;
1770 if (file->dircluster) {
1771 rc = update_short_entry(file, size, attr);
1772 if (rc < 0)
1773 return rc * 10 - 1;
1776 flush_fat(IF_MV(fat_bpb));
1778 #ifdef TEST_FAT
1779 if ( file->firstcluster ) {
1780 /* debug */
1781 #ifdef HAVE_MULTIVOLUME
1782 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1783 #else
1784 struct bpb* fat_bpb = &fat_bpbs[0];
1785 #endif
1786 long count = 0;
1787 long len;
1788 long next;
1789 for ( next = file->firstcluster; next;
1790 next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1791 LDEBUGF("cluster %ld: %lx\n", count, next);
1792 count++;
1794 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1795 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1796 count, len, size );
1797 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1798 panicf("Cluster chain is too long\n");
1799 if ( len < size )
1800 panicf("Cluster chain is too short\n");
1802 #endif
1804 return 0;
1807 static int free_direntries(struct fat_file* file)
1809 unsigned char buf[SECTOR_SIZE];
1810 struct fat_file dir;
1811 int numentries = file->direntries;
1812 unsigned int entry = file->direntry - numentries + 1;
1813 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1814 int i;
1815 int rc;
1817 /* create a temporary file handle for the dir holding this file */
1818 rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1819 if (rc < 0)
1820 return rc * 10 - 1;
1822 rc = fat_seek( &dir, sector );
1823 if (rc < 0)
1824 return rc * 10 - 2;
1826 rc = fat_readwrite(&dir, 1, buf, false);
1827 if (rc < 1)
1828 return rc * 10 - 3;
1830 for (i=0; i < numentries; i++) {
1831 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1832 entry, i+1, numentries);
1833 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1834 entry++;
1836 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1837 /* flush this sector */
1838 rc = fat_seek(&dir, sector);
1839 if (rc < 0)
1840 return rc * 10 - 4;
1842 rc = fat_readwrite(&dir, 1, buf, true);
1843 if (rc < 1)
1844 return rc * 10 - 5;
1846 if ( i+1 < numentries ) {
1847 /* read next sector */
1848 rc = fat_readwrite(&dir, 1, buf, false);
1849 if (rc < 1)
1850 return rc * 10 - 6;
1852 sector++;
1856 if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1857 /* flush this sector */
1858 rc = fat_seek(&dir, sector);
1859 if (rc < 0)
1860 return rc * 10 - 7;
1862 rc = fat_readwrite(&dir, 1, buf, true);
1863 if (rc < 1)
1864 return rc * 10 - 8;
1867 return 0;
1870 int fat_remove(struct fat_file* file)
1872 long next, last = file->firstcluster;
1873 int rc;
1874 #ifdef HAVE_MULTIVOLUME
1875 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1876 #endif
1878 LDEBUGF("fat_remove(%lx)\n",last);
1880 while ( last ) {
1881 next = get_next_cluster(IF_MV2(fat_bpb,) last);
1882 update_fat_entry(IF_MV2(fat_bpb,) last,0);
1883 last = next;
1886 if ( file->dircluster ) {
1887 rc = free_direntries(file);
1888 if (rc < 0)
1889 return rc * 10 - 1;
1892 file->firstcluster = 0;
1893 file->dircluster = 0;
1895 rc = flush_fat(IF_MV(fat_bpb));
1896 if (rc < 0)
1897 return rc * 10 - 2;
1899 return 0;
1902 int fat_rename(struct fat_file* file,
1903 struct fat_dir* dir,
1904 const unsigned char* newname,
1905 long size,
1906 int attr)
1908 int rc;
1909 struct fat_dir olddir;
1910 struct fat_file newfile = *file;
1911 unsigned char buf[SECTOR_SIZE];
1912 unsigned char* entry = NULL;
1913 unsigned short* clusptr = NULL;
1914 unsigned int parentcluster;
1915 #ifdef HAVE_MULTIVOLUME
1916 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1918 if (file->volume != dir->file.volume) {
1919 DEBUGF("No rename across volumes!\n");
1920 return -1;
1922 #else
1923 struct bpb* fat_bpb = &fat_bpbs[0];
1924 #endif
1926 if ( !file->dircluster ) {
1927 DEBUGF("File has no dir cluster!\n");
1928 return -2;
1931 /* create a temporary file handle */
1932 rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1933 if (rc < 0)
1934 return rc * 10 - 1;
1936 /* create new name */
1937 rc = add_dir_entry(dir, &newfile, newname, false, false);
1938 if (rc < 0)
1939 return rc * 10 - 2;
1941 /* write size and cluster link */
1942 rc = update_short_entry(&newfile, size, attr);
1943 if (rc < 0)
1944 return rc * 10 - 3;
1946 /* remove old name */
1947 rc = free_direntries(file);
1948 if (rc < 0)
1949 return rc * 10 - 4;
1951 rc = flush_fat(IF_MV(fat_bpb));
1952 if (rc < 0)
1953 return rc * 10 - 5;
1955 /* if renaming a directory, update the .. entry to make sure
1956 it points to its parent directory (we don't check if it was a move) */
1957 if(FAT_ATTR_DIRECTORY == attr) {
1958 /* open the dir that was renamed, we re-use the olddir struct */
1959 rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1960 NULL);
1961 if (rc < 0)
1962 return rc * 10 - 6;
1964 /* get the first sector of the dir */
1965 rc = fat_seek(&olddir.file, 0);
1966 if (rc < 0)
1967 return rc * 10 - 7;
1969 rc = fat_readwrite(&olddir.file, 1, buf, false);
1970 if (rc < 0)
1971 return rc * 10 - 8;
1973 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1974 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1975 parentcluster = 0;
1976 else
1977 parentcluster = dir->file.firstcluster;
1979 entry = buf + DIR_ENTRY_SIZE;
1980 if(strncmp(".. ", entry, 11))
1982 /* .. entry must be second entry according to FAT spec (p.29) */
1983 DEBUGF("Second dir entry is not double-dot!\n");
1984 return rc * 10 - 9;
1986 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1987 *clusptr = htole16(parentcluster >> 16);
1989 clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1990 *clusptr = htole16(parentcluster & 0xffff);
1992 /* write back this sector */
1993 rc = fat_seek(&olddir.file, 0);
1994 if (rc < 0)
1995 return rc * 10 - 7;
1997 rc = fat_readwrite(&olddir.file, 1, buf, true);
1998 if (rc < 1)
1999 return rc * 10 - 8;
2002 return 0;
2005 static long next_write_cluster(struct fat_file* file,
2006 long oldcluster,
2007 long* newsector)
2009 #ifdef HAVE_MULTIVOLUME
2010 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2011 #else
2012 struct bpb* fat_bpb = &fat_bpbs[0];
2013 #endif
2014 long cluster = 0;
2015 long sector;
2017 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2019 if (oldcluster)
2020 cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2022 if (!cluster) {
2023 if (oldcluster > 0)
2024 cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2025 else if (oldcluster == 0)
2026 cluster = find_free_cluster(IF_MV2(fat_bpb,)
2027 fat_bpb->fsinfo.nextfree);
2028 #ifdef HAVE_FAT16SUPPORT
2029 else /* negative, pseudo-cluster of the root dir */
2030 return 0; /* impossible to append something to the root */
2031 #endif
2033 if (cluster) {
2034 if (oldcluster)
2035 update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2036 else
2037 file->firstcluster = cluster;
2038 update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2040 else {
2041 #ifdef TEST_FAT
2042 if (fat_bpb->fsinfo.freecount>0)
2043 panicf("There is free space, but find_free_cluster() "
2044 "didn't find it!\n");
2045 #endif
2046 DEBUGF("next_write_cluster(): Disk full!\n");
2047 return 0;
2050 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2051 if (sector<0)
2052 return 0;
2054 *newsector = sector;
2055 return cluster;
2058 static int transfer(IF_MV2(struct bpb* fat_bpb,)
2059 unsigned long start, long count, char* buf, bool write )
2061 #ifndef HAVE_MULTIVOLUME
2062 struct bpb* fat_bpb = &fat_bpbs[0];
2063 #endif
2064 int rc;
2066 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2067 start+ fat_bpb->startsector, count, write?"write":"read");
2068 if (write) {
2069 unsigned long firstallowed;
2070 #ifdef HAVE_FAT16SUPPORT
2071 if (fat_bpb->is_fat16)
2072 firstallowed = fat_bpb->rootdirsector;
2073 else
2074 #endif
2075 firstallowed = fat_bpb->firstdatasector;
2077 if (start < firstallowed)
2078 panicf("Write %ld before data\n", firstallowed - start);
2079 if (start + count > fat_bpb->totalsectors)
2080 panicf("Write %ld after data\n",
2081 start + count - fat_bpb->totalsectors);
2082 rc = storage_write_sectors(fat_bpb->drive,
2083 start + fat_bpb->startsector, count, buf);
2085 else
2086 rc = storage_read_sectors(fat_bpb->drive,
2087 start + fat_bpb->startsector, count, buf);
2088 if (rc < 0) {
2089 DEBUGF( "transfer() - Couldn't %s sector %lx"
2090 " (error code %d)\n",
2091 write ? "write":"read", start, rc);
2092 return rc;
2094 return 0;
2098 long fat_readwrite( struct fat_file *file, long sectorcount,
2099 void* buf, bool write )
2101 #ifdef HAVE_MULTIVOLUME
2102 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2103 #else
2104 struct bpb* fat_bpb = &fat_bpbs[0];
2105 #endif
2106 long cluster = file->lastcluster;
2107 long sector = file->lastsector;
2108 long clusternum = file->clusternum;
2109 long numsec = file->sectornum;
2110 bool eof = file->eof;
2111 long first=0, last=0;
2112 long i;
2113 int rc;
2115 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2116 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2117 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2118 sector,numsec, eof?1:0);
2120 if ( eof && !write)
2121 return 0;
2123 /* find sequential sectors and write them all at once */
2124 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2125 numsec++;
2126 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2127 long oldcluster = cluster;
2128 long oldsector = sector;
2129 long oldnumsec = numsec;
2130 if (write)
2131 cluster = next_write_cluster(file, cluster, &sector);
2132 else {
2133 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2134 sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2137 clusternum++;
2138 numsec=1;
2140 if (!cluster) {
2141 eof = true;
2142 if ( write ) {
2143 /* remember last cluster, in case
2144 we want to append to the file */
2145 sector = oldsector;
2146 cluster = oldcluster;
2147 numsec = oldnumsec;
2148 clusternum--;
2149 i = -1; /* Error code */
2150 break;
2153 else
2154 eof = false;
2156 else {
2157 if (sector)
2158 sector++;
2159 else {
2160 /* look up first sector of file */
2161 sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2162 numsec=1;
2163 #ifdef HAVE_FAT16SUPPORT
2164 if (file->firstcluster < 0)
2165 { /* FAT16 root dir */
2166 sector += fat_bpb->rootdiroffset;
2167 numsec += fat_bpb->rootdiroffset;
2169 #endif
2173 if (!first)
2174 first = sector;
2176 if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2177 (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2178 long count = last - first + 1;
2179 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2180 if (rc < 0)
2181 return rc * 10 - 1;
2183 buf = (char *)buf + count * SECTOR_SIZE;
2184 first = sector;
2187 if ((i == sectorcount-1) && /* last sector requested */
2188 (!eof))
2190 long count = sector - first + 1;
2191 rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2192 if (rc < 0)
2193 return rc * 10 - 2;
2196 last = sector;
2199 file->lastcluster = cluster;
2200 file->lastsector = sector;
2201 file->clusternum = clusternum;
2202 file->sectornum = numsec;
2203 file->eof = eof;
2205 /* if eof, don't report last block as read/written */
2206 if (eof)
2207 i--;
2209 DEBUGF("Sectors written: %ld\n", i);
2210 return i;
2213 int fat_seek(struct fat_file *file, unsigned long seeksector )
2215 #ifdef HAVE_MULTIVOLUME
2216 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2217 #else
2218 struct bpb* fat_bpb = &fat_bpbs[0];
2219 #endif
2220 long clusternum=0, numclusters=0, sectornum=0, sector=0;
2221 long cluster = file->firstcluster;
2222 long i;
2224 #ifdef HAVE_FAT16SUPPORT
2225 if (cluster < 0) /* FAT16 root dir */
2226 seeksector += fat_bpb->rootdiroffset;
2227 #endif
2229 file->eof = false;
2230 if (seeksector) {
2231 /* we need to find the sector BEFORE the requested, since
2232 the file struct stores the last accessed sector */
2233 seeksector--;
2234 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2235 sectornum = seeksector % fat_bpb->bpb_secperclus;
2237 if (file->clusternum && clusternum >= file->clusternum)
2239 cluster = file->lastcluster;
2240 numclusters -= file->clusternum;
2243 for (i=0; i<numclusters; i++) {
2244 cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2245 if (!cluster) {
2246 DEBUGF("Seeking beyond the end of the file! "
2247 "(sector %ld, cluster %ld)\n", seeksector, i);
2248 return -1;
2252 sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2254 else {
2255 sectornum = -1;
2258 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2259 file->firstcluster, seeksector, cluster, sector, sectornum);
2261 file->lastcluster = cluster;
2262 file->lastsector = sector;
2263 file->clusternum = clusternum;
2264 file->sectornum = sectornum + 1;
2265 return 0;
2268 int fat_opendir(IF_MV2(int volume,)
2269 struct fat_dir *dir, unsigned long startcluster,
2270 const struct fat_dir *parent_dir)
2272 #ifdef HAVE_MULTIVOLUME
2273 struct bpb* fat_bpb = &fat_bpbs[volume];
2274 /* fixme: remove error check when done */
2275 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2277 LDEBUGF("fat_open() illegal volume %d\n", volume);
2278 return -1;
2280 #else
2281 struct bpb* fat_bpb = &fat_bpbs[0];
2282 #endif
2283 int rc;
2285 dir->entry = 0;
2286 dir->sector = 0;
2288 if (startcluster == 0)
2289 startcluster = fat_bpb->bpb_rootclus;
2291 rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2292 if(rc)
2294 DEBUGF( "fat_opendir() - Couldn't open dir"
2295 " (error code %d)\n", rc);
2296 return rc * 10 - 1;
2299 return 0;
2302 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2303 * destination buffer (UTF-8 encoded). Copying is stopped when
2304 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2305 * Trailing \0 is also appended at the end of the UTF8-encoded
2306 * string.
2308 * utf16src utf16 (little endian) segment to copy
2309 * utf16count max number of the utf16-characters to copy
2310 * utf8dst where to write UTF8-encoded string to
2312 * returns the number of UTF-16 characters actually copied
2314 static int fat_copy_long_name_segment(unsigned char *utf16src,
2315 int utf16count, unsigned char *utf8dst) {
2316 int cnt = 0;
2317 while ((utf16count--) > 0) {
2318 unsigned short ucs = utf16src[0] | (utf16src[1] << 8);
2319 if ((ucs == 0) || (ucs == FAT_LONGNAME_PAD_UCS)) {
2320 break;
2322 utf8dst = utf8encode(ucs, utf8dst);
2323 utf16src += 2;
2324 cnt++;
2326 *utf8dst = 0;
2327 return cnt;
2330 int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2332 bool done = false;
2333 int i;
2334 int rc;
2335 unsigned char firstbyte;
2336 /* Long file names are stored in special entries. Each entry holds
2337 up to 13 characters. Names can be max 255 chars (not bytes!) long
2338 hence max 20 entries are required. */
2339 int longarray[20];
2340 int longs=0;
2341 int sectoridx=0;
2342 unsigned char* cached_buf = dir->sectorcache[0];
2344 dir->entrycount = 0;
2346 while(!done)
2348 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2350 rc = fat_readwrite(&dir->file, 1, cached_buf, false);
2351 if (rc == 0) {
2352 /* eof */
2353 entry->name[0] = 0;
2354 break;
2356 if (rc < 0) {
2357 DEBUGF( "fat_getnext() - Couldn't read dir"
2358 " (error code %d)\n", rc);
2359 return rc * 10 - 1;
2361 dir->sector = dir->file.lastsector;
2364 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2365 i < DIR_ENTRIES_PER_SECTOR; i++)
2367 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2369 firstbyte = cached_buf[entrypos];
2370 dir->entry++;
2372 if (firstbyte == 0xe5) {
2373 /* free entry */
2374 sectoridx = 0;
2375 dir->entrycount = 0;
2376 continue;
2379 if (firstbyte == 0) {
2380 /* last entry */
2381 entry->name[0] = 0;
2382 dir->entrycount = 0;
2383 return 0;
2386 dir->entrycount++;
2388 /* longname entry? */
2389 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
2390 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2391 longarray[longs++] = entrypos + sectoridx;
2393 else {
2394 if ( parse_direntry(entry,
2395 &cached_buf[entrypos]) ) {
2397 /* don't return volume id entry */
2398 if ( (entry->attr &
2399 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2400 == FAT_ATTR_VOLUME_ID)
2401 continue;
2403 /* replace shortname with longname? */
2404 if ( longs ) {
2405 int j;
2406 /* This should be enough to hold any name segment
2407 utf8-encoded */
2408 unsigned char shortname[13]; /* 8+3+dot+\0 */
2409 /* Add 1 for trailing \0 */
2410 unsigned char longname_utf8segm[6*4 + 1];
2411 int longname_utf8len = 0;
2412 /* Temporarily store it */
2413 strcpy(shortname, entry->name);
2414 entry->name[0] = 0;
2416 /* iterate backwards through the dir entries */
2417 for (j=longs-1; j>=0; j--) {
2418 unsigned char* ptr = cached_buf;
2419 int index = longarray[j];
2420 /* current or cached sector? */
2421 if ( sectoridx >= SECTOR_SIZE ) {
2422 if ( sectoridx >= SECTOR_SIZE*2 ) {
2423 if ( ( index >= SECTOR_SIZE ) &&
2424 ( index < SECTOR_SIZE*2 ))
2425 ptr = dir->sectorcache[1];
2426 else
2427 ptr = dir->sectorcache[2];
2429 else {
2430 if ( index < SECTOR_SIZE )
2431 ptr = dir->sectorcache[1];
2434 index &= SECTOR_SIZE-1;
2437 /* Try to append each segment of the long name.
2438 Check if we'd exceed the buffer.
2439 Also check for FAT padding characters 0xFFFF. */
2440 if (fat_copy_long_name_segment(ptr + index + 1, 5,
2441 longname_utf8segm) == 0) break;
2442 /* logf("SG: %s, EN: %s", longname_utf8segm,
2443 entry->name); */
2444 longname_utf8len += strlen(longname_utf8segm);
2445 if (longname_utf8len < FAT_FILENAME_BYTES)
2446 strcat(entry->name, longname_utf8segm);
2447 else
2448 break;
2450 if (fat_copy_long_name_segment(ptr + index + 14, 6,
2451 longname_utf8segm) == 0) break;
2452 /* logf("SG: %s, EN: %s", longname_utf8segm,
2453 entry->name); */
2454 longname_utf8len += strlen(longname_utf8segm);
2455 if (longname_utf8len < FAT_FILENAME_BYTES)
2456 strcat(entry->name, longname_utf8segm);
2457 else
2458 break;
2460 if (fat_copy_long_name_segment(ptr + index + 28, 2,
2461 longname_utf8segm) == 0) break;
2462 /* logf("SG: %s, EN: %s", longname_utf8segm,
2463 entry->name); */
2464 longname_utf8len += strlen(longname_utf8segm);
2465 if (longname_utf8len < FAT_FILENAME_BYTES)
2466 strcat(entry->name, longname_utf8segm);
2467 else
2468 break;
2471 /* Does the utf8-encoded name fit into the entry? */
2472 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2473 /* Take the short DOS name. Need to utf8-encode it
2474 since it may contain chars from the upper half of
2475 the OEM code page which wouldn't be a valid utf8.
2476 Beware: this file will be shown with strange
2477 glyphs in file browser since unicode 0x80 to 0x9F
2478 are control characters. */
2479 logf("SN-DOS: %s", shortname);
2480 unsigned char *utf8;
2481 utf8 = iso_decode(shortname, entry->name, -1,
2482 strlen(shortname));
2483 *utf8 = 0;
2484 logf("SN: %s", entry->name);
2485 } else {
2486 /* logf("LN: %s", entry->name);
2487 logf("LNLen: %d (%c)", longname_utf8len,
2488 entry->name[0]); */
2491 done = true;
2492 sectoridx = 0;
2493 i++;
2494 break;
2499 /* save this sector, for longname use */
2500 if ( sectoridx )
2501 memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
2502 else
2503 memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
2504 sectoridx += SECTOR_SIZE;
2507 return 0;
2510 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2512 #ifndef HAVE_MULTIVOLUME
2513 const int volume = 0;
2514 #endif
2515 struct bpb* fat_bpb = &fat_bpbs[volume];
2516 return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2519 #ifdef HAVE_MULTIVOLUME
2520 bool fat_ismounted(int volume)
2522 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2524 #endif