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 SHAREDBSS_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 #ifdef HAVE_PRIORITY_SCHEDULING
263 /* Disable this because it is dangerous due to the assumption that
264 * mutex_unlock won't yield */
265 mutex_set_preempt(&cache_mutex
, false);
268 /* mark the FAT cache as unused */
269 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
271 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
272 fat_cache
[i
].inuse
= false;
273 fat_cache
[i
].dirty
= false;
274 #ifdef HAVE_MULTIVOLUME
275 fat_cache
[i
].fat_vol
= NULL
;
278 #ifdef HAVE_MULTIVOLUME
279 /* mark the possible volumes as not mounted */
280 for (i
=0; i
<NUM_VOLUMES
;i
++)
282 fat_bpbs
[i
].mounted
= false;
287 int fat_mount(IF_MV2(int volume
,) IF_MV2(int drive
,) long startsector
)
289 #ifndef HAVE_MULTIVOLUME
290 const int volume
= 0;
292 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
293 unsigned char buf
[SECTOR_SIZE
];
297 #ifdef HAVE_FAT16SUPPORT
301 /* Read the sector */
302 rc
= ata_read_sectors(IF_MV2(drive
,) startsector
,1,buf
);
305 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
309 memset(fat_bpb
, 0, sizeof(struct bpb
));
310 fat_bpb
->startsector
= startsector
;
311 #ifdef HAVE_MULTIVOLUME
312 fat_bpb
->drive
= drive
;
315 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
316 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
317 /* Sanity check is performed later */
319 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
320 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
321 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
322 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
323 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
324 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
325 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
326 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
327 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
329 /* calculate a few commonly used values */
330 if (fat_bpb
->bpb_fatsz16
!= 0)
331 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
333 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
335 if (fat_bpb
->bpb_totsec16
!= 0)
336 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
338 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
340 #ifdef HAVE_FAT16SUPPORT
341 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
342 if (!fat_bpb
->bpb_bytspersec
)
344 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
345 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
346 #endif /* #ifdef HAVE_FAT16SUPPORT */
348 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
349 #ifdef HAVE_FAT16SUPPORT
352 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
354 /* Determine FAT type */
355 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
356 if (fat_bpb
->bpb_secperclus
)
357 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
363 we are sometimes testing with "illegally small" fat32 images,
364 so we don't use the proper fat32 test case for test code
366 if ( fat_bpb
->bpb_fatsz16
)
368 if ( fat_bpb
->dataclusters
< 65525 )
371 #ifdef HAVE_FAT16SUPPORT
372 fat_bpb
->is_fat16
= true;
373 if (fat_bpb
->dataclusters
< 4085)
375 DEBUGF("This is FAT12. Go away!\n");
378 #else /* #ifdef HAVE_FAT16SUPPORT */
379 DEBUGF("This is not FAT32. Go away!\n");
381 #endif /* #ifndef HAVE_FAT16SUPPORT */
384 #ifdef HAVE_FAT16SUPPORT
385 if (fat_bpb
->is_fat16
)
386 { /* FAT16 specific part of BPB */
388 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
389 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
390 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
391 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
392 /* I assign negative pseudo cluster numbers for the root directory,
393 their range is counted upward until -1. */
394 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data*/
395 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
399 #endif /* #ifdef HAVE_FAT16SUPPORT */
400 { /* FAT32 specific part of BPB */
401 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
402 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
403 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,)
404 fat_bpb
->bpb_rootclus
);
407 rc
= bpb_is_sane(IF_MV(fat_bpb
));
410 DEBUGF( "fat_mount() - BPB is not sane\n");
414 #ifdef HAVE_FAT16SUPPORT
415 if (fat_bpb
->is_fat16
)
417 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
418 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
421 #endif /* #ifdef HAVE_FAT16SUPPORT */
423 /* Read the fsinfo sector */
424 rc
= ata_read_sectors(IF_MV2(drive
,)
425 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
428 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
431 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
432 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
435 /* calculate freecount if unset */
436 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
438 fat_recalc_free(IF_MV(volume
));
441 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
442 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
443 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
444 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
445 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
447 #ifdef HAVE_MULTIVOLUME
448 fat_bpb
->mounted
= true;
455 int fat_unmount(int volume
, bool flush
)
458 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
462 rc
= flush_fat(fat_bpb
); /* the clean way, while still alive */
465 { /* volume is not accessible any more, e.g. MMC removed */
467 mutex_lock(&cache_mutex
);
468 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
470 struct fat_cache_entry
*fce
= &fat_cache
[i
];
471 if(fce
->inuse
&& fce
->fat_vol
== fat_bpb
)
473 fce
->inuse
= false; /* discard all from that volume */
477 mutex_unlock(&cache_mutex
);
480 fat_bpb
->mounted
= false;
483 #endif /* #ifdef HAVE_HOTSWAP */
485 void fat_recalc_free(IF_MV_NONVOID(int volume
))
487 #ifndef HAVE_MULTIVOLUME
488 const int volume
= 0;
490 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
493 #ifdef HAVE_FAT16SUPPORT
494 if (fat_bpb
->is_fat16
)
496 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
498 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
499 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
500 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
501 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
504 if (letoh16(fat
[j
]) == 0x0000) {
506 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
507 fat_bpb
->fsinfo
.nextfree
= c
;
513 #endif /* #ifdef HAVE_FAT16SUPPORT */
515 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
517 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
518 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
519 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
520 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
523 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
525 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
526 fat_bpb
->fsinfo
.nextfree
= c
;
531 fat_bpb
->fsinfo
.freecount
= free
;
532 update_fsinfo(IF_MV(fat_bpb
));
535 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
537 #ifndef HAVE_MULTIVOLUME
538 struct bpb
* fat_bpb
= &fat_bpbs
[0];
540 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
542 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
543 fat_bpb
->bpb_bytspersec
);
546 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
549 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
551 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
552 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
555 if(fat_bpb
->bpb_numfats
!= 2)
557 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
558 fat_bpb
->bpb_numfats
);
560 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
562 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
563 "media type (0x%02x)\n",
566 if(fat_bpb
->last_word
!= 0xaa55)
568 DEBUGF( "bpb_is_sane() - Error: Last word is not "
569 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
573 if (fat_bpb
->fsinfo
.freecount
>
574 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
575 fat_bpb
->bpb_secperclus
)
577 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
578 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
585 static void flush_fat_sector(struct fat_cache_entry
*fce
,
586 unsigned char *sectorbuf
)
591 /* With multivolume, use only the FAT info from the cached sector! */
592 #ifdef HAVE_MULTIVOLUME
593 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
595 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
598 /* Write to the first FAT */
599 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
604 panicf("flush_fat_sector() - Could not write sector %ld"
608 #ifdef HAVE_MULTIVOLUME
609 if(fce
->fat_vol
->bpb_numfats
> 1)
611 if(fat_bpbs
[0].bpb_numfats
> 1)
614 /* Write to the second FAT */
615 #ifdef HAVE_MULTIVOLUME
616 secnum
+= fce
->fat_vol
->fatsize
;
618 secnum
+= fat_bpbs
[0].fatsize
;
620 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
621 secnum
, 1, sectorbuf
);
624 panicf("flush_fat_sector() - Could not write sector %ld"
632 /* Note: The returned pointer is only safely valid until the next
633 task switch! (Any subsequent ata read/write may yield.) */
634 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
635 long fatsector
, bool dirty
)
637 #ifndef HAVE_MULTIVOLUME
638 struct bpb
* fat_bpb
= &fat_bpbs
[0];
640 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
641 int cache_index
= secnum
& FAT_CACHE_MASK
;
642 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
643 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
646 mutex_lock(&cache_mutex
); /* make changes atomic */
648 /* Delete the cache entry if it isn't the sector we want */
649 if(fce
->inuse
&& (fce
->secnum
!= secnum
650 #ifdef HAVE_MULTIVOLUME
651 || fce
->fat_vol
!= fat_bpb
655 /* Write back if it is dirty */
658 flush_fat_sector(fce
, sectorbuf
);
663 /* Load the sector if it is not cached */
666 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
667 secnum
+ fat_bpb
->startsector
,1,
671 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
672 " (error %d)\n", secnum
, rc
);
673 mutex_unlock(&cache_mutex
);
677 fce
->secnum
= secnum
;
678 #ifdef HAVE_MULTIVOLUME
679 fce
->fat_vol
= fat_bpb
;
683 fce
->dirty
= true; /* dirt remains, sticky until flushed */
684 mutex_unlock(&cache_mutex
);
688 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
689 unsigned long startcluster
)
691 #ifndef HAVE_MULTIVOLUME
692 struct bpb
* fat_bpb
= &fat_bpbs
[0];
694 unsigned long sector
;
695 unsigned long offset
;
698 #ifdef HAVE_FAT16SUPPORT
699 if (fat_bpb
->is_fat16
)
701 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
702 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
704 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
706 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
707 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
710 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
711 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
712 if (letoh16(fat
[k
]) == 0x0000) {
713 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
714 /* Ignore the reserved clusters 0 & 1, and also
715 cluster numbers out of bounds */
716 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
718 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
719 fat_bpb
->fsinfo
.nextfree
= c
;
727 #endif /* #ifdef HAVE_FAT16SUPPORT */
729 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
730 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
732 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
734 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
735 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
738 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
739 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
740 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
741 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
742 /* Ignore the reserved clusters 0 & 1, and also
743 cluster numbers out of bounds */
744 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
746 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
747 fat_bpb
->fsinfo
.nextfree
= c
;
755 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
756 return 0; /* 0 is an illegal cluster number */
759 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
762 #ifndef HAVE_MULTIVOLUME
763 struct bpb
* fat_bpb
= &fat_bpbs
[0];
765 #ifdef HAVE_FAT16SUPPORT
766 if (fat_bpb
->is_fat16
)
768 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
769 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
774 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
777 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
780 panicf("Updating reserved FAT entry %ld.\n",entry
);
782 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
785 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
790 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
791 fat_bpb
->fsinfo
.freecount
--;
794 if (letoh16(sec
[offset
]))
795 fat_bpb
->fsinfo
.freecount
++;
798 LDEBUGF("update_fat_entry: %d free clusters\n",
799 fat_bpb
->fsinfo
.freecount
);
801 sec
[offset
] = htole16(val
);
804 #endif /* #ifdef HAVE_FAT16SUPPORT */
806 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
807 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
810 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
813 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
816 panicf("Updating reserved FAT entry %ld.\n",entry
);
818 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
821 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
826 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
827 fat_bpb
->fsinfo
.freecount
> 0)
828 fat_bpb
->fsinfo
.freecount
--;
831 if (letoh32(sec
[offset
]) & 0x0fffffff)
832 fat_bpb
->fsinfo
.freecount
++;
835 LDEBUGF("update_fat_entry: %ld free clusters\n",
836 fat_bpb
->fsinfo
.freecount
);
838 /* don't change top 4 bits */
839 sec
[offset
] &= htole32(0xf0000000);
840 sec
[offset
] |= htole32(val
& 0x0fffffff);
846 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
848 #ifdef HAVE_FAT16SUPPORT
849 #ifndef HAVE_MULTIVOLUME
850 struct bpb
* fat_bpb
= &fat_bpbs
[0];
852 if (fat_bpb
->is_fat16
)
854 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
855 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
858 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
861 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
865 return letoh16(sec
[offset
]);
868 #endif /* #ifdef HAVE_FAT16SUPPORT */
870 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
871 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
874 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
877 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
881 return letoh32(sec
[offset
]) & 0x0fffffff;
885 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
888 long eof_mark
= FAT_EOF_MARK
;
890 #ifdef HAVE_FAT16SUPPORT
891 #ifndef HAVE_MULTIVOLUME
892 struct bpb
* fat_bpb
= &fat_bpbs
[0];
894 if (fat_bpb
->is_fat16
)
896 eof_mark
&= 0xFFFF; /* only 16 bit */
897 if (cluster
< 0) /* FAT16 root dir */
898 return cluster
+ 1; /* don't use the FAT */
901 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
903 /* is this last cluster in chain? */
904 if ( next_cluster
>= eof_mark
)
910 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
912 #ifndef HAVE_MULTIVOLUME
913 struct bpb
* fat_bpb
= &fat_bpbs
[0];
915 unsigned char fsinfo
[SECTOR_SIZE
];
916 unsigned long* intptr
;
919 #ifdef HAVE_FAT16SUPPORT
920 if (fat_bpb
->is_fat16
)
921 return 0; /* FAT16 has no FsInfo */
922 #endif /* #ifdef HAVE_FAT16SUPPORT */
925 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
926 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
929 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
932 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
933 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
935 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
936 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
938 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
939 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
942 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
949 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
954 LDEBUGF("flush_fat()\n");
956 mutex_lock(&cache_mutex
);
957 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
959 struct fat_cache_entry
*fce
= &fat_cache
[i
];
961 #ifdef HAVE_MULTIVOLUME
962 && fce
->fat_vol
== fat_bpb
966 sec
= fat_cache_sectors
[i
];
967 flush_fat_sector(fce
, sec
);
970 mutex_unlock(&cache_mutex
);
972 rc
= update_fsinfo(IF_MV(fat_bpb
));
979 static void fat_time(unsigned short* date
,
980 unsigned short* time
,
981 unsigned short* tenth
)
984 struct tm
* tm
= get_time();
987 *date
= ((tm
->tm_year
- 80) << 9) |
988 ((tm
->tm_mon
+ 1) << 5) |
992 *time
= (tm
->tm_hour
<< 11) |
997 *tenth
= (tm
->tm_sec
& 1) * 100;
999 /* non-RTC version returns an increment from the supplied time, or a
1000 * fixed standard time/date if no time given as input */
1001 bool next_day
= false;
1007 /* set to 00:15:00 */
1012 unsigned short mins
= (*time
>> 5) & 0x003F;
1013 unsigned short hours
= (*time
>> 11) & 0x001F;
1014 if ((mins
+= 10) >= 60)
1019 if ((++hours
) >= 24)
1024 *time
= (hours
<< 11) | (mins
<< 5);
1032 /* Macros to convert a 2-digit string to a decimal constant.
1033 (YEAR), MONTH and DAY are set by the date command, which outputs
1034 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1035 misinterpretation as an octal constant. */
1036 #define S100(x) 1 ## x
1037 #define C2DIG2DEC(x) (S100(x)-100)
1038 /* set to build date */
1039 *date
= ((YEAR
- 1980) << 9) | (C2DIG2DEC(MONTH
) << 5)
1044 unsigned short day
= *date
& 0x001F;
1045 unsigned short month
= (*date
>> 5) & 0x000F;
1046 unsigned short year
= (*date
>> 9) & 0x007F;
1049 /* do a very simple day increment - never go above 28 days */
1059 *date
= (year
<< 9) | (month
<< 5) | day
;
1065 #endif /* CONFIG_RTC */
1068 static int write_long_name(struct fat_file
* file
,
1069 unsigned int firstentry
,
1070 unsigned int numentries
,
1071 const unsigned char* name
,
1072 const unsigned char* shortname
,
1075 unsigned char buf
[SECTOR_SIZE
];
1076 unsigned char* entry
;
1077 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1078 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1079 unsigned char chksum
= 0;
1080 unsigned int i
, j
=0;
1081 unsigned int nameidx
=0, namelen
= utf8length(name
);
1083 unsigned short name_utf16
[namelen
+ 1];
1085 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1086 file
->firstcluster
, firstentry
, numentries
, name
);
1088 rc
= fat_seek(file
, sector
);
1092 rc
= fat_readwrite(file
, 1, buf
, false);
1096 /* calculate shortname checksum */
1097 for (i
=11; i
>0; i
--)
1098 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1100 /* calc position of last name segment */
1101 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1103 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1104 nameidx
+= NAME_BYTES_PER_ENTRY
);
1106 /* we need to convert the name first */
1107 /* since it is written in reverse order */
1108 for (i
= 0; i
<= namelen
; i
++)
1109 name
= utf8decode(name
, &name_utf16
[i
]);
1111 for (i
=0; i
< numentries
; i
++) {
1113 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1114 /* update current sector */
1115 rc
= fat_seek(file
, sector
);
1119 rc
= fat_readwrite(file
, 1, buf
, true);
1123 /* read next sector */
1124 rc
= fat_readwrite(file
, 1, buf
, false);
1126 LDEBUGF("Failed writing new sector: %d\n",rc
);
1131 memset(buf
, 0, sizeof buf
);
1137 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1139 /* verify this entry is free */
1140 if (entry
[0] && entry
[0] != 0xe5 )
1141 panicf("Dir entry %d in sector %x is not free! "
1142 "%02x %02x %02x %02x",
1144 entry
[0], entry
[1], entry
[2], entry
[3]);
1146 memset(entry
, 0, DIR_ENTRY_SIZE
);
1147 if ( i
+1 < numentries
) {
1148 /* longname entry */
1149 unsigned int k
, l
= nameidx
;
1151 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1153 /* mark this as last long entry */
1154 entry
[FATLONG_ORDER
] |= 0x40;
1156 /* pad name with 0xffff */
1157 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1158 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1159 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1162 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1163 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1164 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1166 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1167 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1168 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1170 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1171 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1172 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1175 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1176 entry
[FATDIR_FSTCLUSLO
] = 0;
1177 entry
[FATLONG_TYPE
] = 0;
1178 entry
[FATLONG_CHKSUM
] = chksum
;
1179 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1182 /* shortname entry */
1183 unsigned short date
=0, time
=0, tenth
=0;
1184 LDEBUGF("Shortname entry: %s\n", shortname
);
1185 strncpy(entry
+ FATDIR_NAME
, shortname
, 11);
1186 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1187 entry
[FATDIR_NTRES
] = 0;
1189 fat_time(&date
, &time
, &tenth
);
1190 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1191 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1192 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1193 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1194 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1195 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1198 nameidx
-= NAME_BYTES_PER_ENTRY
;
1201 /* update last sector */
1202 rc
= fat_seek(file
, sector
);
1206 rc
= fat_readwrite(file
, 1, buf
, true);
1213 static int fat_checkname(const unsigned char* newname
)
1215 static const char invalid_chars
[] = "\"*/:<>?\\|";
1216 int len
= strlen(newname
);
1217 /* More sanity checks are probably needed */
1218 if (len
> 255 || newname
[len
- 1] == '.')
1224 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1228 /* check trailing space(s) */
1229 if(*(--newname
) == ' ')
1235 static int add_dir_entry(struct fat_dir
* dir
,
1236 struct fat_file
* file
,
1241 #ifdef HAVE_MULTIVOLUME
1242 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1244 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1246 unsigned char buf
[SECTOR_SIZE
];
1247 unsigned char shortname
[12];
1249 unsigned int sector
;
1251 int entries_needed
, entries_found
= 0;
1254 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1255 name
, file
->firstcluster
);
1257 /* Don't check dotdirs name for validity */
1258 if (dotdir
== false) {
1259 rc
= fat_checkname(name
);
1261 /* filename is invalid */
1266 #ifdef HAVE_MULTIVOLUME
1267 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1270 /* The "." and ".." directory entries must not be long names */
1273 strncpy(shortname
, name
, 12);
1274 for(i
= strlen(shortname
); i
< 12; i
++)
1279 create_dos_name(name
, shortname
);
1281 /* one dir entry needed for every 13 bytes of filename,
1282 plus one entry for the short name */
1283 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1284 / NAME_BYTES_PER_ENTRY
+ 1;
1290 rc
= fat_seek(&dir
->file
, 0);
1294 /* step 1: search for free entries and check for duplicate shortname */
1295 for (sector
= 0; !done
; sector
++)
1299 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1301 DEBUGF( "add_dir_entry() - Couldn't read dir"
1302 " (error code %d)\n", rc
);
1306 if (rc
== 0) { /* current end of dir reached */
1307 LDEBUGF("End of dir on cluster boundary\n");
1311 /* look for free slots */
1312 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1314 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1316 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1317 LDEBUGF("Found end of dir %d\n",
1318 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1319 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1325 LDEBUGF("Found free entry %d (%d/%d)\n",
1326 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1327 entries_found
, entries_needed
);
1333 /* check that our intended shortname doesn't already exist */
1334 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1335 /* shortname exists already, make a new one */
1336 randomize_dos_name(shortname
);
1337 LDEBUGF("Duplicate shortname, changing to %s\n",
1340 /* name has changed, we need to restart search */
1345 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1346 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1351 /* step 2: extend the dir if necessary */
1354 LDEBUGF("Adding new sector(s) to dir\n");
1355 rc
= fat_seek(&dir
->file
, sector
);
1358 memset(buf
, 0, sizeof buf
);
1360 /* we must clear whole clusters */
1361 for (; (entries_found
< entries_needed
) ||
1362 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1364 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1365 return -5; /* dir too large -- FAT specification */
1367 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1368 if (rc
< 1) /* No more room or something went wrong */
1371 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1374 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1377 /* step 3: add entry */
1378 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1379 LDEBUGF("Adding longname to entry %d in sector %d\n",
1380 firstentry
, sector
);
1382 rc
= write_long_name(&dir
->file
, firstentry
,
1383 entries_needed
, name
, shortname
, is_directory
);
1387 /* remember where the shortname dir entry is located */
1388 file
->direntry
= firstentry
+ entries_needed
- 1;
1389 file
->direntries
= entries_needed
;
1390 file
->dircluster
= dir
->file
.firstcluster
;
1391 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1392 file
->direntry
, file
->direntries
);
1397 static unsigned char char2dos(unsigned char c
, int* randomize
)
1399 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1402 c
= 0; /* Illegal char, remove */
1403 else if (strchr(invalid_chars
, c
) != NULL
)
1405 /* Illegal char, replace */
1407 *randomize
= 1; /* as per FAT spec */
1415 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1421 /* Find extension part */
1422 ext
= strrchr(name
, '.');
1423 if (ext
== name
) /* handle .dotnames */
1426 /* needs to randomize? */
1427 if((ext
&& (strlen(ext
) > 4)) ||
1428 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1432 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1434 unsigned char c
= char2dos(*name
, &randomize
);
1439 /* Pad both name and extension */
1443 if (newname
[0] == 0xe5) /* Special kanji character */
1447 { /* Extension part */
1449 for (i
= 8; *ext
&& (i
< 11); ext
++)
1451 unsigned char c
= char2dos(*ext
, &randomize
);
1458 randomize_dos_name(newname
);
1461 static void randomize_dos_name(unsigned char *name
)
1463 unsigned char* tilde
= NULL
; /* ~ location */
1464 unsigned char* lastpt
= NULL
; /* last point of filename */
1465 unsigned char* nameptr
= name
; /* working copy of name pointer */
1466 unsigned char num
[9]; /* holds number as string */
1474 /* hunt for ~ and where to put it */
1475 if((!tilde
) && (*nameptr
== '~'))
1477 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1483 /* extract current count and increment */
1484 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1485 num
[7-(unsigned int)(tilde
-name
)] = 0;
1486 cnt
= atoi(num
) + 1;
1488 cnt
%= 10000000; /* protection */
1489 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1490 numlen
= strlen(num
); /* required space */
1491 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1492 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1494 memcpy(&name
[offset
], num
, numlen
);
1496 /* in special case of counter overflow: pad with spaces */
1497 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1501 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1503 unsigned char buf
[SECTOR_SIZE
];
1504 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1505 unsigned char* entry
=
1506 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1507 unsigned long* sizeptr
;
1508 unsigned short* clusptr
;
1509 struct fat_file dir
;
1512 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1513 file
->firstcluster
, file
->direntry
, size
);
1515 /* create a temporary file handle for the dir holding this file */
1516 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1520 rc
= fat_seek( &dir
, sector
);
1524 rc
= fat_readwrite(&dir
, 1, buf
, false);
1528 if (!entry
[0] || entry
[0] == 0xe5)
1529 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1531 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1533 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1534 *clusptr
= htole16(file
->firstcluster
>> 16);
1536 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1537 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1539 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1540 *sizeptr
= htole32(size
);
1544 unsigned short time
= 0;
1545 unsigned short date
= 0;
1547 /* get old time to increment from */
1548 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1549 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1551 fat_time(&date
, &time
, NULL
);
1552 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1553 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1554 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1557 rc
= fat_seek( &dir
, sector
);
1561 rc
= fat_readwrite(&dir
, 1, buf
, true);
1568 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1574 memset(de
, 0, sizeof(struct fat_direntry
));
1575 de
->attr
= buf
[FATDIR_ATTR
];
1576 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1577 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1578 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1579 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1580 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1581 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1582 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1583 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1584 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1585 (the result of the shift is always considered signed) */
1588 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1589 c
= buf
[FATDIR_NAME
];
1590 if (c
== 0x05) /* special kanji char */
1594 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1597 c
= buf
[FATDIR_NAME
+i
];
1599 if (buf
[FATDIR_NAME
+8] != ' ') {
1600 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1601 de
->name
[j
++] = '.';
1602 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1603 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1608 int fat_open(IF_MV2(int volume
,)
1610 struct fat_file
*file
,
1611 const struct fat_dir
* dir
)
1613 file
->firstcluster
= startcluster
;
1614 file
->lastcluster
= startcluster
;
1615 file
->lastsector
= 0;
1616 file
->clusternum
= 0;
1617 file
->sectornum
= 0;
1619 #ifdef HAVE_MULTIVOLUME
1620 file
->volume
= volume
;
1621 /* fixme: remove error check when done */
1622 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1624 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1629 /* remember where the file's dir entry is located */
1631 file
->direntry
= dir
->entry
- 1;
1632 file
->direntries
= dir
->entrycount
;
1633 file
->dircluster
= dir
->file
.firstcluster
;
1635 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1639 int fat_create_file(const char* name
,
1640 struct fat_file
* file
,
1641 struct fat_dir
* dir
)
1645 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1646 rc
= add_dir_entry(dir
, file
, name
, false, false);
1648 file
->firstcluster
= 0;
1649 file
->lastcluster
= 0;
1650 file
->lastsector
= 0;
1651 file
->clusternum
= 0;
1652 file
->sectornum
= 0;
1659 int fat_create_dir(const char* name
,
1660 struct fat_dir
* newdir
,
1661 struct fat_dir
* dir
)
1663 #ifdef HAVE_MULTIVOLUME
1664 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1666 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1668 unsigned char buf
[SECTOR_SIZE
];
1672 struct fat_file dummyfile
;
1674 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1676 memset(newdir
, 0, sizeof(struct fat_dir
));
1677 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1679 /* First, add the entry in the parent directory */
1680 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1684 /* Allocate a new cluster for the directory */
1685 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1686 fat_bpb
->fsinfo
.nextfree
);
1687 if(newdir
->file
.firstcluster
== 0)
1690 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1692 /* Clear the entire cluster */
1693 memset(buf
, 0, sizeof buf
);
1694 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1695 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1696 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1701 /* Then add the "." entry */
1702 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1705 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1706 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1708 /* and the ".." entry */
1709 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1713 /* The root cluster is cluster 0 in the ".." entry */
1714 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1715 dummyfile
.firstcluster
= 0;
1717 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1718 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1720 /* Set the firstcluster field in the direntry */
1721 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1723 rc
= flush_fat(IF_MV(fat_bpb
));
1730 int fat_truncate(const struct fat_file
*file
)
1732 /* truncate trailing clusters */
1734 long last
= file
->lastcluster
;
1735 #ifdef HAVE_MULTIVOLUME
1736 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1739 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1741 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1742 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1743 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1745 if (file
->lastcluster
)
1746 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1751 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1754 #ifdef HAVE_MULTIVOLUME
1755 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1757 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1761 if ( file
->firstcluster
) {
1762 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1763 file
->firstcluster
= 0;
1767 if (file
->dircluster
) {
1768 rc
= update_short_entry(file
, size
, attr
);
1773 flush_fat(IF_MV(fat_bpb
));
1776 if ( file
->firstcluster
) {
1778 #ifdef HAVE_MULTIVOLUME
1779 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1781 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1786 for ( next
= file
->firstcluster
; next
;
1787 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1788 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1791 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1792 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1794 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1795 panicf("Cluster chain is too long\n");
1797 panicf("Cluster chain is too short\n");
1804 static int free_direntries(struct fat_file
* file
)
1806 unsigned char buf
[SECTOR_SIZE
];
1807 struct fat_file dir
;
1808 int numentries
= file
->direntries
;
1809 unsigned int entry
= file
->direntry
- numentries
+ 1;
1810 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1814 /* create a temporary file handle for the dir holding this file */
1815 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1819 rc
= fat_seek( &dir
, sector
);
1823 rc
= fat_readwrite(&dir
, 1, buf
, false);
1827 for (i
=0; i
< numentries
; i
++) {
1828 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1829 entry
, i
+1, numentries
);
1830 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1833 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1834 /* flush this sector */
1835 rc
= fat_seek(&dir
, sector
);
1839 rc
= fat_readwrite(&dir
, 1, buf
, true);
1843 if ( i
+1 < numentries
) {
1844 /* read next sector */
1845 rc
= fat_readwrite(&dir
, 1, buf
, false);
1853 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1854 /* flush this sector */
1855 rc
= fat_seek(&dir
, sector
);
1859 rc
= fat_readwrite(&dir
, 1, buf
, true);
1867 int fat_remove(struct fat_file
* file
)
1869 long next
, last
= file
->firstcluster
;
1871 #ifdef HAVE_MULTIVOLUME
1872 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1875 LDEBUGF("fat_remove(%lx)\n",last
);
1878 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1879 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1883 if ( file
->dircluster
) {
1884 rc
= free_direntries(file
);
1889 file
->firstcluster
= 0;
1890 file
->dircluster
= 0;
1892 rc
= flush_fat(IF_MV(fat_bpb
));
1899 int fat_rename(struct fat_file
* file
,
1900 struct fat_dir
* dir
,
1901 const unsigned char* newname
,
1906 struct fat_dir olddir
;
1907 struct fat_file newfile
= *file
;
1908 unsigned char buf
[SECTOR_SIZE
];
1909 unsigned char* entry
= NULL
;
1910 unsigned short* clusptr
= NULL
;
1911 unsigned int parentcluster
;
1912 #ifdef HAVE_MULTIVOLUME
1913 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1915 if (file
->volume
!= dir
->file
.volume
) {
1916 DEBUGF("No rename across volumes!\n");
1920 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1923 if ( !file
->dircluster
) {
1924 DEBUGF("File has no dir cluster!\n");
1928 /* create a temporary file handle */
1929 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1933 /* create new name */
1934 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1938 /* write size and cluster link */
1939 rc
= update_short_entry(&newfile
, size
, attr
);
1943 /* remove old name */
1944 rc
= free_direntries(file
);
1948 rc
= flush_fat(IF_MV(fat_bpb
));
1952 /* if renaming a directory, update the .. entry to make sure
1953 it points to its parent directory (we don't check if it was a move) */
1954 if(FAT_ATTR_DIRECTORY
== attr
) {
1955 /* open the dir that was renamed, we re-use the olddir struct */
1956 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1961 /* get the first sector of the dir */
1962 rc
= fat_seek(&olddir
.file
, 0);
1966 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1970 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1971 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1974 parentcluster
= dir
->file
.firstcluster
;
1976 entry
= buf
+ DIR_ENTRY_SIZE
;
1977 if(strncmp(".. ", entry
, 11))
1979 /* .. entry must be second entry according to FAT spec (p.29) */
1980 DEBUGF("Second dir entry is not double-dot!\n");
1983 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1984 *clusptr
= htole16(parentcluster
>> 16);
1986 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1987 *clusptr
= htole16(parentcluster
& 0xffff);
1989 /* write back this sector */
1990 rc
= fat_seek(&olddir
.file
, 0);
1994 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
2002 static long next_write_cluster(struct fat_file
* file
,
2006 #ifdef HAVE_MULTIVOLUME
2007 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2009 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2014 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
2017 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
2021 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
2022 else if (oldcluster
== 0)
2023 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
2024 fat_bpb
->fsinfo
.nextfree
);
2025 #ifdef HAVE_FAT16SUPPORT
2026 else /* negative, pseudo-cluster of the root dir */
2027 return 0; /* impossible to append something to the root */
2032 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2034 file
->firstcluster
= cluster
;
2035 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2039 if (fat_bpb
->fsinfo
.freecount
>0)
2040 panicf("There is free space, but find_free_cluster() "
2041 "didn't find it!\n");
2043 DEBUGF("next_write_cluster(): Disk full!\n");
2047 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2051 *newsector
= sector
;
2055 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2056 unsigned long start
, long count
, char* buf
, bool write
)
2058 #ifndef HAVE_MULTIVOLUME
2059 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2063 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2064 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2066 unsigned long firstallowed
;
2067 #ifdef HAVE_FAT16SUPPORT
2068 if (fat_bpb
->is_fat16
)
2069 firstallowed
= fat_bpb
->rootdirsector
;
2072 firstallowed
= fat_bpb
->firstdatasector
;
2074 if (start
< firstallowed
)
2075 panicf("Write %ld before data\n", firstallowed
- start
);
2076 if (start
+ count
> fat_bpb
->totalsectors
)
2077 panicf("Write %ld after data\n",
2078 start
+ count
- fat_bpb
->totalsectors
);
2079 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
2080 start
+ fat_bpb
->startsector
, count
, buf
);
2083 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
2084 start
+ fat_bpb
->startsector
, count
, buf
);
2086 DEBUGF( "transfer() - Couldn't %s sector %lx"
2087 " (error code %d)\n",
2088 write
? "write":"read", start
, rc
);
2095 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2096 void* buf
, bool write
)
2098 #ifdef HAVE_MULTIVOLUME
2099 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2101 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2103 long cluster
= file
->lastcluster
;
2104 long sector
= file
->lastsector
;
2105 long clusternum
= file
->clusternum
;
2106 long numsec
= file
->sectornum
;
2107 bool eof
= file
->eof
;
2108 long first
=0, last
=0;
2112 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2113 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2114 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2115 sector
,numsec
, eof
?1:0);
2120 /* find sequential sectors and write them all at once */
2121 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2123 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2124 long oldcluster
= cluster
;
2125 long oldsector
= sector
;
2126 long oldnumsec
= numsec
;
2128 cluster
= next_write_cluster(file
, cluster
, §or
);
2130 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2131 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2140 /* remember last cluster, in case
2141 we want to append to the file */
2143 cluster
= oldcluster
;
2146 i
= -1; /* Error code */
2157 /* look up first sector of file */
2158 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2160 #ifdef HAVE_FAT16SUPPORT
2161 if (file
->firstcluster
< 0)
2162 { /* FAT16 root dir */
2163 sector
+= fat_bpb
->rootdiroffset
;
2164 numsec
+= fat_bpb
->rootdiroffset
;
2173 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2174 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2175 long count
= last
- first
+ 1;
2176 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2180 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2184 if ((i
== sectorcount
-1) && /* last sector requested */
2187 long count
= sector
- first
+ 1;
2188 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2196 file
->lastcluster
= cluster
;
2197 file
->lastsector
= sector
;
2198 file
->clusternum
= clusternum
;
2199 file
->sectornum
= numsec
;
2202 /* if eof, don't report last block as read/written */
2206 DEBUGF("Sectors written: %ld\n", i
);
2210 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2212 #ifdef HAVE_MULTIVOLUME
2213 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2215 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2217 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2218 long cluster
= file
->firstcluster
;
2221 #ifdef HAVE_FAT16SUPPORT
2222 if (cluster
< 0) /* FAT16 root dir */
2223 seeksector
+= fat_bpb
->rootdiroffset
;
2228 /* we need to find the sector BEFORE the requested, since
2229 the file struct stores the last accessed sector */
2231 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2232 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2234 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2236 cluster
= file
->lastcluster
;
2237 numclusters
-= file
->clusternum
;
2240 for (i
=0; i
<numclusters
; i
++) {
2241 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2243 DEBUGF("Seeking beyond the end of the file! "
2244 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2249 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2255 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2256 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2258 file
->lastcluster
= cluster
;
2259 file
->lastsector
= sector
;
2260 file
->clusternum
= clusternum
;
2261 file
->sectornum
= sectornum
+ 1;
2265 int fat_opendir(IF_MV2(int volume
,)
2266 struct fat_dir
*dir
, unsigned long startcluster
,
2267 const struct fat_dir
*parent_dir
)
2269 #ifdef HAVE_MULTIVOLUME
2270 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2271 /* fixme: remove error check when done */
2272 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2274 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2278 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2285 if (startcluster
== 0)
2286 startcluster
= fat_bpb
->bpb_rootclus
;
2288 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2291 DEBUGF( "fat_opendir() - Couldn't open dir"
2292 " (error code %d)\n", rc
);
2299 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2300 * destination buffer (UTF-8 encoded). Copying is stopped when
2301 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2302 * Trailing \0 is also appended at the end of the UTF8-encoded
2305 * utf16src utf16 (little endian) segment to copy
2306 * utf16count max number of the utf16-characters to copy
2307 * utf8dst where to write UTF8-encoded string to
2309 * returns the number of UTF-16 characters actually copied
2311 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2312 int utf16count
, unsigned char *utf8dst
) {
2314 while ((utf16count
--) > 0) {
2315 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2316 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2319 utf8dst
= utf8encode(ucs
, utf8dst
);
2327 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2332 unsigned char firstbyte
;
2333 /* Long file names are stored in special entries. Each entry holds
2334 up to 13 characters. Names can be max 255 chars (not bytes!) long
2335 hence max 20 entries are required. */
2339 unsigned char* cached_buf
= dir
->sectorcache
[0];
2341 dir
->entrycount
= 0;
2345 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2347 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2354 DEBUGF( "fat_getnext() - Couldn't read dir"
2355 " (error code %d)\n", rc
);
2358 dir
->sector
= dir
->file
.lastsector
;
2361 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2362 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2364 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2366 firstbyte
= cached_buf
[entrypos
];
2369 if (firstbyte
== 0xe5) {
2372 dir
->entrycount
= 0;
2376 if (firstbyte
== 0) {
2379 dir
->entrycount
= 0;
2385 /* longname entry? */
2386 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2387 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2388 longarray
[longs
++] = entrypos
+ sectoridx
;
2391 if ( parse_direntry(entry
,
2392 &cached_buf
[entrypos
]) ) {
2394 /* don't return volume id entry */
2396 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2397 == FAT_ATTR_VOLUME_ID
)
2400 /* replace shortname with longname? */
2403 /* This should be enough to hold any name segment
2405 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2406 /* Add 1 for trailing \0 */
2407 unsigned char longname_utf8segm
[6*4 + 1];
2408 int longname_utf8len
= 0;
2409 /* Temporarily store it */
2410 strcpy(shortname
, entry
->name
);
2413 /* iterate backwards through the dir entries */
2414 for (j
=longs
-1; j
>=0; j
--) {
2415 unsigned char* ptr
= cached_buf
;
2416 int index
= longarray
[j
];
2417 /* current or cached sector? */
2418 if ( sectoridx
>= SECTOR_SIZE
) {
2419 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2420 if ( ( index
>= SECTOR_SIZE
) &&
2421 ( index
< SECTOR_SIZE
*2 ))
2422 ptr
= dir
->sectorcache
[1];
2424 ptr
= dir
->sectorcache
[2];
2427 if ( index
< SECTOR_SIZE
)
2428 ptr
= dir
->sectorcache
[1];
2431 index
&= SECTOR_SIZE
-1;
2434 /* Try to append each segment of the long name.
2435 Check if we'd exceed the buffer.
2436 Also check for FAT padding characters 0xFFFF. */
2437 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2438 longname_utf8segm
) == 0) break;
2439 /* logf("SG: %s, EN: %s", longname_utf8segm,
2441 longname_utf8len
+= strlen(longname_utf8segm
);
2442 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2443 strcat(entry
->name
, longname_utf8segm
);
2447 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
2448 longname_utf8segm
) == 0) break;
2449 /* logf("SG: %s, EN: %s", longname_utf8segm,
2451 longname_utf8len
+= strlen(longname_utf8segm
);
2452 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2453 strcat(entry
->name
, longname_utf8segm
);
2457 if (fat_copy_long_name_segment(ptr
+ index
+ 28, 2,
2458 longname_utf8segm
) == 0) break;
2459 /* logf("SG: %s, EN: %s", longname_utf8segm,
2461 longname_utf8len
+= strlen(longname_utf8segm
);
2462 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2463 strcat(entry
->name
, longname_utf8segm
);
2468 /* Does the utf8-encoded name fit into the entry? */
2469 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2470 /* Take the short DOS name. Need to utf8-encode it
2471 since it may contain chars from the upper half of
2472 the OEM code page which wouldn't be a valid utf8.
2473 Beware: this file will be shown with strange
2474 glyphs in file browser since unicode 0x80 to 0x9F
2475 are control characters. */
2476 logf("SN-DOS: %s", shortname
);
2477 unsigned char *utf8
;
2478 utf8
= iso_decode(shortname
, entry
->name
, -1,
2481 logf("SN: %s", entry
->name
);
2483 /* logf("LN: %s", entry->name);
2484 logf("LNLen: %d (%c)", longname_utf8len,
2496 /* save this sector, for longname use */
2498 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2500 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2501 sectoridx
+= SECTOR_SIZE
;
2507 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2509 #ifndef HAVE_MULTIVOLUME
2510 const int volume
= 0;
2512 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2513 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2516 #ifdef HAVE_MULTIVOLUME
2517 bool fat_ismounted(int volume
)
2519 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);