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];
51 theseven 211
static struct mutex cache_mutex;
46 theseven 212
 
213
#if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
214
void fat_lock(void)
215
{
51 theseven 216
    mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
46 theseven 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;
51 theseven 478
        mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
46 theseven 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
 
51 theseven 663
    mutex_lock(&cache_mutex, TIMEOUT_BLOCK); /* make changes atomic */
46 theseven 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
 
51 theseven 973
    mutex_lock(&cache_mutex, TIMEOUT_BLOCK);
46 theseven 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
 
51 theseven 1017
    if (date) *date = (1 << 5) | 1;
1018
    if (time) *time = 0;
1019
    if (tenth) *tenth = 0;
46 theseven 1020
 
1021
#endif /* CONFIG_RTC */
1022
}
1023
 
1024
static int write_long_name(struct fat_file* file,
1025
                           unsigned int firstentry,
1026
                           unsigned int numentries,
1027
                           const unsigned char* name,
1028
                           const unsigned char* shortname,
1029
                           bool is_directory)
1030
{
1031
    unsigned char buf[SECTOR_SIZE];
1032
    unsigned char* entry;
1033
    unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1034
    unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1035
    unsigned char chksum = 0;
1036
    unsigned int i, j=0;
51 theseven 1037
    unsigned int nameidx=0, namelen = strlen(name);
46 theseven 1038
    int rc;
1039
    unsigned short name_utf16[namelen + 1];
1040
 
50 theseven 1041
    DEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)",
46 theseven 1042
            file->firstcluster, firstentry, numentries, name);
1043
 
1044
    rc = fat_seek(file, sector);
1045
    if (rc<0)
1046
        return rc * 10 - 1;
1047
 
1048
    rc = fat_readwrite(file, 1, buf, false);
1049
    if (rc<1)
1050
        return rc * 10 - 2;
1051
 
1052
    /* calculate shortname checksum */
1053
    for (i=11; i>0; i--)
1054
        chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1055
 
1056
    /* calc position of last name segment */
1057
    if ( namelen > NAME_BYTES_PER_ENTRY )
1058
        for (nameidx=0;
1059
             nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1060
             nameidx += NAME_BYTES_PER_ENTRY);
1061
 
1062
    /* we need to convert the name first    */
1063
    /* since it is written in reverse order */
1064
    for (i = 0; i <= namelen; i++)
51 theseven 1065
        name_utf16[i] = *(name++);
46 theseven 1066
 
1067
    for (i=0; i < numentries; i++) {
1068
        /* new sector? */
1069
        if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1070
            /* update current sector */
1071
            rc = fat_seek(file, sector);
1072
            if (rc<0)
1073
                return rc * 10 - 3;
1074
 
1075
            rc = fat_readwrite(file, 1, buf, true);
1076
            if (rc<1)
1077
                return rc * 10 - 4;
1078
 
1079
            /* read next sector */
1080
            rc = fat_readwrite(file, 1, buf, false);
1081
            if (rc<0) {
50 theseven 1082
                DEBUGF("Failed writing new sector: %d",rc);
46 theseven 1083
                return rc * 10 - 5;
1084
            }
1085
            if (rc==0)
1086
                /* end of dir */
1087
                memset(buf, 0, sizeof buf);
1088
 
1089
            sector++;
1090
            idx = 0;
1091
        }
1092
 
1093
        entry = buf + idx * DIR_ENTRY_SIZE;
1094
 
1095
        /* verify this entry is free */
1096
        if (entry[0] && entry[0] != 0xe5 )
50 theseven 1097
            panicf(PANIC_KILLUSERTHREADS, "Dir entry %d in sector %x is not free! "
46 theseven 1098
                   "%02x %02x %02x %02x",
1099
                   idx, sector,
1100
                   entry[0], entry[1], entry[2], entry[3]);
1101
 
1102
        memset(entry, 0, DIR_ENTRY_SIZE);
1103
        if ( i+1 < numentries ) {
1104
            /* longname entry */
1105
            unsigned int k, l = nameidx;
1106
 
1107
            entry[FATLONG_ORDER] = numentries-i-1;
1108
            if (i==0) {
1109
                /* mark this as last long entry */
1110
                entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1111
 
1112
                /* pad name with 0xffff  */
1113
                for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1114
                for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1115
                for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1116
            };
1117
            /* set name */
1118
            for (k=0; k<5 && l <= namelen; k++) {
1119
                entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1120
                entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1121
            }
1122
            for (k=0; k<6 && l <= namelen; k++) {
1123
                entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1124
                entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1125
            }
1126
            for (k=0; k<2 && l <= namelen; k++) {
1127
                entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1128
                entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1129
            }
1130
 
1131
            entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
1132
            entry[FATDIR_FSTCLUSLO] = 0;
1133
            entry[FATLONG_TYPE] = 0;
1134
            entry[FATLONG_CHKSUM] = chksum;
50 theseven 1135
            DEBUGF("Longname entry %d: %s", idx, name+nameidx);
46 theseven 1136
        }
1137
        else {
1138
            /* shortname entry */
1139
            unsigned short date=0, time=0, tenth=0;
50 theseven 1140
            DEBUGF("Shortname entry: %s", shortname);
46 theseven 1141
            memcpy(entry + FATDIR_NAME, shortname, 11);
1142
            entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
1143
            entry[FATDIR_NTRES] = 0;
1144
 
1145
            fat_time(&date, &time, &tenth);
1146
            entry[FATDIR_CRTTIMETENTH] = tenth;
1147
            *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1148
            *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1149
            *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1150
            *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1151
            *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1152
        }
1153
        idx++;
1154
        nameidx -= NAME_BYTES_PER_ENTRY;
1155
    }
1156
 
1157
    /* update last sector */
1158
    rc = fat_seek(file, sector);
1159
    if (rc<0)
1160
        return rc * 10 - 6;
1161
 
1162
    rc = fat_readwrite(file, 1, buf, true);
1163
    if (rc<1)
1164
        return rc * 10 - 7;
1165
 
1166
    return 0;
1167
}
1168
 
1169
static int fat_checkname(const unsigned char* newname)
1170
{
1171
    static const char invalid_chars[] = "\"*/:<>?\\|";
1172
    int len = strlen(newname);
1173
    /* More sanity checks are probably needed */
1174
    if (len > 255 || newname[len - 1] == '.')
1175
    {
1176
        return -1;
1177
    }
1178
    while (*newname)
1179
    {
1180
        if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL)
1181
            return -1;
1182
        newname++;
1183
    }
1184
    /* check trailing space(s) */
1185
    if(*(--newname) == ' ')
1186
        return -1;
1187
 
1188
    return 0;
1189
}
1190
 
1191
static int add_dir_entry(struct fat_dir* dir,
1192
                         struct fat_file* file,
1193
                         const char* name,
1194
                         bool is_directory,
1195
                         bool dotdir)
1196
{
1197
#ifdef HAVE_MULTIVOLUME
1198
    struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1199
#else
1200
    struct bpb* fat_bpb = &fat_bpbs[0];
1201
#endif
1202
    unsigned char buf[SECTOR_SIZE];
1203
    unsigned char shortname[12];
1204
    int rc;
1205
    unsigned int sector;
1206
    bool done = false;
1207
    int entries_needed, entries_found = 0;
1208
    int firstentry;
1209
 
50 theseven 1210
    DEBUGF( "add_dir_entry(%s,%lx)",
46 theseven 1211
             name, file->firstcluster);
1212
 
1213
    /* Don't check dotdirs name for validity */
1214
    if (dotdir == false) {
1215
        rc = fat_checkname(name);
1216
        if (rc < 0) {
1217
            /* filename is invalid */
1218
            return rc * 10 - 1;
1219
        }
1220
    }
1221
 
1222
#ifdef HAVE_MULTIVOLUME
1223
    file->volume = dir->file.volume; /* inherit the volume, to make sure */
1224
#endif
1225
 
1226
    /* The "." and ".." directory entries must not be long names */
1227
    if(dotdir) {
1228
        int i;
1229
        strlcpy(shortname, name, 12);
1230
        for(i = strlen(shortname); i < 12; i++)
1231
            shortname[i] = ' ';
1232
 
1233
        entries_needed = 1;
1234
    } else {
1235
        create_dos_name(name, shortname);
1236
 
1237
        /* one dir entry needed for every 13 bytes of filename,
1238
           plus one entry for the short name */
1239
        entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1240
                         / NAME_BYTES_PER_ENTRY + 1;
1241
    }
1242
 
1243
  restart:
1244
    firstentry = -1;
1245
 
1246
    rc = fat_seek(&dir->file, 0);
1247
    if (rc < 0)
1248
        return rc * 10 - 2;
1249
 
1250
    /* step 1: search for free entries and check for duplicate shortname */
1251
    for (sector = 0; !done; sector++)
1252
    {
1253
        unsigned int i;
1254
 
1255
        rc = fat_readwrite(&dir->file, 1, buf, false);
1256
        if (rc < 0) {
1257
            DEBUGF( "add_dir_entry() - Couldn't read dir"
50 theseven 1258
                    " (error code %d)", rc);
46 theseven 1259
            return rc * 10 - 3;
1260
        }
1261
 
1262
        if (rc == 0) { /* current end of dir reached */
50 theseven 1263
            DEBUGF("End of dir on cluster boundary");
46 theseven 1264
            break;
1265
        }
1266
 
1267
        /* look for free slots */
1268
        for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1269
        {
1270
            switch (buf[i * DIR_ENTRY_SIZE]) {
1271
              case 0:
1272
                entries_found += DIR_ENTRIES_PER_SECTOR - i;
50 theseven 1273
                DEBUGF("Found end of dir %d",
46 theseven 1274
                        sector * DIR_ENTRIES_PER_SECTOR + i);
1275
                i = DIR_ENTRIES_PER_SECTOR - 1;
1276
                done = true;
1277
                break;
1278
 
1279
              case 0xe5:
1280
                entries_found++;
50 theseven 1281
                DEBUGF("Found free entry %d (%d/%d)",
46 theseven 1282
                        sector * DIR_ENTRIES_PER_SECTOR + i,
1283
                        entries_found, entries_needed);
1284
                break;
1285
 
1286
              default:
1287
                entries_found = 0;
1288
 
1289
                /* check that our intended shortname doesn't already exist */
1290
                if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) {
1291
                    /* shortname exists already, make a new one */
1292
                    randomize_dos_name(shortname);
50 theseven 1293
                    DEBUGF("Duplicate shortname, changing to %s",
46 theseven 1294
                            shortname);
1295
 
1296
                    /* name has changed, we need to restart search */
1297
                    goto restart;
1298
                }
1299
                break;
1300
            }
1301
            if (firstentry < 0 && (entries_found >= entries_needed))
1302
                firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
1303
                             - entries_found;
1304
        }
1305
    }
1306
 
1307
    /* step 2: extend the dir if necessary */
1308
    if (firstentry < 0)
1309
    {
50 theseven 1310
        DEBUGF("Adding new sector(s) to dir");
46 theseven 1311
        rc = fat_seek(&dir->file, sector);
1312
        if (rc < 0)
1313
            return rc * 10 - 4;
1314
        memset(buf, 0, sizeof buf);
1315
 
1316
        /* we must clear whole clusters */
1317
        for (; (entries_found < entries_needed) ||
1318
               (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1319
        {
1320
            if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
1321
                return -5; /* dir too large -- FAT specification */
1322
 
1323
            rc = fat_readwrite(&dir->file, 1, buf, true);
1324
            if (rc < 1)  /* No more room or something went wrong */
1325
                return rc * 10 - 6;
1326
 
1327
            entries_found += DIR_ENTRIES_PER_SECTOR;
1328
        }
1329
 
1330
        firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
1331
    }
1332
 
1333
    /* step 3: add entry */
1334
    sector = firstentry / DIR_ENTRIES_PER_SECTOR;
50 theseven 1335
    DEBUGF("Adding longname to entry %d in sector %d",
46 theseven 1336
            firstentry, sector);
1337
 
1338
    rc = write_long_name(&dir->file, firstentry,
1339
                         entries_needed, name, shortname, is_directory);
1340
    if (rc < 0)
1341
        return rc * 10 - 7;
1342
 
1343
    /* remember where the shortname dir entry is located */
1344
    file->direntry = firstentry + entries_needed - 1;
1345
    file->direntries = entries_needed;
1346
    file->dircluster = dir->file.firstcluster;
50 theseven 1347
    DEBUGF("Added new dir entry %d, using %d slots.",
46 theseven 1348
            file->direntry, file->direntries);
1349
 
1350
    return 0;
1351
}
1352
 
1353
static unsigned char char2dos(unsigned char c, int* randomize)
1354
{
1355
    static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
1356
 
1357
    if (c <= 0x20)
1358
        c = 0;   /* Illegal char, remove */
1359
    else if (strchr(invalid_chars, c) != NULL)
1360
    {
1361
        /* Illegal char, replace */
1362
        c = '_';
1363
        *randomize = 1; /* as per FAT spec */
1364
    }
1365
    else
1366
        c = toupper(c);
1367
 
1368
    return c;
1369
}
1370
 
1371
static void create_dos_name(const unsigned char *name, unsigned char *newname)
1372
{
1373
    int i;
1374
    unsigned char *ext;
1375
    int randomize = 0;
1376
 
1377
    /* Find extension part */
1378
    ext = strrchr(name, '.');
1379
    if (ext == name)         /* handle .dotnames */
1380
        ext = NULL;
1381
 
1382
    /* needs to randomize? */
1383
    if((ext && (strlen(ext) > 4)) ||
1384
       ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) )
1385
        randomize = 1;
1386
 
1387
    /* Name part */
1388
    for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
1389
    {
1390
        unsigned char c = char2dos(*name, &randomize);
1391
        if (c)
1392
            newname[i++] = c;
1393
    }
1394
 
1395
    /* Pad both name and extension */
1396
    while (i < 11)
1397
        newname[i++] = ' ';
1398
 
1399
    if (newname[0] == 0xe5) /* Special kanji character */
1400
        newname[0] = 0x05;
1401
 
1402
    if (ext)
1403
    {   /* Extension part */
1404
        ext++;
1405
        for (i = 8; *ext && (i < 11); ext++)
1406
        {
1407
            unsigned char c = char2dos(*ext, &randomize);
1408
            if (c)
1409
                newname[i++] = c;
1410
        }
1411
    }
1412
 
1413
    if(randomize)
1414
        randomize_dos_name(newname);
1415
}
1416
 
1417
static void randomize_dos_name(unsigned char *name)
1418
{
1419
    unsigned char* tilde = NULL;    /* ~ location */
1420
    unsigned char* lastpt = NULL;   /* last point of filename */
1421
    unsigned char* nameptr = name;  /* working copy of name pointer */
1422
    unsigned char num[9];           /* holds number as string */
1423
    int i = 0;
1424
    int cnt = 1;
1425
    int numlen;
1426
    int offset;
1427
 
1428
    while(i++ < 8)
1429
    {
1430
        /* hunt for ~ and where to put it */
1431
        if((!tilde) && (*nameptr == '~'))
1432
            tilde = nameptr;
1433
        if((!lastpt) && ((*nameptr == ' ' || *nameptr == '~')))
1434
            lastpt = nameptr;
1435
        nameptr++;
1436
    }
1437
    if(tilde)
1438
    {
1439
        /* extract current count and increment */
1440
        memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1441
        num[7-(unsigned int)(tilde-name)] = 0;
1442
        cnt = atoi(num) + 1;
1443
    }
1444
    cnt %= 10000000; /* protection */
1445
    snprintf(num, 9, "~%d", cnt);   /* allow room for trailing zero */
1446
    numlen = strlen(num);           /* required space */
1447
    offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1448
    if(offset > (8-numlen)) offset = 8-numlen;  /* correct for new numlen */
1449
 
1450
    memcpy(&name[offset], num, numlen);
1451
 
1452
    /* in special case of counter overflow: pad with spaces */
1453
    for(offset = offset+numlen; offset < 8; offset++)
1454
        name[offset] = ' ';
1455
}
1456
 
1457
static int update_short_entry( struct fat_file* file, long size, int attr )
1458
{
1459
    unsigned char buf[SECTOR_SIZE];
1460
    int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
1461
    unsigned char* entry =
1462
        buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1463
    unsigned long* sizeptr;
1464
    unsigned short* clusptr;
1465
    struct fat_file dir;
1466
    int rc;
1467
 
50 theseven 1468
    DEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)",
46 theseven 1469
            file->firstcluster, file->direntry, size);
1470
 
1471
    /* create a temporary file handle for the dir holding this file */
1472
    rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1473
    if (rc < 0)
1474
        return rc * 10 - 1;
1475
 
1476
    rc = fat_seek( &dir, sector );
1477
    if (rc<0)
1478
        return rc * 10 - 2;
1479
 
1480
    rc = fat_readwrite(&dir, 1, buf, false);
1481
    if (rc < 1)
1482
        return rc * 10 - 3;
1483
 
1484
    if (!entry[0] || entry[0] == 0xe5)
50 theseven 1485
        panicf(PANIC_KILLUSERTHREADS, "Updating size on empty dir entry %d", file->direntry);
46 theseven 1486
 
1487
    entry[FATDIR_ATTR] = attr & 0xFF;
1488
 
1489
    clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1490
    *clusptr = htole16(file->firstcluster >> 16);
1491
 
1492
    clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1493
    *clusptr = htole16(file->firstcluster & 0xffff);
1494
 
1495
    sizeptr = (long*)(entry + FATDIR_FILESIZE);
1496
    *sizeptr = htole32(size);
1497
 
1498
    {
1499
#if CONFIG_RTC
1500
        unsigned short time = 0;
1501
        unsigned short date = 0;
1502
#else
1503
        /* get old time to increment from */
1504
        unsigned short time = htole16(*(unsigned short*)(entry+FATDIR_WRTTIME));
1505
        unsigned short date = htole16(*(unsigned short*)(entry+FATDIR_WRTDATE));
1506
#endif
1507
        fat_time(&date, &time, NULL);
1508
        *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1509
        *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1510
        *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1511
    }
1512
 
1513
    rc = fat_seek( &dir, sector );
1514
    if (rc < 0)
1515
        return rc * 10 - 4;
1516
 
1517
    rc = fat_readwrite(&dir, 1, buf, true);
1518
    if (rc < 1)
1519
        return rc * 10 - 5;
1520
 
1521
    return 0;
1522
}
1523
 
1524
static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
1525
{
1526
    int i=0,j=0;
1527
    unsigned char c;
1528
    bool lowercase;
1529
 
1530
    memset(de, 0, sizeof(struct fat_direntry));
1531
    de->attr = buf[FATDIR_ATTR];
1532
    de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1533
    de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1534
    de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1535
    de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1536
    de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1537
    de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1538
    de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1539
        ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1540
    /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1541
       (the result of the shift is always considered signed) */
1542
 
1543
    /* fix the name */
1544
    lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1545
    c = buf[FATDIR_NAME];
1546
    if (c == 0x05)  /* special kanji char */
1547
        c = 0xe5;
1548
    i = 0;
1549
    while (c != ' ') {
1550
        de->name[j++] = lowercase ? tolower(c) : c;
1551
        if (++i >= 8)
1552
            break;
1553
        c = buf[FATDIR_NAME+i];
1554
    }
1555
    if (buf[FATDIR_NAME+8] != ' ') {
1556
        lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1557
        de->name[j++] = '.';
1558
        for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1559
            de->name[j++] = lowercase ? tolower(c) : c;
1560
    }
1561
    return 1;
1562
}
1563
 
1564
int fat_open(IF_MV2(int volume,)
1565
             long startcluster,
1566
             struct fat_file *file,
1567
             const struct fat_dir* dir)
1568
{
1569
    /* Remember where the file's dir entry is located
1570
     * Do it before assigning other fields so that fat_open
1571
     * can be called with file == &dir->file (see fat_opendir) */
1572
    if ( dir ) {
1573
        file->direntry = dir->entry - 1;
1574
        file->direntries = dir->entrycount;
1575
        file->dircluster = dir->file.firstcluster;
1576
    }
1577
 
1578
    file->firstcluster = startcluster;
1579
    file->lastcluster = startcluster;
1580
    file->lastsector = 0;
1581
    file->clusternum = 0;
1582
    file->sectornum = 0;
1583
    file->eof = false;
1584
#ifdef HAVE_MULTIVOLUME
1585
    file->volume = volume;
1586
    /* fixme: remove error check when done */
1587
    if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1588
    {
50 theseven 1589
        DEBUGF("fat_open() illegal volume %d", volume);
46 theseven 1590
        return -1;
1591
    }
1592
#endif
1593
 
50 theseven 1594
    DEBUGF("fat_open(%lx), entry %d",startcluster,file->direntry);
46 theseven 1595
    return 0;
1596
}
1597
 
1598
int fat_create_file(const char* name,
1599
                    struct fat_file* file,
1600
                    struct fat_dir* dir)
1601
{
1602
    int rc;
1603
 
50 theseven 1604
    DEBUGF("fat_create_file(\"%s\",%lx,%lx)",name,(long)file,(long)dir);
46 theseven 1605
    rc = add_dir_entry(dir, file, name, false, false);
1606
    if (!rc) {
1607
        file->firstcluster = 0;
1608
        file->lastcluster = 0;
1609
        file->lastsector = 0;
1610
        file->clusternum = 0;
1611
        file->sectornum = 0;
1612
        file->eof = false;
1613
    }
1614
 
1615
    return rc;
1616
}
1617
 
1618
int fat_create_dir(const char* name,
1619
                   struct fat_dir* newdir,
1620
                   struct fat_dir* dir)
1621
{
1622
#ifdef HAVE_MULTIVOLUME
1623
    struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1624
#else
1625
    struct bpb* fat_bpb = &fat_bpbs[0];
1626
#endif
1627
    unsigned char buf[SECTOR_SIZE];
1628
    int i;
1629
    long sector;
1630
    int rc;
1631
    struct fat_file dummyfile;
1632
 
50 theseven 1633
    DEBUGF("fat_create_dir(\"%s\",%lx,%lx)",name,(long)newdir,(long)dir);
46 theseven 1634
 
1635
    memset(newdir, 0, sizeof(struct fat_dir));
1636
    memset(&dummyfile, 0, sizeof(struct fat_file));
1637
 
1638
    /* First, add the entry in the parent directory */
1639
    rc = add_dir_entry(dir, &newdir->file, name, true, false);
1640
    if (rc < 0)
1641
        return rc * 10 - 1;
1642
 
1643
    /* Allocate a new cluster for the directory */
1644
    newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,)
1645
                                                  fat_bpb->fsinfo.nextfree);
1646
    if(newdir->file.firstcluster == 0)
1647
        return -1;
1648
 
1649
    update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
1650
 
1651
    /* Clear the entire cluster */
1652
    memset(buf, 0, sizeof buf);
1653
    sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
1654
    for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1655
        rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
1656
        if (rc < 0)
1657
            return rc * 10 - 2;
1658
    }
1659
 
1660
    /* Then add the "." entry */
1661
    rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
1662
    if (rc < 0)
1663
        return rc * 10 - 3;
1664
    dummyfile.firstcluster = newdir->file.firstcluster;
1665
    update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1666
 
1667
    /* and the ".." entry */
1668
    rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
1669
    if (rc < 0)
1670
        return rc * 10 - 4;
1671
 
1672
    /* The root cluster is cluster 0 in the ".." entry */
1673
    if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1674
        dummyfile.firstcluster = 0;
1675
    else
1676
        dummyfile.firstcluster = dir->file.firstcluster;
1677
    update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1678
 
1679
    /* Set the firstcluster field in the direntry */
1680
    update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
1681
 
1682
    rc = flush_fat(IF_MV(fat_bpb));
1683
    if (rc < 0)
1684
        return rc * 10 - 5;
1685
 
1686
    return rc;
1687
}
1688
 
1689
int fat_truncate(const struct fat_file *file)
1690
{
1691
    /* truncate trailing clusters */
1692
    long next;
1693
    long last = file->lastcluster;
1694
#ifdef HAVE_MULTIVOLUME
1695
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
1696
#endif
1697
 
50 theseven 1698
    DEBUGF("fat_truncate(%lx, %lx)", file->firstcluster, last);
46 theseven 1699
 
1700
    for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
1701
        next = get_next_cluster(IF_MV2(fat_bpb,) last);
1702
        update_fat_entry(IF_MV2(fat_bpb,) last,0);
1703
    }
1704
    if (file->lastcluster)
1705
        update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1706
 
1707
    return 0;
1708
}
1709
 
1710
int fat_closewrite(struct fat_file *file, long size, int attr)
1711
{
1712
    int rc;
1713
#ifdef HAVE_MULTIVOLUME
1714
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
1715
#endif
50 theseven 1716
    DEBUGF("fat_closewrite(size=%ld)",size);
46 theseven 1717
 
1718
    if (!size) {
1719
        /* empty file */
1720
        if ( file->firstcluster ) {
1721
            update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
1722
            file->firstcluster = 0;
1723
        }
1724
    }
1725
 
1726
    if (file->dircluster) {
1727
        rc = update_short_entry(file, size, attr);
1728
        if (rc < 0)
1729
            return rc * 10 - 1;
1730
    }
1731
 
1732
    flush_fat(IF_MV(fat_bpb));
1733
 
1734
#ifdef TEST_FAT
1735
    if ( file->firstcluster ) {
1736
        /* debug */
1737
#ifdef HAVE_MULTIVOLUME
1738
        struct bpb* fat_bpb = &fat_bpbs[file->volume];
1739
#else
1740
        struct bpb* fat_bpb = &fat_bpbs[0];
1741
#endif
1742
        long count = 0;
1743
        long len;
1744
        long next;
1745
        for ( next = file->firstcluster; next;
1746
              next = get_next_cluster(IF_MV2(fat_bpb,) next) ) {
50 theseven 1747
            DEBUGF("cluster %ld: %lx", count, next);
46 theseven 1748
            count++;
1749
        }
1750
        len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
50 theseven 1751
        DEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)",
46 theseven 1752
                count, len, size );
1753
        if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
50 theseven 1754
            panicf(PANIC_KILLUSERTHREADS, "Cluster chain is too long");
46 theseven 1755
        if ( len < size )
50 theseven 1756
            panicf(PANIC_KILLUSERTHREADS, "Cluster chain is too short");
46 theseven 1757
    }
1758
#endif
1759
 
1760
    return 0;
1761
}
1762
 
1763
static int free_direntries(struct fat_file* file)
1764
{
1765
    unsigned char buf[SECTOR_SIZE];
1766
    struct fat_file dir;
1767
    int numentries = file->direntries;
1768
    unsigned int entry = file->direntry - numentries + 1;
1769
    unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
1770
    int i;
1771
    int rc;
1772
 
1773
    /* create a temporary file handle for the dir holding this file */
1774
    rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
1775
    if (rc < 0)
1776
        return rc * 10 - 1;
1777
 
1778
    rc = fat_seek( &dir, sector );
1779
    if (rc < 0)
1780
        return rc * 10 - 2;
1781
 
1782
    rc = fat_readwrite(&dir, 1, buf, false);
1783
    if (rc < 1)
1784
        return rc * 10 - 3;
1785
 
1786
    for (i=0; i < numentries; i++) {
50 theseven 1787
        DEBUGF("Clearing dir entry %d (%d/%d)",
46 theseven 1788
                entry, i+1, numentries);
1789
        buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1790
        entry++;
1791
 
1792
        if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
1793
            /* flush this sector */
1794
            rc = fat_seek(&dir, sector);
1795
            if (rc < 0)
1796
                return rc * 10 - 4;
1797
 
1798
            rc = fat_readwrite(&dir, 1, buf, true);
1799
            if (rc < 1)
1800
                return rc * 10 - 5;
1801
 
1802
            if ( i+1 < numentries ) {
1803
                /* read next sector */
1804
                rc = fat_readwrite(&dir, 1, buf, false);
1805
                if (rc < 1)
1806
                    return rc * 10 - 6;
1807
            }
1808
            sector++;
1809
        }
1810
    }
1811
 
1812
    if ( entry % DIR_ENTRIES_PER_SECTOR ) {
1813
        /* flush this sector */
1814
        rc = fat_seek(&dir, sector);
1815
        if (rc < 0)
1816
            return rc * 10 - 7;
1817
 
1818
        rc = fat_readwrite(&dir, 1, buf, true);
1819
        if (rc < 1)
1820
            return rc * 10 - 8;
1821
    }
1822
 
1823
    return 0;
1824
}
1825
 
1826
int fat_remove(struct fat_file* file)
1827
{
1828
    long next, last = file->firstcluster;
1829
    int rc;
1830
#ifdef HAVE_MULTIVOLUME
1831
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
1832
#endif
1833
 
50 theseven 1834
    DEBUGF("fat_remove(%lx)",last);
46 theseven 1835
 
1836
    while ( last ) {
1837
        next = get_next_cluster(IF_MV2(fat_bpb,) last);
1838
        update_fat_entry(IF_MV2(fat_bpb,) last,0);
1839
        last = next;
1840
    }
1841
 
1842
    if ( file->dircluster ) {
1843
        rc = free_direntries(file);
1844
        if (rc < 0)
1845
            return rc * 10 - 1;
1846
    }
1847
 
1848
    file->firstcluster = 0;
1849
    file->dircluster = 0;
1850
 
1851
    rc = flush_fat(IF_MV(fat_bpb));
1852
    if (rc < 0)
1853
        return rc * 10 - 2;
1854
 
1855
    return 0;
1856
}
1857
 
1858
int fat_rename(struct fat_file* file, 
1859
                struct fat_dir* dir, 
1860
                const unsigned char* newname,
1861
                long size,
1862
                int attr)
1863
{
1864
    int rc;
1865
    struct fat_dir olddir;
1866
    struct fat_file newfile = *file;
1867
    unsigned char buf[SECTOR_SIZE];
1868
    unsigned char* entry = NULL;
1869
    unsigned short* clusptr = NULL;
1870
    unsigned int parentcluster;
1871
#ifdef HAVE_MULTIVOLUME
1872
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
1873
 
1874
    if (file->volume != dir->file.volume) {
50 theseven 1875
        DEBUGF("No rename across volumes!");
46 theseven 1876
        return -1;
1877
    }
1878
#else
1879
    struct bpb* fat_bpb = &fat_bpbs[0];
1880
#endif
1881
 
1882
    if ( !file->dircluster ) {
50 theseven 1883
        DEBUGF("File has no dir cluster!");
46 theseven 1884
        return -2;
1885
    }
1886
 
1887
    /* create a temporary file handle */
1888
    rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
1889
    if (rc < 0)
1890
        return rc * 10 - 1;
1891
 
1892
    /* create new name */
1893
    rc = add_dir_entry(dir, &newfile, newname, false, false);
1894
    if (rc < 0)
1895
        return rc * 10 - 2;
1896
 
1897
    /* write size and cluster link */
1898
    rc = update_short_entry(&newfile, size, attr);
1899
    if (rc < 0)
1900
        return rc * 10 - 3;
1901
 
1902
    /* remove old name */
1903
    rc = free_direntries(file);
1904
    if (rc < 0)
1905
        return rc * 10 - 4;
1906
 
1907
    rc = flush_fat(IF_MV(fat_bpb));
1908
    if (rc < 0)
1909
        return rc * 10 - 5;
1910
 
1911
    /* if renaming a directory, update the .. entry to make sure
1912
       it points to its parent directory (we don't check if it was a move) */
1913
    if(FAT_ATTR_DIRECTORY == attr) {
1914
        /* open the dir that was renamed, we re-use the olddir struct */
1915
        rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
1916
                                                                          NULL);
1917
        if (rc < 0)
1918
            return rc * 10 - 6;
1919
 
1920
        /* get the first sector of the dir */
1921
        rc = fat_seek(&olddir.file, 0);
1922
        if (rc < 0)
1923
            return rc * 10 - 7;
1924
 
1925
        rc = fat_readwrite(&olddir.file, 1, buf, false);
1926
        if (rc < 0)
1927
            return rc * 10 - 8;
1928
 
1929
        /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
1930
        if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
1931
            parentcluster = 0;
1932
        else
1933
            parentcluster = dir->file.firstcluster;
1934
 
1935
        entry = buf + DIR_ENTRY_SIZE;
1936
        if(strncmp("..         ", entry, 11))
1937
        {
1938
            /* .. entry must be second entry according to FAT spec (p.29) */
50 theseven 1939
            DEBUGF("Second dir entry is not double-dot!");
46 theseven 1940
            return rc * 10 - 9;
1941
        }
1942
        clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
1943
        *clusptr = htole16(parentcluster >> 16);
1944
 
1945
        clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
1946
        *clusptr = htole16(parentcluster & 0xffff);
1947
 
1948
        /* write back this sector */
1949
        rc = fat_seek(&olddir.file, 0);
1950
        if (rc < 0)
1951
            return rc * 10 - 7;
1952
 
1953
        rc = fat_readwrite(&olddir.file, 1, buf, true);
1954
        if (rc < 1)
1955
            return rc * 10 - 8;
1956
    }
1957
 
1958
    return 0;
1959
}
1960
 
1961
static long next_write_cluster(struct fat_file* file,
1962
                              long oldcluster,
1963
                              long* newsector)
1964
{
1965
#ifdef HAVE_MULTIVOLUME
1966
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
1967
#else
1968
    struct bpb* fat_bpb = &fat_bpbs[0];
1969
#endif
1970
    long cluster = 0;
1971
    long sector;
1972
 
50 theseven 1973
    DEBUGF("next_write_cluster(%lx,%lx)",file->firstcluster, oldcluster);
46 theseven 1974
 
1975
    if (oldcluster)
1976
        cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
1977
 
1978
    if (!cluster) {
1979
        if (oldcluster > 0)
1980
            cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
1981
        else if (oldcluster == 0)
1982
            cluster = find_free_cluster(IF_MV2(fat_bpb,)
1983
                                        fat_bpb->fsinfo.nextfree);
1984
#ifdef HAVE_FAT16SUPPORT
1985
        else /* negative, pseudo-cluster of the root dir */
1986
            return 0; /* impossible to append something to the root */
1987
#endif
1988
 
1989
        if (cluster) {
1990
            if (oldcluster)
1991
                update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
1992
            else
1993
                file->firstcluster = cluster;
1994
            update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
1995
        }
1996
        else {
1997
#ifdef TEST_FAT
1998
            if (fat_bpb->fsinfo.freecount>0)
50 theseven 1999
                panicf(PANIC_KILLUSERTHREADS, "There is free space, but find_free_cluster() "
2000
                       "didn't find it!");
46 theseven 2001
#endif
50 theseven 2002
            DEBUGF("next_write_cluster(): Disk full!");
46 theseven 2003
            return 0;
2004
        }
2005
    }
2006
    sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2007
    if (sector<0)
2008
        return 0;
2009
 
2010
    *newsector = sector;
2011
    return cluster;
2012
}
2013
 
2014
static int transfer(IF_MV2(struct bpb* fat_bpb,) 
2015
                    unsigned long start, long count, char* buf, bool write )
2016
{
2017
#ifndef HAVE_MULTIVOLUME
2018
    struct bpb* fat_bpb = &fat_bpbs[0];
2019
#endif
2020
    int rc;
2021
 
50 theseven 2022
    DEBUGF("transfer(s=%lx, c=%lx, %s)",
46 theseven 2023
        start+ fat_bpb->startsector, count, write?"write":"read");
2024
    if (write) {
2025
        unsigned long firstallowed;
2026
#ifdef HAVE_FAT16SUPPORT
2027
        if (fat_bpb->is_fat16)
2028
            firstallowed = fat_bpb->rootdirsector;
2029
        else
2030
#endif
2031
            firstallowed = fat_bpb->firstdatasector;
2032
 
2033
        if (start < firstallowed)
50 theseven 2034
            panicf(PANIC_KILLUSERTHREADS, "Write %ld before data", firstallowed - start);
46 theseven 2035
        if (start + count > fat_bpb->totalsectors)
50 theseven 2036
            panicf(PANIC_KILLUSERTHREADS, "Write %ld after data",
46 theseven 2037
                start + count - fat_bpb->totalsectors);
2038
        rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
2039
                               start + fat_bpb->startsector, count, buf);
2040
    }
2041
    else
2042
        rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
2043
                              start + fat_bpb->startsector, count, buf);
2044
    if (rc < 0) {
2045
        DEBUGF( "transfer() - Couldn't %s sector %lx"
50 theseven 2046
                " (error code %d)", 
46 theseven 2047
                write ? "write":"read", start, rc);
2048
        return rc;
2049
    }
2050
    return 0;
2051
}
2052
 
2053
 
2054
long fat_readwrite( struct fat_file *file, long sectorcount,
2055
                   void* buf, bool write )
2056
{
2057
#ifdef HAVE_MULTIVOLUME
2058
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
2059
#else
2060
    struct bpb* fat_bpb = &fat_bpbs[0];
2061
#endif
2062
    long cluster = file->lastcluster;
2063
    long sector = file->lastsector;
2064
    long clusternum = file->clusternum;
2065
    long numsec = file->sectornum;
2066
    bool eof = file->eof;
2067
    long first=0, last=0;
2068
    long i;
2069
    int rc;
2070
 
50 theseven 2071
    DEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)",
46 theseven 2072
             file->firstcluster,sectorcount,(long)buf,write?"write":"read");
50 theseven 2073
    DEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d",
46 theseven 2074
             sector,numsec, eof?1:0);
2075
 
2076
    if ( eof && !write)
2077
        return 0;
2078
 
2079
    /* find sequential sectors and write them all at once */
2080
    for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2081
        numsec++;
2082
        if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2083
            long oldcluster = cluster;
2084
            long oldsector = sector;
2085
            long oldnumsec = numsec;
2086
            if (write)
2087
                cluster = next_write_cluster(file, cluster, &sector);
2088
            else {
2089
                cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2090
                sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
2091
            }
2092
 
2093
            clusternum++;
2094
            numsec=1;
2095
 
2096
            if (!cluster) {
2097
                eof = true;
2098
                if ( write ) {
2099
                    /* remember last cluster, in case
2100
                       we want to append to the file */
2101
                    sector = oldsector;
2102
                    cluster = oldcluster;
2103
                    numsec = oldnumsec;
2104
                    clusternum--;
2105
                    i = -1; /* Error code */
2106
                    break;
2107
                }
2108
            }
2109
            else
2110
                eof = false;
2111
        }
2112
        else {
2113
            if (sector)
2114
                sector++;
2115
            else {
2116
                /* look up first sector of file */
2117
                sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
2118
                numsec=1;
2119
#ifdef HAVE_FAT16SUPPORT
2120
                if (file->firstcluster < 0)
2121
                {   /* FAT16 root dir */
2122
                    sector += fat_bpb->rootdiroffset;
2123
                    numsec += fat_bpb->rootdiroffset;
2124
                }
2125
#endif
2126
            }
2127
        }
2128
 
2129
        if (!first)
2130
            first = sector;
2131
 
2132
        if ( ((sector != first) && (sector != last+1)) || /* not sequential */
2133
             (last-first+1 == 256) ) { /* max 256 sectors per ata request */
2134
            long count = last - first + 1;
2135
            rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2136
            if (rc < 0)
2137
                return rc * 10 - 1;
2138
 
2139
            buf = (char *)buf + count * SECTOR_SIZE;
2140
            first = sector;
2141
        }
2142
 
2143
        if ((i == sectorcount-1) && /* last sector requested */
2144
            (!eof))
2145
        {
2146
            long count = sector - first + 1;
2147
            rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
2148
            if (rc < 0)
2149
                return rc * 10 - 2;
2150
        }
2151
 
2152
        last = sector;
2153
    }
2154
 
2155
    file->lastcluster = cluster;
2156
    file->lastsector = sector;
2157
    file->clusternum = clusternum;
2158
    file->sectornum = numsec;
2159
    file->eof = eof;
2160
 
2161
    /* if eof, don't report last block as read/written */
2162
    if (eof)
2163
        i--;
2164
 
50 theseven 2165
    DEBUGF("Sectors written: %ld", i);
46 theseven 2166
    return i;
2167
}
2168
 
2169
int fat_seek(struct fat_file *file, unsigned long seeksector )
2170
{
2171
#ifdef HAVE_MULTIVOLUME
2172
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
2173
#else
2174
    struct bpb* fat_bpb = &fat_bpbs[0];
2175
#endif
2176
    long clusternum=0, numclusters=0, sectornum=0, sector=0;
2177
    long cluster = file->firstcluster;
2178
    long i;
2179
 
2180
#ifdef HAVE_FAT16SUPPORT
2181
    if (cluster < 0) /* FAT16 root dir */
2182
        seeksector += fat_bpb->rootdiroffset;
2183
#endif
2184
 
2185
    file->eof = false;
2186
    if (seeksector) {
2187
        /* we need to find the sector BEFORE the requested, since
2188
           the file struct stores the last accessed sector */
2189
        seeksector--;
2190
        numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
2191
        sectornum = seeksector % fat_bpb->bpb_secperclus;
2192
 
2193
        if (file->clusternum && clusternum >= file->clusternum)
2194
        {
2195
            cluster = file->lastcluster;
2196
            numclusters -= file->clusternum;
2197
        }
2198
 
2199
        for (i=0; i<numclusters; i++) {
2200
            cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
2201
            if (!cluster) {
2202
                DEBUGF("Seeking beyond the end of the file! "
50 theseven 2203
                       "(sector %ld, cluster %ld)", seeksector, i);
46 theseven 2204
                return -1;
2205
            }
2206
        }
2207
 
2208
        sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
2209
    }
2210
    else {
2211
        sectornum = -1;
2212
    }
2213
 
50 theseven 2214
    DEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx",
46 theseven 2215
            file->firstcluster, seeksector, cluster, sector, sectornum);
2216
 
2217
    file->lastcluster = cluster;
2218
    file->lastsector = sector;
2219
    file->clusternum = clusternum;
2220
    file->sectornum = sectornum + 1;
2221
    return 0;
2222
}
2223
 
2224
int fat_opendir(IF_MV2(int volume,) 
2225
                struct fat_dir *dir, unsigned long startcluster,
2226
                const struct fat_dir *parent_dir)
2227
{
2228
#ifdef HAVE_MULTIVOLUME
2229
    struct bpb* fat_bpb = &fat_bpbs[volume];
2230
    /* fixme: remove error check when done */
2231
    if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
2232
    {
50 theseven 2233
        DEBUGF("fat_open() illegal volume %d", volume);
46 theseven 2234
        return -1;
2235
    }
2236
#else
2237
    struct bpb* fat_bpb = &fat_bpbs[0];
2238
#endif
2239
    int rc;
2240
 
2241
    if (startcluster == 0)
2242
        startcluster = fat_bpb->bpb_rootclus;
2243
 
2244
    rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
2245
    if(rc)
2246
    {
2247
        DEBUGF( "fat_opendir() - Couldn't open dir"
50 theseven 2248
                " (error code %d)", rc);
46 theseven 2249
        return rc * 10 - 1;
2250
    }
2251
 
2252
    /* assign them after fat_open call so that fat_opendir can be called with the same
2253
     * fat_dir as parent and result */
2254
    dir->entry = 0;
2255
    dir->sector = 0;
2256
 
2257
    return 0;
2258
}
2259
 
2260
int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2261
{
2262
    bool done = false;
2263
    int i, j;
2264
    int rc;
2265
    int order;
2266
    unsigned char firstbyte;
2267
    /* Long file names are stored in special entries. Each entry holds
2268
       up to 13 characters. Names can be max 255 chars (not bytes!) long */
2269
    /* The number of long entries in the long name can be retrieve from the first
2270
     * long entry because there are stored in reverse order and have an ordinal */
2271
    int nb_longs = 0;
2272
    /* The long entries are expected to be in order, so remember the last ordinal */
2273
    int last_long_ord = 0;
2274
 
2275
    dir->entrycount = 0;
2276
 
2277
    while(!done)
2278
    {
2279
        if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
2280
        {
2281
            rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false);
2282
            if (rc == 0) {
2283
                /* eof */
2284
                entry->name[0] = 0;
2285
                break;
2286
            }
2287
            if (rc < 0) {
2288
                DEBUGF( "fat_getnext() - Couldn't read dir"
50 theseven 2289
                        " (error code %d)", rc);
46 theseven 2290
                return rc * 10 - 1;
2291
            }
2292
            dir->sector = dir->file.lastsector;
2293
        }
2294
 
2295
        for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
2296
             i < DIR_ENTRIES_PER_SECTOR; i++) {
2297
            unsigned int entrypos = i * DIR_ENTRY_SIZE;
2298
 
2299
            firstbyte = dir->sectorcache[entrypos];
2300
            dir->entry++;
2301
 
2302
            if (firstbyte == 0xe5) {
2303
                /* free entry */
2304
                dir->entrycount = 0;
2305
                continue;
2306
            }
2307
 
2308
            if (firstbyte == 0) {
2309
                /* last entry */
2310
                entry->name[0] = 0;
2311
                dir->entrycount = 0;
2312
                return 0;
2313
            }
2314
 
2315
            dir->entrycount++;
2316
 
2317
            /* LFN entry? */
2318
            if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] &
2319
                   FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
2320
                /* extract ordinal */
2321
                order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY;
2322
                /* is this entry the first long entry ? (first in order but containing last part) */
2323
                if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) {
2324
                    /* check that order is not too big ! (and non-zero) */
2325
                    if(order <= 0 || order > FATLONG_MAX_ORDER)
2326
                        continue; /* ignore the whole LFN, will trigger lots of warnings */
2327
                    nb_longs = order;
2328
                    last_long_ord = order;
2329
                }
2330
                else {
2331
                    /* check orphan entry */
2332
                    if (nb_longs == 0) {
47 farthen 2333
                        DEBUGF("fat warning: orphan LFN entry");
46 theseven 2334
                        /* ignore */
2335
                        continue;
2336
                    }
2337
 
2338
                    /* check order */
2339
                    if (order != (last_long_ord - 1)) {
47 farthen 2340
                        DEBUGF("fat warning: wrong LFN ordinal");
46 theseven 2341
                        /* ignore the whole LFN, will trigger lots of warnings */
2342
                        nb_longs = 0;
2343
                    }
2344
 
2345
                    last_long_ord = order;
2346
                }
2347
 
2348
                /* copy part, reuse [order] for another purpose :) */
2349
                order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY;
2350
                for(j = 0; j < FATLONG_NAME_CHUNKS; j++) {
2351
                    memcpy(dir->longname + order,
2352
                            dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2353
                            FATLONG_NAME_SIZE[j]);
2354
                    order += FATLONG_NAME_SIZE[j];
2355
                }
2356
            }
2357
            else {
2358
                if ( parse_direntry(entry, dir->sectorcache + entrypos) ) {
2359
 
2360
                    /* don't return volume id entry */
2361
                    if ( (entry->attr &
2362
                          (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY))
2363
                         == FAT_ATTR_VOLUME_ID)
2364
                        continue;
2365
 
2366
                    /* replace shortname with longname? */
2367
                    /* check that the long name is complete */
2368
                    if (nb_longs != 0 && last_long_ord == 1) {
2369
                        /* hold a copy of the shortname in case the long one is too long */
2370
                        unsigned char shortname[13]; /* 8+3+dot+\0 */
2371
                        int longname_utf8len = 0;
2372
                        /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2373
                         * of a UTF8 encoded character in rockbox */
2374
                        unsigned char longname_utf8segm[4 + 1];
2375
                        unsigned short ucs;
2376
                        int segm_utf8len;
2377
                        /* Temporarily store short name */
2378
                        strcpy(shortname, entry->name);
2379
                        entry->name[0] = 0;
2380
 
2381
                        /* Convert the FAT name to a utf8-encoded one.
2382
                         * The name is not necessary NUL-terminated ! */
2383
                        for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2384
                            ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2385
                            if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2386
                                break;
2387
                            /* utf8encode will return a pointer after the converted
2388
                             * string, subtract the pointer to the start to get the length of it */
51 theseven 2389
                            segm_utf8len = 1;
46 theseven 2390
 
2391
                            /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2392
                            if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2393
                                /* force use of short name */
2394
                                longname_utf8len = FAT_FILENAME_BYTES + 1;
2395
                                break; /* fallback later */
2396
                            }
2397
                            else {
51 theseven 2398
                                if (ucs < 128) longname_utf8segm[0] = (unsigned char)ucs;
2399
                                else longname_utf8segm[0] = '?';
46 theseven 2400
                                longname_utf8segm[segm_utf8len] = 0;
2401
                                strcat(entry->name + longname_utf8len, longname_utf8segm);
2402
                                longname_utf8len += segm_utf8len;
2403
                            }
2404
                        }
2405
 
2406
                        /* Does the utf8-encoded name fit into the entry? */
2407
                        /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2408
                        if (longname_utf8len >= FAT_FILENAME_BYTES) {
2409
                            /* Take the short DOS name. Need to utf8-encode it
2410
                               since it may contain chars from the upper half of
2411
                               the OEM code page which wouldn't be a valid utf8.
2412
                               Beware: this file will be shown with strange
2413
                               glyphs in file browser since unicode 0x80 to 0x9F
2414
                               are control characters. */
47 farthen 2415
                            DEBUGF("SN-DOS: %s", shortname);
46 theseven 2416
                            unsigned char *utf8;
51 theseven 2417
                            memcpy(entry->name, shortname, strlen(shortname));
2418
                            *(entry->name + strlen(shortname)) = 0;
47 farthen 2419
                            DEBUGF("SN: %s", entry->name);
46 theseven 2420
                        } else {
47 farthen 2421
                            DEBUGF("LN: %s", entry->name);
2422
                            DEBUGF("LNLen: %d", longname_utf8len);
46 theseven 2423
                        }
2424
                    }
2425
                    done = true;
2426
                    i++;
2427
                    break;
2428
                }
2429
            }
2430
        }
2431
    }
2432
    return 0;
2433
}
2434
 
2435
unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2436
{
2437
#ifndef HAVE_MULTIVOLUME
2438
    const int volume = 0;
2439
#endif
2440
    struct bpb* fat_bpb = &fat_bpbs[volume];
2441
    return fat_bpb->bpb_secperclus * SECTOR_SIZE;
2442
}
2443
 
2444
#ifdef HAVE_MULTIVOLUME
2445
bool fat_ismounted(int volume)
2446
{
2447
    return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
2448
}
2449
#endif