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
,)
180 long secnum
, bool dirty
);
181 static void create_dos_name(const unsigned char *name
, unsigned char *newname
);
182 static void randomize_dos_name(unsigned char *name
);
183 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
184 unsigned long start
);
185 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
,
186 long count
, char* buf
, bool write
);
188 #define FAT_CACHE_SIZE 0x20
189 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
191 struct fat_cache_entry
196 #ifdef HAVE_MULTIVOLUME
197 struct bpb
* fat_vol
; /* shared cache for all volumes */
201 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
202 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
203 static struct mutex cache_mutex NOCACHEBSS_ATTR
;
205 static long cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
207 #ifndef HAVE_MULTIVOLUME
208 struct bpb
* fat_bpb
= &fat_bpbs
[0];
210 #ifdef HAVE_FAT16SUPPORT
211 /* negative clusters (FAT16 root dir) don't get the 2 offset */
212 int zerocluster
= cluster
< 0 ? 0 : 2;
214 const long zerocluster
= 2;
217 if (cluster
> (long)(fat_bpb
->dataclusters
+ 1))
219 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster
);
223 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
224 + fat_bpb
->firstdatasector
;
227 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
229 #ifndef HAVE_MULTIVOLUME
230 const int volume
= 0;
232 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
234 *size
= fat_bpb
->dataclusters
* fat_bpb
->bpb_secperclus
/ 2;
236 *free
= fat_bpb
->fsinfo
.freecount
* fat_bpb
->bpb_secperclus
/ 2;
243 mutex_init(&cache_mutex
);
245 /* mark the FAT cache as unused */
246 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
248 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
249 fat_cache
[i
].inuse
= false;
250 fat_cache
[i
].dirty
= false;
251 #ifdef HAVE_MULTIVOLUME
252 fat_cache
[i
].fat_vol
= NULL
;
255 #ifdef HAVE_MULTIVOLUME
256 /* mark the possible volumes as not mounted */
257 for (i
=0; i
<NUM_VOLUMES
;i
++)
259 fat_bpbs
[i
].mounted
= false;
264 int fat_mount(IF_MV2(int volume
,) IF_MV2(int drive
,) long startsector
)
266 #ifndef HAVE_MULTIVOLUME
267 const int volume
= 0;
269 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
270 unsigned char buf
[SECTOR_SIZE
];
274 #ifdef HAVE_FAT16SUPPORT
278 /* Read the sector */
279 rc
= ata_read_sectors(IF_MV2(drive
,) startsector
,1,buf
);
282 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
286 memset(fat_bpb
, 0, sizeof(struct bpb
));
287 fat_bpb
->startsector
= startsector
;
288 #ifdef HAVE_MULTIVOLUME
289 fat_bpb
->drive
= drive
;
292 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
293 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
294 /* Sanity check is performed later */
296 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
297 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
298 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
299 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
300 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
301 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
302 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
303 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
304 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
306 /* calculate a few commonly used values */
307 if (fat_bpb
->bpb_fatsz16
!= 0)
308 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
310 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
312 if (fat_bpb
->bpb_totsec16
!= 0)
313 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
315 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
317 #ifdef HAVE_FAT16SUPPORT
318 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
319 if (!fat_bpb
->bpb_bytspersec
)
321 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
322 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
323 #endif /* #ifdef HAVE_FAT16SUPPORT */
325 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
326 #ifdef HAVE_FAT16SUPPORT
329 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
331 /* Determine FAT type */
332 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
333 if (fat_bpb
->bpb_secperclus
)
334 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
340 we are sometimes testing with "illegally small" fat32 images,
341 so we don't use the proper fat32 test case for test code
343 if ( fat_bpb
->bpb_fatsz16
)
345 if ( fat_bpb
->dataclusters
< 65525 )
348 #ifdef HAVE_FAT16SUPPORT
349 fat_bpb
->is_fat16
= true;
350 if (fat_bpb
->dataclusters
< 4085)
352 DEBUGF("This is FAT12. Go away!\n");
355 #else /* #ifdef HAVE_FAT16SUPPORT */
356 DEBUGF("This is not FAT32. Go away!\n");
358 #endif /* #ifndef HAVE_FAT16SUPPORT */
361 #ifdef HAVE_FAT16SUPPORT
362 if (fat_bpb
->is_fat16
)
363 { /* FAT16 specific part of BPB */
365 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
366 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
367 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
368 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
369 /* I assign negative pseudo cluster numbers for the root directory,
370 their range is counted upward until -1. */
371 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data*/
372 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
376 #endif /* #ifdef HAVE_FAT16SUPPORT */
377 { /* FAT32 specific part of BPB */
378 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
379 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
380 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,)
381 fat_bpb
->bpb_rootclus
);
384 rc
= bpb_is_sane(IF_MV(fat_bpb
));
387 DEBUGF( "fat_mount() - BPB is not sane\n");
391 #ifdef HAVE_FAT16SUPPORT
392 if (fat_bpb
->is_fat16
)
394 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
395 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
398 #endif /* #ifdef HAVE_FAT16SUPPORT */
400 /* Read the fsinfo sector */
401 rc
= ata_read_sectors(IF_MV2(drive
,)
402 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
405 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
408 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
409 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
412 /* calculate freecount if unset */
413 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
415 fat_recalc_free(IF_MV(volume
));
418 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
419 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
420 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
421 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
422 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
424 #ifdef HAVE_MULTIVOLUME
425 fat_bpb
->mounted
= true;
432 int fat_unmount(int volume
, bool flush
)
435 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
439 rc
= flush_fat(fat_bpb
); /* the clean way, while still alive */
442 { /* volume is not accessible any more, e.g. MMC removed */
444 mutex_lock(&cache_mutex
);
445 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
447 struct fat_cache_entry
*fce
= &fat_cache
[i
];
448 if(fce
->inuse
&& fce
->fat_vol
== fat_bpb
)
450 fce
->inuse
= false; /* discard all from that volume */
454 mutex_unlock(&cache_mutex
);
457 fat_bpb
->mounted
= false;
460 #endif /* #ifdef HAVE_HOTSWAP */
462 void fat_recalc_free(IF_MV_NONVOID(int volume
))
464 #ifndef HAVE_MULTIVOLUME
465 const int volume
= 0;
467 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
470 #ifdef HAVE_FAT16SUPPORT
471 if (fat_bpb
->is_fat16
)
473 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
475 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
476 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
477 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
478 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
481 if (letoh16(fat
[j
]) == 0x0000) {
483 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
484 fat_bpb
->fsinfo
.nextfree
= c
;
490 #endif /* #ifdef HAVE_FAT16SUPPORT */
492 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
494 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
495 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
496 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
497 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
500 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
502 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
503 fat_bpb
->fsinfo
.nextfree
= c
;
508 fat_bpb
->fsinfo
.freecount
= free
;
509 update_fsinfo(IF_MV(fat_bpb
));
512 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
514 #ifndef HAVE_MULTIVOLUME
515 struct bpb
* fat_bpb
= &fat_bpbs
[0];
517 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
519 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
520 fat_bpb
->bpb_bytspersec
);
523 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
526 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
528 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
529 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
532 if(fat_bpb
->bpb_numfats
!= 2)
534 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
535 fat_bpb
->bpb_numfats
);
537 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
539 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
540 "media type (0x%02x)\n",
543 if(fat_bpb
->last_word
!= 0xaa55)
545 DEBUGF( "bpb_is_sane() - Error: Last word is not "
546 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
550 if (fat_bpb
->fsinfo
.freecount
>
551 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
552 fat_bpb
->bpb_secperclus
)
554 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
555 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
562 static void flush_fat_sector(struct fat_cache_entry
*fce
,
563 unsigned char *sectorbuf
)
568 /* With multivolume, use only the FAT info from the cached sector! */
569 #ifdef HAVE_MULTIVOLUME
570 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
572 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
575 /* Write to the first FAT */
576 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
581 panicf("flush_fat_sector() - Could not write sector %ld"
585 #ifdef HAVE_MULTIVOLUME
586 if(fce
->fat_vol
->bpb_numfats
> 1)
588 if(fat_bpbs
[0].bpb_numfats
> 1)
591 /* Write to the second FAT */
592 #ifdef HAVE_MULTIVOLUME
593 secnum
+= fce
->fat_vol
->fatsize
;
595 secnum
+= fat_bpbs
[0].fatsize
;
597 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
598 secnum
, 1, sectorbuf
);
601 panicf("flush_fat_sector() - Could not write sector %ld"
609 /* Note: The returned pointer is only safely valid until the next
610 task switch! (Any subsequent ata read/write may yield.) */
611 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
612 long fatsector
, bool dirty
)
614 #ifndef HAVE_MULTIVOLUME
615 struct bpb
* fat_bpb
= &fat_bpbs
[0];
617 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
618 int cache_index
= secnum
& FAT_CACHE_MASK
;
619 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
620 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
623 mutex_lock(&cache_mutex
); /* make changes atomic */
625 /* Delete the cache entry if it isn't the sector we want */
626 if(fce
->inuse
&& (fce
->secnum
!= secnum
627 #ifdef HAVE_MULTIVOLUME
628 || fce
->fat_vol
!= fat_bpb
632 /* Write back if it is dirty */
635 flush_fat_sector(fce
, sectorbuf
);
640 /* Load the sector if it is not cached */
643 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
644 secnum
+ fat_bpb
->startsector
,1,
648 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
649 " (error %d)\n", secnum
, rc
);
650 mutex_unlock(&cache_mutex
);
654 fce
->secnum
= secnum
;
655 #ifdef HAVE_MULTIVOLUME
656 fce
->fat_vol
= fat_bpb
;
660 fce
->dirty
= true; /* dirt remains, sticky until flushed */
661 mutex_unlock(&cache_mutex
);
665 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
666 unsigned long startcluster
)
668 #ifndef HAVE_MULTIVOLUME
669 struct bpb
* fat_bpb
= &fat_bpbs
[0];
671 unsigned long sector
;
672 unsigned long offset
;
675 #ifdef HAVE_FAT16SUPPORT
676 if (fat_bpb
->is_fat16
)
678 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
679 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
681 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
683 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
684 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
687 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
688 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
689 if (letoh16(fat
[k
]) == 0x0000) {
690 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
691 /* Ignore the reserved clusters 0 & 1, and also
692 cluster numbers out of bounds */
693 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
695 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
696 fat_bpb
->fsinfo
.nextfree
= c
;
704 #endif /* #ifdef HAVE_FAT16SUPPORT */
706 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
707 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
709 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
711 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
712 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
715 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
716 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
717 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
718 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
719 /* Ignore the reserved clusters 0 & 1, and also
720 cluster numbers out of bounds */
721 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
723 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
724 fat_bpb
->fsinfo
.nextfree
= c
;
732 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
733 return 0; /* 0 is an illegal cluster number */
736 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
739 #ifndef HAVE_MULTIVOLUME
740 struct bpb
* fat_bpb
= &fat_bpbs
[0];
742 #ifdef HAVE_FAT16SUPPORT
743 if (fat_bpb
->is_fat16
)
745 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
746 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
751 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
754 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
757 panicf("Updating reserved FAT entry %ld.\n",entry
);
759 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
762 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
767 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
768 fat_bpb
->fsinfo
.freecount
--;
771 if (letoh16(sec
[offset
]))
772 fat_bpb
->fsinfo
.freecount
++;
775 LDEBUGF("update_fat_entry: %d free clusters\n",
776 fat_bpb
->fsinfo
.freecount
);
778 sec
[offset
] = htole16(val
);
781 #endif /* #ifdef HAVE_FAT16SUPPORT */
783 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
784 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
787 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
790 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
793 panicf("Updating reserved FAT entry %ld.\n",entry
);
795 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
798 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
803 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
804 fat_bpb
->fsinfo
.freecount
> 0)
805 fat_bpb
->fsinfo
.freecount
--;
808 if (letoh32(sec
[offset
]) & 0x0fffffff)
809 fat_bpb
->fsinfo
.freecount
++;
812 LDEBUGF("update_fat_entry: %ld free clusters\n",
813 fat_bpb
->fsinfo
.freecount
);
815 /* don't change top 4 bits */
816 sec
[offset
] &= htole32(0xf0000000);
817 sec
[offset
] |= htole32(val
& 0x0fffffff);
823 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
825 #ifdef HAVE_FAT16SUPPORT
826 #ifndef HAVE_MULTIVOLUME
827 struct bpb
* fat_bpb
= &fat_bpbs
[0];
829 if (fat_bpb
->is_fat16
)
831 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
832 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
835 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
838 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
842 return letoh16(sec
[offset
]);
845 #endif /* #ifdef HAVE_FAT16SUPPORT */
847 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
848 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
851 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
854 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
858 return letoh32(sec
[offset
]) & 0x0fffffff;
862 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
865 long eof_mark
= FAT_EOF_MARK
;
867 #ifdef HAVE_FAT16SUPPORT
868 #ifndef HAVE_MULTIVOLUME
869 struct bpb
* fat_bpb
= &fat_bpbs
[0];
871 if (fat_bpb
->is_fat16
)
873 eof_mark
&= 0xFFFF; /* only 16 bit */
874 if (cluster
< 0) /* FAT16 root dir */
875 return cluster
+ 1; /* don't use the FAT */
878 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
880 /* is this last cluster in chain? */
881 if ( next_cluster
>= eof_mark
)
887 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
889 #ifndef HAVE_MULTIVOLUME
890 struct bpb
* fat_bpb
= &fat_bpbs
[0];
892 unsigned char fsinfo
[SECTOR_SIZE
];
893 unsigned long* intptr
;
896 #ifdef HAVE_FAT16SUPPORT
897 if (fat_bpb
->is_fat16
)
898 return 0; /* FAT16 has no FsInfo */
899 #endif /* #ifdef HAVE_FAT16SUPPORT */
902 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
903 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
906 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
909 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
910 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
912 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
913 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
915 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
916 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
919 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
926 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
931 LDEBUGF("flush_fat()\n");
933 mutex_lock(&cache_mutex
);
934 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
936 struct fat_cache_entry
*fce
= &fat_cache
[i
];
938 #ifdef HAVE_MULTIVOLUME
939 && fce
->fat_vol
== fat_bpb
943 sec
= fat_cache_sectors
[i
];
944 flush_fat_sector(fce
, sec
);
947 mutex_unlock(&cache_mutex
);
949 rc
= update_fsinfo(IF_MV(fat_bpb
));
956 static void fat_time(unsigned short* date
,
957 unsigned short* time
,
958 unsigned short* tenth
)
961 struct tm
* tm
= get_time();
964 *date
= ((tm
->tm_year
- 80) << 9) |
965 ((tm
->tm_mon
+ 1) << 5) |
969 *time
= (tm
->tm_hour
<< 11) |
974 *tenth
= (tm
->tm_sec
& 1) * 100;
976 /* non-RTC version returns an increment from the supplied time, or a
977 * fixed standard time/date if no time given as input */
978 bool next_day
= false;
984 /* set to 00:15:00 */
989 unsigned short mins
= (*time
>> 5) & 0x003F;
990 unsigned short hours
= (*time
>> 11) & 0x001F;
991 if ((mins
+= 10) >= 60)
1001 *time
= (hours
<< 11) | (mins
<< 5);
1009 /* Macros to convert a 2-digit string to a decimal constant.
1010 (YEAR), MONTH and DAY are set by the date command, which outputs
1011 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1012 misinterpretation as an octal constant. */
1013 #define S100(x) 1 ## x
1014 #define C2DIG2DEC(x) (S100(x)-100)
1015 /* set to build date */
1016 *date
= ((YEAR
- 1980) << 9) | (C2DIG2DEC(MONTH
) << 5)
1021 unsigned short day
= *date
& 0x001F;
1022 unsigned short month
= (*date
>> 5) & 0x000F;
1023 unsigned short year
= (*date
>> 9) & 0x007F;
1026 /* do a very simple day increment - never go above 28 days */
1036 *date
= (year
<< 9) | (month
<< 5) | day
;
1042 #endif /* CONFIG_RTC */
1045 static int write_long_name(struct fat_file
* file
,
1046 unsigned int firstentry
,
1047 unsigned int numentries
,
1048 const unsigned char* name
,
1049 const unsigned char* shortname
,
1052 unsigned char buf
[SECTOR_SIZE
];
1053 unsigned char* entry
;
1054 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1055 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1056 unsigned char chksum
= 0;
1057 unsigned int i
, j
=0;
1058 unsigned int nameidx
=0, namelen
= utf8length(name
);
1060 unsigned short name_utf16
[namelen
+ 1];
1062 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1063 file
->firstcluster
, firstentry
, numentries
, name
);
1065 rc
= fat_seek(file
, sector
);
1069 rc
= fat_readwrite(file
, 1, buf
, false);
1073 /* calculate shortname checksum */
1074 for (i
=11; i
>0; i
--)
1075 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1077 /* calc position of last name segment */
1078 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1080 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1081 nameidx
+= NAME_BYTES_PER_ENTRY
);
1083 /* we need to convert the name first */
1084 /* since it is written in reverse order */
1085 for (i
= 0; i
<= namelen
; i
++)
1086 name
= utf8decode(name
, &name_utf16
[i
]);
1088 for (i
=0; i
< numentries
; i
++) {
1090 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1091 /* update current sector */
1092 rc
= fat_seek(file
, sector
);
1096 rc
= fat_readwrite(file
, 1, buf
, true);
1100 /* read next sector */
1101 rc
= fat_readwrite(file
, 1, buf
, false);
1103 LDEBUGF("Failed writing new sector: %d\n",rc
);
1108 memset(buf
, 0, sizeof buf
);
1114 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1116 /* verify this entry is free */
1117 if (entry
[0] && entry
[0] != 0xe5 )
1118 panicf("Dir entry %d in sector %x is not free! "
1119 "%02x %02x %02x %02x",
1121 entry
[0], entry
[1], entry
[2], entry
[3]);
1123 memset(entry
, 0, DIR_ENTRY_SIZE
);
1124 if ( i
+1 < numentries
) {
1125 /* longname entry */
1126 unsigned int k
, l
= nameidx
;
1128 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1130 /* mark this as last long entry */
1131 entry
[FATLONG_ORDER
] |= 0x40;
1133 /* pad name with 0xffff */
1134 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1135 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1136 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1139 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1140 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1141 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1143 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1144 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1145 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1147 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1148 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1149 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1152 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1153 entry
[FATDIR_FSTCLUSLO
] = 0;
1154 entry
[FATLONG_TYPE
] = 0;
1155 entry
[FATLONG_CHKSUM
] = chksum
;
1156 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1159 /* shortname entry */
1160 unsigned short date
=0, time
=0, tenth
=0;
1161 LDEBUGF("Shortname entry: %s\n", shortname
);
1162 strncpy(entry
+ FATDIR_NAME
, shortname
, 11);
1163 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1164 entry
[FATDIR_NTRES
] = 0;
1166 fat_time(&date
, &time
, &tenth
);
1167 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1168 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1169 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1170 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1171 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1172 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1175 nameidx
-= NAME_BYTES_PER_ENTRY
;
1178 /* update last sector */
1179 rc
= fat_seek(file
, sector
);
1183 rc
= fat_readwrite(file
, 1, buf
, true);
1190 static int fat_checkname(const unsigned char* newname
)
1192 static const char invalid_chars
[] = "\"*/:<>?\\|";
1193 int len
= strlen(newname
);
1194 /* More sanity checks are probably needed */
1195 if (len
> 255 || newname
[len
- 1] == '.')
1201 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1208 static int add_dir_entry(struct fat_dir
* dir
,
1209 struct fat_file
* file
,
1214 #ifdef HAVE_MULTIVOLUME
1215 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1217 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1219 unsigned char buf
[SECTOR_SIZE
];
1220 unsigned char shortname
[12];
1222 unsigned int sector
;
1224 int entries_needed
, entries_found
= 0;
1227 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1228 name
, file
->firstcluster
);
1230 /* Don't check dotdirs name for validity */
1231 if (dotdir
== false) {
1232 rc
= fat_checkname(name
);
1234 /* filename is invalid */
1239 #ifdef HAVE_MULTIVOLUME
1240 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1243 /* The "." and ".." directory entries must not be long names */
1246 strncpy(shortname
, name
, 12);
1247 for(i
= strlen(shortname
); i
< 12; i
++)
1252 create_dos_name(name
, shortname
);
1254 /* one dir entry needed for every 13 bytes of filename,
1255 plus one entry for the short name */
1256 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1257 / NAME_BYTES_PER_ENTRY
+ 1;
1263 rc
= fat_seek(&dir
->file
, 0);
1267 /* step 1: search for free entries and check for duplicate shortname */
1268 for (sector
= 0; !done
; sector
++)
1272 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1274 DEBUGF( "add_dir_entry() - Couldn't read dir"
1275 " (error code %d)\n", rc
);
1279 if (rc
== 0) { /* current end of dir reached */
1280 LDEBUGF("End of dir on cluster boundary\n");
1284 /* look for free slots */
1285 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1287 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1289 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1290 LDEBUGF("Found end of dir %d\n",
1291 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1292 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1298 LDEBUGF("Found free entry %d (%d/%d)\n",
1299 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1300 entries_found
, entries_needed
);
1306 /* check that our intended shortname doesn't already exist */
1307 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1308 /* shortname exists already, make a new one */
1309 randomize_dos_name(shortname
);
1310 LDEBUGF("Duplicate shortname, changing to %s\n",
1313 /* name has changed, we need to restart search */
1318 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1319 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1324 /* step 2: extend the dir if necessary */
1327 LDEBUGF("Adding new sector(s) to dir\n");
1328 rc
= fat_seek(&dir
->file
, sector
);
1331 memset(buf
, 0, sizeof buf
);
1333 /* we must clear whole clusters */
1334 for (; (entries_found
< entries_needed
) ||
1335 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1337 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1338 return -5; /* dir too large -- FAT specification */
1340 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1341 if (rc
< 1) /* No more room or something went wrong */
1344 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1347 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1350 /* step 3: add entry */
1351 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1352 LDEBUGF("Adding longname to entry %d in sector %d\n",
1353 firstentry
, sector
);
1355 rc
= write_long_name(&dir
->file
, firstentry
,
1356 entries_needed
, name
, shortname
, is_directory
);
1360 /* remember where the shortname dir entry is located */
1361 file
->direntry
= firstentry
+ entries_needed
- 1;
1362 file
->direntries
= entries_needed
;
1363 file
->dircluster
= dir
->file
.firstcluster
;
1364 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1365 file
->direntry
, file
->direntries
);
1370 static unsigned char char2dos(unsigned char c
, int* randomize
)
1372 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1375 c
= 0; /* Illegal char, remove */
1376 else if (strchr(invalid_chars
, c
) != NULL
)
1378 /* Illegal char, replace */
1380 *randomize
= 1; /* as per FAT spec */
1388 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1394 /* Find extension part */
1395 ext
= strrchr(name
, '.');
1396 if (ext
== name
) /* handle .dotnames */
1399 /* needs to randomize? */
1400 if((ext
&& (strlen(ext
) > 4)) ||
1401 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1405 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1407 unsigned char c
= char2dos(*name
, &randomize
);
1412 /* Pad both name and extension */
1416 if (newname
[0] == 0xe5) /* Special kanji character */
1420 { /* Extension part */
1422 for (i
= 8; *ext
&& (i
< 11); ext
++)
1424 unsigned char c
= char2dos(*ext
, &randomize
);
1431 randomize_dos_name(newname
);
1434 static void randomize_dos_name(unsigned char *name
)
1436 unsigned char* tilde
= NULL
; /* ~ location */
1437 unsigned char* lastpt
= NULL
; /* last point of filename */
1438 unsigned char* nameptr
= name
; /* working copy of name pointer */
1439 unsigned char num
[9]; /* holds number as string */
1447 /* hunt for ~ and where to put it */
1448 if((!tilde
) && (*nameptr
== '~'))
1450 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1456 /* extract current count and increment */
1457 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1458 num
[7-(unsigned int)(tilde
-name
)] = 0;
1459 cnt
= atoi(num
) + 1;
1461 cnt
%= 10000000; /* protection */
1462 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1463 numlen
= strlen(num
); /* required space */
1464 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1465 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1467 memcpy(&name
[offset
], num
, numlen
);
1469 /* in special case of counter overflow: pad with spaces */
1470 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1474 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1476 unsigned char buf
[SECTOR_SIZE
];
1477 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1478 unsigned char* entry
=
1479 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1480 unsigned long* sizeptr
;
1481 unsigned short* clusptr
;
1482 struct fat_file dir
;
1485 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1486 file
->firstcluster
, file
->direntry
, size
);
1488 /* create a temporary file handle for the dir holding this file */
1489 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1493 rc
= fat_seek( &dir
, sector
);
1497 rc
= fat_readwrite(&dir
, 1, buf
, false);
1501 if (!entry
[0] || entry
[0] == 0xe5)
1502 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1504 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1506 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1507 *clusptr
= htole16(file
->firstcluster
>> 16);
1509 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1510 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1512 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1513 *sizeptr
= htole32(size
);
1517 unsigned short time
= 0;
1518 unsigned short date
= 0;
1520 /* get old time to increment from */
1521 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1522 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1524 fat_time(&date
, &time
, NULL
);
1525 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1526 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1527 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1530 rc
= fat_seek( &dir
, sector
);
1534 rc
= fat_readwrite(&dir
, 1, buf
, true);
1541 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1547 memset(de
, 0, sizeof(struct fat_direntry
));
1548 de
->attr
= buf
[FATDIR_ATTR
];
1549 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1550 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1551 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1552 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1553 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1554 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1555 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1556 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1557 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1558 (the result of the shift is always considered signed) */
1561 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1562 c
= buf
[FATDIR_NAME
];
1563 if (c
== 0x05) /* special kanji char */
1567 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1570 c
= buf
[FATDIR_NAME
+i
];
1572 if (buf
[FATDIR_NAME
+8] != ' ') {
1573 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1574 de
->name
[j
++] = '.';
1575 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1576 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1581 int fat_open(IF_MV2(int volume
,)
1583 struct fat_file
*file
,
1584 const struct fat_dir
* dir
)
1586 file
->firstcluster
= startcluster
;
1587 file
->lastcluster
= startcluster
;
1588 file
->lastsector
= 0;
1589 file
->clusternum
= 0;
1590 file
->sectornum
= 0;
1592 #ifdef HAVE_MULTIVOLUME
1593 file
->volume
= volume
;
1594 /* fixme: remove error check when done */
1595 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1597 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1602 /* remember where the file's dir entry is located */
1604 file
->direntry
= dir
->entry
- 1;
1605 file
->direntries
= dir
->entrycount
;
1606 file
->dircluster
= dir
->file
.firstcluster
;
1608 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1612 int fat_create_file(const char* name
,
1613 struct fat_file
* file
,
1614 struct fat_dir
* dir
)
1618 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1619 rc
= add_dir_entry(dir
, file
, name
, false, false);
1621 file
->firstcluster
= 0;
1622 file
->lastcluster
= 0;
1623 file
->lastsector
= 0;
1624 file
->clusternum
= 0;
1625 file
->sectornum
= 0;
1632 int fat_create_dir(const char* name
,
1633 struct fat_dir
* newdir
,
1634 struct fat_dir
* dir
)
1636 #ifdef HAVE_MULTIVOLUME
1637 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1639 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1641 unsigned char buf
[SECTOR_SIZE
];
1645 struct fat_file dummyfile
;
1647 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1649 memset(newdir
, 0, sizeof(struct fat_dir
));
1650 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1652 /* First, add the entry in the parent directory */
1653 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1657 /* Allocate a new cluster for the directory */
1658 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1659 fat_bpb
->fsinfo
.nextfree
);
1660 if(newdir
->file
.firstcluster
== 0)
1663 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1665 /* Clear the entire cluster */
1666 memset(buf
, 0, sizeof buf
);
1667 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1668 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1669 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1674 /* Then add the "." entry */
1675 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1678 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1679 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1681 /* and the ".." entry */
1682 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1686 /* The root cluster is cluster 0 in the ".." entry */
1687 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1688 dummyfile
.firstcluster
= 0;
1690 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1691 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1693 /* Set the firstcluster field in the direntry */
1694 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1696 rc
= flush_fat(IF_MV(fat_bpb
));
1703 int fat_truncate(const struct fat_file
*file
)
1705 /* truncate trailing clusters */
1707 long last
= file
->lastcluster
;
1708 #ifdef HAVE_MULTIVOLUME
1709 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1712 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1714 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1715 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1716 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1718 if (file
->lastcluster
)
1719 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1724 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1727 #ifdef HAVE_MULTIVOLUME
1728 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1730 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1734 if ( file
->firstcluster
) {
1735 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1736 file
->firstcluster
= 0;
1740 if (file
->dircluster
) {
1741 rc
= update_short_entry(file
, size
, attr
);
1746 flush_fat(IF_MV(fat_bpb
));
1749 if ( file
->firstcluster
) {
1751 #ifdef HAVE_MULTIVOLUME
1752 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1754 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1759 for ( next
= file
->firstcluster
; next
;
1760 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1761 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1764 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1765 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1767 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1768 panicf("Cluster chain is too long\n");
1770 panicf("Cluster chain is too short\n");
1777 static int free_direntries(struct fat_file
* file
)
1779 unsigned char buf
[SECTOR_SIZE
];
1780 struct fat_file dir
;
1781 int numentries
= file
->direntries
;
1782 unsigned int entry
= file
->direntry
- numentries
+ 1;
1783 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1787 /* create a temporary file handle for the dir holding this file */
1788 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1792 rc
= fat_seek( &dir
, sector
);
1796 rc
= fat_readwrite(&dir
, 1, buf
, false);
1800 for (i
=0; i
< numentries
; i
++) {
1801 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1802 entry
, i
+1, numentries
);
1803 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1806 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1807 /* flush this sector */
1808 rc
= fat_seek(&dir
, sector
);
1812 rc
= fat_readwrite(&dir
, 1, buf
, true);
1816 if ( i
+1 < numentries
) {
1817 /* read next sector */
1818 rc
= fat_readwrite(&dir
, 1, buf
, false);
1826 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1827 /* flush this sector */
1828 rc
= fat_seek(&dir
, sector
);
1832 rc
= fat_readwrite(&dir
, 1, buf
, true);
1840 int fat_remove(struct fat_file
* file
)
1842 long next
, last
= file
->firstcluster
;
1844 #ifdef HAVE_MULTIVOLUME
1845 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1848 LDEBUGF("fat_remove(%lx)\n",last
);
1851 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1852 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1856 if ( file
->dircluster
) {
1857 rc
= free_direntries(file
);
1862 file
->firstcluster
= 0;
1863 file
->dircluster
= 0;
1865 rc
= flush_fat(IF_MV(fat_bpb
));
1872 int fat_rename(struct fat_file
* file
,
1873 struct fat_dir
* dir
,
1874 const unsigned char* newname
,
1879 struct fat_dir olddir
;
1880 struct fat_file newfile
= *file
;
1881 unsigned char buf
[SECTOR_SIZE
];
1882 unsigned char* entry
= NULL
;
1883 unsigned short* clusptr
= NULL
;
1884 unsigned int parentcluster
;
1885 #ifdef HAVE_MULTIVOLUME
1886 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1888 if (file
->volume
!= dir
->file
.volume
) {
1889 DEBUGF("No rename across volumes!\n");
1893 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1896 if ( !file
->dircluster
) {
1897 DEBUGF("File has no dir cluster!\n");
1901 /* create a temporary file handle */
1902 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1906 /* create new name */
1907 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1911 /* write size and cluster link */
1912 rc
= update_short_entry(&newfile
, size
, attr
);
1916 /* remove old name */
1917 rc
= free_direntries(file
);
1921 rc
= flush_fat(IF_MV(fat_bpb
));
1925 /* if renaming a directory, update the .. entry to make sure
1926 it points to its parent directory (we don't check if it was a move) */
1927 if(FAT_ATTR_DIRECTORY
== attr
) {
1928 /* open the dir that was renamed, we re-use the olddir struct */
1929 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1934 /* get the first sector of the dir */
1935 rc
= fat_seek(&olddir
.file
, 0);
1939 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1943 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1944 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1947 parentcluster
= dir
->file
.firstcluster
;
1949 entry
= buf
+ DIR_ENTRY_SIZE
;
1950 if(strncmp(".. ", entry
, 11))
1952 /* .. entry must be second entry according to FAT spec (p.29) */
1953 DEBUGF("Second dir entry is not double-dot!\n");
1956 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1957 *clusptr
= htole16(parentcluster
>> 16);
1959 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1960 *clusptr
= htole16(parentcluster
& 0xffff);
1962 /* write back this sector */
1963 rc
= fat_seek(&olddir
.file
, 0);
1967 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
1975 static long next_write_cluster(struct fat_file
* file
,
1979 #ifdef HAVE_MULTIVOLUME
1980 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1982 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1987 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
1990 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
1994 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
1995 else if (oldcluster
== 0)
1996 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1997 fat_bpb
->fsinfo
.nextfree
);
1998 #ifdef HAVE_FAT16SUPPORT
1999 else /* negative, pseudo-cluster of the root dir */
2000 return 0; /* impossible to append something to the root */
2005 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2007 file
->firstcluster
= cluster
;
2008 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2012 if (fat_bpb
->fsinfo
.freecount
>0)
2013 panicf("There is free space, but find_free_cluster() "
2014 "didn't find it!\n");
2016 DEBUGF("next_write_cluster(): Disk full!\n");
2020 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2024 *newsector
= sector
;
2028 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2029 unsigned long start
, long count
, char* buf
, bool write
)
2031 #ifndef HAVE_MULTIVOLUME
2032 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2036 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2037 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2039 unsigned long firstallowed
;
2040 #ifdef HAVE_FAT16SUPPORT
2041 if (fat_bpb
->is_fat16
)
2042 firstallowed
= fat_bpb
->rootdirsector
;
2045 firstallowed
= fat_bpb
->firstdatasector
;
2047 if (start
< firstallowed
)
2048 panicf("Write %ld before data\n", firstallowed
- start
);
2049 if (start
+ count
> fat_bpb
->totalsectors
)
2050 panicf("Write %ld after data\n",
2051 start
+ count
- fat_bpb
->totalsectors
);
2052 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
2053 start
+ fat_bpb
->startsector
, count
, buf
);
2056 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
2057 start
+ fat_bpb
->startsector
, count
, buf
);
2059 DEBUGF( "transfer() - Couldn't %s sector %lx"
2060 " (error code %d)\n",
2061 write
? "write":"read", start
, rc
);
2068 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2069 void* buf
, bool write
)
2071 #ifdef HAVE_MULTIVOLUME
2072 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2074 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2076 long cluster
= file
->lastcluster
;
2077 long sector
= file
->lastsector
;
2078 long clusternum
= file
->clusternum
;
2079 long numsec
= file
->sectornum
;
2080 bool eof
= file
->eof
;
2081 long first
=0, last
=0;
2085 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2086 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2087 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2088 sector
,numsec
, eof
?1:0);
2093 /* find sequential sectors and write them all at once */
2094 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2096 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2097 long oldcluster
= cluster
;
2098 long oldsector
= sector
;
2099 long oldnumsec
= numsec
;
2101 cluster
= next_write_cluster(file
, cluster
, §or
);
2103 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2104 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2113 /* remember last cluster, in case
2114 we want to append to the file */
2116 cluster
= oldcluster
;
2119 i
= -1; /* Error code */
2130 /* look up first sector of file */
2131 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2133 #ifdef HAVE_FAT16SUPPORT
2134 if (file
->firstcluster
< 0)
2135 { /* FAT16 root dir */
2136 sector
+= fat_bpb
->rootdiroffset
;
2137 numsec
+= fat_bpb
->rootdiroffset
;
2146 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2147 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2148 long count
= last
- first
+ 1;
2149 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2153 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2157 if ((i
== sectorcount
-1) && /* last sector requested */
2160 long count
= sector
- first
+ 1;
2161 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2169 file
->lastcluster
= cluster
;
2170 file
->lastsector
= sector
;
2171 file
->clusternum
= clusternum
;
2172 file
->sectornum
= numsec
;
2175 /* if eof, don't report last block as read/written */
2179 DEBUGF("Sectors written: %ld\n", i
);
2183 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2185 #ifdef HAVE_MULTIVOLUME
2186 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2188 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2190 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2191 long cluster
= file
->firstcluster
;
2194 #ifdef HAVE_FAT16SUPPORT
2195 if (cluster
< 0) /* FAT16 root dir */
2196 seeksector
+= fat_bpb
->rootdiroffset
;
2201 /* we need to find the sector BEFORE the requested, since
2202 the file struct stores the last accessed sector */
2204 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2205 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2207 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2209 cluster
= file
->lastcluster
;
2210 numclusters
-= file
->clusternum
;
2213 for (i
=0; i
<numclusters
; i
++) {
2214 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2216 DEBUGF("Seeking beyond the end of the file! "
2217 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2222 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2228 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2229 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2231 file
->lastcluster
= cluster
;
2232 file
->lastsector
= sector
;
2233 file
->clusternum
= clusternum
;
2234 file
->sectornum
= sectornum
+ 1;
2238 int fat_opendir(IF_MV2(int volume
,)
2239 struct fat_dir
*dir
, unsigned long startcluster
,
2240 const struct fat_dir
*parent_dir
)
2242 #ifdef HAVE_MULTIVOLUME
2243 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2244 /* fixme: remove error check when done */
2245 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2247 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2251 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2258 if (startcluster
== 0)
2259 startcluster
= fat_bpb
->bpb_rootclus
;
2261 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2264 DEBUGF( "fat_opendir() - Couldn't open dir"
2265 " (error code %d)\n", rc
);
2272 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2273 * destination buffer (UTF-8 encoded). Copying is stopped when
2274 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2275 * Trailing \0 is also appended at the end of the UTF8-encoded
2278 * utf16src utf16 (little endian) segment to copy
2279 * utf16count max number of the utf16-characters to copy
2280 * utf8dst where to write UTF8-encoded string to
2282 * returns the number of UTF-16 characters actually copied
2284 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2285 int utf16count
, unsigned char *utf8dst
) {
2287 while ((utf16count
--) > 0) {
2288 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2289 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2292 utf8dst
= utf8encode(ucs
, utf8dst
);
2300 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2305 unsigned char firstbyte
;
2306 /* Long file names are stored in special entries. Each entry holds
2307 up to 13 characters. Names can be max 255 chars (not bytes!) long
2308 hence max 20 entries are required. */
2312 unsigned char* cached_buf
= dir
->sectorcache
[0];
2314 dir
->entrycount
= 0;
2318 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2320 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2327 DEBUGF( "fat_getnext() - Couldn't read dir"
2328 " (error code %d)\n", rc
);
2331 dir
->sector
= dir
->file
.lastsector
;
2334 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2335 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2337 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2339 firstbyte
= cached_buf
[entrypos
];
2342 if (firstbyte
== 0xe5) {
2345 dir
->entrycount
= 0;
2349 if (firstbyte
== 0) {
2352 dir
->entrycount
= 0;
2358 /* longname entry? */
2359 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2360 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2361 longarray
[longs
++] = entrypos
+ sectoridx
;
2364 if ( parse_direntry(entry
,
2365 &cached_buf
[entrypos
]) ) {
2367 /* don't return volume id entry */
2369 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2370 == FAT_ATTR_VOLUME_ID
)
2373 /* replace shortname with longname? */
2376 /* This should be enough to hold any name segment
2378 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2379 /* Add 1 for trailing \0 */
2380 unsigned char longname_utf8segm
[6*4 + 1];
2381 int longname_utf8len
= 0;
2382 /* Temporarily store it */
2383 strcpy(shortname
, entry
->name
);
2386 /* iterate backwards through the dir entries */
2387 for (j
=longs
-1; j
>=0; j
--) {
2388 unsigned char* ptr
= cached_buf
;
2389 int index
= longarray
[j
];
2390 /* current or cached sector? */
2391 if ( sectoridx
>= SECTOR_SIZE
) {
2392 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2393 if ( ( index
>= SECTOR_SIZE
) &&
2394 ( index
< SECTOR_SIZE
*2 ))
2395 ptr
= dir
->sectorcache
[1];
2397 ptr
= dir
->sectorcache
[2];
2400 if ( index
< SECTOR_SIZE
)
2401 ptr
= dir
->sectorcache
[1];
2404 index
&= SECTOR_SIZE
-1;
2407 /* Try to append each segment of the long name.
2408 Check if we'd exceed the buffer.
2409 Also check for FAT padding characters 0xFFFF. */
2410 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2411 longname_utf8segm
) == 0) break;
2412 /* logf("SG: %s, EN: %s", longname_utf8segm,
2414 longname_utf8len
+= strlen(longname_utf8segm
);
2415 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2416 strcat(entry
->name
, longname_utf8segm
);
2420 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
2421 longname_utf8segm
) == 0) break;
2422 /* logf("SG: %s, EN: %s", longname_utf8segm,
2424 longname_utf8len
+= strlen(longname_utf8segm
);
2425 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2426 strcat(entry
->name
, longname_utf8segm
);
2430 if (fat_copy_long_name_segment(ptr
+ index
+ 28, 2,
2431 longname_utf8segm
) == 0) break;
2432 /* logf("SG: %s, EN: %s", longname_utf8segm,
2434 longname_utf8len
+= strlen(longname_utf8segm
);
2435 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2436 strcat(entry
->name
, longname_utf8segm
);
2441 /* Does the utf8-encoded name fit into the entry? */
2442 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2443 /* Take the short DOS name. Need to utf8-encode it
2444 since it may contain chars from the upper half of
2445 the OEM code page which wouldn't be a valid utf8.
2446 Beware: this file will be shown with strange
2447 glyphs in file browser since unicode 0x80 to 0x9F
2448 are control characters. */
2449 logf("SN-DOS: %s", shortname
);
2450 unsigned char *utf8
;
2451 utf8
= iso_decode(shortname
, entry
->name
, -1,
2454 logf("SN: %s", entry
->name
);
2456 /* logf("LN: %s", entry->name);
2457 logf("LNLen: %d (%c)", longname_utf8len,
2469 /* save this sector, for longname use */
2471 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2473 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2474 sectoridx
+= SECTOR_SIZE
;
2480 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2482 #ifndef HAVE_MULTIVOLUME
2483 const int volume
= 0;
2485 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2486 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2489 #ifdef HAVE_MULTIVOLUME
2490 bool fat_ismounted(int volume
)
2492 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);