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