Subversion Repositories freemyipod

Rev

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