Subversion Repositories freemyipod

Rev

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

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