1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
29 #include "timefuncs.h"
31 #include "rbunicode.h"
35 #define BYTES2INT16(array,pos) \
36 (array[pos] | (array[pos+1] << 8 ))
37 #define BYTES2INT32(array,pos) \
38 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
39 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
41 #define FATTYPE_FAT12 0
42 #define FATTYPE_FAT16 1
43 #define FATTYPE_FAT32 2
45 /* BPB offsets; generic */
48 #define BPB_BYTSPERSEC 11
49 #define BPB_SECPERCLUS 13
50 #define BPB_RSVDSECCNT 14
51 #define BPB_NUMFATS 16
52 #define BPB_ROOTENTCNT 17
53 #define BPB_TOTSEC16 19
55 #define BPB_FATSZ16 22
56 #define BPB_SECPERTRK 24
57 #define BPB_NUMHEADS 26
58 #define BPB_HIDDSEC 28
59 #define BPB_TOTSEC32 32
63 #define BS_RESERVED1 37
67 #define BS_FILSYSTYPE 54
70 #define BPB_FATSZ32 36
71 #define BPB_EXTFLAGS 40
73 #define BPB_ROOTCLUS 44
75 #define BPB_BKBOOTSEC 50
76 #define BS_32_DRVNUM 64
77 #define BS_32_BOOTSIG 66
78 #define BS_32_VOLID 67
79 #define BS_32_VOLLAB 71
80 #define BS_32_FILSYSTYPE 82
82 #define BPB_LAST_WORD 510
86 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
87 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
88 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
90 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
93 #define FAT_NTRES_LC_NAME 0x08
94 #define FAT_NTRES_LC_EXT 0x10
97 #define FATDIR_ATTR 11
98 #define FATDIR_NTRES 12
99 #define FATDIR_CRTTIMETENTH 13
100 #define FATDIR_CRTTIME 14
101 #define FATDIR_CRTDATE 16
102 #define FATDIR_LSTACCDATE 18
103 #define FATDIR_FSTCLUSHI 20
104 #define FATDIR_WRTTIME 22
105 #define FATDIR_WRTDATE 24
106 #define FATDIR_FSTCLUSLO 26
107 #define FATDIR_FILESIZE 28
109 #define FATLONG_ORDER 0
110 #define FATLONG_TYPE 12
111 #define FATLONG_CHKSUM 13
113 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
114 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
115 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
116 #define DIR_ENTRY_SIZE 32
117 #define NAME_BYTES_PER_ENTRY 13
118 #define FAT_BAD_MARK 0x0ffffff7
119 #define FAT_EOF_MARK 0x0ffffff8
120 #define FAT_LONGNAME_PAD_BYTE 0xff
121 #define FAT_LONGNAME_PAD_UCS 0xffff
124 unsigned long freecount
; /* last known free cluster count */
125 unsigned long nextfree
; /* first cluster to start looking for free
126 clusters, or 0xffffffff for no hint */
129 #define FSINFO_FREECOUNT 488
130 #define FSINFO_NEXTFREE 492
132 /* Note: This struct doesn't hold the raw values after mounting if
133 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
134 * physical sectors. */
137 int bpb_bytspersec
; /* Bytes per sector, typically 512 */
138 unsigned int bpb_secperclus
; /* Sectors per cluster */
139 int bpb_rsvdseccnt
; /* Number of reserved sectors */
140 int bpb_numfats
; /* Number of FAT structures, typically 2 */
141 int bpb_totsec16
; /* Number of sectors on the volume (old 16-bit) */
142 int bpb_media
; /* Media type (typically 0xf0 or 0xf8) */
143 int bpb_fatsz16
; /* Number of used sectors per FAT structure */
144 unsigned long bpb_totsec32
; /* Number of sectors on the volume
146 unsigned int last_word
; /* 0xAA55 */
148 /**** FAT32 specific *****/
153 /* variables for internal use */
154 unsigned long fatsize
;
155 unsigned long totalsectors
;
156 unsigned long rootdirsector
;
157 unsigned long firstdatasector
;
158 unsigned long startsector
;
159 unsigned long dataclusters
;
160 struct fsinfo fsinfo
;
161 #ifdef HAVE_FAT16SUPPORT
162 int bpb_rootentcnt
; /* Number of dir entries in the root */
163 /* internals for FAT16 support */
164 bool is_fat16
; /* true if we mounted a FAT16 partition, false if FAT32 */
165 unsigned int rootdiroffset
; /* sector offset of root dir relative to start
166 * of first pseudo cluster */
167 #endif /* #ifdef HAVE_FAT16SUPPORT */
168 #ifdef HAVE_MULTIVOLUME
169 int drive
; /* on which physical device is this located */
170 bool mounted
; /* flag if this volume is mounted */
174 static struct bpb fat_bpbs
[NUM_VOLUMES
]; /* mounted partition info */
175 static bool initialized
= false;
177 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
));
178 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
));
179 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
));
180 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
181 long secnum
, bool dirty
);
182 static void create_dos_name(const unsigned char *name
, unsigned char *newname
);
183 static void randomize_dos_name(unsigned char *name
);
184 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
185 unsigned long start
);
186 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
,
187 long count
, char* buf
, bool write
);
189 #define FAT_CACHE_SIZE 0x20
190 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
192 struct fat_cache_entry
197 #ifdef HAVE_MULTIVOLUME
198 struct bpb
* fat_vol
; /* shared cache for all volumes */
202 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
203 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
204 static struct mutex cache_mutex NOCACHEBSS_ATTR
;
206 #if defined(HAVE_HOTSWAP) && !defined(HAVE_MMC) /* A better condition ?? */
209 mutex_lock(&cache_mutex
);
212 void fat_unlock(void)
214 mutex_unlock(&cache_mutex
);
218 static long cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
220 #ifndef HAVE_MULTIVOLUME
221 struct bpb
* fat_bpb
= &fat_bpbs
[0];
223 #ifdef HAVE_FAT16SUPPORT
224 /* negative clusters (FAT16 root dir) don't get the 2 offset */
225 int zerocluster
= cluster
< 0 ? 0 : 2;
227 const long zerocluster
= 2;
230 if (cluster
> (long)(fat_bpb
->dataclusters
+ 1))
232 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster
);
236 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
237 + fat_bpb
->firstdatasector
;
240 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
242 #ifndef HAVE_MULTIVOLUME
243 const int volume
= 0;
245 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
247 *size
= fat_bpb
->dataclusters
* fat_bpb
->bpb_secperclus
/ 2;
249 *free
= fat_bpb
->fsinfo
.freecount
* fat_bpb
->bpb_secperclus
/ 2;
259 mutex_init(&cache_mutex
);
262 /* mark the FAT cache as unused */
263 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
265 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
266 fat_cache
[i
].inuse
= false;
267 fat_cache
[i
].dirty
= false;
268 #ifdef HAVE_MULTIVOLUME
269 fat_cache
[i
].fat_vol
= NULL
;
272 #ifdef HAVE_MULTIVOLUME
273 /* mark the possible volumes as not mounted */
274 for (i
=0; i
<NUM_VOLUMES
;i
++)
276 fat_bpbs
[i
].mounted
= false;
281 int fat_mount(IF_MV2(int volume
,) IF_MV2(int drive
,) long startsector
)
283 #ifndef HAVE_MULTIVOLUME
284 const int volume
= 0;
286 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
287 unsigned char buf
[SECTOR_SIZE
];
291 #ifdef HAVE_FAT16SUPPORT
295 /* Read the sector */
296 rc
= ata_read_sectors(IF_MV2(drive
,) startsector
,1,buf
);
299 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
303 memset(fat_bpb
, 0, sizeof(struct bpb
));
304 fat_bpb
->startsector
= startsector
;
305 #ifdef HAVE_MULTIVOLUME
306 fat_bpb
->drive
= drive
;
309 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
310 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
311 /* Sanity check is performed later */
313 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
314 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
315 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
316 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
317 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
318 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
319 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
320 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
321 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
323 /* calculate a few commonly used values */
324 if (fat_bpb
->bpb_fatsz16
!= 0)
325 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
327 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
329 if (fat_bpb
->bpb_totsec16
!= 0)
330 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
332 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
334 #ifdef HAVE_FAT16SUPPORT
335 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
336 if (!fat_bpb
->bpb_bytspersec
)
338 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
339 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
340 #endif /* #ifdef HAVE_FAT16SUPPORT */
342 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
343 #ifdef HAVE_FAT16SUPPORT
346 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
348 /* Determine FAT type */
349 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
350 if (fat_bpb
->bpb_secperclus
)
351 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
357 we are sometimes testing with "illegally small" fat32 images,
358 so we don't use the proper fat32 test case for test code
360 if ( fat_bpb
->bpb_fatsz16
)
362 if ( fat_bpb
->dataclusters
< 65525 )
365 #ifdef HAVE_FAT16SUPPORT
366 fat_bpb
->is_fat16
= true;
367 if (fat_bpb
->dataclusters
< 4085)
369 DEBUGF("This is FAT12. Go away!\n");
372 #else /* #ifdef HAVE_FAT16SUPPORT */
373 DEBUGF("This is not FAT32. Go away!\n");
375 #endif /* #ifndef HAVE_FAT16SUPPORT */
378 #ifdef HAVE_FAT16SUPPORT
379 if (fat_bpb
->is_fat16
)
380 { /* FAT16 specific part of BPB */
382 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
383 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
384 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
385 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
386 /* I assign negative pseudo cluster numbers for the root directory,
387 their range is counted upward until -1. */
388 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data*/
389 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
393 #endif /* #ifdef HAVE_FAT16SUPPORT */
394 { /* FAT32 specific part of BPB */
395 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
396 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
397 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,)
398 fat_bpb
->bpb_rootclus
);
401 rc
= bpb_is_sane(IF_MV(fat_bpb
));
404 DEBUGF( "fat_mount() - BPB is not sane\n");
408 #ifdef HAVE_FAT16SUPPORT
409 if (fat_bpb
->is_fat16
)
411 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
412 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
415 #endif /* #ifdef HAVE_FAT16SUPPORT */
417 /* Read the fsinfo sector */
418 rc
= ata_read_sectors(IF_MV2(drive
,)
419 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
422 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
425 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
426 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
429 /* calculate freecount if unset */
430 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
432 fat_recalc_free(IF_MV(volume
));
435 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
436 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
437 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
438 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
439 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
441 #ifdef HAVE_MULTIVOLUME
442 fat_bpb
->mounted
= true;
449 int fat_unmount(int volume
, bool flush
)
452 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
456 rc
= flush_fat(fat_bpb
); /* the clean way, while still alive */
459 { /* volume is not accessible any more, e.g. MMC removed */
461 mutex_lock(&cache_mutex
);
462 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
464 struct fat_cache_entry
*fce
= &fat_cache
[i
];
465 if(fce
->inuse
&& fce
->fat_vol
== fat_bpb
)
467 fce
->inuse
= false; /* discard all from that volume */
471 mutex_unlock(&cache_mutex
);
474 fat_bpb
->mounted
= false;
477 #endif /* #ifdef HAVE_HOTSWAP */
479 void fat_recalc_free(IF_MV_NONVOID(int volume
))
481 #ifndef HAVE_MULTIVOLUME
482 const int volume
= 0;
484 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
487 #ifdef HAVE_FAT16SUPPORT
488 if (fat_bpb
->is_fat16
)
490 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
492 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
493 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
494 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
495 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
498 if (letoh16(fat
[j
]) == 0x0000) {
500 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
501 fat_bpb
->fsinfo
.nextfree
= c
;
507 #endif /* #ifdef HAVE_FAT16SUPPORT */
509 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
511 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
512 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
513 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
514 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
517 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
519 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
520 fat_bpb
->fsinfo
.nextfree
= c
;
525 fat_bpb
->fsinfo
.freecount
= free
;
526 update_fsinfo(IF_MV(fat_bpb
));
529 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
531 #ifndef HAVE_MULTIVOLUME
532 struct bpb
* fat_bpb
= &fat_bpbs
[0];
534 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
536 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
537 fat_bpb
->bpb_bytspersec
);
540 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
543 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
545 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
546 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
549 if(fat_bpb
->bpb_numfats
!= 2)
551 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
552 fat_bpb
->bpb_numfats
);
554 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
556 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
557 "media type (0x%02x)\n",
560 if(fat_bpb
->last_word
!= 0xaa55)
562 DEBUGF( "bpb_is_sane() - Error: Last word is not "
563 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
567 if (fat_bpb
->fsinfo
.freecount
>
568 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
569 fat_bpb
->bpb_secperclus
)
571 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
572 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
579 static void flush_fat_sector(struct fat_cache_entry
*fce
,
580 unsigned char *sectorbuf
)
585 /* With multivolume, use only the FAT info from the cached sector! */
586 #ifdef HAVE_MULTIVOLUME
587 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
589 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
592 /* Write to the first FAT */
593 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
598 panicf("flush_fat_sector() - Could not write sector %ld"
602 #ifdef HAVE_MULTIVOLUME
603 if(fce
->fat_vol
->bpb_numfats
> 1)
605 if(fat_bpbs
[0].bpb_numfats
> 1)
608 /* Write to the second FAT */
609 #ifdef HAVE_MULTIVOLUME
610 secnum
+= fce
->fat_vol
->fatsize
;
612 secnum
+= fat_bpbs
[0].fatsize
;
614 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
615 secnum
, 1, sectorbuf
);
618 panicf("flush_fat_sector() - Could not write sector %ld"
626 /* Note: The returned pointer is only safely valid until the next
627 task switch! (Any subsequent ata read/write may yield.) */
628 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
629 long fatsector
, bool dirty
)
631 #ifndef HAVE_MULTIVOLUME
632 struct bpb
* fat_bpb
= &fat_bpbs
[0];
634 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
635 int cache_index
= secnum
& FAT_CACHE_MASK
;
636 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
637 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
640 mutex_lock(&cache_mutex
); /* make changes atomic */
642 /* Delete the cache entry if it isn't the sector we want */
643 if(fce
->inuse
&& (fce
->secnum
!= secnum
644 #ifdef HAVE_MULTIVOLUME
645 || fce
->fat_vol
!= fat_bpb
649 /* Write back if it is dirty */
652 flush_fat_sector(fce
, sectorbuf
);
657 /* Load the sector if it is not cached */
660 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
661 secnum
+ fat_bpb
->startsector
,1,
665 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
666 " (error %d)\n", secnum
, rc
);
667 mutex_unlock(&cache_mutex
);
671 fce
->secnum
= secnum
;
672 #ifdef HAVE_MULTIVOLUME
673 fce
->fat_vol
= fat_bpb
;
677 fce
->dirty
= true; /* dirt remains, sticky until flushed */
678 mutex_unlock(&cache_mutex
);
682 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
683 unsigned long startcluster
)
685 #ifndef HAVE_MULTIVOLUME
686 struct bpb
* fat_bpb
= &fat_bpbs
[0];
688 unsigned long sector
;
689 unsigned long offset
;
692 #ifdef HAVE_FAT16SUPPORT
693 if (fat_bpb
->is_fat16
)
695 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
696 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
698 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
700 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
701 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
704 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
705 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
706 if (letoh16(fat
[k
]) == 0x0000) {
707 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
708 /* Ignore the reserved clusters 0 & 1, and also
709 cluster numbers out of bounds */
710 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
712 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
713 fat_bpb
->fsinfo
.nextfree
= c
;
721 #endif /* #ifdef HAVE_FAT16SUPPORT */
723 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
724 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
726 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
728 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
729 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
732 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
733 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
734 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
735 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
736 /* Ignore the reserved clusters 0 & 1, and also
737 cluster numbers out of bounds */
738 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
740 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
741 fat_bpb
->fsinfo
.nextfree
= c
;
749 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
750 return 0; /* 0 is an illegal cluster number */
753 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
756 #ifndef HAVE_MULTIVOLUME
757 struct bpb
* fat_bpb
= &fat_bpbs
[0];
759 #ifdef HAVE_FAT16SUPPORT
760 if (fat_bpb
->is_fat16
)
762 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
763 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
768 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
771 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
774 panicf("Updating reserved FAT entry %ld.\n",entry
);
776 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
779 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
784 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
785 fat_bpb
->fsinfo
.freecount
--;
788 if (letoh16(sec
[offset
]))
789 fat_bpb
->fsinfo
.freecount
++;
792 LDEBUGF("update_fat_entry: %d free clusters\n",
793 fat_bpb
->fsinfo
.freecount
);
795 sec
[offset
] = htole16(val
);
798 #endif /* #ifdef HAVE_FAT16SUPPORT */
800 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
801 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
804 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
807 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
810 panicf("Updating reserved FAT entry %ld.\n",entry
);
812 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
815 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
820 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
821 fat_bpb
->fsinfo
.freecount
> 0)
822 fat_bpb
->fsinfo
.freecount
--;
825 if (letoh32(sec
[offset
]) & 0x0fffffff)
826 fat_bpb
->fsinfo
.freecount
++;
829 LDEBUGF("update_fat_entry: %ld free clusters\n",
830 fat_bpb
->fsinfo
.freecount
);
832 /* don't change top 4 bits */
833 sec
[offset
] &= htole32(0xf0000000);
834 sec
[offset
] |= htole32(val
& 0x0fffffff);
840 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
842 #ifdef HAVE_FAT16SUPPORT
843 #ifndef HAVE_MULTIVOLUME
844 struct bpb
* fat_bpb
= &fat_bpbs
[0];
846 if (fat_bpb
->is_fat16
)
848 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
849 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
852 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
855 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
859 return letoh16(sec
[offset
]);
862 #endif /* #ifdef HAVE_FAT16SUPPORT */
864 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
865 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
868 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
871 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
875 return letoh32(sec
[offset
]) & 0x0fffffff;
879 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
882 long eof_mark
= FAT_EOF_MARK
;
884 #ifdef HAVE_FAT16SUPPORT
885 #ifndef HAVE_MULTIVOLUME
886 struct bpb
* fat_bpb
= &fat_bpbs
[0];
888 if (fat_bpb
->is_fat16
)
890 eof_mark
&= 0xFFFF; /* only 16 bit */
891 if (cluster
< 0) /* FAT16 root dir */
892 return cluster
+ 1; /* don't use the FAT */
895 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
897 /* is this last cluster in chain? */
898 if ( next_cluster
>= eof_mark
)
904 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
906 #ifndef HAVE_MULTIVOLUME
907 struct bpb
* fat_bpb
= &fat_bpbs
[0];
909 unsigned char fsinfo
[SECTOR_SIZE
];
910 unsigned long* intptr
;
913 #ifdef HAVE_FAT16SUPPORT
914 if (fat_bpb
->is_fat16
)
915 return 0; /* FAT16 has no FsInfo */
916 #endif /* #ifdef HAVE_FAT16SUPPORT */
919 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
920 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
923 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
926 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
927 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
929 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
930 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
932 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
933 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
936 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
943 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
948 LDEBUGF("flush_fat()\n");
950 mutex_lock(&cache_mutex
);
951 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
953 struct fat_cache_entry
*fce
= &fat_cache
[i
];
955 #ifdef HAVE_MULTIVOLUME
956 && fce
->fat_vol
== fat_bpb
960 sec
= fat_cache_sectors
[i
];
961 flush_fat_sector(fce
, sec
);
964 mutex_unlock(&cache_mutex
);
966 rc
= update_fsinfo(IF_MV(fat_bpb
));
973 static void fat_time(unsigned short* date
,
974 unsigned short* time
,
975 unsigned short* tenth
)
978 struct tm
* tm
= get_time();
981 *date
= ((tm
->tm_year
- 80) << 9) |
982 ((tm
->tm_mon
+ 1) << 5) |
986 *time
= (tm
->tm_hour
<< 11) |
991 *tenth
= (tm
->tm_sec
& 1) * 100;
993 /* non-RTC version returns an increment from the supplied time, or a
994 * fixed standard time/date if no time given as input */
995 bool next_day
= false;
1001 /* set to 00:15:00 */
1006 unsigned short mins
= (*time
>> 5) & 0x003F;
1007 unsigned short hours
= (*time
>> 11) & 0x001F;
1008 if ((mins
+= 10) >= 60)
1013 if ((++hours
) >= 24)
1018 *time
= (hours
<< 11) | (mins
<< 5);
1026 /* Macros to convert a 2-digit string to a decimal constant.
1027 (YEAR), MONTH and DAY are set by the date command, which outputs
1028 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1029 misinterpretation as an octal constant. */
1030 #define S100(x) 1 ## x
1031 #define C2DIG2DEC(x) (S100(x)-100)
1032 /* set to build date */
1033 *date
= ((YEAR
- 1980) << 9) | (C2DIG2DEC(MONTH
) << 5)
1038 unsigned short day
= *date
& 0x001F;
1039 unsigned short month
= (*date
>> 5) & 0x000F;
1040 unsigned short year
= (*date
>> 9) & 0x007F;
1043 /* do a very simple day increment - never go above 28 days */
1053 *date
= (year
<< 9) | (month
<< 5) | day
;
1059 #endif /* CONFIG_RTC */
1062 static int write_long_name(struct fat_file
* file
,
1063 unsigned int firstentry
,
1064 unsigned int numentries
,
1065 const unsigned char* name
,
1066 const unsigned char* shortname
,
1069 unsigned char buf
[SECTOR_SIZE
];
1070 unsigned char* entry
;
1071 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1072 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1073 unsigned char chksum
= 0;
1074 unsigned int i
, j
=0;
1075 unsigned int nameidx
=0, namelen
= utf8length(name
);
1077 unsigned short name_utf16
[namelen
+ 1];
1079 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1080 file
->firstcluster
, firstentry
, numentries
, name
);
1082 rc
= fat_seek(file
, sector
);
1086 rc
= fat_readwrite(file
, 1, buf
, false);
1090 /* calculate shortname checksum */
1091 for (i
=11; i
>0; i
--)
1092 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1094 /* calc position of last name segment */
1095 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1097 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1098 nameidx
+= NAME_BYTES_PER_ENTRY
);
1100 /* we need to convert the name first */
1101 /* since it is written in reverse order */
1102 for (i
= 0; i
<= namelen
; i
++)
1103 name
= utf8decode(name
, &name_utf16
[i
]);
1105 for (i
=0; i
< numentries
; i
++) {
1107 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1108 /* update current sector */
1109 rc
= fat_seek(file
, sector
);
1113 rc
= fat_readwrite(file
, 1, buf
, true);
1117 /* read next sector */
1118 rc
= fat_readwrite(file
, 1, buf
, false);
1120 LDEBUGF("Failed writing new sector: %d\n",rc
);
1125 memset(buf
, 0, sizeof buf
);
1131 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1133 /* verify this entry is free */
1134 if (entry
[0] && entry
[0] != 0xe5 )
1135 panicf("Dir entry %d in sector %x is not free! "
1136 "%02x %02x %02x %02x",
1138 entry
[0], entry
[1], entry
[2], entry
[3]);
1140 memset(entry
, 0, DIR_ENTRY_SIZE
);
1141 if ( i
+1 < numentries
) {
1142 /* longname entry */
1143 unsigned int k
, l
= nameidx
;
1145 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1147 /* mark this as last long entry */
1148 entry
[FATLONG_ORDER
] |= 0x40;
1150 /* pad name with 0xffff */
1151 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1152 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1153 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1156 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1157 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1158 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1160 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1161 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1162 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1164 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1165 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1166 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1169 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1170 entry
[FATDIR_FSTCLUSLO
] = 0;
1171 entry
[FATLONG_TYPE
] = 0;
1172 entry
[FATLONG_CHKSUM
] = chksum
;
1173 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1176 /* shortname entry */
1177 unsigned short date
=0, time
=0, tenth
=0;
1178 LDEBUGF("Shortname entry: %s\n", shortname
);
1179 strncpy(entry
+ FATDIR_NAME
, shortname
, 11);
1180 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1181 entry
[FATDIR_NTRES
] = 0;
1183 fat_time(&date
, &time
, &tenth
);
1184 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1185 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1186 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1187 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1188 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1189 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1192 nameidx
-= NAME_BYTES_PER_ENTRY
;
1195 /* update last sector */
1196 rc
= fat_seek(file
, sector
);
1200 rc
= fat_readwrite(file
, 1, buf
, true);
1207 static int fat_checkname(const unsigned char* newname
)
1209 static const char invalid_chars
[] = "\"*/:<>?\\|";
1210 int len
= strlen(newname
);
1211 /* More sanity checks are probably needed */
1212 if (len
> 255 || newname
[len
- 1] == '.')
1218 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1222 /* check trailing space(s) */
1223 if(*(--newname
) == ' ')
1229 static int add_dir_entry(struct fat_dir
* dir
,
1230 struct fat_file
* file
,
1235 #ifdef HAVE_MULTIVOLUME
1236 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1238 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1240 unsigned char buf
[SECTOR_SIZE
];
1241 unsigned char shortname
[12];
1243 unsigned int sector
;
1245 int entries_needed
, entries_found
= 0;
1248 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1249 name
, file
->firstcluster
);
1251 /* Don't check dotdirs name for validity */
1252 if (dotdir
== false) {
1253 rc
= fat_checkname(name
);
1255 /* filename is invalid */
1260 #ifdef HAVE_MULTIVOLUME
1261 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1264 /* The "." and ".." directory entries must not be long names */
1267 strncpy(shortname
, name
, 12);
1268 for(i
= strlen(shortname
); i
< 12; i
++)
1273 create_dos_name(name
, shortname
);
1275 /* one dir entry needed for every 13 bytes of filename,
1276 plus one entry for the short name */
1277 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1278 / NAME_BYTES_PER_ENTRY
+ 1;
1284 rc
= fat_seek(&dir
->file
, 0);
1288 /* step 1: search for free entries and check for duplicate shortname */
1289 for (sector
= 0; !done
; sector
++)
1293 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1295 DEBUGF( "add_dir_entry() - Couldn't read dir"
1296 " (error code %d)\n", rc
);
1300 if (rc
== 0) { /* current end of dir reached */
1301 LDEBUGF("End of dir on cluster boundary\n");
1305 /* look for free slots */
1306 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1308 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1310 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1311 LDEBUGF("Found end of dir %d\n",
1312 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1313 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1319 LDEBUGF("Found free entry %d (%d/%d)\n",
1320 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1321 entries_found
, entries_needed
);
1327 /* check that our intended shortname doesn't already exist */
1328 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1329 /* shortname exists already, make a new one */
1330 randomize_dos_name(shortname
);
1331 LDEBUGF("Duplicate shortname, changing to %s\n",
1334 /* name has changed, we need to restart search */
1339 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1340 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1345 /* step 2: extend the dir if necessary */
1348 LDEBUGF("Adding new sector(s) to dir\n");
1349 rc
= fat_seek(&dir
->file
, sector
);
1352 memset(buf
, 0, sizeof buf
);
1354 /* we must clear whole clusters */
1355 for (; (entries_found
< entries_needed
) ||
1356 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1358 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1359 return -5; /* dir too large -- FAT specification */
1361 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1362 if (rc
< 1) /* No more room or something went wrong */
1365 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1368 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1371 /* step 3: add entry */
1372 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1373 LDEBUGF("Adding longname to entry %d in sector %d\n",
1374 firstentry
, sector
);
1376 rc
= write_long_name(&dir
->file
, firstentry
,
1377 entries_needed
, name
, shortname
, is_directory
);
1381 /* remember where the shortname dir entry is located */
1382 file
->direntry
= firstentry
+ entries_needed
- 1;
1383 file
->direntries
= entries_needed
;
1384 file
->dircluster
= dir
->file
.firstcluster
;
1385 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1386 file
->direntry
, file
->direntries
);
1391 static unsigned char char2dos(unsigned char c
, int* randomize
)
1393 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1396 c
= 0; /* Illegal char, remove */
1397 else if (strchr(invalid_chars
, c
) != NULL
)
1399 /* Illegal char, replace */
1401 *randomize
= 1; /* as per FAT spec */
1409 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1415 /* Find extension part */
1416 ext
= strrchr(name
, '.');
1417 if (ext
== name
) /* handle .dotnames */
1420 /* needs to randomize? */
1421 if((ext
&& (strlen(ext
) > 4)) ||
1422 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1426 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1428 unsigned char c
= char2dos(*name
, &randomize
);
1433 /* Pad both name and extension */
1437 if (newname
[0] == 0xe5) /* Special kanji character */
1441 { /* Extension part */
1443 for (i
= 8; *ext
&& (i
< 11); ext
++)
1445 unsigned char c
= char2dos(*ext
, &randomize
);
1452 randomize_dos_name(newname
);
1455 static void randomize_dos_name(unsigned char *name
)
1457 unsigned char* tilde
= NULL
; /* ~ location */
1458 unsigned char* lastpt
= NULL
; /* last point of filename */
1459 unsigned char* nameptr
= name
; /* working copy of name pointer */
1460 unsigned char num
[9]; /* holds number as string */
1468 /* hunt for ~ and where to put it */
1469 if((!tilde
) && (*nameptr
== '~'))
1471 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1477 /* extract current count and increment */
1478 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1479 num
[7-(unsigned int)(tilde
-name
)] = 0;
1480 cnt
= atoi(num
) + 1;
1482 cnt
%= 10000000; /* protection */
1483 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1484 numlen
= strlen(num
); /* required space */
1485 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1486 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1488 memcpy(&name
[offset
], num
, numlen
);
1490 /* in special case of counter overflow: pad with spaces */
1491 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1495 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1497 unsigned char buf
[SECTOR_SIZE
];
1498 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1499 unsigned char* entry
=
1500 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1501 unsigned long* sizeptr
;
1502 unsigned short* clusptr
;
1503 struct fat_file dir
;
1506 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1507 file
->firstcluster
, file
->direntry
, size
);
1509 /* create a temporary file handle for the dir holding this file */
1510 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1514 rc
= fat_seek( &dir
, sector
);
1518 rc
= fat_readwrite(&dir
, 1, buf
, false);
1522 if (!entry
[0] || entry
[0] == 0xe5)
1523 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1525 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1527 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1528 *clusptr
= htole16(file
->firstcluster
>> 16);
1530 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1531 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1533 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1534 *sizeptr
= htole32(size
);
1538 unsigned short time
= 0;
1539 unsigned short date
= 0;
1541 /* get old time to increment from */
1542 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1543 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1545 fat_time(&date
, &time
, NULL
);
1546 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1547 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1548 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1551 rc
= fat_seek( &dir
, sector
);
1555 rc
= fat_readwrite(&dir
, 1, buf
, true);
1562 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1568 memset(de
, 0, sizeof(struct fat_direntry
));
1569 de
->attr
= buf
[FATDIR_ATTR
];
1570 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1571 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1572 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1573 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1574 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1575 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1576 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1577 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1578 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1579 (the result of the shift is always considered signed) */
1582 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1583 c
= buf
[FATDIR_NAME
];
1584 if (c
== 0x05) /* special kanji char */
1588 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1591 c
= buf
[FATDIR_NAME
+i
];
1593 if (buf
[FATDIR_NAME
+8] != ' ') {
1594 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1595 de
->name
[j
++] = '.';
1596 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1597 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1602 int fat_open(IF_MV2(int volume
,)
1604 struct fat_file
*file
,
1605 const struct fat_dir
* dir
)
1607 file
->firstcluster
= startcluster
;
1608 file
->lastcluster
= startcluster
;
1609 file
->lastsector
= 0;
1610 file
->clusternum
= 0;
1611 file
->sectornum
= 0;
1613 #ifdef HAVE_MULTIVOLUME
1614 file
->volume
= volume
;
1615 /* fixme: remove error check when done */
1616 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1618 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1623 /* remember where the file's dir entry is located */
1625 file
->direntry
= dir
->entry
- 1;
1626 file
->direntries
= dir
->entrycount
;
1627 file
->dircluster
= dir
->file
.firstcluster
;
1629 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1633 int fat_create_file(const char* name
,
1634 struct fat_file
* file
,
1635 struct fat_dir
* dir
)
1639 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1640 rc
= add_dir_entry(dir
, file
, name
, false, false);
1642 file
->firstcluster
= 0;
1643 file
->lastcluster
= 0;
1644 file
->lastsector
= 0;
1645 file
->clusternum
= 0;
1646 file
->sectornum
= 0;
1653 int fat_create_dir(const char* name
,
1654 struct fat_dir
* newdir
,
1655 struct fat_dir
* dir
)
1657 #ifdef HAVE_MULTIVOLUME
1658 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1660 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1662 unsigned char buf
[SECTOR_SIZE
];
1666 struct fat_file dummyfile
;
1668 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1670 memset(newdir
, 0, sizeof(struct fat_dir
));
1671 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1673 /* First, add the entry in the parent directory */
1674 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1678 /* Allocate a new cluster for the directory */
1679 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1680 fat_bpb
->fsinfo
.nextfree
);
1681 if(newdir
->file
.firstcluster
== 0)
1684 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1686 /* Clear the entire cluster */
1687 memset(buf
, 0, sizeof buf
);
1688 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1689 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1690 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1695 /* Then add the "." entry */
1696 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1699 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1700 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1702 /* and the ".." entry */
1703 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1707 /* The root cluster is cluster 0 in the ".." entry */
1708 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1709 dummyfile
.firstcluster
= 0;
1711 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1712 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1714 /* Set the firstcluster field in the direntry */
1715 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1717 rc
= flush_fat(IF_MV(fat_bpb
));
1724 int fat_truncate(const struct fat_file
*file
)
1726 /* truncate trailing clusters */
1728 long last
= file
->lastcluster
;
1729 #ifdef HAVE_MULTIVOLUME
1730 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1733 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1735 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1736 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1737 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1739 if (file
->lastcluster
)
1740 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1745 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1748 #ifdef HAVE_MULTIVOLUME
1749 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1751 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1755 if ( file
->firstcluster
) {
1756 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1757 file
->firstcluster
= 0;
1761 if (file
->dircluster
) {
1762 rc
= update_short_entry(file
, size
, attr
);
1767 flush_fat(IF_MV(fat_bpb
));
1770 if ( file
->firstcluster
) {
1772 #ifdef HAVE_MULTIVOLUME
1773 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1775 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1780 for ( next
= file
->firstcluster
; next
;
1781 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1782 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1785 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1786 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1788 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1789 panicf("Cluster chain is too long\n");
1791 panicf("Cluster chain is too short\n");
1798 static int free_direntries(struct fat_file
* file
)
1800 unsigned char buf
[SECTOR_SIZE
];
1801 struct fat_file dir
;
1802 int numentries
= file
->direntries
;
1803 unsigned int entry
= file
->direntry
- numentries
+ 1;
1804 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1808 /* create a temporary file handle for the dir holding this file */
1809 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1813 rc
= fat_seek( &dir
, sector
);
1817 rc
= fat_readwrite(&dir
, 1, buf
, false);
1821 for (i
=0; i
< numentries
; i
++) {
1822 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1823 entry
, i
+1, numentries
);
1824 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1827 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1828 /* flush this sector */
1829 rc
= fat_seek(&dir
, sector
);
1833 rc
= fat_readwrite(&dir
, 1, buf
, true);
1837 if ( i
+1 < numentries
) {
1838 /* read next sector */
1839 rc
= fat_readwrite(&dir
, 1, buf
, false);
1847 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1848 /* flush this sector */
1849 rc
= fat_seek(&dir
, sector
);
1853 rc
= fat_readwrite(&dir
, 1, buf
, true);
1861 int fat_remove(struct fat_file
* file
)
1863 long next
, last
= file
->firstcluster
;
1865 #ifdef HAVE_MULTIVOLUME
1866 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1869 LDEBUGF("fat_remove(%lx)\n",last
);
1872 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1873 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1877 if ( file
->dircluster
) {
1878 rc
= free_direntries(file
);
1883 file
->firstcluster
= 0;
1884 file
->dircluster
= 0;
1886 rc
= flush_fat(IF_MV(fat_bpb
));
1893 int fat_rename(struct fat_file
* file
,
1894 struct fat_dir
* dir
,
1895 const unsigned char* newname
,
1900 struct fat_dir olddir
;
1901 struct fat_file newfile
= *file
;
1902 unsigned char buf
[SECTOR_SIZE
];
1903 unsigned char* entry
= NULL
;
1904 unsigned short* clusptr
= NULL
;
1905 unsigned int parentcluster
;
1906 #ifdef HAVE_MULTIVOLUME
1907 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1909 if (file
->volume
!= dir
->file
.volume
) {
1910 DEBUGF("No rename across volumes!\n");
1914 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1917 if ( !file
->dircluster
) {
1918 DEBUGF("File has no dir cluster!\n");
1922 /* create a temporary file handle */
1923 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1927 /* create new name */
1928 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1932 /* write size and cluster link */
1933 rc
= update_short_entry(&newfile
, size
, attr
);
1937 /* remove old name */
1938 rc
= free_direntries(file
);
1942 rc
= flush_fat(IF_MV(fat_bpb
));
1946 /* if renaming a directory, update the .. entry to make sure
1947 it points to its parent directory (we don't check if it was a move) */
1948 if(FAT_ATTR_DIRECTORY
== attr
) {
1949 /* open the dir that was renamed, we re-use the olddir struct */
1950 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1955 /* get the first sector of the dir */
1956 rc
= fat_seek(&olddir
.file
, 0);
1960 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1964 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1965 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1968 parentcluster
= dir
->file
.firstcluster
;
1970 entry
= buf
+ DIR_ENTRY_SIZE
;
1971 if(strncmp(".. ", entry
, 11))
1973 /* .. entry must be second entry according to FAT spec (p.29) */
1974 DEBUGF("Second dir entry is not double-dot!\n");
1977 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1978 *clusptr
= htole16(parentcluster
>> 16);
1980 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1981 *clusptr
= htole16(parentcluster
& 0xffff);
1983 /* write back this sector */
1984 rc
= fat_seek(&olddir
.file
, 0);
1988 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
1996 static long next_write_cluster(struct fat_file
* file
,
2000 #ifdef HAVE_MULTIVOLUME
2001 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2003 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2008 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
2011 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
2015 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
2016 else if (oldcluster
== 0)
2017 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
2018 fat_bpb
->fsinfo
.nextfree
);
2019 #ifdef HAVE_FAT16SUPPORT
2020 else /* negative, pseudo-cluster of the root dir */
2021 return 0; /* impossible to append something to the root */
2026 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2028 file
->firstcluster
= cluster
;
2029 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2033 if (fat_bpb
->fsinfo
.freecount
>0)
2034 panicf("There is free space, but find_free_cluster() "
2035 "didn't find it!\n");
2037 DEBUGF("next_write_cluster(): Disk full!\n");
2041 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2045 *newsector
= sector
;
2049 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2050 unsigned long start
, long count
, char* buf
, bool write
)
2052 #ifndef HAVE_MULTIVOLUME
2053 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2057 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2058 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2060 unsigned long firstallowed
;
2061 #ifdef HAVE_FAT16SUPPORT
2062 if (fat_bpb
->is_fat16
)
2063 firstallowed
= fat_bpb
->rootdirsector
;
2066 firstallowed
= fat_bpb
->firstdatasector
;
2068 if (start
< firstallowed
)
2069 panicf("Write %ld before data\n", firstallowed
- start
);
2070 if (start
+ count
> fat_bpb
->totalsectors
)
2071 panicf("Write %ld after data\n",
2072 start
+ count
- fat_bpb
->totalsectors
);
2073 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
2074 start
+ fat_bpb
->startsector
, count
, buf
);
2077 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
2078 start
+ fat_bpb
->startsector
, count
, buf
);
2080 DEBUGF( "transfer() - Couldn't %s sector %lx"
2081 " (error code %d)\n",
2082 write
? "write":"read", start
, rc
);
2089 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2090 void* buf
, bool write
)
2092 #ifdef HAVE_MULTIVOLUME
2093 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2095 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2097 long cluster
= file
->lastcluster
;
2098 long sector
= file
->lastsector
;
2099 long clusternum
= file
->clusternum
;
2100 long numsec
= file
->sectornum
;
2101 bool eof
= file
->eof
;
2102 long first
=0, last
=0;
2106 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2107 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2108 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2109 sector
,numsec
, eof
?1:0);
2114 /* find sequential sectors and write them all at once */
2115 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2117 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2118 long oldcluster
= cluster
;
2119 long oldsector
= sector
;
2120 long oldnumsec
= numsec
;
2122 cluster
= next_write_cluster(file
, cluster
, §or
);
2124 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2125 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2134 /* remember last cluster, in case
2135 we want to append to the file */
2137 cluster
= oldcluster
;
2140 i
= -1; /* Error code */
2151 /* look up first sector of file */
2152 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2154 #ifdef HAVE_FAT16SUPPORT
2155 if (file
->firstcluster
< 0)
2156 { /* FAT16 root dir */
2157 sector
+= fat_bpb
->rootdiroffset
;
2158 numsec
+= fat_bpb
->rootdiroffset
;
2167 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2168 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2169 long count
= last
- first
+ 1;
2170 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2174 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2178 if ((i
== sectorcount
-1) && /* last sector requested */
2181 long count
= sector
- first
+ 1;
2182 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2190 file
->lastcluster
= cluster
;
2191 file
->lastsector
= sector
;
2192 file
->clusternum
= clusternum
;
2193 file
->sectornum
= numsec
;
2196 /* if eof, don't report last block as read/written */
2200 DEBUGF("Sectors written: %ld\n", i
);
2204 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2206 #ifdef HAVE_MULTIVOLUME
2207 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2209 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2211 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2212 long cluster
= file
->firstcluster
;
2215 #ifdef HAVE_FAT16SUPPORT
2216 if (cluster
< 0) /* FAT16 root dir */
2217 seeksector
+= fat_bpb
->rootdiroffset
;
2222 /* we need to find the sector BEFORE the requested, since
2223 the file struct stores the last accessed sector */
2225 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2226 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2228 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2230 cluster
= file
->lastcluster
;
2231 numclusters
-= file
->clusternum
;
2234 for (i
=0; i
<numclusters
; i
++) {
2235 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2237 DEBUGF("Seeking beyond the end of the file! "
2238 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2243 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2249 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2250 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2252 file
->lastcluster
= cluster
;
2253 file
->lastsector
= sector
;
2254 file
->clusternum
= clusternum
;
2255 file
->sectornum
= sectornum
+ 1;
2259 int fat_opendir(IF_MV2(int volume
,)
2260 struct fat_dir
*dir
, unsigned long startcluster
,
2261 const struct fat_dir
*parent_dir
)
2263 #ifdef HAVE_MULTIVOLUME
2264 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2265 /* fixme: remove error check when done */
2266 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2268 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2272 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2279 if (startcluster
== 0)
2280 startcluster
= fat_bpb
->bpb_rootclus
;
2282 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2285 DEBUGF( "fat_opendir() - Couldn't open dir"
2286 " (error code %d)\n", rc
);
2293 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2294 * destination buffer (UTF-8 encoded). Copying is stopped when
2295 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2296 * Trailing \0 is also appended at the end of the UTF8-encoded
2299 * utf16src utf16 (little endian) segment to copy
2300 * utf16count max number of the utf16-characters to copy
2301 * utf8dst where to write UTF8-encoded string to
2303 * returns the number of UTF-16 characters actually copied
2305 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2306 int utf16count
, unsigned char *utf8dst
) {
2308 while ((utf16count
--) > 0) {
2309 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2310 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2313 utf8dst
= utf8encode(ucs
, utf8dst
);
2321 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2326 unsigned char firstbyte
;
2327 /* Long file names are stored in special entries. Each entry holds
2328 up to 13 characters. Names can be max 255 chars (not bytes!) long
2329 hence max 20 entries are required. */
2333 unsigned char* cached_buf
= dir
->sectorcache
[0];
2335 dir
->entrycount
= 0;
2339 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2341 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2348 DEBUGF( "fat_getnext() - Couldn't read dir"
2349 " (error code %d)\n", rc
);
2352 dir
->sector
= dir
->file
.lastsector
;
2355 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2356 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2358 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2360 firstbyte
= cached_buf
[entrypos
];
2363 if (firstbyte
== 0xe5) {
2366 dir
->entrycount
= 0;
2370 if (firstbyte
== 0) {
2373 dir
->entrycount
= 0;
2379 /* longname entry? */
2380 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2381 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2382 longarray
[longs
++] = entrypos
+ sectoridx
;
2385 if ( parse_direntry(entry
,
2386 &cached_buf
[entrypos
]) ) {
2388 /* don't return volume id entry */
2390 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2391 == FAT_ATTR_VOLUME_ID
)
2394 /* replace shortname with longname? */
2397 /* This should be enough to hold any name segment
2399 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2400 /* Add 1 for trailing \0 */
2401 unsigned char longname_utf8segm
[6*4 + 1];
2402 int longname_utf8len
= 0;
2403 /* Temporarily store it */
2404 strcpy(shortname
, entry
->name
);
2407 /* iterate backwards through the dir entries */
2408 for (j
=longs
-1; j
>=0; j
--) {
2409 unsigned char* ptr
= cached_buf
;
2410 int index
= longarray
[j
];
2411 /* current or cached sector? */
2412 if ( sectoridx
>= SECTOR_SIZE
) {
2413 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2414 if ( ( index
>= SECTOR_SIZE
) &&
2415 ( index
< SECTOR_SIZE
*2 ))
2416 ptr
= dir
->sectorcache
[1];
2418 ptr
= dir
->sectorcache
[2];
2421 if ( index
< SECTOR_SIZE
)
2422 ptr
= dir
->sectorcache
[1];
2425 index
&= SECTOR_SIZE
-1;
2428 /* Try to append each segment of the long name.
2429 Check if we'd exceed the buffer.
2430 Also check for FAT padding characters 0xFFFF. */
2431 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2432 longname_utf8segm
) == 0) break;
2433 /* logf("SG: %s, EN: %s", longname_utf8segm,
2435 longname_utf8len
+= strlen(longname_utf8segm
);
2436 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2437 strcat(entry
->name
, longname_utf8segm
);
2441 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
2442 longname_utf8segm
) == 0) break;
2443 /* logf("SG: %s, EN: %s", longname_utf8segm,
2445 longname_utf8len
+= strlen(longname_utf8segm
);
2446 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2447 strcat(entry
->name
, longname_utf8segm
);
2451 if (fat_copy_long_name_segment(ptr
+ index
+ 28, 2,
2452 longname_utf8segm
) == 0) break;
2453 /* logf("SG: %s, EN: %s", longname_utf8segm,
2455 longname_utf8len
+= strlen(longname_utf8segm
);
2456 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2457 strcat(entry
->name
, longname_utf8segm
);
2462 /* Does the utf8-encoded name fit into the entry? */
2463 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2464 /* Take the short DOS name. Need to utf8-encode it
2465 since it may contain chars from the upper half of
2466 the OEM code page which wouldn't be a valid utf8.
2467 Beware: this file will be shown with strange
2468 glyphs in file browser since unicode 0x80 to 0x9F
2469 are control characters. */
2470 logf("SN-DOS: %s", shortname
);
2471 unsigned char *utf8
;
2472 utf8
= iso_decode(shortname
, entry
->name
, -1,
2475 logf("SN: %s", entry
->name
);
2477 /* logf("LN: %s", entry->name);
2478 logf("LNLen: %d (%c)", longname_utf8len,
2490 /* save this sector, for longname use */
2492 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2494 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2495 sectoridx
+= SECTOR_SIZE
;
2501 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2503 #ifndef HAVE_MULTIVOLUME
2504 const int volume
= 0;
2506 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2507 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2510 #ifdef HAVE_MULTIVOLUME
2511 bool fat_ismounted(int volume
)
2513 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);