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
/ 2;
252 *free
= fat_bpb
->fsinfo
.freecount
* fat_bpb
->bpb_secperclus
/ 2;
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 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
465 rc
= flush_fat(fat_bpb
); /* the clean way, while still alive */
468 { /* volume is not accessible any more, e.g. MMC removed */
470 mutex_lock(&cache_mutex
);
471 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
473 struct fat_cache_entry
*fce
= &fat_cache
[i
];
474 if(fce
->inuse
&& fce
->fat_vol
== fat_bpb
)
476 fce
->inuse
= false; /* discard all from that volume */
480 mutex_unlock(&cache_mutex
);
483 fat_bpb
->mounted
= false;
486 #endif /* #ifdef HAVE_HOTSWAP */
488 void fat_recalc_free(IF_MV_NONVOID(int volume
))
490 #ifndef HAVE_MULTIVOLUME
491 const int volume
= 0;
493 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
496 #ifdef HAVE_FAT16SUPPORT
497 if (fat_bpb
->is_fat16
)
499 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
501 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
502 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
503 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
504 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
507 if (letoh16(fat
[j
]) == 0x0000) {
509 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
510 fat_bpb
->fsinfo
.nextfree
= c
;
516 #endif /* #ifdef HAVE_FAT16SUPPORT */
518 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
520 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
521 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
522 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
523 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
526 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
528 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
529 fat_bpb
->fsinfo
.nextfree
= c
;
534 fat_bpb
->fsinfo
.freecount
= free
;
535 update_fsinfo(IF_MV(fat_bpb
));
538 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
540 #ifndef HAVE_MULTIVOLUME
541 struct bpb
* fat_bpb
= &fat_bpbs
[0];
543 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
545 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
546 fat_bpb
->bpb_bytspersec
);
549 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
552 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
554 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
555 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
558 if(fat_bpb
->bpb_numfats
!= 2)
560 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
561 fat_bpb
->bpb_numfats
);
563 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
565 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
566 "media type (0x%02x)\n",
569 if(fat_bpb
->last_word
!= 0xaa55)
571 DEBUGF( "bpb_is_sane() - Error: Last word is not "
572 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
576 if (fat_bpb
->fsinfo
.freecount
>
577 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
578 fat_bpb
->bpb_secperclus
)
580 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
581 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
588 static void flush_fat_sector(struct fat_cache_entry
*fce
,
589 unsigned char *sectorbuf
)
594 /* With multivolume, use only the FAT info from the cached sector! */
595 #ifdef HAVE_MULTIVOLUME
596 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
598 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
601 /* Write to the first FAT */
602 rc
= storage_write_sectors(fce
->fat_vol
->drive
,
607 panicf("flush_fat_sector() - Could not write sector %ld"
611 #ifdef HAVE_MULTIVOLUME
612 if(fce
->fat_vol
->bpb_numfats
> 1)
614 if(fat_bpbs
[0].bpb_numfats
> 1)
617 /* Write to the second FAT */
618 #ifdef HAVE_MULTIVOLUME
619 secnum
+= fce
->fat_vol
->fatsize
;
621 secnum
+= fat_bpbs
[0].fatsize
;
623 rc
= storage_write_sectors(fce
->fat_vol
->drive
,
624 secnum
, 1, sectorbuf
);
627 panicf("flush_fat_sector() - Could not write sector %ld"
635 /* Note: The returned pointer is only safely valid until the next
636 task switch! (Any subsequent ata read/write may yield.) */
637 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
638 long fatsector
, bool dirty
)
640 #ifndef HAVE_MULTIVOLUME
641 struct bpb
* fat_bpb
= &fat_bpbs
[0];
643 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
644 int cache_index
= secnum
& FAT_CACHE_MASK
;
645 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
646 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
649 mutex_lock(&cache_mutex
); /* make changes atomic */
651 /* Delete the cache entry if it isn't the sector we want */
652 if(fce
->inuse
&& (fce
->secnum
!= secnum
653 #ifdef HAVE_MULTIVOLUME
654 || fce
->fat_vol
!= fat_bpb
658 /* Write back if it is dirty */
661 flush_fat_sector(fce
, sectorbuf
);
666 /* Load the sector if it is not cached */
669 rc
= storage_read_sectors(fat_bpb
->drive
,
670 secnum
+ fat_bpb
->startsector
,1,
674 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
675 " (error %d)\n", secnum
, rc
);
676 mutex_unlock(&cache_mutex
);
680 fce
->secnum
= secnum
;
681 #ifdef HAVE_MULTIVOLUME
682 fce
->fat_vol
= fat_bpb
;
686 fce
->dirty
= true; /* dirt remains, sticky until flushed */
687 mutex_unlock(&cache_mutex
);
691 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
692 unsigned long startcluster
)
694 #ifndef HAVE_MULTIVOLUME
695 struct bpb
* fat_bpb
= &fat_bpbs
[0];
697 unsigned long sector
;
698 unsigned long offset
;
701 #ifdef HAVE_FAT16SUPPORT
702 if (fat_bpb
->is_fat16
)
704 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
705 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
707 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
709 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
710 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
713 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
714 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
715 if (letoh16(fat
[k
]) == 0x0000) {
716 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
717 /* Ignore the reserved clusters 0 & 1, and also
718 cluster numbers out of bounds */
719 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
721 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
722 fat_bpb
->fsinfo
.nextfree
= c
;
730 #endif /* #ifdef HAVE_FAT16SUPPORT */
732 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
733 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
735 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
737 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
738 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
741 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
742 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
743 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
744 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
745 /* Ignore the reserved clusters 0 & 1, and also
746 cluster numbers out of bounds */
747 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
749 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
750 fat_bpb
->fsinfo
.nextfree
= c
;
758 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
759 return 0; /* 0 is an illegal cluster number */
762 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
765 #ifndef HAVE_MULTIVOLUME
766 struct bpb
* fat_bpb
= &fat_bpbs
[0];
768 #ifdef HAVE_FAT16SUPPORT
769 if (fat_bpb
->is_fat16
)
771 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
772 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
777 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
780 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
783 panicf("Updating reserved FAT entry %ld.\n",entry
);
785 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
788 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
793 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
794 fat_bpb
->fsinfo
.freecount
--;
797 if (letoh16(sec
[offset
]))
798 fat_bpb
->fsinfo
.freecount
++;
801 LDEBUGF("update_fat_entry: %d free clusters\n",
802 fat_bpb
->fsinfo
.freecount
);
804 sec
[offset
] = htole16(val
);
807 #endif /* #ifdef HAVE_FAT16SUPPORT */
809 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
810 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
813 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
816 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
819 panicf("Updating reserved FAT entry %ld.\n",entry
);
821 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
824 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
829 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
830 fat_bpb
->fsinfo
.freecount
> 0)
831 fat_bpb
->fsinfo
.freecount
--;
834 if (letoh32(sec
[offset
]) & 0x0fffffff)
835 fat_bpb
->fsinfo
.freecount
++;
838 LDEBUGF("update_fat_entry: %ld free clusters\n",
839 fat_bpb
->fsinfo
.freecount
);
841 /* don't change top 4 bits */
842 sec
[offset
] &= htole32(0xf0000000);
843 sec
[offset
] |= htole32(val
& 0x0fffffff);
849 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
851 #ifdef HAVE_FAT16SUPPORT
852 #ifndef HAVE_MULTIVOLUME
853 struct bpb
* fat_bpb
= &fat_bpbs
[0];
855 if (fat_bpb
->is_fat16
)
857 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
858 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
861 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
864 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
868 return letoh16(sec
[offset
]);
871 #endif /* #ifdef HAVE_FAT16SUPPORT */
873 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
874 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
877 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
880 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
884 return letoh32(sec
[offset
]) & 0x0fffffff;
888 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
891 long eof_mark
= FAT_EOF_MARK
;
893 #ifdef HAVE_FAT16SUPPORT
894 #ifndef HAVE_MULTIVOLUME
895 struct bpb
* fat_bpb
= &fat_bpbs
[0];
897 if (fat_bpb
->is_fat16
)
899 eof_mark
&= 0xFFFF; /* only 16 bit */
900 if (cluster
< 0) /* FAT16 root dir */
901 return cluster
+ 1; /* don't use the FAT */
904 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
906 /* is this last cluster in chain? */
907 if ( next_cluster
>= eof_mark
)
913 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
915 #ifndef HAVE_MULTIVOLUME
916 struct bpb
* fat_bpb
= &fat_bpbs
[0];
918 unsigned char fsinfo
[SECTOR_SIZE
];
919 unsigned long* intptr
;
922 #ifdef HAVE_FAT16SUPPORT
923 if (fat_bpb
->is_fat16
)
924 return 0; /* FAT16 has no FsInfo */
925 #endif /* #ifdef HAVE_FAT16SUPPORT */
928 rc
= storage_read_sectors(fat_bpb
->drive
,
929 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
932 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
935 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
936 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
938 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
939 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
941 rc
= storage_write_sectors(fat_bpb
->drive
,
942 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
945 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
952 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
957 LDEBUGF("flush_fat()\n");
959 mutex_lock(&cache_mutex
);
960 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
962 struct fat_cache_entry
*fce
= &fat_cache
[i
];
964 #ifdef HAVE_MULTIVOLUME
965 && fce
->fat_vol
== fat_bpb
969 sec
= fat_cache_sectors
[i
];
970 flush_fat_sector(fce
, sec
);
973 mutex_unlock(&cache_mutex
);
975 rc
= update_fsinfo(IF_MV(fat_bpb
));
982 static void fat_time(unsigned short* date
,
983 unsigned short* time
,
984 unsigned short* tenth
)
987 struct tm
* tm
= get_time();
990 *date
= ((tm
->tm_year
- 80) << 9) |
991 ((tm
->tm_mon
+ 1) << 5) |
995 *time
= (tm
->tm_hour
<< 11) |
1000 *tenth
= (tm
->tm_sec
& 1) * 100;
1002 /* non-RTC version returns an increment from the supplied time, or a
1003 * fixed standard time/date if no time given as input */
1005 /* Macros to convert a 2-digit string to a decimal constant.
1006 (YEAR), MONTH and DAY are set by the date command, which outputs
1007 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1008 misinterpretation as an octal constant. */
1009 #define S100(x) 1 ## x
1010 #define C2DIG2DEC(x) (S100(x)-100)
1011 /* The actual build date, as FAT date constant */
1012 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1013 | (C2DIG2DEC(MONTH) << 5) \
1016 bool date_forced
= false;
1017 bool next_day
= false;
1018 unsigned time2
= 0; /* double time, for CRTTIME with 1s precision */
1020 if (date
&& *date
< BUILD_DATE_FAT
)
1022 *date
= BUILD_DATE_FAT
;
1029 if (time2
== 0 || date_forced
)
1031 time2
= (11 < 6) | 11; /* set to 00:11:11 */
1035 unsigned mins
= (time2
>> 6) & 0x3f;
1036 unsigned hours
= (time2
>> 12) & 0x1f;
1038 mins
= 11 * ((mins
/11) + 1); /* advance to next multiple of 11 */
1041 mins
= 11; /* 00 would be a bad marker */
1048 time2
= (hours
<< 12) | (mins
<< 6) | mins
; /* secs = mins */
1054 *tenth
= (time2
& 1) * 100;
1056 if (date
&& next_day
)
1058 static const unsigned char daysinmonth
[] =
1059 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1060 unsigned day
= *date
& 0x1f;
1061 unsigned month
= (*date
>> 5) & 0x0f;
1062 unsigned year
= (*date
>> 9) & 0x7f;
1064 /* simplification: ignore leap years */
1065 if (++day
> daysinmonth
[month
-1])
1074 *date
= (year
<< 9) | (month
<< 5) | day
;
1077 #endif /* CONFIG_RTC */
1080 static int write_long_name(struct fat_file
* file
,
1081 unsigned int firstentry
,
1082 unsigned int numentries
,
1083 const unsigned char* name
,
1084 const unsigned char* shortname
,
1087 unsigned char buf
[SECTOR_SIZE
];
1088 unsigned char* entry
;
1089 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1090 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1091 unsigned char chksum
= 0;
1092 unsigned int i
, j
=0;
1093 unsigned int nameidx
=0, namelen
= utf8length(name
);
1095 unsigned short name_utf16
[namelen
+ 1];
1097 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1098 file
->firstcluster
, firstentry
, numentries
, name
);
1100 rc
= fat_seek(file
, sector
);
1104 rc
= fat_readwrite(file
, 1, buf
, false);
1108 /* calculate shortname checksum */
1109 for (i
=11; i
>0; i
--)
1110 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1112 /* calc position of last name segment */
1113 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1115 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1116 nameidx
+= NAME_BYTES_PER_ENTRY
);
1118 /* we need to convert the name first */
1119 /* since it is written in reverse order */
1120 for (i
= 0; i
<= namelen
; i
++)
1121 name
= utf8decode(name
, &name_utf16
[i
]);
1123 for (i
=0; i
< numentries
; i
++) {
1125 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1126 /* update current sector */
1127 rc
= fat_seek(file
, sector
);
1131 rc
= fat_readwrite(file
, 1, buf
, true);
1135 /* read next sector */
1136 rc
= fat_readwrite(file
, 1, buf
, false);
1138 LDEBUGF("Failed writing new sector: %d\n",rc
);
1143 memset(buf
, 0, sizeof buf
);
1149 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1151 /* verify this entry is free */
1152 if (entry
[0] && entry
[0] != 0xe5 )
1153 panicf("Dir entry %d in sector %x is not free! "
1154 "%02x %02x %02x %02x",
1156 entry
[0], entry
[1], entry
[2], entry
[3]);
1158 memset(entry
, 0, DIR_ENTRY_SIZE
);
1159 if ( i
+1 < numentries
) {
1160 /* longname entry */
1161 unsigned int k
, l
= nameidx
;
1163 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1165 /* mark this as last long entry */
1166 entry
[FATLONG_ORDER
] |= 0x40;
1168 /* pad name with 0xffff */
1169 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1170 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1171 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1174 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1175 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1176 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1178 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1179 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1180 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1182 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1183 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1184 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1187 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1188 entry
[FATDIR_FSTCLUSLO
] = 0;
1189 entry
[FATLONG_TYPE
] = 0;
1190 entry
[FATLONG_CHKSUM
] = chksum
;
1191 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1194 /* shortname entry */
1195 unsigned short date
=0, time
=0, tenth
=0;
1196 LDEBUGF("Shortname entry: %s\n", shortname
);
1197 memcpy(entry
+ FATDIR_NAME
, shortname
, 11);
1198 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1199 entry
[FATDIR_NTRES
] = 0;
1201 fat_time(&date
, &time
, &tenth
);
1202 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1203 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1204 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1205 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1206 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1207 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1210 nameidx
-= NAME_BYTES_PER_ENTRY
;
1213 /* update last sector */
1214 rc
= fat_seek(file
, sector
);
1218 rc
= fat_readwrite(file
, 1, buf
, true);
1225 static int fat_checkname(const unsigned char* newname
)
1227 static const char invalid_chars
[] = "\"*/:<>?\\|";
1228 int len
= strlen(newname
);
1229 /* More sanity checks are probably needed */
1230 if (len
> 255 || newname
[len
- 1] == '.')
1236 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1240 /* check trailing space(s) */
1241 if(*(--newname
) == ' ')
1247 static int add_dir_entry(struct fat_dir
* dir
,
1248 struct fat_file
* file
,
1253 #ifdef HAVE_MULTIVOLUME
1254 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1256 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1258 unsigned char buf
[SECTOR_SIZE
];
1259 unsigned char shortname
[12];
1261 unsigned int sector
;
1263 int entries_needed
, entries_found
= 0;
1266 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1267 name
, file
->firstcluster
);
1269 /* Don't check dotdirs name for validity */
1270 if (dotdir
== false) {
1271 rc
= fat_checkname(name
);
1273 /* filename is invalid */
1278 #ifdef HAVE_MULTIVOLUME
1279 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1282 /* The "." and ".." directory entries must not be long names */
1285 strlcpy(shortname
, name
, 12);
1286 for(i
= strlen(shortname
); i
< 12; i
++)
1291 create_dos_name(name
, shortname
);
1293 /* one dir entry needed for every 13 bytes of filename,
1294 plus one entry for the short name */
1295 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1296 / NAME_BYTES_PER_ENTRY
+ 1;
1302 rc
= fat_seek(&dir
->file
, 0);
1306 /* step 1: search for free entries and check for duplicate shortname */
1307 for (sector
= 0; !done
; sector
++)
1311 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1313 DEBUGF( "add_dir_entry() - Couldn't read dir"
1314 " (error code %d)\n", rc
);
1318 if (rc
== 0) { /* current end of dir reached */
1319 LDEBUGF("End of dir on cluster boundary\n");
1323 /* look for free slots */
1324 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1326 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1328 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1329 LDEBUGF("Found end of dir %d\n",
1330 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1331 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1337 LDEBUGF("Found free entry %d (%d/%d)\n",
1338 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1339 entries_found
, entries_needed
);
1345 /* check that our intended shortname doesn't already exist */
1346 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1347 /* shortname exists already, make a new one */
1348 randomize_dos_name(shortname
);
1349 LDEBUGF("Duplicate shortname, changing to %s\n",
1352 /* name has changed, we need to restart search */
1357 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1358 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1363 /* step 2: extend the dir if necessary */
1366 LDEBUGF("Adding new sector(s) to dir\n");
1367 rc
= fat_seek(&dir
->file
, sector
);
1370 memset(buf
, 0, sizeof buf
);
1372 /* we must clear whole clusters */
1373 for (; (entries_found
< entries_needed
) ||
1374 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1376 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1377 return -5; /* dir too large -- FAT specification */
1379 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1380 if (rc
< 1) /* No more room or something went wrong */
1383 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1386 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1389 /* step 3: add entry */
1390 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1391 LDEBUGF("Adding longname to entry %d in sector %d\n",
1392 firstentry
, sector
);
1394 rc
= write_long_name(&dir
->file
, firstentry
,
1395 entries_needed
, name
, shortname
, is_directory
);
1399 /* remember where the shortname dir entry is located */
1400 file
->direntry
= firstentry
+ entries_needed
- 1;
1401 file
->direntries
= entries_needed
;
1402 file
->dircluster
= dir
->file
.firstcluster
;
1403 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1404 file
->direntry
, file
->direntries
);
1409 static unsigned char char2dos(unsigned char c
, int* randomize
)
1411 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1414 c
= 0; /* Illegal char, remove */
1415 else if (strchr(invalid_chars
, c
) != NULL
)
1417 /* Illegal char, replace */
1419 *randomize
= 1; /* as per FAT spec */
1427 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1433 /* Find extension part */
1434 ext
= strrchr(name
, '.');
1435 if (ext
== name
) /* handle .dotnames */
1438 /* needs to randomize? */
1439 if((ext
&& (strlen(ext
) > 4)) ||
1440 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1444 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1446 unsigned char c
= char2dos(*name
, &randomize
);
1451 /* Pad both name and extension */
1455 if (newname
[0] == 0xe5) /* Special kanji character */
1459 { /* Extension part */
1461 for (i
= 8; *ext
&& (i
< 11); ext
++)
1463 unsigned char c
= char2dos(*ext
, &randomize
);
1470 randomize_dos_name(newname
);
1473 static void randomize_dos_name(unsigned char *name
)
1475 unsigned char* tilde
= NULL
; /* ~ location */
1476 unsigned char* lastpt
= NULL
; /* last point of filename */
1477 unsigned char* nameptr
= name
; /* working copy of name pointer */
1478 unsigned char num
[9]; /* holds number as string */
1486 /* hunt for ~ and where to put it */
1487 if((!tilde
) && (*nameptr
== '~'))
1489 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1495 /* extract current count and increment */
1496 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1497 num
[7-(unsigned int)(tilde
-name
)] = 0;
1498 cnt
= atoi(num
) + 1;
1500 cnt
%= 10000000; /* protection */
1501 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1502 numlen
= strlen(num
); /* required space */
1503 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1504 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1506 memcpy(&name
[offset
], num
, numlen
);
1508 /* in special case of counter overflow: pad with spaces */
1509 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1513 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1515 unsigned char buf
[SECTOR_SIZE
];
1516 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1517 unsigned char* entry
=
1518 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1519 unsigned long* sizeptr
;
1520 unsigned short* clusptr
;
1521 struct fat_file dir
;
1524 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1525 file
->firstcluster
, file
->direntry
, size
);
1527 /* create a temporary file handle for the dir holding this file */
1528 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1532 rc
= fat_seek( &dir
, sector
);
1536 rc
= fat_readwrite(&dir
, 1, buf
, false);
1540 if (!entry
[0] || entry
[0] == 0xe5)
1541 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1543 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1545 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1546 *clusptr
= htole16(file
->firstcluster
>> 16);
1548 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1549 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1551 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1552 *sizeptr
= htole32(size
);
1556 unsigned short time
= 0;
1557 unsigned short date
= 0;
1559 /* get old time to increment from */
1560 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1561 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1563 fat_time(&date
, &time
, NULL
);
1564 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1565 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1566 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1569 rc
= fat_seek( &dir
, sector
);
1573 rc
= fat_readwrite(&dir
, 1, buf
, true);
1580 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1586 memset(de
, 0, sizeof(struct fat_direntry
));
1587 de
->attr
= buf
[FATDIR_ATTR
];
1588 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1589 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1590 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1591 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1592 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1593 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1594 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1595 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1596 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1597 (the result of the shift is always considered signed) */
1600 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1601 c
= buf
[FATDIR_NAME
];
1602 if (c
== 0x05) /* special kanji char */
1606 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1609 c
= buf
[FATDIR_NAME
+i
];
1611 if (buf
[FATDIR_NAME
+8] != ' ') {
1612 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1613 de
->name
[j
++] = '.';
1614 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1615 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1620 int fat_open(IF_MV2(int volume
,)
1622 struct fat_file
*file
,
1623 const struct fat_dir
* dir
)
1625 file
->firstcluster
= startcluster
;
1626 file
->lastcluster
= startcluster
;
1627 file
->lastsector
= 0;
1628 file
->clusternum
= 0;
1629 file
->sectornum
= 0;
1631 #ifdef HAVE_MULTIVOLUME
1632 file
->volume
= volume
;
1633 /* fixme: remove error check when done */
1634 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1636 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1641 /* remember where the file's dir entry is located */
1643 file
->direntry
= dir
->entry
- 1;
1644 file
->direntries
= dir
->entrycount
;
1645 file
->dircluster
= dir
->file
.firstcluster
;
1647 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1651 int fat_create_file(const char* name
,
1652 struct fat_file
* file
,
1653 struct fat_dir
* dir
)
1657 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1658 rc
= add_dir_entry(dir
, file
, name
, false, false);
1660 file
->firstcluster
= 0;
1661 file
->lastcluster
= 0;
1662 file
->lastsector
= 0;
1663 file
->clusternum
= 0;
1664 file
->sectornum
= 0;
1671 int fat_create_dir(const char* name
,
1672 struct fat_dir
* newdir
,
1673 struct fat_dir
* dir
)
1675 #ifdef HAVE_MULTIVOLUME
1676 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1678 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1680 unsigned char buf
[SECTOR_SIZE
];
1684 struct fat_file dummyfile
;
1686 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1688 memset(newdir
, 0, sizeof(struct fat_dir
));
1689 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1691 /* First, add the entry in the parent directory */
1692 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1696 /* Allocate a new cluster for the directory */
1697 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1698 fat_bpb
->fsinfo
.nextfree
);
1699 if(newdir
->file
.firstcluster
== 0)
1702 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1704 /* Clear the entire cluster */
1705 memset(buf
, 0, sizeof buf
);
1706 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1707 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1708 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1713 /* Then add the "." entry */
1714 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1717 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1718 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1720 /* and the ".." entry */
1721 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1725 /* The root cluster is cluster 0 in the ".." entry */
1726 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1727 dummyfile
.firstcluster
= 0;
1729 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1730 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1732 /* Set the firstcluster field in the direntry */
1733 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1735 rc
= flush_fat(IF_MV(fat_bpb
));
1742 int fat_truncate(const struct fat_file
*file
)
1744 /* truncate trailing clusters */
1746 long last
= file
->lastcluster
;
1747 #ifdef HAVE_MULTIVOLUME
1748 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1751 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1753 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1754 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1755 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1757 if (file
->lastcluster
)
1758 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1763 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1766 #ifdef HAVE_MULTIVOLUME
1767 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1769 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1773 if ( file
->firstcluster
) {
1774 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1775 file
->firstcluster
= 0;
1779 if (file
->dircluster
) {
1780 rc
= update_short_entry(file
, size
, attr
);
1785 flush_fat(IF_MV(fat_bpb
));
1788 if ( file
->firstcluster
) {
1790 #ifdef HAVE_MULTIVOLUME
1791 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1793 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1798 for ( next
= file
->firstcluster
; next
;
1799 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1800 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1803 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1804 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1806 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1807 panicf("Cluster chain is too long\n");
1809 panicf("Cluster chain is too short\n");
1816 static int free_direntries(struct fat_file
* file
)
1818 unsigned char buf
[SECTOR_SIZE
];
1819 struct fat_file dir
;
1820 int numentries
= file
->direntries
;
1821 unsigned int entry
= file
->direntry
- numentries
+ 1;
1822 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1826 /* create a temporary file handle for the dir holding this file */
1827 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1831 rc
= fat_seek( &dir
, sector
);
1835 rc
= fat_readwrite(&dir
, 1, buf
, false);
1839 for (i
=0; i
< numentries
; i
++) {
1840 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1841 entry
, i
+1, numentries
);
1842 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1845 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1846 /* flush this sector */
1847 rc
= fat_seek(&dir
, sector
);
1851 rc
= fat_readwrite(&dir
, 1, buf
, true);
1855 if ( i
+1 < numentries
) {
1856 /* read next sector */
1857 rc
= fat_readwrite(&dir
, 1, buf
, false);
1865 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1866 /* flush this sector */
1867 rc
= fat_seek(&dir
, sector
);
1871 rc
= fat_readwrite(&dir
, 1, buf
, true);
1879 int fat_remove(struct fat_file
* file
)
1881 long next
, last
= file
->firstcluster
;
1883 #ifdef HAVE_MULTIVOLUME
1884 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1887 LDEBUGF("fat_remove(%lx)\n",last
);
1890 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1891 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1895 if ( file
->dircluster
) {
1896 rc
= free_direntries(file
);
1901 file
->firstcluster
= 0;
1902 file
->dircluster
= 0;
1904 rc
= flush_fat(IF_MV(fat_bpb
));
1911 int fat_rename(struct fat_file
* file
,
1912 struct fat_dir
* dir
,
1913 const unsigned char* newname
,
1918 struct fat_dir olddir
;
1919 struct fat_file newfile
= *file
;
1920 unsigned char buf
[SECTOR_SIZE
];
1921 unsigned char* entry
= NULL
;
1922 unsigned short* clusptr
= NULL
;
1923 unsigned int parentcluster
;
1924 #ifdef HAVE_MULTIVOLUME
1925 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1927 if (file
->volume
!= dir
->file
.volume
) {
1928 DEBUGF("No rename across volumes!\n");
1932 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1935 if ( !file
->dircluster
) {
1936 DEBUGF("File has no dir cluster!\n");
1940 /* create a temporary file handle */
1941 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1945 /* create new name */
1946 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1950 /* write size and cluster link */
1951 rc
= update_short_entry(&newfile
, size
, attr
);
1955 /* remove old name */
1956 rc
= free_direntries(file
);
1960 rc
= flush_fat(IF_MV(fat_bpb
));
1964 /* if renaming a directory, update the .. entry to make sure
1965 it points to its parent directory (we don't check if it was a move) */
1966 if(FAT_ATTR_DIRECTORY
== attr
) {
1967 /* open the dir that was renamed, we re-use the olddir struct */
1968 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, newfile
.firstcluster
,
1973 /* get the first sector of the dir */
1974 rc
= fat_seek(&olddir
.file
, 0);
1978 rc
= fat_readwrite(&olddir
.file
, 1, buf
, false);
1982 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1983 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1986 parentcluster
= dir
->file
.firstcluster
;
1988 entry
= buf
+ DIR_ENTRY_SIZE
;
1989 if(strncmp(".. ", entry
, 11))
1991 /* .. entry must be second entry according to FAT spec (p.29) */
1992 DEBUGF("Second dir entry is not double-dot!\n");
1995 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1996 *clusptr
= htole16(parentcluster
>> 16);
1998 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1999 *clusptr
= htole16(parentcluster
& 0xffff);
2001 /* write back this sector */
2002 rc
= fat_seek(&olddir
.file
, 0);
2006 rc
= fat_readwrite(&olddir
.file
, 1, buf
, true);
2014 static long next_write_cluster(struct fat_file
* file
,
2018 #ifdef HAVE_MULTIVOLUME
2019 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2021 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2026 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
2029 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
2033 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
2034 else if (oldcluster
== 0)
2035 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
2036 fat_bpb
->fsinfo
.nextfree
);
2037 #ifdef HAVE_FAT16SUPPORT
2038 else /* negative, pseudo-cluster of the root dir */
2039 return 0; /* impossible to append something to the root */
2044 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2046 file
->firstcluster
= cluster
;
2047 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2051 if (fat_bpb
->fsinfo
.freecount
>0)
2052 panicf("There is free space, but find_free_cluster() "
2053 "didn't find it!\n");
2055 DEBUGF("next_write_cluster(): Disk full!\n");
2059 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2063 *newsector
= sector
;
2067 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2068 unsigned long start
, long count
, char* buf
, bool write
)
2070 #ifndef HAVE_MULTIVOLUME
2071 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2075 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2076 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2078 unsigned long firstallowed
;
2079 #ifdef HAVE_FAT16SUPPORT
2080 if (fat_bpb
->is_fat16
)
2081 firstallowed
= fat_bpb
->rootdirsector
;
2084 firstallowed
= fat_bpb
->firstdatasector
;
2086 if (start
< firstallowed
)
2087 panicf("Write %ld before data\n", firstallowed
- start
);
2088 if (start
+ count
> fat_bpb
->totalsectors
)
2089 panicf("Write %ld after data\n",
2090 start
+ count
- fat_bpb
->totalsectors
);
2091 rc
= storage_write_sectors(fat_bpb
->drive
,
2092 start
+ fat_bpb
->startsector
, count
, buf
);
2095 rc
= storage_read_sectors(fat_bpb
->drive
,
2096 start
+ fat_bpb
->startsector
, count
, buf
);
2098 DEBUGF( "transfer() - Couldn't %s sector %lx"
2099 " (error code %d)\n",
2100 write
? "write":"read", start
, rc
);
2107 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2108 void* buf
, bool write
)
2110 #ifdef HAVE_MULTIVOLUME
2111 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2113 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2115 long cluster
= file
->lastcluster
;
2116 long sector
= file
->lastsector
;
2117 long clusternum
= file
->clusternum
;
2118 long numsec
= file
->sectornum
;
2119 bool eof
= file
->eof
;
2120 long first
=0, last
=0;
2124 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2125 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2126 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2127 sector
,numsec
, eof
?1:0);
2132 /* find sequential sectors and write them all at once */
2133 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2135 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2136 long oldcluster
= cluster
;
2137 long oldsector
= sector
;
2138 long oldnumsec
= numsec
;
2140 cluster
= next_write_cluster(file
, cluster
, §or
);
2142 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2143 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2152 /* remember last cluster, in case
2153 we want to append to the file */
2155 cluster
= oldcluster
;
2158 i
= -1; /* Error code */
2169 /* look up first sector of file */
2170 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2172 #ifdef HAVE_FAT16SUPPORT
2173 if (file
->firstcluster
< 0)
2174 { /* FAT16 root dir */
2175 sector
+= fat_bpb
->rootdiroffset
;
2176 numsec
+= fat_bpb
->rootdiroffset
;
2185 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2186 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2187 long count
= last
- first
+ 1;
2188 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2192 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2196 if ((i
== sectorcount
-1) && /* last sector requested */
2199 long count
= sector
- first
+ 1;
2200 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2208 file
->lastcluster
= cluster
;
2209 file
->lastsector
= sector
;
2210 file
->clusternum
= clusternum
;
2211 file
->sectornum
= numsec
;
2214 /* if eof, don't report last block as read/written */
2218 DEBUGF("Sectors written: %ld\n", i
);
2222 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2224 #ifdef HAVE_MULTIVOLUME
2225 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2227 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2229 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2230 long cluster
= file
->firstcluster
;
2233 #ifdef HAVE_FAT16SUPPORT
2234 if (cluster
< 0) /* FAT16 root dir */
2235 seeksector
+= fat_bpb
->rootdiroffset
;
2240 /* we need to find the sector BEFORE the requested, since
2241 the file struct stores the last accessed sector */
2243 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2244 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2246 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2248 cluster
= file
->lastcluster
;
2249 numclusters
-= file
->clusternum
;
2252 for (i
=0; i
<numclusters
; i
++) {
2253 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2255 DEBUGF("Seeking beyond the end of the file! "
2256 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2261 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2267 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2268 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2270 file
->lastcluster
= cluster
;
2271 file
->lastsector
= sector
;
2272 file
->clusternum
= clusternum
;
2273 file
->sectornum
= sectornum
+ 1;
2277 int fat_opendir(IF_MV2(int volume
,)
2278 struct fat_dir
*dir
, unsigned long startcluster
,
2279 const struct fat_dir
*parent_dir
)
2281 #ifdef HAVE_MULTIVOLUME
2282 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2283 /* fixme: remove error check when done */
2284 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2286 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2290 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2297 if (startcluster
== 0)
2298 startcluster
= fat_bpb
->bpb_rootclus
;
2300 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2303 DEBUGF( "fat_opendir() - Couldn't open dir"
2304 " (error code %d)\n", rc
);
2311 /* Copies a segment of long file name (UTF-16 LE encoded) to the
2312 * destination buffer (UTF-8 encoded). Copying is stopped when
2313 * either 0x0000 or 0xffff (FAT pad char) is encountered.
2314 * Trailing \0 is also appended at the end of the UTF8-encoded
2317 * utf16src utf16 (little endian) segment to copy
2318 * utf16count max number of the utf16-characters to copy
2319 * utf8dst where to write UTF8-encoded string to
2321 * returns the number of UTF-16 characters actually copied
2323 static int fat_copy_long_name_segment(unsigned char *utf16src
,
2324 int utf16count
, unsigned char *utf8dst
) {
2326 while ((utf16count
--) > 0) {
2327 unsigned short ucs
= utf16src
[0] | (utf16src
[1] << 8);
2328 if ((ucs
== 0) || (ucs
== FAT_LONGNAME_PAD_UCS
)) {
2331 utf8dst
= utf8encode(ucs
, utf8dst
);
2339 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2344 unsigned char firstbyte
;
2345 /* Long file names are stored in special entries. Each entry holds
2346 up to 13 characters. Names can be max 255 chars (not bytes!) long
2347 hence max 20 entries are required. */
2351 unsigned char* cached_buf
= dir
->sectorcache
[0];
2353 dir
->entrycount
= 0;
2357 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2359 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2366 DEBUGF( "fat_getnext() - Couldn't read dir"
2367 " (error code %d)\n", rc
);
2370 dir
->sector
= dir
->file
.lastsector
;
2373 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2374 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2376 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2378 firstbyte
= cached_buf
[entrypos
];
2381 if (firstbyte
== 0xe5) {
2384 dir
->entrycount
= 0;
2388 if (firstbyte
== 0) {
2391 dir
->entrycount
= 0;
2397 /* longname entry? */
2398 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2399 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2400 longarray
[longs
++] = entrypos
+ sectoridx
;
2403 if ( parse_direntry(entry
,
2404 &cached_buf
[entrypos
]) ) {
2406 /* don't return volume id entry */
2408 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2409 == FAT_ATTR_VOLUME_ID
)
2412 /* replace shortname with longname? */
2415 /* This should be enough to hold any name segment
2417 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2418 /* Add 1 for trailing \0 */
2419 unsigned char longname_utf8segm
[6*4 + 1];
2420 int longname_utf8len
= 0;
2421 /* Temporarily store it */
2422 strcpy(shortname
, entry
->name
);
2425 /* iterate backwards through the dir entries */
2426 for (j
=longs
-1; j
>=0; j
--) {
2427 unsigned char* ptr
= cached_buf
;
2428 int index
= longarray
[j
];
2429 /* current or cached sector? */
2430 if ( sectoridx
>= SECTOR_SIZE
) {
2431 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2432 if ( ( index
>= SECTOR_SIZE
) &&
2433 ( index
< SECTOR_SIZE
*2 ))
2434 ptr
= dir
->sectorcache
[1];
2436 ptr
= dir
->sectorcache
[2];
2439 if ( index
< SECTOR_SIZE
)
2440 ptr
= dir
->sectorcache
[1];
2443 index
&= SECTOR_SIZE
-1;
2446 /* Try to append each segment of the long name.
2447 Check if we'd exceed the buffer.
2448 Also check for FAT padding characters 0xFFFF. */
2449 if (fat_copy_long_name_segment(ptr
+ index
+ 1, 5,
2450 longname_utf8segm
) == 0) break;
2451 /* logf("SG: %s, EN: %s", longname_utf8segm,
2453 longname_utf8len
+= strlen(longname_utf8segm
);
2454 if (longname_utf8len
< FAT_FILENAME_BYTES
)
2455 strcat(entry
->name
, longname_utf8segm
);
2459 if (fat_copy_long_name_segment(ptr
+ index
+ 14, 6,
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
+ 28, 2,
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
);
2480 /* Does the utf8-encoded name fit into the entry? */
2481 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2482 /* Take the short DOS name. Need to utf8-encode it
2483 since it may contain chars from the upper half of
2484 the OEM code page which wouldn't be a valid utf8.
2485 Beware: this file will be shown with strange
2486 glyphs in file browser since unicode 0x80 to 0x9F
2487 are control characters. */
2488 logf("SN-DOS: %s", shortname
);
2489 unsigned char *utf8
;
2490 utf8
= iso_decode(shortname
, entry
->name
, -1,
2493 logf("SN: %s", entry
->name
);
2495 /* logf("LN: %s", entry->name);
2496 logf("LNLen: %d (%c)", longname_utf8len,
2508 /* save this sector, for longname use */
2510 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2512 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2513 sectoridx
+= SECTOR_SIZE
;
2519 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2521 #ifndef HAVE_MULTIVOLUME
2522 const int volume
= 0;
2524 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2525 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2528 #ifdef HAVE_MULTIVOLUME
2529 bool fat_ismounted(int volume
)
2531 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);