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