1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
31 #include "timefuncs.h"
33 #include "rbunicode.h"
36 #define BYTES2INT16(array,pos) \
37 (array[pos] | (array[pos+1] << 8 ))
38 #define BYTES2INT32(array,pos) \
39 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
40 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
42 #define FATTYPE_FAT12 0
43 #define FATTYPE_FAT16 1
44 #define FATTYPE_FAT32 2
46 /* BPB offsets; generic */
49 #define BPB_BYTSPERSEC 11
50 #define BPB_SECPERCLUS 13
51 #define BPB_RSVDSECCNT 14
52 #define BPB_NUMFATS 16
53 #define BPB_ROOTENTCNT 17
54 #define BPB_TOTSEC16 19
56 #define BPB_FATSZ16 22
57 #define BPB_SECPERTRK 24
58 #define BPB_NUMHEADS 26
59 #define BPB_HIDDSEC 28
60 #define BPB_TOTSEC32 32
64 #define BS_RESERVED1 37
68 #define BS_FILSYSTYPE 54
71 #define BPB_FATSZ32 36
72 #define BPB_EXTFLAGS 40
74 #define BPB_ROOTCLUS 44
76 #define BPB_BKBOOTSEC 50
77 #define BS_32_DRVNUM 64
78 #define BS_32_BOOTSIG 66
79 #define BS_32_VOLID 67
80 #define BS_32_VOLLAB 71
81 #define BS_32_FILSYSTYPE 82
83 #define BPB_LAST_WORD 510
87 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
88 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
89 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
90 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
91 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
94 #define FAT_NTRES_LC_NAME 0x08
95 #define FAT_NTRES_LC_EXT 0x10
98 #define FATDIR_ATTR 11
99 #define FATDIR_NTRES 12
100 #define FATDIR_CRTTIMETENTH 13
101 #define FATDIR_CRTTIME 14
102 #define FATDIR_CRTDATE 16
103 #define FATDIR_LSTACCDATE 18
104 #define FATDIR_FSTCLUSHI 20
105 #define FATDIR_WRTTIME 22
106 #define FATDIR_WRTDATE 24
107 #define FATDIR_FSTCLUSLO 26
108 #define FATDIR_FILESIZE 28
110 #define FATLONG_ORDER 0
111 #define FATLONG_TYPE 12
112 #define FATLONG_CHKSUM 13
114 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
115 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
116 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
117 #define DIR_ENTRY_SIZE 32
118 #define NAME_BYTES_PER_ENTRY 13
119 #define FAT_BAD_MARK 0x0ffffff7
120 #define FAT_EOF_MARK 0x0ffffff8
121 #define FAT_LONGNAME_PAD_BYTE 0xff
122 #define FAT_LONGNAME_PAD_UCS 0xffff
125 unsigned long freecount
; /* last known free cluster count */
126 unsigned long nextfree
; /* first cluster to start looking for free
127 clusters, or 0xffffffff for no hint */
130 #define FSINFO_FREECOUNT 488
131 #define FSINFO_NEXTFREE 492
133 /* Note: This struct doesn't hold the raw values after mounting if
134 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
135 * physical sectors. */
138 int bpb_bytspersec
; /* Bytes per sector, typically 512 */
139 unsigned int bpb_secperclus
; /* Sectors per cluster */
140 int bpb_rsvdseccnt
; /* Number of reserved sectors */
141 int bpb_numfats
; /* Number of FAT structures, typically 2 */
142 int bpb_totsec16
; /* Number of sectors on the volume (old 16-bit) */
143 int bpb_media
; /* Media type (typically 0xf0 or 0xf8) */
144 int bpb_fatsz16
; /* Number of used sectors per FAT structure */
145 unsigned long bpb_totsec32
; /* Number of sectors on the volume
147 unsigned int last_word
; /* 0xAA55 */
149 /**** FAT32 specific *****/
154 /* variables for internal use */
155 unsigned long fatsize
;
156 unsigned long totalsectors
;
157 unsigned long rootdirsector
;
158 unsigned long firstdatasector
;
159 unsigned long startsector
;
160 unsigned long dataclusters
;
161 struct fsinfo fsinfo
;
162 #ifdef HAVE_FAT16SUPPORT
163 int bpb_rootentcnt
; /* Number of dir entries in the root */
164 /* internals for FAT16 support */
165 bool is_fat16
; /* true if we mounted a FAT16 partition, false if FAT32 */
166 unsigned int rootdiroffset
; /* sector offset of root dir relative to start
167 * of first pseudo cluster */
168 #endif /* #ifdef HAVE_FAT16SUPPORT */
169 #ifdef HAVE_MULTIVOLUME
170 #ifdef HAVE_MULTIDRIVE
171 int drive
; /* on which physical device is this located */
173 bool mounted
; /* flag if this volume is mounted */
177 static struct bpb fat_bpbs
[NUM_VOLUMES
]; /* mounted partition info */
178 static bool initialized
= false;
180 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
));
181 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
));
182 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
));
183 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
184 long secnum
, bool dirty
);
185 static void create_dos_name(const unsigned char *name
, unsigned char *newname
);
186 static void randomize_dos_name(unsigned char *name
);
187 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
188 unsigned long start
);
189 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
,
190 long count
, char* buf
, bool write
);
192 #define FAT_CACHE_SIZE 0x20
193 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
195 struct fat_cache_entry
200 #ifdef HAVE_MULTIVOLUME
201 struct bpb
* fat_vol
; /* shared cache for all volumes */
205 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
206 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
207 static struct mutex cache_mutex SHAREDBSS_ATTR
;
209 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
212 mutex_lock(&cache_mutex
);
215 void fat_unlock(void)
217 mutex_unlock(&cache_mutex
);
221 static long cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
223 #ifndef HAVE_MULTIVOLUME
224 struct bpb
* fat_bpb
= &fat_bpbs
[0];
226 #ifdef HAVE_FAT16SUPPORT
227 /* negative clusters (FAT16 root dir) don't get the 2 offset */
228 int zerocluster
= cluster
< 0 ? 0 : 2;
230 const long zerocluster
= 2;
233 if (cluster
> (long)(fat_bpb
->dataclusters
+ 1))
235 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster
);
239 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
240 + fat_bpb
->firstdatasector
;
243 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
245 #ifndef HAVE_MULTIVOLUME
246 const int volume
= 0;
248 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
250 *size
= fat_bpb
->dataclusters
* (fat_bpb
->bpb_secperclus
* SECTOR_SIZE
/ 1024);
252 *free
= fat_bpb
->fsinfo
.freecount
* (fat_bpb
->bpb_secperclus
* SECTOR_SIZE
/ 1024);
262 mutex_init(&cache_mutex
);
265 #ifdef HAVE_PRIORITY_SCHEDULING
266 /* Disable this because it is dangerous due to the assumption that
267 * mutex_unlock won't yield */
268 mutex_set_preempt(&cache_mutex
, false);
271 /* mark the FAT cache as unused */
272 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
274 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
275 fat_cache
[i
].inuse
= false;
276 fat_cache
[i
].dirty
= false;
277 #ifdef HAVE_MULTIVOLUME
278 fat_cache
[i
].fat_vol
= NULL
;
281 #ifdef HAVE_MULTIVOLUME
282 /* mark the possible volumes as not mounted */
283 for (i
=0; i
<NUM_VOLUMES
;i
++)
285 fat_bpbs
[i
].mounted
= false;
290 int fat_mount(IF_MV2(int volume
,) IF_MD2(int drive
,) long startsector
)
292 #ifndef HAVE_MULTIVOLUME
293 const int volume
= 0;
295 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
296 unsigned char buf
[SECTOR_SIZE
];
300 #ifdef HAVE_FAT16SUPPORT
304 /* Read the sector */
305 rc
= storage_read_sectors(drive
, startsector
,1,buf
);
308 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
312 memset(fat_bpb
, 0, sizeof(struct bpb
));
313 fat_bpb
->startsector
= startsector
;
314 #ifdef HAVE_MULTIDRIVE
315 fat_bpb
->drive
= drive
;
318 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
319 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
320 /* Sanity check is performed later */
322 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
323 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
324 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
325 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
326 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
327 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
328 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
329 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
330 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
332 /* calculate a few commonly used values */
333 if (fat_bpb
->bpb_fatsz16
!= 0)
334 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
336 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
338 if (fat_bpb
->bpb_totsec16
!= 0)
339 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
341 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
343 #ifdef HAVE_FAT16SUPPORT
344 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
345 if (!fat_bpb
->bpb_bytspersec
)
347 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
348 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
349 #endif /* #ifdef HAVE_FAT16SUPPORT */
351 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
352 #ifdef HAVE_FAT16SUPPORT
355 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
357 /* Determine FAT type */
358 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
359 if (fat_bpb
->bpb_secperclus
)
360 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
366 we are sometimes testing with "illegally small" fat32 images,
367 so we don't use the proper fat32 test case for test code
369 if ( fat_bpb
->bpb_fatsz16
)
371 if ( fat_bpb
->dataclusters
< 65525 )
374 #ifdef HAVE_FAT16SUPPORT
375 fat_bpb
->is_fat16
= true;
376 if (fat_bpb
->dataclusters
< 4085)
378 DEBUGF("This is FAT12. Go away!\n");
381 #else /* #ifdef HAVE_FAT16SUPPORT */
382 DEBUGF("This is not FAT32. Go away!\n");
384 #endif /* #ifndef HAVE_FAT16SUPPORT */
387 #ifdef HAVE_FAT16SUPPORT
388 if (fat_bpb
->is_fat16
)
389 { /* FAT16 specific part of BPB */
391 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
392 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
393 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
394 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
395 /* I assign negative pseudo cluster numbers for the root directory,
396 their range is counted upward until -1. */
397 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data*/
398 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
402 #endif /* #ifdef HAVE_FAT16SUPPORT */
403 { /* FAT32 specific part of BPB */
404 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
405 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
406 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,)
407 fat_bpb
->bpb_rootclus
);
410 rc
= bpb_is_sane(IF_MV(fat_bpb
));
413 DEBUGF( "fat_mount() - BPB is not sane\n");
417 #ifdef HAVE_FAT16SUPPORT
418 if (fat_bpb
->is_fat16
)
420 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
421 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
424 #endif /* #ifdef HAVE_FAT16SUPPORT */
426 /* Read the fsinfo sector */
427 rc
= storage_read_sectors(drive
,
428 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
431 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
434 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
435 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
438 /* calculate freecount if unset */
439 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
441 fat_recalc_free(IF_MV(volume
));
444 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
445 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
446 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
447 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
448 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
450 #ifdef HAVE_MULTIVOLUME
451 fat_bpb
->mounted
= true;
458 int fat_unmount(int volume
, bool flush
)
461 #ifdef HAVE_MULTIVOLUME
462 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
469 rc
= flush_fat(IF_MV(fat_bpb
)); /* the clean way, while still alive */
472 { /* volume is not accessible any more, e.g. MMC removed */
474 mutex_lock(&cache_mutex
);
475 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
477 struct fat_cache_entry
*fce
= &fat_cache
[i
];
479 #ifdef HAVE_MULTIVOLUME
480 && fce
->fat_vol
== fat_bpb
484 fce
->inuse
= false; /* discard all from that volume */
488 mutex_unlock(&cache_mutex
);
491 #ifdef HAVE_MULTIVOLUME
492 fat_bpb
->mounted
= false;
496 #endif /* #ifdef HAVE_HOTSWAP */
498 void fat_recalc_free(IF_MV_NONVOID(int volume
))
500 #ifndef HAVE_MULTIVOLUME
501 const int volume
= 0;
503 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
506 #ifdef HAVE_FAT16SUPPORT
507 if (fat_bpb
->is_fat16
)
509 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
511 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
512 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
513 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
514 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
517 if (letoh16(fat
[j
]) == 0x0000) {
519 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
520 fat_bpb
->fsinfo
.nextfree
= c
;
526 #endif /* #ifdef HAVE_FAT16SUPPORT */
528 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
530 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
531 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
532 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
533 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
536 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
538 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
539 fat_bpb
->fsinfo
.nextfree
= c
;
544 fat_bpb
->fsinfo
.freecount
= free
;
545 update_fsinfo(IF_MV(fat_bpb
));
548 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
550 #ifndef HAVE_MULTIVOLUME
551 struct bpb
* fat_bpb
= &fat_bpbs
[0];
553 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
555 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
556 fat_bpb
->bpb_bytspersec
);
559 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
562 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
564 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
565 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
568 if(fat_bpb
->bpb_numfats
!= 2)
570 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
571 fat_bpb
->bpb_numfats
);
573 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
575 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
576 "media type (0x%02x)\n",
579 if(fat_bpb
->last_word
!= 0xaa55)
581 DEBUGF( "bpb_is_sane() - Error: Last word is not "
582 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
586 if (fat_bpb
->fsinfo
.freecount
>
587 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
588 fat_bpb
->bpb_secperclus
)
590 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
591 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
598 static void flush_fat_sector(struct fat_cache_entry
*fce
,
599 unsigned char *sectorbuf
)
604 /* With multivolume, use only the FAT info from the cached sector! */
605 #ifdef HAVE_MULTIVOLUME
606 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
608 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
611 /* Write to the first FAT */
612 rc
= storage_write_sectors(fce
->fat_vol
->drive
,
617 panicf("flush_fat_sector() - Could not write sector %ld"
621 #ifdef HAVE_MULTIVOLUME
622 if(fce
->fat_vol
->bpb_numfats
> 1)
624 if(fat_bpbs
[0].bpb_numfats
> 1)
627 /* Write to the second FAT */
628 #ifdef HAVE_MULTIVOLUME
629 secnum
+= fce
->fat_vol
->fatsize
;
631 secnum
+= fat_bpbs
[0].fatsize
;
633 rc
= storage_write_sectors(fce
->fat_vol
->drive
,
634 secnum
, 1, sectorbuf
);
637 panicf("flush_fat_sector() - Could not write sector %ld"
645 /* Note: The returned pointer is only safely valid until the next
646 task switch! (Any subsequent ata read/write may yield.) */
647 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
648 long fatsector
, bool dirty
)
650 #ifndef HAVE_MULTIVOLUME
651 struct bpb
* fat_bpb
= &fat_bpbs
[0];
653 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
654 int cache_index
= secnum
& FAT_CACHE_MASK
;
655 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
656 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
659 mutex_lock(&cache_mutex
); /* make changes atomic */
661 /* Delete the cache entry if it isn't the sector we want */
662 if(fce
->inuse
&& (fce
->secnum
!= secnum
663 #ifdef HAVE_MULTIVOLUME
664 || fce
->fat_vol
!= fat_bpb
668 /* Write back if it is dirty */
671 flush_fat_sector(fce
, sectorbuf
);
676 /* Load the sector if it is not cached */
679 rc
= storage_read_sectors(fat_bpb
->drive
,
680 secnum
+ fat_bpb
->startsector
,1,
684 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
685 " (error %d)\n", secnum
, rc
);
686 mutex_unlock(&cache_mutex
);
690 fce
->secnum
= secnum
;
691 #ifdef HAVE_MULTIVOLUME
692 fce
->fat_vol
= fat_bpb
;
696 fce
->dirty
= true; /* dirt remains, sticky until flushed */
697 mutex_unlock(&cache_mutex
);
701 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
702 unsigned long startcluster
)
704 #ifndef HAVE_MULTIVOLUME
705 struct bpb
* fat_bpb
= &fat_bpbs
[0];
707 unsigned long sector
;
708 unsigned long offset
;
711 #ifdef HAVE_FAT16SUPPORT
712 if (fat_bpb
->is_fat16
)
714 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
715 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
717 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
719 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
720 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
723 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
724 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
725 if (letoh16(fat
[k
]) == 0x0000) {
726 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
727 /* Ignore the reserved clusters 0 & 1, and also
728 cluster numbers out of bounds */
729 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
731 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
732 fat_bpb
->fsinfo
.nextfree
= c
;
740 #endif /* #ifdef HAVE_FAT16SUPPORT */
742 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
743 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
745 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
747 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
748 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
751 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
752 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
753 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
754 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
755 /* Ignore the reserved clusters 0 & 1, and also
756 cluster numbers out of bounds */
757 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
759 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
760 fat_bpb
->fsinfo
.nextfree
= c
;
768 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
769 return 0; /* 0 is an illegal cluster number */
772 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
775 #ifndef HAVE_MULTIVOLUME
776 struct bpb
* fat_bpb
= &fat_bpbs
[0];
778 #ifdef HAVE_FAT16SUPPORT
779 if (fat_bpb
->is_fat16
)
781 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
782 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
787 LDEBUGF("update_fat_entry(%x,%x)\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 %d\n", sector
);
803 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
804 fat_bpb
->fsinfo
.freecount
--;
807 if (letoh16(sec
[offset
]))
808 fat_bpb
->fsinfo
.freecount
++;
811 LDEBUGF("update_fat_entry: %d free clusters\n",
812 fat_bpb
->fsinfo
.freecount
);
814 sec
[offset
] = htole16(val
);
817 #endif /* #ifdef HAVE_FAT16SUPPORT */
819 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
820 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
823 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
826 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
829 panicf("Updating reserved FAT entry %ld.\n",entry
);
831 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
834 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
839 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
840 fat_bpb
->fsinfo
.freecount
> 0)
841 fat_bpb
->fsinfo
.freecount
--;
844 if (letoh32(sec
[offset
]) & 0x0fffffff)
845 fat_bpb
->fsinfo
.freecount
++;
848 LDEBUGF("update_fat_entry: %ld free clusters\n",
849 fat_bpb
->fsinfo
.freecount
);
851 /* don't change top 4 bits */
852 sec
[offset
] &= htole32(0xf0000000);
853 sec
[offset
] |= htole32(val
& 0x0fffffff);
859 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
861 #ifdef HAVE_FAT16SUPPORT
862 #ifndef HAVE_MULTIVOLUME
863 struct bpb
* fat_bpb
= &fat_bpbs
[0];
865 if (fat_bpb
->is_fat16
)
867 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
868 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
871 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
874 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
878 return letoh16(sec
[offset
]);
881 #endif /* #ifdef HAVE_FAT16SUPPORT */
883 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
884 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
887 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
890 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
894 return letoh32(sec
[offset
]) & 0x0fffffff;
898 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
901 long eof_mark
= FAT_EOF_MARK
;
903 #ifdef HAVE_FAT16SUPPORT
904 #ifndef HAVE_MULTIVOLUME
905 struct bpb
* fat_bpb
= &fat_bpbs
[0];
907 if (fat_bpb
->is_fat16
)
909 eof_mark
&= 0xFFFF; /* only 16 bit */
910 if (cluster
< 0) /* FAT16 root dir */
911 return cluster
+ 1; /* don't use the FAT */
914 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
916 /* is this last cluster in chain? */
917 if ( next_cluster
>= eof_mark
)
923 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
925 #ifndef HAVE_MULTIVOLUME
926 struct bpb
* fat_bpb
= &fat_bpbs
[0];
928 unsigned char fsinfo
[SECTOR_SIZE
];
929 unsigned long* intptr
;
932 #ifdef HAVE_FAT16SUPPORT
933 if (fat_bpb
->is_fat16
)
934 return 0; /* FAT16 has no FsInfo */
935 #endif /* #ifdef HAVE_FAT16SUPPORT */
938 rc
= storage_read_sectors(fat_bpb
->drive
,
939 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
942 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
945 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
946 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
948 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
949 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
951 rc
= storage_write_sectors(fat_bpb
->drive
,
952 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
955 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
962 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
967 LDEBUGF("flush_fat()\n");
969 mutex_lock(&cache_mutex
);
970 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
972 struct fat_cache_entry
*fce
= &fat_cache
[i
];
974 #ifdef HAVE_MULTIVOLUME
975 && fce
->fat_vol
== fat_bpb
979 sec
= fat_cache_sectors
[i
];
980 flush_fat_sector(fce
, sec
);
983 mutex_unlock(&cache_mutex
);
985 rc
= update_fsinfo(IF_MV(fat_bpb
));
992 static void fat_time(unsigned short* date
,
993 unsigned short* time
,
994 unsigned short* tenth
)
997 struct tm
* tm
= get_time();
1000 *date
= ((tm
->tm_year
- 80) << 9) |
1001 ((tm
->tm_mon
+ 1) << 5) |
1005 *time
= (tm
->tm_hour
<< 11) |
1010 *tenth
= (tm
->tm_sec
& 1) * 100;
1012 /* non-RTC version returns an increment from the supplied time, or a
1013 * fixed standard time/date if no time given as input */
1015 /* Macros to convert a 2-digit string to a decimal constant.
1016 (YEAR), MONTH and DAY are set by the date command, which outputs
1017 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1018 misinterpretation as an octal constant. */
1019 #define S100(x) 1 ## x
1020 #define C2DIG2DEC(x) (S100(x)-100)
1021 /* The actual build date, as FAT date constant */
1022 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1023 | (C2DIG2DEC(MONTH) << 5) \
1026 bool date_forced
= false;
1027 bool next_day
= false;
1028 unsigned time2
= 0; /* double time, for CRTTIME with 1s precision */
1030 if (date
&& *date
< BUILD_DATE_FAT
)
1032 *date
= BUILD_DATE_FAT
;
1039 if (time2
== 0 || date_forced
)
1041 time2
= (11 < 6) | 11; /* set to 00:11:11 */
1045 unsigned mins
= (time2
>> 6) & 0x3f;
1046 unsigned hours
= (time2
>> 12) & 0x1f;
1048 mins
= 11 * ((mins
/11) + 1); /* advance to next multiple of 11 */
1051 mins
= 11; /* 00 would be a bad marker */
1058 time2
= (hours
<< 12) | (mins
<< 6) | mins
; /* secs = mins */
1064 *tenth
= (time2
& 1) * 100;
1066 if (date
&& next_day
)
1068 static const unsigned char daysinmonth
[] =
1069 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1070 unsigned day
= *date
& 0x1f;
1071 unsigned month
= (*date
>> 5) & 0x0f;
1072 unsigned year
= (*date
>> 9) & 0x7f;
1074 /* simplification: ignore leap years */
1075 if (++day
> daysinmonth
[month
-1])
1084 *date
= (year
<< 9) | (month
<< 5) | day
;
1087 #endif /* CONFIG_RTC */
1090 static int write_long_name(struct fat_file
* file
,
1091 unsigned int firstentry
,
1092 unsigned int numentries
,
1093 const unsigned char* name
,
1094 const unsigned char* shortname
,
1097 unsigned char buf
[SECTOR_SIZE
];
1098 unsigned char* entry
;
1099 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1100 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1101 unsigned char chksum
= 0;
1102 unsigned int i
, j
=0;
1103 unsigned int nameidx
=0, namelen
= utf8length(name
);
1105 unsigned short name_utf16
[namelen
+ 1];
1107 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1108 file
->firstcluster
, firstentry
, numentries
, name
);
1110 rc
= fat_seek(file
, sector
);
1114 rc
= fat_readwrite(file
, 1, buf
, false);
1118 /* calculate shortname checksum */
1119 for (i
=11; i
>0; i
--)
1120 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1122 /* calc position of last name segment */
1123 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1125 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1126 nameidx
+= NAME_BYTES_PER_ENTRY
);
1128 /* we need to convert the name first */
1129 /* since it is written in reverse order */
1130 for (i
= 0; i
<= namelen
; i
++)
1131 name
= utf8decode(name
, &name_utf16
[i
]);
1133 for (i
=0; i
< numentries
; i
++) {
1135 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1136 /* update current sector */
1137 rc
= fat_seek(file
, sector
);
1141 rc
= fat_readwrite(file
, 1, buf
, true);
1145 /* read next sector */
1146 rc
= fat_readwrite(file
, 1, buf
, false);
1148 LDEBUGF("Failed writing new sector: %d\n",rc
);
1153 memset(buf
, 0, sizeof buf
);
1159 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1161 /* verify this entry is free */
1162 if (entry
[0] && entry
[0] != 0xe5 )
1163 panicf("Dir entry %d in sector %x is not free! "
1164 "%02x %02x %02x %02x",
1166 entry
[0], entry
[1], entry
[2], entry
[3]);
1168 memset(entry
, 0, DIR_ENTRY_SIZE
);
1169 if ( i
+1 < numentries
) {
1170 /* longname entry */
1171 unsigned int k
, l
= nameidx
;
1173 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1175 /* mark this as last long entry */
1176 entry
[FATLONG_ORDER
] |= 0x40;
1178 /* pad name with 0xffff */
1179 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1180 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1181 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1184 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1185 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1186 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1188 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1189 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1190 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1192 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1193 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1194 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1197 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1198 entry
[FATDIR_FSTCLUSLO
] = 0;
1199 entry
[FATLONG_TYPE
] = 0;
1200 entry
[FATLONG_CHKSUM
] = chksum
;
1201 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1204 /* shortname entry */
1205 unsigned short date
=0, time
=0, tenth
=0;
1206 LDEBUGF("Shortname entry: %s\n", shortname
);
1207 memcpy(entry
+ FATDIR_NAME
, shortname
, 11);
1208 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1209 entry
[FATDIR_NTRES
] = 0;
1211 fat_time(&date
, &time
, &tenth
);
1212 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1213 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1214 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1215 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1216 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1217 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1220 nameidx
-= NAME_BYTES_PER_ENTRY
;
1223 /* update last sector */
1224 rc
= fat_seek(file
, sector
);
1228 rc
= fat_readwrite(file
, 1, buf
, true);
1235 static int fat_checkname(const unsigned char* newname
)
1237 static const char invalid_chars
[] = "\"*/:<>?\\|";
1238 int len
= strlen(newname
);
1239 /* More sanity checks are probably needed */
1240 if (len
> 255 || newname
[len
- 1] == '.')
1246 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1250 /* check trailing space(s) */
1251 if(*(--newname
) == ' ')
1257 static int add_dir_entry(struct fat_dir
* dir
,
1258 struct fat_file
* file
,
1263 #ifdef HAVE_MULTIVOLUME
1264 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1266 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1268 unsigned char buf
[SECTOR_SIZE
];
1269 unsigned char shortname
[12];
1271 unsigned int sector
;
1273 int entries_needed
, entries_found
= 0;
1276 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1277 name
, file
->firstcluster
);
1279 /* Don't check dotdirs name for validity */
1280 if (dotdir
== false) {
1281 rc
= fat_checkname(name
);
1283 /* filename is invalid */
1288 #ifdef HAVE_MULTIVOLUME
1289 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1292 /* The "." and ".." directory entries must not be long names */
1295 strlcpy(shortname
, name
, 12);
1296 for(i
= strlen(shortname
); i
< 12; i
++)
1301 create_dos_name(name
, shortname
);
1303 /* one dir entry needed for every 13 bytes of filename,
1304 plus one entry for the short name */
1305 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1306 / NAME_BYTES_PER_ENTRY
+ 1;
1312 rc
= fat_seek(&dir
->file
, 0);
1316 /* step 1: search for free entries and check for duplicate shortname */
1317 for (sector
= 0; !done
; sector
++)
1321 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1323 DEBUGF( "add_dir_entry() - Couldn't read dir"
1324 " (error code %d)\n", rc
);
1328 if (rc
== 0) { /* current end of dir reached */
1329 LDEBUGF("End of dir on cluster boundary\n");
1333 /* look for free slots */
1334 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1336 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1338 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1339 LDEBUGF("Found end of dir %d\n",
1340 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1341 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1347 LDEBUGF("Found free entry %d (%d/%d)\n",
1348 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1349 entries_found
, entries_needed
);
1355 /* check that our intended shortname doesn't already exist */
1356 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1357 /* shortname exists already, make a new one */
1358 randomize_dos_name(shortname
);
1359 LDEBUGF("Duplicate shortname, changing to %s\n",
1362 /* name has changed, we need to restart search */
1367 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1368 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1373 /* step 2: extend the dir if necessary */
1376 LDEBUGF("Adding new sector(s) to dir\n");
1377 rc
= fat_seek(&dir
->file
, sector
);
1380 memset(buf
, 0, sizeof buf
);
1382 /* we must clear whole clusters */
1383 for (; (entries_found
< entries_needed
) ||
1384 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1386 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1387 return -5; /* dir too large -- FAT specification */
1389 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1390 if (rc
< 1) /* No more room or something went wrong */
1393 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1396 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1399 /* step 3: add entry */
1400 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1401 LDEBUGF("Adding longname to entry %d in sector %d\n",
1402 firstentry
, sector
);
1404 rc
= write_long_name(&dir
->file
, firstentry
,
1405 entries_needed
, name
, shortname
, is_directory
);
1409 /* remember where the shortname dir entry is located */
1410 file
->direntry
= firstentry
+ entries_needed
- 1;
1411 file
->direntries
= entries_needed
;
1412 file
->dircluster
= dir
->file
.firstcluster
;
1413 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1414 file
->direntry
, file
->direntries
);
1419 static unsigned char char2dos(unsigned char c
, int* randomize
)
1421 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1424 c
= 0; /* Illegal char, remove */
1425 else if (strchr(invalid_chars
, c
) != NULL
)
1427 /* Illegal char, replace */
1429 *randomize
= 1; /* as per FAT spec */
1437 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1443 /* Find extension part */
1444 ext
= strrchr(name
, '.');
1445 if (ext
== name
) /* handle .dotnames */
1448 /* needs to randomize? */
1449 if((ext
&& (strlen(ext
) > 4)) ||
1450 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1454 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1456 unsigned char c
= char2dos(*name
, &randomize
);
1461 /* Pad both name and extension */
1465 if (newname
[0] == 0xe5) /* Special kanji character */
1469 { /* Extension part */
1471 for (i
= 8; *ext
&& (i
< 11); ext
++)
1473 unsigned char c
= char2dos(*ext
, &randomize
);
1480 randomize_dos_name(newname
);
1483 static void randomize_dos_name(unsigned char *name
)
1485 unsigned char* tilde
= NULL
; /* ~ location */
1486 unsigned char* lastpt
= NULL
; /* last point of filename */
1487 unsigned char* nameptr
= name
; /* working copy of name pointer */
1488 unsigned char num
[9]; /* holds number as string */
1496 /* hunt for ~ and where to put it */
1497 if((!tilde
) && (*nameptr
== '~'))
1499 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1505 /* extract current count and increment */
1506 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1507 num
[7-(unsigned int)(tilde
-name
)] = 0;
1508 cnt
= atoi(num
) + 1;
1510 cnt
%= 10000000; /* protection */
1511 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1512 numlen
= strlen(num
); /* required space */
1513 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1514 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1516 memcpy(&name
[offset
], num
, numlen
);
1518 /* in special case of counter overflow: pad with spaces */
1519 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1523 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1525 unsigned char buf
[SECTOR_SIZE
];
1526 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1527 unsigned char* entry
=
1528 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1529 unsigned long* sizeptr
;
1530 unsigned short* clusptr
;
1531 struct fat_file dir
;
1534 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1535 file
->firstcluster
, file
->direntry
, size
);
1537 /* create a temporary file handle for the dir holding this file */
1538 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1542 rc
= fat_seek( &dir
, sector
);
1546 rc
= fat_readwrite(&dir
, 1, buf
, false);
1550 if (!entry
[0] || entry
[0] == 0xe5)
1551 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1553 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1555 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1556 *clusptr
= htole16(file
->firstcluster
>> 16);
1558 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1559 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1561 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1562 *sizeptr
= htole32(size
);
1566 unsigned short time
= 0;
1567 unsigned short date
= 0;
1569 /* get old time to increment from */
1570 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1571 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1573 fat_time(&date
, &time
, NULL
);
1574 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1575 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1576 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1579 rc
= fat_seek( &dir
, sector
);
1583 rc
= fat_readwrite(&dir
, 1, buf
, true);
1590 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1596 memset(de
, 0, sizeof(struct fat_direntry
));
1597 de
->attr
= buf
[FATDIR_ATTR
];
1598 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1599 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1600 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1601 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1602 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1603 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1604 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1605 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1606 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1607 (the result of the shift is always considered signed) */
1610 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1611 c
= buf
[FATDIR_NAME
];
1612 if (c
== 0x05) /* special kanji char */
1616 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1619 c
= buf
[FATDIR_NAME
+i
];
1621 if (buf
[FATDIR_NAME
+8] != ' ') {
1622 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1623 de
->name
[j
++] = '.';
1624 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1625 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1630 int fat_open(IF_MV2(int volume
,)
1632 struct fat_file
*file
,
1633 const struct fat_dir
* dir
)
1635 file
->firstcluster
= startcluster
;
1636 file
->lastcluster
= startcluster
;
1637 file
->lastsector
= 0;
1638 file
->clusternum
= 0;
1639 file
->sectornum
= 0;
1641 #ifdef HAVE_MULTIVOLUME
1642 file
->volume
= volume
;
1643 /* fixme: remove error check when done */
1644 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1646 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1651 /* remember where the file's dir entry is located */
1653 file
->direntry
= dir
->entry
- 1;
1654 file
->direntries
= dir
->entrycount
;
1655 file
->dircluster
= dir
->file
.firstcluster
;
1657 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1661 int fat_create_file(const char* name
,
1662 struct fat_file
* file
,
1663 struct fat_dir
* dir
)
1667 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1668 rc
= add_dir_entry(dir
, file
, name
, false, false);
1670 file
->firstcluster
= 0;
1671 file
->lastcluster
= 0;
1672 file
->lastsector
= 0;
1673 file
->clusternum
= 0;
1674 file
->sectornum
= 0;
1681 int fat_create_dir(const char* name
,
1682 struct fat_dir
* newdir
,
1683 struct fat_dir
* dir
)
1685 #ifdef HAVE_MULTIVOLUME
1686 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1688 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1690 unsigned char buf
[SECTOR_SIZE
];
1694 struct fat_file dummyfile
;
1696 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1698 memset(newdir
, 0, sizeof(struct fat_dir
));
1699 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1701 /* First, add the entry in the parent directory */
1702 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1706 /* Allocate a new cluster for the directory */
1707 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1708 fat_bpb
->fsinfo
.nextfree
);
1709 if(newdir
->file
.firstcluster
== 0)
1712 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1714 /* Clear the entire cluster */
1715 memset(buf
, 0, sizeof buf
);
1716 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1717 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1718 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1723 /* Then add the "." entry */
1724 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1727 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1728 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1730 /* and the ".." entry */
1731 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1735 /* The root cluster is cluster 0 in the ".." entry */
1736 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1737 dummyfile
.firstcluster
= 0;
1739 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1740 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1742 /* Set the firstcluster field in the direntry */
1743 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1745 rc
= flush_fat(IF_MV(fat_bpb
));
1752 int fat_truncate(const struct fat_file
*file
)
1754 /* truncate trailing clusters */
1756 long last
= file
->lastcluster
;
1757 #ifdef HAVE_MULTIVOLUME
1758 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1761 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1763 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1764 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1765 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1767 if (file
->lastcluster
)
1768 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1773 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1776 #ifdef HAVE_MULTIVOLUME
1777 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1779 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1783 if ( file
->firstcluster
) {
1784 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1785 file
->firstcluster
= 0;
1789 if (file
->dircluster
) {
1790 rc
= update_short_entry(file
, size
, attr
);
1795 flush_fat(IF_MV(fat_bpb
));
1798 if ( file
->firstcluster
) {
1800 #ifdef HAVE_MULTIVOLUME
1801 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1803 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1808 for ( next
= file
->firstcluster
; next
;
1809 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1810 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1813 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1814 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1816 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1817 panicf("Cluster chain is too long\n");
1819 panicf("Cluster chain is too short\n");
1826 static int free_direntries(struct fat_file
* file
)
1828 unsigned char buf
[SECTOR_SIZE
];
1829 struct fat_file dir
;
1830 int numentries
= file
->direntries
;
1831 unsigned int entry
= file
->direntry
- numentries
+ 1;
1832 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1836 /* create a temporary file handle for the dir holding this file */
1837 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1841 rc
= fat_seek( &dir
, sector
);
1845 rc
= fat_readwrite(&dir
, 1, buf
, false);
1849 for (i
=0; i
< numentries
; i
++) {
1850 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1851 entry
, i
+1, numentries
);
1852 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1855 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1856 /* flush this sector */
1857 rc
= fat_seek(&dir
, sector
);
1861 rc
= fat_readwrite(&dir
, 1, buf
, true);
1865 if ( i
+1 < numentries
) {
1866 /* read next sector */
1867 rc
= fat_readwrite(&dir
, 1, buf
, false);
1875 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1876 /* flush this sector */
1877 rc
= fat_seek(&dir
, sector
);
1881 rc
= fat_readwrite(&dir
, 1, buf
, true);
1889 int fat_remove(struct fat_file
* file
)
1891 long next
, last
= file
->firstcluster
;
1893 #ifdef HAVE_MULTIVOLUME
1894 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1897 LDEBUGF("fat_remove(%lx)\n",last
);
1900 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1901 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1905 if ( file
->dircluster
) {
1906 rc
= free_direntries(file
);
1911 file
->firstcluster
= 0;
1912 file
->dircluster
= 0;
1914 rc
= flush_fat(IF_MV(fat_bpb
));
1921 int fat_rename(struct fat_file
* file
,
1922 struct fat_dir
* dir
,
1923 const unsigned char* newname
,
1928 struct fat_dir olddir
;
1929 struct fat_file newfile
= *file
;
1930 unsigned char buf
[SECTOR_SIZE
];
1931 unsigned char* entry
= NULL
;
1932 unsigned short* clusptr
= NULL
;
1933 unsigned int parentcluster
;
1934 #ifdef HAVE_MULTIVOLUME
1935 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1937 if (file
->volume
!= dir
->file
.volume
) {
1938 DEBUGF("No rename across volumes!\n");
1942 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1945 if ( !file
->dircluster
) {
1946 DEBUGF("File has no dir cluster!\n");
1950 /* create a temporary file handle */
1951 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1955 /* create new name */
1956 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1960 /* write size and cluster link */
1961 rc
= update_short_entry(&newfile
, size
, attr
);
1965 /* remove old name */
1966 rc
= free_direntries(file
);
1970 rc
= flush_fat(IF_MV(fat_bpb
));
1974 /* if renaming a directory, update the .. entry to make sure
1975 it points to its parent directory (we don't check if it was a move) */
1976 if(FAT_ATTR_DIRECTORY
== attr
) {
1977 /* open the dir that was renamed, we re-use the olddir struct */
1978 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1983 /* get the first sector of the dir */
1984 rc
= fat_seek(&olddir
.file
, 0);
1988 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1992 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1993 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1996 parentcluster
= dir
->file
.firstcluster
;
1998 entry
= buf
+ DIR_ENTRY_SIZE
;
1999 if(strncmp(".. ", entry
, 11))
2001 /* .. entry must be second entry according to FAT spec (p.29) */
2002 DEBUGF("Second dir entry is not double-dot!\n");
2005 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
2006 *clusptr
= htole16(parentcluster
>> 16);
2008 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
2009 *clusptr
= htole16(parentcluster
& 0xffff);
2011 /* write back this sector */
2012 rc
= fat_seek(&olddir
.file
, 0);
2016 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
2024 static long next_write_cluster(struct fat_file
* file
,
2028 #ifdef HAVE_MULTIVOLUME
2029 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2031 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2036 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
2039 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
2043 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
2044 else if (oldcluster
== 0)
2045 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
2046 fat_bpb
->fsinfo
.nextfree
);
2047 #ifdef HAVE_FAT16SUPPORT
2048 else /* negative, pseudo-cluster of the root dir */
2049 return 0; /* impossible to append something to the root */
2054 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2056 file
->firstcluster
= cluster
;
2057 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2061 if (fat_bpb
->fsinfo
.freecount
>0)
2062 panicf("There is free space, but find_free_cluster() "
2063 "didn't find it!\n");
2065 DEBUGF("next_write_cluster(): Disk full!\n");
2069 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2073 *newsector
= sector
;
2077 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2078 unsigned long start
, long count
, char* buf
, bool write
)
2080 #ifndef HAVE_MULTIVOLUME
2081 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2085 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2086 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2088 unsigned long firstallowed
;
2089 #ifdef HAVE_FAT16SUPPORT
2090 if (fat_bpb
->is_fat16
)
2091 firstallowed
= fat_bpb
->rootdirsector
;
2094 firstallowed
= fat_bpb
->firstdatasector
;
2096 if (start
< firstallowed
)
2097 panicf("Write %ld before data\n", firstallowed
- start
);
2098 if (start
+ count
> fat_bpb
->totalsectors
)
2099 panicf("Write %ld after data\n",
2100 start
+ count
- fat_bpb
->totalsectors
);
2101 rc
= storage_write_sectors(fat_bpb
->drive
,
2102 start
+ fat_bpb
->startsector
, count
, buf
);
2105 rc
= storage_read_sectors(fat_bpb
->drive
,
2106 start
+ fat_bpb
->startsector
, count
, buf
);
2108 DEBUGF( "transfer() - Couldn't %s sector %lx"
2109 " (error code %d)\n",
2110 write
? "write":"read", start
, rc
);
2117 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2118 void* buf
, bool write
)
2120 #ifdef HAVE_MULTIVOLUME
2121 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2123 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2125 long cluster
= file
->lastcluster
;
2126 long sector
= file
->lastsector
;
2127 long clusternum
= file
->clusternum
;
2128 long numsec
= file
->sectornum
;
2129 bool eof
= file
->eof
;
2130 long first
=0, last
=0;
2134 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2135 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2136 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2137 sector
,numsec
, eof
?1:0);
2142 /* find sequential sectors and write them all at once */
2143 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2145 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2146 long oldcluster
= cluster
;
2147 long oldsector
= sector
;
2148 long oldnumsec
= numsec
;
2150 cluster
= next_write_cluster(file
, cluster
, §or
);
2152 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2153 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2162 /* remember last cluster, in case
2163 we want to append to the file */
2165 cluster
= oldcluster
;
2168 i
= -1; /* Error code */
2179 /* look up first sector of file */
2180 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2182 #ifdef HAVE_FAT16SUPPORT
2183 if (file
->firstcluster
< 0)
2184 { /* FAT16 root dir */
2185 sector
+= fat_bpb
->rootdiroffset
;
2186 numsec
+= fat_bpb
->rootdiroffset
;
2195 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2196 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2197 long count
= last
- first
+ 1;
2198 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2202 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2206 if ((i
== sectorcount
-1) && /* last sector requested */
2209 long count
= sector
- first
+ 1;
2210 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2218 file
->lastcluster
= cluster
;
2219 file
->lastsector
= sector
;
2220 file
->clusternum
= clusternum
;
2221 file
->sectornum
= numsec
;
2224 /* if eof, don't report last block as read/written */
2228 DEBUGF("Sectors written: %ld\n", i
);
2232 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2234 #ifdef HAVE_MULTIVOLUME
2235 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2237 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2239 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2240 long cluster
= file
->firstcluster
;
2243 #ifdef HAVE_FAT16SUPPORT
2244 if (cluster
< 0) /* FAT16 root dir */
2245 seeksector
+= fat_bpb
->rootdiroffset
;
2250 /* we need to find the sector BEFORE the requested, since
2251 the file struct stores the last accessed sector */
2253 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2254 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2256 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2258 cluster
= file
->lastcluster
;
2259 numclusters
-= file
->clusternum
;
2262 for (i
=0; i
<numclusters
; i
++) {
2263 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2265 DEBUGF("Seeking beyond the end of the file! "
2266 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2271 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2277 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2278 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2280 file
->lastcluster
= cluster
;
2281 file
->lastsector
= sector
;
2282 file
->clusternum
= clusternum
;
2283 file
->sectornum
= sectornum
+ 1;
2287 int fat_opendir(IF_MV2(int volume
,)
2288 struct fat_dir
*dir
, unsigned long startcluster
,
2289 const struct fat_dir
*parent_dir
)
2291 #ifdef HAVE_MULTIVOLUME
2292 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2293 /* fixme: remove error check when done */
2294 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2296 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2300 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2307 if (startcluster
== 0)
2308 startcluster
= fat_bpb
->bpb_rootclus
;
2310 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2313 DEBUGF( "fat_opendir() - Couldn't open dir"
2314 " (error code %d)\n", rc
);
2321 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2322 * destination buffer (UTF-8 encoded). Copying is stopped when
2323 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2324 * Trailing \0 is also appended at the end of the UTF8-encoded
2327 * utf16src utf16 (little endian) segment to copy
2328 * utf16count max number of the utf16-characters to copy
2329 * utf8dst where to write UTF8-encoded string to
2331 * returns the number of UTF-16 characters actually copied
2333 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2334 int utf16count
, unsigned char *utf8dst
) {
2336 while ((utf16count
--) > 0) {
2337 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2338 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2341 utf8dst
= utf8encode(ucs
, utf8dst
);
2349 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2354 unsigned char firstbyte
;
2355 /* Long file names are stored in special entries. Each entry holds
2356 up to 13 characters. Names can be max 255 chars (not bytes!) long
2357 hence max 20 entries are required. */
2361 unsigned char* cached_buf
= dir
->sectorcache
[0];
2363 dir
->entrycount
= 0;
2367 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2369 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2376 DEBUGF( "fat_getnext() - Couldn't read dir"
2377 " (error code %d)\n", rc
);
2380 dir
->sector
= dir
->file
.lastsector
;
2383 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2384 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2386 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2388 firstbyte
= cached_buf
[entrypos
];
2391 if (firstbyte
== 0xe5) {
2394 dir
->entrycount
= 0;
2398 if (firstbyte
== 0) {
2401 dir
->entrycount
= 0;
2407 /* longname entry? */
2408 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2409 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2410 longarray
[longs
++] = entrypos
+ sectoridx
;
2413 if ( parse_direntry(entry
,
2414 &cached_buf
[entrypos
]) ) {
2416 /* don't return volume id entry */
2418 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2419 == FAT_ATTR_VOLUME_ID
)
2422 /* replace shortname with longname? */
2425 /* This should be enough to hold any name segment
2427 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2428 /* Add 1 for trailing \0 */
2429 unsigned char longname_utf8segm
[6*4 + 1];
2430 int longname_utf8len
= 0;
2431 /* Temporarily store it */
2432 strcpy(shortname
, entry
->name
);
2435 /* iterate backwards through the dir entries */
2436 for (j
=longs
-1; j
>=0; j
--) {
2437 unsigned char* ptr
= cached_buf
;
2438 int index
= longarray
[j
];
2439 /* current or cached sector? */
2440 if ( sectoridx
>= SECTOR_SIZE
) {
2441 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2442 if ( ( index
>= SECTOR_SIZE
) &&
2443 ( index
< SECTOR_SIZE
*2 ))
2444 ptr
= dir
->sectorcache
[1];
2446 ptr
= dir
->sectorcache
[2];
2449 if ( index
< SECTOR_SIZE
)
2450 ptr
= dir
->sectorcache
[1];
2453 index
&= SECTOR_SIZE
-1;
2456 /* Try to append each segment of the long name.
2457 Check if we'd exceed the buffer.
2458 Also check for FAT padding characters 0xFFFF. */
2459 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2460 longname_utf8segm
) == 0) break;
2461 /* logf("SG: %s, EN: %s", longname_utf8segm,
2463 longname_utf8len
+= strlen(longname_utf8segm
);
2464 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2465 strcat(entry
->name
, longname_utf8segm
);
2469 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
2470 longname_utf8segm
) == 0) break;
2471 /* logf("SG: %s, EN: %s", longname_utf8segm,
2473 longname_utf8len
+= strlen(longname_utf8segm
);
2474 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2475 strcat(entry
->name
, longname_utf8segm
);
2479 if (fat_copy_long_name_segment(ptr
+ index
+ 28, 2,
2480 longname_utf8segm
) == 0) break;
2481 /* logf("SG: %s, EN: %s", longname_utf8segm,
2483 longname_utf8len
+= strlen(longname_utf8segm
);
2484 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2485 strcat(entry
->name
, longname_utf8segm
);
2490 /* Does the utf8-encoded name fit into the entry? */
2491 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2492 /* Take the short DOS name. Need to utf8-encode it
2493 since it may contain chars from the upper half of
2494 the OEM code page which wouldn't be a valid utf8.
2495 Beware: this file will be shown with strange
2496 glyphs in file browser since unicode 0x80 to 0x9F
2497 are control characters. */
2498 logf("SN-DOS: %s", shortname
);
2499 unsigned char *utf8
;
2500 utf8
= iso_decode(shortname
, entry
->name
, -1,
2503 logf("SN: %s", entry
->name
);
2505 /* logf("LN: %s", entry->name);
2506 logf("LNLen: %d (%c)", longname_utf8len,
2518 /* save this sector, for longname use */
2520 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2522 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2523 sectoridx
+= SECTOR_SIZE
;
2529 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2531 #ifndef HAVE_MULTIVOLUME
2532 const int volume
= 0;
2534 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2535 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2538 #ifdef HAVE_MULTIVOLUME
2539 bool fat_ismounted(int volume
)
2541 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);