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 */
176 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
));
177 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
));
178 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
));
179 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,) long secnum
, bool dirty
);
180 static void create_dos_name(const unsigned char *name
, unsigned char *newname
);
181 static void randomize_dos_name(unsigned char *name
);
182 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
);
183 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
, long count
, char* buf
, bool write
);
185 #define FAT_CACHE_SIZE 0x20
186 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
188 struct fat_cache_entry
193 #ifdef HAVE_MULTIVOLUME
194 struct bpb
* fat_vol
; /* shared cache for all volumes */
198 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
199 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
200 static struct mutex cache_mutex
;
202 static long cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
204 #ifndef HAVE_MULTIVOLUME
205 struct bpb
* fat_bpb
= &fat_bpbs
[0];
207 #ifdef HAVE_FAT16SUPPORT
208 /* negative clusters (FAT16 root dir) don't get the 2 offset */
209 int zerocluster
= cluster
< 0 ? 0 : 2;
211 const long zerocluster
= 2;
214 if (cluster
> (long)(fat_bpb
->dataclusters
+ 1))
216 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster
);
220 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
221 + fat_bpb
->firstdatasector
;
224 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
226 #ifndef HAVE_MULTIVOLUME
227 const int volume
= 0;
229 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
231 *size
= fat_bpb
->dataclusters
* fat_bpb
->bpb_secperclus
/ 2;
233 *free
= fat_bpb
->fsinfo
.freecount
* fat_bpb
->bpb_secperclus
/ 2;
240 mutex_init(&cache_mutex
);
242 /* mark the FAT cache as unused */
243 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
245 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
246 fat_cache
[i
].inuse
= false;
247 fat_cache
[i
].dirty
= false;
248 #ifdef HAVE_MULTIVOLUME
249 fat_cache
[i
].fat_vol
= NULL
;
252 #ifdef HAVE_MULTIVOLUME
253 /* mark the possible volumes as not mounted */
254 for (i
=0; i
<NUM_VOLUMES
;i
++)
256 fat_bpbs
[i
].mounted
= false;
261 int fat_mount(IF_MV2(int volume
,) IF_MV2(int drive
,) long startsector
)
263 #ifndef HAVE_MULTIVOLUME
264 const int volume
= 0;
266 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
267 unsigned char buf
[SECTOR_SIZE
];
271 #ifdef HAVE_FAT16SUPPORT
275 /* Read the sector */
276 rc
= ata_read_sectors(IF_MV2(drive
,) startsector
,1,buf
);
279 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
283 memset(fat_bpb
, 0, sizeof(struct bpb
));
284 fat_bpb
->startsector
= startsector
;
285 #ifdef HAVE_MULTIVOLUME
286 fat_bpb
->drive
= drive
;
289 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
290 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
291 /* Sanity check is performed later */
293 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
294 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
295 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
296 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
297 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
298 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
299 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
300 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
301 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
303 /* calculate a few commonly used values */
304 if (fat_bpb
->bpb_fatsz16
!= 0)
305 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
307 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
309 if (fat_bpb
->bpb_totsec16
!= 0)
310 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
312 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
314 #ifdef HAVE_FAT16SUPPORT
315 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
316 if (!fat_bpb
->bpb_bytspersec
)
318 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
319 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
320 #endif /* #ifdef HAVE_FAT16SUPPORT */
322 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
323 #ifdef HAVE_FAT16SUPPORT
326 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
328 /* Determine FAT type */
329 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
330 if (fat_bpb
->bpb_secperclus
)
331 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
337 we are sometimes testing with "illegally small" fat32 images,
338 so we don't use the proper fat32 test case for test code
340 if ( fat_bpb
->bpb_fatsz16
)
342 if ( fat_bpb
->dataclusters
< 65525 )
345 #ifdef HAVE_FAT16SUPPORT
346 fat_bpb
->is_fat16
= true;
347 if (fat_bpb
->dataclusters
< 4085)
349 DEBUGF("This is FAT12. Go away!\n");
352 #else /* #ifdef HAVE_FAT16SUPPORT */
353 DEBUGF("This is not FAT32. Go away!\n");
355 #endif /* #ifndef HAVE_FAT16SUPPORT */
358 #ifdef HAVE_FAT16SUPPORT
359 if (fat_bpb
->is_fat16
)
360 { /* FAT16 specific part of BPB */
362 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
363 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
364 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
365 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
366 /* I assign negative pseudo cluster numbers for the root directory,
367 their range is counted upward until -1. */
368 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data */
369 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
373 #endif /* #ifdef HAVE_FAT16SUPPORT */
374 { /* FAT32 specific part of BPB */
375 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
376 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
377 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,) fat_bpb
->bpb_rootclus
);
380 rc
= bpb_is_sane(IF_MV(fat_bpb
));
383 DEBUGF( "fat_mount() - BPB is not sane\n");
387 #ifdef HAVE_FAT16SUPPORT
388 if (fat_bpb
->is_fat16
)
390 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
391 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
394 #endif /* #ifdef HAVE_FAT16SUPPORT */
396 /* Read the fsinfo sector */
397 rc
= ata_read_sectors(IF_MV2(drive
,)
398 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
401 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
404 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
405 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
408 /* calculate freecount if unset */
409 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
411 fat_recalc_free(IF_MV(volume
));
414 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
415 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
416 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
417 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
418 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
420 #ifdef HAVE_MULTIVOLUME
421 fat_bpb
->mounted
= true;
428 int fat_unmount(int volume
, bool flush
)
431 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
435 rc
= flush_fat(fat_bpb
); /* the clean way, while still alive */
438 { /* volume is not accessible any more, e.g. MMC removed */
440 mutex_lock(&cache_mutex
);
441 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
443 struct fat_cache_entry
*fce
= &fat_cache
[i
];
444 if(fce
->inuse
&& fce
->fat_vol
== fat_bpb
)
446 fce
->inuse
= false; /* discard all from that volume */
450 mutex_unlock(&cache_mutex
);
453 fat_bpb
->mounted
= false;
456 #endif /* #ifdef HAVE_HOTSWAP */
458 void fat_recalc_free(IF_MV_NONVOID(int volume
))
460 #ifndef HAVE_MULTIVOLUME
461 const int volume
= 0;
463 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
466 #ifdef HAVE_FAT16SUPPORT
467 if (fat_bpb
->is_fat16
)
469 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
471 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
472 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
473 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
474 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
477 if (letoh16(fat
[j
]) == 0x0000) {
479 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
480 fat_bpb
->fsinfo
.nextfree
= c
;
486 #endif /* #ifdef HAVE_FAT16SUPPORT */
488 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
490 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
491 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
492 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
493 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
496 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
498 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
499 fat_bpb
->fsinfo
.nextfree
= c
;
504 fat_bpb
->fsinfo
.freecount
= free
;
505 update_fsinfo(IF_MV(fat_bpb
));
508 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
510 #ifndef HAVE_MULTIVOLUME
511 struct bpb
* fat_bpb
= &fat_bpbs
[0];
513 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
515 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
516 fat_bpb
->bpb_bytspersec
);
519 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
> 128L*1024L)
521 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
523 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
524 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
527 if(fat_bpb
->bpb_numfats
!= 2)
529 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
530 fat_bpb
->bpb_numfats
);
532 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
534 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
535 "media type (0x%02x)\n",
538 if(fat_bpb
->last_word
!= 0xaa55)
540 DEBUGF( "bpb_is_sane() - Error: Last word is not "
541 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
545 if (fat_bpb
->fsinfo
.freecount
>
546 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
547 fat_bpb
->bpb_secperclus
)
549 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
550 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
557 static void flush_fat_sector(struct fat_cache_entry
*fce
,
558 unsigned char *sectorbuf
)
563 /* With multivolume, use only the FAT info from the cached sector! */
564 #ifdef HAVE_MULTIVOLUME
565 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
567 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
570 /* Write to the first FAT */
571 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
576 panicf("flush_fat_sector() - Could not write sector %ld"
580 #ifdef HAVE_MULTIVOLUME
581 if(fce
->fat_vol
->bpb_numfats
> 1)
583 if(fat_bpbs
[0].bpb_numfats
> 1)
586 /* Write to the second FAT */
587 #ifdef HAVE_MULTIVOLUME
588 secnum
+= fce
->fat_vol
->fatsize
;
590 secnum
+= fat_bpbs
[0].fatsize
;
592 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
593 secnum
, 1, sectorbuf
);
596 panicf("flush_fat_sector() - Could not write sector %ld"
604 /* Note: The returned pointer is only safely valid until the next
605 task switch! (Any subsequent ata read/write may yield.) */
606 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
607 long fatsector
, bool dirty
)
609 #ifndef HAVE_MULTIVOLUME
610 struct bpb
* fat_bpb
= &fat_bpbs
[0];
612 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
613 int cache_index
= secnum
& FAT_CACHE_MASK
;
614 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
615 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
618 mutex_lock(&cache_mutex
); /* make changes atomic */
620 /* Delete the cache entry if it isn't the sector we want */
621 if(fce
->inuse
&& (fce
->secnum
!= secnum
622 #ifdef HAVE_MULTIVOLUME
623 || fce
->fat_vol
!= fat_bpb
627 /* Write back if it is dirty */
630 flush_fat_sector(fce
, sectorbuf
);
635 /* Load the sector if it is not cached */
638 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
639 secnum
+ fat_bpb
->startsector
,1,
643 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
644 " (error %d)\n", secnum
, rc
);
645 mutex_unlock(&cache_mutex
);
649 fce
->secnum
= secnum
;
650 #ifdef HAVE_MULTIVOLUME
651 fce
->fat_vol
= fat_bpb
;
655 fce
->dirty
= true; /* dirt remains, sticky until flushed */
656 mutex_unlock(&cache_mutex
);
660 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,) unsigned long startcluster
)
662 #ifndef HAVE_MULTIVOLUME
663 struct bpb
* fat_bpb
= &fat_bpbs
[0];
665 unsigned long sector
;
666 unsigned long offset
;
669 #ifdef HAVE_FAT16SUPPORT
670 if (fat_bpb
->is_fat16
)
672 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
673 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
675 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
677 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
678 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
681 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
682 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
683 if (letoh16(fat
[k
]) == 0x0000) {
684 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
685 /* Ignore the reserved clusters 0 & 1, and also
686 cluster numbers out of bounds */
687 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
689 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
690 fat_bpb
->fsinfo
.nextfree
= c
;
698 #endif /* #ifdef HAVE_FAT16SUPPORT */
700 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
701 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
703 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
705 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
706 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
709 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
710 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
711 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
712 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
713 /* Ignore the reserved clusters 0 & 1, and also
714 cluster numbers out of bounds */
715 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
717 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
718 fat_bpb
->fsinfo
.nextfree
= c
;
726 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
727 return 0; /* 0 is an illegal cluster number */
730 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
, unsigned long val
)
732 #ifndef HAVE_MULTIVOLUME
733 struct bpb
* fat_bpb
= &fat_bpbs
[0];
735 #ifdef HAVE_FAT16SUPPORT
736 if (fat_bpb
->is_fat16
)
738 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
739 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
744 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
747 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
750 panicf("Updating reserved FAT entry %ld.\n",entry
);
752 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
755 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
760 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
761 fat_bpb
->fsinfo
.freecount
--;
764 if (letoh16(sec
[offset
]))
765 fat_bpb
->fsinfo
.freecount
++;
768 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb
->fsinfo
.freecount
);
770 sec
[offset
] = htole16(val
);
773 #endif /* #ifdef HAVE_FAT16SUPPORT */
775 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
776 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
779 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
782 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
785 panicf("Updating reserved FAT entry %ld.\n",entry
);
787 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
790 DEBUGF( "update_fat_entry() - Could not cache sector %ld\n", sector
);
795 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
796 fat_bpb
->fsinfo
.freecount
> 0)
797 fat_bpb
->fsinfo
.freecount
--;
800 if (letoh32(sec
[offset
]) & 0x0fffffff)
801 fat_bpb
->fsinfo
.freecount
++;
804 LDEBUGF("update_fat_entry: %ld free clusters\n", fat_bpb
->fsinfo
.freecount
);
806 /* don't change top 4 bits */
807 sec
[offset
] &= htole32(0xf0000000);
808 sec
[offset
] |= htole32(val
& 0x0fffffff);
814 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
816 #ifdef HAVE_FAT16SUPPORT
817 #ifndef HAVE_MULTIVOLUME
818 struct bpb
* fat_bpb
= &fat_bpbs
[0];
820 if (fat_bpb
->is_fat16
)
822 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
823 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
826 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
829 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
833 return letoh16(sec
[offset
]);
836 #endif /* #ifdef HAVE_FAT16SUPPORT */
838 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
839 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
842 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
845 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
849 return letoh32(sec
[offset
]) & 0x0fffffff;
853 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
856 long eof_mark
= FAT_EOF_MARK
;
858 #ifdef HAVE_FAT16SUPPORT
859 #ifndef HAVE_MULTIVOLUME
860 struct bpb
* fat_bpb
= &fat_bpbs
[0];
862 if (fat_bpb
->is_fat16
)
864 eof_mark
&= 0xFFFF; /* only 16 bit */
865 if (cluster
< 0) /* FAT16 root dir */
866 return cluster
+ 1; /* don't use the FAT */
869 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
871 /* is this last cluster in chain? */
872 if ( next_cluster
>= eof_mark
)
878 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
880 #ifndef HAVE_MULTIVOLUME
881 struct bpb
* fat_bpb
= &fat_bpbs
[0];
883 unsigned char fsinfo
[SECTOR_SIZE
];
884 unsigned long* intptr
;
887 #ifdef HAVE_FAT16SUPPORT
888 if (fat_bpb
->is_fat16
)
889 return 0; /* FAT16 has no FsInfo */
890 #endif /* #ifdef HAVE_FAT16SUPPORT */
893 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
894 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
897 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
900 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
901 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
903 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
904 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
906 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
907 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
910 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
917 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
922 LDEBUGF("flush_fat()\n");
924 mutex_lock(&cache_mutex
);
925 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
927 struct fat_cache_entry
*fce
= &fat_cache
[i
];
929 #ifdef HAVE_MULTIVOLUME
930 && fce
->fat_vol
== fat_bpb
934 sec
= fat_cache_sectors
[i
];
935 flush_fat_sector(fce
, sec
);
938 mutex_unlock(&cache_mutex
);
940 rc
= update_fsinfo(IF_MV(fat_bpb
));
947 static void fat_time(unsigned short* date
,
948 unsigned short* time
,
949 unsigned short* tenth
)
952 struct tm
* tm
= get_time();
955 *date
= ((tm
->tm_year
- 80) << 9) |
956 ((tm
->tm_mon
+ 1) << 5) |
960 *time
= (tm
->tm_hour
<< 11) |
965 *tenth
= (tm
->tm_sec
& 1) * 100;
967 /* non-RTC version returns an increment from the supplied time, or a
968 * fixed standard time/date if no time given as input */
969 bool next_day
= false;
975 /* set to 00:15:00 */
980 unsigned short mins
= (*time
>> 5) & 0x003F;
981 unsigned short hours
= (*time
>> 11) & 0x001F;
982 if ((mins
+= 10) >= 60)
992 *time
= (hours
<< 11) | (mins
<< 5);
1000 /* Macros to convert a 2-digit string to a decimal constant.
1001 (YEAR), MONTH and DAY are set by the date command, which outputs
1002 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1003 misinterpretation as an octal constant. */
1004 #define S100(x) 1 ## x
1005 #define C2DIG2DEC(x) (S100(x)-100)
1006 /* set to build date */
1007 *date
= ((YEAR
- 1980) << 9) | (C2DIG2DEC(MONTH
) << 5)
1012 unsigned short day
= *date
& 0x001F;
1013 unsigned short month
= (*date
>> 5) & 0x000F;
1014 unsigned short year
= (*date
>> 9) & 0x007F;
1017 /* do a very simple day increment - never go above 28 days */
1027 *date
= (year
<< 9) | (month
<< 5) | day
;
1033 #endif /* CONFIG_RTC */
1036 static int write_long_name(struct fat_file
* file
,
1037 unsigned int firstentry
,
1038 unsigned int numentries
,
1039 const unsigned char* name
,
1040 const unsigned char* shortname
,
1043 unsigned char buf
[SECTOR_SIZE
];
1044 unsigned char* entry
;
1045 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1046 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1047 unsigned char chksum
= 0;
1048 unsigned int i
, j
=0;
1049 unsigned int nameidx
=0, namelen
= utf8length(name
);
1051 unsigned short name_utf16
[namelen
+ 1];
1053 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1054 file
->firstcluster
, firstentry
, numentries
, name
);
1056 rc
= fat_seek(file
, sector
);
1060 rc
= fat_readwrite(file
, 1, buf
, false);
1064 /* calculate shortname checksum */
1065 for (i
=11; i
>0; i
--)
1066 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1068 /* calc position of last name segment */
1069 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1071 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1072 nameidx
+= NAME_BYTES_PER_ENTRY
);
1074 /* we need to convert the name first */
1075 /* since it is written in reverse order */
1076 for (i
= 0; i
<= namelen
; i
++)
1077 name
= utf8decode(name
, &name_utf16
[i
]);
1079 for (i
=0; i
< numentries
; i
++) {
1081 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1082 /* update current sector */
1083 rc
= fat_seek(file
, sector
);
1087 rc
= fat_readwrite(file
, 1, buf
, true);
1091 /* read next sector */
1092 rc
= fat_readwrite(file
, 1, buf
, false);
1094 LDEBUGF("Failed writing new sector: %d\n",rc
);
1099 memset(buf
, 0, sizeof buf
);
1105 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1107 /* verify this entry is free */
1108 if (entry
[0] && entry
[0] != 0xe5 )
1109 panicf("Dir entry %d in sector %x is not free! "
1110 "%02x %02x %02x %02x",
1112 entry
[0], entry
[1], entry
[2], entry
[3]);
1114 memset(entry
, 0, DIR_ENTRY_SIZE
);
1115 if ( i
+1 < numentries
) {
1116 /* longname entry */
1117 unsigned int k
, l
= nameidx
;
1119 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1121 /* mark this as last long entry */
1122 entry
[FATLONG_ORDER
] |= 0x40;
1124 /* pad name with 0xffff */
1125 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1126 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1127 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1130 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1131 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1132 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1134 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1135 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1136 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1138 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1139 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1140 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1143 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1144 entry
[FATDIR_FSTCLUSLO
] = 0;
1145 entry
[FATLONG_TYPE
] = 0;
1146 entry
[FATLONG_CHKSUM
] = chksum
;
1147 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1150 /* shortname entry */
1151 unsigned short date
=0, time
=0, tenth
=0;
1152 LDEBUGF("Shortname entry: %s\n", shortname
);
1153 strncpy(entry
+ FATDIR_NAME
, shortname
, 11);
1154 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1155 entry
[FATDIR_NTRES
] = 0;
1157 fat_time(&date
, &time
, &tenth
);
1158 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1159 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1160 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1161 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1162 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1163 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1166 nameidx
-= NAME_BYTES_PER_ENTRY
;
1169 /* update last sector */
1170 rc
= fat_seek(file
, sector
);
1174 rc
= fat_readwrite(file
, 1, buf
, true);
1181 static int fat_checkname(const unsigned char* newname
)
1183 static const char invalid_chars
[] = "\"*/:<>?\\|";
1184 int len
= strlen(newname
);
1185 /* More sanity checks are probably needed */
1186 if (len
> 255 || newname
[len
- 1] == '.')
1192 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1199 static int add_dir_entry(struct fat_dir
* dir
,
1200 struct fat_file
* file
,
1205 #ifdef HAVE_MULTIVOLUME
1206 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1208 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1210 unsigned char buf
[SECTOR_SIZE
];
1211 unsigned char shortname
[12];
1213 unsigned int sector
;
1215 int entries_needed
, entries_found
= 0;
1218 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1219 name
, file
->firstcluster
);
1221 /* Don't check dotdirs name for validity */
1222 if (dotdir
== false) {
1223 rc
= fat_checkname(name
);
1225 /* filename is invalid */
1230 #ifdef HAVE_MULTIVOLUME
1231 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1234 /* The "." and ".." directory entries must not be long names */
1237 strncpy(shortname
, name
, 12);
1238 for(i
= strlen(shortname
); i
< 12; i
++)
1243 create_dos_name(name
, shortname
);
1245 /* one dir entry needed for every 13 bytes of filename,
1246 plus one entry for the short name */
1247 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1248 / NAME_BYTES_PER_ENTRY
+ 1;
1254 rc
= fat_seek(&dir
->file
, 0);
1258 /* step 1: search for free entries and check for duplicate shortname */
1259 for (sector
= 0; !done
; sector
++)
1263 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1265 DEBUGF( "add_dir_entry() - Couldn't read dir"
1266 " (error code %d)\n", rc
);
1270 if (rc
== 0) { /* current end of dir reached */
1271 LDEBUGF("End of dir on cluster boundary\n");
1275 /* look for free slots */
1276 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1278 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1280 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1281 LDEBUGF("Found end of dir %d\n",
1282 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1283 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1289 LDEBUGF("Found free entry %d (%d/%d)\n",
1290 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1291 entries_found
, entries_needed
);
1297 /* check that our intended shortname doesn't already exist */
1298 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1299 /* shortname exists already, make a new one */
1300 randomize_dos_name(shortname
);
1301 LDEBUGF("Duplicate shortname, changing to %s\n",
1304 /* name has changed, we need to restart search */
1309 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1310 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1315 /* step 2: extend the dir if necessary */
1318 LDEBUGF("Adding new sector(s) to dir\n");
1319 rc
= fat_seek(&dir
->file
, sector
);
1322 memset(buf
, 0, sizeof buf
);
1324 /* we must clear whole clusters */
1325 for (; (entries_found
< entries_needed
) ||
1326 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1328 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1329 return -5; /* dir too large -- FAT specification */
1331 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1332 if (rc
< 1) /* No more room or something went wrong */
1335 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1338 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1341 /* step 3: add entry */
1342 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1343 LDEBUGF("Adding longname to entry %d in sector %d\n",
1344 firstentry
, sector
);
1346 rc
= write_long_name(&dir
->file
, firstentry
,
1347 entries_needed
, name
, shortname
, is_directory
);
1351 /* remember where the shortname dir entry is located */
1352 file
->direntry
= firstentry
+ entries_needed
- 1;
1353 file
->direntries
= entries_needed
;
1354 file
->dircluster
= dir
->file
.firstcluster
;
1355 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1356 file
->direntry
, file
->direntries
);
1361 static unsigned char char2dos(unsigned char c
, int* randomize
)
1363 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1366 c
= 0; /* Illegal char, remove */
1367 else if (strchr(invalid_chars
, c
) != NULL
)
1369 /* Illegal char, replace */
1371 *randomize
= 1; /* as per FAT spec */
1379 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1385 /* Find extension part */
1386 ext
= strrchr(name
, '.');
1387 if (ext
== name
) /* handle .dotnames */
1390 /* needs to randomize? */
1391 if((ext
&& (strlen(ext
) > 4)) ||
1392 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1396 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1398 unsigned char c
= char2dos(*name
, &randomize
);
1403 /* Pad both name and extension */
1407 if (newname
[0] == 0xe5) /* Special kanji character */
1411 { /* Extension part */
1413 for (i
= 8; *ext
&& (i
< 11); ext
++)
1415 unsigned char c
= char2dos(*ext
, &randomize
);
1422 randomize_dos_name(newname
);
1425 static void randomize_dos_name(unsigned char *name
)
1427 unsigned char* tilde
= NULL
; /* ~ location */
1428 unsigned char* lastpt
= NULL
; /* last point of filename */
1429 unsigned char* nameptr
= name
; /* working copy of name pointer */
1430 unsigned char num
[9]; /* holds number as string */
1438 /* hunt for ~ and where to put it */
1439 if((!tilde
) && (*nameptr
== '~'))
1441 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1447 /* extract current count and increment */
1448 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1449 num
[7-(unsigned int)(tilde
-name
)] = 0;
1450 cnt
= atoi(num
) + 1;
1452 cnt
%= 10000000; /* protection */
1453 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1454 numlen
= strlen(num
); /* required space */
1455 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1456 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1458 memcpy(&name
[offset
], num
, numlen
);
1460 /* in special case of counter overflow: pad with spaces */
1461 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1465 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1467 unsigned char buf
[SECTOR_SIZE
];
1468 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1469 unsigned char* entry
=
1470 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1471 unsigned long* sizeptr
;
1472 unsigned short* clusptr
;
1473 struct fat_file dir
;
1476 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1477 file
->firstcluster
, file
->direntry
, size
);
1479 /* create a temporary file handle for the dir holding this file */
1480 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1484 rc
= fat_seek( &dir
, sector
);
1488 rc
= fat_readwrite(&dir
, 1, buf
, false);
1492 if (!entry
[0] || entry
[0] == 0xe5)
1493 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1495 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1497 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1498 *clusptr
= htole16(file
->firstcluster
>> 16);
1500 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1501 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1503 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1504 *sizeptr
= htole32(size
);
1508 unsigned short time
= 0;
1509 unsigned short date
= 0;
1511 /* get old time to increment from */
1512 unsigned short time
= htole16(*(unsigned short*)(entry
+ FATDIR_WRTTIME
));
1513 unsigned short date
= htole16(*(unsigned short*)(entry
+ FATDIR_WRTDATE
));
1515 fat_time(&date
, &time
, NULL
);
1516 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1517 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1518 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1521 rc
= fat_seek( &dir
, sector
);
1525 rc
= fat_readwrite(&dir
, 1, buf
, true);
1532 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1538 memset(de
, 0, sizeof(struct fat_direntry
));
1539 de
->attr
= buf
[FATDIR_ATTR
];
1540 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1541 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1542 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1543 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1544 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1545 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1546 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1547 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1548 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1549 (the result of the shift is always considered signed) */
1552 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1553 c
= buf
[FATDIR_NAME
];
1554 if (c
== 0x05) /* special kanji char */
1558 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1561 c
= buf
[FATDIR_NAME
+i
];
1563 if (buf
[FATDIR_NAME
+8] != ' ') {
1564 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1565 de
->name
[j
++] = '.';
1566 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1567 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1572 int fat_open(IF_MV2(int volume
,)
1574 struct fat_file
*file
,
1575 const struct fat_dir
* dir
)
1577 file
->firstcluster
= startcluster
;
1578 file
->lastcluster
= startcluster
;
1579 file
->lastsector
= 0;
1580 file
->clusternum
= 0;
1581 file
->sectornum
= 0;
1583 #ifdef HAVE_MULTIVOLUME
1584 file
->volume
= volume
;
1585 /* fixme: remove error check when done */
1586 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1588 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1593 /* remember where the file's dir entry is located */
1595 file
->direntry
= dir
->entry
- 1;
1596 file
->direntries
= dir
->entrycount
;
1597 file
->dircluster
= dir
->file
.firstcluster
;
1599 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1603 int fat_create_file(const char* name
,
1604 struct fat_file
* file
,
1605 struct fat_dir
* dir
)
1609 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1610 rc
= add_dir_entry(dir
, file
, name
, false, false);
1612 file
->firstcluster
= 0;
1613 file
->lastcluster
= 0;
1614 file
->lastsector
= 0;
1615 file
->clusternum
= 0;
1616 file
->sectornum
= 0;
1623 int fat_create_dir(const char* name
,
1624 struct fat_dir
* newdir
,
1625 struct fat_dir
* dir
)
1627 #ifdef HAVE_MULTIVOLUME
1628 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1630 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1632 unsigned char buf
[SECTOR_SIZE
];
1636 struct fat_file dummyfile
;
1638 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1640 memset(newdir
, 0, sizeof(struct fat_dir
));
1641 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1643 /* First, add the entry in the parent directory */
1644 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1648 /* Allocate a new cluster for the directory */
1649 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,) fat_bpb
->fsinfo
.nextfree
);
1650 if(newdir
->file
.firstcluster
== 0)
1653 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1655 /* Clear the entire cluster */
1656 memset(buf
, 0, sizeof buf
);
1657 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1658 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1659 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1664 /* Then add the "." entry */
1665 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1668 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1669 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1671 /* and the ".." entry */
1672 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1676 /* The root cluster is cluster 0 in the ".." entry */
1677 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1678 dummyfile
.firstcluster
= 0;
1680 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1681 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1683 /* Set the firstcluster field in the direntry */
1684 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1686 rc
= flush_fat(IF_MV(fat_bpb
));
1693 int fat_truncate(const struct fat_file
*file
)
1695 /* truncate trailing clusters */
1697 long last
= file
->lastcluster
;
1698 #ifdef HAVE_MULTIVOLUME
1699 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1702 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1704 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1705 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1706 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1708 if (file
->lastcluster
)
1709 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1714 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1717 #ifdef HAVE_MULTIVOLUME
1718 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1720 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1724 if ( file
->firstcluster
) {
1725 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1726 file
->firstcluster
= 0;
1730 if (file
->dircluster
) {
1731 rc
= update_short_entry(file
, size
, attr
);
1736 flush_fat(IF_MV(fat_bpb
));
1739 if ( file
->firstcluster
) {
1741 #ifdef HAVE_MULTIVOLUME
1742 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1744 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1749 for ( next
= file
->firstcluster
; next
;
1750 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1751 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1754 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1755 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1757 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1758 panicf("Cluster chain is too long\n");
1760 panicf("Cluster chain is too short\n");
1767 static int free_direntries(struct fat_file
* file
)
1769 unsigned char buf
[SECTOR_SIZE
];
1770 struct fat_file dir
;
1771 int numentries
= file
->direntries
;
1772 unsigned int entry
= file
->direntry
- numentries
+ 1;
1773 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1777 /* create a temporary file handle for the dir holding this file */
1778 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1782 rc
= fat_seek( &dir
, sector
);
1786 rc
= fat_readwrite(&dir
, 1, buf
, false);
1790 for (i
=0; i
< numentries
; i
++) {
1791 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1792 entry
, i
+1, numentries
);
1793 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1796 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1797 /* flush this sector */
1798 rc
= fat_seek(&dir
, sector
);
1802 rc
= fat_readwrite(&dir
, 1, buf
, true);
1806 if ( i
+1 < numentries
) {
1807 /* read next sector */
1808 rc
= fat_readwrite(&dir
, 1, buf
, false);
1816 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1817 /* flush this sector */
1818 rc
= fat_seek(&dir
, sector
);
1822 rc
= fat_readwrite(&dir
, 1, buf
, true);
1830 int fat_remove(struct fat_file
* file
)
1832 long next
, last
= file
->firstcluster
;
1834 #ifdef HAVE_MULTIVOLUME
1835 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1838 LDEBUGF("fat_remove(%lx)\n",last
);
1841 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1842 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1846 if ( file
->dircluster
) {
1847 rc
= free_direntries(file
);
1852 file
->firstcluster
= 0;
1853 file
->dircluster
= 0;
1855 rc
= flush_fat(IF_MV(fat_bpb
));
1862 int fat_rename(struct fat_file
* file
,
1863 struct fat_dir
* dir
,
1864 const unsigned char* newname
,
1869 struct fat_dir olddir
;
1870 struct fat_file newfile
= *file
;
1871 unsigned char buf
[SECTOR_SIZE
];
1872 unsigned char* entry
= NULL
;
1873 unsigned short* clusptr
= NULL
;
1874 unsigned int parentcluster
;
1875 #ifdef HAVE_MULTIVOLUME
1876 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1878 if (file
->volume
!= dir
->file
.volume
) {
1879 DEBUGF("No rename across volumes!\n");
1883 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1886 if ( !file
->dircluster
) {
1887 DEBUGF("File has no dir cluster!\n");
1891 /* create a temporary file handle */
1892 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1896 /* create new name */
1897 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1901 /* write size and cluster link */
1902 rc
= update_short_entry(&newfile
, size
, attr
);
1906 /* remove old name */
1907 rc
= free_direntries(file
);
1911 rc
= flush_fat(IF_MV(fat_bpb
));
1915 /* if renaming a directory, update the .. entry to make sure
1916 it points to its parent directory (we don't check if it was a move) */
1917 if(FAT_ATTR_DIRECTORY
== attr
) {
1918 /* open the dir that was renamed, we re-use the olddir struct */
1919 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1924 /* get the first sector of the dir */
1925 rc
= fat_seek(&olddir
.file
, 0);
1929 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1933 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1934 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1937 parentcluster
= dir
->file
.firstcluster
;
1939 entry
= buf
+ DIR_ENTRY_SIZE
;
1940 if(strncmp(".. ", entry
, 11))
1942 /* .. entry must be second entry according to FAT spec (p.29) */
1943 DEBUGF("Second dir entry is not double-dot!\n");
1946 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1947 *clusptr
= htole16(parentcluster
>> 16);
1949 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1950 *clusptr
= htole16(parentcluster
& 0xffff);
1952 /* write back this sector */
1953 rc
= fat_seek(&olddir
.file
, 0);
1957 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
1965 static long next_write_cluster(struct fat_file
* file
,
1969 #ifdef HAVE_MULTIVOLUME
1970 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1972 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1977 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
1980 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
1984 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
1985 else if (oldcluster
== 0)
1986 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) fat_bpb
->fsinfo
.nextfree
);
1987 #ifdef HAVE_FAT16SUPPORT
1988 else /* negative, pseudo-cluster of the root dir */
1989 return 0; /* impossible to append something to the root */
1994 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
1996 file
->firstcluster
= cluster
;
1997 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2001 if (fat_bpb
->fsinfo
.freecount
>0)
2002 panicf("There is free space, but find_free_cluster() "
2003 "didn't find it!\n");
2005 DEBUGF("next_write_cluster(): Disk full!\n");
2009 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2013 *newsector
= sector
;
2017 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2018 unsigned long start
, long count
, char* buf
, bool write
)
2020 #ifndef HAVE_MULTIVOLUME
2021 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2025 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2026 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2028 unsigned long firstallowed
;
2029 #ifdef HAVE_FAT16SUPPORT
2030 if (fat_bpb
->is_fat16
)
2031 firstallowed
= fat_bpb
->rootdirsector
;
2034 firstallowed
= fat_bpb
->firstdatasector
;
2036 if (start
< firstallowed
)
2037 panicf("Write %ld before data\n", firstallowed
- start
);
2038 if (start
+ count
> fat_bpb
->totalsectors
)
2039 panicf("Write %ld after data\n",
2040 start
+ count
- fat_bpb
->totalsectors
);
2041 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
2042 start
+ fat_bpb
->startsector
, count
, buf
);
2045 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
2046 start
+ fat_bpb
->startsector
, count
, buf
);
2048 DEBUGF( "transfer() - Couldn't %s sector %lx"
2049 " (error code %d)\n",
2050 write
? "write":"read", start
, rc
);
2057 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2058 void* buf
, bool write
)
2060 #ifdef HAVE_MULTIVOLUME
2061 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2063 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2065 long cluster
= file
->lastcluster
;
2066 long sector
= file
->lastsector
;
2067 long clusternum
= file
->clusternum
;
2068 long numsec
= file
->sectornum
;
2069 bool eof
= file
->eof
;
2070 long first
=0, last
=0;
2074 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2075 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2076 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2077 sector
,numsec
, eof
?1:0);
2082 /* find sequential sectors and write them all at once */
2083 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2085 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2086 long oldcluster
= cluster
;
2088 cluster
= next_write_cluster(file
, cluster
, §or
);
2090 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2091 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2100 /* remember last cluster, in case
2101 we want to append to the file */
2102 cluster
= oldcluster
;
2104 i
= -1; /* Error code */
2115 /* look up first sector of file */
2116 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2118 #ifdef HAVE_FAT16SUPPORT
2119 if (file
->firstcluster
< 0)
2120 { /* FAT16 root dir */
2121 sector
+= fat_bpb
->rootdiroffset
;
2122 numsec
+= fat_bpb
->rootdiroffset
;
2131 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2132 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2133 long count
= last
- first
+ 1;
2134 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2138 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2142 if ((i
== sectorcount
-1) && /* last sector requested */
2145 long count
= sector
- first
+ 1;
2146 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2154 file
->lastcluster
= cluster
;
2155 file
->lastsector
= sector
;
2156 file
->clusternum
= clusternum
;
2157 file
->sectornum
= numsec
;
2160 /* if eof, don't report last block as read/written */
2164 DEBUGF("Sectors written: %ld\n", i
);
2168 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2170 #ifdef HAVE_MULTIVOLUME
2171 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2173 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2175 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2176 long cluster
= file
->firstcluster
;
2179 #ifdef HAVE_FAT16SUPPORT
2180 if (cluster
< 0) /* FAT16 root dir */
2181 seeksector
+= fat_bpb
->rootdiroffset
;
2186 /* we need to find the sector BEFORE the requested, since
2187 the file struct stores the last accessed sector */
2189 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2190 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2192 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2194 cluster
= file
->lastcluster
;
2195 numclusters
-= file
->clusternum
;
2198 for (i
=0; i
<numclusters
; i
++) {
2199 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2201 DEBUGF("Seeking beyond the end of the file! "
2202 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2207 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2213 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2214 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2216 file
->lastcluster
= cluster
;
2217 file
->lastsector
= sector
;
2218 file
->clusternum
= clusternum
;
2219 file
->sectornum
= sectornum
+ 1;
2223 int fat_opendir(IF_MV2(int volume
,)
2224 struct fat_dir
*dir
, unsigned long startcluster
,
2225 const struct fat_dir
*parent_dir
)
2227 #ifdef HAVE_MULTIVOLUME
2228 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2229 /* fixme: remove error check when done */
2230 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2232 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2236 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2243 if (startcluster
== 0)
2244 startcluster
= fat_bpb
->bpb_rootclus
;
2246 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2249 DEBUGF( "fat_opendir() - Couldn't open dir"
2250 " (error code %d)\n", rc
);
2257 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2258 * destination buffer (UTF-8 encoded). Copying is stopped when
2259 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2260 * Trailing \0 is also appended at the end of the UTF8-encoded
2263 * utf16src utf16 (little endian) segment to copy
2264 * utf16count max number of the utf16-characters to copy
2265 * utf8dst where to write UTF8-encoded string to
2267 * returns the number of UTF-16 characters actually copied
2269 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2270 int utf16count
, unsigned char *utf8dst
) {
2272 while ((utf16count
--) > 0) {
2273 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2274 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2277 utf8dst
= utf8encode(ucs
, utf8dst
);
2285 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2290 unsigned char firstbyte
;
2291 /* Long file names are stored in special entries. Each entry holds
2292 up to 13 characters. Names can be max 255 chars (not bytes!) long
2293 hence max 20 entries are required. */
2297 unsigned char* cached_buf
= dir
->sectorcache
[0];
2299 dir
->entrycount
= 0;
2303 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2305 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2312 DEBUGF( "fat_getnext() - Couldn't read dir"
2313 " (error code %d)\n", rc
);
2316 dir
->sector
= dir
->file
.lastsector
;
2319 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2320 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2322 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2324 firstbyte
= cached_buf
[entrypos
];
2327 if (firstbyte
== 0xe5) {
2330 dir
->entrycount
= 0;
2334 if (firstbyte
== 0) {
2337 dir
->entrycount
= 0;
2343 /* longname entry? */
2344 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2345 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2346 longarray
[longs
++] = entrypos
+ sectoridx
;
2349 if ( parse_direntry(entry
,
2350 &cached_buf
[entrypos
]) ) {
2352 /* don't return volume id entry */
2354 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2355 == FAT_ATTR_VOLUME_ID
)
2358 /* replace shortname with longname? */
2361 /* This should be enough to hold any name segment utf8-encoded */
2362 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2363 unsigned char longname_utf8segm
[6*4 + 1]; /* Add 1 for trailing \0 */
2364 int longname_utf8len
= 0;
2366 strcpy(shortname
, entry
->name
); /* Temporarily store it */
2369 /* iterate backwards through the dir entries */
2370 for (j
=longs
-1; j
>=0; j
--) {
2371 unsigned char* ptr
= cached_buf
;
2372 int index
= longarray
[j
];
2373 /* current or cached sector? */
2374 if ( sectoridx
>= SECTOR_SIZE
) {
2375 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2376 if ( ( index
>= SECTOR_SIZE
) &&
2377 ( index
< SECTOR_SIZE
*2 ))
2378 ptr
= dir
->sectorcache
[1];
2380 ptr
= dir
->sectorcache
[2];
2383 if ( index
< SECTOR_SIZE
)
2384 ptr
= dir
->sectorcache
[1];
2387 index
&= SECTOR_SIZE
-1;
2390 /* Try to append each segment of the long name. Check if we'd
2391 exceed the buffer. Also check for FAT padding characters 0xFFFF. */
2392 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2393 longname_utf8segm
) == 0) break;
2394 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2395 longname_utf8len
+= strlen(longname_utf8segm
);
2396 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2397 strcat(entry
->name
, longname_utf8segm
);
2401 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
2402 longname_utf8segm
) == 0) break;
2403 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2404 longname_utf8len
+= strlen(longname_utf8segm
);
2405 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2406 strcat(entry
->name
, longname_utf8segm
);
2410 if (fat_copy_long_name_segment(ptr
+ index
+ 28, 2,
2411 longname_utf8segm
) == 0) break;
2412 // logf("SG: %s, EN: %s", longname_utf8segm, entry->name);
2413 longname_utf8len
+= strlen(longname_utf8segm
);
2414 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2415 strcat(entry
->name
, longname_utf8segm
);
2420 /* Does the utf8-encoded name fit into the entry? */
2421 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2422 /* Take the short DOS name. Need to utf8-encode it since
2423 it may contain chars from the upper half of the OEM
2424 code page which wouldn't be a valid utf8. Beware: this
2425 file will be shown with strange glyphs in file browser
2426 since unicode 0x80 to 0x9F are control characters. */
2427 logf("SN-DOS: %s", shortname
);
2428 unsigned char *utf8
;
2429 utf8
= iso_decode(shortname
, entry
->name
, -1, strlen(shortname
));
2431 logf("SN: %s", entry
->name
);
2433 // logf("LN: %s", entry->name);
2434 // logf("LNLen: %d (%c)", longname_utf8len, entry->name[0]);
2445 /* save this sector, for longname use */
2447 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2449 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2450 sectoridx
+= SECTOR_SIZE
;
2456 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2458 #ifndef HAVE_MULTIVOLUME
2459 const int volume
= 0;
2461 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2462 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2465 #ifdef HAVE_MULTIVOLUME
2466 bool fat_ismounted(int volume
)
2468 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);