1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
29 #include "timefuncs.h"
32 #define BYTES2INT16(array,pos) \
33 (array[pos] | (array[pos+1] << 8 ))
34 #define BYTES2INT32(array,pos) \
35 (array[pos] | (array[pos+1] << 8 ) | \
36 (array[pos+2] << 16 ) | (array[pos+3] << 24 ))
38 #define FATTYPE_FAT12 0
39 #define FATTYPE_FAT16 1
40 #define FATTYPE_FAT32 2
42 /* BPB offsets; generic */
45 #define BPB_BYTSPERSEC 11
46 #define BPB_SECPERCLUS 13
47 #define BPB_RSVDSECCNT 14
48 #define BPB_NUMFATS 16
49 #define BPB_ROOTENTCNT 17
50 #define BPB_TOTSEC16 19
52 #define BPB_FATSZ16 22
53 #define BPB_SECPERTRK 24
54 #define BPB_NUMHEADS 26
55 #define BPB_HIDDSEC 28
56 #define BPB_TOTSEC32 32
60 #define BS_RESERVED1 37
64 #define BS_FILSYSTYPE 54
67 #define BPB_FATSZ32 36
68 #define BPB_EXTFLAGS 40
70 #define BPB_ROOTCLUS 44
72 #define BPB_BKBOOTSEC 50
73 #define BS_32_DRVNUM 64
74 #define BS_32_BOOTSIG 66
75 #define BS_32_VOLID 67
76 #define BS_32_VOLLAB 71
77 #define BS_32_FILSYSTYPE 82
79 #define BPB_LAST_WORD 510
83 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
84 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
85 #define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
86 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
87 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
90 #define FATDIR_ATTR 11
91 #define FATDIR_NTRES 12
92 #define FATDIR_CRTTIMETENTH 13
93 #define FATDIR_CRTTIME 14
94 #define FATDIR_CRTDATE 16
95 #define FATDIR_LSTACCDATE 18
96 #define FATDIR_FSTCLUSHI 20
97 #define FATDIR_WRTTIME 22
98 #define FATDIR_WRTDATE 24
99 #define FATDIR_FSTCLUSLO 26
100 #define FATDIR_FILESIZE 28
102 #define FATLONG_ORDER 0
103 #define FATLONG_TYPE 12
104 #define FATLONG_CHKSUM 13
106 #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
107 #define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
108 #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
109 #define DIR_ENTRY_SIZE 32
110 #define NAME_BYTES_PER_ENTRY 13
111 #define FAT_BAD_MARK 0x0ffffff7
112 #define FAT_EOF_MARK 0x0ffffff8
114 /* filename charset conversion table */
115 static const unsigned char unicode2iso8859_2
[] = {
116 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x0100 */
117 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x0108 */
118 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110 */
119 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x0118 */
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120 */
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0128 */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0130 */
123 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x0138 */
124 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x0140 */
125 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0148 */
126 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x0150 */
127 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x0158 */
128 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x0160 */
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x0168 */
130 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0170 */
131 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x0178 */
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180 */
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0188 */
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0190 */
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0198 */
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0 */
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a8 */
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b0 */
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b8 */
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0 */
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c8 */
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d0 */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d8 */
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e0 */
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e8 */
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f0 */
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f8 */
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200 */
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0208 */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0210 */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0218 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0220 */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0228 */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0230 */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0238 */
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240 */
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0248 */
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0250 */
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0258 */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0260 */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0268 */
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0270 */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0278 */
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280 */
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0288 */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0290 */
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0298 */
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a0 */
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a8 */
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b0 */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b8 */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0x02c0 */
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c8 */
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02d0 */
175 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0x02d8 */
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e0 */
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e8 */
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02f0 */
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x02f8 */
183 unsigned int freecount
; /* last known free cluster count */
184 unsigned int nextfree
; /* first cluster to start looking for free
185 clusters, or 0xffffffff for no hint */
188 #define FSINFO_FREECOUNT 488
189 #define FSINFO_NEXTFREE 492
193 int bpb_bytspersec
; /* Bytes per sector, typically 512 */
194 unsigned int bpb_secperclus
; /* Sectors per cluster */
195 int bpb_rsvdseccnt
; /* Number of reserved sectors */
196 int bpb_numfats
; /* Number of FAT structures, typically 2 */
197 int bpb_totsec16
; /* Number of sectors on the volume (old 16-bit) */
198 int bpb_media
; /* Media type (typically 0xf0 or 0xf8) */
199 int bpb_fatsz16
; /* Number of used sectors per FAT structure */
200 unsigned int bpb_totsec32
; /* Number of sectors on the volume
202 int last_word
; /* 0xAA55 */
204 /**** FAT32 specific *****/
209 /* variables for internal use */
210 unsigned int fatsize
;
211 unsigned int totalsectors
;
212 unsigned int rootdirsector
;
213 unsigned int firstdatasector
;
214 unsigned int startsector
;
215 unsigned int dataclusters
;
216 struct fsinfo fsinfo
;
217 #ifdef HAVE_FAT16SUPPORT
218 int bpb_rootentcnt
; /* Number of dir entries in the root */
219 /* internals for FAT16 support */
220 bool is_fat16
; /* true if we mounted a FAT16 partition, false if FAT32 */
221 unsigned int rootdiroffset
; /* sector offset of root dir relative to start
222 * of first pseudo cluster */
223 #endif /* #ifdef HAVE_FAT16SUPPORT */
224 #ifdef HAVE_MULTIVOLUME
225 int drive
; /* on which physical device is this located */
226 bool mounted
; /* flag if this volume is mounted */
230 static struct bpb fat_bpbs
[NUM_VOLUMES
]; /* mounted partition info */
232 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
));
233 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
));
234 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,) int secnum
, bool dirty
);
235 static int create_dos_name(const unsigned char *name
, unsigned char *newname
);
236 static unsigned int find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,) unsigned int start
);
237 static int transfer(IF_MV2(struct bpb
* fat_bpb
,) unsigned int start
, int count
, char* buf
, bool write
);
239 #define FAT_CACHE_SIZE 0x20
240 #define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
242 struct fat_cache_entry
247 #ifdef HAVE_MULTIVOLUME
248 struct bpb
* fat_vol
; /* shared cache for all volumes */
252 static char fat_cache_sectors
[FAT_CACHE_SIZE
][SECTOR_SIZE
];
253 static struct fat_cache_entry fat_cache
[FAT_CACHE_SIZE
];
254 static struct mutex cache_mutex
;
256 static int cluster2sec(IF_MV2(struct bpb
* fat_bpb
,) int cluster
)
258 #ifndef HAVE_MULTIVOLUME
259 struct bpb
* fat_bpb
= &fat_bpbs
[0];
261 #ifdef HAVE_FAT16SUPPORT
262 /* negative clusters (FAT16 root dir) don't get the 2 offset */
263 int zerocluster
= cluster
< 0 ? 0 : 2;
265 const int zerocluster
= 2;
267 int max_cluster
= fat_bpb
->totalsectors
-
268 fat_bpb
->firstdatasector
/ fat_bpb
->bpb_secperclus
+ 1;
270 if (cluster
> max_cluster
)
272 DEBUGF( "cluster2sec() - Bad cluster number (%d)\n", cluster
);
276 return (cluster
- zerocluster
) * fat_bpb
->bpb_secperclus
277 + fat_bpb
->firstdatasector
;
280 int fat_startsector(IF_MV_NONVOID(int volume
))
282 #ifndef HAVE_MULTIVOLUME
283 const int volume
= 0;
285 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
286 return fat_bpb
->startsector
;
289 void fat_size(IF_MV2(int volume
,) unsigned int* size
, unsigned int* free
)
291 #ifndef HAVE_MULTIVOLUME
292 const int volume
= 0;
294 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
296 *size
= fat_bpb
->dataclusters
* fat_bpb
->bpb_secperclus
/ 2;
298 *free
= fat_bpb
->fsinfo
.freecount
* fat_bpb
->bpb_secperclus
/ 2;
305 mutex_init(&cache_mutex
);
307 /* mark the FAT cache as unused */
308 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
310 fat_cache
[i
].secnum
= 8; /* We use a "safe" sector just in case */
311 fat_cache
[i
].inuse
= false;
312 fat_cache
[i
].dirty
= false;
313 #ifdef HAVE_MULTIVOLUME
314 fat_cache
[i
].fat_vol
= NULL
;
317 #ifdef HAVE_MULTIVOLUME
318 /* mark the possible volumes as not mounted */
319 for (i
=0; i
<NUM_VOLUMES
;i
++)
321 fat_bpbs
[i
].mounted
= false;
326 int fat_mount(IF_MV2(int volume
,) IF_MV2(int drive
,) int startsector
)
328 #ifndef HAVE_MULTIVOLUME
329 const int volume
= 0;
331 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
332 unsigned char buf
[SECTOR_SIZE
];
335 #ifdef HAVE_FAT16SUPPORT
339 /* Read the sector */
340 rc
= ata_read_sectors(IF_MV2(drive
,) startsector
,1,buf
);
343 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc
);
347 memset(fat_bpb
, 0, sizeof(struct bpb
));
348 fat_bpb
->startsector
= startsector
;
349 #ifdef HAVE_MULTIVOLUME
350 fat_bpb
->drive
= drive
;
353 fat_bpb
->bpb_bytspersec
= BYTES2INT16(buf
,BPB_BYTSPERSEC
);
354 fat_bpb
->bpb_secperclus
= buf
[BPB_SECPERCLUS
];
355 fat_bpb
->bpb_rsvdseccnt
= BYTES2INT16(buf
,BPB_RSVDSECCNT
);
356 fat_bpb
->bpb_numfats
= buf
[BPB_NUMFATS
];
357 fat_bpb
->bpb_totsec16
= BYTES2INT16(buf
,BPB_TOTSEC16
);
358 fat_bpb
->bpb_media
= buf
[BPB_MEDIA
];
359 fat_bpb
->bpb_fatsz16
= BYTES2INT16(buf
,BPB_FATSZ16
);
360 fat_bpb
->bpb_fatsz32
= BYTES2INT32(buf
,BPB_FATSZ32
);
361 fat_bpb
->bpb_totsec32
= BYTES2INT32(buf
,BPB_TOTSEC32
);
362 fat_bpb
->last_word
= BYTES2INT16(buf
,BPB_LAST_WORD
);
364 /* calculate a few commonly used values */
365 if (fat_bpb
->bpb_fatsz16
!= 0)
366 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz16
;
368 fat_bpb
->fatsize
= fat_bpb
->bpb_fatsz32
;
370 if (fat_bpb
->bpb_totsec16
!= 0)
371 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec16
;
373 fat_bpb
->totalsectors
= fat_bpb
->bpb_totsec32
;
375 #ifdef HAVE_FAT16SUPPORT
376 fat_bpb
->bpb_rootentcnt
= BYTES2INT16(buf
,BPB_ROOTENTCNT
);
377 rootdirsectors
= ((fat_bpb
->bpb_rootentcnt
* 32)
378 + (fat_bpb
->bpb_bytspersec
- 1)) / fat_bpb
->bpb_bytspersec
;
379 #endif /* #ifdef HAVE_FAT16SUPPORT */
381 fat_bpb
->firstdatasector
= fat_bpb
->bpb_rsvdseccnt
382 #ifdef HAVE_FAT16SUPPORT
385 + fat_bpb
->bpb_numfats
* fat_bpb
->fatsize
;
387 /* Determine FAT type */
388 datasec
= fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
;
389 fat_bpb
->dataclusters
= datasec
/ fat_bpb
->bpb_secperclus
;
393 we are sometimes testing with "illegally small" fat32 images,
394 so we don't use the proper fat32 test case for test code
396 if ( fat_bpb
->bpb_fatsz16
)
398 if ( fat_bpb
->dataclusters
< 65525 )
401 #ifdef HAVE_FAT16SUPPORT
402 fat_bpb
->is_fat16
= true;
403 if (fat_bpb
->dataclusters
< 4085)
405 DEBUGF("This is FAT12. Go away!\n");
408 #else /* #ifdef HAVE_FAT16SUPPORT */
409 DEBUGF("This is not FAT32. Go away!\n");
411 #endif /* #ifndef HAVE_FAT16SUPPORT */
414 #ifdef HAVE_FAT16SUPPORT
415 if (fat_bpb
->is_fat16
)
416 { /* FAT16 specific part of BPB */
418 fat_bpb
->rootdirsector
= fat_bpb
->bpb_rsvdseccnt
419 + fat_bpb
->bpb_numfats
* fat_bpb
->bpb_fatsz16
;
420 dirclusters
= ((rootdirsectors
+ fat_bpb
->bpb_secperclus
- 1)
421 / fat_bpb
->bpb_secperclus
); /* rounded up, to full clusters */
422 /* I assign negative pseudo cluster numbers for the root directory,
423 their range is counted upward until -1. */
424 fat_bpb
->bpb_rootclus
= 0 - dirclusters
; /* backwards, before the data */
425 fat_bpb
->rootdiroffset
= dirclusters
* fat_bpb
->bpb_secperclus
429 #endif /* #ifdef HAVE_FAT16SUPPORT */
430 { /* FAT32 specific part of BPB */
431 fat_bpb
->bpb_rootclus
= BYTES2INT32(buf
,BPB_ROOTCLUS
);
432 fat_bpb
->bpb_fsinfo
= BYTES2INT16(buf
,BPB_FSINFO
);
433 fat_bpb
->rootdirsector
= cluster2sec(IF_MV2(fat_bpb
,) fat_bpb
->bpb_rootclus
);
436 rc
= bpb_is_sane(IF_MV(fat_bpb
));
439 DEBUGF( "fat_mount() - BPB is not sane\n");
443 #ifdef HAVE_FAT16SUPPORT
444 if (fat_bpb
->is_fat16
)
446 fat_bpb
->fsinfo
.freecount
= 0xffffffff; /* force recalc below */
447 fat_bpb
->fsinfo
.nextfree
= 0xffffffff;
450 #endif /* #ifdef HAVE_FAT16SUPPORT */
452 /* Read the fsinfo sector */
453 rc
= ata_read_sectors(IF_MV2(drive
,)
454 startsector
+ fat_bpb
->bpb_fsinfo
, 1, buf
);
457 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc
);
460 fat_bpb
->fsinfo
.freecount
= BYTES2INT32(buf
, FSINFO_FREECOUNT
);
461 fat_bpb
->fsinfo
.nextfree
= BYTES2INT32(buf
, FSINFO_NEXTFREE
);
464 /* calculate freecount if unset */
465 if ( fat_bpb
->fsinfo
.freecount
== 0xffffffff )
467 fat_recalc_free(IF_MV(volume
));
470 LDEBUGF("Freecount: %d\n",fat_bpb
->fsinfo
.freecount
);
471 LDEBUGF("Nextfree: 0x%x\n",fat_bpb
->fsinfo
.nextfree
);
472 LDEBUGF("Cluster count: 0x%x\n",fat_bpb
->dataclusters
);
473 LDEBUGF("Sectors per cluster: %d\n",fat_bpb
->bpb_secperclus
);
474 LDEBUGF("FAT sectors: 0x%x\n",fat_bpb
->fatsize
);
476 #ifdef HAVE_MULTIVOLUME
477 fat_bpb
->mounted
= true;
483 void fat_recalc_free(IF_MV_NONVOID(int volume
))
485 #ifndef HAVE_MULTIVOLUME
486 const int volume
= 0;
488 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
491 #ifdef HAVE_FAT16SUPPORT
492 if (fat_bpb
->is_fat16
)
494 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
496 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
497 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
498 unsigned int c
= i
* CLUSTERS_PER_FAT16_SECTOR
+ j
;
499 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
502 if (SWAB16(fat
[j
]) == 0x0000) {
504 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
505 fat_bpb
->fsinfo
.nextfree
= c
;
511 #endif /* #ifdef HAVE_FAT16SUPPORT */
513 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
515 unsigned int* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) i
, false);
516 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
517 unsigned int c
= i
* CLUSTERS_PER_FAT_SECTOR
+ j
;
518 if ( c
> fat_bpb
->dataclusters
+1 ) /* nr 0 is unused */
521 if (!(SWAB32(fat
[j
]) & 0x0fffffff)) {
523 if ( fat_bpb
->fsinfo
.nextfree
== 0xffffffff )
524 fat_bpb
->fsinfo
.nextfree
= c
;
529 fat_bpb
->fsinfo
.freecount
= free
;
530 update_fsinfo(IF_MV(fat_bpb
));
533 static int bpb_is_sane(IF_MV_NONVOID(struct bpb
* fat_bpb
))
535 #ifndef HAVE_MULTIVOLUME
536 struct bpb
* fat_bpb
= &fat_bpbs
[0];
538 if(fat_bpb
->bpb_bytspersec
!= 512)
540 DEBUGF( "bpb_is_sane() - Error: sector size is not 512 (%d)\n",
541 fat_bpb
->bpb_bytspersec
);
544 if(fat_bpb
->bpb_secperclus
* fat_bpb
->bpb_bytspersec
> 128*1024)
546 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
548 fat_bpb
->bpb_bytspersec
, fat_bpb
->bpb_secperclus
,
549 fat_bpb
->bpb_bytspersec
* fat_bpb
->bpb_secperclus
);
552 if(fat_bpb
->bpb_numfats
!= 2)
554 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
555 fat_bpb
->bpb_numfats
);
557 if(fat_bpb
->bpb_media
!= 0xf0 && fat_bpb
->bpb_media
< 0xf8)
559 DEBUGF( "bpb_is_sane() - Warning: Non-standard "
560 "media type (0x%02x)\n",
563 if(fat_bpb
->last_word
!= 0xaa55)
565 DEBUGF( "bpb_is_sane() - Error: Last word is not "
566 "0xaa55 (0x%04x)\n", fat_bpb
->last_word
);
570 if (fat_bpb
->fsinfo
.freecount
>
571 (fat_bpb
->totalsectors
- fat_bpb
->firstdatasector
)/
572 fat_bpb
->bpb_secperclus
)
574 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
575 "(0x%04x)\n", fat_bpb
->fsinfo
.freecount
);
582 static void flush_fat_sector(struct fat_cache_entry
*fce
,
583 unsigned char *sectorbuf
)
588 /* With multivolume, use only the FAT info from the cached sector! */
589 #ifdef HAVE_MULTIVOLUME
590 secnum
= fce
->secnum
+ fce
->fat_vol
->startsector
;
592 secnum
= fce
->secnum
+ fat_bpbs
[0].startsector
;
595 /* Write to the first FAT */
596 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
601 panicf("flush_fat_sector() - Could not write sector %d"
605 #ifdef HAVE_MULTIVOLUME
606 if(fce
->fat_vol
->bpb_numfats
> 1)
608 if(fat_bpbs
[0].bpb_numfats
> 1)
611 /* Write to the second FAT */
612 #ifdef HAVE_MULTIVOLUME
613 secnum
+= fce
->fat_vol
->fatsize
;
615 secnum
+= fat_bpbs
[0].fatsize
;
617 rc
= ata_write_sectors(IF_MV2(fce
->fat_vol
->drive
,)
618 secnum
, 1, sectorbuf
);
621 panicf("flush_fat_sector() - Could not write sector %d"
629 /* Note: The returned pointer is only safely valid until the next
630 task switch! (Any subsequent ata read/write may yield.) */
631 static void *cache_fat_sector(IF_MV2(struct bpb
* fat_bpb
,)
632 int fatsector
, bool dirty
)
634 #ifndef HAVE_MULTIVOLUME
635 struct bpb
* fat_bpb
= &fat_bpbs
[0];
637 int secnum
= fatsector
+ fat_bpb
->bpb_rsvdseccnt
;
638 int cache_index
= secnum
& FAT_CACHE_MASK
;
639 struct fat_cache_entry
*fce
= &fat_cache
[cache_index
];
640 unsigned char *sectorbuf
= &fat_cache_sectors
[cache_index
][0];
643 mutex_lock(&cache_mutex
); /* make changes atomic */
645 /* Delete the cache entry if it isn't the sector we want */
646 if(fce
->inuse
&& (fce
->secnum
!= secnum
647 #ifdef HAVE_MULTIVOLUME
648 || fce
->fat_vol
!= fat_bpb
652 /* Write back if it is dirty */
655 flush_fat_sector(fce
, sectorbuf
);
660 /* Load the sector if it is not cached */
663 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
664 secnum
+ fat_bpb
->startsector
,1,
668 DEBUGF( "cache_fat_sector() - Could not read sector %d"
669 " (error %d)\n", secnum
, rc
);
670 mutex_unlock(&cache_mutex
);
674 fce
->secnum
= secnum
;
675 #ifdef HAVE_MULTIVOLUME
676 fce
->fat_vol
= fat_bpb
;
680 fce
->dirty
= true; /* dirt remains, sticky until flushed */
681 mutex_unlock(&cache_mutex
);
685 static unsigned int find_free_cluster(IF_MV2(struct bpb
* fat_bpb
,) unsigned int startcluster
)
687 #ifndef HAVE_MULTIVOLUME
688 struct bpb
* fat_bpb
= &fat_bpbs
[0];
694 #ifdef HAVE_FAT16SUPPORT
695 if (fat_bpb
->is_fat16
)
697 sector
= startcluster
/ CLUSTERS_PER_FAT16_SECTOR
;
698 offset
= startcluster
% CLUSTERS_PER_FAT16_SECTOR
;
700 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
702 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
703 unsigned short* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
706 for (j
= 0; j
< CLUSTERS_PER_FAT16_SECTOR
; j
++) {
707 int k
= (j
+ offset
) % CLUSTERS_PER_FAT16_SECTOR
;
708 if (SWAB16(fat
[k
]) == 0x0000) {
709 unsigned int c
= nr
* CLUSTERS_PER_FAT16_SECTOR
+ k
;
710 /* Ignore the reserved clusters 0 & 1, and also
711 cluster numbers out of bounds */
712 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
714 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
715 fat_bpb
->fsinfo
.nextfree
= c
;
723 #endif /* #ifdef HAVE_FAT16SUPPORT */
725 sector
= startcluster
/ CLUSTERS_PER_FAT_SECTOR
;
726 offset
= startcluster
% CLUSTERS_PER_FAT_SECTOR
;
728 for (i
= 0; i
<fat_bpb
->fatsize
; i
++) {
730 unsigned int nr
= (i
+ sector
) % fat_bpb
->fatsize
;
731 unsigned int* fat
= cache_fat_sector(IF_MV2(fat_bpb
,) nr
, false);
734 for (j
= 0; j
< CLUSTERS_PER_FAT_SECTOR
; j
++) {
735 int k
= (j
+ offset
) % CLUSTERS_PER_FAT_SECTOR
;
736 if (!(SWAB32(fat
[k
]) & 0x0fffffff)) {
737 unsigned int c
= nr
* CLUSTERS_PER_FAT_SECTOR
+ k
;
738 /* Ignore the reserved clusters 0 & 1, and also
739 cluster numbers out of bounds */
740 if ( c
< 2 || c
> fat_bpb
->dataclusters
+1 )
742 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster
,c
);
743 fat_bpb
->fsinfo
.nextfree
= c
;
751 LDEBUGF("find_free_cluster(%x) == 0\n",startcluster
);
752 return 0; /* 0 is an illegal cluster number */
755 static int update_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned int entry
, unsigned int val
)
757 #ifndef HAVE_MULTIVOLUME
758 struct bpb
* fat_bpb
= &fat_bpbs
[0];
760 #ifdef HAVE_FAT16SUPPORT
761 if (fat_bpb
->is_fat16
)
763 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
764 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
769 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
772 panicf("Creating FAT loop: %x,%x\n",entry
,val
);
775 panicf("Updating reserved FAT entry %d.\n",entry
);
777 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
780 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
785 if (SWAB16(sec
[offset
]) == 0x0000 && fat_bpb
->fsinfo
.freecount
> 0)
786 fat_bpb
->fsinfo
.freecount
--;
789 if (SWAB16(sec
[offset
]))
790 fat_bpb
->fsinfo
.freecount
++;
793 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb
->fsinfo
.freecount
);
795 sec
[offset
] = SWAB16(val
);
798 #endif /* #ifdef HAVE_FAT16SUPPORT */
800 int sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
801 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
804 LDEBUGF("update_fat_entry(%x,%x)\n",entry
,val
);
807 panicf("Creating FAT loop: %x,%x\n",entry
,val
);
810 panicf("Updating reserved FAT entry %d.\n",entry
);
812 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, true);
815 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector
);
820 if (!(SWAB32(sec
[offset
]) & 0x0fffffff) &&
821 fat_bpb
->fsinfo
.freecount
> 0)
822 fat_bpb
->fsinfo
.freecount
--;
825 if (SWAB32(sec
[offset
]) & 0x0fffffff)
826 fat_bpb
->fsinfo
.freecount
++;
829 LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb
->fsinfo
.freecount
);
831 /* don't change top 4 bits */
832 sec
[offset
] &= SWAB32(0xf0000000);
833 sec
[offset
] |= SWAB32(val
& 0x0fffffff);
839 static int read_fat_entry(IF_MV2(struct bpb
* fat_bpb
,) unsigned int entry
)
841 #ifdef HAVE_FAT16SUPPORT
842 #ifndef HAVE_MULTIVOLUME
843 struct bpb
* fat_bpb
= &fat_bpbs
[0];
845 if (fat_bpb
->is_fat16
)
847 int sector
= entry
/ CLUSTERS_PER_FAT16_SECTOR
;
848 int offset
= entry
% CLUSTERS_PER_FAT16_SECTOR
;
851 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
854 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
858 return SWAB16(sec
[offset
]);
861 #endif /* #ifdef HAVE_FAT16SUPPORT */
863 int sector
= entry
/ CLUSTERS_PER_FAT_SECTOR
;
864 int offset
= entry
% CLUSTERS_PER_FAT_SECTOR
;
867 sec
= cache_fat_sector(IF_MV2(fat_bpb
,) sector
, false);
870 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector
);
874 return SWAB32(sec
[offset
]) & 0x0fffffff;
878 static int get_next_cluster(IF_MV2(struct bpb
* fat_bpb
,) int cluster
)
881 int eof_mark
= FAT_EOF_MARK
;
883 #ifdef HAVE_FAT16SUPPORT
884 #ifndef HAVE_MULTIVOLUME
885 struct bpb
* fat_bpb
= &fat_bpbs
[0];
887 if (fat_bpb
->is_fat16
)
889 eof_mark
&= 0xFFFF; /* only 16 bit */
890 if (cluster
< 0) /* FAT16 root dir */
891 return cluster
+ 1; /* don't use the FAT */
894 next_cluster
= read_fat_entry(IF_MV2(fat_bpb
,) cluster
);
896 /* is this last cluster in chain? */
897 if ( next_cluster
>= eof_mark
)
903 static int update_fsinfo(IF_MV_NONVOID(struct bpb
* fat_bpb
))
905 #ifndef HAVE_MULTIVOLUME
906 struct bpb
* fat_bpb
= &fat_bpbs
[0];
908 unsigned char fsinfo
[SECTOR_SIZE
];
909 unsigned int* intptr
;
912 #ifdef HAVE_FAT16SUPPORT
913 if (fat_bpb
->is_fat16
)
914 return 0; /* FAT16 has no FsInfo */
915 #endif /* #ifdef HAVE_FAT16SUPPORT */
918 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
919 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
, 1,fsinfo
);
922 DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc
);
925 intptr
= (int*)&(fsinfo
[FSINFO_FREECOUNT
]);
926 *intptr
= SWAB32(fat_bpb
->fsinfo
.freecount
);
928 intptr
= (int*)&(fsinfo
[FSINFO_NEXTFREE
]);
929 *intptr
= SWAB32(fat_bpb
->fsinfo
.nextfree
);
931 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
932 fat_bpb
->startsector
+ fat_bpb
->bpb_fsinfo
,1,fsinfo
);
935 DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc
);
942 static int flush_fat(IF_MV_NONVOID(struct bpb
* fat_bpb
))
947 LDEBUGF("flush_fat()\n");
949 for(i
= 0;i
< FAT_CACHE_SIZE
;i
++)
951 struct fat_cache_entry
*fce
= &fat_cache
[i
];
952 if(fce
->inuse
&& fce
->dirty
)
954 sec
= fat_cache_sectors
[i
];
955 flush_fat_sector(fce
, sec
);
959 rc
= update_fsinfo(IF_MV(fat_bpb
));
966 static void fat_time(unsigned short* date
,
967 unsigned short* time
,
968 unsigned short* tenth
)
971 struct tm
* tm
= get_time();
974 *date
= ((tm
->tm_year
- 80) << 9) |
975 ((tm
->tm_mon
+ 1) << 5) |
979 *time
= (tm
->tm_hour
<< 11) |
984 *tenth
= (tm
->tm_sec
& 1) * 100;
986 /* non-RTC version returns an increment from the supplied time, or a
987 * fixed standard time/date if no time given as input */
988 bool next_day
= false;
994 /* set to 00:15:00 */
999 unsigned short mins
= (*time
>> 5) & 0x003F;
1000 unsigned short hours
= (*time
>> 11) & 0x001F;
1001 if ((mins
+= 10) >= 60)
1006 if ((++hours
) >= 24)
1011 *time
= (hours
<< 11) | (mins
<< 5);
1019 /* set to 1 August 2003 */
1020 *date
= ((2003 - 1980) << 9) | (8 << 5) | 1;
1024 unsigned short day
= *date
& 0x001F;
1025 unsigned short month
= (*date
>> 5) & 0x000F;
1026 unsigned short year
= (*date
>> 9) & 0x007F;
1029 /* do a very simple day increment - never go above 28 days */
1039 *date
= (year
<< 9) | (month
<< 5) | day
;
1045 #endif /* HAVE_RTC */
1048 static int write_long_name(struct fat_file
* file
,
1049 unsigned int firstentry
,
1050 unsigned int numentries
,
1051 const unsigned char* name
,
1052 const unsigned char* shortname
,
1055 unsigned char buf
[SECTOR_SIZE
];
1056 unsigned char* entry
;
1057 unsigned int idx
= firstentry
% DIR_ENTRIES_PER_SECTOR
;
1058 unsigned int sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1059 unsigned int i
, j
=0;
1060 unsigned char chksum
= 0;
1061 int nameidx
=0, namelen
= strlen(name
);
1064 LDEBUGF("write_long_name(file:%x, first:%d, num:%d, name:%s)\n",
1065 file
->firstcluster
, firstentry
, numentries
, name
);
1067 rc
= fat_seek(file
, sector
);
1071 rc
= fat_readwrite(file
, 1, buf
, false);
1075 /* calculate shortname checksum */
1076 for (i
=11; i
>0; i
--)
1077 chksum
= ((chksum
& 1) ? 0x80 : 0) + (chksum
>> 1) + shortname
[j
++];
1079 /* calc position of last name segment */
1080 if ( namelen
> NAME_BYTES_PER_ENTRY
)
1082 nameidx
< (namelen
- NAME_BYTES_PER_ENTRY
);
1083 nameidx
+= NAME_BYTES_PER_ENTRY
);
1085 for (i
=0; i
< numentries
; i
++) {
1087 if ( idx
>= DIR_ENTRIES_PER_SECTOR
) {
1088 /* update current sector */
1089 rc
= fat_seek(file
, sector
);
1093 rc
= fat_readwrite(file
, 1, buf
, true);
1097 /* read next sector */
1098 rc
= fat_readwrite(file
, 1, buf
, false);
1100 LDEBUGF("Failed writing new sector: %d\n",rc
);
1105 memset(buf
, 0, sizeof buf
);
1111 entry
= buf
+ idx
* DIR_ENTRY_SIZE
;
1113 /* verify this entry is free */
1114 if (entry
[0] && entry
[0] != 0xe5 )
1115 panicf("Dir entry %d in sector %x is not free! "
1116 "%02x %02x %02x %02x",
1118 entry
[0], entry
[1], entry
[2], entry
[3]);
1120 memset(entry
, 0, DIR_ENTRY_SIZE
);
1121 if ( i
+1 < numentries
) {
1122 /* longname entry */
1125 entry
[FATLONG_ORDER
] = numentries
-i
-1;
1127 /* mark this as last long entry */
1128 entry
[FATLONG_ORDER
] |= 0x40;
1130 /* pad name with 0xffff */
1131 for (k
=1; k
<12; k
++) entry
[k
] = 0xff;
1132 for (k
=14; k
<26; k
++) entry
[k
] = 0xff;
1133 for (k
=28; k
<32; k
++) entry
[k
] = 0xff;
1136 for (k
=0; k
<5 && l
<= namelen
; k
++) {
1137 entry
[k
*2 + 1] = name
[l
++];
1140 for (k
=0; k
<6 && l
<= namelen
; k
++) {
1141 entry
[k
*2 + 14] = name
[l
++];
1142 entry
[k
*2 + 15] = 0;
1144 for (k
=0; k
<2 && l
<= namelen
; k
++) {
1145 entry
[k
*2 + 28] = name
[l
++];
1146 entry
[k
*2 + 29] = 0;
1149 entry
[FATDIR_ATTR
] = FAT_ATTR_LONG_NAME
;
1150 entry
[FATDIR_FSTCLUSLO
] = 0;
1151 entry
[FATLONG_TYPE
] = 0;
1152 entry
[FATLONG_CHKSUM
] = chksum
;
1153 LDEBUGF("Longname entry %d: %.13s\n", idx
, name
+nameidx
);
1156 /* shortname entry */
1157 unsigned short date
=0, time
=0, tenth
=0;
1158 LDEBUGF("Shortname entry: %.13s\n", shortname
);
1159 strncpy(entry
+ FATDIR_NAME
, shortname
, 11);
1160 entry
[FATDIR_ATTR
] = is_directory
?FAT_ATTR_DIRECTORY
:0;
1161 entry
[FATDIR_NTRES
] = 0;
1163 fat_time(&date
, &time
, &tenth
);
1164 entry
[FATDIR_CRTTIMETENTH
] = tenth
;
1165 *(unsigned short*)(entry
+ FATDIR_CRTTIME
) = SWAB16(time
);
1166 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = SWAB16(time
);
1167 *(unsigned short*)(entry
+ FATDIR_CRTDATE
) = SWAB16(date
);
1168 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = SWAB16(date
);
1169 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = SWAB16(date
);
1172 nameidx
-= NAME_BYTES_PER_ENTRY
;
1175 /* update last sector */
1176 rc
= fat_seek(file
, sector
);
1180 rc
= fat_readwrite(file
, 1, buf
, true);
1187 static int add_dir_entry(struct fat_dir
* dir
,
1188 struct fat_file
* file
,
1193 #ifdef HAVE_MULTIVOLUME
1194 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1196 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1198 unsigned char buf
[SECTOR_SIZE
];
1199 unsigned char shortname
[16];
1201 unsigned int sector
;
1205 int entries_needed
, entries_found
= 0;
1206 int namelen
= strlen(name
);
1209 LDEBUGF( "add_dir_entry(%s,%x)\n",
1210 name
, file
->firstcluster
);
1212 #ifdef HAVE_MULTIVOLUME
1213 file
->volume
= dir
->file
.volume
; /* inherit the volume, to make sure */
1216 /* The "." and ".." directory entries must not be long names */
1219 strncpy(shortname
, name
, 16);
1220 for(i
= strlen(shortname
);i
< 12;i
++)
1225 /* create dos name */
1226 rc
= create_dos_name(name
, shortname
);
1230 /* one dir entry needed for every 13 bytes of filename,
1231 plus one entry for the short name */
1232 entries_needed
= namelen
/ NAME_BYTES_PER_ENTRY
+ 1;
1233 if (namelen
% NAME_BYTES_PER_ENTRY
)
1240 rc
= fat_seek(&dir
->file
, 0);
1244 for (sector
=0; !done
; sector
++)
1250 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1253 /* eof: add new sector */
1256 memset(buf
, 0, sizeof buf
);
1257 LDEBUGF("Adding new sector to dir\n");
1258 rc
= fat_seek(&dir
->file
, sector
);
1262 /* add sectors (we must clear the whole cluster) */
1264 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1267 } while (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
);
1270 DEBUGF( "add_dir_entry() - Couldn't read dir"
1271 " (error code %d)\n", rc
);
1275 /* look for free slots */
1276 for (i
=0; i
< DIR_ENTRIES_PER_SECTOR
&& !done
; i
++)
1278 unsigned char firstbyte
= buf
[i
* DIR_ENTRY_SIZE
];
1279 switch (firstbyte
) {
1280 case 0: /* end of dir */
1281 entries_found
= entries_needed
;
1282 LDEBUGF("Found last entry %d\n",
1283 sector
* DIR_ENTRIES_PER_SECTOR
+ i
);
1287 case 0xe5: /* free entry */
1289 LDEBUGF("Found free entry %d (%d/%d)\n",
1290 sector
* DIR_ENTRIES_PER_SECTOR
+ i
,
1291 entries_found
, entries_needed
);
1297 /* check that our intended shortname doesn't already exist */
1298 if (!strncmp(shortname
, buf
+ i
* DIR_ENTRY_SIZE
, 12)) {
1299 /* filename exists already. make a new one */
1300 snprintf(shortname
+8, 4, "%03X", (unsigned)rand() & 0xfff);
1301 LDEBUGF("Duplicate shortname, changing to %s\n",
1304 /* name has changed, we need to restart search */
1310 if (!firstentry
&& (entries_found
== entries_needed
)) {
1311 firstentry
= sector
* DIR_ENTRIES_PER_SECTOR
+ i
;
1313 /* if we're not extending the dir,
1314 we must go back to first free entry */
1318 firstentry
-= (entries_needed
- 1);
1323 sector
= firstentry
/ DIR_ENTRIES_PER_SECTOR
;
1324 LDEBUGF("Adding longname to entry %d in sector %d\n",
1325 firstentry
, sector
);
1327 rc
= write_long_name(&dir
->file
, firstentry
,
1328 entries_needed
, name
, shortname
, is_directory
);
1332 /* remember where the shortname dir entry is located */
1333 file
->direntry
= firstentry
+ entries_needed
- 1;
1334 file
->direntries
= entries_needed
;
1335 file
->dircluster
= dir
->file
.firstcluster
;
1336 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1337 file
->direntry
, file
->direntries
);
1339 /* advance the end-of-dir marker? */
1342 unsigned int lastentry
= firstentry
+ entries_needed
;
1344 LDEBUGF("Updating end-of-dir entry %d\n",lastentry
);
1346 if (lastentry
% DIR_ENTRIES_PER_SECTOR
)
1348 int idx
= (lastentry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
;
1350 rc
= fat_seek(&dir
->file
, lastentry
/ DIR_ENTRIES_PER_SECTOR
);
1354 rc
= fat_readwrite(&dir
->file
, 1, buf
, false);
1358 /* clear last entry */
1361 rc
= fat_seek(&dir
->file
, lastentry
/ DIR_ENTRIES_PER_SECTOR
);
1365 /* we must clear entire last cluster */
1367 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1370 memset(buf
, 0, sizeof buf
);
1371 } while (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
);
1375 /* add a new sector/cluster for last entry */
1376 memset(buf
, 0, sizeof buf
);
1378 rc
= fat_readwrite(&dir
->file
, 1, buf
, true);
1380 return rc
* 10 - 9; /* Same error code as above, can't be
1382 } while (dir
->file
.sectornum
< (int)fat_bpb
->bpb_secperclus
);
1389 unsigned char char2dos(unsigned char c
)
1393 case 0xe5: /* Special kanji character */
1427 static int create_dos_name(const unsigned char *name
, unsigned char *newname
)
1432 for (i
=0, j
=0; name
[i
] && (j
< 8); i
++)
1434 unsigned char c
= char2dos(name
[i
]);
1436 newname
[j
++] = toupper(c
);
1441 /* Extension part */
1442 snprintf(newname
+8, 4, "%03X", (unsigned)rand() & 0xfff);
1447 static int update_short_entry( struct fat_file
* file
, int size
, int attr
)
1449 unsigned char buf
[SECTOR_SIZE
];
1450 int sector
= file
->direntry
/ DIR_ENTRIES_PER_SECTOR
;
1451 unsigned char* entry
=
1452 buf
+ DIR_ENTRY_SIZE
* (file
->direntry
% DIR_ENTRIES_PER_SECTOR
);
1453 unsigned int* sizeptr
;
1454 unsigned short* clusptr
;
1455 struct fat_file dir
;
1458 LDEBUGF("update_file_size(cluster:%x entry:%d size:%d)\n",
1459 file
->firstcluster
, file
->direntry
, size
);
1461 /* create a temporary file handle for the dir holding this file */
1462 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1466 rc
= fat_seek( &dir
, sector
);
1470 rc
= fat_readwrite(&dir
, 1, buf
, false);
1474 if (!entry
[0] || entry
[0] == 0xe5)
1475 panicf("Updating size on empty dir entry %d\n", file
->direntry
);
1477 entry
[FATDIR_ATTR
] = attr
& 0xFF;
1479 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSHI
);
1480 *clusptr
= SWAB16(file
->firstcluster
>> 16);
1482 clusptr
= (short*)(entry
+ FATDIR_FSTCLUSLO
);
1483 *clusptr
= SWAB16(file
->firstcluster
& 0xffff);
1485 sizeptr
= (int*)(entry
+ FATDIR_FILESIZE
);
1486 *sizeptr
= SWAB32(size
);
1490 unsigned short time
= 0;
1491 unsigned short date
= 0;
1493 /* get old time to increment from */
1494 unsigned short time
= SWAB16(*(unsigned short*)(entry
+ FATDIR_WRTTIME
));
1495 unsigned short date
= SWAB16(*(unsigned short*)(entry
+ FATDIR_WRTDATE
));
1497 fat_time(&date
, &time
, NULL
);
1498 *(unsigned short*)(entry
+ FATDIR_WRTTIME
) = SWAB16(time
);
1499 *(unsigned short*)(entry
+ FATDIR_WRTDATE
) = SWAB16(date
);
1500 *(unsigned short*)(entry
+ FATDIR_LSTACCDATE
) = SWAB16(date
);
1503 rc
= fat_seek( &dir
, sector
);
1507 rc
= fat_readwrite(&dir
, 1, buf
, true);
1514 static int parse_direntry(struct fat_direntry
*de
, const unsigned char *buf
)
1517 memset(de
, 0, sizeof(struct fat_direntry
));
1518 de
->attr
= buf
[FATDIR_ATTR
];
1519 de
->crttimetenth
= buf
[FATDIR_CRTTIMETENTH
];
1520 de
->crtdate
= BYTES2INT16(buf
,FATDIR_CRTDATE
);
1521 de
->crttime
= BYTES2INT16(buf
,FATDIR_CRTTIME
);
1522 de
->wrtdate
= BYTES2INT16(buf
,FATDIR_WRTDATE
);
1523 de
->wrttime
= BYTES2INT16(buf
,FATDIR_WRTTIME
);
1524 de
->filesize
= BYTES2INT32(buf
,FATDIR_FILESIZE
);
1525 de
->firstcluster
= BYTES2INT16(buf
,FATDIR_FSTCLUSLO
) |
1526 (BYTES2INT16(buf
,FATDIR_FSTCLUSHI
) << 16);
1529 for (i
=0; (i
<8) && (buf
[FATDIR_NAME
+i
] != ' '); i
++)
1530 de
->name
[j
++] = buf
[FATDIR_NAME
+i
];
1531 if ( buf
[FATDIR_NAME
+8] != ' ' ) {
1532 de
->name
[j
++] = '.';
1533 for (i
=8; (i
<11) && (buf
[FATDIR_NAME
+i
] != ' '); i
++)
1534 de
->name
[j
++] = buf
[FATDIR_NAME
+i
];
1539 int fat_open(IF_MV2(int volume
,)
1541 struct fat_file
*file
,
1542 const struct fat_dir
* dir
)
1544 file
->firstcluster
= startcluster
;
1545 file
->lastcluster
= startcluster
;
1546 file
->lastsector
= 0;
1547 file
->clusternum
= 0;
1548 file
->sectornum
= 0;
1550 #ifdef HAVE_MULTIVOLUME
1551 file
->volume
= volume
;
1552 /* fixme: remove error check when done */
1553 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
1555 LDEBUGF("fat_open() illegal volume %d\n", volume
);
1560 /* remember where the file's dir entry is located */
1562 file
->direntry
= dir
->entry
- 1;
1563 file
->direntries
= dir
->entrycount
;
1564 file
->dircluster
= dir
->file
.firstcluster
;
1566 LDEBUGF("fat_open(%x), entry %d\n",startcluster
,file
->direntry
);
1570 int fat_create_file(const char* name
,
1571 struct fat_file
* file
,
1572 struct fat_dir
* dir
)
1576 LDEBUGF("fat_create_file(\"%s\",%x,%x)\n",name
,file
,dir
);
1577 rc
= add_dir_entry(dir
, file
, name
, false, false);
1579 file
->firstcluster
= 0;
1580 file
->lastcluster
= 0;
1581 file
->lastsector
= 0;
1582 file
->clusternum
= 0;
1583 file
->sectornum
= 0;
1590 int fat_create_dir(const char* name
,
1591 struct fat_dir
* newdir
,
1592 struct fat_dir
* dir
)
1594 #ifdef HAVE_MULTIVOLUME
1595 struct bpb
* fat_bpb
= &fat_bpbs
[dir
->file
.volume
];
1597 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1599 unsigned char buf
[SECTOR_SIZE
];
1603 struct fat_file dummyfile
;
1605 LDEBUGF("fat_create_dir(\"%s\",%x,%x)\n",name
,newdir
,dir
);
1607 memset(newdir
, 0, sizeof(struct fat_dir
));
1608 memset(&dummyfile
, 0, sizeof(struct fat_file
));
1610 /* First, add the entry in the parent directory */
1611 rc
= add_dir_entry(dir
, &newdir
->file
, name
, true, false);
1615 /* Allocate a new cluster for the directory */
1616 newdir
->file
.firstcluster
= find_free_cluster(IF_MV2(fat_bpb
,) fat_bpb
->fsinfo
.nextfree
);
1617 if(newdir
->file
.firstcluster
== 0)
1620 update_fat_entry(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
, FAT_EOF_MARK
);
1622 /* Clear the entire cluster */
1623 memset(buf
, 0, sizeof buf
);
1624 sector
= cluster2sec(IF_MV2(fat_bpb
,) newdir
->file
.firstcluster
);
1625 for(i
= 0;i
< (int)fat_bpb
->bpb_secperclus
;i
++) {
1626 rc
= transfer(IF_MV2(fat_bpb
,) sector
+ i
, 1, buf
, true );
1631 /* Then add the "." entry */
1632 rc
= add_dir_entry(newdir
, &dummyfile
, ".", true, true);
1635 dummyfile
.firstcluster
= newdir
->file
.firstcluster
;
1636 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1638 /* and the ".." entry */
1639 rc
= add_dir_entry(newdir
, &dummyfile
, "..", true, true);
1643 /* The root cluster is cluster 0 in the ".." entry */
1644 if(dir
->file
.firstcluster
== fat_bpb
->bpb_rootclus
)
1645 dummyfile
.firstcluster
= 0;
1647 dummyfile
.firstcluster
= dir
->file
.firstcluster
;
1648 update_short_entry(&dummyfile
, 0, FAT_ATTR_DIRECTORY
);
1650 /* Set the firstcluster field in the direntry */
1651 update_short_entry(&newdir
->file
, 0, FAT_ATTR_DIRECTORY
);
1653 rc
= flush_fat(IF_MV(fat_bpb
));
1660 int fat_truncate(const struct fat_file
*file
)
1662 /* truncate trailing clusters */
1664 int last
= file
->lastcluster
;
1665 #ifdef HAVE_MULTIVOLUME
1666 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1669 LDEBUGF("fat_truncate(%x, %x)\n", file
->firstcluster
, last
);
1671 for ( last
= get_next_cluster(IF_MV2(fat_bpb
,) last
); last
; last
= next
) {
1672 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1673 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1675 if (file
->lastcluster
)
1676 update_fat_entry(IF_MV2(fat_bpb
,) file
->lastcluster
,FAT_EOF_MARK
);
1681 int fat_closewrite(struct fat_file
*file
, int size
, int attr
)
1684 #ifdef HAVE_MULTIVOLUME
1685 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1687 LDEBUGF("fat_closewrite(size=%d)\n",size
);
1691 if ( file
->firstcluster
) {
1692 update_fat_entry(IF_MV2(fat_bpb
,) file
->firstcluster
, 0);
1693 file
->firstcluster
= 0;
1697 if (file
->dircluster
) {
1698 rc
= update_short_entry(file
, size
, attr
);
1703 flush_fat(IF_MV(fat_bpb
));
1706 if ( file
->firstcluster
) {
1708 #ifdef HAVE_MULTIVOLUME
1709 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1711 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1716 for ( next
= file
->firstcluster
; next
;
1717 next
= get_next_cluster(IF_MV2(fat_bpb
,) next
) )
1718 LDEBUGF("cluster %d: %x\n", count
++, next
);
1719 len
= count
* fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
1720 LDEBUGF("File is %d clusters (chainlen=%d, size=%d)\n",
1722 if ( len
> size
+ fat_bpb
->bpb_secperclus
* SECTOR_SIZE
)
1723 panicf("Cluster chain is too long\n");
1725 panicf("Cluster chain is too short\n");
1732 static int free_direntries(struct fat_file
* file
)
1734 unsigned char buf
[SECTOR_SIZE
];
1735 struct fat_file dir
;
1736 int numentries
= file
->direntries
;
1737 unsigned int entry
= file
->direntry
- numentries
+ 1;
1738 unsigned int sector
= entry
/ DIR_ENTRIES_PER_SECTOR
;
1742 /* create a temporary file handle for the dir holding this file */
1743 rc
= fat_open(IF_MV2(file
->volume
,) file
->dircluster
, &dir
, NULL
);
1747 rc
= fat_seek( &dir
, sector
);
1751 rc
= fat_readwrite(&dir
, 1, buf
, false);
1755 for (i
=0; i
< numentries
; i
++) {
1756 LDEBUGF("Clearing dir entry %d (%d/%d)\n",
1757 entry
, i
+1, numentries
);
1758 buf
[(entry
% DIR_ENTRIES_PER_SECTOR
) * DIR_ENTRY_SIZE
] = 0xe5;
1761 if ( (entry
% DIR_ENTRIES_PER_SECTOR
) == 0 ) {
1762 /* flush this sector */
1763 rc
= fat_seek(&dir
, sector
);
1767 rc
= fat_readwrite(&dir
, 1, buf
, true);
1771 if ( i
+1 < numentries
) {
1772 /* read next sector */
1773 rc
= fat_readwrite(&dir
, 1, buf
, false);
1781 if ( entry
% DIR_ENTRIES_PER_SECTOR
) {
1782 /* flush this sector */
1783 rc
= fat_seek(&dir
, sector
);
1787 rc
= fat_readwrite(&dir
, 1, buf
, true);
1795 int fat_remove(struct fat_file
* file
)
1797 int next
, last
= file
->firstcluster
;
1799 #ifdef HAVE_MULTIVOLUME
1800 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1803 LDEBUGF("fat_remove(%x)\n",last
);
1806 next
= get_next_cluster(IF_MV2(fat_bpb
,) last
);
1807 update_fat_entry(IF_MV2(fat_bpb
,) last
,0);
1811 if ( file
->dircluster
) {
1812 rc
= free_direntries(file
);
1817 file
->firstcluster
= 0;
1818 file
->dircluster
= 0;
1820 rc
= flush_fat(IF_MV(fat_bpb
));
1827 int fat_rename(struct fat_file
* file
,
1828 struct fat_dir
* dir
,
1829 const unsigned char* newname
,
1834 struct fat_dir olddir
;
1835 struct fat_file newfile
= *file
;
1836 #ifdef HAVE_MULTIVOLUME
1837 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1839 if (file
->volume
!= dir
->file
.volume
) {
1840 DEBUGF("No rename across volumes!\n");
1845 if ( !file
->dircluster
) {
1846 DEBUGF("File has no dir cluster!\n");
1850 /* create a temporary file handle */
1851 rc
= fat_opendir(IF_MV2(file
->volume
,) &olddir
, file
->dircluster
, NULL
);
1855 /* create new name */
1856 rc
= add_dir_entry(dir
, &newfile
, newname
, false, false);
1860 /* write size and cluster link */
1861 rc
= update_short_entry(&newfile
, size
, attr
);
1865 /* remove old name */
1866 rc
= free_direntries(file
);
1870 rc
= flush_fat(IF_MV(fat_bpb
));
1877 static int next_write_cluster(struct fat_file
* file
,
1881 #ifdef HAVE_MULTIVOLUME
1882 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1884 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1889 LDEBUGF("next_write_cluster(%x,%x)\n",file
->firstcluster
, oldcluster
);
1892 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) oldcluster
);
1896 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) oldcluster
+1);
1897 else if (oldcluster
== 0)
1898 cluster
= find_free_cluster(IF_MV2(fat_bpb
,) fat_bpb
->fsinfo
.nextfree
);
1899 #ifdef HAVE_FAT16SUPPORT
1900 else /* negative, pseudo-cluster of the root dir */
1901 return 0; /* impossible to append something to the root */
1906 update_fat_entry(IF_MV2(fat_bpb
,) oldcluster
, cluster
);
1908 file
->firstcluster
= cluster
;
1909 update_fat_entry(IF_MV2(fat_bpb
,) cluster
, FAT_EOF_MARK
);
1913 if (fat_bpb
->fsinfo
.freecount
>0)
1914 panicf("There is free space, but find_free_cluster() "
1915 "didn't find it!\n");
1917 DEBUGF("next_write_cluster(): Disk full!\n");
1921 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
1925 *newsector
= sector
;
1929 static int transfer(IF_MV2(struct bpb
* fat_bpb
,)
1930 unsigned int start
, int count
, char* buf
, bool write
)
1932 #ifndef HAVE_MULTIVOLUME
1933 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1937 LDEBUGF("transfer(s=%x, c=%x, %s)\n",
1938 start
+ fat_bpb
->startsector
, count
, write
?"write":"read");
1940 unsigned int firstallowed
;
1941 #ifdef HAVE_FAT16SUPPORT
1942 if (fat_bpb
->is_fat16
)
1943 firstallowed
= fat_bpb
->rootdirsector
;
1946 firstallowed
= fat_bpb
->firstdatasector
;
1948 if (start
< firstallowed
)
1949 panicf("Write %d before data\n", firstallowed
- start
);
1950 if (start
+ count
> fat_bpb
->totalsectors
)
1951 panicf("Write %d after data\n",
1952 start
+ count
- fat_bpb
->totalsectors
);
1953 rc
= ata_write_sectors(IF_MV2(fat_bpb
->drive
,)
1954 start
+ fat_bpb
->startsector
, count
, buf
);
1957 rc
= ata_read_sectors(IF_MV2(fat_bpb
->drive
,)
1958 start
+ fat_bpb
->startsector
, count
, buf
);
1960 DEBUGF( "transfer() - Couldn't %s sector %x"
1961 " (error code %d)\n",
1962 write
? "write":"read", start
, rc
);
1969 int fat_readwrite( struct fat_file
*file
, int sectorcount
,
1970 void* buf
, bool write
)
1972 #ifdef HAVE_MULTIVOLUME
1973 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
1975 struct bpb
* fat_bpb
= &fat_bpbs
[0];
1977 int cluster
= file
->lastcluster
;
1978 int sector
= file
->lastsector
;
1979 int clusternum
= file
->clusternum
;
1980 int numsec
= file
->sectornum
;
1981 bool eof
= file
->eof
;
1982 int first
=0, last
=0;
1986 LDEBUGF( "fat_readwrite(file:%x,count:0x%x,buf:%x,%s)\n",
1987 file
->firstcluster
,sectorcount
,buf
,write
?"write":"read");
1988 LDEBUGF( "fat_readwrite: sec=%x numsec=%d eof=%d\n",
1989 sector
,numsec
, eof
?1:0);
1994 /* find sequential sectors and write them all at once */
1995 for (i
=0; (i
< sectorcount
) && (sector
> -1); i
++ ) {
1997 if ( numsec
> (int)fat_bpb
->bpb_secperclus
|| !cluster
) {
1998 int oldcluster
= cluster
;
2000 cluster
= next_write_cluster(file
, cluster
, §or
);
2002 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2003 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
);
2012 /* remember last cluster, in case
2013 we want to append to the file */
2014 cluster
= oldcluster
;
2016 i
= -1; /* Error code */
2027 /* look up first sector of file */
2028 sector
= cluster2sec(IF_MV2(fat_bpb
,) file
->firstcluster
);
2030 #ifdef HAVE_FAT16SUPPORT
2031 if (file
->firstcluster
< 0)
2032 { /* FAT16 root dir */
2033 sector
+= fat_bpb
->rootdiroffset
;
2034 numsec
+= fat_bpb
->rootdiroffset
;
2043 if ( ((sector
!= first
) && (sector
!= last
+1)) || /* not sequential */
2044 (last
-first
+1 == 256) ) { /* max 256 sectors per ata request */
2045 int count
= last
- first
+ 1;
2046 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2050 buf
= (char *)buf
+ count
* SECTOR_SIZE
;
2054 if ((i
== sectorcount
-1) && /* last sector requested */
2057 int count
= sector
- first
+ 1;
2058 rc
= transfer(IF_MV2(fat_bpb
,) first
, count
, buf
, write
);
2066 file
->lastcluster
= cluster
;
2067 file
->lastsector
= sector
;
2068 file
->clusternum
= clusternum
;
2069 file
->sectornum
= numsec
;
2072 /* if eof, don't report last block as read/written */
2076 DEBUGF("Sectors written: %d\n", i
);
2080 int fat_seek(struct fat_file
*file
, unsigned int seeksector
)
2082 #ifdef HAVE_MULTIVOLUME
2083 struct bpb
* fat_bpb
= &fat_bpbs
[file
->volume
];
2085 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2087 int clusternum
=0, numclusters
=0, sectornum
=0, sector
=0;
2088 int cluster
= file
->firstcluster
;
2091 #ifdef HAVE_FAT16SUPPORT
2092 if (cluster
< 0) /* FAT16 root dir */
2093 seeksector
+= fat_bpb
->rootdiroffset
;
2098 /* we need to find the sector BEFORE the requested, since
2099 the file struct stores the last accessed sector */
2101 numclusters
= clusternum
= seeksector
/ fat_bpb
->bpb_secperclus
;
2102 sectornum
= seeksector
% fat_bpb
->bpb_secperclus
;
2104 if (file
->clusternum
&& clusternum
>= file
->clusternum
)
2106 cluster
= file
->lastcluster
;
2107 numclusters
-= file
->clusternum
;
2110 for (i
=0; i
<numclusters
; i
++) {
2111 cluster
= get_next_cluster(IF_MV2(fat_bpb
,) cluster
);
2113 DEBUGF("Seeking beyond the end of the file! "
2114 "(sector %d, cluster %d)\n", seeksector
, i
);
2119 sector
= cluster2sec(IF_MV2(fat_bpb
,) cluster
) + sectornum
;
2125 LDEBUGF("fat_seek(%x, %x) == %x, %x, %x\n",
2126 file
->firstcluster
, seeksector
, cluster
, sector
, sectornum
);
2128 file
->lastcluster
= cluster
;
2129 file
->lastsector
= sector
;
2130 file
->clusternum
= clusternum
;
2131 file
->sectornum
= sectornum
+ 1;
2135 int fat_opendir(IF_MV2(int volume
,)
2136 struct fat_dir
*dir
, unsigned int startcluster
,
2137 const struct fat_dir
*parent_dir
)
2139 #ifdef HAVE_MULTIVOLUME
2140 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2141 /* fixme: remove error check when done */
2142 if (volume
>= NUM_VOLUMES
|| !fat_bpbs
[volume
].mounted
)
2144 LDEBUGF("fat_open() illegal volume %d\n", volume
);
2148 struct bpb
* fat_bpb
= &fat_bpbs
[0];
2155 if (startcluster
== 0)
2156 startcluster
= fat_bpb
->bpb_rootclus
;
2158 rc
= fat_open(IF_MV2(volume
,) startcluster
, &dir
->file
, parent_dir
);
2161 DEBUGF( "fat_opendir() - Couldn't open dir"
2162 " (error code %d)\n", rc
);
2169 /* convert from unicode to a single-byte charset */
2170 static void unicode2iso(const unsigned char* unicode
, unsigned char* iso
,
2175 for (i
=0; i
<count
; i
++) {
2177 switch (unicode
[x
+1]) {
2178 case 0x01: /* latin extended. convert to ISO 8859-2 */
2180 iso
[i
] = unicode2iso8859_2
[unicode
[x
]];
2183 case 0x03: /* greek, convert to ISO 8859-7 */
2184 iso
[i
] = unicode
[x
] + 0x30;
2187 /* Sergei says most russians use Win1251, so we will too.
2188 Win1251 differs from ISO 8859-5 by an offset of 0x10. */
2189 case 0x04: /* cyrillic, convert to Win1251 */
2190 switch (unicode
[x
]) {
2200 iso
[i
] = unicode
[x
] + 0xb0; /* 0xa0 for ISO 8859-5 */
2205 case 0x05: /* hebrew, convert to ISO 8859-8 */
2206 iso
[i
] = unicode
[x
] + 0x10;
2209 case 0x06: /* arabic, convert to ISO 8859-6 */
2210 case 0x0e: /* thai, convert to ISO 8859-11 */
2211 iso
[i
] = unicode
[x
] + 0xa0;
2215 iso
[i
] = unicode
[x
];
2221 int fat_getnext(struct fat_dir
*dir
, struct fat_direntry
*entry
)
2226 unsigned char firstbyte
;
2230 unsigned char* cached_buf
= dir
->sectorcache
[0];
2232 dir
->entrycount
= 0;
2236 if ( !(dir
->entry
% DIR_ENTRIES_PER_SECTOR
) || !dir
->sector
)
2238 rc
= fat_readwrite(&dir
->file
, 1, cached_buf
, false);
2245 DEBUGF( "fat_getnext() - Couldn't read dir"
2246 " (error code %d)\n", rc
);
2249 dir
->sector
= dir
->file
.lastsector
;
2252 for (i
= dir
->entry
% DIR_ENTRIES_PER_SECTOR
;
2253 i
< DIR_ENTRIES_PER_SECTOR
; i
++)
2255 unsigned int entrypos
= i
* DIR_ENTRY_SIZE
;
2257 firstbyte
= cached_buf
[entrypos
];
2260 if (firstbyte
== 0xe5) {
2263 dir
->entrycount
= 0;
2267 if (firstbyte
== 0) {
2270 dir
->entrycount
= 0;
2276 /* longname entry? */
2277 if ( ( cached_buf
[entrypos
+ FATDIR_ATTR
] &
2278 FAT_ATTR_LONG_NAME_MASK
) == FAT_ATTR_LONG_NAME
) {
2279 longarray
[longs
++] = entrypos
+ sectoridx
;
2282 if ( parse_direntry(entry
,
2283 &cached_buf
[entrypos
]) ) {
2285 /* don't return volume id entry */
2286 if ( entry
->attr
== FAT_ATTR_VOLUME_ID
)
2289 /* replace shortname with longname? */
2292 /* iterate backwards through the dir entries */
2293 for (j
=longs
-1; j
>=0; j
--) {
2294 unsigned char* ptr
= cached_buf
;
2295 int index
= longarray
[j
];
2296 /* current or cached sector? */
2297 if ( sectoridx
>= SECTOR_SIZE
) {
2298 if ( sectoridx
>= SECTOR_SIZE
*2 ) {
2299 if ( ( index
>= SECTOR_SIZE
) &&
2300 ( index
< SECTOR_SIZE
*2 ))
2301 ptr
= dir
->sectorcache
[1];
2303 ptr
= dir
->sectorcache
[2];
2306 if ( index
< SECTOR_SIZE
)
2307 ptr
= dir
->sectorcache
[1];
2310 index
&= SECTOR_SIZE
-1;
2313 /* names are stored in unicode, but we
2314 only grab the low byte (iso8859-1). */
2315 unicode2iso(ptr
+ index
+ 1, entry
->name
+ l
, 5);
2317 unicode2iso(ptr
+ index
+ 14, entry
->name
+ l
, 6);
2319 unicode2iso(ptr
+ index
+ 28, entry
->name
+ l
, 2);
2332 /* save this sector, for longname use */
2334 memcpy( dir
->sectorcache
[2], dir
->sectorcache
[0], SECTOR_SIZE
);
2336 memcpy( dir
->sectorcache
[1], dir
->sectorcache
[0], SECTOR_SIZE
);
2337 sectoridx
+= SECTOR_SIZE
;
2343 int fat_get_cluster_size(IF_MV_NONVOID(int volume
))
2345 #ifndef HAVE_MULTIVOLUME
2346 const int volume
= 0;
2348 struct bpb
* fat_bpb
= &fat_bpbs
[volume
];
2349 return fat_bpb
->bpb_secperclus
* SECTOR_SIZE
;
2352 #ifdef HAVE_MULTIVOLUME
2353 bool fat_ismounted(int volume
)
2355 return (volume
<NUM_VOLUMES
&& fat_bpbs
[volume
].mounted
);