freemyipod r211 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r210‎ | r211 | r212 >
Date:22:20, 8 September 2010
Author:theseven
Status:new
Tags:
Comment:
Get rid of some leftover on-stack sector buffers
Modified paths:
  • /embios/trunk/dir.c (modified) (history)
  • /embios/trunk/fat.c (modified) (history)
  • /embios/trunk/fat.h (modified) (history)
  • /embios/trunk/target/ipodnano2g/ftl.c (modified) (history)

Diff [purge]

Index: embios/trunk/target/ipodnano2g/ftl.c
@@ -2565,19 +2565,19 @@
25662566 ftl_initialized = true;
25672567 return 0;
25682568 }
2569 - cprintf(CONSOLE_BOOT, "The FTL seems to be damaged. Forcing check.\n");
 2569+ cputs(CONSOLE_BOOT, "The FTL seems to be damaged. Forcing check.\n");
25702570 if (ftl_repair() != 0)
2571 - cprintf(CONSOLE_BOOT, "FTL recovery failed. Use disk mode to recover.\n");
 2571+ cputs(CONSOLE_BOOT, "FTL recovery failed. Use disk mode to recover.\n");
25722572 else
25732573 {
2574 - cprintf(CONSOLE_BOOT, "FTL recovery finished. Trying to mount again...\n");
 2574+ cputs(CONSOLE_BOOT, "FTL recovery finished. Trying to mount again...\n");
25752575 if (ftl_open() == 0)
25762576 {
2577 - cprintf(CONSOLE_BOOT, "Mount succeeded.\n");
 2577+ cputs(CONSOLE_BOOT, "Mount succeeded.\n");
25782578 ftl_initialized = true;
25792579 return 0;
25802580 }
2581 - cprintf(CONSOLE_BOOT, "Mounting FTL failed again, use disk mode to recover.\n");
 2581+ cputs(CONSOLE_BOOT, "Mounting FTL failed again, use disk mode to recover.\n");
25822582 }
25832583 }
25842584
Index: embios/trunk/fat.c
@@ -1,2578 +1,2561 @@
2 -/***************************************************************************
3 - * __________ __ ___.
4 - * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 - * \/ \/ \/ \/ \/
9 - * $Id: fat.c 25459 2010-04-03 22:02:09Z gevaerts $
10 - *
11 - * Copyright (C) 2002 by Linus Nielsen Feltzing
12 - *
13 - * This program is free software; you can redistribute it and/or
14 - * modify it under the terms of the GNU General Public License
15 - * as published by the Free Software Foundation; either version 2
16 - * of the License, or (at your option) any later version.
17 - *
18 - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 - * KIND, either express or implied.
20 - *
21 - ****************************************************************************/
22 -#include "global.h"
23 -#include "thread.h"
24 -#include "libc/include/string.h"
25 -#include "libc/include/stdio.h"
26 -#include "fat.h"
27 -#include "storage.h"
28 -#include "debug.h"
29 -#include "panic.h"
30 -#include "libc/include/ctype.h"
31 -
32 -#define BYTES2INT16(array,pos) \
33 - (array[pos] | (array[pos+1] << 8 ))
34 -#define BYTES2INT32(array,pos) \
35 - ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
36 - ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
37 -
38 -#define FATTYPE_FAT12 0
39 -#define FATTYPE_FAT16 1
40 -#define FATTYPE_FAT32 2
41 -
42 -/* BPB offsets; generic */
43 -#define BS_JMPBOOT 0
44 -#define BS_OEMNAME 3
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
51 -#define BPB_MEDIA 21
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
57 -
58 -/* fat12/16 */
59 -#define BS_DRVNUM 36
60 -#define BS_RESERVED1 37
61 -#define BS_BOOTSIG 38
62 -#define BS_VOLID 39
63 -#define BS_VOLLAB 43
64 -#define BS_FILSYSTYPE 54
65 -
66 -/* fat32 */
67 -#define BPB_FATSZ32 36
68 -#define BPB_EXTFLAGS 40
69 -#define BPB_FSVER 42
70 -#define BPB_ROOTCLUS 44
71 -#define BPB_FSINFO 48
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
78 -
79 -#define BPB_LAST_WORD 510
80 -
81 -
82 -/* attributes */
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 )
88 -
89 -/* NTRES flags */
90 -#define FAT_NTRES_LC_NAME 0x08
91 -#define FAT_NTRES_LC_EXT 0x10
92 -
93 -#define FATDIR_NAME 0
94 -#define FATDIR_ATTR 11
95 -#define FATDIR_NTRES 12
96 -#define FATDIR_CRTTIMETENTH 13
97 -#define FATDIR_CRTTIME 14
98 -#define FATDIR_CRTDATE 16
99 -#define FATDIR_LSTACCDATE 18
100 -#define FATDIR_FSTCLUSHI 20
101 -#define FATDIR_WRTTIME 22
102 -#define FATDIR_WRTDATE 24
103 -#define FATDIR_FSTCLUSLO 26
104 -#define FATDIR_FILESIZE 28
105 -
106 -#define FATLONG_ORDER 0
107 -#define FATLONG_TYPE 12
108 -#define FATLONG_CHKSUM 13
109 -#define FATLONG_LAST_LONG_ENTRY 0x40
110 -#define FATLONG_NAME_BYTES_PER_ENTRY 26
111 -/* at most 20 LFN entries, keep coherent with fat_dir->longname size ! */
112 -#define FATLONG_MAX_ORDER 20
113 -
114 -#define FATLONG_NAME_CHUNKS 3
115 -static unsigned char FATLONG_NAME_POS[FATLONG_NAME_CHUNKS] = {1, 14, 28};
116 -static unsigned char FATLONG_NAME_SIZE[FATLONG_NAME_CHUNKS] = {10, 12, 4};
117 -
118 -#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
119 -#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
120 -#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
121 -#define DIR_ENTRY_SIZE 32
122 -#define NAME_BYTES_PER_ENTRY 13
123 -#define FAT_BAD_MARK 0x0ffffff7
124 -#define FAT_EOF_MARK 0x0ffffff8
125 -#define FAT_LONGNAME_PAD_BYTE 0xff
126 -#define FAT_LONGNAME_PAD_UCS 0xffff
127 -
128 -struct fsinfo {
129 - unsigned long freecount; /* last known free cluster count */
130 - unsigned long nextfree; /* first cluster to start looking for free
131 - clusters, or 0xffffffff for no hint */
132 -};
133 -/* fsinfo offsets */
134 -#define FSINFO_FREECOUNT 488
135 -#define FSINFO_NEXTFREE 492
136 -
137 -/* Note: This struct doesn't hold the raw values after mounting if
138 - * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
139 - * physical sectors. */
140 -struct bpb
141 -{
142 - int bpb_bytspersec; /* Bytes per sector, typically 512 */
143 - unsigned int bpb_secperclus; /* Sectors per cluster */
144 - int bpb_rsvdseccnt; /* Number of reserved sectors */
145 - int bpb_numfats; /* Number of FAT structures, typically 2 */
146 - int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
147 - int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
148 - int bpb_fatsz16; /* Number of used sectors per FAT structure */
149 - unsigned long bpb_totsec32; /* Number of sectors on the volume
150 - (new 32-bit) */
151 - unsigned int last_word; /* 0xAA55 */
152 -
153 - /**** FAT32 specific *****/
154 - long bpb_fatsz32;
155 - long bpb_rootclus;
156 - long bpb_fsinfo;
157 -
158 - /* variables for internal use */
159 - unsigned long fatsize;
160 - unsigned long totalsectors;
161 - unsigned long rootdirsector;
162 - unsigned long firstdatasector;
163 - unsigned long startsector;
164 - unsigned long dataclusters;
165 - struct fsinfo fsinfo;
166 -#ifdef HAVE_FAT16SUPPORT
167 - int bpb_rootentcnt; /* Number of dir entries in the root */
168 - /* internals for FAT16 support */
169 - bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
170 - unsigned int rootdiroffset; /* sector offset of root dir relative to start
171 - * of first pseudo cluster */
172 -#endif /* #ifdef HAVE_FAT16SUPPORT */
173 -#ifdef HAVE_MULTIVOLUME
174 -#ifdef HAVE_MULTIDRIVE
175 - int drive; /* on which physical device is this located */
176 -#endif
177 - bool mounted; /* flag if this volume is mounted */
178 -#endif
179 -};
180 -
181 -static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
182 -static bool initialized = false;
183 -
184 -static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
185 -static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
186 -static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
187 -static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
188 - long secnum, bool dirty);
189 -static void unlock_fat_sector(IF_MV2(struct bpb* fat_bpb,)
190 - long secnum);
191 -static void create_dos_name(const unsigned char *name, unsigned char *newname);
192 -static void randomize_dos_name(unsigned char *name);
193 -static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
194 - unsigned long start);
195 -static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
196 - long count, char* buf, bool write );
197 -
198 -#define FAT_CACHE_SIZE 4
199 -#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
200 -
201 -struct fat_cache_entry
202 -{
203 - long secnum;
204 - bool valid;
205 - int locked;
206 - bool dirty;
207 -#ifdef HAVE_MULTIVOLUME
208 - struct bpb* fat_vol; /* shared cache for all volumes */
209 -#endif
210 -};
211 -
212 -static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE] CACHEALIGN_ATTR;
213 -static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
214 -static struct mutex cache_mutex;
215 -static struct mutex tempbuf_mutex;
216 -static char fat_tempbuf[SECTOR_SIZE] CACHEALIGN_ATTR;
217 -static bool tempbuf_locked;
218 -
219 -#if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
220 -void fat_lock(void)
221 -{
222 - mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
223 -}
224 -
225 -void fat_unlock(void)
226 -{
227 - mutex_unlock(&cache_mutex);
228 -}
229 -#endif
230 -
231 -static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
232 -{
233 -#ifndef HAVE_MULTIVOLUME
234 - struct bpb* fat_bpb = &fat_bpbs[0];
235 -#endif
236 -#ifdef HAVE_FAT16SUPPORT
237 - /* negative clusters (FAT16 root dir) don't get the 2 offset */
238 - int zerocluster = cluster < 0 ? 0 : 2;
239 -#else
240 - const long zerocluster = 2;
241 -#endif
242 -
243 - if (cluster > (long)(fat_bpb->dataclusters + 1))
244 - {
245 - DEBUGF( "cluster2sec() - Bad cluster number (%ld)", cluster);
246 - return -1;
247 - }
248 -
249 - return (cluster - zerocluster) * fat_bpb->bpb_secperclus
250 - + fat_bpb->firstdatasector;
251 -}
252 -
253 -void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
254 -{
255 -#ifndef HAVE_MULTIVOLUME
256 - const int volume = 0;
257 -#endif
258 - struct bpb* fat_bpb = &fat_bpbs[volume];
259 - if (size)
260 - *size = fat_bpb->dataclusters * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
261 - if (free)
262 - *free = fat_bpb->fsinfo.freecount * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
263 -}
264 -
265 -void fat_init(void)
266 -{
267 - unsigned int i;
268 -
269 - if (!initialized)
270 - {
271 - initialized = true;
272 - mutex_init(&cache_mutex);
273 - mutex_init(&tempbuf_mutex);
274 - tempbuf_locked = false;
275 - }
276 -
277 - /* mark the FAT cache as unused */
278 - for(i = 0;i < FAT_CACHE_SIZE;i++)
279 - {
280 - fat_cache[i].secnum = -1;
281 - fat_cache[i].valid = false;
282 - fat_cache[i].locked = 0;
283 - fat_cache[i].dirty = false;
284 -#ifdef HAVE_MULTIVOLUME
285 - fat_cache[i].fat_vol = NULL;
286 -#endif
287 - }
288 -#ifdef HAVE_MULTIVOLUME
289 - /* mark the possible volumes as not mounted */
290 - for (i=0; i<NUM_VOLUMES;i++)
291 - {
292 - fat_bpbs[i].mounted = false;
293 - }
294 -#endif
295 -}
296 -
297 -int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
298 -{
299 -#ifndef HAVE_MULTIVOLUME
300 - const int volume = 0;
301 -#endif
302 - struct bpb* fat_bpb = &fat_bpbs[volume];
303 - int rc;
304 - int secmult;
305 - long datasec;
306 -#ifdef HAVE_FAT16SUPPORT
307 - int rootdirsectors;
308 -#endif
309 -
310 - /* Read the sector */
311 - unsigned char* buf = fat_get_sector_buffer();
312 - rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
313 - if(rc)
314 - {
315 - fat_release_sector_buffer();
316 - DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)", rc);
317 - return rc * 10 - 1;
318 - }
319 -
320 - memset(fat_bpb, 0, sizeof(struct bpb));
321 - fat_bpb->startsector = startsector;
322 -#ifdef HAVE_MULTIDRIVE
323 - fat_bpb->drive = drive;
324 -#endif
325 -
326 - fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
327 - secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
328 - /* Sanity check is performed later */
329 -
330 - fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
331 - fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
332 - fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
333 - fat_bpb->bpb_media = buf[BPB_MEDIA];
334 - fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
335 - fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
336 - fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
337 - fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
338 - fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
339 -
340 - /* calculate a few commonly used values */
341 - if (fat_bpb->bpb_fatsz16 != 0)
342 - fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
343 - else
344 - fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
345 -
346 - if (fat_bpb->bpb_totsec16 != 0)
347 - fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
348 - else
349 - fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
350 -
351 -#ifdef HAVE_FAT16SUPPORT
352 - fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
353 - if (!fat_bpb->bpb_bytspersec)
354 - {
355 - fat_release_sector_buffer();
356 - return -2;
357 - }
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 */
361 -
362 - fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
363 -#ifdef HAVE_FAT16SUPPORT
364 - + rootdirsectors
365 -#endif
366 - + fat_bpb->bpb_numfats * fat_bpb->fatsize;
367 -
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;
372 - else
373 - {
374 - fat_release_sector_buffer();
375 - return -2;
376 - }
377 -
378 -#ifdef TEST_FAT
379 - /*
380 - we are sometimes testing with "illegally small" fat32 images,
381 - so we don't use the proper fat32 test case for test code
382 - */
383 - if ( fat_bpb->bpb_fatsz16 )
384 -#else
385 - if ( fat_bpb->dataclusters < 65525 )
386 -#endif
387 - { /* FAT16 */
388 -#ifdef HAVE_FAT16SUPPORT
389 - fat_bpb->is_fat16 = true;
390 - if (fat_bpb->dataclusters < 4085)
391 - { /* FAT12 */
392 - fat_release_sector_buffer();
393 - DEBUGF("This is FAT12. Go away!");
394 - return -2;
395 - }
396 -#else /* #ifdef HAVE_FAT16SUPPORT */
397 - fat_release_sector_buffer();
398 - DEBUGF("This is not FAT32. Go away!");
399 - return -2;
400 -#endif /* #ifndef HAVE_FAT16SUPPORT */
401 - }
402 -
403 -#ifdef HAVE_FAT16SUPPORT
404 - if (fat_bpb->is_fat16)
405 - { /* FAT16 specific part of BPB */
406 - int dirclusters;
407 - fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
408 - + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
409 - dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
410 - / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
411 - /* I assign negative pseudo cluster numbers for the root directory,
412 - their range is counted upward until -1. */
413 - fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
414 - fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
415 - - rootdirsectors;
416 - }
417 - else
418 -#endif /* #ifdef HAVE_FAT16SUPPORT */
419 - { /* FAT32 specific part of BPB */
420 - fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
421 - fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
422 - fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
423 - fat_bpb->bpb_rootclus);
424 - }
425 -
426 - rc = bpb_is_sane(IF_MV(fat_bpb));
427 - if (rc < 0)
428 - {
429 - fat_release_sector_buffer();
430 - DEBUGF( "fat_mount() - BPB is not sane");
431 - return rc * 10 - 3;
432 - }
433 -
434 -#ifdef HAVE_FAT16SUPPORT
435 - if (fat_bpb->is_fat16)
436 - {
437 - fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
438 - fat_bpb->fsinfo.nextfree = 0xffffffff;
439 - }
440 - else
441 -#endif /* #ifdef HAVE_FAT16SUPPORT */
442 - {
443 - /* Read the fsinfo sector */
444 - rc = storage_read_sectors(IF_MD2(drive,)
445 - startsector + fat_bpb->bpb_fsinfo, 1, buf);
446 - if (rc < 0)
447 - {
448 - fat_release_sector_buffer();
449 - DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)", rc);
450 - return rc * 10 - 4;
451 - }
452 - fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
453 - fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
454 - }
455 - fat_release_sector_buffer();
456 -
457 - /* calculate freecount if unset */
458 - if ( fat_bpb->fsinfo.freecount == 0xffffffff )
459 - {
460 - fat_recalc_free(IF_MV(volume));
461 - }
462 -
463 - DEBUGF("Freecount: %ld",fat_bpb->fsinfo.freecount);
464 - DEBUGF("Nextfree: 0x%lx",fat_bpb->fsinfo.nextfree);
465 - DEBUGF("Cluster count: 0x%lx",fat_bpb->dataclusters);
466 - DEBUGF("Sectors per cluster: %d",fat_bpb->bpb_secperclus);
467 - DEBUGF("FAT sectors: 0x%lx",fat_bpb->fatsize);
468 -
469 -#ifdef HAVE_MULTIVOLUME
470 - fat_bpb->mounted = true;
471 -#endif
472 -
473 - return 0;
474 -}
475 -
476 -#ifdef HAVE_HOTSWAP
477 -int fat_unmount(int volume, bool flush)
478 -{
479 - int rc;
480 -#ifdef HAVE_MULTIVOLUME
481 - struct bpb* fat_bpb = &fat_bpbs[volume];
482 -#else
483 - (void)volume;
484 -#endif
485 -
486 - if(flush)
487 - {
488 - rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
489 - }
490 - else
491 - { /* volume is not accessible any more, e.g. MMC removed */
492 - int i;
493 - mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
494 - for(i = 0;i < FAT_CACHE_SIZE;i++)
495 - {
496 - struct fat_cache_entry *fce = &fat_cache[i];
497 - if((fce->valid || fce->locked)
498 -#ifdef HAVE_MULTIVOLUME
499 - && fce->fat_vol == fat_bpb
500 -#endif
501 - )
502 - {
503 - fce->valid = false; /* discard all from that volume */
504 - fce->locked = 0;
505 - fce->dirty = false;
506 - }
507 - }
508 - mutex_unlock(&cache_mutex);
509 - rc = 0;
510 - }
511 -#ifdef HAVE_MULTIVOLUME
512 - fat_bpb->mounted = false;
513 -#endif
514 - return rc;
515 -}
516 -#endif /* #ifdef HAVE_HOTSWAP */
517 -
518 -void fat_recalc_free(IF_MV_NONVOID(int volume))
519 -{
520 -#ifndef HAVE_MULTIVOLUME
521 - const int volume = 0;
522 -#endif
523 - struct bpb* fat_bpb = &fat_bpbs[volume];
524 - long free = 0;
525 - unsigned long i;
526 -#ifdef HAVE_FAT16SUPPORT
527 - if (fat_bpb->is_fat16)
528 - {
529 - for (i = 0; i<fat_bpb->fatsize; i++) {
530 - unsigned int j;
531 - unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
532 - for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
533 - unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
534 - if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
535 - break;
536 -
537 - if (letoh16(fat[j]) == 0x0000) {
538 - free++;
539 - if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
540 - fat_bpb->fsinfo.nextfree = c;
541 - }
542 - }
543 - unlock_fat_sector(IF_MV2(fat_bpb,) i);
544 - }
545 - }
546 - else
547 -#endif /* #ifdef HAVE_FAT16SUPPORT */
548 - {
549 - for (i = 0; i<fat_bpb->fatsize; i++) {
550 - unsigned int j;
551 - unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
552 - for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
553 - unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
554 - if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
555 - break;
556 -
557 - if (!(letoh32(fat[j]) & 0x0fffffff)) {
558 - free++;
559 - if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
560 - fat_bpb->fsinfo.nextfree = c;
561 - }
562 - }
563 - unlock_fat_sector(IF_MV2(fat_bpb,) i);
564 - }
565 - }
566 - fat_bpb->fsinfo.freecount = free;
567 - update_fsinfo(IF_MV(fat_bpb));
568 -}
569 -
570 -static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
571 -{
572 -#ifndef HAVE_MULTIVOLUME
573 - struct bpb* fat_bpb = &fat_bpbs[0];
574 -#endif
575 - if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
576 - {
577 - DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)",
578 - fat_bpb->bpb_bytspersec);
579 - return -1;
580 - }
581 - if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
582 - > 128L*1024L)
583 - {
584 - DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
585 - "(%d * %d = %d)",
586 - fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
587 - fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
588 - return -2;
589 - }
590 - if(fat_bpb->bpb_numfats != 2)
591 - {
592 - DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)",
593 - fat_bpb->bpb_numfats);
594 - }
595 - if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
596 - {
597 - DEBUGF( "bpb_is_sane() - Warning: Non-standard "
598 - "media type (0x%02x)",
599 - fat_bpb->bpb_media);
600 - }
601 - if(fat_bpb->last_word != 0xaa55)
602 - {
603 - DEBUGF( "bpb_is_sane() - Error: Last word is not "
604 - "0xaa55 (0x%04x)", fat_bpb->last_word);
605 - return -3;
606 - }
607 -
608 - if (fat_bpb->fsinfo.freecount >
609 - (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
610 - fat_bpb->bpb_secperclus)
611 - {
612 - DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
613 - "(0x%04lx)", fat_bpb->fsinfo.freecount);
614 - return -4;
615 - }
616 -
617 - return 0;
618 -}
619 -
620 -static void flush_fat_sector(struct fat_cache_entry *fce,
621 - unsigned char *sectorbuf)
622 -{
623 - int rc;
624 - long secnum;
625 -
626 - /* With multivolume, use only the FAT info from the cached sector! */
627 -#ifdef HAVE_MULTIVOLUME
628 - secnum = fce->secnum + fce->fat_vol->startsector;
629 -#else
630 - secnum = fce->secnum + fat_bpbs[0].startsector;
631 -#endif
632 -
633 - /* Write to the first FAT */
634 - rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
635 - secnum, 1,
636 - sectorbuf);
637 - if(rc < 0)
638 - {
639 - panicf(PANIC_KILLUSERTHREADS, "flush_fat_sector() - Could not write sector %ld"
640 - " (error %d)",
641 - secnum, rc);
642 - }
643 -#ifdef HAVE_MULTIVOLUME
644 - if(fce->fat_vol->bpb_numfats > 1)
645 -#else
646 - if(fat_bpbs[0].bpb_numfats > 1)
647 -#endif
648 - {
649 - /* Write to the second FAT */
650 -#ifdef HAVE_MULTIVOLUME
651 - secnum += fce->fat_vol->fatsize;
652 -#else
653 - secnum += fat_bpbs[0].fatsize;
654 -#endif
655 - rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
656 - secnum, 1, sectorbuf);
657 - if(rc < 0)
658 - {
659 - panicf(PANIC_KILLUSERTHREADS, "flush_fat_sector() - Could not write sector %ld"
660 - " (error %d)",
661 - secnum, rc);
662 - }
663 - }
664 - fce->dirty = false;
665 -}
666 -
667 -static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
668 - long fatsector, bool dirty)
669 -{
670 -#ifndef HAVE_MULTIVOLUME
671 - struct bpb* fat_bpb = &fat_bpbs[0];
672 -#endif
673 - long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
674 - int cache_index = secnum & FAT_CACHE_MASK;
675 - struct fat_cache_entry *fce = &fat_cache[cache_index];
676 - unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
677 - int rc;
678 -
679 - mutex_lock(&cache_mutex, TIMEOUT_BLOCK); /* make changes atomic */
680 -
681 - /* Delete the cache entry if it isn't the sector we want */
682 - if(fce->valid && (fce->secnum != secnum
683 -#ifdef HAVE_MULTIVOLUME
684 - || fce->fat_vol != fat_bpb
685 -#endif
686 - ))
687 - {
688 - while (fce->locked) sleep(1000);
689 - /* Write back if it is dirty */
690 - if(fce->dirty)
691 - {
692 - flush_fat_sector(fce, sectorbuf);
693 - }
694 - fce->valid = false;
695 - }
696 -
697 - /* Load the sector if it is not cached */
698 - if(!fce->valid)
699 - {
700 - rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
701 - secnum + fat_bpb->startsector,1,
702 - sectorbuf);
703 - if(rc < 0)
704 - {
705 - DEBUGF( "cache_fat_sector() - Could not read sector %ld"
706 - " (error %d)", secnum, rc);
707 - mutex_unlock(&cache_mutex);
708 - return NULL;
709 - }
710 - fce->valid = true;
711 - fce->secnum = secnum;
712 -#ifdef HAVE_MULTIVOLUME
713 - fce->fat_vol = fat_bpb;
714 -#endif
715 - }
716 - fce->locked++;
717 - if (dirty)
718 - fce->dirty = true; /* dirt remains, sticky until flushed */
719 - mutex_unlock(&cache_mutex);
720 - return sectorbuf;
721 -}
722 -
723 -static void unlock_fat_sector(IF_MV2(struct bpb* fat_bpb,) long fatsector)
724 -{
725 -#ifndef HAVE_MULTIVOLUME
726 - struct bpb* fat_bpb = &fat_bpbs[0];
727 -#endif
728 - long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
729 - int cache_index = secnum & FAT_CACHE_MASK;
730 - fat_cache[cache_index].locked--;
731 -}
732 -
733 -void* fat_get_sector_buffer()
734 -{
735 - mutex_lock(&tempbuf_mutex, TIMEOUT_BLOCK);
736 - if (tempbuf_locked)
737 - panicf(PANIC_KILLUSERTHREADS, "FAT: Tried to lock temporary sector buffer twice!");
738 - tempbuf_locked = true;
739 - return fat_tempbuf;
740 -}
741 -
742 -void fat_release_sector_buffer()
743 -{
744 - tempbuf_locked = false;
745 - mutex_unlock(&tempbuf_mutex);
746 -}
747 -
748 -static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
749 - unsigned long startcluster)
750 -{
751 -#ifndef HAVE_MULTIVOLUME
752 - struct bpb* fat_bpb = &fat_bpbs[0];
753 -#endif
754 - unsigned long sector;
755 - unsigned long offset;
756 - unsigned long i;
757 -
758 -#ifdef HAVE_FAT16SUPPORT
759 - if (fat_bpb->is_fat16)
760 - {
761 - sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
762 - offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
763 -
764 - for (i = 0; i<fat_bpb->fatsize; i++) {
765 - unsigned int j;
766 - unsigned int nr = (i + sector) % fat_bpb->fatsize;
767 - unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
768 - if ( !fat )
769 - break;
770 - for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
771 - int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
772 - if (letoh16(fat[k]) == 0x0000) {
773 - unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
774 - /* Ignore the reserved clusters 0 & 1, and also
775 - cluster numbers out of bounds */
776 - if ( c < 2 || c > fat_bpb->dataclusters+1 )
777 - continue;
778 - unlock_fat_sector(IF_MV2(fat_bpb,) nr);
779 - DEBUGF("find_free_cluster(%x) == %x",startcluster,c);
780 - fat_bpb->fsinfo.nextfree = c;
781 - return c;
782 - }
783 - }
784 - unlock_fat_sector(IF_MV2(fat_bpb,) nr);
785 - offset = 0;
786 - }
787 - }
788 - else
789 -#endif /* #ifdef HAVE_FAT16SUPPORT */
790 - {
791 - sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
792 - offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
793 -
794 - for (i = 0; i<fat_bpb->fatsize; i++) {
795 - unsigned int j;
796 - unsigned long nr = (i + sector) % fat_bpb->fatsize;
797 - unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
798 - if ( !fat )
799 - break;
800 - for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
801 - int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
802 - if (!(letoh32(fat[k]) & 0x0fffffff)) {
803 - unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
804 - /* Ignore the reserved clusters 0 & 1, and also
805 - cluster numbers out of bounds */
806 - if ( c < 2 || c > fat_bpb->dataclusters+1 )
807 - continue;
808 - unlock_fat_sector(IF_MV2(fat_bpb,) nr);
809 - DEBUGF("find_free_cluster(%lx) == %lx",startcluster,c);
810 - fat_bpb->fsinfo.nextfree = c;
811 - return c;
812 - }
813 - }
814 - unlock_fat_sector(IF_MV2(fat_bpb,) nr);
815 - offset = 0;
816 - }
817 - }
818 -
819 - DEBUGF("find_free_cluster(%lx) == 0",startcluster);
820 - return 0; /* 0 is an illegal cluster number */
821 -}
822 -
823 -static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
824 - unsigned long val)
825 -{
826 -#ifndef HAVE_MULTIVOLUME
827 - struct bpb* fat_bpb = &fat_bpbs[0];
828 -#endif
829 -#ifdef HAVE_FAT16SUPPORT
830 - if (fat_bpb->is_fat16)
831 - {
832 - int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
833 - int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
834 - unsigned short* sec;
835 -
836 - val &= 0xFFFF;
837 -
838 - DEBUGF("update_fat_entry(%x,%x)",entry,val);
839 -
840 - if (entry==val)
841 - panicf(PANIC_KILLUSERTHREADS, "Creating FAT loop: %lx,%lx",entry,val);
842 -
843 - if ( entry < 2 )
844 - panicf(PANIC_KILLUSERTHREADS, "Updating reserved FAT entry %ld.",entry);
845 -
846 - sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
847 - if (!sec)
848 - {
849 - DEBUGF( "update_fat_entry() - Could not cache sector %d", sector);
850 - return -1;
851 - }
852 -
853 - if ( val ) {
854 - if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
855 - fat_bpb->fsinfo.freecount--;
856 - }
857 - else {
858 - if (letoh16(sec[offset]))
859 - fat_bpb->fsinfo.freecount++;
860 - }
861 -
862 - DEBUGF("update_fat_entry: %d free clusters",
863 - fat_bpb->fsinfo.freecount);
864 -
865 - sec[offset] = htole16(val);
866 - unlock_fat_sector(IF_MV2(fat_bpb,) sector);
867 - }
868 - else
869 -#endif /* #ifdef HAVE_FAT16SUPPORT */
870 - {
871 - long sector = entry / CLUSTERS_PER_FAT_SECTOR;
872 - int offset = entry % CLUSTERS_PER_FAT_SECTOR;
873 - unsigned long* sec;
874 -
875 - DEBUGF("update_fat_entry(%lx,%lx)",entry,val);
876 -
877 - if (entry==val)
878 - panicf(PANIC_KILLUSERTHREADS, "Creating FAT loop: %lx,%lx",entry,val);
879 -
880 - if ( entry < 2 )
881 - panicf(PANIC_KILLUSERTHREADS, "Updating reserved FAT entry %ld.",entry);
882 -
883 - sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
884 - if (!sec)
885 - {
886 - DEBUGF("update_fat_entry() - Could not cache sector %ld", sector);
887 - return -1;
888 - }
889 -
890 - if ( val ) {
891 - if (!(letoh32(sec[offset]) & 0x0fffffff) &&
892 - fat_bpb->fsinfo.freecount > 0)
893 - fat_bpb->fsinfo.freecount--;
894 - }
895 - else {
896 - if (letoh32(sec[offset]) & 0x0fffffff)
897 - fat_bpb->fsinfo.freecount++;
898 - }
899 -
900 - DEBUGF("update_fat_entry: %ld free clusters",
901 - fat_bpb->fsinfo.freecount);
902 -
903 - /* don't change top 4 bits */
904 - sec[offset] &= htole32(0xf0000000);
905 - sec[offset] |= htole32(val & 0x0fffffff);
906 - unlock_fat_sector(IF_MV2(fat_bpb,) sector);
907 - }
908 -
909 - return 0;
910 -}
911 -
912 -static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
913 -{
914 -#ifdef HAVE_FAT16SUPPORT
915 -#ifndef HAVE_MULTIVOLUME
916 - struct bpb* fat_bpb = &fat_bpbs[0];
917 -#endif
918 - if (fat_bpb->is_fat16)
919 - {
920 - int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
921 - int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
922 - unsigned short* sec;
923 -
924 - sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
925 - if (!sec)
926 - {
927 - DEBUGF( "read_fat_entry() - Could not cache sector %d", sector);
928 - return -1;
929 - }
930 -
931 - long val = letoh16(sec[offset]);
932 - unlock_fat_sector(IF_MV2(fat_bpb,) sector);
933 -
934 - return val;
935 - }
936 - else
937 -#endif /* #ifdef HAVE_FAT16SUPPORT */
938 - {
939 - long sector = entry / CLUSTERS_PER_FAT_SECTOR;
940 - int offset = entry % CLUSTERS_PER_FAT_SECTOR;
941 - unsigned long* sec;
942 -
943 - sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
944 - if (!sec)
945 - {
946 - DEBUGF( "read_fat_entry() - Could not cache sector %ld", sector);
947 - return -1;
948 - }
949 -
950 - long val = letoh32(sec[offset]) & 0x0fffffff;
951 - unlock_fat_sector(IF_MV2(fat_bpb,) sector);
952 -
953 - return val;
954 - }
955 -}
956 -
957 -static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
958 -{
959 - long next_cluster;
960 - long eof_mark = FAT_EOF_MARK;
961 -
962 -#ifdef HAVE_FAT16SUPPORT
963 -#ifndef HAVE_MULTIVOLUME
964 - struct bpb* fat_bpb = &fat_bpbs[0];
965 -#endif
966 - if (fat_bpb->is_fat16)
967 - {
968 - eof_mark &= 0xFFFF; /* only 16 bit */
969 - if (cluster < 0) /* FAT16 root dir */
970 - return cluster + 1; /* don't use the FAT */
971 - }
972 -#endif
973 - next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
974 -
975 - /* is this last cluster in chain? */
976 - if ( next_cluster >= eof_mark )
977 - return 0;
978 - else
979 - return next_cluster;
980 -}
981 -
982 -static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
983 -{
984 -#ifndef HAVE_MULTIVOLUME
985 - struct bpb* fat_bpb = &fat_bpbs[0];
986 -#endif
987 - unsigned long* intptr;
988 - int rc;
989 -
990 -#ifdef HAVE_FAT16SUPPORT
991 - if (fat_bpb->is_fat16)
992 - return 0; /* FAT16 has no FsInfo */
993 -#endif /* #ifdef HAVE_FAT16SUPPORT */
994 -
995 - /* update fsinfo */
996 - unsigned char* fsinfo = fat_get_sector_buffer();
997 - rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
998 - fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
999 - if (rc < 0)
1000 - {
1001 - fat_release_sector_buffer();
1002 - DEBUGF( "update_fsinfo() - Couldn't read FSInfo (error code %d)", rc);
1003 - return rc * 10 - 1;
1004 - }
1005 - intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
1006 - *intptr = htole32(fat_bpb->fsinfo.freecount);
1007 -
1008 - intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
1009 - *intptr = htole32(fat_bpb->fsinfo.nextfree);
1010 -
1011 - rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
1012 - fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
1013 - fat_release_sector_buffer();
1014 - if (rc < 0)
1015 - {
1016 - DEBUGF( "update_fsinfo() - Couldn't write FSInfo (error code %d)", rc);
1017 - return rc * 10 - 2;
1018 - }
1019 -
1020 - return 0;
1021 -}
1022 -
1023 -static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
1024 -{
1025 - int i;
1026 - int rc;
1027 - unsigned char *sec;
1028 - DEBUGF("flush_fat()");
1029 -
1030 - mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
1031 - for(i = 0;i < FAT_CACHE_SIZE;i++)
1032 - {
1033 - struct fat_cache_entry *fce = &fat_cache[i];
1034 - if(fce->valid
1035 -#ifdef HAVE_MULTIVOLUME
1036 - && fce->fat_vol == fat_bpb
1037 -#endif
1038 - && fce->dirty)
1039 - {
1040 - sec = fat_cache_sectors[i];
1041 - flush_fat_sector(fce, sec);
1042 - }
1043 - }
1044 - mutex_unlock(&cache_mutex);
1045 -
1046 - rc = update_fsinfo(IF_MV(fat_bpb));
1047 - if (rc < 0)
1048 - return rc * 10 - 3;
1049 -
1050 - return 0;
1051 -}
1052 -
1053 -static void fat_time(unsigned short* date,
1054 - unsigned short* time,
1055 - unsigned short* tenth )
1056 -{
1057 -#if CONFIG_RTC
1058 - struct tm* tm = get_time();
1059 -
1060 - if (date)
1061 - *date = ((tm->tm_year - 80) << 9) |
1062 - ((tm->tm_mon + 1) << 5) |
1063 - tm->tm_mday;
1064 -
1065 - if (time)
1066 - *time = (tm->tm_hour << 11) |
1067 - (tm->tm_min << 5) |
1068 - (tm->tm_sec >> 1);
1069 -
1070 - if (tenth)
1071 - *tenth = (tm->tm_sec & 1) * 100;
1072 -#else
1073 -
1074 - if (date) *date = (1 << 5) | 1;
1075 - if (time) *time = 0;
1076 - if (tenth) *tenth = 0;
1077 -
1078 -#endif /* CONFIG_RTC */
1079 -}
1080 -
1081 -static int write_long_name(struct fat_file* file,
1082 - unsigned int firstentry,
1083 - unsigned int numentries,
1084 - const unsigned char* name,
1085 - const unsigned char* shortname,
1086 - bool is_directory)
1087 -{
1088 - unsigned char* entry;
1089 - unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1090 - unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1091 - unsigned char chksum = 0;
1092 - unsigned int i, j=0;
1093 - unsigned int nameidx=0, namelen = strlen(name);
1094 - int rc;
1095 - unsigned short name_utf16[namelen + 1];
1096 -
1097 - DEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)",
1098 - file->firstcluster, firstentry, numentries, name);
1099 -
1100 - rc = fat_seek(file, sector);
1101 - if (rc<0)
1102 - return rc * 10 - 1;
1103 -
1104 - unsigned char* buf = fat_get_sector_buffer();
1105 - rc = fat_readwrite(file, 1, buf, false);
1106 - if (rc<1)
1107 - {
1108 - fat_release_sector_buffer();
1109 - return rc * 10 - 2;
1110 - }
1111 -
1112 - /* calculate shortname checksum */
1113 - for (i=11; i>0; i--)
1114 - chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1115 -
1116 - /* calc position of last name segment */
1117 - if ( namelen > NAME_BYTES_PER_ENTRY )
1118 - for (nameidx=0;
1119 - nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1120 - nameidx += NAME_BYTES_PER_ENTRY);
1121 -
1122 - /* we need to convert the name first */
1123 - /* since it is written in reverse order */
1124 - for (i = 0; i <= namelen; i++)
1125 - name_utf16[i] = *(name++);
1126 -
1127 - for (i=0; i < numentries; i++) {
1128 - /* new sector? */
1129 - if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1130 - /* update current sector */
1131 - rc = fat_seek(file, sector);
1132 - if (rc<0)
1133 - {
1134 - fat_release_sector_buffer();
1135 - return rc * 10 - 3;
1136 - }
1137 -
1138 - rc = fat_readwrite(file, 1, buf, true);
1139 - if (rc<1)
1140 - {
1141 - fat_release_sector_buffer();
1142 - return rc * 10 - 4;
1143 - }
1144 -
1145 - /* read next sector */
1146 - rc = fat_readwrite(file, 1, buf, false);
1147 - if (rc<0) {
1148 - fat_release_sector_buffer();
1149 - DEBUGF("Failed writing new sector: %d",rc);
1150 - return rc * 10 - 5;
1151 - }
1152 - if (rc==0)
1153 - /* end of dir */
1154 - memset(buf, 0, SECTOR_SIZE);
1155 -
1156 - sector++;
1157 - idx = 0;
1158 - }
1159 -
1160 - entry = buf + idx * DIR_ENTRY_SIZE;
1161 -
1162 - /* verify this entry is free */
1163 - if (entry[0] && entry[0] != 0xe5 )
1164 - {
1165 - fat_release_sector_buffer();
1166 - panicf(PANIC_KILLUSERTHREADS, "Dir entry %d in sector %x is not free! "
1167 - "%02x %02x %02x %02x",
1168 - idx, sector,
1169 - entry[0], entry[1], entry[2], entry[3]);
1170 - }
1171 -
1172 - memset(entry, 0, DIR_ENTRY_SIZE);
1173 - if ( i+1 < numentries ) {
1174 - /* longname entry */
1175 - unsigned int k, l = nameidx;
1176 -
1177 - entry[FATLONG_ORDER] = numentries-i-1;
1178 - if (i==0) {
1179 - /* mark this as last long entry */
1180 - entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1181 -
1182 - /* pad name with 0xffff */
1183 - for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1184 - for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1185 - for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1186 - };
1187 - /* set name */
1188 - for (k=0; k<5 && l <= namelen; k++) {
1189 - entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1190 - entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1191 - }
1192 - for (k=0; k<6 && l <= namelen; k++) {
1193 - entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1194 - entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1195 - }
1196 - for (k=0; k<2 && l <= namelen; k++) {
1197 - entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1198 - entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1199 - }
1200 -
1201 - entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1202 - entry[FATDIR_FSTCLUSLO] = 0;
1203 - entry[FATLONG_TYPE] = 0;
1204 - entry[FATLONG_CHKSUM] = chksum;
1205 - DEBUGF("Longname entry %d (%d): %s", idx, nameidx, name+nameidx);
1206 - }
1207 - else {
1208 - /* shortname entry */
1209 - unsigned short date=0, time=0, tenth=0;
1210 - DEBUGF("Shortname entry: %s", shortname);
1211 - memcpy(entry + FATDIR_NAME, shortname, 11);
1212 - entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1213 - entry[FATDIR_NTRES] = 0;
1214 -
1215 - fat_time(&date, &time, &tenth);
1216 - entry[FATDIR_CRTTIMETENTH] = tenth;
1217 - *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1218 - *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1219 - *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1220 - *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1221 - *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1222 - }
1223 - idx++;
1224 - nameidx -= NAME_BYTES_PER_ENTRY;
1225 - }
1226 -
1227 - /* update last sector */
1228 - rc = fat_seek(file, sector);
1229 - if (rc<0)
1230 - {
1231 - fat_release_sector_buffer();
1232 - return rc * 10 - 6;
1233 - }
1234 -
1235 - rc = fat_readwrite(file, 1, buf, true);
1236 - fat_release_sector_buffer();
1237 - if (rc<1)
1238 - return rc * 10 - 7;
1239 -
1240 - DEBUGF("write_long_name: success");
1241 - return 0;
1242 -}
1243 -
1244 -static int fat_checkname(const unsigned char* newname)
1245 -{
1246 - static const char invalid_chars[] = "\"*/:<>?\\|";
1247 - int len = strlen(newname);
1248 - /* More sanity checks are probably needed */
1249 - if (len > 255 || newname[len - 1] == '.')
1250 - {
1251 - return -1;
1252 - }
1253 - while (*newname)
1254 - {
1255 - if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1256 - return -1;
1257 - newname++;
1258 - }
1259 - /* check trailing space(s) */
1260 - if(*(--newname) == ' ')
1261 - return -1;
1262 -
1263 - return 0;
1264 -}
1265 -
1266 -static int add_dir_entry(struct fat_dir* dir,
1267 - struct fat_file* file,
1268 - const char* name,
1269 - bool is_directory,
1270 - bool dotdir)
1271 -{
1272 -#ifdef HAVE_MULTIVOLUME
1273 - struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1274 -#else
1275 - struct bpb* fat_bpb = &fat_bpbs[0];
1276 -#endif
1277 - unsigned char shortname[12];
1278 - int rc;
1279 - unsigned int sector;
1280 - bool done = false;
1281 - int entries_needed, entries_found = 0;
1282 - int firstentry;
1283 -
1284 - DEBUGF( "add_dir_entry(%s,%lx)",
1285 - name, file->firstcluster);
1286 -
1287 - /* Don't check dotdirs name for validity */
1288 - if (dotdir == false) {
1289 - rc = fat_checkname(name);
1290 - if (rc < 0) {
1291 - /* filename is invalid */
1292 - return rc * 10 - 1;
1293 - }
1294 - }
1295 -
1296 -#ifdef HAVE_MULTIVOLUME
1297 - file->volume = dir->file.volume; /* inherit the volume, to make sure */
1298 -#endif
1299 -
1300 - /* The "." and ".." directory entries must not be long names */
1301 - if(dotdir) {
1302 - int i;
1303 - strlcpy(shortname, name, 12);
1304 - for(i = strlen(shortname); i < 12; i++)
1305 - shortname[i] = ' ';
1306 -
1307 - entries_needed = 1;
1308 - } else {
1309 - create_dos_name(name, shortname);
1310 -
1311 - /* one dir entry needed for every 13 bytes of filename,
1312 - plus one entry for the short name */
1313 - entries_needed = (strlen(name) + (NAME_BYTES_PER_ENTRY-1))
1314 - / NAME_BYTES_PER_ENTRY + 1;
1315 - }
1316 -
1317 - unsigned char* buf = fat_get_sector_buffer();
1318 - restart:
1319 - firstentry = -1;
1320 -
1321 - rc = fat_seek(&dir->file, 0);
1322 - if (rc < 0)
1323 - {
1324 - fat_release_sector_buffer();
1325 - return rc * 10 - 2;
1326 - }
1327 -
1328 - /* step 1: search for free entries and check for duplicate shortname */
1329 - for (sector = 0; !done; sector++)
1330 - {
1331 - unsigned int i;
1332 -
1333 - rc = fat_readwrite(&dir->file, 1, buf, false);
1334 - if (rc < 0) {
1335 - fat_release_sector_buffer();
1336 - DEBUGF( "add_dir_entry() - Couldn't read dir"
1337 - " (error code %d)", rc);
1338 - return rc * 10 - 3;
1339 - }
1340 -
1341 - if (rc == 0) { /* current end of dir reached */
1342 - DEBUGF("End of dir on cluster boundary");
1343 - break;
1344 - }
1345 -
1346 - /* look for free slots */
1347 - for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1348 - {
1349 - switch (buf[i * DIR_ENTRY_SIZE]) {
1350 - case 0:
1351 - entries_found += DIR_ENTRIES_PER_SECTOR - i;
1352 - DEBUGF("Found end of dir %d",
1353 - sector * DIR_ENTRIES_PER_SECTOR + i);
1354 - i = DIR_ENTRIES_PER_SECTOR - 1;
1355 - done = true;
1356 - break;
1357 -
1358 - case 0xe5:
1359 - entries_found++;
1360 - DEBUGF("Found free entry %d (%d/%d)",
1361 - sector * DIR_ENTRIES_PER_SECTOR + i,
1362 - entries_found, entries_needed);
1363 - break;
1364 -
1365 - default:
1366 - entries_found = 0;
1367 -
1368 - /* check that our intended shortname doesn't already exist */
1369 - if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1370 - /* shortname exists already, make a new one */
1371 - randomize_dos_name(shortname);
1372 - DEBUGF("Duplicate shortname, changing to %s",
1373 - shortname);
1374 -
1375 - /* name has changed, we need to restart search */
1376 - goto restart;
1377 - }
1378 - break;
1379 - }
1380 - if (firstentry < 0 && (entries_found >= entries_needed))
1381 - firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1382 - - entries_found;
1383 - }
1384 - }
1385 -
1386 - /* step 2: extend the dir if necessary */
1387 - if (firstentry < 0)
1388 - {
1389 - DEBUGF("Adding new sector(s) to dir");
1390 - rc = fat_seek(&dir->file, sector);
1391 - if (rc < 0)
1392 - {
1393 - fat_release_sector_buffer();
1394 - return rc * 10 - 4;
1395 - }
1396 - memset(buf, 0, SECTOR_SIZE);
1397 -
1398 - /* we must clear whole clusters */
1399 - for (; (entries_found < entries_needed) ||
1400 - (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1401 - {
1402 - if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1403 - {
1404 - fat_release_sector_buffer();
1405 - return -5; /* dir too large -- FAT specification */
1406 - }
1407 -
1408 - rc = fat_readwrite(&dir->file, 1, buf, true);
1409 - if (rc < 1) /* No more room or something went wrong */
1410 - {
1411 - fat_release_sector_buffer();
1412 - return rc * 10 - 6;
1413 - }
1414 -
1415 - entries_found += DIR_ENTRIES_PER_SECTOR;
1416 - }
1417 -
1418 - firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1419 - }
1420 - fat_release_sector_buffer();
1421 -
1422 - /* step 3: add entry */
1423 - sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1424 - DEBUGF("Adding longname to entry %d in sector %d",
1425 - firstentry, sector);
1426 -
1427 - rc = write_long_name(&dir->file, firstentry,
1428 - entries_needed, name, shortname, is_directory);
1429 - if (rc < 0)
1430 - return rc * 10 - 7;
1431 -
1432 - /* remember where the shortname dir entry is located */
1433 - file->direntry = firstentry + entries_needed - 1;
1434 - file->direntries = entries_needed;
1435 - file->dircluster = dir->file.firstcluster;
1436 - DEBUGF("Added new dir entry %d, using %d slots.",
1437 - file->direntry, file->direntries);
1438 -
1439 - return 0;
1440 -}
1441 -
1442 -static unsigned char char2dos(unsigned char c, int* randomize)
1443 -{
1444 - static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1445 -
1446 - if (c <= 0x20)
1447 - c = 0; /* Illegal char, remove */
1448 - else if (strchr(invalid_chars, c) != NULL)
1449 - {
1450 - /* Illegal char, replace */
1451 - c = '_';
1452 - *randomize = 1; /* as per FAT spec */
1453 - }
1454 - else
1455 - c = toupper(c);
1456 -
1457 - return c;
1458 -}
1459 -
1460 -static void create_dos_name(const unsigned char *name, unsigned char *newname)
1461 -{
1462 - int i;
1463 - unsigned char *ext;
1464 - int randomize = 0;
1465 -
1466 - /* Find extension part */
1467 - ext = strrchr(name, '.');
1468 - if (ext == name) /* handle .dotnames */
1469 - ext = NULL;
1470 -
1471 - /* needs to randomize? */
1472 - if((ext && (strlen(ext) > 4)) ||
1473 - ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1474 - randomize = 1;
1475 -
1476 - /* Name part */
1477 - for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1478 - {
1479 - unsigned char c = char2dos(*name, &randomize);
1480 - if (c)
1481 - newname[i++] = c;
1482 - }
1483 -
1484 - /* Pad both name and extension */
1485 - while (i < 11)
1486 - newname[i++] = ' ';
1487 -
1488 - if (newname[0] == 0xe5) /* Special kanji character */
1489 - newname[0] = 0x05;
1490 -
1491 - if (ext)
1492 - { /* Extension part */
1493 - ext++;
1494 - for (i = 8; *ext && (i < 11); ext++)
1495 - {
1496 - unsigned char c = char2dos(*ext, &randomize);
1497 - if (c)
1498 - newname[i++] = c;
1499 - }
1500 - }
1501 -
1502 - if(randomize)
1503 - randomize_dos_name(newname);
1504 -}
1505 -
1506 -static void randomize_dos_name(unsigned char *name)
1507 -{
1508 - unsigned char* tilde = NULL; /* ~ location */
1509 - unsigned char* lastpt = NULL; /* last point of filename */
1510 - unsigned char* nameptr = name; /* working copy of name pointer */
1511 - unsigned char num[9]; /* holds number as string */
1512 - int i = 0;
1513 - int cnt = 1;
1514 - int numlen;
1515 - int offset;
1516 -
1517 - while(i++ < 8)
1518 - {
1519 - /* hunt for ~ and where to put it */
1520 - if((!tilde) && (*nameptr == '~'))
1521 - tilde = nameptr;
1522 - if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1523 - lastpt = nameptr;
1524 - nameptr++;
1525 - }
1526 - if(tilde)
1527 - {
1528 - /* extract current count and increment */
1529 - memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1530 - num[7-(unsigned int)(tilde-name)] = 0;
1531 - cnt = atoi(num) + 1;
1532 - }
1533 - cnt %= 10000000; /* protection */
1534 - snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1535 - numlen = strlen(num); /* required space */
1536 - offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1537 - if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1538 -
1539 - memcpy(&name[offset], num, numlen);
1540 -
1541 - /* in special case of counter overflow: pad with spaces */
1542 - for(offset = offset+numlen; offset < 8; offset++)
1543 - name[offset] = ' ';
1544 -}
1545 -
1546 -static int update_short_entry( struct fat_file* file, long size, int attr )
1547 -{
1548 - int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1549 - unsigned long* sizeptr;
1550 - unsigned short* clusptr;
1551 - struct fat_file dir;
1552 - int rc;
1553 -
1554 - DEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)",
1555 - file->firstcluster, file->direntry, size);
1556 -
1557 - /* create a temporary file handle for the dir holding this file */
1558 - rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1559 - if (rc < 0)
1560 - return rc * 10 - 1;
1561 -
1562 - rc = fat_seek( &dir, sector );
1563 - if (rc<0)
1564 - return rc * 10 - 2;
1565 -
1566 - unsigned char* buf = fat_get_sector_buffer();
1567 - unsigned char* entry =
1568 - buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1569 - rc = fat_readwrite(&dir, 1, buf, false);
1570 - if (rc < 1)
1571 - {
1572 - fat_release_sector_buffer();
1573 - return rc * 10 - 3;
1574 - }
1575 -
1576 - if (!entry[0] || entry[0] == 0xe5)
1577 - {
1578 - fat_release_sector_buffer();
1579 - panicf(PANIC_KILLUSERTHREADS, "Updating size on empty dir entry %d", file->direntry);
1580 - }
1581 -
1582 - entry[FATDIR_ATTR] = attr & 0xFF;
1583 -
1584 - clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1585 - *clusptr = htole16(file->firstcluster >> 16);
1586 -
1587 - clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1588 - *clusptr = htole16(file->firstcluster & 0xffff);
1589 -
1590 - sizeptr = (long*)(entry + FATDIR_FILESIZE);
1591 - *sizeptr = htole32(size);
1592 -
1593 - {
1594 -#if CONFIG_RTC
1595 - unsigned short time = 0;
1596 - unsigned short date = 0;
1597 -#else
1598 - /* get old time to increment from */
1599 - unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1600 - unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1601 -#endif
1602 - fat_time(&date, &time, NULL);
1603 - *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1604 - *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1605 - *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1606 - }
1607 -
1608 - rc = fat_seek( &dir, sector );
1609 - if (rc < 0)
1610 - {
1611 - fat_release_sector_buffer();
1612 - return rc * 10 - 4;
1613 - }
1614 -
1615 - rc = fat_readwrite(&dir, 1, buf, true);
1616 - fat_release_sector_buffer();
1617 - if (rc < 1)
1618 - return rc * 10 - 5;
1619 -
1620 - return 0;
1621 -}
1622 -
1623 -static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1624 -{
1625 - int i=0,j=0;
1626 - unsigned char c;
1627 - bool lowercase;
1628 -
1629 - memset(de, 0, sizeof(struct fat_direntry));
1630 - de->attr = buf[FATDIR_ATTR];
1631 - de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1632 - de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1633 - de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1634 - de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1635 - de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1636 - de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1637 - de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1638 - ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1639 - /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1640 - (the result of the shift is always considered signed) */
1641 -
1642 - /* fix the name */
1643 - lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1644 - c = buf[FATDIR_NAME];
1645 - if (c == 0x05) /* special kanji char */
1646 - c = 0xe5;
1647 - i = 0;
1648 - while (c != ' ') {
1649 - de->name[j++] = lowercase ? tolower(c) : c;
1650 - if (++i >= 8)
1651 - break;
1652 - c = buf[FATDIR_NAME+i];
1653 - }
1654 - if (buf[FATDIR_NAME+8] != ' ') {
1655 - lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1656 - de->name[j++] = '.';
1657 - for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1658 - de->name[j++] = lowercase ? tolower(c) : c;
1659 - }
1660 - return 1;
1661 -}
1662 -
1663 -int fat_open(IF_MV2(int volume,)
1664 - long startcluster,
1665 - struct fat_file *file,
1666 - const struct fat_dir* dir)
1667 -{
1668 - /* Remember where the file's dir entry is located
1669 - * Do it before assigning other fields so that fat_open
1670 - * can be called with file == &dir->file (see fat_opendir) */
1671 - if ( dir ) {
1672 - file->direntry = dir->entry - 1;
1673 - file->direntries = dir->entrycount;
1674 - file->dircluster = dir->file.firstcluster;
1675 - }
1676 -
1677 - file->firstcluster = startcluster;
1678 - file->lastcluster = startcluster;
1679 - file->lastsector = 0;
1680 - file->clusternum = 0;
1681 - file->sectornum = 0;
1682 - file->eof = false;
1683 -#ifdef HAVE_MULTIVOLUME
1684 - file->volume = volume;
1685 - /* fixme: remove error check when done */
1686 - if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1687 - {
1688 - DEBUGF("fat_open() illegal volume %d", volume);
1689 - return -1;
1690 - }
1691 -#endif
1692 -
1693 - DEBUGF("fat_open(%lx), entry %d",startcluster,file->direntry);
1694 - return 0;
1695 -}
1696 -
1697 -int fat_create_file(const char* name,
1698 - struct fat_file* file,
1699 - struct fat_dir* dir)
1700 -{
1701 - int rc;
1702 -
1703 - DEBUGF("fat_create_file(\"%s\",%lx,%lx)",name,(long)file,(long)dir);
1704 - rc = add_dir_entry(dir, file, name, false, false);
1705 - if (!rc) {
1706 - file->firstcluster = 0;
1707 - file->lastcluster = 0;
1708 - file->lastsector = 0;
1709 - file->clusternum = 0;
1710 - file->sectornum = 0;
1711 - file->eof = false;
1712 - }
1713 -
1714 - return rc;
1715 -}
1716 -
1717 -int fat_create_dir(const char* name,
1718 - struct fat_dir* newdir,
1719 - struct fat_dir* dir)
1720 -{
1721 -#ifdef HAVE_MULTIVOLUME
1722 - struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1723 -#else
1724 - struct bpb* fat_bpb = &fat_bpbs[0];
1725 -#endif
1726 - int i;
1727 - long sector;
1728 - int rc;
1729 - struct fat_file dummyfile;
1730 -
1731 - DEBUGF("fat_create_dir(\"%s\",%lx,%lx)",name,(long)newdir,(long)dir);
1732 -
1733 - memset(newdir, 0, sizeof(struct fat_dir));
1734 - memset(&dummyfile, 0, sizeof(struct fat_file));
1735 -
1736 - /* First, add the entry in the parent directory */
1737 - rc = add_dir_entry(dir, &newdir->file, name, true, false);
1738 - if (rc < 0)
1739 - return rc * 10 - 1;
1740 -
1741 - /* Allocate a new cluster for the directory */
1742 - newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1743 - fat_bpb->fsinfo.nextfree);
1744 - if(newdir->file.firstcluster == 0)
1745 - return -1;
1746 -
1747 - update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1748 -
1749 - /* Clear the entire cluster */
1750 - unsigned char* buf = fat_get_sector_buffer();
1751 - memset(buf, 0, SECTOR_SIZE);
1752 - sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1753 - for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1754 - rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1755 - if (rc < 0)
1756 - {
1757 - fat_release_sector_buffer();
1758 - return rc * 10 - 2;
1759 - }
1760 - }
1761 - fat_release_sector_buffer();
1762 -
1763 - /* Then add the "." entry */
1764 - rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1765 - if (rc < 0)
1766 - return rc * 10 - 3;
1767 - dummyfile.firstcluster = newdir->file.firstcluster;
1768 - update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1769 -
1770 - /* and the ".." entry */
1771 - rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1772 - if (rc < 0)
1773 - return rc * 10 - 4;
1774 -
1775 - /* The root cluster is cluster 0 in the ".." entry */
1776 - if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1777 - dummyfile.firstcluster = 0;
1778 - else
1779 - dummyfile.firstcluster = dir->file.firstcluster;
1780 - update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1781 -
1782 - /* Set the firstcluster field in the direntry */
1783 - update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1784 -
1785 - rc = flush_fat(IF_MV(fat_bpb));
1786 - if (rc < 0)
1787 - return rc * 10 - 5;
1788 -
1789 - return rc;
1790 -}
1791 -
1792 -int fat_truncate(const struct fat_file *file)
1793 -{
1794 - /* truncate trailing clusters */
1795 - long next;
1796 - long last = file->lastcluster;
1797 -#ifdef HAVE_MULTIVOLUME
1798 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
1799 -#endif
1800 -
1801 - DEBUGF("fat_truncate(%lx, %lx)", file->firstcluster, last);
1802 -
1803 - for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1804 - next = get_next_cluster(IF_MV2(fat_bpb,) last);
1805 - update_fat_entry(IF_MV2(fat_bpb,) last,0);
1806 - }
1807 - if (file->lastcluster)
1808 - update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1809 -
1810 - return 0;
1811 -}
1812 -
1813 -int fat_closewrite(struct fat_file *file, long size, int attr)
1814 -{
1815 - int rc;
1816 -#ifdef HAVE_MULTIVOLUME
1817 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
1818 -#endif
1819 - DEBUGF("fat_closewrite(size=%ld)",size);
1820 -
1821 - if (!size) {
1822 - /* empty file */
1823 - if ( file->firstcluster ) {
1824 - update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1825 - file->firstcluster = 0;
1826 - }
1827 - }
1828 -
1829 - if (file->dircluster) {
1830 - rc = update_short_entry(file, size, attr);
1831 - if (rc < 0)
1832 - return rc * 10 - 1;
1833 - }
1834 -
1835 - flush_fat(IF_MV(fat_bpb));
1836 -
1837 -#ifdef TEST_FAT
1838 - if ( file->firstcluster ) {
1839 - /* debug */
1840 -#ifdef HAVE_MULTIVOLUME
1841 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
1842 -#else
1843 - struct bpb* fat_bpb = &fat_bpbs[0];
1844 -#endif
1845 - long count = 0;
1846 - long len;
1847 - long next;
1848 - for ( next = file->firstcluster; next;
1849 - next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
1850 - DEBUGF("cluster %ld: %lx", count, next);
1851 - count++;
1852 - }
1853 - len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1854 - DEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)",
1855 - count, len, size );
1856 - if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1857 - panicf(PANIC_KILLUSERTHREADS, "Cluster chain is too long");
1858 - if ( len < size )
1859 - panicf(PANIC_KILLUSERTHREADS, "Cluster chain is too short");
1860 - }
1861 -#endif
1862 -
1863 - return 0;
1864 -}
1865 -
1866 -static int free_direntries(struct fat_file* file)
1867 -{
1868 - struct fat_file dir;
1869 - int numentries = file->direntries;
1870 - unsigned int entry = file->direntry - numentries + 1;
1871 - unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1872 - int i;
1873 - int rc;
1874 -
1875 - /* create a temporary file handle for the dir holding this file */
1876 - rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1877 - if (rc < 0)
1878 - return rc * 10 - 1;
1879 -
1880 - rc = fat_seek( &dir, sector );
1881 - if (rc < 0)
1882 - return rc * 10 - 2;
1883 -
1884 - unsigned char* buf = fat_get_sector_buffer();
1885 - rc = fat_readwrite(&dir, 1, buf, false);
1886 - if (rc < 1)
1887 - {
1888 - fat_release_sector_buffer();
1889 - return rc * 10 - 3;
1890 - }
1891 -
1892 - for (i=0; i < numentries; i++) {
1893 - DEBUGF("Clearing dir entry %d (%d/%d)",
1894 - entry, i+1, numentries);
1895 - buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1896 - entry++;
1897 -
1898 - if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1899 - /* flush this sector */
1900 - rc = fat_seek(&dir, sector);
1901 - if (rc < 0)
1902 - {
1903 - fat_release_sector_buffer();
1904 - return rc * 10 - 4;
1905 - }
1906 -
1907 - rc = fat_readwrite(&dir, 1, buf, true);
1908 - if (rc < 1)
1909 - {
1910 - fat_release_sector_buffer();
1911 - return rc * 10 - 5;
1912 - }
1913 -
1914 - if ( i+1 < numentries ) {
1915 - /* read next sector */
1916 - rc = fat_readwrite(&dir, 1, buf, false);
1917 - if (rc < 1)
1918 - {
1919 - fat_release_sector_buffer();
1920 - return rc * 10 - 6;
1921 - }
1922 - }
1923 - sector++;
1924 - }
1925 - }
1926 -
1927 - if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1928 - /* flush this sector */
1929 - rc = fat_seek(&dir, sector);
1930 - if (rc < 0)
1931 - {
1932 - fat_release_sector_buffer();
1933 - return rc * 10 - 7;
1934 - }
1935 -
1936 - rc = fat_readwrite(&dir, 1, buf, true);
1937 - if (rc < 1)
1938 - {
1939 - fat_release_sector_buffer();
1940 - return rc * 10 - 8;
1941 - }
1942 - }
1943 -
1944 - fat_release_sector_buffer();
1945 - return 0;
1946 -}
1947 -
1948 -int fat_remove(struct fat_file* file)
1949 -{
1950 - long next, last = file->firstcluster;
1951 - int rc;
1952 -#ifdef HAVE_MULTIVOLUME
1953 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
1954 -#endif
1955 -
1956 - DEBUGF("fat_remove(%lx)",last);
1957 -
1958 - while ( last ) {
1959 - next = get_next_cluster(IF_MV2(fat_bpb,) last);
1960 - update_fat_entry(IF_MV2(fat_bpb,) last,0);
1961 - last = next;
1962 - }
1963 -
1964 - if ( file->dircluster ) {
1965 - rc = free_direntries(file);
1966 - if (rc < 0)
1967 - return rc * 10 - 1;
1968 - }
1969 -
1970 - file->firstcluster = 0;
1971 - file->dircluster = 0;
1972 -
1973 - rc = flush_fat(IF_MV(fat_bpb));
1974 - if (rc < 0)
1975 - return rc * 10 - 2;
1976 -
1977 - return 0;
1978 -}
1979 -
1980 -int fat_rename(struct fat_file* file,
1981 - struct fat_dir* dir,
1982 - const unsigned char* newname,
1983 - long size,
1984 - int attr)
1985 -{
1986 - int rc;
1987 - struct fat_dir olddir;
1988 - struct fat_file newfile = *file;
1989 - unsigned char* entry = NULL;
1990 - unsigned short* clusptr = NULL;
1991 - unsigned int parentcluster;
1992 -#ifdef HAVE_MULTIVOLUME
1993 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
1994 -
1995 - if (file->volume != dir->file.volume) {
1996 - DEBUGF("No rename across volumes!");
1997 - return -1;
1998 - }
1999 -#else
2000 - struct bpb* fat_bpb = &fat_bpbs[0];
2001 -#endif
2002 -
2003 - if ( !file->dircluster ) {
2004 - DEBUGF("File has no dir cluster!");
2005 - return -2;
2006 - }
2007 -
2008 - /* create a temporary file handle */
2009 - rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
2010 - if (rc < 0)
2011 - return rc * 10 - 1;
2012 -
2013 - /* create new name */
2014 - rc = add_dir_entry(dir, &newfile, newname, false, false);
2015 - if (rc < 0)
2016 - return rc * 10 - 2;
2017 -
2018 - /* write size and cluster link */
2019 - rc = update_short_entry(&newfile, size, attr);
2020 - if (rc < 0)
2021 - return rc * 10 - 3;
2022 -
2023 - /* remove old name */
2024 - rc = free_direntries(file);
2025 - if (rc < 0)
2026 - return rc * 10 - 4;
2027 -
2028 - rc = flush_fat(IF_MV(fat_bpb));
2029 - if (rc < 0)
2030 - return rc * 10 - 5;
2031 -
2032 - /* if renaming a directory, update the .. entry to make sure
2033 - it points to its parent directory (we don't check if it was a move) */
2034 - if(FAT_ATTR_DIRECTORY == attr) {
2035 - /* open the dir that was renamed, we re-use the olddir struct */
2036 - rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
2037 - NULL);
2038 - if (rc < 0)
2039 - return rc * 10 - 6;
2040 -
2041 - /* get the first sector of the dir */
2042 - rc = fat_seek(&olddir.file, 0);
2043 - if (rc < 0)
2044 - return rc * 10 - 7;
2045 -
2046 - unsigned char* buf = fat_get_sector_buffer();
2047 - rc = fat_readwrite(&olddir.file, 1, buf, false);
2048 - if (rc < 0)
2049 - {
2050 - fat_release_sector_buffer();
2051 - return rc * 10 - 8;
2052 - }
2053 -
2054 - /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2055 - if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2056 - parentcluster = 0;
2057 - else
2058 - parentcluster = dir->file.firstcluster;
2059 -
2060 - entry = buf + DIR_ENTRY_SIZE;
2061 - if(strncmp(".. ", entry, 11))
2062 - {
2063 - fat_release_sector_buffer();
2064 - /* .. entry must be second entry according to FAT spec (p.29) */
2065 - DEBUGF("Second dir entry is not double-dot!");
2066 - return rc * 10 - 9;
2067 - }
2068 - clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2069 - *clusptr = htole16(parentcluster >> 16);
2070 -
2071 - clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
2072 - *clusptr = htole16(parentcluster & 0xffff);
2073 -
2074 - /* write back this sector */
2075 - rc = fat_seek(&olddir.file, 0);
2076 - if (rc < 0)
2077 - {
2078 - fat_release_sector_buffer();
2079 - return rc * 10 - 7;
2080 - }
2081 -
2082 - rc = fat_readwrite(&olddir.file, 1, buf, true);
2083 - fat_release_sector_buffer();
2084 - if (rc < 1)
2085 - return rc * 10 - 8;
2086 - }
2087 -
2088 - return 0;
2089 -}
2090 -
2091 -static long next_write_cluster(struct fat_file* file,
2092 - long oldcluster,
2093 - long* newsector)
2094 -{
2095 -#ifdef HAVE_MULTIVOLUME
2096 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
2097 -#else
2098 - struct bpb* fat_bpb = &fat_bpbs[0];
2099 -#endif
2100 - long cluster = 0;
2101 - long sector;
2102 -
2103 - DEBUGF("next_write_cluster(%lx,%lx)",file->firstcluster, oldcluster);
2104 -
2105 - if (oldcluster)
2106 - cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
2107 -
2108 - if (!cluster) {
2109 - if (oldcluster > 0)
2110 - cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
2111 - else if (oldcluster == 0)
2112 - cluster = find_free_cluster(IF_MV2(fat_bpb,)
2113 - fat_bpb->fsinfo.nextfree);
2114 -#ifdef HAVE_FAT16SUPPORT
2115 - else /* negative, pseudo-cluster of the root dir */
2116 - return 0; /* impossible to append something to the root */
2117 -#endif
2118 -
2119 - if (cluster) {
2120 - if (oldcluster)
2121 - update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
2122 - else
2123 - file->firstcluster = cluster;
2124 - update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
2125 - }
2126 - else {
2127 -#ifdef TEST_FAT
2128 - if (fat_bpb->fsinfo.freecount>0)
2129 - panicf(PANIC_KILLUSERTHREADS, "There is free space, but find_free_cluster() "
2130 - "didn't find it!");
2131 -#endif
2132 - DEBUGF("next_write_cluster(): Disk full!");
2133 - return 0;
2134 - }
2135 - }
2136 - sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2137 - if (sector<0)
2138 - return 0;
2139 -
2140 - *newsector = sector;
2141 - return cluster;
2142 -}
2143 -
2144 -static int transfer(IF_MV2(struct bpb* fat_bpb,)
2145 - unsigned long start, long count, char* buf, bool write )
2146 -{
2147 -#ifndef HAVE_MULTIVOLUME
2148 - struct bpb* fat_bpb = &fat_bpbs[0];
2149 -#endif
2150 - int rc;
2151 -
2152 - DEBUGF("transfer(s=%lx, c=%lx, %s)",
2153 - start+ fat_bpb->startsector, count, write?"write":"read");
2154 - if (write) {
2155 - unsigned long firstallowed;
2156 -#ifdef HAVE_FAT16SUPPORT
2157 - if (fat_bpb->is_fat16)
2158 - firstallowed = fat_bpb->rootdirsector;
2159 - else
2160 -#endif
2161 - firstallowed = fat_bpb->firstdatasector;
2162 -
2163 - if (start < firstallowed)
2164 - panicf(PANIC_KILLUSERTHREADS, "Write %ld before data", firstallowed - start);
2165 - if (start + count > fat_bpb->totalsectors)
2166 - panicf(PANIC_KILLUSERTHREADS, "Write %ld after data",
2167 - start + count - fat_bpb->totalsectors);
2168 - rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2169 - start + fat_bpb->startsector, count, buf);
2170 - }
2171 - else
2172 - rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2173 - start + fat_bpb->startsector, count, buf);
2174 - if (rc < 0) {
2175 - DEBUGF( "transfer() - Couldn't %s sector %lx"
2176 - " (error code %d)",
2177 - write ? "write":"read", start, rc);
2178 - return rc;
2179 - }
2180 - return 0;
2181 -}
2182 -
2183 -
2184 -long fat_readwrite( struct fat_file *file, long sectorcount,
2185 - void* buf, bool write )
2186 -{
2187 -#ifdef HAVE_MULTIVOLUME
2188 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
2189 -#else
2190 - struct bpb* fat_bpb = &fat_bpbs[0];
2191 -#endif
2192 - long cluster = file->lastcluster;
2193 - long sector = file->lastsector;
2194 - long clusternum = file->clusternum;
2195 - long numsec = file->sectornum;
2196 - bool eof = file->eof;
2197 - long first=0, last=0;
2198 - long i;
2199 - int rc;
2200 -
2201 - DEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)",
2202 - file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2203 - DEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d",
2204 - sector,numsec, eof?1:0);
2205 -
2206 - if ( eof && !write)
2207 - return 0;
2208 -
2209 - /* find sequential sectors and write them all at once */
2210 - for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2211 - numsec++;
2212 - if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2213 - long oldcluster = cluster;
2214 - long oldsector = sector;
2215 - long oldnumsec = numsec;
2216 - if (write)
2217 - cluster = next_write_cluster(file, cluster, &sector);
2218 - else {
2219 - cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2220 - sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2221 - }
2222 -
2223 - clusternum++;
2224 - numsec=1;
2225 -
2226 - if (!cluster) {
2227 - eof = true;
2228 - if ( write ) {
2229 - /* remember last cluster, in case
2230 - we want to append to the file */
2231 - sector = oldsector;
2232 - cluster = oldcluster;
2233 - numsec = oldnumsec;
2234 - clusternum--;
2235 - i = -1; /* Error code */
2236 - break;
2237 - }
2238 - }
2239 - else
2240 - eof = false;
2241 - }
2242 - else {
2243 - if (sector)
2244 - sector++;
2245 - else {
2246 - /* look up first sector of file */
2247 - sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2248 - numsec=1;
2249 -#ifdef HAVE_FAT16SUPPORT
2250 - if (file->firstcluster < 0)
2251 - { /* FAT16 root dir */
2252 - sector += fat_bpb->rootdiroffset;
2253 - numsec += fat_bpb->rootdiroffset;
2254 - }
2255 -#endif
2256 - }
2257 - }
2258 -
2259 - if (!first)
2260 - first = sector;
2261 -
2262 - if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2263 - (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2264 - long count = last - first + 1;
2265 - rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2266 - if (rc < 0)
2267 - return rc * 10 - 1;
2268 -
2269 - buf = (char *)buf + count * SECTOR_SIZE;
2270 - first = sector;
2271 - }
2272 -
2273 - if ((i == sectorcount-1) && /* last sector requested */
2274 - (!eof))
2275 - {
2276 - long count = sector - first + 1;
2277 - rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2278 - if (rc < 0)
2279 - return rc * 10 - 2;
2280 - }
2281 -
2282 - last = sector;
2283 - }
2284 -
2285 - file->lastcluster = cluster;
2286 - file->lastsector = sector;
2287 - file->clusternum = clusternum;
2288 - file->sectornum = numsec;
2289 - file->eof = eof;
2290 -
2291 - /* if eof, don't report last block as read/written */
2292 - if (eof)
2293 - i--;
2294 -
2295 - DEBUGF("Sectors written: %ld", i);
2296 - return i;
2297 -}
2298 -
2299 -int fat_seek(struct fat_file *file, unsigned long seeksector )
2300 -{
2301 -#ifdef HAVE_MULTIVOLUME
2302 - struct bpb* fat_bpb = &fat_bpbs[file->volume];
2303 -#else
2304 - struct bpb* fat_bpb = &fat_bpbs[0];
2305 -#endif
2306 - long clusternum=0, numclusters=0, sectornum=0, sector=0;
2307 - long cluster = file->firstcluster;
2308 - long i;
2309 -
2310 -#ifdef HAVE_FAT16SUPPORT
2311 - if (cluster < 0) /* FAT16 root dir */
2312 - seeksector += fat_bpb->rootdiroffset;
2313 -#endif
2314 -
2315 - file->eof = false;
2316 - if (seeksector) {
2317 - /* we need to find the sector BEFORE the requested, since
2318 - the file struct stores the last accessed sector */
2319 - seeksector--;
2320 - numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2321 - sectornum = seeksector % fat_bpb->bpb_secperclus;
2322 -
2323 - if (file->clusternum && clusternum >= file->clusternum)
2324 - {
2325 - cluster = file->lastcluster;
2326 - numclusters -= file->clusternum;
2327 - }
2328 -
2329 - for (i=0; i<numclusters; i++) {
2330 - cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2331 - if (!cluster) {
2332 - DEBUGF("Seeking beyond the end of the file! "
2333 - "(sector %ld, cluster %ld)", seeksector, i);
2334 - return -1;
2335 - }
2336 - }
2337 -
2338 - sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2339 - }
2340 - else {
2341 - sectornum = -1;
2342 - }
2343 -
2344 - DEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx",
2345 - file->firstcluster, seeksector, cluster, sector, sectornum);
2346 -
2347 - file->lastcluster = cluster;
2348 - file->lastsector = sector;
2349 - file->clusternum = clusternum;
2350 - file->sectornum = sectornum + 1;
2351 - return 0;
2352 -}
2353 -
2354 -int fat_opendir(IF_MV2(int volume,)
2355 - struct fat_dir *dir, unsigned long startcluster,
2356 - const struct fat_dir *parent_dir)
2357 -{
2358 -#ifdef HAVE_MULTIVOLUME
2359 - struct bpb* fat_bpb = &fat_bpbs[volume];
2360 - /* fixme: remove error check when done */
2361 - if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2362 - {
2363 - DEBUGF("fat_open() illegal volume %d", volume);
2364 - return -1;
2365 - }
2366 -#else
2367 - struct bpb* fat_bpb = &fat_bpbs[0];
2368 -#endif
2369 - int rc;
2370 -
2371 - if (startcluster == 0)
2372 - startcluster = fat_bpb->bpb_rootclus;
2373 -
2374 - rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2375 - if(rc)
2376 - {
2377 - DEBUGF( "fat_opendir() - Couldn't open dir"
2378 - " (error code %d)", rc);
2379 - return rc * 10 - 1;
2380 - }
2381 -
2382 - /* assign them after fat_open call so that fat_opendir can be called with the same
2383 - * fat_dir as parent and result */
2384 - dir->entry = 0;
2385 - dir->sector = 0;
2386 -
2387 - return 0;
2388 -}
2389 -
2390 -int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2391 -{
2392 - bool done = false;
2393 - int i, j;
2394 - int rc;
2395 - int order;
2396 - unsigned char firstbyte;
2397 - /* Long file names are stored in special entries. Each entry holds
2398 - up to 13 characters. Names can be max 255 chars (not bytes!) long */
2399 - /* The number of long entries in the long name can be retrieve from the first
2400 - * long entry because there are stored in reverse order and have an ordinal */
2401 - int nb_longs = 0;
2402 - /* The long entries are expected to be in order, so remember the last ordinal */
2403 - int last_long_ord = 0;
2404 -
2405 - dir->entrycount = 0;
2406 -
2407 - while(!done)
2408 - {
2409 - if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2410 - {
2411 - rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2412 - if (rc == 0) {
2413 - /* eof */
2414 - entry->name[0] = 0;
2415 - break;
2416 - }
2417 - if (rc < 0) {
2418 - DEBUGF( "fat_getnext() - Couldn't read dir"
2419 - " (error code %d)", rc);
2420 - return rc * 10 - 1;
2421 - }
2422 - dir->sector = dir->file.lastsector;
2423 - }
2424 -
2425 - for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2426 - i < DIR_ENTRIES_PER_SECTOR; i++) {
2427 - unsigned int entrypos = i * DIR_ENTRY_SIZE;
2428 -
2429 - firstbyte = dir->sectorcache[entrypos];
2430 - dir->entry++;
2431 -
2432 - if (firstbyte == 0xe5) {
2433 - /* free entry */
2434 - dir->entrycount = 0;
2435 - continue;
2436 - }
2437 -
2438 - if (firstbyte == 0) {
2439 - /* last entry */
2440 - entry->name[0] = 0;
2441 - dir->entrycount = 0;
2442 - return 0;
2443 - }
2444 -
2445 - dir->entrycount++;
2446 -
2447 - /* LFN entry? */
2448 - if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2449 - FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2450 - /* extract ordinal */
2451 - order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2452 - /* is this entry the first long entry ? (first in order but containing last part) */
2453 - if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2454 - /* check that order is not too big ! (and non-zero) */
2455 - if(order <= 0 || order > FATLONG_MAX_ORDER)
2456 - continue; /* ignore the whole LFN, will trigger lots of warnings */
2457 - nb_longs = order;
2458 - last_long_ord = order;
2459 - }
2460 - else {
2461 - /* check orphan entry */
2462 - if (nb_longs == 0) {
2463 - DEBUGF("fat warning: orphan LFN entry");
2464 - /* ignore */
2465 - continue;
2466 - }
2467 -
2468 - /* check order */
2469 - if (order != (last_long_ord - 1)) {
2470 - DEBUGF("fat warning: wrong LFN ordinal");
2471 - /* ignore the whole LFN, will trigger lots of warnings */
2472 - nb_longs = 0;
2473 - }
2474 -
2475 - last_long_ord = order;
2476 - }
2477 -
2478 - /* copy part, reuse [order] for another purpose :) */
2479 - order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2480 - for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2481 - memcpy(dir->longname + order,
2482 - dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2483 - FATLONG_NAME_SIZE[j]);
2484 - order += FATLONG_NAME_SIZE[j];
2485 - }
2486 - }
2487 - else {
2488 - if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2489 -
2490 - /* don't return volume id entry */
2491 - if ( (entry->attr &
2492 - (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2493 - == FAT_ATTR_VOLUME_ID)
2494 - continue;
2495 -
2496 - /* replace shortname with longname? */
2497 - /* check that the long name is complete */
2498 - if (nb_longs != 0 && last_long_ord == 1) {
2499 - /* hold a copy of the shortname in case the long one is too long */
2500 - unsigned char shortname[13]; /* 8+3+dot+\0 */
2501 - int longname_utf8len = 0;
2502 - /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2503 - * of a UTF8 encoded character in rockbox */
2504 - unsigned char longname_utf8segm[4 + 1];
2505 - unsigned short ucs;
2506 - int segm_utf8len;
2507 - /* Temporarily store short name */
2508 - strcpy(shortname, entry->name);
2509 - entry->name[0] = 0;
2510 -
2511 - /* Convert the FAT name to a utf8-encoded one.
2512 - * The name is not necessary NUL-terminated ! */
2513 - for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2514 - ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2515 - if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2516 - break;
2517 - /* utf8encode will return a pointer after the converted
2518 - * string, subtract the pointer to the start to get the length of it */
2519 - segm_utf8len = 1;
2520 -
2521 - /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2522 - if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2523 - /* force use of short name */
2524 - longname_utf8len = FAT_FILENAME_BYTES + 1;
2525 - break; /* fallback later */
2526 - }
2527 - else {
2528 - if (ucs < 128) longname_utf8segm[0] = (unsigned char)ucs;
2529 - else longname_utf8segm[0] = '?';
2530 - longname_utf8segm[segm_utf8len] = 0;
2531 - strcat(entry->name + longname_utf8len, longname_utf8segm);
2532 - longname_utf8len += segm_utf8len;
2533 - }
2534 - }
2535 -
2536 - /* Does the utf8-encoded name fit into the entry? */
2537 - /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2538 - if (longname_utf8len >= FAT_FILENAME_BYTES) {
2539 - /* Take the short DOS name. Need to utf8-encode it
2540 - since it may contain chars from the upper half of
2541 - the OEM code page which wouldn't be a valid utf8.
2542 - Beware: this file will be shown with strange
2543 - glyphs in file browser since unicode 0x80 to 0x9F
2544 - are control characters. */
2545 - DEBUGF("SN-DOS: %s", shortname);
2546 - unsigned char *utf8;
2547 - memcpy(entry->name, shortname, strlen(shortname));
2548 - *(entry->name + strlen(shortname)) = 0;
2549 - DEBUGF("SN: %s", entry->name);
2550 - } else {
2551 - DEBUGF("LN: %s", entry->name);
2552 - DEBUGF("LNLen: %d", longname_utf8len);
2553 - }
2554 - }
2555 - done = true;
2556 - i++;
2557 - break;
2558 - }
2559 - }
2560 - }
2561 - }
2562 - return 0;
2563 -}
2564 -
2565 -unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2566 -{
2567 -#ifndef HAVE_MULTIVOLUME
2568 - const int volume = 0;
2569 -#endif
2570 - struct bpb* fat_bpb = &fat_bpbs[volume];
2571 - return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2572 -}
2573 -
2574 -#ifdef HAVE_MULTIVOLUME
2575 -bool fat_ismounted(int volume)
2576 -{
2577 - return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2578 -}
2579 -#endif
 2+/***************************************************************************
 3+ * __________ __ ___.
 4+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
 5+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
 6+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
 7+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
 8+ * \/ \/ \/ \/ \/
 9+ * $Id: fat.c 25459 2010-04-03 22:02:09Z gevaerts $
 10+ *
 11+ * Copyright (C) 2002 by Linus Nielsen Feltzing
 12+ *
 13+ * This program is free software; you can redistribute it and/or
 14+ * modify it under the terms of the GNU General Public License
 15+ * as published by the Free Software Foundation; either version 2
 16+ * of the License, or (at your option) any later version.
 17+ *
 18+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 19+ * KIND, either express or implied.
 20+ *
 21+ ****************************************************************************/
 22+#include "global.h"
 23+#include "thread.h"
 24+#include "libc/include/string.h"
 25+#include "libc/include/stdio.h"
 26+#include "fat.h"
 27+#include "storage.h"
 28+#include "debug.h"
 29+#include "panic.h"
 30+#include "libc/include/ctype.h"
 31+
 32+#define BYTES2INT16(array,pos) \
 33+ (array[pos] | (array[pos+1] << 8 ))
 34+#define BYTES2INT32(array,pos) \
 35+ ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
 36+ ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
 37+
 38+#define FATTYPE_FAT12 0
 39+#define FATTYPE_FAT16 1
 40+#define FATTYPE_FAT32 2
 41+
 42+/* BPB offsets; generic */
 43+#define BS_JMPBOOT 0
 44+#define BS_OEMNAME 3
 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
 51+#define BPB_MEDIA 21
 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
 57+
 58+/* fat12/16 */
 59+#define BS_DRVNUM 36
 60+#define BS_RESERVED1 37
 61+#define BS_BOOTSIG 38
 62+#define BS_VOLID 39
 63+#define BS_VOLLAB 43
 64+#define BS_FILSYSTYPE 54
 65+
 66+/* fat32 */
 67+#define BPB_FATSZ32 36
 68+#define BPB_EXTFLAGS 40
 69+#define BPB_FSVER 42
 70+#define BPB_ROOTCLUS 44
 71+#define BPB_FSINFO 48
 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
 78+
 79+#define BPB_LAST_WORD 510
 80+
 81+
 82+/* attributes */
 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 )
 88+
 89+/* NTRES flags */
 90+#define FAT_NTRES_LC_NAME 0x08
 91+#define FAT_NTRES_LC_EXT 0x10
 92+
 93+#define FATDIR_NAME 0
 94+#define FATDIR_ATTR 11
 95+#define FATDIR_NTRES 12
 96+#define FATDIR_CRTTIMETENTH 13
 97+#define FATDIR_CRTTIME 14
 98+#define FATDIR_CRTDATE 16
 99+#define FATDIR_LSTACCDATE 18
 100+#define FATDIR_FSTCLUSHI 20
 101+#define FATDIR_WRTTIME 22
 102+#define FATDIR_WRTDATE 24
 103+#define FATDIR_FSTCLUSLO 26
 104+#define FATDIR_FILESIZE 28
 105+
 106+#define FATLONG_ORDER 0
 107+#define FATLONG_TYPE 12
 108+#define FATLONG_CHKSUM 13
 109+#define FATLONG_LAST_LONG_ENTRY 0x40
 110+#define FATLONG_NAME_BYTES_PER_ENTRY 26
 111+/* at most 20 LFN entries, keep coherent with fat_dir->longname size ! */
 112+#define FATLONG_MAX_ORDER 20
 113+
 114+#define FATLONG_NAME_CHUNKS 3
 115+static unsigned char FATLONG_NAME_POS[FATLONG_NAME_CHUNKS] = {1, 14, 28};
 116+static unsigned char FATLONG_NAME_SIZE[FATLONG_NAME_CHUNKS] = {10, 12, 4};
 117+
 118+#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
 119+#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
 120+#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
 121+#define DIR_ENTRY_SIZE 32
 122+#define NAME_BYTES_PER_ENTRY 13
 123+#define FAT_BAD_MARK 0x0ffffff7
 124+#define FAT_EOF_MARK 0x0ffffff8
 125+#define FAT_LONGNAME_PAD_BYTE 0xff
 126+#define FAT_LONGNAME_PAD_UCS 0xffff
 127+
 128+struct fsinfo {
 129+ unsigned long freecount; /* last known free cluster count */
 130+ unsigned long nextfree; /* first cluster to start looking for free
 131+ clusters, or 0xffffffff for no hint */
 132+};
 133+/* fsinfo offsets */
 134+#define FSINFO_FREECOUNT 488
 135+#define FSINFO_NEXTFREE 492
 136+
 137+/* Note: This struct doesn't hold the raw values after mounting if
 138+ * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
 139+ * physical sectors. */
 140+struct bpb
 141+{
 142+ int bpb_bytspersec; /* Bytes per sector, typically 512 */
 143+ unsigned int bpb_secperclus; /* Sectors per cluster */
 144+ int bpb_rsvdseccnt; /* Number of reserved sectors */
 145+ int bpb_numfats; /* Number of FAT structures, typically 2 */
 146+ int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
 147+ int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
 148+ int bpb_fatsz16; /* Number of used sectors per FAT structure */
 149+ unsigned long bpb_totsec32; /* Number of sectors on the volume
 150+ (new 32-bit) */
 151+ unsigned int last_word; /* 0xAA55 */
 152+
 153+ /**** FAT32 specific *****/
 154+ long bpb_fatsz32;
 155+ long bpb_rootclus;
 156+ long bpb_fsinfo;
 157+
 158+ /* variables for internal use */
 159+ unsigned long fatsize;
 160+ unsigned long totalsectors;
 161+ unsigned long rootdirsector;
 162+ unsigned long firstdatasector;
 163+ unsigned long startsector;
 164+ unsigned long dataclusters;
 165+ struct fsinfo fsinfo;
 166+#ifdef HAVE_FAT16SUPPORT
 167+ int bpb_rootentcnt; /* Number of dir entries in the root */
 168+ /* internals for FAT16 support */
 169+ bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
 170+ unsigned int rootdiroffset; /* sector offset of root dir relative to start
 171+ * of first pseudo cluster */
 172+#endif /* #ifdef HAVE_FAT16SUPPORT */
 173+#ifdef HAVE_MULTIVOLUME
 174+#ifdef HAVE_MULTIDRIVE
 175+ int drive; /* on which physical device is this located */
 176+#endif
 177+ bool mounted; /* flag if this volume is mounted */
 178+#endif
 179+};
 180+
 181+static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
 182+static bool initialized = false;
 183+
 184+static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
 185+static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
 186+static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
 187+static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
 188+ long secnum, bool dirty);
 189+static void unlock_fat_sector(IF_MV2(struct bpb* fat_bpb,)
 190+ long secnum);
 191+static void create_dos_name(const unsigned char *name, unsigned char *newname);
 192+static void randomize_dos_name(unsigned char *name);
 193+static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
 194+ unsigned long start);
 195+static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned long start,
 196+ long count, char* buf, bool write );
 197+
 198+#define FAT_CACHE_SIZE 4
 199+#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
 200+
 201+struct fat_cache_entry
 202+{
 203+ long secnum;
 204+ bool valid;
 205+ int locked;
 206+ bool dirty;
 207+#ifdef HAVE_MULTIVOLUME
 208+ struct bpb* fat_vol; /* shared cache for all volumes */
 209+#endif
 210+};
 211+
 212+static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE] CACHEALIGN_ATTR;
 213+static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
 214+static struct mutex cache_mutex;
 215+static struct mutex tempbuf_mutex;
 216+static char fat_tempbuf[SECTOR_SIZE] CACHEALIGN_ATTR;
 217+static bool tempbuf_locked;
 218+
 219+#if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
 220+void fat_lock(void)
 221+{
 222+ mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
 223+}
 224+
 225+void fat_unlock(void)
 226+{
 227+ mutex_unlock(&cache_mutex);
 228+}
 229+#endif
 230+
 231+static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster)
 232+{
 233+#ifndef HAVE_MULTIVOLUME
 234+ struct bpb* fat_bpb = &fat_bpbs[0];
 235+#endif
 236+#ifdef HAVE_FAT16SUPPORT
 237+ /* negative clusters (FAT16 root dir) don't get the 2 offset */
 238+ int zerocluster = cluster < 0 ? 0 : 2;
 239+#else
 240+ const long zerocluster = 2;
 241+#endif
 242+
 243+ if (cluster > (long)(fat_bpb->dataclusters + 1))
 244+ {
 245+ DEBUGF( "cluster2sec() - Bad cluster number (%ld)", cluster);
 246+ return -1;
 247+ }
 248+
 249+ return (cluster - zerocluster) * fat_bpb->bpb_secperclus
 250+ + fat_bpb->firstdatasector;
 251+}
 252+
 253+void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
 254+{
 255+#ifndef HAVE_MULTIVOLUME
 256+ const int volume = 0;
 257+#endif
 258+ struct bpb* fat_bpb = &fat_bpbs[volume];
 259+ if (size)
 260+ *size = fat_bpb->dataclusters * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
 261+ if (free)
 262+ *free = fat_bpb->fsinfo.freecount * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
 263+}
 264+
 265+void fat_init(void)
 266+{
 267+ unsigned int i;
 268+
 269+ if (!initialized)
 270+ {
 271+ initialized = true;
 272+ mutex_init(&cache_mutex);
 273+ mutex_init(&tempbuf_mutex);
 274+ tempbuf_locked = false;
 275+ }
 276+
 277+ /* mark the FAT cache as unused */
 278+ for(i = 0;i < FAT_CACHE_SIZE;i++)
 279+ {
 280+ fat_cache[i].secnum = -1;
 281+ fat_cache[i].valid = false;
 282+ fat_cache[i].locked = 0;
 283+ fat_cache[i].dirty = false;
 284+#ifdef HAVE_MULTIVOLUME
 285+ fat_cache[i].fat_vol = NULL;
 286+#endif
 287+ }
 288+#ifdef HAVE_MULTIVOLUME
 289+ /* mark the possible volumes as not mounted */
 290+ for (i=0; i<NUM_VOLUMES;i++)
 291+ {
 292+ fat_bpbs[i].mounted = false;
 293+ }
 294+#endif
 295+}
 296+
 297+int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
 298+{
 299+#ifndef HAVE_MULTIVOLUME
 300+ const int volume = 0;
 301+#endif
 302+ struct bpb* fat_bpb = &fat_bpbs[volume];
 303+ int rc;
 304+ int secmult;
 305+ long datasec;
 306+#ifdef HAVE_FAT16SUPPORT
 307+ int rootdirsectors;
 308+#endif
 309+
 310+ /* Read the sector */
 311+ unsigned char* buf = fat_get_sector_buffer();
 312+ rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
 313+ if(rc)
 314+ {
 315+ fat_release_sector_buffer();
 316+ DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)", rc);
 317+ return rc * 10 - 1;
 318+ }
 319+
 320+ memset(fat_bpb, 0, sizeof(struct bpb));
 321+ fat_bpb->startsector = startsector;
 322+#ifdef HAVE_MULTIDRIVE
 323+ fat_bpb->drive = drive;
 324+#endif
 325+
 326+ fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
 327+ secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
 328+ /* Sanity check is performed later */
 329+
 330+ fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
 331+ fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT);
 332+ fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
 333+ fat_bpb->bpb_media = buf[BPB_MEDIA];
 334+ fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
 335+ fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
 336+ fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
 337+ fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
 338+ fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
 339+
 340+ /* calculate a few commonly used values */
 341+ if (fat_bpb->bpb_fatsz16 != 0)
 342+ fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
 343+ else
 344+ fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
 345+
 346+ if (fat_bpb->bpb_totsec16 != 0)
 347+ fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
 348+ else
 349+ fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
 350+
 351+#ifdef HAVE_FAT16SUPPORT
 352+ fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
 353+ if (!fat_bpb->bpb_bytspersec)
 354+ {
 355+ fat_release_sector_buffer();
 356+ return -2;
 357+ }
 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 */
 361+
 362+ fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
 363+#ifdef HAVE_FAT16SUPPORT
 364+ + rootdirsectors
 365+#endif
 366+ + fat_bpb->bpb_numfats * fat_bpb->fatsize;
 367+
 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;
 372+ else
 373+ {
 374+ fat_release_sector_buffer();
 375+ return -2;
 376+ }
 377+
 378+#ifdef TEST_FAT
 379+ /*
 380+ we are sometimes testing with "illegally small" fat32 images,
 381+ so we don't use the proper fat32 test case for test code
 382+ */
 383+ if ( fat_bpb->bpb_fatsz16 )
 384+#else
 385+ if ( fat_bpb->dataclusters < 65525 )
 386+#endif
 387+ { /* FAT16 */
 388+#ifdef HAVE_FAT16SUPPORT
 389+ fat_bpb->is_fat16 = true;
 390+ if (fat_bpb->dataclusters < 4085)
 391+ { /* FAT12 */
 392+ fat_release_sector_buffer();
 393+ DEBUGF("This is FAT12. Go away!");
 394+ return -2;
 395+ }
 396+#else /* #ifdef HAVE_FAT16SUPPORT */
 397+ fat_release_sector_buffer();
 398+ DEBUGF("This is not FAT32. Go away!");
 399+ return -2;
 400+#endif /* #ifndef HAVE_FAT16SUPPORT */
 401+ }
 402+
 403+#ifdef HAVE_FAT16SUPPORT
 404+ if (fat_bpb->is_fat16)
 405+ { /* FAT16 specific part of BPB */
 406+ int dirclusters;
 407+ fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
 408+ + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
 409+ dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
 410+ / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
 411+ /* I assign negative pseudo cluster numbers for the root directory,
 412+ their range is counted upward until -1. */
 413+ fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
 414+ fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
 415+ - rootdirsectors;
 416+ }
 417+ else
 418+#endif /* #ifdef HAVE_FAT16SUPPORT */
 419+ { /* FAT32 specific part of BPB */
 420+ fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
 421+ fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
 422+ fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,)
 423+ fat_bpb->bpb_rootclus);
 424+ }
 425+
 426+ rc = bpb_is_sane(IF_MV(fat_bpb));
 427+ if (rc < 0)
 428+ {
 429+ fat_release_sector_buffer();
 430+ DEBUGF( "fat_mount() - BPB is not sane");
 431+ return rc * 10 - 3;
 432+ }
 433+
 434+#ifdef HAVE_FAT16SUPPORT
 435+ if (fat_bpb->is_fat16)
 436+ {
 437+ fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
 438+ fat_bpb->fsinfo.nextfree = 0xffffffff;
 439+ }
 440+ else
 441+#endif /* #ifdef HAVE_FAT16SUPPORT */
 442+ {
 443+ /* Read the fsinfo sector */
 444+ rc = storage_read_sectors(IF_MD2(drive,)
 445+ startsector + fat_bpb->bpb_fsinfo, 1, buf);
 446+ if (rc < 0)
 447+ {
 448+ fat_release_sector_buffer();
 449+ DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)", rc);
 450+ return rc * 10 - 4;
 451+ }
 452+ fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
 453+ fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
 454+ }
 455+ fat_release_sector_buffer();
 456+
 457+ /* calculate freecount if unset */
 458+ if ( fat_bpb->fsinfo.freecount == 0xffffffff )
 459+ {
 460+ fat_recalc_free(IF_MV(volume));
 461+ }
 462+
 463+ DEBUGF("Freecount: %ld",fat_bpb->fsinfo.freecount);
 464+ DEBUGF("Nextfree: 0x%lx",fat_bpb->fsinfo.nextfree);
 465+ DEBUGF("Cluster count: 0x%lx",fat_bpb->dataclusters);
 466+ DEBUGF("Sectors per cluster: %d",fat_bpb->bpb_secperclus);
 467+ DEBUGF("FAT sectors: 0x%lx",fat_bpb->fatsize);
 468+
 469+#ifdef HAVE_MULTIVOLUME
 470+ fat_bpb->mounted = true;
 471+#endif
 472+
 473+ return 0;
 474+}
 475+
 476+#ifdef HAVE_HOTSWAP
 477+int fat_unmount(int volume, bool flush)
 478+{
 479+ int rc;
 480+#ifdef HAVE_MULTIVOLUME
 481+ struct bpb* fat_bpb = &fat_bpbs[volume];
 482+#else
 483+ (void)volume;
 484+#endif
 485+
 486+ if(flush)
 487+ {
 488+ rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
 489+ }
 490+ else
 491+ { /* volume is not accessible any more, e.g. MMC removed */
 492+ int i;
 493+ mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
 494+ for(i = 0;i < FAT_CACHE_SIZE;i++)
 495+ {
 496+ struct fat_cache_entry *fce = &fat_cache[i];
 497+ if((fce->valid || fce->locked)
 498+#ifdef HAVE_MULTIVOLUME
 499+ && fce->fat_vol == fat_bpb
 500+#endif
 501+ )
 502+ {
 503+ fce->valid = false; /* discard all from that volume */
 504+ fce->locked = 0;
 505+ fce->dirty = false;
 506+ }
 507+ }
 508+ mutex_unlock(&cache_mutex);
 509+ rc = 0;
 510+ }
 511+#ifdef HAVE_MULTIVOLUME
 512+ fat_bpb->mounted = false;
 513+#endif
 514+ return rc;
 515+}
 516+#endif /* #ifdef HAVE_HOTSWAP */
 517+
 518+void fat_recalc_free(IF_MV_NONVOID(int volume))
 519+{
 520+#ifndef HAVE_MULTIVOLUME
 521+ const int volume = 0;
 522+#endif
 523+ struct bpb* fat_bpb = &fat_bpbs[volume];
 524+ long free = 0;
 525+ unsigned long i;
 526+#ifdef HAVE_FAT16SUPPORT
 527+ if (fat_bpb->is_fat16)
 528+ {
 529+ for (i = 0; i<fat_bpb->fatsize; i++) {
 530+ unsigned int j;
 531+ unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
 532+ for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
 533+ unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
 534+ if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
 535+ break;
 536+
 537+ if (letoh16(fat[j]) == 0x0000) {
 538+ free++;
 539+ if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
 540+ fat_bpb->fsinfo.nextfree = c;
 541+ }
 542+ }
 543+ unlock_fat_sector(IF_MV2(fat_bpb,) i);
 544+ }
 545+ }
 546+ else
 547+#endif /* #ifdef HAVE_FAT16SUPPORT */
 548+ {
 549+ for (i = 0; i<fat_bpb->fatsize; i++) {
 550+ unsigned int j;
 551+ unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
 552+ for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
 553+ unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
 554+ if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
 555+ break;
 556+
 557+ if (!(letoh32(fat[j]) & 0x0fffffff)) {
 558+ free++;
 559+ if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
 560+ fat_bpb->fsinfo.nextfree = c;
 561+ }
 562+ }
 563+ unlock_fat_sector(IF_MV2(fat_bpb,) i);
 564+ }
 565+ }
 566+ fat_bpb->fsinfo.freecount = free;
 567+ update_fsinfo(IF_MV(fat_bpb));
 568+}
 569+
 570+static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
 571+{
 572+#ifndef HAVE_MULTIVOLUME
 573+ struct bpb* fat_bpb = &fat_bpbs[0];
 574+#endif
 575+ if(fat_bpb->bpb_bytspersec % SECTOR_SIZE)
 576+ {
 577+ DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)",
 578+ fat_bpb->bpb_bytspersec);
 579+ return -1;
 580+ }
 581+ if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec
 582+ > 128L*1024L)
 583+ {
 584+ DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
 585+ "(%d * %d = %d)",
 586+ fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
 587+ fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
 588+ return -2;
 589+ }
 590+ if(fat_bpb->bpb_numfats != 2)
 591+ {
 592+ DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)",
 593+ fat_bpb->bpb_numfats);
 594+ }
 595+ if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
 596+ {
 597+ DEBUGF( "bpb_is_sane() - Warning: Non-standard "
 598+ "media type (0x%02x)",
 599+ fat_bpb->bpb_media);
 600+ }
 601+ if(fat_bpb->last_word != 0xaa55)
 602+ {
 603+ DEBUGF( "bpb_is_sane() - Error: Last word is not "
 604+ "0xaa55 (0x%04x)", fat_bpb->last_word);
 605+ return -3;
 606+ }
 607+
 608+ if (fat_bpb->fsinfo.freecount >
 609+ (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
 610+ fat_bpb->bpb_secperclus)
 611+ {
 612+ DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
 613+ "(0x%04lx)", fat_bpb->fsinfo.freecount);
 614+ return -4;
 615+ }
 616+
 617+ return 0;
 618+}
 619+
 620+static void flush_fat_sector(struct fat_cache_entry *fce,
 621+ unsigned char *sectorbuf)
 622+{
 623+ int rc;
 624+ long secnum;
 625+
 626+ /* With multivolume, use only the FAT info from the cached sector! */
 627+#ifdef HAVE_MULTIVOLUME
 628+ secnum = fce->secnum + fce->fat_vol->startsector;
 629+#else
 630+ secnum = fce->secnum + fat_bpbs[0].startsector;
 631+#endif
 632+
 633+ /* Write to the first FAT */
 634+ rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
 635+ secnum, 1,
 636+ sectorbuf);
 637+ if(rc < 0)
 638+ {
 639+ panicf(PANIC_KILLUSERTHREADS, "flush_fat_sector() - Could not write sector %ld"
 640+ " (error %d)",
 641+ secnum, rc);
 642+ }
 643+#ifdef HAVE_MULTIVOLUME
 644+ if(fce->fat_vol->bpb_numfats > 1)
 645+#else
 646+ if(fat_bpbs[0].bpb_numfats > 1)
 647+#endif
 648+ {
 649+ /* Write to the second FAT */
 650+#ifdef HAVE_MULTIVOLUME
 651+ secnum += fce->fat_vol->fatsize;
 652+#else
 653+ secnum += fat_bpbs[0].fatsize;
 654+#endif
 655+ rc = storage_write_sectors(IF_MD2(fce->fat_vol->drive,)
 656+ secnum, 1, sectorbuf);
 657+ if(rc < 0)
 658+ {
 659+ panicf(PANIC_KILLUSERTHREADS, "flush_fat_sector() - Could not write sector %ld"
 660+ " (error %d)",
 661+ secnum, rc);
 662+ }
 663+ }
 664+ fce->dirty = false;
 665+}
 666+
 667+static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
 668+ long fatsector, bool dirty)
 669+{
 670+#ifndef HAVE_MULTIVOLUME
 671+ struct bpb* fat_bpb = &fat_bpbs[0];
 672+#endif
 673+ long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
 674+ int cache_index = secnum & FAT_CACHE_MASK;
 675+ struct fat_cache_entry *fce = &fat_cache[cache_index];
 676+ unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
 677+ int rc;
 678+
 679+ mutex_lock(&cache_mutex, TIMEOUT_BLOCK); /* make changes atomic */
 680+
 681+ /* Delete the cache entry if it isn't the sector we want */
 682+ if(fce->valid && (fce->secnum != secnum
 683+#ifdef HAVE_MULTIVOLUME
 684+ || fce->fat_vol != fat_bpb
 685+#endif
 686+ ))
 687+ {
 688+ while (fce->locked) sleep(1000);
 689+ /* Write back if it is dirty */
 690+ if(fce->dirty)
 691+ {
 692+ flush_fat_sector(fce, sectorbuf);
 693+ }
 694+ fce->valid = false;
 695+ }
 696+
 697+ /* Load the sector if it is not cached */
 698+ if(!fce->valid)
 699+ {
 700+ rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
 701+ secnum + fat_bpb->startsector,1,
 702+ sectorbuf);
 703+ if(rc < 0)
 704+ {
 705+ DEBUGF( "cache_fat_sector() - Could not read sector %ld"
 706+ " (error %d)", secnum, rc);
 707+ mutex_unlock(&cache_mutex);
 708+ return NULL;
 709+ }
 710+ fce->valid = true;
 711+ fce->secnum = secnum;
 712+#ifdef HAVE_MULTIVOLUME
 713+ fce->fat_vol = fat_bpb;
 714+#endif
 715+ }
 716+ fce->locked++;
 717+ if (dirty)
 718+ fce->dirty = true; /* dirt remains, sticky until flushed */
 719+ mutex_unlock(&cache_mutex);
 720+ return sectorbuf;
 721+}
 722+
 723+static void unlock_fat_sector(IF_MV2(struct bpb* fat_bpb,) long fatsector)
 724+{
 725+#ifndef HAVE_MULTIVOLUME
 726+ struct bpb* fat_bpb = &fat_bpbs[0];
 727+#endif
 728+ long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
 729+ int cache_index = secnum & FAT_CACHE_MASK;
 730+ fat_cache[cache_index].locked--;
 731+}
 732+
 733+void* fat_get_sector_buffer()
 734+{
 735+ mutex_lock(&tempbuf_mutex, TIMEOUT_BLOCK);
 736+ if (tempbuf_locked)
 737+ panicf(PANIC_KILLUSERTHREADS, "FAT: Tried to lock temporary sector buffer twice!");
 738+ tempbuf_locked = true;
 739+ return fat_tempbuf;
 740+}
 741+
 742+void fat_release_sector_buffer()
 743+{
 744+ tempbuf_locked = false;
 745+ mutex_unlock(&tempbuf_mutex);
 746+}
 747+
 748+static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,)
 749+ unsigned long startcluster)
 750+{
 751+#ifndef HAVE_MULTIVOLUME
 752+ struct bpb* fat_bpb = &fat_bpbs[0];
 753+#endif
 754+ unsigned long sector;
 755+ unsigned long offset;
 756+ unsigned long i;
 757+
 758+#ifdef HAVE_FAT16SUPPORT
 759+ if (fat_bpb->is_fat16)
 760+ {
 761+ sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
 762+ offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
 763+
 764+ for (i = 0; i<fat_bpb->fatsize; i++) {
 765+ unsigned int j;
 766+ unsigned int nr = (i + sector) % fat_bpb->fatsize;
 767+ unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
 768+ if ( !fat )
 769+ break;
 770+ for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
 771+ int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
 772+ if (letoh16(fat[k]) == 0x0000) {
 773+ unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
 774+ /* Ignore the reserved clusters 0 & 1, and also
 775+ cluster numbers out of bounds */
 776+ if ( c < 2 || c > fat_bpb->dataclusters+1 )
 777+ continue;
 778+ unlock_fat_sector(IF_MV2(fat_bpb,) nr);
 779+ DEBUGF("find_free_cluster(%x) == %x",startcluster,c);
 780+ fat_bpb->fsinfo.nextfree = c;
 781+ return c;
 782+ }
 783+ }
 784+ unlock_fat_sector(IF_MV2(fat_bpb,) nr);
 785+ offset = 0;
 786+ }
 787+ }
 788+ else
 789+#endif /* #ifdef HAVE_FAT16SUPPORT */
 790+ {
 791+ sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
 792+ offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
 793+
 794+ for (i = 0; i<fat_bpb->fatsize; i++) {
 795+ unsigned int j;
 796+ unsigned long nr = (i + sector) % fat_bpb->fatsize;
 797+ unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
 798+ if ( !fat )
 799+ break;
 800+ for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
 801+ int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
 802+ if (!(letoh32(fat[k]) & 0x0fffffff)) {
 803+ unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
 804+ /* Ignore the reserved clusters 0 & 1, and also
 805+ cluster numbers out of bounds */
 806+ if ( c < 2 || c > fat_bpb->dataclusters+1 )
 807+ continue;
 808+ unlock_fat_sector(IF_MV2(fat_bpb,) nr);
 809+ DEBUGF("find_free_cluster(%lx) == %lx",startcluster,c);
 810+ fat_bpb->fsinfo.nextfree = c;
 811+ return c;
 812+ }
 813+ }
 814+ unlock_fat_sector(IF_MV2(fat_bpb,) nr);
 815+ offset = 0;
 816+ }
 817+ }
 818+
 819+ DEBUGF("find_free_cluster(%lx) == 0",startcluster);
 820+ return 0; /* 0 is an illegal cluster number */
 821+}
 822+
 823+static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry,
 824+ unsigned long val)
 825+{
 826+#ifndef HAVE_MULTIVOLUME
 827+ struct bpb* fat_bpb = &fat_bpbs[0];
 828+#endif
 829+#ifdef HAVE_FAT16SUPPORT
 830+ if (fat_bpb->is_fat16)
 831+ {
 832+ int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
 833+ int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
 834+ unsigned short* sec;
 835+
 836+ val &= 0xFFFF;
 837+
 838+ DEBUGF("update_fat_entry(%x,%x)",entry,val);
 839+
 840+ if (entry==val)
 841+ panicf(PANIC_KILLUSERTHREADS, "Creating FAT loop: %lx,%lx",entry,val);
 842+
 843+ if ( entry < 2 )
 844+ panicf(PANIC_KILLUSERTHREADS, "Updating reserved FAT entry %ld.",entry);
 845+
 846+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
 847+ if (!sec)
 848+ {
 849+ DEBUGF( "update_fat_entry() - Could not cache sector %d", sector);
 850+ return -1;
 851+ }
 852+
 853+ if ( val ) {
 854+ if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
 855+ fat_bpb->fsinfo.freecount--;
 856+ }
 857+ else {
 858+ if (letoh16(sec[offset]))
 859+ fat_bpb->fsinfo.freecount++;
 860+ }
 861+
 862+ DEBUGF("update_fat_entry: %d free clusters",
 863+ fat_bpb->fsinfo.freecount);
 864+
 865+ sec[offset] = htole16(val);
 866+ unlock_fat_sector(IF_MV2(fat_bpb,) sector);
 867+ }
 868+ else
 869+#endif /* #ifdef HAVE_FAT16SUPPORT */
 870+ {
 871+ long sector = entry / CLUSTERS_PER_FAT_SECTOR;
 872+ int offset = entry % CLUSTERS_PER_FAT_SECTOR;
 873+ unsigned long* sec;
 874+
 875+ DEBUGF("update_fat_entry(%lx,%lx)",entry,val);
 876+
 877+ if (entry==val)
 878+ panicf(PANIC_KILLUSERTHREADS, "Creating FAT loop: %lx,%lx",entry,val);
 879+
 880+ if ( entry < 2 )
 881+ panicf(PANIC_KILLUSERTHREADS, "Updating reserved FAT entry %ld.",entry);
 882+
 883+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
 884+ if (!sec)
 885+ {
 886+ DEBUGF("update_fat_entry() - Could not cache sector %ld", sector);
 887+ return -1;
 888+ }
 889+
 890+ if ( val ) {
 891+ if (!(letoh32(sec[offset]) & 0x0fffffff) &&
 892+ fat_bpb->fsinfo.freecount > 0)
 893+ fat_bpb->fsinfo.freecount--;
 894+ }
 895+ else {
 896+ if (letoh32(sec[offset]) & 0x0fffffff)
 897+ fat_bpb->fsinfo.freecount++;
 898+ }
 899+
 900+ DEBUGF("update_fat_entry: %ld free clusters",
 901+ fat_bpb->fsinfo.freecount);
 902+
 903+ /* don't change top 4 bits */
 904+ sec[offset] &= htole32(0xf0000000);
 905+ sec[offset] |= htole32(val & 0x0fffffff);
 906+ unlock_fat_sector(IF_MV2(fat_bpb,) sector);
 907+ }
 908+
 909+ return 0;
 910+}
 911+
 912+static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
 913+{
 914+#ifdef HAVE_FAT16SUPPORT
 915+#ifndef HAVE_MULTIVOLUME
 916+ struct bpb* fat_bpb = &fat_bpbs[0];
 917+#endif
 918+ if (fat_bpb->is_fat16)
 919+ {
 920+ int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
 921+ int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
 922+ unsigned short* sec;
 923+
 924+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
 925+ if (!sec)
 926+ {
 927+ DEBUGF( "read_fat_entry() - Could not cache sector %d", sector);
 928+ return -1;
 929+ }
 930+
 931+ long val = letoh16(sec[offset]);
 932+ unlock_fat_sector(IF_MV2(fat_bpb,) sector);
 933+
 934+ return val;
 935+ }
 936+ else
 937+#endif /* #ifdef HAVE_FAT16SUPPORT */
 938+ {
 939+ long sector = entry / CLUSTERS_PER_FAT_SECTOR;
 940+ int offset = entry % CLUSTERS_PER_FAT_SECTOR;
 941+ unsigned long* sec;
 942+
 943+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
 944+ if (!sec)
 945+ {
 946+ DEBUGF( "read_fat_entry() - Could not cache sector %ld", sector);
 947+ return -1;
 948+ }
 949+
 950+ long val = letoh32(sec[offset]) & 0x0fffffff;
 951+ unlock_fat_sector(IF_MV2(fat_bpb,) sector);
 952+
 953+ return val;
 954+ }
 955+}
 956+
 957+static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
 958+{
 959+ long next_cluster;
 960+ long eof_mark = FAT_EOF_MARK;
 961+
 962+#ifdef HAVE_FAT16SUPPORT
 963+#ifndef HAVE_MULTIVOLUME
 964+ struct bpb* fat_bpb = &fat_bpbs[0];
 965+#endif
 966+ if (fat_bpb->is_fat16)
 967+ {
 968+ eof_mark &= 0xFFFF; /* only 16 bit */
 969+ if (cluster < 0) /* FAT16 root dir */
 970+ return cluster + 1; /* don't use the FAT */
 971+ }
 972+#endif
 973+ next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
 974+
 975+ /* is this last cluster in chain? */
 976+ if ( next_cluster >= eof_mark )
 977+ return 0;
 978+ else
 979+ return next_cluster;
 980+}
 981+
 982+static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
 983+{
 984+#ifndef HAVE_MULTIVOLUME
 985+ struct bpb* fat_bpb = &fat_bpbs[0];
 986+#endif
 987+ unsigned long* intptr;
 988+ int rc;
 989+
 990+#ifdef HAVE_FAT16SUPPORT
 991+ if (fat_bpb->is_fat16)
 992+ return 0; /* FAT16 has no FsInfo */
 993+#endif /* #ifdef HAVE_FAT16SUPPORT */
 994+
 995+ /* update fsinfo */
 996+ unsigned char* fsinfo = fat_get_sector_buffer();
 997+ rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
 998+ fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
 999+ if (rc < 0)
 1000+ {
 1001+ fat_release_sector_buffer();
 1002+ DEBUGF( "update_fsinfo() - Couldn't read FSInfo (error code %d)", rc);
 1003+ return rc * 10 - 1;
 1004+ }
 1005+ intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
 1006+ *intptr = htole32(fat_bpb->fsinfo.freecount);
 1007+
 1008+ intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
 1009+ *intptr = htole32(fat_bpb->fsinfo.nextfree);
 1010+
 1011+ rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
 1012+ fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
 1013+ fat_release_sector_buffer();
 1014+ if (rc < 0)
 1015+ {
 1016+ DEBUGF( "update_fsinfo() - Couldn't write FSInfo (error code %d)", rc);
 1017+ return rc * 10 - 2;
 1018+ }
 1019+
 1020+ return 0;
 1021+}
 1022+
 1023+static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
 1024+{
 1025+ int i;
 1026+ int rc;
 1027+ unsigned char *sec;
 1028+ DEBUGF("flush_fat()");
 1029+
 1030+ mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
 1031+ for(i = 0;i < FAT_CACHE_SIZE;i++)
 1032+ {
 1033+ struct fat_cache_entry *fce = &fat_cache[i];
 1034+ if(fce->valid
 1035+#ifdef HAVE_MULTIVOLUME
 1036+ && fce->fat_vol == fat_bpb
 1037+#endif
 1038+ && fce->dirty)
 1039+ {
 1040+ sec = fat_cache_sectors[i];
 1041+ flush_fat_sector(fce, sec);
 1042+ }
 1043+ }
 1044+ mutex_unlock(&cache_mutex);
 1045+
 1046+ rc = update_fsinfo(IF_MV(fat_bpb));
 1047+ if (rc < 0)
 1048+ return rc * 10 - 3;
 1049+
 1050+ return 0;
 1051+}
 1052+
 1053+static void fat_time(unsigned short* date,
 1054+ unsigned short* time,
 1055+ unsigned short* tenth )
 1056+{
 1057+#if CONFIG_RTC
 1058+ struct tm* tm = get_time();
 1059+
 1060+ if (date)
 1061+ *date = ((tm->tm_year - 80) << 9) |
 1062+ ((tm->tm_mon + 1) << 5) |
 1063+ tm->tm_mday;
 1064+
 1065+ if (time)
 1066+ *time = (tm->tm_hour << 11) |
 1067+ (tm->tm_min << 5) |
 1068+ (tm->tm_sec >> 1);
 1069+
 1070+ if (tenth)
 1071+ *tenth = (tm->tm_sec & 1) * 100;
 1072+#else
 1073+
 1074+ if (date) *date = 0;
 1075+ if (time) *time = 0;
 1076+ if (tenth) *tenth = 0;
 1077+
 1078+#endif /* CONFIG_RTC */
 1079+}
 1080+
 1081+static int write_long_name(struct fat_file* file,
 1082+ unsigned int firstentry,
 1083+ unsigned int numentries,
 1084+ const unsigned char* name,
 1085+ const unsigned char* shortname,
 1086+ bool is_directory)
 1087+{
 1088+ unsigned char* entry;
 1089+ unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
 1090+ unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
 1091+ unsigned char chksum = 0;
 1092+ unsigned int i, j=0;
 1093+ unsigned int nameidx=0, namelen = strlen(name);
 1094+ int rc;
 1095+ unsigned short name_utf16[namelen + 1];
 1096+
 1097+ DEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)",
 1098+ file->firstcluster, firstentry, numentries, name);
 1099+
 1100+ rc = fat_seek(file, sector);
 1101+ if (rc<0)
 1102+ return rc * 10 - 1;
 1103+
 1104+ unsigned char* buf = fat_get_sector_buffer();
 1105+ rc = fat_readwrite(file, 1, buf, false);
 1106+ if (rc<1)
 1107+ {
 1108+ fat_release_sector_buffer();
 1109+ return rc * 10 - 2;
 1110+ }
 1111+
 1112+ /* calculate shortname checksum */
 1113+ for (i=11; i>0; i--)
 1114+ chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
 1115+
 1116+ /* calc position of last name segment */
 1117+ if ( namelen > NAME_BYTES_PER_ENTRY )
 1118+ for (nameidx=0;
 1119+ nameidx < (namelen - NAME_BYTES_PER_ENTRY);
 1120+ nameidx += NAME_BYTES_PER_ENTRY);
 1121+
 1122+ /* we need to convert the name first */
 1123+ /* since it is written in reverse order */
 1124+ for (i = 0; i <= namelen; i++)
 1125+ name_utf16[i] = *(name++);
 1126+
 1127+ for (i=0; i < numentries; i++) {
 1128+ /* new sector? */
 1129+ if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
 1130+ /* update current sector */
 1131+ rc = fat_seek(file, sector);
 1132+ if (rc<0)
 1133+ {
 1134+ fat_release_sector_buffer();
 1135+ return rc * 10 - 3;
 1136+ }
 1137+
 1138+ rc = fat_readwrite(file, 1, buf, true);
 1139+ if (rc<1)
 1140+ {
 1141+ fat_release_sector_buffer();
 1142+ return rc * 10 - 4;
 1143+ }
 1144+
 1145+ /* read next sector */
 1146+ rc = fat_readwrite(file, 1, buf, false);
 1147+ if (rc<0) {
 1148+ fat_release_sector_buffer();
 1149+ DEBUGF("Failed writing new sector: %d",rc);
 1150+ return rc * 10 - 5;
 1151+ }
 1152+ if (rc==0)
 1153+ /* end of dir */
 1154+ memset(buf, 0, SECTOR_SIZE);
 1155+
 1156+ sector++;
 1157+ idx = 0;
 1158+ }
 1159+
 1160+ entry = buf + idx * DIR_ENTRY_SIZE;
 1161+
 1162+ /* verify this entry is free */
 1163+ if (entry[0] && entry[0] != 0xe5 )
 1164+ {
 1165+ fat_release_sector_buffer();
 1166+ panicf(PANIC_KILLUSERTHREADS, "Dir entry %d in sector %x is not free! "
 1167+ "%02x %02x %02x %02x",
 1168+ idx, sector,
 1169+ entry[0], entry[1], entry[2], entry[3]);
 1170+ }
 1171+
 1172+ memset(entry, 0, DIR_ENTRY_SIZE);
 1173+ if ( i+1 < numentries ) {
 1174+ /* longname entry */
 1175+ unsigned int k, l = nameidx;
 1176+
 1177+ entry[FATLONG_ORDER] = numentries-i-1;
 1178+ if (i==0) {
 1179+ /* mark this as last long entry */
 1180+ entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
 1181+
 1182+ /* pad name with 0xffff */
 1183+ for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
 1184+ for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
 1185+ for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
 1186+ };
 1187+ /* set name */
 1188+ for (k=0; k<5 && l <= namelen; k++) {
 1189+ entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
 1190+ entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
 1191+ }
 1192+ for (k=0; k<6 && l <= namelen; k++) {
 1193+ entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
 1194+ entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
 1195+ }
 1196+ for (k=0; k<2 && l <= namelen; k++) {
 1197+ entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
 1198+ entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
 1199+ }
 1200+
 1201+ entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
 1202+ entry[FATDIR_FSTCLUSLO] = 0;
 1203+ entry[FATLONG_TYPE] = 0;
 1204+ entry[FATLONG_CHKSUM] = chksum;
 1205+ DEBUGF("Longname entry %d (%d): %s", idx, nameidx, name+nameidx);
 1206+ }
 1207+ else {
 1208+ /* shortname entry */
 1209+ unsigned short date=0, time=0, tenth=0;
 1210+ DEBUGF("Shortname entry: %s", shortname);
 1211+ memcpy(entry + FATDIR_NAME, shortname, 11);
 1212+ entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
 1213+ entry[FATDIR_NTRES] = 0;
 1214+
 1215+ fat_time(&date, &time, &tenth);
 1216+ entry[FATDIR_CRTTIMETENTH] = tenth;
 1217+ *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
 1218+ *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
 1219+ *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
 1220+ *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
 1221+ *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
 1222+ }
 1223+ idx++;
 1224+ nameidx -= NAME_BYTES_PER_ENTRY;
 1225+ }
 1226+
 1227+ /* update last sector */
 1228+ rc = fat_seek(file, sector);
 1229+ if (rc<0)
 1230+ {
 1231+ fat_release_sector_buffer();
 1232+ return rc * 10 - 6;
 1233+ }
 1234+
 1235+ rc = fat_readwrite(file, 1, buf, true);
 1236+ fat_release_sector_buffer();
 1237+ if (rc<1)
 1238+ return rc * 10 - 7;
 1239+
 1240+ DEBUGF("write_long_name: success");
 1241+ return 0;
 1242+}
 1243+
 1244+static int fat_checkname(const unsigned char* newname)
 1245+{
 1246+ static const char invalid_chars[] = "\"*/:<>?\\|";
 1247+ int len = strlen(newname);
 1248+ /* More sanity checks are probably needed */
 1249+ if (len > 255 || newname[len - 1] == '.')
 1250+ {
 1251+ return -1;
 1252+ }
 1253+ while (*newname)
 1254+ {
 1255+ if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
 1256+ return -1;
 1257+ newname++;
 1258+ }
 1259+ /* check trailing space(s) */
 1260+ if(*(--newname) == ' ')
 1261+ return -1;
 1262+
 1263+ return 0;
 1264+}
 1265+
 1266+static int add_dir_entry(struct fat_dir* dir,
 1267+ struct fat_file* file,
 1268+ const char* name,
 1269+ bool is_directory,
 1270+ bool dotdir)
 1271+{
 1272+#ifdef HAVE_MULTIVOLUME
 1273+ struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
 1274+#else
 1275+ struct bpb* fat_bpb = &fat_bpbs[0];
 1276+#endif
 1277+ unsigned char shortname[12];
 1278+ int rc;
 1279+ unsigned int sector;
 1280+ bool done = false;
 1281+ int entries_needed, entries_found = 0;
 1282+ int firstentry;
 1283+
 1284+ DEBUGF( "add_dir_entry(%s,%lx)",
 1285+ name, file->firstcluster);
 1286+
 1287+ /* Don't check dotdirs name for validity */
 1288+ if (dotdir == false) {
 1289+ rc = fat_checkname(name);
 1290+ if (rc < 0) {
 1291+ /* filename is invalid */
 1292+ return rc * 10 - 1;
 1293+ }
 1294+ }
 1295+
 1296+#ifdef HAVE_MULTIVOLUME
 1297+ file->volume = dir->file.volume; /* inherit the volume, to make sure */
 1298+#endif
 1299+
 1300+ /* The "." and ".." directory entries must not be long names */
 1301+ if(dotdir) {
 1302+ int i;
 1303+ strlcpy(shortname, name, 12);
 1304+ for(i = strlen(shortname); i < 12; i++)
 1305+ shortname[i] = ' ';
 1306+
 1307+ entries_needed = 1;
 1308+ } else {
 1309+ create_dos_name(name, shortname);
 1310+
 1311+ /* one dir entry needed for every 13 bytes of filename,
 1312+ plus one entry for the short name */
 1313+ entries_needed = (strlen(name) + (NAME_BYTES_PER_ENTRY-1))
 1314+ / NAME_BYTES_PER_ENTRY + 1;
 1315+ }
 1316+
 1317+ unsigned char* buf = fat_get_sector_buffer();
 1318+ restart:
 1319+ firstentry = -1;
 1320+
 1321+ rc = fat_seek(&dir->file, 0);
 1322+ if (rc < 0)
 1323+ {
 1324+ fat_release_sector_buffer();
 1325+ return rc * 10 - 2;
 1326+ }
 1327+
 1328+ /* step 1: search for free entries and check for duplicate shortname */
 1329+ for (sector = 0; !done; sector++)
 1330+ {
 1331+ unsigned int i;
 1332+
 1333+ rc = fat_readwrite(&dir->file, 1, buf, false);
 1334+ if (rc < 0) {
 1335+ fat_release_sector_buffer();
 1336+ DEBUGF( "add_dir_entry() - Couldn't read dir"
 1337+ " (error code %d)", rc);
 1338+ return rc * 10 - 3;
 1339+ }
 1340+
 1341+ if (rc == 0) { /* current end of dir reached */
 1342+ DEBUGF("End of dir on cluster boundary");
 1343+ break;
 1344+ }
 1345+
 1346+ /* look for free slots */
 1347+ for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
 1348+ {
 1349+ switch (buf[i * DIR_ENTRY_SIZE]) {
 1350+ case 0:
 1351+ entries_found += DIR_ENTRIES_PER_SECTOR - i;
 1352+ DEBUGF("Found end of dir %d",
 1353+ sector * DIR_ENTRIES_PER_SECTOR + i);
 1354+ i = DIR_ENTRIES_PER_SECTOR - 1;
 1355+ done = true;
 1356+ break;
 1357+
 1358+ case 0xe5:
 1359+ entries_found++;
 1360+ DEBUGF("Found free entry %d (%d/%d)",
 1361+ sector * DIR_ENTRIES_PER_SECTOR + i,
 1362+ entries_found, entries_needed);
 1363+ break;
 1364+
 1365+ default:
 1366+ entries_found = 0;
 1367+
 1368+ /* check that our intended shortname doesn't already exist */
 1369+ if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
 1370+ /* shortname exists already, make a new one */
 1371+ randomize_dos_name(shortname);
 1372+ DEBUGF("Duplicate shortname, changing to %s",
 1373+ shortname);
 1374+
 1375+ /* name has changed, we need to restart search */
 1376+ goto restart;
 1377+ }
 1378+ break;
 1379+ }
 1380+ if (firstentry < 0 && (entries_found >= entries_needed))
 1381+ firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
 1382+ - entries_found;
 1383+ }
 1384+ }
 1385+
 1386+ /* step 2: extend the dir if necessary */
 1387+ if (firstentry < 0)
 1388+ {
 1389+ DEBUGF("Adding new sector(s) to dir");
 1390+ rc = fat_seek(&dir->file, sector);
 1391+ if (rc < 0)
 1392+ {
 1393+ fat_release_sector_buffer();
 1394+ return rc * 10 - 4;
 1395+ }
 1396+ memset(buf, 0, SECTOR_SIZE);
 1397+
 1398+ /* we must clear whole clusters */
 1399+ for (; (entries_found < entries_needed) ||
 1400+ (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
 1401+ {
 1402+ if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
 1403+ {
 1404+ fat_release_sector_buffer();
 1405+ return -5; /* dir too large -- FAT specification */
 1406+ }
 1407+
 1408+ rc = fat_readwrite(&dir->file, 1, buf, true);
 1409+ if (rc < 1) /* No more room or something went wrong */
 1410+ {
 1411+ fat_release_sector_buffer();
 1412+ return rc * 10 - 6;
 1413+ }
 1414+
 1415+ entries_found += DIR_ENTRIES_PER_SECTOR;
 1416+ }
 1417+
 1418+ firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
 1419+ }
 1420+ fat_release_sector_buffer();
 1421+
 1422+ /* step 3: add entry */
 1423+ sector = firstentry / DIR_ENTRIES_PER_SECTOR;
 1424+ DEBUGF("Adding longname to entry %d in sector %d",
 1425+ firstentry, sector);
 1426+
 1427+ rc = write_long_name(&dir->file, firstentry,
 1428+ entries_needed, name, shortname, is_directory);
 1429+ if (rc < 0)
 1430+ return rc * 10 - 7;
 1431+
 1432+ /* remember where the shortname dir entry is located */
 1433+ file->direntry = firstentry + entries_needed - 1;
 1434+ file->direntries = entries_needed;
 1435+ file->dircluster = dir->file.firstcluster;
 1436+ DEBUGF("Added new dir entry %d, using %d slots.",
 1437+ file->direntry, file->direntries);
 1438+
 1439+ return 0;
 1440+}
 1441+
 1442+static unsigned char char2dos(unsigned char c, int* randomize)
 1443+{
 1444+ static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
 1445+
 1446+ if (c <= 0x20)
 1447+ c = 0; /* Illegal char, remove */
 1448+ else if (strchr(invalid_chars, c) != NULL)
 1449+ {
 1450+ /* Illegal char, replace */
 1451+ c = '_';
 1452+ *randomize = 1; /* as per FAT spec */
 1453+ }
 1454+ else
 1455+ c = toupper(c);
 1456+
 1457+ return c;
 1458+}
 1459+
 1460+static void create_dos_name(const unsigned char *name, unsigned char *newname)
 1461+{
 1462+ int i;
 1463+ unsigned char *ext;
 1464+ int randomize = 0;
 1465+
 1466+ /* Find extension part */
 1467+ ext = strrchr(name, '.');
 1468+ if (ext == name) /* handle .dotnames */
 1469+ ext = NULL;
 1470+
 1471+ /* needs to randomize? */
 1472+ if((ext && (strlen(ext) > 4)) ||
 1473+ ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
 1474+ randomize = 1;
 1475+
 1476+ /* Name part */
 1477+ for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
 1478+ {
 1479+ unsigned char c = char2dos(*name, &randomize);
 1480+ if (c)
 1481+ newname[i++] = c;
 1482+ }
 1483+
 1484+ /* Pad both name and extension */
 1485+ while (i < 11)
 1486+ newname[i++] = ' ';
 1487+
 1488+ if (newname[0] == 0xe5) /* Special kanji character */
 1489+ newname[0] = 0x05;
 1490+
 1491+ if (ext)
 1492+ { /* Extension part */
 1493+ ext++;
 1494+ for (i = 8; *ext && (i < 11); ext++)
 1495+ {
 1496+ unsigned char c = char2dos(*ext, &randomize);
 1497+ if (c)
 1498+ newname[i++] = c;
 1499+ }
 1500+ }
 1501+
 1502+ if(randomize)
 1503+ randomize_dos_name(newname);
 1504+}
 1505+
 1506+static void randomize_dos_name(unsigned char *name)
 1507+{
 1508+ unsigned char* tilde = NULL; /* ~ location */
 1509+ unsigned char* lastpt = NULL; /* last point of filename */
 1510+ unsigned char* nameptr = name; /* working copy of name pointer */
 1511+ unsigned char num[9]; /* holds number as string */
 1512+ int i = 0;
 1513+ int cnt = 1;
 1514+ int numlen;
 1515+ int offset;
 1516+
 1517+ while(i++ < 8)
 1518+ {
 1519+ /* hunt for ~ and where to put it */
 1520+ if((!tilde) && (*nameptr == '~'))
 1521+ tilde = nameptr;
 1522+ if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
 1523+ lastpt = nameptr;
 1524+ nameptr++;
 1525+ }
 1526+ if(tilde)
 1527+ {
 1528+ /* extract current count and increment */
 1529+ memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
 1530+ num[7-(unsigned int)(tilde-name)] = 0;
 1531+ cnt = atoi(num) + 1;
 1532+ }
 1533+ cnt %= 10000000; /* protection */
 1534+ snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
 1535+ numlen = strlen(num); /* required space */
 1536+ offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
 1537+ if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
 1538+
 1539+ memcpy(&name[offset], num, numlen);
 1540+
 1541+ /* in special case of counter overflow: pad with spaces */
 1542+ for(offset = offset+numlen; offset < 8; offset++)
 1543+ name[offset] = ' ';
 1544+}
 1545+
 1546+static int update_short_entry( struct fat_file* file, long size, int attr )
 1547+{
 1548+ int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
 1549+ unsigned long* sizeptr;
 1550+ unsigned short* clusptr;
 1551+ struct fat_file dir;
 1552+ int rc;
 1553+
 1554+ DEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)",
 1555+ file->firstcluster, file->direntry, size);
 1556+
 1557+ /* create a temporary file handle for the dir holding this file */
 1558+ rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
 1559+ if (rc < 0)
 1560+ return rc * 10 - 1;
 1561+
 1562+ rc = fat_seek( &dir, sector );
 1563+ if (rc<0)
 1564+ return rc * 10 - 2;
 1565+
 1566+ unsigned char* buf = fat_get_sector_buffer();
 1567+ unsigned char* entry =
 1568+ buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
 1569+ rc = fat_readwrite(&dir, 1, buf, false);
 1570+ if (rc < 1)
 1571+ {
 1572+ fat_release_sector_buffer();
 1573+ return rc * 10 - 3;
 1574+ }
 1575+
 1576+ if (!entry[0] || entry[0] == 0xe5)
 1577+ {
 1578+ fat_release_sector_buffer();
 1579+ panicf(PANIC_KILLUSERTHREADS, "Updating size on empty dir entry %d", file->direntry);
 1580+ }
 1581+
 1582+ entry[FATDIR_ATTR] = attr & 0xFF;
 1583+
 1584+ clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
 1585+ *clusptr = htole16(file->firstcluster >> 16);
 1586+
 1587+ clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
 1588+ *clusptr = htole16(file->firstcluster & 0xffff);
 1589+
 1590+ sizeptr = (long*)(entry + FATDIR_FILESIZE);
 1591+ *sizeptr = htole32(size);
 1592+
 1593+ {
 1594+#if CONFIG_RTC
 1595+ unsigned short time = 0;
 1596+ unsigned short date = 0;
 1597+#else
 1598+ /* get old time to increment from */
 1599+ unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
 1600+ unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
 1601+#endif
 1602+ fat_time(&date, &time, NULL);
 1603+ *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
 1604+ *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
 1605+ *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
 1606+ }
 1607+
 1608+ rc = fat_seek( &dir, sector );
 1609+ if (rc < 0)
 1610+ {
 1611+ fat_release_sector_buffer();
 1612+ return rc * 10 - 4;
 1613+ }
 1614+
 1615+ rc = fat_readwrite(&dir, 1, buf, true);
 1616+ fat_release_sector_buffer();
 1617+ if (rc < 1)
 1618+ return rc * 10 - 5;
 1619+
 1620+ return 0;
 1621+}
 1622+
 1623+static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
 1624+{
 1625+ int i=0,j=0;
 1626+ unsigned char c;
 1627+ bool lowercase;
 1628+
 1629+ memset(de, 0, sizeof(struct fat_direntry));
 1630+ de->attr = buf[FATDIR_ATTR];
 1631+ de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
 1632+ de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
 1633+ de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
 1634+ de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
 1635+ de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
 1636+ de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
 1637+ de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
 1638+ ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
 1639+ /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
 1640+ (the result of the shift is always considered signed) */
 1641+
 1642+ /* fix the name */
 1643+ lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
 1644+ c = buf[FATDIR_NAME];
 1645+ if (c == 0x05) /* special kanji char */
 1646+ c = 0xe5;
 1647+ i = 0;
 1648+ while (c != ' ') {
 1649+ de->name[j++] = lowercase ? tolower(c) : c;
 1650+ if (++i >= 8)
 1651+ break;
 1652+ c = buf[FATDIR_NAME+i];
 1653+ }
 1654+ if (buf[FATDIR_NAME+8] != ' ') {
 1655+ lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
 1656+ de->name[j++] = '.';
 1657+ for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
 1658+ de->name[j++] = lowercase ? tolower(c) : c;
 1659+ }
 1660+ return 1;
 1661+}
 1662+
 1663+int fat_open(IF_MV2(int volume,)
 1664+ long startcluster,
 1665+ struct fat_file *file,
 1666+ const struct fat_dir* dir)
 1667+{
 1668+ /* Remember where the file's dir entry is located
 1669+ * Do it before assigning other fields so that fat_open
 1670+ * can be called with file == &dir->file (see fat_opendir) */
 1671+ if ( dir ) {
 1672+ file->direntry = dir->entry - 1;
 1673+ file->direntries = dir->entrycount;
 1674+ file->dircluster = dir->file.firstcluster;
 1675+ }
 1676+
 1677+ file->firstcluster = startcluster;
 1678+ file->lastcluster = startcluster;
 1679+ file->lastsector = 0;
 1680+ file->clusternum = 0;
 1681+ file->sectornum = 0;
 1682+ file->eof = false;
 1683+#ifdef HAVE_MULTIVOLUME
 1684+ file->volume = volume;
 1685+ /* fixme: remove error check when done */
 1686+ if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
 1687+ {
 1688+ DEBUGF("fat_open() illegal volume %d", volume);
 1689+ return -1;
 1690+ }
 1691+#endif
 1692+
 1693+ DEBUGF("fat_open(%lx), entry %d",startcluster,file->direntry);
 1694+ return 0;
 1695+}
 1696+
 1697+int fat_create_file(const char* name,
 1698+ struct fat_file* file,
 1699+ struct fat_dir* dir)
 1700+{
 1701+ int rc;
 1702+
 1703+ DEBUGF("fat_create_file(\"%s\",%lx,%lx)",name,(long)file,(long)dir);
 1704+ rc = add_dir_entry(dir, file, name, false, false);
 1705+ if (!rc) {
 1706+ file->firstcluster = 0;
 1707+ file->lastcluster = 0;
 1708+ file->lastsector = 0;
 1709+ file->clusternum = 0;
 1710+ file->sectornum = 0;
 1711+ file->eof = false;
 1712+ }
 1713+
 1714+ return rc;
 1715+}
 1716+
 1717+int fat_create_dir(const char* name,
 1718+ struct fat_dir* dir)
 1719+{
 1720+#ifdef HAVE_MULTIVOLUME
 1721+ struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
 1722+#else
 1723+ struct bpb* fat_bpb = &fat_bpbs[0];
 1724+#endif
 1725+ int i;
 1726+ long sector;
 1727+ int rc;
 1728+ struct fat_file newdir;
 1729+
 1730+ DEBUGF("fat_create_dir(\"%s\",%lx)",name,(long)dir);
 1731+
 1732+ /* First, add the entry in the parent directory */
 1733+ rc = add_dir_entry(dir, &newdir, name, true, false);
 1734+ if (rc < 0)
 1735+ return rc * 10 - 1;
 1736+
 1737+ /* Allocate a new cluster for the directory */
 1738+ newdir.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
 1739+ fat_bpb->fsinfo.nextfree);
 1740+ if(newdir.firstcluster == 0)
 1741+ return -6;
 1742+
 1743+ update_fat_entry(IF_MV2(fat_bpb,) newdir.firstcluster, FAT_EOF_MARK);
 1744+
 1745+ /* Clear the entire cluster */
 1746+ unsigned char* buf = fat_get_sector_buffer();
 1747+ sector = cluster2sec(IF_MV2(fat_bpb,) newdir.firstcluster);
 1748+ for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
 1749+ memset(buf, 0, SECTOR_SIZE);
 1750+ if (!i)
 1751+ {
 1752+ memcpy(buf, ". \0x10", 12);
 1753+ memcpy(&buf[0x20], ".. \0x10", 12);
 1754+ ((uint16_t*)buf)[0xd] = newdir.firstcluster;
 1755+ ((uint16_t*)buf)[0xa] = newdir.firstcluster >> 16;
 1756+ if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
 1757+ {
 1758+ ((uint16_t*)buf)[0x1d] = fat_bpb->bpb_rootclus;
 1759+ ((uint16_t*)buf)[0x1a] = fat_bpb->bpb_rootclus >> 16;
 1760+ }
 1761+ }
 1762+ rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
 1763+ if (rc < 0)
 1764+ {
 1765+ fat_release_sector_buffer();
 1766+ return rc * 10 - 2;
 1767+ }
 1768+ }
 1769+ fat_release_sector_buffer();
 1770+
 1771+ /* Set the firstcluster field in the direntry */
 1772+ update_short_entry(&newdir, 0, FAT_ATTR_DIRECTORY);
 1773+
 1774+ rc = flush_fat(IF_MV(fat_bpb));
 1775+ if (rc < 0)
 1776+ return rc * 10 - 5;
 1777+
 1778+ return 0;
 1779+}
 1780+
 1781+int fat_truncate(const struct fat_file *file)
 1782+{
 1783+ /* truncate trailing clusters */
 1784+ long next;
 1785+ long last = file->lastcluster;
 1786+#ifdef HAVE_MULTIVOLUME
 1787+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 1788+#endif
 1789+
 1790+ DEBUGF("fat_truncate(%lx, %lx)", file->firstcluster, last);
 1791+
 1792+ for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
 1793+ next = get_next_cluster(IF_MV2(fat_bpb,) last);
 1794+ update_fat_entry(IF_MV2(fat_bpb,) last,0);
 1795+ }
 1796+ if (file->lastcluster)
 1797+ update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
 1798+
 1799+ return 0;
 1800+}
 1801+
 1802+int fat_closewrite(struct fat_file *file, long size, int attr)
 1803+{
 1804+ int rc;
 1805+#ifdef HAVE_MULTIVOLUME
 1806+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 1807+#endif
 1808+ DEBUGF("fat_closewrite(size=%ld)",size);
 1809+
 1810+ if (!size) {
 1811+ /* empty file */
 1812+ if ( file->firstcluster ) {
 1813+ update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
 1814+ file->firstcluster = 0;
 1815+ }
 1816+ }
 1817+
 1818+ if (file->dircluster) {
 1819+ rc = update_short_entry(file, size, attr);
 1820+ if (rc < 0)
 1821+ return rc * 10 - 1;
 1822+ }
 1823+
 1824+ flush_fat(IF_MV(fat_bpb));
 1825+
 1826+#ifdef TEST_FAT
 1827+ if ( file->firstcluster ) {
 1828+ /* debug */
 1829+#ifdef HAVE_MULTIVOLUME
 1830+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 1831+#else
 1832+ struct bpb* fat_bpb = &fat_bpbs[0];
 1833+#endif
 1834+ long count = 0;
 1835+ long len;
 1836+ long next;
 1837+ for ( next = file->firstcluster; next;
 1838+ next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
 1839+ DEBUGF("cluster %ld: %lx", count, next);
 1840+ count++;
 1841+ }
 1842+ len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
 1843+ DEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)",
 1844+ count, len, size );
 1845+ if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
 1846+ panicf(PANIC_KILLUSERTHREADS, "Cluster chain is too long");
 1847+ if ( len < size )
 1848+ panicf(PANIC_KILLUSERTHREADS, "Cluster chain is too short");
 1849+ }
 1850+#endif
 1851+
 1852+ return 0;
 1853+}
 1854+
 1855+static int free_direntries(struct fat_file* file)
 1856+{
 1857+ struct fat_file dir;
 1858+ int numentries = file->direntries;
 1859+ unsigned int entry = file->direntry - numentries + 1;
 1860+ unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
 1861+ int i;
 1862+ int rc;
 1863+
 1864+ /* create a temporary file handle for the dir holding this file */
 1865+ rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
 1866+ if (rc < 0)
 1867+ return rc * 10 - 1;
 1868+
 1869+ rc = fat_seek( &dir, sector );
 1870+ if (rc < 0)
 1871+ return rc * 10 - 2;
 1872+
 1873+ unsigned char* buf = fat_get_sector_buffer();
 1874+ rc = fat_readwrite(&dir, 1, buf, false);
 1875+ if (rc < 1)
 1876+ {
 1877+ fat_release_sector_buffer();
 1878+ return rc * 10 - 3;
 1879+ }
 1880+
 1881+ for (i=0; i < numentries; i++) {
 1882+ DEBUGF("Clearing dir entry %d (%d/%d)",
 1883+ entry, i+1, numentries);
 1884+ buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
 1885+ entry++;
 1886+
 1887+ if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
 1888+ /* flush this sector */
 1889+ rc = fat_seek(&dir, sector);
 1890+ if (rc < 0)
 1891+ {
 1892+ fat_release_sector_buffer();
 1893+ return rc * 10 - 4;
 1894+ }
 1895+
 1896+ rc = fat_readwrite(&dir, 1, buf, true);
 1897+ if (rc < 1)
 1898+ {
 1899+ fat_release_sector_buffer();
 1900+ return rc * 10 - 5;
 1901+ }
 1902+
 1903+ if ( i+1 < numentries ) {
 1904+ /* read next sector */
 1905+ rc = fat_readwrite(&dir, 1, buf, false);
 1906+ if (rc < 1)
 1907+ {
 1908+ fat_release_sector_buffer();
 1909+ return rc * 10 - 6;
 1910+ }
 1911+ }
 1912+ sector++;
 1913+ }
 1914+ }
 1915+
 1916+ if ( entry % DIR_ENTRIES_PER_SECTOR ) {
 1917+ /* flush this sector */
 1918+ rc = fat_seek(&dir, sector);
 1919+ if (rc < 0)
 1920+ {
 1921+ fat_release_sector_buffer();
 1922+ return rc * 10 - 7;
 1923+ }
 1924+
 1925+ rc = fat_readwrite(&dir, 1, buf, true);
 1926+ if (rc < 1)
 1927+ {
 1928+ fat_release_sector_buffer();
 1929+ return rc * 10 - 8;
 1930+ }
 1931+ }
 1932+
 1933+ fat_release_sector_buffer();
 1934+ return 0;
 1935+}
 1936+
 1937+int fat_remove(struct fat_file* file)
 1938+{
 1939+ long next, last = file->firstcluster;
 1940+ int rc;
 1941+#ifdef HAVE_MULTIVOLUME
 1942+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 1943+#endif
 1944+
 1945+ DEBUGF("fat_remove(%lx)",last);
 1946+
 1947+ while ( last ) {
 1948+ next = get_next_cluster(IF_MV2(fat_bpb,) last);
 1949+ update_fat_entry(IF_MV2(fat_bpb,) last,0);
 1950+ last = next;
 1951+ }
 1952+
 1953+ if ( file->dircluster ) {
 1954+ rc = free_direntries(file);
 1955+ if (rc < 0)
 1956+ return rc * 10 - 1;
 1957+ }
 1958+
 1959+ file->firstcluster = 0;
 1960+ file->dircluster = 0;
 1961+
 1962+ rc = flush_fat(IF_MV(fat_bpb));
 1963+ if (rc < 0)
 1964+ return rc * 10 - 2;
 1965+
 1966+ return 0;
 1967+}
 1968+
 1969+int fat_rename(struct fat_file* file,
 1970+ struct fat_dir* dir,
 1971+ const unsigned char* newname,
 1972+ long size,
 1973+ int attr)
 1974+{
 1975+ int rc;
 1976+ struct fat_file newfile = *file;
 1977+ unsigned char* entry = NULL;
 1978+ unsigned short* clusptr = NULL;
 1979+ unsigned int parentcluster;
 1980+#ifdef HAVE_MULTIVOLUME
 1981+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 1982+
 1983+ if (file->volume != dir->file.volume) {
 1984+ DEBUGF("No rename across volumes!");
 1985+ return -1;
 1986+ }
 1987+#else
 1988+ struct bpb* fat_bpb = &fat_bpbs[0];
 1989+#endif
 1990+
 1991+ if ( !file->dircluster ) {
 1992+ DEBUGF("File has no dir cluster!");
 1993+ return -2;
 1994+ }
 1995+
 1996+ /* create new name */
 1997+ rc = add_dir_entry(dir, &newfile, newname, false, false);
 1998+ if (rc < 0)
 1999+ return rc * 10 - 2;
 2000+
 2001+ /* write size and cluster link */
 2002+ rc = update_short_entry(&newfile, size, attr);
 2003+ if (rc < 0)
 2004+ return rc * 10 - 3;
 2005+
 2006+ /* remove old name */
 2007+ rc = free_direntries(file);
 2008+ if (rc < 0)
 2009+ return rc * 10 - 4;
 2010+
 2011+ rc = flush_fat(IF_MV(fat_bpb));
 2012+ if (rc < 0)
 2013+ return rc * 10 - 5;
 2014+
 2015+ /* if renaming a directory, update the .. entry to make sure
 2016+ it points to its parent directory (we don't check if it was a move) */
 2017+ if(FAT_ATTR_DIRECTORY == attr) {
 2018+ /* open the dir that was renamed, we re-use the newfile struct */
 2019+
 2020+ rc = fat_open(IF_MV2(volume,) newfile.firstcluster, &newfile, NULL);
 2021+ if (rc < 0)
 2022+ return rc * 10 - 6;
 2023+
 2024+ /* get the first sector of the dir */
 2025+ rc = fat_seek(&newfile, 0);
 2026+ if (rc < 0)
 2027+ return rc * 10 - 7;
 2028+
 2029+ unsigned char* buf = fat_get_sector_buffer();
 2030+ rc = fat_readwrite(&newfile, 1, buf, false);
 2031+ if (rc < 0)
 2032+ {
 2033+ fat_release_sector_buffer();
 2034+ return rc * 10 - 8;
 2035+ }
 2036+
 2037+ /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
 2038+ if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
 2039+ parentcluster = 0;
 2040+ else
 2041+ parentcluster = dir->file.firstcluster;
 2042+
 2043+ entry = buf + DIR_ENTRY_SIZE;
 2044+ if(strncmp(".. ", entry, 11))
 2045+ {
 2046+ fat_release_sector_buffer();
 2047+ /* .. entry must be second entry according to FAT spec (p.29) */
 2048+ DEBUGF("Second dir entry is not double-dot!");
 2049+ return rc * 10 - 9;
 2050+ }
 2051+ clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
 2052+ *clusptr = htole16(parentcluster >> 16);
 2053+
 2054+ clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
 2055+ *clusptr = htole16(parentcluster & 0xffff);
 2056+
 2057+ /* write back this sector */
 2058+ rc = fat_seek(&newfile, 0);
 2059+ if (rc < 0)
 2060+ {
 2061+ fat_release_sector_buffer();
 2062+ return rc * 10 - 7;
 2063+ }
 2064+
 2065+ rc = fat_readwrite(&newfile, 1, buf, true);
 2066+ fat_release_sector_buffer();
 2067+ if (rc < 1)
 2068+ return rc * 10 - 8;
 2069+ }
 2070+
 2071+ return 0;
 2072+}
 2073+
 2074+static long next_write_cluster(struct fat_file* file,
 2075+ long oldcluster,
 2076+ long* newsector)
 2077+{
 2078+#ifdef HAVE_MULTIVOLUME
 2079+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 2080+#else
 2081+ struct bpb* fat_bpb = &fat_bpbs[0];
 2082+#endif
 2083+ long cluster = 0;
 2084+ long sector;
 2085+
 2086+ DEBUGF("next_write_cluster(%lx,%lx)",file->firstcluster, oldcluster);
 2087+
 2088+ if (oldcluster)
 2089+ cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
 2090+
 2091+ if (!cluster) {
 2092+ if (oldcluster > 0)
 2093+ cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
 2094+ else if (oldcluster == 0)
 2095+ cluster = find_free_cluster(IF_MV2(fat_bpb,)
 2096+ fat_bpb->fsinfo.nextfree);
 2097+#ifdef HAVE_FAT16SUPPORT
 2098+ else /* negative, pseudo-cluster of the root dir */
 2099+ return 0; /* impossible to append something to the root */
 2100+#endif
 2101+
 2102+ if (cluster) {
 2103+ if (oldcluster)
 2104+ update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
 2105+ else
 2106+ file->firstcluster = cluster;
 2107+ update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
 2108+ }
 2109+ else {
 2110+#ifdef TEST_FAT
 2111+ if (fat_bpb->fsinfo.freecount>0)
 2112+ panicf(PANIC_KILLUSERTHREADS, "There is free space, but find_free_cluster() "
 2113+ "didn't find it!");
 2114+#endif
 2115+ DEBUGF("next_write_cluster(): Disk full!");
 2116+ return 0;
 2117+ }
 2118+ }
 2119+ sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
 2120+ if (sector<0)
 2121+ return 0;
 2122+
 2123+ *newsector = sector;
 2124+ return cluster;
 2125+}
 2126+
 2127+static int transfer(IF_MV2(struct bpb* fat_bpb,)
 2128+ unsigned long start, long count, char* buf, bool write )
 2129+{
 2130+#ifndef HAVE_MULTIVOLUME
 2131+ struct bpb* fat_bpb = &fat_bpbs[0];
 2132+#endif
 2133+ int rc;
 2134+
 2135+ DEBUGF("transfer(s=%lx, c=%lx, %s)",
 2136+ start+ fat_bpb->startsector, count, write?"write":"read");
 2137+ if (write) {
 2138+ unsigned long firstallowed;
 2139+#ifdef HAVE_FAT16SUPPORT
 2140+ if (fat_bpb->is_fat16)
 2141+ firstallowed = fat_bpb->rootdirsector;
 2142+ else
 2143+#endif
 2144+ firstallowed = fat_bpb->firstdatasector;
 2145+
 2146+ if (start < firstallowed)
 2147+ panicf(PANIC_KILLUSERTHREADS, "Write %ld before data", firstallowed - start);
 2148+ if (start + count > fat_bpb->totalsectors)
 2149+ panicf(PANIC_KILLUSERTHREADS, "Write %ld after data",
 2150+ start + count - fat_bpb->totalsectors);
 2151+ rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
 2152+ start + fat_bpb->startsector, count, buf);
 2153+ }
 2154+ else
 2155+ rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
 2156+ start + fat_bpb->startsector, count, buf);
 2157+ if (rc < 0) {
 2158+ DEBUGF( "transfer() - Couldn't %s sector %lx"
 2159+ " (error code %d)",
 2160+ write ? "write":"read", start, rc);
 2161+ return rc;
 2162+ }
 2163+ return 0;
 2164+}
 2165+
 2166+
 2167+long fat_readwrite( struct fat_file *file, long sectorcount,
 2168+ void* buf, bool write )
 2169+{
 2170+#ifdef HAVE_MULTIVOLUME
 2171+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 2172+#else
 2173+ struct bpb* fat_bpb = &fat_bpbs[0];
 2174+#endif
 2175+ long cluster = file->lastcluster;
 2176+ long sector = file->lastsector;
 2177+ long clusternum = file->clusternum;
 2178+ long numsec = file->sectornum;
 2179+ bool eof = file->eof;
 2180+ long first=0, last=0;
 2181+ long i;
 2182+ int rc;
 2183+
 2184+ DEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)",
 2185+ file->firstcluster,sectorcount,(long)buf,write?"write":"read");
 2186+ DEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d",
 2187+ sector,numsec, eof?1:0);
 2188+
 2189+ if ( eof && !write)
 2190+ return 0;
 2191+
 2192+ /* find sequential sectors and write them all at once */
 2193+ for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
 2194+ numsec++;
 2195+ if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
 2196+ long oldcluster = cluster;
 2197+ long oldsector = sector;
 2198+ long oldnumsec = numsec;
 2199+ if (write)
 2200+ cluster = next_write_cluster(file, cluster, &sector);
 2201+ else {
 2202+ cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
 2203+ sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
 2204+ }
 2205+
 2206+ clusternum++;
 2207+ numsec=1;
 2208+
 2209+ if (!cluster) {
 2210+ eof = true;
 2211+ if ( write ) {
 2212+ /* remember last cluster, in case
 2213+ we want to append to the file */
 2214+ sector = oldsector;
 2215+ cluster = oldcluster;
 2216+ numsec = oldnumsec;
 2217+ clusternum--;
 2218+ i = -1; /* Error code */
 2219+ break;
 2220+ }
 2221+ }
 2222+ else
 2223+ eof = false;
 2224+ }
 2225+ else {
 2226+ if (sector)
 2227+ sector++;
 2228+ else {
 2229+ /* look up first sector of file */
 2230+ sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
 2231+ numsec=1;
 2232+#ifdef HAVE_FAT16SUPPORT
 2233+ if (file->firstcluster < 0)
 2234+ { /* FAT16 root dir */
 2235+ sector += fat_bpb->rootdiroffset;
 2236+ numsec += fat_bpb->rootdiroffset;
 2237+ }
 2238+#endif
 2239+ }
 2240+ }
 2241+
 2242+ if (!first)
 2243+ first = sector;
 2244+
 2245+ if ( ((sector != first) && (sector != last+1)) || /* not sequential */
 2246+ (last-first+1 == 256) ) { /* max 256 sectors per ata request */
 2247+ long count = last - first + 1;
 2248+ rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
 2249+ if (rc < 0)
 2250+ return rc * 10 - 1;
 2251+
 2252+ buf = (char *)buf + count * SECTOR_SIZE;
 2253+ first = sector;
 2254+ }
 2255+
 2256+ if ((i == sectorcount-1) && /* last sector requested */
 2257+ (!eof))
 2258+ {
 2259+ long count = sector - first + 1;
 2260+ rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
 2261+ if (rc < 0)
 2262+ return rc * 10 - 2;
 2263+ }
 2264+
 2265+ last = sector;
 2266+ }
 2267+
 2268+ file->lastcluster = cluster;
 2269+ file->lastsector = sector;
 2270+ file->clusternum = clusternum;
 2271+ file->sectornum = numsec;
 2272+ file->eof = eof;
 2273+
 2274+ /* if eof, don't report last block as read/written */
 2275+ if (eof)
 2276+ i--;
 2277+
 2278+ DEBUGF("Sectors written: %ld", i);
 2279+ return i;
 2280+}
 2281+
 2282+int fat_seek(struct fat_file *file, unsigned long seeksector )
 2283+{
 2284+#ifdef HAVE_MULTIVOLUME
 2285+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
 2286+#else
 2287+ struct bpb* fat_bpb = &fat_bpbs[0];
 2288+#endif
 2289+ long clusternum=0, numclusters=0, sectornum=0, sector=0;
 2290+ long cluster = file->firstcluster;
 2291+ long i;
 2292+
 2293+#ifdef HAVE_FAT16SUPPORT
 2294+ if (cluster < 0) /* FAT16 root dir */
 2295+ seeksector += fat_bpb->rootdiroffset;
 2296+#endif
 2297+
 2298+ file->eof = false;
 2299+ if (seeksector) {
 2300+ /* we need to find the sector BEFORE the requested, since
 2301+ the file struct stores the last accessed sector */
 2302+ seeksector--;
 2303+ numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
 2304+ sectornum = seeksector % fat_bpb->bpb_secperclus;
 2305+
 2306+ if (file->clusternum && clusternum >= file->clusternum)
 2307+ {
 2308+ cluster = file->lastcluster;
 2309+ numclusters -= file->clusternum;
 2310+ }
 2311+
 2312+ for (i=0; i<numclusters; i++) {
 2313+ cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
 2314+ if (!cluster) {
 2315+ DEBUGF("Seeking beyond the end of the file! "
 2316+ "(sector %ld, cluster %ld)", seeksector, i);
 2317+ return -1;
 2318+ }
 2319+ }
 2320+
 2321+ sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
 2322+ }
 2323+ else {
 2324+ sectornum = -1;
 2325+ }
 2326+
 2327+ DEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx",
 2328+ file->firstcluster, seeksector, cluster, sector, sectornum);
 2329+
 2330+ file->lastcluster = cluster;
 2331+ file->lastsector = sector;
 2332+ file->clusternum = clusternum;
 2333+ file->sectornum = sectornum + 1;
 2334+ return 0;
 2335+}
 2336+
 2337+int fat_opendir(IF_MV2(int volume,)
 2338+ struct fat_dir *dir, unsigned long startcluster,
 2339+ const struct fat_dir *parent_dir)
 2340+{
 2341+#ifdef HAVE_MULTIVOLUME
 2342+ struct bpb* fat_bpb = &fat_bpbs[volume];
 2343+ /* fixme: remove error check when done */
 2344+ if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
 2345+ {
 2346+ DEBUGF("fat_open() illegal volume %d", volume);
 2347+ return -1;
 2348+ }
 2349+#else
 2350+ struct bpb* fat_bpb = &fat_bpbs[0];
 2351+#endif
 2352+ int rc;
 2353+
 2354+ if (startcluster == 0)
 2355+ startcluster = fat_bpb->bpb_rootclus;
 2356+
 2357+ rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
 2358+ if(rc)
 2359+ {
 2360+ DEBUGF( "fat_opendir() - Couldn't open dir"
 2361+ " (error code %d)", rc);
 2362+ return rc * 10 - 1;
 2363+ }
 2364+
 2365+ /* assign them after fat_open call so that fat_opendir can be called with the same
 2366+ * fat_dir as parent and result */
 2367+ dir->entry = 0;
 2368+ dir->sector = 0;
 2369+
 2370+ return 0;
 2371+}
 2372+
 2373+int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
 2374+{
 2375+ bool done = false;
 2376+ int i, j;
 2377+ int rc;
 2378+ int order;
 2379+ unsigned char firstbyte;
 2380+ /* Long file names are stored in special entries. Each entry holds
 2381+ up to 13 characters. Names can be max 255 chars (not bytes!) long */
 2382+ /* The number of long entries in the long name can be retrieve from the first
 2383+ * long entry because there are stored in reverse order and have an ordinal */
 2384+ int nb_longs = 0;
 2385+ /* The long entries are expected to be in order, so remember the last ordinal */
 2386+ int last_long_ord = 0;
 2387+
 2388+ dir->entrycount = 0;
 2389+
 2390+ while(!done)
 2391+ {
 2392+ if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
 2393+ {
 2394+ rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
 2395+ if (rc == 0) {
 2396+ /* eof */
 2397+ entry->name[0] = 0;
 2398+ break;
 2399+ }
 2400+ if (rc < 0) {
 2401+ DEBUGF( "fat_getnext() - Couldn't read dir"
 2402+ " (error code %d)", rc);
 2403+ return rc * 10 - 1;
 2404+ }
 2405+ dir->sector = dir->file.lastsector;
 2406+ }
 2407+
 2408+ for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
 2409+ i < DIR_ENTRIES_PER_SECTOR; i++) {
 2410+ unsigned int entrypos = i * DIR_ENTRY_SIZE;
 2411+
 2412+ firstbyte = dir->sectorcache[entrypos];
 2413+ dir->entry++;
 2414+
 2415+ if (firstbyte == 0xe5) {
 2416+ /* free entry */
 2417+ dir->entrycount = 0;
 2418+ continue;
 2419+ }
 2420+
 2421+ if (firstbyte == 0) {
 2422+ /* last entry */
 2423+ entry->name[0] = 0;
 2424+ dir->entrycount = 0;
 2425+ return 0;
 2426+ }
 2427+
 2428+ dir->entrycount++;
 2429+
 2430+ /* LFN entry? */
 2431+ if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
 2432+ FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
 2433+ /* extract ordinal */
 2434+ order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
 2435+ /* is this entry the first long entry ? (first in order but containing last part) */
 2436+ if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
 2437+ /* check that order is not too big ! (and non-zero) */
 2438+ if(order <= 0 || order > FATLONG_MAX_ORDER)
 2439+ continue; /* ignore the whole LFN, will trigger lots of warnings */
 2440+ nb_longs = order;
 2441+ last_long_ord = order;
 2442+ }
 2443+ else {
 2444+ /* check orphan entry */
 2445+ if (nb_longs == 0) {
 2446+ DEBUGF("fat warning: orphan LFN entry");
 2447+ /* ignore */
 2448+ continue;
 2449+ }
 2450+
 2451+ /* check order */
 2452+ if (order != (last_long_ord - 1)) {
 2453+ DEBUGF("fat warning: wrong LFN ordinal");
 2454+ /* ignore the whole LFN, will trigger lots of warnings */
 2455+ nb_longs = 0;
 2456+ }
 2457+
 2458+ last_long_ord = order;
 2459+ }
 2460+
 2461+ /* copy part, reuse [order] for another purpose :) */
 2462+ order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
 2463+ for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
 2464+ memcpy(dir->longname + order,
 2465+ dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
 2466+ FATLONG_NAME_SIZE[j]);
 2467+ order += FATLONG_NAME_SIZE[j];
 2468+ }
 2469+ }
 2470+ else {
 2471+ if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
 2472+
 2473+ /* don't return volume id entry */
 2474+ if ( (entry->attr &
 2475+ (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
 2476+ == FAT_ATTR_VOLUME_ID)
 2477+ continue;
 2478+
 2479+ /* replace shortname with longname? */
 2480+ /* check that the long name is complete */
 2481+ if (nb_longs != 0 && last_long_ord == 1) {
 2482+ /* hold a copy of the shortname in case the long one is too long */
 2483+ unsigned char shortname[13]; /* 8+3+dot+\0 */
 2484+ int longname_utf8len = 0;
 2485+ /* One character at a time, add 1 for trailing \0, 4 is the maximum size
 2486+ * of a UTF8 encoded character in rockbox */
 2487+ unsigned char longname_utf8segm[4 + 1];
 2488+ unsigned short ucs;
 2489+ int segm_utf8len;
 2490+ /* Temporarily store short name */
 2491+ strcpy(shortname, entry->name);
 2492+ entry->name[0] = 0;
 2493+
 2494+ /* Convert the FAT name to a utf8-encoded one.
 2495+ * The name is not necessary NUL-terminated ! */
 2496+ for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
 2497+ ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
 2498+ if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
 2499+ break;
 2500+ /* utf8encode will return a pointer after the converted
 2501+ * string, subtract the pointer to the start to get the length of it */
 2502+ segm_utf8len = 1;
 2503+
 2504+ /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
 2505+ if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
 2506+ /* force use of short name */
 2507+ longname_utf8len = FAT_FILENAME_BYTES + 1;
 2508+ break; /* fallback later */
 2509+ }
 2510+ else {
 2511+ if (ucs < 128) longname_utf8segm[0] = (unsigned char)ucs;
 2512+ else longname_utf8segm[0] = '?';
 2513+ longname_utf8segm[segm_utf8len] = 0;
 2514+ strcat(entry->name + longname_utf8len, longname_utf8segm);
 2515+ longname_utf8len += segm_utf8len;
 2516+ }
 2517+ }
 2518+
 2519+ /* Does the utf8-encoded name fit into the entry? */
 2520+ /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
 2521+ if (longname_utf8len >= FAT_FILENAME_BYTES) {
 2522+ /* Take the short DOS name. Need to utf8-encode it
 2523+ since it may contain chars from the upper half of
 2524+ the OEM code page which wouldn't be a valid utf8.
 2525+ Beware: this file will be shown with strange
 2526+ glyphs in file browser since unicode 0x80 to 0x9F
 2527+ are control characters. */
 2528+ DEBUGF("SN-DOS: %s", shortname);
 2529+ unsigned char *utf8;
 2530+ memcpy(entry->name, shortname, strlen(shortname));
 2531+ *(entry->name + strlen(shortname)) = 0;
 2532+ DEBUGF("SN: %s", entry->name);
 2533+ } else {
 2534+ DEBUGF("LN: %s", entry->name);
 2535+ DEBUGF("LNLen: %d", longname_utf8len);
 2536+ }
 2537+ }
 2538+ done = true;
 2539+ i++;
 2540+ break;
 2541+ }
 2542+ }
 2543+ }
 2544+ }
 2545+ return 0;
 2546+}
 2547+
 2548+unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
 2549+{
 2550+#ifndef HAVE_MULTIVOLUME
 2551+ const int volume = 0;
 2552+#endif
 2553+ struct bpb* fat_bpb = &fat_bpbs[volume];
 2554+ return fat_bpb->bpb_secperclus * SECTOR_SIZE;
 2555+}
 2556+
 2557+#ifdef HAVE_MULTIVOLUME
 2558+bool fat_ismounted(int volume)
 2559+{
 2560+ return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
 2561+}
 2562+#endif
Index: embios/trunk/dir.c
@@ -1,4 +1,4 @@
2 -/***************************************************************************
 2+/***************************************************************************
33 * __________ __ ___.
44 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
55 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
@@ -217,7 +217,6 @@
218218 char *basename;
219219 char *parent;
220220 struct dirent *entry;
221 - struct fat_dir newdir;
222221 int rc;
223222
224223 if ( name[0] != '/' ) {
@@ -262,9 +261,7 @@
263262 }
264263 }
265264
266 - memset(&newdir, 0, sizeof(struct fat_dir));
267 -
268 - rc = fat_create_dir(basename, &newdir, &(dir->fatdir));
 265+ rc = fat_create_dir(basename, &(dir->fatdir));
269266 closedir(dir);
270267
271268 return rc;
Index: embios/trunk/fat.h
@@ -1,136 +1,135 @@
2 -/***************************************************************************
3 - * __________ __ ___.
4 - * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 - * \/ \/ \/ \/ \/
9 - * $Id$
10 - *
11 - * Copyright (C) 2002 by Linus Nielsen Feltzing
12 - *
13 - * This program is free software; you can redistribute it and/or
14 - * modify it under the terms of the GNU General Public License
15 - * as published by the Free Software Foundation; either version 2
16 - * of the License, or (at your option) any later version.
17 - *
18 - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 - * KIND, either express or implied.
20 - *
21 - ****************************************************************************/
22 -
23 -#ifndef FAT_H
24 -#define FAT_H
25 -
26 -#include "global.h"
27 -#include "util.h"
28 -#include "mv.h" /* for volume definitions */
29 -
30 -#ifndef SECTOR_SIZE
31 -#define SECTOR_SIZE 512
32 -#endif
33 -
34 -/* Number of bytes reserved for a file name (including the trailing \0).
35 - Since names are stored in the entry as UTF-8, we won't be able to
36 - store all names allowed by FAT. In FAT, a name can have max 255
37 - characters (not bytes!). Since the UTF-8 encoding of a char may take
38 - up to 4 bytes, there will be names that we won't be able to store
39 - completely. For such names, the short DOS name is used. */
40 -#define FAT_FILENAME_BYTES 256
41 -
42 -struct fat_direntry
43 -{
44 - unsigned char name[FAT_FILENAME_BYTES]; /* UTF-8 encoded name plus \0 */
45 - unsigned short attr; /* Attributes */
46 - unsigned char crttimetenth; /* Millisecond creation
47 - time stamp (0-199) */
48 - unsigned short crttime; /* Creation time */
49 - unsigned short crtdate; /* Creation date */
50 - unsigned short lstaccdate; /* Last access date */
51 - unsigned short wrttime; /* Last write time */
52 - unsigned short wrtdate; /* Last write date */
53 - unsigned long filesize; /* File size in bytes */
54 - long firstcluster; /* fstclusterhi<<16 + fstcluslo */
55 -};
56 -
57 -#define FAT_ATTR_READ_ONLY 0x01
58 -#define FAT_ATTR_HIDDEN 0x02
59 -#define FAT_ATTR_SYSTEM 0x04
60 -#define FAT_ATTR_VOLUME_ID 0x08
61 -#define FAT_ATTR_DIRECTORY 0x10
62 -#define FAT_ATTR_ARCHIVE 0x20
63 -#define FAT_ATTR_VOLUME 0x40 /* this is a volume, not a real directory */
64 -
65 -struct fat_file
66 -{
67 - long firstcluster; /* first cluster in file */
68 - long lastcluster; /* cluster of last access */
69 - long lastsector; /* sector of last access */
70 - long clusternum; /* current clusternum */
71 - long sectornum; /* sector number in this cluster */
72 - unsigned int direntry; /* short dir entry index from start of dir */
73 - unsigned int direntries; /* number of dir entries used by this file */
74 - long dircluster; /* first cluster of dir */
75 - bool eof;
76 -#ifdef HAVE_MULTIVOLUME
77 - int volume; /* file resides on which volume */
78 -#endif
79 -};
80 -
81 -struct fat_dir
82 -{
83 - unsigned int entry;
84 - unsigned int entrycount;
85 - long sector;
86 - struct fat_file file;
87 - unsigned char sectorcache[SECTOR_SIZE] CACHEALIGN_ATTR;
88 - /* There are 2-bytes per characters. We don't want to bother too much, as LFN entries are
89 - * at much 255 characters longs, that's at most 20 LFN entries. Each entry hold at most
90 - * 13 characters, that a total of 260 characters. So we keep a buffer of that size.
91 - * Keep coherent with fat.c code. */
92 - unsigned char longname[260 * 2];
93 -} CACHEALIGN_ATTR;
94 -
95 -#ifdef HAVE_HOTSWAP
96 -extern void fat_lock(void);
97 -extern void fat_unlock(void);
98 -#endif
99 -
100 -extern void fat_init(void);
101 -extern int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector);
102 -extern int fat_unmount(int volume, bool flush);
103 -extern void fat_size(IF_MV2(int volume,) /* public for info */
104 - unsigned long* size,
105 - unsigned long* free);
106 -extern void fat_recalc_free(IF_MV_NONVOID(int volume)); /* public for debug info screen */
107 -extern int fat_create_dir(const char* name,
108 - struct fat_dir* newdir,
109 - struct fat_dir* dir);
110 -extern int fat_open(IF_MV2(int volume,)
111 - long cluster,
112 - struct fat_file* ent,
113 - const struct fat_dir* dir);
114 -extern int fat_create_file(const char* name,
115 - struct fat_file* ent,
116 - struct fat_dir* dir);
117 -extern long fat_readwrite(struct fat_file *ent, long sectorcount,
118 - void* buf, bool write );
119 -extern int fat_closewrite(struct fat_file *ent, long size, int attr);
120 -extern int fat_seek(struct fat_file *ent, unsigned long sector );
121 -extern int fat_remove(struct fat_file *ent);
122 -extern int fat_truncate(const struct fat_file *ent);
123 -extern int fat_rename(struct fat_file* file,
124 - struct fat_dir* dir,
125 - const unsigned char* newname,
126 - long size, int attr);
127 -
128 -extern int fat_opendir(IF_MV2(int volume,)
129 - struct fat_dir *ent, unsigned long startcluster,
130 - const struct fat_dir *parent_dir);
131 -extern int fat_getnext(struct fat_dir *ent, struct fat_direntry *entry);
132 -extern unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)); /* public for debug info screen */
133 -extern bool fat_ismounted(int volume);
134 -extern void* fat_get_sector_buffer(void);
135 -extern void fat_release_sector_buffer(void);
136 -
137 -#endif
 2+/***************************************************************************
 3+ * __________ __ ___.
 4+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
 5+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
 6+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
 7+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
 8+ * \/ \/ \/ \/ \/
 9+ * $Id$
 10+ *
 11+ * Copyright (C) 2002 by Linus Nielsen Feltzing
 12+ *
 13+ * This program is free software; you can redistribute it and/or
 14+ * modify it under the terms of the GNU General Public License
 15+ * as published by the Free Software Foundation; either version 2
 16+ * of the License, or (at your option) any later version.
 17+ *
 18+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 19+ * KIND, either express or implied.
 20+ *
 21+ ****************************************************************************/
 22+
 23+#ifndef FAT_H
 24+#define FAT_H
 25+
 26+#include "global.h"
 27+#include "util.h"
 28+#include "mv.h" /* for volume definitions */
 29+
 30+#ifndef SECTOR_SIZE
 31+#define SECTOR_SIZE 512
 32+#endif
 33+
 34+/* Number of bytes reserved for a file name (including the trailing \0).
 35+ Since names are stored in the entry as UTF-8, we won't be able to
 36+ store all names allowed by FAT. In FAT, a name can have max 255
 37+ characters (not bytes!). Since the UTF-8 encoding of a char may take
 38+ up to 4 bytes, there will be names that we won't be able to store
 39+ completely. For such names, the short DOS name is used. */
 40+#define FAT_FILENAME_BYTES 256
 41+
 42+struct fat_direntry
 43+{
 44+ unsigned char name[FAT_FILENAME_BYTES]; /* UTF-8 encoded name plus \0 */
 45+ unsigned short attr; /* Attributes */
 46+ unsigned char crttimetenth; /* Millisecond creation
 47+ time stamp (0-199) */
 48+ unsigned short crttime; /* Creation time */
 49+ unsigned short crtdate; /* Creation date */
 50+ unsigned short lstaccdate; /* Last access date */
 51+ unsigned short wrttime; /* Last write time */
 52+ unsigned short wrtdate; /* Last write date */
 53+ unsigned long filesize; /* File size in bytes */
 54+ long firstcluster; /* fstclusterhi<<16 + fstcluslo */
 55+};
 56+
 57+#define FAT_ATTR_READ_ONLY 0x01
 58+#define FAT_ATTR_HIDDEN 0x02
 59+#define FAT_ATTR_SYSTEM 0x04
 60+#define FAT_ATTR_VOLUME_ID 0x08
 61+#define FAT_ATTR_DIRECTORY 0x10
 62+#define FAT_ATTR_ARCHIVE 0x20
 63+#define FAT_ATTR_VOLUME 0x40 /* this is a volume, not a real directory */
 64+
 65+struct fat_file
 66+{
 67+ long firstcluster; /* first cluster in file */
 68+ long lastcluster; /* cluster of last access */
 69+ long lastsector; /* sector of last access */
 70+ long clusternum; /* current clusternum */
 71+ long sectornum; /* sector number in this cluster */
 72+ unsigned int direntry; /* short dir entry index from start of dir */
 73+ unsigned int direntries; /* number of dir entries used by this file */
 74+ long dircluster; /* first cluster of dir */
 75+ bool eof;
 76+#ifdef HAVE_MULTIVOLUME
 77+ int volume; /* file resides on which volume */
 78+#endif
 79+};
 80+
 81+struct fat_dir
 82+{
 83+ unsigned int entry;
 84+ unsigned int entrycount;
 85+ long sector;
 86+ struct fat_file file;
 87+ unsigned char sectorcache[SECTOR_SIZE] CACHEALIGN_ATTR;
 88+ /* There are 2-bytes per characters. We don't want to bother too much, as LFN entries are
 89+ * at much 255 characters longs, that's at most 20 LFN entries. Each entry hold at most
 90+ * 13 characters, that a total of 260 characters. So we keep a buffer of that size.
 91+ * Keep coherent with fat.c code. */
 92+ unsigned char longname[260 * 2];
 93+} CACHEALIGN_ATTR;
 94+
 95+#ifdef HAVE_HOTSWAP
 96+extern void fat_lock(void);
 97+extern void fat_unlock(void);
 98+#endif
 99+
 100+extern void fat_init(void);
 101+extern int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector);
 102+extern int fat_unmount(int volume, bool flush);
 103+extern void fat_size(IF_MV2(int volume,) /* public for info */
 104+ unsigned long* size,
 105+ unsigned long* free);
 106+extern void fat_recalc_free(IF_MV_NONVOID(int volume)); /* public for debug info screen */
 107+extern int fat_create_dir(const char* name,
 108+ struct fat_dir* dir);
 109+extern int fat_open(IF_MV2(int volume,)
 110+ long cluster,
 111+ struct fat_file* ent,
 112+ const struct fat_dir* dir);
 113+extern int fat_create_file(const char* name,
 114+ struct fat_file* ent,
 115+ struct fat_dir* dir);
 116+extern long fat_readwrite(struct fat_file *ent, long sectorcount,
 117+ void* buf, bool write );
 118+extern int fat_closewrite(struct fat_file *ent, long size, int attr);
 119+extern int fat_seek(struct fat_file *ent, unsigned long sector );
 120+extern int fat_remove(struct fat_file *ent);
 121+extern int fat_truncate(const struct fat_file *ent);
 122+extern int fat_rename(struct fat_file* file,
 123+ struct fat_dir* dir,
 124+ const unsigned char* newname,
 125+ long size, int attr);
 126+
 127+extern int fat_opendir(IF_MV2(int volume,)
 128+ struct fat_dir *ent, unsigned long startcluster,
 129+ const struct fat_dir *parent_dir);
 130+extern int fat_getnext(struct fat_dir *ent, struct fat_direntry *entry);
 131+extern unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)); /* public for debug info screen */
 132+extern bool fat_ismounted(int volume);
 133+extern void* fat_get_sector_buffer(void);
 134+extern void fat_release_sector_buffer(void);
 135+
 136+#endif