1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
31 #include "timefuncs.h"
33 #include "rbunicode.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 */
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
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
64 #define BS_RESERVED1 37
68 #define BS_FILSYSTYPE 54
71 #define BPB_FATSZ32 36
72 #define BPB_EXTFLAGS 40
74 #define BPB_ROOTCLUS 44
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
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 )
94 #define FAT_NTRES_LC_NAME 0x08
95 #define FAT_NTRES_LC_EXT 0x10
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
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 */
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. */
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
147 unsigned int last_word
; /* 0xAA55 */
149 /**** FAT32 specific *****/
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 int drive
; /* on which physical device is this located */
171 bool mounted
; /* flag if this volume is mounted */
175 static struct bpb fat_bpbs
[NUM_VOLUMES
]; /* mounted partition info */
176 static bool initialized
= false;
178 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
));
179 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
));
180 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
));
181 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
182 long secnum
, bool dirty
);
183 static void create_dos_name(const unsigned char *name
, unsigned char *newname
);
184 static void randomize_dos_name(unsigned char *name
);
185 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
186 unsigned long start
);
187 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
,
188 long count
, char* buf
, bool write
);
190 #define FAT_CACHE_SIZE 0x20
191 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
193 struct fat_cache_entry
198 #ifdef HAVE_MULTIVOLUME
199 struct bpb
* fat_vol
; /* shared cache for all volumes */
203 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
204 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
205 static struct mutex cache_mutex SHAREDBSS_ATTR
;
207 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
210 mutex_lock(&cache_mutex
);
213 void fat_unlock(void)
215 mutex_unlock(&cache_mutex
);
219 static long cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
221 #ifndef HAVE_MULTIVOLUME
222 struct bpb
* fat_bpb
= &fat_bpbs
[0];
224 #ifdef HAVE_FAT16SUPPORT
225 /* negative clusters (FAT16 root dir) don't get the 2 offset */
226 int zerocluster
= cluster
< 0 ? 0 : 2;
228 const long zerocluster
= 2;
231 if (cluster
> (long)(fat_bpb
->dataclusters
+ 1))
233 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster
);
237 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
238 + fat_bpb
->firstdatasector
;
241 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
243 #ifndef HAVE_MULTIVOLUME
244 const int volume
= 0;
246 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
248 *size
= fat_bpb
->dataclusters
* fat_bpb
->bpb_secperclus
/ 2;
250 *free
= fat_bpb
->fsinfo
.freecount
* fat_bpb
->bpb_secperclus
/ 2;
260 mutex_init(&cache_mutex
);
263 #ifdef HAVE_PRIORITY_SCHEDULING
264 /* Disable this because it is dangerous due to the assumption that
265 * mutex_unlock won't yield */
266 mutex_set_preempt(&cache_mutex
, false);
269 /* mark the FAT cache as unused */
270 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
272 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
273 fat_cache
[i
].inuse
= false;
274 fat_cache
[i
].dirty
= false;
275 #ifdef HAVE_MULTIVOLUME
276 fat_cache
[i
].fat_vol
= NULL
;
279 #ifdef HAVE_MULTIVOLUME
280 /* mark the possible volumes as not mounted */
281 for (i
=0; i
<NUM_VOLUMES
;i
++)
283 fat_bpbs
[i
].mounted
= false;
288 int fat_mount(IF_MV2(int volume
,) IF_MV2(int drive
,) long startsector
)
290 #ifndef HAVE_MULTIVOLUME
291 const int volume
= 0;
293 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
294 unsigned char buf
[SECTOR_SIZE
];
298 #ifdef HAVE_FAT16SUPPORT
302 /* Read the sector */
303 rc
= storage_read_sectors(drive
, startsector
,1,buf
);
306 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
310 memset(fat_bpb
, 0, sizeof(struct bpb
));
311 fat_bpb
->startsector
= startsector
;
312 #ifdef HAVE_MULTIVOLUME
313 fat_bpb
->drive
= drive
;
316 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
317 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
318 /* Sanity check is performed later */
320 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
321 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
322 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
323 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
324 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
325 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
326 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
327 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
328 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
330 /* calculate a few commonly used values */
331 if (fat_bpb
->bpb_fatsz16
!= 0)
332 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
334 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
336 if (fat_bpb
->bpb_totsec16
!= 0)
337 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
339 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
341 #ifdef HAVE_FAT16SUPPORT
342 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
343 if (!fat_bpb
->bpb_bytspersec
)
345 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
346 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
347 #endif /* #ifdef HAVE_FAT16SUPPORT */
349 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
350 #ifdef HAVE_FAT16SUPPORT
353 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
355 /* Determine FAT type */
356 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
357 if (fat_bpb
->bpb_secperclus
)
358 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
364 we are sometimes testing with "illegally small" fat32 images,
365 so we don't use the proper fat32 test case for test code
367 if ( fat_bpb
->bpb_fatsz16
)
369 if ( fat_bpb
->dataclusters
< 65525 )
372 #ifdef HAVE_FAT16SUPPORT
373 fat_bpb
->is_fat16
= true;
374 if (fat_bpb
->dataclusters
< 4085)
376 DEBUGF("This is FAT12. Go away!\n");
379 #else /* #ifdef HAVE_FAT16SUPPORT */
380 DEBUGF("This is not FAT32. Go away!\n");
382 #endif /* #ifndef HAVE_FAT16SUPPORT */
385 #ifdef HAVE_FAT16SUPPORT
386 if (fat_bpb
->is_fat16
)
387 { /* FAT16 specific part of BPB */
389 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
390 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
391 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
392 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
393 /* I assign negative pseudo cluster numbers for the root directory,
394 their range is counted upward until -1. */
395 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data*/
396 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
400 #endif /* #ifdef HAVE_FAT16SUPPORT */
401 { /* FAT32 specific part of BPB */
402 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
403 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
404 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,)
405 fat_bpb
->bpb_rootclus
);
408 rc
= bpb_is_sane(IF_MV(fat_bpb
));
411 DEBUGF( "fat_mount() - BPB is not sane\n");
415 #ifdef HAVE_FAT16SUPPORT
416 if (fat_bpb
->is_fat16
)
418 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
419 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
422 #endif /* #ifdef HAVE_FAT16SUPPORT */
424 /* Read the fsinfo sector */
425 rc
= storage_read_sectors(drive
,
426 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
429 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
432 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
433 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
436 /* calculate freecount if unset */
437 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
439 fat_recalc_free(IF_MV(volume
));
442 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
443 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
444 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
445 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
446 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
448 #ifdef HAVE_MULTIVOLUME
449 fat_bpb
->mounted
= true;
456 int fat_unmount(int volume
, bool flush
)
459 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
463 rc
= flush_fat(fat_bpb
); /* the clean way, while still alive */
466 { /* volume is not accessible any more, e.g. MMC removed */
468 mutex_lock(&cache_mutex
);
469 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
471 struct fat_cache_entry
*fce
= &fat_cache
[i
];
472 if(fce
->inuse
&& fce
->fat_vol
== fat_bpb
)
474 fce
->inuse
= false; /* discard all from that volume */
478 mutex_unlock(&cache_mutex
);
481 fat_bpb
->mounted
= false;
484 #endif /* #ifdef HAVE_HOTSWAP */
486 void fat_recalc_free(IF_MV_NONVOID(int volume
))
488 #ifndef HAVE_MULTIVOLUME
489 const int volume
= 0;
491 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
494 #ifdef HAVE_FAT16SUPPORT
495 if (fat_bpb
->is_fat16
)
497 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
499 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
500 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
501 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
502 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
505 if (letoh16(fat
[j
]) == 0x0000) {
507 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
508 fat_bpb
->fsinfo
.nextfree
= c
;
514 #endif /* #ifdef HAVE_FAT16SUPPORT */
516 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
518 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
519 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
520 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
521 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
524 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
526 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
527 fat_bpb
->fsinfo
.nextfree
= c
;
532 fat_bpb
->fsinfo
.freecount
= free
;
533 update_fsinfo(IF_MV(fat_bpb
));
536 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
538 #ifndef HAVE_MULTIVOLUME
539 struct bpb
* fat_bpb
= &fat_bpbs
[0];
541 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
543 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
544 fat_bpb
->bpb_bytspersec
);
547 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
550 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
552 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
553 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
556 if(fat_bpb
->bpb_numfats
!= 2)
558 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
559 fat_bpb
->bpb_numfats
);
561 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
563 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
564 "media type (0x%02x)\n",
567 if(fat_bpb
->last_word
!= 0xaa55)
569 DEBUGF( "bpb_is_sane() - Error: Last word is not "
570 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
574 if (fat_bpb
->fsinfo
.freecount
>
575 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
576 fat_bpb
->bpb_secperclus
)
578 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
579 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
586 static void flush_fat_sector(struct fat_cache_entry
*fce
,
587 unsigned char *sectorbuf
)
592 /* With multivolume, use only the FAT info from the cached sector! */
593 #ifdef HAVE_MULTIVOLUME
594 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
596 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
599 /* Write to the first FAT */
600 rc
= storage_write_sectors(fce
->fat_vol
->drive
,
605 panicf("flush_fat_sector() - Could not write sector %ld"
609 #ifdef HAVE_MULTIVOLUME
610 if(fce
->fat_vol
->bpb_numfats
> 1)
612 if(fat_bpbs
[0].bpb_numfats
> 1)
615 /* Write to the second FAT */
616 #ifdef HAVE_MULTIVOLUME
617 secnum
+= fce
->fat_vol
->fatsize
;
619 secnum
+= fat_bpbs
[0].fatsize
;
621 rc
= storage_write_sectors(fce
->fat_vol
->drive
,
622 secnum
, 1, sectorbuf
);
625 panicf("flush_fat_sector() - Could not write sector %ld"
633 /* Note: The returned pointer is only safely valid until the next
634 task switch! (Any subsequent ata read/write may yield.) */
635 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
636 long fatsector
, bool dirty
)
638 #ifndef HAVE_MULTIVOLUME
639 struct bpb
* fat_bpb
= &fat_bpbs
[0];
641 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
642 int cache_index
= secnum
& FAT_CACHE_MASK
;
643 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
644 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
647 mutex_lock(&cache_mutex
); /* make changes atomic */
649 /* Delete the cache entry if it isn't the sector we want */
650 if(fce
->inuse
&& (fce
->secnum
!= secnum
651 #ifdef HAVE_MULTIVOLUME
652 || fce
->fat_vol
!= fat_bpb
656 /* Write back if it is dirty */
659 flush_fat_sector(fce
, sectorbuf
);
664 /* Load the sector if it is not cached */
667 rc
= storage_read_sectors(fat_bpb
->drive
,
668 secnum
+ fat_bpb
->startsector
,1,
672 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
673 " (error %d)\n", secnum
, rc
);
674 mutex_unlock(&cache_mutex
);
678 fce
->secnum
= secnum
;
679 #ifdef HAVE_MULTIVOLUME
680 fce
->fat_vol
= fat_bpb
;
684 fce
->dirty
= true; /* dirt remains, sticky until flushed */
685 mutex_unlock(&cache_mutex
);
689 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
690 unsigned long startcluster
)
692 #ifndef HAVE_MULTIVOLUME
693 struct bpb
* fat_bpb
= &fat_bpbs
[0];
695 unsigned long sector
;
696 unsigned long offset
;
699 #ifdef HAVE_FAT16SUPPORT
700 if (fat_bpb
->is_fat16
)
702 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
703 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
705 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
707 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
708 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
711 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
712 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
713 if (letoh16(fat
[k
]) == 0x0000) {
714 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
715 /* Ignore the reserved clusters 0 & 1, and also
716 cluster numbers out of bounds */
717 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
719 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
720 fat_bpb
->fsinfo
.nextfree
= c
;
728 #endif /* #ifdef HAVE_FAT16SUPPORT */
730 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
731 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
733 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
735 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
736 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
739 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
740 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
741 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
742 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
743 /* Ignore the reserved clusters 0 & 1, and also
744 cluster numbers out of bounds */
745 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
747 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
748 fat_bpb
->fsinfo
.nextfree
= c
;
756 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
757 return 0; /* 0 is an illegal cluster number */
760 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
763 #ifndef HAVE_MULTIVOLUME
764 struct bpb
* fat_bpb
= &fat_bpbs
[0];
766 #ifdef HAVE_FAT16SUPPORT
767 if (fat_bpb
->is_fat16
)
769 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
770 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
775 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
778 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
781 panicf("Updating reserved FAT entry %ld.\n",entry
);
783 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
786 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
791 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
792 fat_bpb
->fsinfo
.freecount
--;
795 if (letoh16(sec
[offset
]))
796 fat_bpb
->fsinfo
.freecount
++;
799 LDEBUGF("update_fat_entry: %d free clusters\n",
800 fat_bpb
->fsinfo
.freecount
);
802 sec
[offset
] = htole16(val
);
805 #endif /* #ifdef HAVE_FAT16SUPPORT */
807 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
808 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
811 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
814 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
817 panicf("Updating reserved FAT entry %ld.\n",entry
);
819 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
822 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
827 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
828 fat_bpb
->fsinfo
.freecount
> 0)
829 fat_bpb
->fsinfo
.freecount
--;
832 if (letoh32(sec
[offset
]) & 0x0fffffff)
833 fat_bpb
->fsinfo
.freecount
++;
836 LDEBUGF("update_fat_entry: %ld free clusters\n",
837 fat_bpb
->fsinfo
.freecount
);
839 /* don't change top 4 bits */
840 sec
[offset
] &= htole32(0xf0000000);
841 sec
[offset
] |= htole32(val
& 0x0fffffff);
847 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
849 #ifdef HAVE_FAT16SUPPORT
850 #ifndef HAVE_MULTIVOLUME
851 struct bpb
* fat_bpb
= &fat_bpbs
[0];
853 if (fat_bpb
->is_fat16
)
855 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
856 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
859 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
862 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
866 return letoh16(sec
[offset
]);
869 #endif /* #ifdef HAVE_FAT16SUPPORT */
871 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
872 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
875 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
878 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
882 return letoh32(sec
[offset
]) & 0x0fffffff;
886 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
889 long eof_mark
= FAT_EOF_MARK
;
891 #ifdef HAVE_FAT16SUPPORT
892 #ifndef HAVE_MULTIVOLUME
893 struct bpb
* fat_bpb
= &fat_bpbs
[0];
895 if (fat_bpb
->is_fat16
)
897 eof_mark
&= 0xFFFF; /* only 16 bit */
898 if (cluster
< 0) /* FAT16 root dir */
899 return cluster
+ 1; /* don't use the FAT */
902 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
904 /* is this last cluster in chain? */
905 if ( next_cluster
>= eof_mark
)
911 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
913 #ifndef HAVE_MULTIVOLUME
914 struct bpb
* fat_bpb
= &fat_bpbs
[0];
916 unsigned char fsinfo
[SECTOR_SIZE
];
917 unsigned long* intptr
;
920 #ifdef HAVE_FAT16SUPPORT
921 if (fat_bpb
->is_fat16
)
922 return 0; /* FAT16 has no FsInfo */
923 #endif /* #ifdef HAVE_FAT16SUPPORT */
926 rc
= storage_read_sectors(fat_bpb
->drive
,
927 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
930 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
933 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
934 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
936 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
937 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
939 rc
= storage_write_sectors(fat_bpb
->drive
,
940 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
943 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
950 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
955 LDEBUGF("flush_fat()\n");
957 mutex_lock(&cache_mutex
);
958 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
960 struct fat_cache_entry
*fce
= &fat_cache
[i
];
962 #ifdef HAVE_MULTIVOLUME
963 && fce
->fat_vol
== fat_bpb
967 sec
= fat_cache_sectors
[i
];
968 flush_fat_sector(fce
, sec
);
971 mutex_unlock(&cache_mutex
);
973 rc
= update_fsinfo(IF_MV(fat_bpb
));
980 static void fat_time(unsigned short* date
,
981 unsigned short* time
,
982 unsigned short* tenth
)
985 struct tm
* tm
= get_time();
988 *date
= ((tm
->tm_year
- 80) << 9) |
989 ((tm
->tm_mon
+ 1) << 5) |
993 *time
= (tm
->tm_hour
<< 11) |
998 *tenth
= (tm
->tm_sec
& 1) * 100;
1000 /* non-RTC version returns an increment from the supplied time, or a
1001 * fixed standard time/date if no time given as input */
1002 bool next_day
= false;
1008 /* set to 00:15:00 */
1013 unsigned short mins
= (*time
>> 5) & 0x003F;
1014 unsigned short hours
= (*time
>> 11) & 0x001F;
1015 if ((mins
+= 10) >= 60)
1020 if ((++hours
) >= 24)
1025 *time
= (hours
<< 11) | (mins
<< 5);
1033 /* Macros to convert a 2-digit string to a decimal constant.
1034 (YEAR), MONTH and DAY are set by the date command, which outputs
1035 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1036 misinterpretation as an octal constant. */
1037 #define S100(x) 1 ## x
1038 #define C2DIG2DEC(x) (S100(x)-100)
1039 /* set to build date */
1040 *date
= ((YEAR
- 1980) << 9) | (C2DIG2DEC(MONTH
) << 5)
1045 unsigned short day
= *date
& 0x001F;
1046 unsigned short month
= (*date
>> 5) & 0x000F;
1047 unsigned short year
= (*date
>> 9) & 0x007F;
1050 /* do a very simple day increment - never go above 28 days */
1060 *date
= (year
<< 9) | (month
<< 5) | day
;
1066 #endif /* CONFIG_RTC */
1069 static int write_long_name(struct fat_file
* file
,
1070 unsigned int firstentry
,
1071 unsigned int numentries
,
1072 const unsigned char* name
,
1073 const unsigned char* shortname
,
1076 unsigned char buf
[SECTOR_SIZE
];
1077 unsigned char* entry
;
1078 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1079 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1080 unsigned char chksum
= 0;
1081 unsigned int i
, j
=0;
1082 unsigned int nameidx
=0, namelen
= utf8length(name
);
1084 unsigned short name_utf16
[namelen
+ 1];
1086 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1087 file
->firstcluster
, firstentry
, numentries
, name
);
1089 rc
= fat_seek(file
, sector
);
1093 rc
= fat_readwrite(file
, 1, buf
, false);
1097 /* calculate shortname checksum */
1098 for (i
=11; i
>0; i
--)
1099 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1101 /* calc position of last name segment */
1102 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1104 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1105 nameidx
+= NAME_BYTES_PER_ENTRY
);
1107 /* we need to convert the name first */
1108 /* since it is written in reverse order */
1109 for (i
= 0; i
<= namelen
; i
++)
1110 name
= utf8decode(name
, &name_utf16
[i
]);
1112 for (i
=0; i
< numentries
; i
++) {
1114 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1115 /* update current sector */
1116 rc
= fat_seek(file
, sector
);
1120 rc
= fat_readwrite(file
, 1, buf
, true);
1124 /* read next sector */
1125 rc
= fat_readwrite(file
, 1, buf
, false);
1127 LDEBUGF("Failed writing new sector: %d\n",rc
);
1132 memset(buf
, 0, sizeof buf
);
1138 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1140 /* verify this entry is free */
1141 if (entry
[0] && entry
[0] != 0xe5 )
1142 panicf("Dir entry %d in sector %x is not free! "
1143 "%02x %02x %02x %02x",
1145 entry
[0], entry
[1], entry
[2], entry
[3]);
1147 memset(entry
, 0, DIR_ENTRY_SIZE
);
1148 if ( i
+1 < numentries
) {
1149 /* longname entry */
1150 unsigned int k
, l
= nameidx
;
1152 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1154 /* mark this as last long entry */
1155 entry
[FATLONG_ORDER
] |= 0x40;
1157 /* pad name with 0xffff */
1158 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1159 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1160 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1163 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1164 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1165 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1167 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1168 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1169 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1171 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1172 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1173 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1176 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1177 entry
[FATDIR_FSTCLUSLO
] = 0;
1178 entry
[FATLONG_TYPE
] = 0;
1179 entry
[FATLONG_CHKSUM
] = chksum
;
1180 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1183 /* shortname entry */
1184 unsigned short date
=0, time
=0, tenth
=0;
1185 LDEBUGF("Shortname entry: %s\n", shortname
);
1186 strncpy(entry
+ FATDIR_NAME
, shortname
, 11);
1187 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1188 entry
[FATDIR_NTRES
] = 0;
1190 fat_time(&date
, &time
, &tenth
);
1191 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1192 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1193 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1194 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1195 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1196 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1199 nameidx
-= NAME_BYTES_PER_ENTRY
;
1202 /* update last sector */
1203 rc
= fat_seek(file
, sector
);
1207 rc
= fat_readwrite(file
, 1, buf
, true);
1214 static int fat_checkname(const unsigned char* newname
)
1216 static const char invalid_chars
[] = "\"*/:<>?\\|";
1217 int len
= strlen(newname
);
1218 /* More sanity checks are probably needed */
1219 if (len
> 255 || newname
[len
- 1] == '.')
1225 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1229 /* check trailing space(s) */
1230 if(*(--newname
) == ' ')
1236 static int add_dir_entry(struct fat_dir
* dir
,
1237 struct fat_file
* file
,
1242 #ifdef HAVE_MULTIVOLUME
1243 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1245 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1247 unsigned char buf
[SECTOR_SIZE
];
1248 unsigned char shortname
[12];
1250 unsigned int sector
;
1252 int entries_needed
, entries_found
= 0;
1255 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1256 name
, file
->firstcluster
);
1258 /* Don't check dotdirs name for validity */
1259 if (dotdir
== false) {
1260 rc
= fat_checkname(name
);
1262 /* filename is invalid */
1267 #ifdef HAVE_MULTIVOLUME
1268 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1271 /* The "." and ".." directory entries must not be long names */
1274 strncpy(shortname
, name
, 12);
1275 for(i
= strlen(shortname
); i
< 12; i
++)
1280 create_dos_name(name
, shortname
);
1282 /* one dir entry needed for every 13 bytes of filename,
1283 plus one entry for the short name */
1284 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1285 / NAME_BYTES_PER_ENTRY
+ 1;
1291 rc
= fat_seek(&dir
->file
, 0);
1295 /* step 1: search for free entries and check for duplicate shortname */
1296 for (sector
= 0; !done
; sector
++)
1300 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1302 DEBUGF( "add_dir_entry() - Couldn't read dir"
1303 " (error code %d)\n", rc
);
1307 if (rc
== 0) { /* current end of dir reached */
1308 LDEBUGF("End of dir on cluster boundary\n");
1312 /* look for free slots */
1313 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1315 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1317 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1318 LDEBUGF("Found end of dir %d\n",
1319 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1320 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1326 LDEBUGF("Found free entry %d (%d/%d)\n",
1327 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1328 entries_found
, entries_needed
);
1334 /* check that our intended shortname doesn't already exist */
1335 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1336 /* shortname exists already, make a new one */
1337 randomize_dos_name(shortname
);
1338 LDEBUGF("Duplicate shortname, changing to %s\n",
1341 /* name has changed, we need to restart search */
1346 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1347 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1352 /* step 2: extend the dir if necessary */
1355 LDEBUGF("Adding new sector(s) to dir\n");
1356 rc
= fat_seek(&dir
->file
, sector
);
1359 memset(buf
, 0, sizeof buf
);
1361 /* we must clear whole clusters */
1362 for (; (entries_found
< entries_needed
) ||
1363 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1365 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1366 return -5; /* dir too large -- FAT specification */
1368 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1369 if (rc
< 1) /* No more room or something went wrong */
1372 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1375 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1378 /* step 3: add entry */
1379 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1380 LDEBUGF("Adding longname to entry %d in sector %d\n",
1381 firstentry
, sector
);
1383 rc
= write_long_name(&dir
->file
, firstentry
,
1384 entries_needed
, name
, shortname
, is_directory
);
1388 /* remember where the shortname dir entry is located */
1389 file
->direntry
= firstentry
+ entries_needed
- 1;
1390 file
->direntries
= entries_needed
;
1391 file
->dircluster
= dir
->file
.firstcluster
;
1392 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1393 file
->direntry
, file
->direntries
);
1398 static unsigned char char2dos(unsigned char c
, int* randomize
)
1400 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1403 c
= 0; /* Illegal char, remove */
1404 else if (strchr(invalid_chars
, c
) != NULL
)
1406 /* Illegal char, replace */
1408 *randomize
= 1; /* as per FAT spec */
1416 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1422 /* Find extension part */
1423 ext
= strrchr(name
, '.');
1424 if (ext
== name
) /* handle .dotnames */
1427 /* needs to randomize? */
1428 if((ext
&& (strlen(ext
) > 4)) ||
1429 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1433 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1435 unsigned char c
= char2dos(*name
, &randomize
);
1440 /* Pad both name and extension */
1444 if (newname
[0] == 0xe5) /* Special kanji character */
1448 { /* Extension part */
1450 for (i
= 8; *ext
&& (i
< 11); ext
++)
1452 unsigned char c
= char2dos(*ext
, &randomize
);
1459 randomize_dos_name(newname
);
1462 static void randomize_dos_name(unsigned char *name
)
1464 unsigned char* tilde
= NULL
; /* ~ location */
1465 unsigned char* lastpt
= NULL
; /* last point of filename */
1466 unsigned char* nameptr
= name
; /* working copy of name pointer */
1467 unsigned char num
[9]; /* holds number as string */
1475 /* hunt for ~ and where to put it */
1476 if((!tilde
) && (*nameptr
== '~'))
1478 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1484 /* extract current count and increment */
1485 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1486 num
[7-(unsigned int)(tilde
-name
)] = 0;
1487 cnt
= atoi(num
) + 1;
1489 cnt
%= 10000000; /* protection */
1490 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1491 numlen
= strlen(num
); /* required space */
1492 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1493 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1495 memcpy(&name
[offset
], num
, numlen
);
1497 /* in special case of counter overflow: pad with spaces */
1498 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1502 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1504 unsigned char buf
[SECTOR_SIZE
];
1505 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1506 unsigned char* entry
=
1507 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1508 unsigned long* sizeptr
;
1509 unsigned short* clusptr
;
1510 struct fat_file dir
;
1513 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1514 file
->firstcluster
, file
->direntry
, size
);
1516 /* create a temporary file handle for the dir holding this file */
1517 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1521 rc
= fat_seek( &dir
, sector
);
1525 rc
= fat_readwrite(&dir
, 1, buf
, false);
1529 if (!entry
[0] || entry
[0] == 0xe5)
1530 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1532 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1534 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1535 *clusptr
= htole16(file
->firstcluster
>> 16);
1537 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1538 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1540 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1541 *sizeptr
= htole32(size
);
1545 unsigned short time
= 0;
1546 unsigned short date
= 0;
1548 /* get old time to increment from */
1549 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1550 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1552 fat_time(&date
, &time
, NULL
);
1553 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1554 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1555 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1558 rc
= fat_seek( &dir
, sector
);
1562 rc
= fat_readwrite(&dir
, 1, buf
, true);
1569 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1575 memset(de
, 0, sizeof(struct fat_direntry
));
1576 de
->attr
= buf
[FATDIR_ATTR
];
1577 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1578 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1579 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1580 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1581 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1582 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1583 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1584 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1585 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1586 (the result of the shift is always considered signed) */
1589 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1590 c
= buf
[FATDIR_NAME
];
1591 if (c
== 0x05) /* special kanji char */
1595 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1598 c
= buf
[FATDIR_NAME
+i
];
1600 if (buf
[FATDIR_NAME
+8] != ' ') {
1601 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1602 de
->name
[j
++] = '.';
1603 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1604 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1609 int fat_open(IF_MV2(int volume
,)
1611 struct fat_file
*file
,
1612 const struct fat_dir
* dir
)
1614 file
->firstcluster
= startcluster
;
1615 file
->lastcluster
= startcluster
;
1616 file
->lastsector
= 0;
1617 file
->clusternum
= 0;
1618 file
->sectornum
= 0;
1620 #ifdef HAVE_MULTIVOLUME
1621 file
->volume
= volume
;
1622 /* fixme: remove error check when done */
1623 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1625 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1630 /* remember where the file's dir entry is located */
1632 file
->direntry
= dir
->entry
- 1;
1633 file
->direntries
= dir
->entrycount
;
1634 file
->dircluster
= dir
->file
.firstcluster
;
1636 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1640 int fat_create_file(const char* name
,
1641 struct fat_file
* file
,
1642 struct fat_dir
* dir
)
1646 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1647 rc
= add_dir_entry(dir
, file
, name
, false, false);
1649 file
->firstcluster
= 0;
1650 file
->lastcluster
= 0;
1651 file
->lastsector
= 0;
1652 file
->clusternum
= 0;
1653 file
->sectornum
= 0;
1660 int fat_create_dir(const char* name
,
1661 struct fat_dir
* newdir
,
1662 struct fat_dir
* dir
)
1664 #ifdef HAVE_MULTIVOLUME
1665 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1667 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1669 unsigned char buf
[SECTOR_SIZE
];
1673 struct fat_file dummyfile
;
1675 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1677 memset(newdir
, 0, sizeof(struct fat_dir
));
1678 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1680 /* First, add the entry in the parent directory */
1681 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1685 /* Allocate a new cluster for the directory */
1686 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1687 fat_bpb
->fsinfo
.nextfree
);
1688 if(newdir
->file
.firstcluster
== 0)
1691 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1693 /* Clear the entire cluster */
1694 memset(buf
, 0, sizeof buf
);
1695 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1696 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1697 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1702 /* Then add the "." entry */
1703 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1706 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1707 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1709 /* and the ".." entry */
1710 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1714 /* The root cluster is cluster 0 in the ".." entry */
1715 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1716 dummyfile
.firstcluster
= 0;
1718 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1719 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1721 /* Set the firstcluster field in the direntry */
1722 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1724 rc
= flush_fat(IF_MV(fat_bpb
));
1731 int fat_truncate(const struct fat_file
*file
)
1733 /* truncate trailing clusters */
1735 long last
= file
->lastcluster
;
1736 #ifdef HAVE_MULTIVOLUME
1737 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1740 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1742 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1743 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1744 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1746 if (file
->lastcluster
)
1747 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1752 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1755 #ifdef HAVE_MULTIVOLUME
1756 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1758 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1762 if ( file
->firstcluster
) {
1763 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1764 file
->firstcluster
= 0;
1768 if (file
->dircluster
) {
1769 rc
= update_short_entry(file
, size
, attr
);
1774 flush_fat(IF_MV(fat_bpb
));
1777 if ( file
->firstcluster
) {
1779 #ifdef HAVE_MULTIVOLUME
1780 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1782 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1787 for ( next
= file
->firstcluster
; next
;
1788 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1789 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1792 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1793 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1795 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1796 panicf("Cluster chain is too long\n");
1798 panicf("Cluster chain is too short\n");
1805 static int free_direntries(struct fat_file
* file
)
1807 unsigned char buf
[SECTOR_SIZE
];
1808 struct fat_file dir
;
1809 int numentries
= file
->direntries
;
1810 unsigned int entry
= file
->direntry
- numentries
+ 1;
1811 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1815 /* create a temporary file handle for the dir holding this file */
1816 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1820 rc
= fat_seek( &dir
, sector
);
1824 rc
= fat_readwrite(&dir
, 1, buf
, false);
1828 for (i
=0; i
< numentries
; i
++) {
1829 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1830 entry
, i
+1, numentries
);
1831 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1834 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1835 /* flush this sector */
1836 rc
= fat_seek(&dir
, sector
);
1840 rc
= fat_readwrite(&dir
, 1, buf
, true);
1844 if ( i
+1 < numentries
) {
1845 /* read next sector */
1846 rc
= fat_readwrite(&dir
, 1, buf
, false);
1854 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1855 /* flush this sector */
1856 rc
= fat_seek(&dir
, sector
);
1860 rc
= fat_readwrite(&dir
, 1, buf
, true);
1868 int fat_remove(struct fat_file
* file
)
1870 long next
, last
= file
->firstcluster
;
1872 #ifdef HAVE_MULTIVOLUME
1873 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1876 LDEBUGF("fat_remove(%lx)\n",last
);
1879 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1880 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1884 if ( file
->dircluster
) {
1885 rc
= free_direntries(file
);
1890 file
->firstcluster
= 0;
1891 file
->dircluster
= 0;
1893 rc
= flush_fat(IF_MV(fat_bpb
));
1900 int fat_rename(struct fat_file
* file
,
1901 struct fat_dir
* dir
,
1902 const unsigned char* newname
,
1907 struct fat_dir olddir
;
1908 struct fat_file newfile
= *file
;
1909 unsigned char buf
[SECTOR_SIZE
];
1910 unsigned char* entry
= NULL
;
1911 unsigned short* clusptr
= NULL
;
1912 unsigned int parentcluster
;
1913 #ifdef HAVE_MULTIVOLUME
1914 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1916 if (file
->volume
!= dir
->file
.volume
) {
1917 DEBUGF("No rename across volumes!\n");
1921 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1924 if ( !file
->dircluster
) {
1925 DEBUGF("File has no dir cluster!\n");
1929 /* create a temporary file handle */
1930 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1934 /* create new name */
1935 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1939 /* write size and cluster link */
1940 rc
= update_short_entry(&newfile
, size
, attr
);
1944 /* remove old name */
1945 rc
= free_direntries(file
);
1949 rc
= flush_fat(IF_MV(fat_bpb
));
1953 /* if renaming a directory, update the .. entry to make sure
1954 it points to its parent directory (we don't check if it was a move) */
1955 if(FAT_ATTR_DIRECTORY
== attr
) {
1956 /* open the dir that was renamed, we re-use the olddir struct */
1957 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1962 /* get the first sector of the dir */
1963 rc
= fat_seek(&olddir
.file
, 0);
1967 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1971 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1972 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1975 parentcluster
= dir
->file
.firstcluster
;
1977 entry
= buf
+ DIR_ENTRY_SIZE
;
1978 if(strncmp(".. ", entry
, 11))
1980 /* .. entry must be second entry according to FAT spec (p.29) */
1981 DEBUGF("Second dir entry is not double-dot!\n");
1984 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1985 *clusptr
= htole16(parentcluster
>> 16);
1987 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1988 *clusptr
= htole16(parentcluster
& 0xffff);
1990 /* write back this sector */
1991 rc
= fat_seek(&olddir
.file
, 0);
1995 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
2003 static long next_write_cluster(struct fat_file
* file
,
2007 #ifdef HAVE_MULTIVOLUME
2008 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2010 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2015 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
2018 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
2022 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
2023 else if (oldcluster
== 0)
2024 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
2025 fat_bpb
->fsinfo
.nextfree
);
2026 #ifdef HAVE_FAT16SUPPORT
2027 else /* negative, pseudo-cluster of the root dir */
2028 return 0; /* impossible to append something to the root */
2033 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2035 file
->firstcluster
= cluster
;
2036 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2040 if (fat_bpb
->fsinfo
.freecount
>0)
2041 panicf("There is free space, but find_free_cluster() "
2042 "didn't find it!\n");
2044 DEBUGF("next_write_cluster(): Disk full!\n");
2048 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2052 *newsector
= sector
;
2056 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2057 unsigned long start
, long count
, char* buf
, bool write
)
2059 #ifndef HAVE_MULTIVOLUME
2060 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2064 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2065 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2067 unsigned long firstallowed
;
2068 #ifdef HAVE_FAT16SUPPORT
2069 if (fat_bpb
->is_fat16
)
2070 firstallowed
= fat_bpb
->rootdirsector
;
2073 firstallowed
= fat_bpb
->firstdatasector
;
2075 if (start
< firstallowed
)
2076 panicf("Write %ld before data\n", firstallowed
- start
);
2077 if (start
+ count
> fat_bpb
->totalsectors
)
2078 panicf("Write %ld after data\n",
2079 start
+ count
- fat_bpb
->totalsectors
);
2080 rc
= storage_write_sectors(fat_bpb
->drive
,
2081 start
+ fat_bpb
->startsector
, count
, buf
);
2084 rc
= storage_read_sectors(fat_bpb
->drive
,
2085 start
+ fat_bpb
->startsector
, count
, buf
);
2087 DEBUGF( "transfer() - Couldn't %s sector %lx"
2088 " (error code %d)\n",
2089 write
? "write":"read", start
, rc
);
2096 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2097 void* buf
, bool write
)
2099 #ifdef HAVE_MULTIVOLUME
2100 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2102 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2104 long cluster
= file
->lastcluster
;
2105 long sector
= file
->lastsector
;
2106 long clusternum
= file
->clusternum
;
2107 long numsec
= file
->sectornum
;
2108 bool eof
= file
->eof
;
2109 long first
=0, last
=0;
2113 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2114 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2115 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2116 sector
,numsec
, eof
?1:0);
2121 /* find sequential sectors and write them all at once */
2122 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2124 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2125 long oldcluster
= cluster
;
2126 long oldsector
= sector
;
2127 long oldnumsec
= numsec
;
2129 cluster
= next_write_cluster(file
, cluster
, §or
);
2131 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2132 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2141 /* remember last cluster, in case
2142 we want to append to the file */
2144 cluster
= oldcluster
;
2147 i
= -1; /* Error code */
2158 /* look up first sector of file */
2159 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2161 #ifdef HAVE_FAT16SUPPORT
2162 if (file
->firstcluster
< 0)
2163 { /* FAT16 root dir */
2164 sector
+= fat_bpb
->rootdiroffset
;
2165 numsec
+= fat_bpb
->rootdiroffset
;
2174 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2175 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2176 long count
= last
- first
+ 1;
2177 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2181 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2185 if ((i
== sectorcount
-1) && /* last sector requested */
2188 long count
= sector
- first
+ 1;
2189 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2197 file
->lastcluster
= cluster
;
2198 file
->lastsector
= sector
;
2199 file
->clusternum
= clusternum
;
2200 file
->sectornum
= numsec
;
2203 /* if eof, don't report last block as read/written */
2207 DEBUGF("Sectors written: %ld\n", i
);
2211 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2213 #ifdef HAVE_MULTIVOLUME
2214 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2216 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2218 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2219 long cluster
= file
->firstcluster
;
2222 #ifdef HAVE_FAT16SUPPORT
2223 if (cluster
< 0) /* FAT16 root dir */
2224 seeksector
+= fat_bpb
->rootdiroffset
;
2229 /* we need to find the sector BEFORE the requested, since
2230 the file struct stores the last accessed sector */
2232 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2233 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2235 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2237 cluster
= file
->lastcluster
;
2238 numclusters
-= file
->clusternum
;
2241 for (i
=0; i
<numclusters
; i
++) {
2242 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2244 DEBUGF("Seeking beyond the end of the file! "
2245 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2250 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2256 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2257 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2259 file
->lastcluster
= cluster
;
2260 file
->lastsector
= sector
;
2261 file
->clusternum
= clusternum
;
2262 file
->sectornum
= sectornum
+ 1;
2266 int fat_opendir(IF_MV2(int volume
,)
2267 struct fat_dir
*dir
, unsigned long startcluster
,
2268 const struct fat_dir
*parent_dir
)
2270 #ifdef HAVE_MULTIVOLUME
2271 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2272 /* fixme: remove error check when done */
2273 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2275 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2279 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2286 if (startcluster
== 0)
2287 startcluster
= fat_bpb
->bpb_rootclus
;
2289 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2292 DEBUGF( "fat_opendir() - Couldn't open dir"
2293 " (error code %d)\n", rc
);
2300 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2301 * destination buffer (UTF-8 encoded). Copying is stopped when
2302 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2303 * Trailing \0 is also appended at the end of the UTF8-encoded
2306 * utf16src utf16 (little endian) segment to copy
2307 * utf16count max number of the utf16-characters to copy
2308 * utf8dst where to write UTF8-encoded string to
2310 * returns the number of UTF-16 characters actually copied
2312 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2313 int utf16count
, unsigned char *utf8dst
) {
2315 while ((utf16count
--) > 0) {
2316 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2317 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2320 utf8dst
= utf8encode(ucs
, utf8dst
);
2328 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2333 unsigned char firstbyte
;
2334 /* Long file names are stored in special entries. Each entry holds
2335 up to 13 characters. Names can be max 255 chars (not bytes!) long
2336 hence max 20 entries are required. */
2340 unsigned char* cached_buf
= dir
->sectorcache
[0];
2342 dir
->entrycount
= 0;
2346 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2348 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2355 DEBUGF( "fat_getnext() - Couldn't read dir"
2356 " (error code %d)\n", rc
);
2359 dir
->sector
= dir
->file
.lastsector
;
2362 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2363 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2365 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2367 firstbyte
= cached_buf
[entrypos
];
2370 if (firstbyte
== 0xe5) {
2373 dir
->entrycount
= 0;
2377 if (firstbyte
== 0) {
2380 dir
->entrycount
= 0;
2386 /* longname entry? */
2387 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2388 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2389 longarray
[longs
++] = entrypos
+ sectoridx
;
2392 if ( parse_direntry(entry
,
2393 &cached_buf
[entrypos
]) ) {
2395 /* don't return volume id entry */
2397 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2398 == FAT_ATTR_VOLUME_ID
)
2401 /* replace shortname with longname? */
2404 /* This should be enough to hold any name segment
2406 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2407 /* Add 1 for trailing \0 */
2408 unsigned char longname_utf8segm
[6*4 + 1];
2409 int longname_utf8len
= 0;
2410 /* Temporarily store it */
2411 strcpy(shortname
, entry
->name
);
2414 /* iterate backwards through the dir entries */
2415 for (j
=longs
-1; j
>=0; j
--) {
2416 unsigned char* ptr
= cached_buf
;
2417 int index
= longarray
[j
];
2418 /* current or cached sector? */
2419 if ( sectoridx
>= SECTOR_SIZE
) {
2420 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2421 if ( ( index
>= SECTOR_SIZE
) &&
2422 ( index
< SECTOR_SIZE
*2 ))
2423 ptr
= dir
->sectorcache
[1];
2425 ptr
= dir
->sectorcache
[2];
2428 if ( index
< SECTOR_SIZE
)
2429 ptr
= dir
->sectorcache
[1];
2432 index
&= SECTOR_SIZE
-1;
2435 /* Try to append each segment of the long name.
2436 Check if we'd exceed the buffer.
2437 Also check for FAT padding characters 0xFFFF. */
2438 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2439 longname_utf8segm
) == 0) break;
2440 /* logf("SG: %s, EN: %s", longname_utf8segm,
2442 longname_utf8len
+= strlen(longname_utf8segm
);
2443 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2444 strcat(entry
->name
, longname_utf8segm
);
2448 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
2449 longname_utf8segm
) == 0) break;
2450 /* logf("SG: %s, EN: %s", longname_utf8segm,
2452 longname_utf8len
+= strlen(longname_utf8segm
);
2453 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2454 strcat(entry
->name
, longname_utf8segm
);
2458 if (fat_copy_long_name_segment(ptr
+ index
+ 28, 2,
2459 longname_utf8segm
) == 0) break;
2460 /* logf("SG: %s, EN: %s", longname_utf8segm,
2462 longname_utf8len
+= strlen(longname_utf8segm
);
2463 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2464 strcat(entry
->name
, longname_utf8segm
);
2469 /* Does the utf8-encoded name fit into the entry? */
2470 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2471 /* Take the short DOS name. Need to utf8-encode it
2472 since it may contain chars from the upper half of
2473 the OEM code page which wouldn't be a valid utf8.
2474 Beware: this file will be shown with strange
2475 glyphs in file browser since unicode 0x80 to 0x9F
2476 are control characters. */
2477 logf("SN-DOS: %s", shortname
);
2478 unsigned char *utf8
;
2479 utf8
= iso_decode(shortname
, entry
->name
, -1,
2482 logf("SN: %s", entry
->name
);
2484 /* logf("LN: %s", entry->name);
2485 logf("LNLen: %d (%c)", longname_utf8len,
2497 /* save this sector, for longname use */
2499 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2501 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2502 sectoridx
+= SECTOR_SIZE
;
2508 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2510 #ifndef HAVE_MULTIVOLUME
2511 const int volume
= 0;
2513 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2514 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2517 #ifdef HAVE_MULTIVOLUME
2518 bool fat_ismounted(int volume
)
2520 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);