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"
34 /*#define LOGF_ENABLE*/
37 #define BYTES2INT16(array,pos) \
38 (array[pos] | (array[pos+1] << 8 ))
39 #define BYTES2INT32(array,pos) \
40 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
41 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
43 #define FATTYPE_FAT12 0
44 #define FATTYPE_FAT16 1
45 #define FATTYPE_FAT32 2
47 /* BPB offsets; generic */
50 #define BPB_BYTSPERSEC 11
51 #define BPB_SECPERCLUS 13
52 #define BPB_RSVDSECCNT 14
53 #define BPB_NUMFATS 16
54 #define BPB_ROOTENTCNT 17
55 #define BPB_TOTSEC16 19
57 #define BPB_FATSZ16 22
58 #define BPB_SECPERTRK 24
59 #define BPB_NUMHEADS 26
60 #define BPB_HIDDSEC 28
61 #define BPB_TOTSEC32 32
65 #define BS_RESERVED1 37
69 #define BS_FILSYSTYPE 54
72 #define BPB_FATSZ32 36
73 #define BPB_EXTFLAGS 40
75 #define BPB_ROOTCLUS 44
77 #define BPB_BKBOOTSEC 50
78 #define BS_32_DRVNUM 64
79 #define BS_32_BOOTSIG 66
80 #define BS_32_VOLID 67
81 #define BS_32_VOLLAB 71
82 #define BS_32_FILSYSTYPE 82
84 #define BPB_LAST_WORD 510
88 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
90 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
91 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
92 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
95 #define FAT_NTRES_LC_NAME 0x08
96 #define FAT_NTRES_LC_EXT 0x10
99 #define FATDIR_ATTR 11
100 #define FATDIR_NTRES 12
101 #define FATDIR_CRTTIMETENTH 13
102 #define FATDIR_CRTTIME 14
103 #define FATDIR_CRTDATE 16
104 #define FATDIR_LSTACCDATE 18
105 #define FATDIR_FSTCLUSHI 20
106 #define FATDIR_WRTTIME 22
107 #define FATDIR_WRTDATE 24
108 #define FATDIR_FSTCLUSLO 26
109 #define FATDIR_FILESIZE 28
111 #define FATLONG_ORDER 0
112 #define FATLONG_TYPE 12
113 #define FATLONG_CHKSUM 13
114 #define FATLONG_LAST_LONG_ENTRY 0x40
115 #define FATLONG_NAME_BYTES_PER_ENTRY 26
116 /* at most 20 LFN entries, keep coherent with fat_dir->longname size ! */
117 #define FATLONG_MAX_ORDER 20
119 #define FATLONG_NAME_CHUNKS 3
120 static unsigned char FATLONG_NAME_POS
[FATLONG_NAME_CHUNKS
] = {1, 14, 28};
121 static unsigned char FATLONG_NAME_SIZE
[FATLONG_NAME_CHUNKS
] = {10, 12, 4};
123 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
124 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
125 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
126 #define DIR_ENTRY_SIZE 32
127 #define NAME_BYTES_PER_ENTRY 13
128 #define FAT_BAD_MARK 0x0ffffff7
129 #define FAT_EOF_MARK 0x0ffffff8
130 #define FAT_LONGNAME_PAD_BYTE 0xff
131 #define FAT_LONGNAME_PAD_UCS 0xffff
134 unsigned long freecount
; /* last known free cluster count */
135 unsigned long nextfree
; /* first cluster to start looking for free
136 clusters, or 0xffffffff for no hint */
139 #define FSINFO_FREECOUNT 488
140 #define FSINFO_NEXTFREE 492
142 /* Note: This struct doesn't hold the raw values after mounting if
143 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
144 * physical sectors. */
147 int bpb_bytspersec
; /* Bytes per sector, typically 512 */
148 unsigned int bpb_secperclus
; /* Sectors per cluster */
149 int bpb_rsvdseccnt
; /* Number of reserved sectors */
150 int bpb_numfats
; /* Number of FAT structures, typically 2 */
151 int bpb_totsec16
; /* Number of sectors on the volume (old 16-bit) */
152 int bpb_media
; /* Media type (typically 0xf0 or 0xf8) */
153 int bpb_fatsz16
; /* Number of used sectors per FAT structure */
154 unsigned long bpb_totsec32
; /* Number of sectors on the volume
156 unsigned int last_word
; /* 0xAA55 */
158 /**** FAT32 specific *****/
163 /* variables for internal use */
164 unsigned long fatsize
;
165 unsigned long totalsectors
;
166 unsigned long rootdirsector
;
167 unsigned long firstdatasector
;
168 unsigned long startsector
;
169 unsigned long dataclusters
;
170 struct fsinfo fsinfo
;
171 #ifdef HAVE_FAT16SUPPORT
172 int bpb_rootentcnt
; /* Number of dir entries in the root */
173 /* internals for FAT16 support */
174 bool is_fat16
; /* true if we mounted a FAT16 partition, false if FAT32 */
175 unsigned int rootdiroffset
; /* sector offset of root dir relative to start
176 * of first pseudo cluster */
177 #endif /* #ifdef HAVE_FAT16SUPPORT */
178 #ifdef HAVE_MULTIVOLUME
179 #ifdef HAVE_MULTIDRIVE
180 int drive
; /* on which physical device is this located */
182 bool mounted
; /* flag if this volume is mounted */
186 static struct bpb fat_bpbs
[NUM_VOLUMES
]; /* mounted partition info */
187 static bool initialized
= false;
189 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
));
190 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
));
191 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
));
192 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
193 long secnum
, bool dirty
);
194 static void create_dos_name(const unsigned char *name
, unsigned char *newname
);
195 static void randomize_dos_name(unsigned char *name
);
196 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
197 unsigned long start
);
198 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned long start
,
199 long count
, char* buf
, bool write
);
201 #define FAT_CACHE_SIZE 0x20
202 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
204 struct fat_cache_entry
209 #ifdef HAVE_MULTIVOLUME
210 struct bpb
* fat_vol
; /* shared cache for all volumes */
214 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
215 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
216 static struct mutex cache_mutex SHAREDBSS_ATTR
;
218 #if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
221 mutex_lock(&cache_mutex
);
224 void fat_unlock(void)
226 mutex_unlock(&cache_mutex
);
230 static long cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
232 #ifndef HAVE_MULTIVOLUME
233 struct bpb
* fat_bpb
= &fat_bpbs
[0];
235 #ifdef HAVE_FAT16SUPPORT
236 /* negative clusters (FAT16 root dir) don't get the 2 offset */
237 int zerocluster
= cluster
< 0 ? 0 : 2;
239 const long zerocluster
= 2;
242 if (cluster
> (long)(fat_bpb
->dataclusters
+ 1))
244 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster
);
248 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
249 + fat_bpb
->firstdatasector
;
252 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
254 #ifndef HAVE_MULTIVOLUME
255 const int volume
= 0;
257 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
259 *size
= fat_bpb
->dataclusters
* (fat_bpb
->bpb_secperclus
* SECTOR_SIZE
/ 1024);
261 *free
= fat_bpb
->fsinfo
.freecount
* (fat_bpb
->bpb_secperclus
* SECTOR_SIZE
/ 1024);
271 mutex_init(&cache_mutex
);
274 #ifdef HAVE_PRIORITY_SCHEDULING
275 /* Disable this because it is dangerous due to the assumption that
276 * mutex_unlock won't yield */
277 mutex_set_preempt(&cache_mutex
, false);
280 /* mark the FAT cache as unused */
281 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
283 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
284 fat_cache
[i
].inuse
= false;
285 fat_cache
[i
].dirty
= false;
286 #ifdef HAVE_MULTIVOLUME
287 fat_cache
[i
].fat_vol
= NULL
;
290 #ifdef HAVE_MULTIVOLUME
291 /* mark the possible volumes as not mounted */
292 for (i
=0; i
<NUM_VOLUMES
;i
++)
294 fat_bpbs
[i
].mounted
= false;
299 /* fat_mount_internal is split out of fat_mount() to avoid having both the sector
300 * buffer used here and the sector buffer used by update_fsinfo() on stack */
301 static int fat_mount_internal(IF_MV2(int volume
,) IF_MD2(int drive
,) long startsector
)
303 #ifndef HAVE_MULTIVOLUME
304 const int volume
= 0;
306 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
307 unsigned char buf
[SECTOR_SIZE
];
311 #ifdef HAVE_FAT16SUPPORT
315 /* Read the sector */
316 rc
= storage_read_sectors(IF_MD2(drive
,) startsector
,1,buf
);
319 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
323 memset(fat_bpb
, 0, sizeof(struct bpb
));
324 fat_bpb
->startsector
= startsector
;
325 #ifdef HAVE_MULTIDRIVE
326 fat_bpb
->drive
= drive
;
329 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
330 secmult
= fat_bpb
->bpb_bytspersec
/ SECTOR_SIZE
;
331 /* Sanity check is performed later */
333 fat_bpb
->bpb_secperclus
= secmult
* buf
[BPB_SECPERCLUS
];
334 fat_bpb
->bpb_rsvdseccnt
= secmult
* BYTES2INT16(buf
,BPB_RSVDSECCNT
);
335 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
336 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
337 fat_bpb
->bpb_fatsz16
= secmult
* BYTES2INT16(buf
,BPB_FATSZ16
);
338 fat_bpb
->bpb_fatsz32
= secmult
* BYTES2INT32(buf
,BPB_FATSZ32
);
339 fat_bpb
->bpb_totsec16
= secmult
* BYTES2INT16(buf
,BPB_TOTSEC16
);
340 fat_bpb
->bpb_totsec32
= secmult
* BYTES2INT32(buf
,BPB_TOTSEC32
);
341 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
343 /* calculate a few commonly used values */
344 if (fat_bpb
->bpb_fatsz16
!= 0)
345 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
347 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
349 if (fat_bpb
->bpb_totsec16
!= 0)
350 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
352 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
354 #ifdef HAVE_FAT16SUPPORT
355 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
356 if (!fat_bpb
->bpb_bytspersec
)
358 rootdirsectors
= secmult
* ((fat_bpb
->bpb_rootentcnt
* DIR_ENTRY_SIZE
359 + fat_bpb
->bpb_bytspersec
- 1) / fat_bpb
->bpb_bytspersec
);
360 #endif /* #ifdef HAVE_FAT16SUPPORT */
362 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
363 #ifdef HAVE_FAT16SUPPORT
366 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
368 /* Determine FAT type */
369 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
370 if (fat_bpb
->bpb_secperclus
)
371 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
377 we are sometimes testing with "illegally small" fat32 images,
378 so we don't use the proper fat32 test case for test code
380 if ( fat_bpb
->bpb_fatsz16
)
382 if ( fat_bpb
->dataclusters
< 65525 )
385 #ifdef HAVE_FAT16SUPPORT
386 fat_bpb
->is_fat16
= true;
387 if (fat_bpb
->dataclusters
< 4085)
389 DEBUGF("This is FAT12. Go away!\n");
392 #else /* #ifdef HAVE_FAT16SUPPORT */
393 DEBUGF("This is not FAT32. Go away!\n");
395 #endif /* #ifndef HAVE_FAT16SUPPORT */
398 #ifdef HAVE_FAT16SUPPORT
399 if (fat_bpb
->is_fat16
)
400 { /* FAT16 specific part of BPB */
402 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
403 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
404 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
405 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
406 /* I assign negative pseudo cluster numbers for the root directory,
407 their range is counted upward until -1. */
408 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data*/
409 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
413 #endif /* #ifdef HAVE_FAT16SUPPORT */
414 { /* FAT32 specific part of BPB */
415 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
416 fat_bpb
->bpb_fsinfo
= secmult
* BYTES2INT16(buf
,BPB_FSINFO
);
417 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,)
418 fat_bpb
->bpb_rootclus
);
421 rc
= bpb_is_sane(IF_MV(fat_bpb
));
424 DEBUGF( "fat_mount() - BPB is not sane\n");
428 #ifdef HAVE_FAT16SUPPORT
429 if (fat_bpb
->is_fat16
)
431 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
432 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
435 #endif /* #ifdef HAVE_FAT16SUPPORT */
437 /* Read the fsinfo sector */
438 rc
= storage_read_sectors(IF_MD2(drive
,)
439 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
442 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
445 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
446 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
451 int fat_mount(IF_MV2(int volume
,) IF_MD2(int drive
,) long startsector
)
453 #ifndef HAVE_MULTIVOLUME
454 const int volume
= 0;
456 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
459 rc
= fat_mount_internal(IF_MV2(volume
,) IF_MD2(drive
,) startsector
);
463 /* calculate freecount if unset */
464 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
466 fat_recalc_free(IF_MV(volume
));
469 LDEBUGF("Freecount: %ld\n",fat_bpb
->fsinfo
.freecount
);
470 LDEBUGF("Nextfree: 0x%lx\n",fat_bpb
->fsinfo
.nextfree
);
471 LDEBUGF("Cluster count: 0x%lx\n",fat_bpb
->dataclusters
);
472 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
473 LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb
->fatsize
);
475 #ifdef HAVE_MULTIVOLUME
476 fat_bpb
->mounted
= true;
483 int fat_unmount(int volume
, bool flush
)
486 #ifdef HAVE_MULTIVOLUME
487 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
494 rc
= flush_fat(IF_MV(fat_bpb
)); /* the clean way, while still alive */
497 { /* volume is not accessible any more, e.g. MMC removed */
499 mutex_lock(&cache_mutex
);
500 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
502 struct fat_cache_entry
*fce
= &fat_cache
[i
];
504 #ifdef HAVE_MULTIVOLUME
505 && fce
->fat_vol
== fat_bpb
509 fce
->inuse
= false; /* discard all from that volume */
513 mutex_unlock(&cache_mutex
);
516 #ifdef HAVE_MULTIVOLUME
517 fat_bpb
->mounted
= false;
521 #endif /* #ifdef HAVE_HOTSWAP */
523 void fat_recalc_free(IF_MV_NONVOID(int volume
))
525 #ifndef HAVE_MULTIVOLUME
526 const int volume
= 0;
528 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
531 #ifdef HAVE_FAT16SUPPORT
532 if (fat_bpb
->is_fat16
)
534 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
536 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
537 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
538 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
539 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
542 if (letoh16(fat
[j
]) == 0x0000) {
544 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
545 fat_bpb
->fsinfo
.nextfree
= c
;
551 #endif /* #ifdef HAVE_FAT16SUPPORT */
553 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
555 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
556 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
557 unsigned long c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
558 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
561 if (!(letoh32(fat
[j
]) & 0x0fffffff)) {
563 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
564 fat_bpb
->fsinfo
.nextfree
= c
;
569 fat_bpb
->fsinfo
.freecount
= free
;
570 update_fsinfo(IF_MV(fat_bpb
));
573 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
575 #ifndef HAVE_MULTIVOLUME
576 struct bpb
* fat_bpb
= &fat_bpbs
[0];
578 if(fat_bpb
->bpb_bytspersec
% SECTOR_SIZE
)
580 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n",
581 fat_bpb
->bpb_bytspersec
);
584 if((long)fat_bpb
->bpb_secperclus
* (long)fat_bpb
->bpb_bytspersec
587 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
589 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
590 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
593 if(fat_bpb
->bpb_numfats
!= 2)
595 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
596 fat_bpb
->bpb_numfats
);
598 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
600 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
601 "media type (0x%02x)\n",
604 if(fat_bpb
->last_word
!= 0xaa55)
606 DEBUGF( "bpb_is_sane() - Error: Last word is not "
607 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
611 if (fat_bpb
->fsinfo
.freecount
>
612 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
613 fat_bpb
->bpb_secperclus
)
615 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
616 "(0x%04lx)\n", fat_bpb
->fsinfo
.freecount
);
623 static void flush_fat_sector(struct fat_cache_entry
*fce
,
624 unsigned char *sectorbuf
)
629 /* With multivolume, use only the FAT info from the cached sector! */
630 #ifdef HAVE_MULTIVOLUME
631 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
633 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
636 /* Write to the first FAT */
637 rc
= storage_write_sectors(IF_MD2(fce
->fat_vol
->drive
,)
642 panicf("flush_fat_sector() - Could not write sector %ld"
646 #ifdef HAVE_MULTIVOLUME
647 if(fce
->fat_vol
->bpb_numfats
> 1)
649 if(fat_bpbs
[0].bpb_numfats
> 1)
652 /* Write to the second FAT */
653 #ifdef HAVE_MULTIVOLUME
654 secnum
+= fce
->fat_vol
->fatsize
;
656 secnum
+= fat_bpbs
[0].fatsize
;
658 rc
= storage_write_sectors(IF_MD2(fce
->fat_vol
->drive
,)
659 secnum
, 1, sectorbuf
);
662 panicf("flush_fat_sector() - Could not write sector %ld"
670 /* Note: The returned pointer is only safely valid until the next
671 task switch! (Any subsequent ata read/write may yield.) */
672 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
673 long fatsector
, bool dirty
)
675 #ifndef HAVE_MULTIVOLUME
676 struct bpb
* fat_bpb
= &fat_bpbs
[0];
678 long secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
679 int cache_index
= secnum
& FAT_CACHE_MASK
;
680 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
681 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
684 mutex_lock(&cache_mutex
); /* make changes atomic */
686 /* Delete the cache entry if it isn't the sector we want */
687 if(fce
->inuse
&& (fce
->secnum
!= secnum
688 #ifdef HAVE_MULTIVOLUME
689 || fce
->fat_vol
!= fat_bpb
693 /* Write back if it is dirty */
696 flush_fat_sector(fce
, sectorbuf
);
701 /* Load the sector if it is not cached */
704 rc
= storage_read_sectors(IF_MD2(fat_bpb
->drive
,)
705 secnum
+ fat_bpb
->startsector
,1,
709 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
710 " (error %d)\n", secnum
, rc
);
711 mutex_unlock(&cache_mutex
);
715 fce
->secnum
= secnum
;
716 #ifdef HAVE_MULTIVOLUME
717 fce
->fat_vol
= fat_bpb
;
721 fce
->dirty
= true; /* dirt remains, sticky until flushed */
722 mutex_unlock(&cache_mutex
);
726 static unsigned long find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,)
727 unsigned long startcluster
)
729 #ifndef HAVE_MULTIVOLUME
730 struct bpb
* fat_bpb
= &fat_bpbs
[0];
732 unsigned long sector
;
733 unsigned long offset
;
736 #ifdef HAVE_FAT16SUPPORT
737 if (fat_bpb
->is_fat16
)
739 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
740 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
742 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
744 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
745 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
748 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
749 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
750 if (letoh16(fat
[k
]) == 0x0000) {
751 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
752 /* Ignore the reserved clusters 0 & 1, and also
753 cluster numbers out of bounds */
754 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
756 LDEBUGF("find_free_cluster(%lx) == %x\n",startcluster
,c
);
757 fat_bpb
->fsinfo
.nextfree
= c
;
765 #endif /* #ifdef HAVE_FAT16SUPPORT */
767 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
768 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
770 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
772 unsigned long nr
= (i
+ sector
) % fat_bpb
->fatsize
;
773 unsigned long* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
776 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
777 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
778 if (!(letoh32(fat
[k
]) & 0x0fffffff)) {
779 unsigned long c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
780 /* Ignore the reserved clusters 0 & 1, and also
781 cluster numbers out of bounds */
782 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
784 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster
,c
);
785 fat_bpb
->fsinfo
.nextfree
= c
;
793 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster
);
794 return 0; /* 0 is an illegal cluster number */
797 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
,
800 #ifndef HAVE_MULTIVOLUME
801 struct bpb
* fat_bpb
= &fat_bpbs
[0];
803 #ifdef HAVE_FAT16SUPPORT
804 if (fat_bpb
->is_fat16
)
806 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
807 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
812 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
815 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
818 panicf("Updating reserved FAT entry %ld.\n",entry
);
820 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
823 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
828 if (letoh16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
829 fat_bpb
->fsinfo
.freecount
--;
832 if (letoh16(sec
[offset
]))
833 fat_bpb
->fsinfo
.freecount
++;
836 LDEBUGF("update_fat_entry: %lu free clusters\n",
837 fat_bpb
->fsinfo
.freecount
);
839 sec
[offset
] = htole16(val
);
842 #endif /* #ifdef HAVE_FAT16SUPPORT */
844 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
845 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
848 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry
,val
);
851 panicf("Creating FAT loop: %lx,%lx\n",entry
,val
);
854 panicf("Updating reserved FAT entry %ld.\n",entry
);
856 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
859 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector
);
864 if (!(letoh32(sec
[offset
]) & 0x0fffffff) &&
865 fat_bpb
->fsinfo
.freecount
> 0)
866 fat_bpb
->fsinfo
.freecount
--;
869 if (letoh32(sec
[offset
]) & 0x0fffffff)
870 fat_bpb
->fsinfo
.freecount
++;
873 LDEBUGF("update_fat_entry: %ld free clusters\n",
874 fat_bpb
->fsinfo
.freecount
);
876 /* don't change top 4 bits */
877 sec
[offset
] &= htole32(0xf0000000);
878 sec
[offset
] |= htole32(val
& 0x0fffffff);
884 static long read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned long entry
)
886 #ifdef HAVE_FAT16SUPPORT
887 #ifndef HAVE_MULTIVOLUME
888 struct bpb
* fat_bpb
= &fat_bpbs
[0];
890 if (fat_bpb
->is_fat16
)
892 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
893 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
896 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
899 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
903 return letoh16(sec
[offset
]);
906 #endif /* #ifdef HAVE_FAT16SUPPORT */
908 long sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
909 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
912 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
915 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector
);
919 return letoh32(sec
[offset
]) & 0x0fffffff;
923 static long get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) long cluster
)
926 long eof_mark
= FAT_EOF_MARK
;
928 #ifdef HAVE_FAT16SUPPORT
929 #ifndef HAVE_MULTIVOLUME
930 struct bpb
* fat_bpb
= &fat_bpbs
[0];
932 if (fat_bpb
->is_fat16
)
934 eof_mark
&= 0xFFFF; /* only 16 bit */
935 if (cluster
< 0) /* FAT16 root dir */
936 return cluster
+ 1; /* don't use the FAT */
939 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
941 /* is this last cluster in chain? */
942 if ( next_cluster
>= eof_mark
)
948 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
950 #ifndef HAVE_MULTIVOLUME
951 struct bpb
* fat_bpb
= &fat_bpbs
[0];
953 unsigned char fsinfo
[SECTOR_SIZE
];
954 unsigned long* intptr
;
957 #ifdef HAVE_FAT16SUPPORT
958 if (fat_bpb
->is_fat16
)
959 return 0; /* FAT16 has no FsInfo */
960 #endif /* #ifdef HAVE_FAT16SUPPORT */
963 rc
= storage_read_sectors(IF_MD2(fat_bpb
->drive
,)
964 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
967 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
970 intptr
= (long*)&(fsinfo
[FSINFO_FREECOUNT
]);
971 *intptr
= htole32(fat_bpb
->fsinfo
.freecount
);
973 intptr
= (long*)&(fsinfo
[FSINFO_NEXTFREE
]);
974 *intptr
= htole32(fat_bpb
->fsinfo
.nextfree
);
976 rc
= storage_write_sectors(IF_MD2(fat_bpb
->drive
,)
977 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
980 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
987 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
992 LDEBUGF("flush_fat()\n");
994 mutex_lock(&cache_mutex
);
995 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
997 struct fat_cache_entry
*fce
= &fat_cache
[i
];
999 #ifdef HAVE_MULTIVOLUME
1000 && fce
->fat_vol
== fat_bpb
1004 sec
= fat_cache_sectors
[i
];
1005 flush_fat_sector(fce
, sec
);
1008 mutex_unlock(&cache_mutex
);
1010 rc
= update_fsinfo(IF_MV(fat_bpb
));
1017 static void fat_time(unsigned short* date
,
1018 unsigned short* time
,
1019 unsigned short* tenth
)
1022 struct tm
* tm
= get_time();
1025 *date
= ((tm
->tm_year
- 80) << 9) |
1026 ((tm
->tm_mon
+ 1) << 5) |
1030 *time
= (tm
->tm_hour
<< 11) |
1035 *tenth
= (tm
->tm_sec
& 1) * 100;
1037 /* non-RTC version returns an increment from the supplied time, or a
1038 * fixed standard time/date if no time given as input */
1040 /* Macros to convert a 2-digit string to a decimal constant.
1041 (YEAR), MONTH and DAY are set by the date command, which outputs
1042 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1043 misinterpretation as an octal constant. */
1044 #define S100(x) 1 ## x
1045 #define C2DIG2DEC(x) (S100(x)-100)
1046 /* The actual build date, as FAT date constant */
1047 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1048 | (C2DIG2DEC(MONTH) << 5) \
1051 bool date_forced
= false;
1052 bool next_day
= false;
1053 unsigned time2
= 0; /* double time, for CRTTIME with 1s precision */
1055 if (date
&& *date
< BUILD_DATE_FAT
)
1057 *date
= BUILD_DATE_FAT
;
1064 if (time2
== 0 || date_forced
)
1066 time2
= (11 < 6) | 11; /* set to 00:11:11 */
1070 unsigned mins
= (time2
>> 6) & 0x3f;
1071 unsigned hours
= (time2
>> 12) & 0x1f;
1073 mins
= 11 * ((mins
/11) + 1); /* advance to next multiple of 11 */
1076 mins
= 11; /* 00 would be a bad marker */
1083 time2
= (hours
<< 12) | (mins
<< 6) | mins
; /* secs = mins */
1089 *tenth
= (time2
& 1) * 100;
1091 if (date
&& next_day
)
1093 static const unsigned char daysinmonth
[] =
1094 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1095 unsigned day
= *date
& 0x1f;
1096 unsigned month
= (*date
>> 5) & 0x0f;
1097 unsigned year
= (*date
>> 9) & 0x7f;
1099 /* simplification: ignore leap years */
1100 if (++day
> daysinmonth
[month
-1])
1109 *date
= (year
<< 9) | (month
<< 5) | day
;
1112 #endif /* CONFIG_RTC */
1115 static int write_long_name(struct fat_file
* file
,
1116 unsigned int firstentry
,
1117 unsigned int numentries
,
1118 const unsigned char* name
,
1119 const unsigned char* shortname
,
1121 unsigned char *sector_buffer
)
1123 unsigned char* entry
;
1124 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1125 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1126 unsigned char chksum
= 0;
1127 unsigned int i
, j
=0;
1128 unsigned int nameidx
=0, namelen
= utf8length(name
);
1130 unsigned short name_utf16
[namelen
+ 1];
1132 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1133 file
->firstcluster
, firstentry
, numentries
, name
);
1135 rc
= fat_seek(file
, sector
);
1139 rc
= fat_readwrite(file
, 1, sector_buffer
, false);
1143 /* calculate shortname checksum */
1144 for (i
=11; i
>0; i
--)
1145 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1147 /* calc position of last name segment */
1148 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1150 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1151 nameidx
+= NAME_BYTES_PER_ENTRY
);
1153 /* we need to convert the name first */
1154 /* since it is written in reverse order */
1155 for (i
= 0; i
<= namelen
; i
++)
1156 name
= utf8decode(name
, &name_utf16
[i
]);
1158 for (i
=0; i
< numentries
; i
++) {
1160 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1161 /* update current sector */
1162 rc
= fat_seek(file
, sector
);
1166 rc
= fat_readwrite(file
, 1, sector_buffer
, true);
1170 /* read next sector */
1171 rc
= fat_readwrite(file
, 1, sector_buffer
, false);
1173 LDEBUGF("Failed writing new sector: %d\n",rc
);
1178 memset(sector_buffer
, 0, SECTOR_SIZE
);
1184 entry
= sector_buffer
+ idx
* DIR_ENTRY_SIZE
;
1186 /* verify this entry is free */
1187 if (entry
[0] && entry
[0] != 0xe5 )
1188 panicf("Dir entry %d in sector %x is not free! "
1189 "%02x %02x %02x %02x",
1191 entry
[0], entry
[1], entry
[2], entry
[3]);
1193 memset(entry
, 0, DIR_ENTRY_SIZE
);
1194 if ( i
+1 < numentries
) {
1195 /* longname entry */
1196 unsigned int k
, l
= nameidx
;
1198 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1200 /* mark this as last long entry */
1201 entry
[FATLONG_ORDER
] |= FATLONG_LAST_LONG_ENTRY
;
1203 /* pad name with 0xffff */
1204 for (k
=1; k
<11; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1205 for (k
=14; k
<26; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1206 for (k
=28; k
<32; k
++) entry
[k
] = FAT_LONGNAME_PAD_BYTE
;
1209 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1210 entry
[k
*2 + 1] = (unsigned char)(name_utf16
[l
] & 0xff);
1211 entry
[k
*2 + 2] = (unsigned char)(name_utf16
[l
++] >> 8);
1213 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1214 entry
[k
*2 + 14] = (unsigned char)(name_utf16
[l
] & 0xff);
1215 entry
[k
*2 + 15] = (unsigned char)(name_utf16
[l
++] >> 8);
1217 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1218 entry
[k
*2 + 28] = (unsigned char)(name_utf16
[l
] & 0xff);
1219 entry
[k
*2 + 29] = (unsigned char)(name_utf16
[l
++] >> 8);
1222 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1223 entry
[FATDIR_FSTCLUSLO
] = 0;
1224 entry
[FATLONG_TYPE
] = 0;
1225 entry
[FATLONG_CHKSUM
] = chksum
;
1226 LDEBUGF("Longname entry %d: %s\n", idx
, name
+nameidx
);
1229 /* shortname entry */
1230 unsigned short date
=0, time
=0, tenth
=0;
1231 LDEBUGF("Shortname entry: %s\n", shortname
);
1232 memcpy(entry
+ FATDIR_NAME
, shortname
, 11);
1233 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1234 entry
[FATDIR_NTRES
] = 0;
1236 fat_time(&date
, &time
, &tenth
);
1237 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1238 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = htole16(time
);
1239 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1240 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = htole16(date
);
1241 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1242 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1245 nameidx
-= NAME_BYTES_PER_ENTRY
;
1248 /* update last sector */
1249 rc
= fat_seek(file
, sector
);
1253 rc
= fat_readwrite(file
, 1, sector_buffer
, true);
1260 static int fat_checkname(const unsigned char* newname
)
1262 static const char invalid_chars
[] = "\"*/:<>?\\|";
1263 int len
= strlen(newname
);
1264 /* More sanity checks are probably needed */
1265 if (len
> 255 || newname
[len
- 1] == '.')
1271 if (*newname
< ' ' || strchr(invalid_chars
, *newname
) != NULL
)
1275 /* check trailing space(s) */
1276 if(*(--newname
) == ' ')
1282 static int add_dir_entry(struct fat_dir
* dir
,
1283 struct fat_file
* file
,
1288 #ifdef HAVE_MULTIVOLUME
1289 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1291 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1293 unsigned char buf
[SECTOR_SIZE
];
1294 unsigned char shortname
[12];
1296 unsigned int sector
;
1298 int entries_needed
, entries_found
= 0;
1301 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1302 name
, file
->firstcluster
);
1304 /* Don't check dotdirs name for validity */
1305 if (dotdir
== false) {
1306 rc
= fat_checkname(name
);
1308 /* filename is invalid */
1313 #ifdef HAVE_MULTIVOLUME
1314 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1317 /* The "." and ".." directory entries must not be long names */
1320 strlcpy(shortname
, name
, 12);
1321 for(i
= strlen(shortname
); i
< 12; i
++)
1326 create_dos_name(name
, shortname
);
1328 /* one dir entry needed for every 13 bytes of filename,
1329 plus one entry for the short name */
1330 entries_needed
= (utf8length(name
) + (NAME_BYTES_PER_ENTRY
-1))
1331 / NAME_BYTES_PER_ENTRY
+ 1;
1337 rc
= fat_seek(&dir
->file
, 0);
1341 /* step 1: search for free entries and check for duplicate shortname */
1342 for (sector
= 0; !done
; sector
++)
1346 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1348 DEBUGF( "add_dir_entry() - Couldn't read dir"
1349 " (error code %d)\n", rc
);
1353 if (rc
== 0) { /* current end of dir reached */
1354 LDEBUGF("End of dir on cluster boundary\n");
1358 /* look for free slots */
1359 for (i
= 0; i
< DIR_ENTRIES_PER_SECTOR
; i
++)
1361 switch (buf
[i
* DIR_ENTRY_SIZE
]) {
1363 entries_found
+= DIR_ENTRIES_PER_SECTOR
- i
;
1364 LDEBUGF("Found end of dir %d\n",
1365 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1366 i
= DIR_ENTRIES_PER_SECTOR
- 1;
1372 LDEBUGF("Found free entry %d (%d/%d)\n",
1373 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1374 entries_found
, entries_needed
);
1380 /* check that our intended shortname doesn't already exist */
1381 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 11)) {
1382 /* shortname exists already, make a new one */
1383 randomize_dos_name(shortname
);
1384 LDEBUGF("Duplicate shortname, changing to %s\n",
1387 /* name has changed, we need to restart search */
1392 if (firstentry
< 0 && (entries_found
>= entries_needed
))
1393 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
+ 1
1398 /* step 2: extend the dir if necessary */
1401 LDEBUGF("Adding new sector(s) to dir\n");
1402 rc
= fat_seek(&dir
->file
, sector
);
1405 memset(buf
, 0, sizeof buf
);
1407 /* we must clear whole clusters */
1408 for (; (entries_found
< entries_needed
) ||
1409 (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
); sector
++)
1411 if (sector
>= (65536/DIR_ENTRIES_PER_SECTOR
))
1412 return -5; /* dir too large -- FAT specification */
1414 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1415 if (rc
< 1) /* No more room or something went wrong */
1418 entries_found
+= DIR_ENTRIES_PER_SECTOR
;
1421 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
- entries_found
;
1424 /* step 3: add entry */
1425 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1426 LDEBUGF("Adding longname to entry %d in sector %d\n",
1427 firstentry
, sector
);
1429 rc
= write_long_name(&dir
->file
, firstentry
,
1430 entries_needed
, name
,
1431 shortname
, is_directory
, buf
);
1435 /* remember where the shortname dir entry is located */
1436 file
->direntry
= firstentry
+ entries_needed
- 1;
1437 file
->direntries
= entries_needed
;
1438 file
->dircluster
= dir
->file
.firstcluster
;
1439 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1440 file
->direntry
, file
->direntries
);
1445 static unsigned char char2dos(unsigned char c
, int* randomize
)
1447 static const char invalid_chars
[] = "\"*+,./:;<=>?[\\]|";
1450 c
= 0; /* Illegal char, remove */
1451 else if (strchr(invalid_chars
, c
) != NULL
)
1453 /* Illegal char, replace */
1455 *randomize
= 1; /* as per FAT spec */
1463 static void create_dos_name(const unsigned char *name
, unsigned char *newname
)
1469 /* Find extension part */
1470 ext
= strrchr(name
, '.');
1471 if (ext
== name
) /* handle .dotnames */
1474 /* needs to randomize? */
1475 if((ext
&& (strlen(ext
) > 4)) ||
1476 ((ext
? (unsigned int)(ext
-name
) : strlen(name
)) > 8) )
1480 for (i
= 0; *name
&& (!ext
|| name
< ext
) && (i
< 8); name
++)
1482 unsigned char c
= char2dos(*name
, &randomize
);
1487 /* Pad both name and extension */
1491 if (newname
[0] == 0xe5) /* Special kanji character */
1495 { /* Extension part */
1497 for (i
= 8; *ext
&& (i
< 11); ext
++)
1499 unsigned char c
= char2dos(*ext
, &randomize
);
1506 randomize_dos_name(newname
);
1509 static void randomize_dos_name(unsigned char *name
)
1511 unsigned char* tilde
= NULL
; /* ~ location */
1512 unsigned char* lastpt
= NULL
; /* last point of filename */
1513 unsigned char* nameptr
= name
; /* working copy of name pointer */
1514 unsigned char num
[9]; /* holds number as string */
1522 /* hunt for ~ and where to put it */
1523 if((!tilde
) && (*nameptr
== '~'))
1525 if((!lastpt
) && ((*nameptr
== ' ' || *nameptr
== '~')))
1531 /* extract current count and increment */
1532 memcpy(num
,tilde
+1,7-(unsigned int)(tilde
-name
));
1533 num
[7-(unsigned int)(tilde
-name
)] = 0;
1534 cnt
= atoi(num
) + 1;
1536 cnt
%= 10000000; /* protection */
1537 snprintf(num
, 9, "~%d", cnt
); /* allow room for trailing zero */
1538 numlen
= strlen(num
); /* required space */
1539 offset
= (unsigned int)(lastpt
? lastpt
- name
: 8); /* prev startpoint */
1540 if(offset
> (8-numlen
)) offset
= 8-numlen
; /* correct for new numlen */
1542 memcpy(&name
[offset
], num
, numlen
);
1544 /* in special case of counter overflow: pad with spaces */
1545 for(offset
= offset
+numlen
; offset
< 8; offset
++)
1549 static int update_short_entry( struct fat_file
* file
, long size
, int attr
)
1551 unsigned char buf
[SECTOR_SIZE
];
1552 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1553 unsigned char* entry
=
1554 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1555 unsigned long* sizeptr
;
1556 unsigned short* clusptr
;
1557 struct fat_file dir
;
1560 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
1561 file
->firstcluster
, file
->direntry
, size
);
1563 /* create a temporary file handle for the dir holding this file */
1564 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1568 rc
= fat_seek( &dir
, sector
);
1572 rc
= fat_readwrite(&dir
, 1, buf
, false);
1576 if (!entry
[0] || entry
[0] == 0xe5)
1577 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1579 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1581 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1582 *clusptr
= htole16(file
->firstcluster
>> 16);
1584 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1585 *clusptr
= htole16(file
->firstcluster
& 0xffff);
1587 sizeptr
= (long*)(entry
+ FATDIR_FILESIZE
);
1588 *sizeptr
= htole32(size
);
1592 unsigned short time
= 0;
1593 unsigned short date
= 0;
1595 /* get old time to increment from */
1596 unsigned short time
= htole16(*(unsigned short*)(entry
+FATDIR_WRTTIME
));
1597 unsigned short date
= htole16(*(unsigned short*)(entry
+FATDIR_WRTDATE
));
1599 fat_time(&date
, &time
, NULL
);
1600 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = htole16(time
);
1601 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = htole16(date
);
1602 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = htole16(date
);
1605 rc
= fat_seek( &dir
, sector
);
1609 rc
= fat_readwrite(&dir
, 1, buf
, true);
1616 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1622 memset(de
, 0, sizeof(struct fat_direntry
));
1623 de
->attr
= buf
[FATDIR_ATTR
];
1624 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1625 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1626 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1627 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1628 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1629 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1630 de
->firstcluster
= ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSLO
)) |
1631 ((long)(unsigned)BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1632 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1633 (the result of the shift is always considered signed) */
1636 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_NAME
);
1637 c
= buf
[FATDIR_NAME
];
1638 if (c
== 0x05) /* special kanji char */
1642 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1645 c
= buf
[FATDIR_NAME
+i
];
1647 if (buf
[FATDIR_NAME
+8] != ' ') {
1648 lowercase
= (buf
[FATDIR_NTRES
] & FAT_NTRES_LC_EXT
);
1649 de
->name
[j
++] = '.';
1650 for (i
= 8; (i
< 11) && ((c
= buf
[FATDIR_NAME
+i
]) != ' '); i
++)
1651 de
->name
[j
++] = lowercase
? tolower(c
) : c
;
1656 int fat_open(IF_MV2(int volume
,)
1658 struct fat_file
*file
,
1659 const struct fat_dir
* dir
)
1661 /* Remember where the file's dir entry is located
1662 * Do it before assigning other fields so that fat_open
1663 * can be called with file == &dir->file (see fat_opendir) */
1665 file
->direntry
= dir
->entry
- 1;
1666 file
->direntries
= dir
->entrycount
;
1667 file
->dircluster
= dir
->file
.firstcluster
;
1670 file
->firstcluster
= startcluster
;
1671 file
->lastcluster
= startcluster
;
1672 file
->lastsector
= 0;
1673 file
->clusternum
= 0;
1674 file
->sectornum
= 0;
1676 #ifdef HAVE_MULTIVOLUME
1677 file
->volume
= volume
;
1678 /* fixme: remove error check when done */
1679 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1681 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1686 LDEBUGF("fat_open(%lx), entry %d\n",startcluster
,file
->direntry
);
1690 int fat_create_file(const char* name
,
1691 struct fat_file
* file
,
1692 struct fat_dir
* dir
)
1696 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name
,(long)file
,(long)dir
);
1697 rc
= add_dir_entry(dir
, file
, name
, false, false);
1699 file
->firstcluster
= 0;
1700 file
->lastcluster
= 0;
1701 file
->lastsector
= 0;
1702 file
->clusternum
= 0;
1703 file
->sectornum
= 0;
1710 /* noinline because this is only split out of fat_create_dir to make sure
1711 * the sector buffer doesn't remain on the stack, to avoid nasty stack
1712 * overflows later on (when flush_fat() is called */
1713 static __attribute__((noinline
)) int fat_clear_cluster(int sector
,
1714 struct bpb
*fat_bpb
)
1716 unsigned char buf
[SECTOR_SIZE
];
1718 memset(buf
, 0, sizeof buf
);
1719 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1720 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1727 int fat_create_dir(const char* name
,
1728 struct fat_dir
* newdir
,
1729 struct fat_dir
* dir
)
1731 #ifdef HAVE_MULTIVOLUME
1732 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1734 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1738 struct fat_file dummyfile
;
1740 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name
,(long)newdir
,(long)dir
);
1742 memset(newdir
, 0, sizeof(struct fat_dir
));
1743 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1745 /* First, add the entry in the parent directory */
1746 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1750 /* Allocate a new cluster for the directory */
1751 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,)
1752 fat_bpb
->fsinfo
.nextfree
);
1753 if(newdir
->file
.firstcluster
== 0)
1756 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1758 /* Clear the entire cluster */
1759 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1760 rc
= fat_clear_cluster(sector
,fat_bpb
);
1765 /* Then add the "." entry */
1766 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1769 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1770 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1772 /* and the ".." entry */
1773 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1777 /* The root cluster is cluster 0 in the ".." entry */
1778 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1779 dummyfile
.firstcluster
= 0;
1781 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1782 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1784 /* Set the firstcluster field in the direntry */
1785 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1787 rc
= flush_fat(IF_MV(fat_bpb
));
1794 int fat_truncate(const struct fat_file
*file
)
1796 /* truncate trailing clusters */
1798 long last
= file
->lastcluster
;
1799 #ifdef HAVE_MULTIVOLUME
1800 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1803 LDEBUGF("fat_truncate(%lx, %lx)\n", file
->firstcluster
, last
);
1805 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1806 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1807 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1809 if (file
->lastcluster
)
1810 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1815 int fat_closewrite(struct fat_file
*file
, long size
, int attr
)
1818 #ifdef HAVE_MULTIVOLUME
1819 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1821 LDEBUGF("fat_closewrite(size=%ld)\n",size
);
1825 if ( file
->firstcluster
) {
1826 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1827 file
->firstcluster
= 0;
1831 if (file
->dircluster
) {
1832 rc
= update_short_entry(file
, size
, attr
);
1837 flush_fat(IF_MV(fat_bpb
));
1840 if ( file
->firstcluster
) {
1842 #ifdef HAVE_MULTIVOLUME
1843 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1845 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1850 for ( next
= file
->firstcluster
; next
;
1851 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) ) {
1852 LDEBUGF("cluster %ld: %lx\n", count
, next
);
1855 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1856 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1858 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1859 panicf("Cluster chain is too long\n");
1861 panicf("Cluster chain is too short\n");
1868 static int free_direntries(struct fat_file
* file
)
1870 unsigned char buf
[SECTOR_SIZE
];
1871 struct fat_file dir
;
1872 int numentries
= file
->direntries
;
1873 unsigned int entry
= file
->direntry
- numentries
+ 1;
1874 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1878 /* create a temporary file handle for the dir holding this file */
1879 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1883 rc
= fat_seek( &dir
, sector
);
1887 rc
= fat_readwrite(&dir
, 1, buf
, false);
1891 for (i
=0; i
< numentries
; i
++) {
1892 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1893 entry
, i
+1, numentries
);
1894 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1897 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1898 /* flush this sector */
1899 rc
= fat_seek(&dir
, sector
);
1903 rc
= fat_readwrite(&dir
, 1, buf
, true);
1907 if ( i
+1 < numentries
) {
1908 /* read next sector */
1909 rc
= fat_readwrite(&dir
, 1, buf
, false);
1917 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1918 /* flush this sector */
1919 rc
= fat_seek(&dir
, sector
);
1923 rc
= fat_readwrite(&dir
, 1, buf
, true);
1931 int fat_remove(struct fat_file
* file
)
1933 long next
, last
= file
->firstcluster
;
1935 #ifdef HAVE_MULTIVOLUME
1936 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1939 LDEBUGF("fat_remove(%lx)\n",last
);
1942 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1943 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1947 if ( file
->dircluster
) {
1948 rc
= free_direntries(file
);
1953 file
->firstcluster
= 0;
1954 file
->dircluster
= 0;
1956 rc
= flush_fat(IF_MV(fat_bpb
));
1963 int fat_rename(struct fat_file
* file
,
1964 struct fat_dir
* dir
,
1965 const unsigned char* newname
,
1970 struct fat_file olddir_file
;
1971 struct fat_file newfile
= *file
;
1972 unsigned char* entry
= NULL
;
1973 unsigned short* clusptr
= NULL
;
1974 unsigned int parentcluster
;
1975 #ifdef HAVE_MULTIVOLUME
1976 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1978 if (file
->volume
!= dir
->file
.volume
) {
1979 DEBUGF("No rename across volumes!\n");
1983 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1986 if ( !file
->dircluster
) {
1987 DEBUGF("File has no dir cluster!\n");
1991 /* create new name */
1992 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1996 /* write size and cluster link */
1997 rc
= update_short_entry(&newfile
, size
, attr
);
2001 /* remove old name */
2002 rc
= free_direntries(file
);
2006 rc
= flush_fat(IF_MV(fat_bpb
));
2010 /* if renaming a directory, update the .. entry to make sure
2011 it points to its parent directory (we don't check if it was a move) */
2012 if(FAT_ATTR_DIRECTORY
== attr
) {
2013 unsigned char buf
[SECTOR_SIZE
];
2014 /* open the dir that was renamed, we re-use the olddir_file struct */
2015 rc
= fat_open(IF_MV2(file
->volume
,) newfile
.firstcluster
, &olddir_file
, NULL
);
2019 /* get the first sector of the dir */
2020 rc
= fat_seek(&olddir_file
, 0);
2024 rc
= fat_readwrite(&olddir_file
, 1, buf
, false);
2028 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2029 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
2032 parentcluster
= dir
->file
.firstcluster
;
2034 entry
= buf
+ DIR_ENTRY_SIZE
;
2035 if(strncmp(".. ", entry
, 11))
2037 /* .. entry must be second entry according to FAT spec (p.29) */
2038 DEBUGF("Second dir entry is not double-dot!\n");
2041 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
2042 *clusptr
= htole16(parentcluster
>> 16);
2044 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
2045 *clusptr
= htole16(parentcluster
& 0xffff);
2047 /* write back this sector */
2048 rc
= fat_seek(&olddir_file
, 0);
2052 rc
= fat_readwrite(&olddir_file
, 1, buf
, true);
2060 static long next_write_cluster(struct fat_file
* file
,
2064 #ifdef HAVE_MULTIVOLUME
2065 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2067 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2072 LDEBUGF("next_write_cluster(%lx,%lx)\n",file
->firstcluster
, oldcluster
);
2075 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
2079 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
2080 else if (oldcluster
== 0)
2081 cluster
= find_free_cluster(IF_MV2(fat_bpb
,)
2082 fat_bpb
->fsinfo
.nextfree
);
2083 #ifdef HAVE_FAT16SUPPORT
2084 else /* negative, pseudo-cluster of the root dir */
2085 return 0; /* impossible to append something to the root */
2090 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
2092 file
->firstcluster
= cluster
;
2093 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
2097 if (fat_bpb
->fsinfo
.freecount
>0)
2098 panicf("There is free space, but find_free_cluster() "
2099 "didn't find it!\n");
2101 DEBUGF("next_write_cluster(): Disk full!\n");
2105 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2109 *newsector
= sector
;
2113 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
2114 unsigned long start
, long count
, char* buf
, bool write
)
2116 #ifndef HAVE_MULTIVOLUME
2117 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2121 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
2122 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
2124 unsigned long firstallowed
;
2125 #ifdef HAVE_FAT16SUPPORT
2126 if (fat_bpb
->is_fat16
)
2127 firstallowed
= fat_bpb
->rootdirsector
;
2130 firstallowed
= fat_bpb
->firstdatasector
;
2132 if (start
< firstallowed
)
2133 panicf("Write %ld before data\n", firstallowed
- start
);
2134 if (start
+ count
> fat_bpb
->totalsectors
)
2135 panicf("Write %ld after data\n",
2136 start
+ count
- fat_bpb
->totalsectors
);
2137 rc
= storage_write_sectors(IF_MD2(fat_bpb
->drive
,)
2138 start
+ fat_bpb
->startsector
, count
, buf
);
2141 rc
= storage_read_sectors(IF_MD2(fat_bpb
->drive
,)
2142 start
+ fat_bpb
->startsector
, count
, buf
);
2144 DEBUGF( "transfer() - Couldn't %s sector %lx"
2145 " (error code %d)\n",
2146 write
? "write":"read", start
, rc
);
2153 long fat_readwrite( struct fat_file
*file
, long sectorcount
,
2154 void* buf
, bool write
)
2156 #ifdef HAVE_MULTIVOLUME
2157 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2159 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2161 long cluster
= file
->lastcluster
;
2162 long sector
= file
->lastsector
;
2163 long clusternum
= file
->clusternum
;
2164 long numsec
= file
->sectornum
;
2165 bool eof
= file
->eof
;
2166 long first
=0, last
=0;
2170 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
2171 file
->firstcluster
,sectorcount
,(long)buf
,write
?"write":"read");
2172 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2173 sector
,numsec
, eof
?1:0);
2178 /* find sequential sectors and write them all at once */
2179 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
2181 if ( numsec
> (long)fat_bpb
->bpb_secperclus
|| !cluster
) {
2182 long oldcluster
= cluster
;
2183 long oldsector
= sector
;
2184 long oldnumsec
= numsec
;
2186 cluster
= next_write_cluster(file
, cluster
, §or
);
2188 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2189 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2198 /* remember last cluster, in case
2199 we want to append to the file */
2201 cluster
= oldcluster
;
2204 i
= -1; /* Error code */
2215 /* look up first sector of file */
2216 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2218 #ifdef HAVE_FAT16SUPPORT
2219 if (file
->firstcluster
< 0)
2220 { /* FAT16 root dir */
2221 sector
+= fat_bpb
->rootdiroffset
;
2222 numsec
+= fat_bpb
->rootdiroffset
;
2231 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2232 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2233 long count
= last
- first
+ 1;
2234 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2238 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2242 if ((i
== sectorcount
-1) && /* last sector requested */
2245 long count
= sector
- first
+ 1;
2246 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2254 file
->lastcluster
= cluster
;
2255 file
->lastsector
= sector
;
2256 file
->clusternum
= clusternum
;
2257 file
->sectornum
= numsec
;
2260 /* if eof, don't report last block as read/written */
2264 DEBUGF("Sectors written: %ld\n", i
);
2268 int fat_seek(struct fat_file
*file
, unsigned long seeksector
)
2270 #ifdef HAVE_MULTIVOLUME
2271 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2273 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2275 long clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2276 long cluster
= file
->firstcluster
;
2279 #ifdef HAVE_FAT16SUPPORT
2280 if (cluster
< 0) /* FAT16 root dir */
2281 seeksector
+= fat_bpb
->rootdiroffset
;
2286 /* we need to find the sector BEFORE the requested, since
2287 the file struct stores the last accessed sector */
2289 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2290 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2292 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2294 cluster
= file
->lastcluster
;
2295 numclusters
-= file
->clusternum
;
2298 for (i
=0; i
<numclusters
; i
++) {
2299 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2301 DEBUGF("Seeking beyond the end of the file! "
2302 "(sector %ld, cluster %ld)\n", seeksector
, i
);
2307 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2313 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
2314 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2316 file
->lastcluster
= cluster
;
2317 file
->lastsector
= sector
;
2318 file
->clusternum
= clusternum
;
2319 file
->sectornum
= sectornum
+ 1;
2323 int fat_opendir(IF_MV2(int volume
,)
2324 struct fat_dir
*dir
, unsigned long startcluster
,
2325 const struct fat_dir
*parent_dir
)
2327 #ifdef HAVE_MULTIVOLUME
2328 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2329 /* fixme: remove error check when done */
2330 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2332 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2336 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2340 if (startcluster
== 0)
2341 startcluster
= fat_bpb
->bpb_rootclus
;
2343 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2346 DEBUGF( "fat_opendir() - Couldn't open dir"
2347 " (error code %d)\n", rc
);
2351 /* assign them after fat_open call so that fat_opendir can be called with the same
2352 * fat_dir as parent and result */
2359 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2365 unsigned char firstbyte
;
2366 /* Long file names are stored in special entries. Each entry holds
2367 up to 13 characters. Names can be max 255 chars (not bytes!) long */
2368 /* The number of long entries in the long name can be retrieve from the first
2369 * long entry because there are stored in reverse order and have an ordinal */
2371 /* The long entries are expected to be in order, so remember the last ordinal */
2372 int last_long_ord
= 0;
2374 dir
->entrycount
= 0;
2378 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2380 rc
= fat_readwrite(&dir
->file
, 1, dir
->sectorcache
, false);
2387 DEBUGF( "fat_getnext() - Couldn't read dir"
2388 " (error code %d)\n", rc
);
2391 dir
->sector
= dir
->file
.lastsector
;
2394 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2395 i
< DIR_ENTRIES_PER_SECTOR
; i
++) {
2396 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2398 firstbyte
= dir
->sectorcache
[entrypos
];
2401 if (firstbyte
== 0xe5) {
2403 dir
->entrycount
= 0;
2407 if (firstbyte
== 0) {
2410 dir
->entrycount
= 0;
2417 if ( ( dir
->sectorcache
[entrypos
+ FATDIR_ATTR
] &
2418 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2419 /* extract ordinal */
2420 order
= dir
->sectorcache
[entrypos
+ FATLONG_ORDER
] & ~FATLONG_LAST_LONG_ENTRY
;
2421 /* is this entry the first long entry ? (first in order but containing last part) */
2422 if (dir
->sectorcache
[entrypos
+ FATLONG_ORDER
] & FATLONG_LAST_LONG_ENTRY
) {
2423 /* check that order is not too big ! (and non-zero) */
2424 if(order
<= 0 || order
> FATLONG_MAX_ORDER
)
2425 continue; /* ignore the whole LFN, will trigger lots of warnings */
2427 last_long_ord
= order
;
2430 /* check orphan entry */
2431 if (nb_longs
== 0) {
2432 logf("fat warning: orphan LFN entry");
2438 if (order
!= (last_long_ord
- 1)) {
2439 logf("fat warning: wrong LFN ordinal");
2440 /* ignore the whole LFN, will trigger lots of warnings */
2444 last_long_ord
= order
;
2447 /* copy part, reuse [order] for another purpose :) */
2448 order
= (order
- 1) * FATLONG_NAME_BYTES_PER_ENTRY
;
2449 for(j
= 0; j
< FATLONG_NAME_CHUNKS
; j
++) {
2450 memcpy(dir
->longname
+ order
,
2451 dir
->sectorcache
+ entrypos
+ FATLONG_NAME_POS
[j
],
2452 FATLONG_NAME_SIZE
[j
]);
2453 order
+= FATLONG_NAME_SIZE
[j
];
2457 if ( parse_direntry(entry
, dir
->sectorcache
+ entrypos
) ) {
2459 /* don't return volume id entry */
2461 (FAT_ATTR_VOLUME_ID
|FAT_ATTR_DIRECTORY
))
2462 == FAT_ATTR_VOLUME_ID
)
2465 /* replace shortname with longname? */
2466 /* check that the long name is complete */
2467 if (nb_longs
!= 0 && last_long_ord
== 1) {
2468 /* hold a copy of the shortname in case the long one is too long */
2469 unsigned char shortname
[13]; /* 8+3+dot+\0 */
2470 int longname_utf8len
= 0;
2471 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2472 * of a UTF8 encoded character in rockbox */
2473 unsigned char longname_utf8segm
[4 + 1];
2476 /* Temporarily store short name */
2477 strcpy(shortname
, entry
->name
);
2480 /* Convert the FAT name to a utf8-encoded one.
2481 * The name is not necessary NUL-terminated ! */
2482 for (j
= 0; j
< nb_longs
* FATLONG_NAME_BYTES_PER_ENTRY
; j
+= 2) {
2483 ucs
= dir
->longname
[j
] | (dir
->longname
[j
+ 1] << 8);
2484 if(ucs
== 0 || ucs
== FAT_LONGNAME_PAD_UCS
)
2486 /* utf8encode will return a pointer after the converted
2487 * string, subtract the pointer to the start to get the length of it */
2488 segm_utf8len
= utf8encode(ucs
, longname_utf8segm
) - longname_utf8segm
;
2490 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2491 if (longname_utf8len
+ segm_utf8len
>= FAT_FILENAME_BYTES
) {
2492 /* force use of short name */
2493 longname_utf8len
= FAT_FILENAME_BYTES
+ 1;
2494 break; /* fallback later */
2497 longname_utf8segm
[segm_utf8len
] = 0;
2498 strcat(entry
->name
+ longname_utf8len
, longname_utf8segm
);
2499 longname_utf8len
+= segm_utf8len
;
2503 /* Does the utf8-encoded name fit into the entry? */
2504 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2505 if (longname_utf8len
>= FAT_FILENAME_BYTES
) {
2506 /* Take the short DOS name. Need to utf8-encode it
2507 since it may contain chars from the upper half of
2508 the OEM code page which wouldn't be a valid utf8.
2509 Beware: this file will be shown with strange
2510 glyphs in file browser since unicode 0x80 to 0x9F
2511 are control characters. */
2512 logf("SN-DOS: %s", shortname
);
2513 unsigned char *utf8
;
2514 utf8
= iso_decode(shortname
, entry
->name
, -1,
2517 logf("SN: %s", entry
->name
);
2519 logf("LN: %s", entry
->name
);
2520 logf("LNLen: %d", longname_utf8len
);
2533 unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2535 #ifndef HAVE_MULTIVOLUME
2536 const int volume
= 0;
2538 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2539 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2542 #ifdef HAVE_MULTIVOLUME
2543 bool fat_ismounted(int volume
)
2545 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);