Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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