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