OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [FileSystem/] [FatFs-0.7e/] [src/] [ff.c] - Blame information for rev 606

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/*----------------------------------------------------------------------------/
2
/  FatFs - FAT file system module  R0.07e                    (C)ChaN, 2009
3
/-----------------------------------------------------------------------------/
4
/ FatFs module is a generic FAT file system module for small embedded systems.
5
/ This is a free software that opened for education, research and commercial
6
/ developments under license policy of following trems.
7
/
8
/  Copyright (C) 2009, ChaN, all right reserved.
9
/
10
/ * The FatFs module is a free software and there is NO WARRANTY.
11
/ * No restriction on use. You can use, modify and redistribute it for
12
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
13
/ * Redistributions of source code must retain the above copyright notice.
14
/
15
/-----------------------------------------------------------------------------/
16
/ Feb 26,'06 R0.00  Prototype.
17
/
18
/ Apr 29,'06 R0.01  First stable version.
19
/
20
/ Jun 01,'06 R0.02  Added FAT12 support.
21
/                   Removed unbuffered mode.
22
/                   Fixed a problem on small (<32M) patition.
23
/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
24
/
25
/ Sep 22,'06 R0.03  Added f_rename().
26
/                   Changed option _FS_MINIMUM to _FS_MINIMIZE.
27
/ Dec 11,'06 R0.03a Improved cluster scan algolithm to write files fast.
28
/                   Fixed f_mkdir() creates incorrect directory on FAT32.
29
/
30
/ Feb 04,'07 R0.04  Supported multiple drive system.
31
/                   Changed some interfaces for multiple drive system.
32
/                   Changed f_mountdrv() to f_mount().
33
/                   Added f_mkfs().
34
/ Apr 01,'07 R0.04a Supported multiple partitions on a plysical drive.
35
/                   Added a capability of extending file size to f_lseek().
36
/                   Added minimization level 3.
37
/                   Fixed an endian sensitive code in f_mkfs().
38
/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
39
/                   Added FSInfo support.
40
/                   Fixed DBCS name can result FR_INVALID_NAME.
41
/                   Fixed short seek (<= csize) collapses the file object.
42
/
43
/ Aug 25,'07 R0.05  Changed arguments of f_read(), f_write() and f_mkfs().
44
/                   Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
45
/                   Fixed f_mkdir() on FAT32 creates incorrect directory.
46
/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
47
/                   Fixed off by one error at FAT sub-type determination.
48
/                   Fixed btr in f_read() can be mistruncated.
49
/                   Fixed cached sector is not flushed when create and close
50
/                   without write.
51
/
52
/ Apr 01,'08 R0.06  Added fputc(), fputs(), fprintf() and fgets().
53
/                   Improved performance of f_lseek() on moving to the same
54
/                   or following cluster.
55
/
56
/ Apr 01,'09 R0.07  Merged Tiny-FatFs as a buffer configuration option.
57
/                   Added long file name support.
58
/                   Added multiple code page support.
59
/                   Added re-entrancy for multitask operation.
60
/                   Added auto cluster size selection to f_mkfs().
61
/                   Added rewind option to f_readdir().
62
/                   Changed result code of critical errors.
63
/                   Renamed string functions to avoid name collision.
64
/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
65
/                   Added multiple sector size support.
66
/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
67
/                   Fixed wrong cache control in f_lseek().
68
/                   Added relative path feature.
69
/                   Added f_chdir() and f_chdrive().
70
/                   Added proper case conversion to extended char.
71
/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
72
/                   Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
73
/                   Fixed name matching error on the 13 char boundary.
74
/                   Added a configuration option, _LFN_UNICODE.
75
/                   Changed f_readdir() to return the SFN with always upper
76
/                   case on non-LFN cfg.
77
/---------------------------------------------------------------------------*/
78
#include "ff.h"                                         /* FatFs configurations and declarations */
79
#include "diskio.h"                                     /* Declarations of low level disk I/O functions */
80
 
81
/*--------------------------------------------------------------------------
82
 
83
   Module Private Definitions
84
 
85
---------------------------------------------------------------------------*/
86
#if _FATFS != 0x007E
87
        #error Wrong include file (ff.h).
88
#endif
89
#if _FS_REENTRANT
90
        #if _USE_LFN == 1
91
                #error Static LFN work area must not be used in re-entrant configuration.
92
        #endif
93
        #define ENTER_FF( fs )     \
94
        {                                                  \
95
                if( !lock_fs(fs) )         \
96
                {                                          \
97
                        return FR_TIMEOUT; \
98
                }                                          \
99
        }
100
 
101
        #define LEAVE_FF( fs, res ) \
102
        {                                                       \
103
                unlock_fs( fs, res );   \
104
                return res;                             \
105
        }
106
 
107
#else
108
        #define ENTER_FF( fs )
109
        #define LEAVE_FF( fs, res ) return res
110
#endif
111
#define ABORT( fs, res )           \
112
        {                                                  \
113
                fp->flag |= FA__ERROR; \
114
                LEAVE_FF( fs, res );   \
115
        }
116
 
117
#ifndef NULL
118
        #define NULL    0
119
#endif
120
 
121
/* Name status flags */
122
#define NS              11                                      /* Offset of name status byte */
123
#define NS_LOSS 0x01                            /* Out of 8.3 format */
124
#define NS_LFN  0x02                            /* Force to create LFN entry */
125
#define NS_LAST 0x04                            /* Last segment */
126
#define NS_BODY 0x08                            /* Lower case flag (body) */
127
#define NS_EXT  0x10                            /* Lower case flag (ext) */
128
#define NS_DOT  0x20                            /* Dot entry */
129
 
130
/*--------------------------------------------------------------------------
131
 
132
   Private Work Area
133
 
134
---------------------------------------------------------------------------*/
135
#if _DRIVES < 1 || _DRIVES > 9
136
        #error Number of drives must be 1-9.
137
#endif
138
static FATFS    *FatFs[_DRIVES];        /* Pointer to the file system objects (logical drives) */
139
 
140
static WORD             Fsid;                           /* File system mount ID */
141
 
142
#if _FS_RPATH
143
static BYTE             Drive;                          /* Current drive */
144
#endif
145
#if _USE_LFN == 1                                       /* LFN with static LFN working buffer */
146
static WCHAR    LfnBuf[_MAX_LFN + 1];
147
        #define NAMEBUF( sp, lp ) \
148
        BYTE  sp[12];                     \
149
        WCHAR                                           *lp = LfnBuf
150
        #define INITBUF( dj, sp, lp ) \
151
        dj.fn = sp;                                       \
152
        dj.lfn = lp
153
 
154
#elif _USE_LFN > 1                                      /* LFN with dynamic LFN working buffer */
155
        #define NAMEBUF( sp, lp ) \
156
        BYTE sp[12];                      \
157
        WCHAR   lbuf[_MAX_LFN + 1], *lp = lbuf
158
        #define INITBUF( dj, sp, lp ) \
159
        dj.fn = sp;                                       \
160
        dj.lfn = lp
161
 
162
#else /* No LFN */
163
        #define NAMEBUF( sp, lp )               BYTE sp[12]
164
        #define INITBUF( dj, sp, lp )   dj.fn = sp
165
#endif
166
 
167
/*--------------------------------------------------------------------------
168
 
169
   Module Private Functions
170
 
171
---------------------------------------------------------------------------*/
172
 
173
/*-----------------------------------------------------------------------*/
174
 
175
/* String functions                                                      */
176
 
177
/*-----------------------------------------------------------------------*/
178
 
179
/* Copy memory to memory */
180
static void mem_cpy ( void *dst, const void *src, int cnt )
181
{
182
        char *d = ( char * ) dst;
183
        const char *s = ( const char * ) src;
184
        while( cnt-- )
185
        {
186
                *d++ = *s++;
187
        }
188
}
189
 
190
/* Fill memory */
191
static void mem_set ( void *dst, int val, int cnt )
192
{
193
        char *d = ( char * ) dst;
194
        while( cnt-- )
195
        {
196
                *d++ = ( char ) val;
197
        }
198
}
199
 
200
/* Compare memory to memory */
201
static int mem_cmp ( const void *dst, const void *src, int cnt )
202
{
203
        const char *d = ( const char * ) dst, *s = ( const char * ) src;
204
        int r = 0;
205
        while( cnt-- && (r = *d++ -*s++) == 0 );
206
        return r;
207
}
208
 
209
/* Check if chr is contained in the string */
210
static int chk_chr ( const char *str, int chr )
211
{
212
        while( *str && *str != chr )
213
        {
214
                str++;
215
        }
216
 
217
        return *str;
218
}
219
 
220
/*-----------------------------------------------------------------------*/
221
 
222
/* Request/Release grant to access the volume                            */
223
 
224
/*-----------------------------------------------------------------------*/
225
#if _FS_REENTRANT
226
static BOOL lock_fs ( FATFS * fs /* File system object */ )
227
{
228
        return ff_req_grant( fs->sobj );
229
}
230
 
231
static void unlock_fs ( FATFS * fs, /* File system object */ FRESULT res /* Result code to be returned */ )
232
{
233
        if( res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_INVALID_OBJECT && res != FR_TIMEOUT )
234
        {
235
                ff_rel_grant( fs->sobj );
236
        }
237
}
238
 
239
#endif
240
 
241
/*-----------------------------------------------------------------------*/
242
 
243
/* Change window offset                                                  */
244
 
245
/*-----------------------------------------------------------------------*/
246
static FRESULT move_window ( FATFS * fs, /* File system object */ DWORD sector /* Sector number to make apperance in the fs->win[] */ ) /* Move to zero only writes back dirty window */
247
{
248
        DWORD wsect;
249
 
250
        wsect = fs->winsect;
251
        if( wsect != sector )
252
        {                               /* Changed current window */
253
                #if !_FS_READONLY
254
                if( fs->wflag )
255
                {                       /* Write back dirty window if needed */
256
                        if( disk_write(fs->drive, fs->win, wsect, 1) != RES_OK )
257
                        {
258
                                return FR_DISK_ERR;
259
                        }
260
 
261
                        fs->wflag = 0;
262
                        if( wsect < (fs->fatbase + fs->sects_fat) )
263
                        {               /* In FAT area */
264
                                BYTE nf;
265
                                for( nf = fs->n_fats; nf > 1; nf-- )
266
                                {       /* Refrect the change to all FAT copies */
267
                                        wsect += fs->sects_fat;
268
                                        disk_write( fs->drive, fs->win, wsect, 1 );
269
                                }
270
                        }
271
                }
272
 
273
                #endif
274
                if( sector )
275
                {
276
                        if( disk_read(fs->drive, fs->win, sector, 1) != RES_OK )
277
                        {
278
                                return FR_DISK_ERR;
279
                        }
280
 
281
                        fs->winsect = sector;
282
                }
283
        }
284
 
285
        return FR_OK;
286
}
287
 
288
/*-----------------------------------------------------------------------*/
289
 
290
/* Clean-up cached data                                                  */
291
 
292
/*-----------------------------------------------------------------------*/
293
#if !_FS_READONLY
294
static FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */ FATFS * fs /* File system object */ )
295
{
296
        FRESULT res;
297
 
298
        res = move_window( fs, 0 );
299
        if( res == FR_OK )
300
        {
301
                /* Update FSInfo sector if needed */
302
                if( fs->fs_type == FS_FAT32 && fs->fsi_flag )
303
                {
304
                        fs->winsect = 0;
305
                        mem_set( fs->win, 0, 512 );
306
                        ST_WORD( fs->win + BS_55AA, 0xAA55 );
307
                        ST_DWORD( fs->win + FSI_LeadSig, 0x41615252 );
308
                        ST_DWORD( fs->win + FSI_StrucSig, 0x61417272 );
309
                        ST_DWORD( fs->win + FSI_Free_Count, fs->free_clust );
310
                        ST_DWORD( fs->win + FSI_Nxt_Free, fs->last_clust );
311
                        disk_write( fs->drive, fs->win, fs->fsi_sector, 1 );
312
                        fs->fsi_flag = 0;
313
                }
314
 
315
                /* Make sure that no pending write process in the physical drive */
316
                if( disk_ioctl(fs->drive, CTRL_SYNC, ( void * ) NULL) != RES_OK )
317
                {
318
                        res = FR_DISK_ERR;
319
                }
320
        }
321
 
322
        return res;
323
}
324
 
325
#endif
326
 
327
/*-----------------------------------------------------------------------*/
328
 
329
/* FAT access - Read value of a FAT entry                                */
330
 
331
/*-----------------------------------------------------------------------*/
332
DWORD get_fat
333
        (                               /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */
334
                FATFS * fs, /* File system object */ DWORD clst /* Cluster# to get the link information */
335
        )
336
{
337
        UINT wc, bc;
338
        DWORD fsect;
339
 
340
        if( clst < 2 || clst >= fs->max_clust )
341
        {                                       /* Range check */
342
                return 1;
343
        }
344
 
345
        fsect = fs->fatbase;
346
        switch( fs->fs_type )
347
        {
348
                case FS_FAT12:
349
                        bc = clst;
350
                        bc += bc / 2;
351
                        if( move_window(fs, fsect + (bc / SS(fs))) )
352
                        {
353
                                break;
354
                        }
355
 
356
                        wc = fs->win[bc & ( SS(fs) - 1 )];
357
                        bc++;
358
                        if( move_window(fs, fsect + (bc / SS(fs))) )
359
                        {
360
                                break;
361
                        }
362
 
363
                        wc |= ( WORD ) fs->win[bc & ( SS(fs) - 1 )] << 8;
364
                        return( clst & 1 ) ? ( wc >> 4 ) : ( wc & 0xFFF );
365
 
366
                case FS_FAT16:
367
                        if( move_window(fs, fsect + (clst / (SS(fs) / 2))) )
368
                        {
369
                                break;
370
                        }
371
 
372
                        return LD_WORD( &fs->win[((WORD) clst * 2) & (SS(fs) - 1)] );
373
 
374
                case FS_FAT32:
375
                        if( move_window(fs, fsect + (clst / (SS(fs) / 4))) )
376
                        {
377
                                break;
378
                        }
379
 
380
                        return
381
                        LD_DWORD( &fs->win[((WORD) clst * 4) & (SS(fs) - 1)] )
382
                        & 0x0FFFFFFF;
383
        }
384
 
385
        return 0xFFFFFFFF;      /* An error occured at the disk I/O layer */
386
}
387
 
388
/*-----------------------------------------------------------------------*/
389
 
390
/* FAT access - Change value of a FAT entry                              */
391
 
392
/*-----------------------------------------------------------------------*/
393
#if !_FS_READONLY
394
FRESULT put_fat
395
        ( FATFS * fs, /* File system object */ DWORD clst, /* Cluster# to be changed in range of 2 to fs->max_clust - 1 */ DWORD val    /* New value to mark the cluster */ )
396
{
397
        UINT bc;
398
        BYTE * p;
399
        DWORD fsect;
400
        FRESULT res;
401
 
402
        if( clst < 2 || clst >= fs->max_clust )
403
        {                                       /* Range check */
404
                res = FR_INT_ERR;
405
        }
406
        else
407
        {
408
                fsect = fs->fatbase;
409
                switch( fs->fs_type )
410
                {
411
                        case FS_FAT12:
412
                                bc = clst;
413
                                bc += bc / 2;
414
                                res = move_window( fs, fsect + (bc / SS(fs)) );
415
                                if( res != FR_OK )
416
                                {
417
                                        break;
418
                                }
419
 
420
                                p = &fs->win[bc & ( SS(fs) - 1 )];
421
                                *p = ( clst & 1 ) ? ( (*p & 0x0F) | ((BYTE) val << 4) ) : ( BYTE ) val;
422
                                bc++;
423
                                fs->wflag = 1;
424
                                res = move_window( fs, fsect + (bc / SS(fs)) );
425
                                if( res != FR_OK )
426
                                {
427
                                        break;
428
                                }
429
 
430
                                p = &fs->win[bc & ( SS(fs) - 1 )];
431
                                *p = ( clst & 1 ) ? ( BYTE ) ( val >> 4 ) : ( (*p & 0xF0) | ((BYTE) (val >> 8) & 0x0F) );
432
                                break;
433
 
434
                        case FS_FAT16:
435
                                res = move_window( fs, fsect + (clst / (SS(fs) / 2)) );
436
                                if( res != FR_OK )
437
                                {
438
                                        break;
439
                                }
440
 
441
                                ST_WORD( &fs->win[((WORD) clst * 2) & (SS(fs) - 1)], (WORD) val );
442
                                break;
443
 
444
                        case FS_FAT32:
445
                                res = move_window( fs, fsect + (clst / (SS(fs) / 4)) );
446
                                if( res != FR_OK )
447
                                {
448
                                        break;
449
                                }
450
 
451
                                ST_DWORD( &fs->win[((WORD) clst * 4) & (SS(fs) - 1)], val );
452
                                break;
453
 
454
                        default:
455
                                res = FR_INT_ERR;
456
                }
457
 
458
                fs->wflag = 1;
459
        }
460
 
461
        return res;
462
}
463
 
464
#endif /* !_FS_READONLY */
465
 
466
/*-----------------------------------------------------------------------*/
467
 
468
/* FAT handling - Remove a cluster chain                                 */
469
 
470
/*-----------------------------------------------------------------------*/
471
#if !_FS_READONLY
472
static FRESULT remove_chain ( FATFS * fs, /* File system object */ DWORD clst /* Cluster# to remove a chain from */ )
473
{
474
        FRESULT res;
475
        DWORD nxt;
476
 
477
        if( clst < 2 || clst >= fs->max_clust )
478
        {                                       /* Check the range of cluster# */
479
                res = FR_INT_ERR;
480
        }
481
        else
482
        {
483
                res = FR_OK;
484
                while( clst < fs->max_clust )
485
                {                               /* Not a last link? */
486
                        nxt = get_fat( fs, clst );      /* Get cluster status */
487
                        if( nxt == 0 )
488
                        {
489
                                break;                                  /* Empty cluster? */
490
                        }
491
 
492
                        if( nxt == 1 )
493
                        {
494
                                res = FR_INT_ERR;
495
                                break;
496
                        }       /* Internal error? */
497
                        if( nxt == 0xFFFFFFFF )
498
                        {
499
                                res = FR_DISK_ERR;
500
                                break;
501
                        }       /* Disk error? */
502
                        res = put_fat( fs, clst, 0 );    /* Mark the cluster "empty" */
503
                        if( res != FR_OK )
504
                        {
505
                                break;
506
                        }
507
 
508
                        if( fs->free_clust != 0xFFFFFFFF )
509
                        {                       /* Update FSInfo */
510
                                fs->free_clust++;
511
                                fs->fsi_flag = 1;
512
                        }
513
 
514
                        clst = nxt; /* Next cluster */
515
                }
516
        }
517
 
518
        return res;
519
}
520
 
521
#endif
522
 
523
/*-----------------------------------------------------------------------*/
524
 
525
/* FAT handling - Stretch or Create a cluster chain                      */
526
 
527
/*-----------------------------------------------------------------------*/
528
#if !_FS_READONLY
529
static DWORD create_chain
530
        (                                       /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
531
                FATFS * fs, /* File system object */ DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
532
        )
533
{
534
        DWORD cs, ncl, scl, mcl;
535
 
536
        mcl = fs->max_clust;
537
        if( clst == 0 )
538
        {       /* Create new chain */
539
                scl = fs->last_clust;   /* Get suggested start point */
540
                if( scl == 0 || scl >= mcl )
541
                {
542
                        scl = 1;
543
                }
544
        }
545
        else
546
        {       /* Stretch existing chain */
547
                cs = get_fat( fs, clst );       /* Check the cluster status */
548
                if( cs < 2 )
549
                {
550
                        return 1;                               /* It is an invalid cluster */
551
                }
552
 
553
                if( cs < mcl )
554
                {
555
                        return cs;                              /* It is already followed by next cluster */
556
                }
557
 
558
                scl = clst;
559
        }
560
 
561
        ncl = scl;                                              /* Start cluster */
562
        for( ;; )
563
        {
564
                ncl++;                                          /* Next cluster */
565
                if( ncl >= mcl )
566
                {                                       /* Wrap around */
567
                        ncl = 2;
568
                        if( ncl > scl )
569
                        {
570
                                return 0;        /* No free custer */
571
                        }
572
                }
573
 
574
                cs = get_fat( fs, ncl );        /* Get the cluster status */
575
                if( cs == 0 )
576
                {
577
                        break;                                  /* Found a free cluster */
578
                }
579
 
580
                if( cs == 0xFFFFFFFF || cs == 1 )
581
                {                                       /* An error occured */
582
                        return cs;
583
                }
584
 
585
                if( ncl == scl )
586
                {
587
                        return 0;                /* No free custer */
588
                }
589
        }
590
 
591
        if( put_fat(fs, ncl, 0x0FFFFFFF) )
592
        {                                               /* Mark the new cluster "in use" */
593
                return 0xFFFFFFFF;
594
        }
595
 
596
        if( clst != 0 )
597
        {                                               /* Link it to the previous one if needed */
598
                if( put_fat(fs, clst, ncl) )
599
                {
600
                        return 0xFFFFFFFF;
601
                }
602
        }
603
 
604
        fs->last_clust = ncl;   /* Update FSINFO */
605
        if( fs->free_clust != 0xFFFFFFFF )
606
        {
607
                fs->free_clust--;
608
                fs->fsi_flag = 1;
609
        }
610
 
611
        return ncl;                             /* Return new cluster number */
612
}
613
 
614
#endif /* !_FS_READONLY */
615
 
616
/*-----------------------------------------------------------------------*/
617
 
618
/* Get sector# from cluster#                                             */
619
 
620
/*-----------------------------------------------------------------------*/
621
DWORD clust2sect
622
        ( /* !=0: Sector number, 0: Failed - invalid cluster# */ FATFS * fs, /* File system object */ DWORD clst /* Cluster# to be converted */ )
623
{
624
        clst -= 2;
625
        if( clst >= (fs->max_clust - 2) )
626
        {
627
                return 0;                        /* Invalid cluster# */
628
        }
629
 
630
        return clst * fs->csize + fs->database;
631
}
632
 
633
/*-----------------------------------------------------------------------*/
634
 
635
/* Directory handling - Seek directory index                             */
636
 
637
/*-----------------------------------------------------------------------*/
638
static FRESULT dir_seek ( DIR * dj, /* Pointer to directory object */ WORD idx /* Directory index number */ )
639
{
640
        DWORD clst;
641
        WORD ic;
642
 
643
        dj->index = idx;
644
        clst = dj->sclust;
645
        if( clst == 1 || clst >= dj->fs->max_clust )
646
        {                                               /* Check start cluster range */
647
                return FR_INT_ERR;
648
        }
649
 
650
        if( !clst && dj->fs->fs_type == FS_FAT32 )
651
        {                                               /* Replace cluster# 0 with root cluster# if in FAT32 */
652
                clst = dj->fs->dirbase;
653
        }
654
 
655
        if( clst == 0 )
656
        {                                               /* Static table */
657
                dj->clust = clst;
658
                if( idx >= dj->fs->n_rootdir )
659
                {                                       /* Index is out of range */
660
                        return FR_INT_ERR;
661
                }
662
 
663
                dj->sect = dj->fs->dirbase + idx / ( SS(dj->fs) / 32 ); /* Sector# */
664
        }
665
        else
666
        {       /* Dynamic table */
667
                ic =
668
                SS( dj->fs )
669
                / 32 * dj->fs->csize;                           /* Entries per cluster */
670
                while( idx >= ic )
671
                {                                                                       /* Follow cluster chain */
672
                        clst = get_fat( dj->fs, clst ); /* Get next cluster */
673
                        if( clst == 0xFFFFFFFF )
674
                        {
675
                                return FR_DISK_ERR;                     /* Disk error */
676
                        }
677
 
678
                        if( clst < 2 || clst >= dj->fs->max_clust )
679
                        {       /* Reached to end of table or int error */
680
                                return FR_INT_ERR;
681
                        }
682
 
683
                        idx -= ic;
684
                }
685
 
686
                dj->clust = clst;
687
                dj->sect =
688
                clust2sect( dj->fs, clst )
689
                + idx / ( SS(dj->fs) / 32 );    /* Sector# */
690
        }
691
 
692
        dj->dir = dj->fs->win + ( idx % (SS(dj->fs) / 32) ) * 32;       /* Ptr to the entry in the sector */
693
 
694
        return FR_OK;   /* Seek succeeded */
695
}
696
 
697
/*-----------------------------------------------------------------------*/
698
 
699
/* Directory handling - Move directory index next                        */
700
 
701
/*-----------------------------------------------------------------------*/
702
static FRESULT dir_next
703
        (                               /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
704
                DIR *
705
                dj, /* Pointer to directory object */ BOOL streach      /* FALSE: Do not streach table, TRUE: Streach table if needed */
706
        )
707
{
708
        DWORD clst;
709
        WORD i;
710
 
711
        i = dj->index + 1;
712
        if( !i || !dj->sect )
713
        {                               /* Report EOT when index has reached 65535 */
714
                return FR_NO_FILE;
715
        }
716
 
717
        if( !(i % (SS(dj->fs) / 32)) )
718
        {                               /* Sector changed? */
719
                dj->sect++; /* Next sector */
720
 
721
                if( dj->clust == 0 )
722
                {                       /* Static table */
723
                        if( i >= dj->fs->n_rootdir )
724
                        {               /* Report EOT when end of table */
725
                                return FR_NO_FILE;
726
                        }
727
                }
728
                else
729
                {                       /* Dynamic table */
730
                        if( ((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0 )
731
                        {               /* Cluster changed? */
732
                                clst = get_fat( dj->fs, dj->clust );    /* Get next cluster */
733
                                if( clst <= 1 )
734
                                {
735
                                        return FR_INT_ERR;
736
                                }
737
 
738
                                if( clst == 0xFFFFFFFF )
739
                                {
740
                                        return FR_DISK_ERR;
741
                                }
742
 
743
                                if( clst >= dj->fs->max_clust )
744
                                {       /* When it reached end of dynamic table */
745
                                        #if !_FS_READONLY
746
                                        BYTE c;
747
                                        if( !streach )
748
                                        {
749
                                                return FR_NO_FILE;                                              /* When do not streach, report EOT */
750
                                        }
751
 
752
                                        clst = create_chain( dj->fs, dj->clust );       /* Streach cluster chain */
753
                                        if( clst == 0 )
754
                                        {
755
                                                return FR_DENIED;                                               /* No free cluster */
756
                                        }
757
 
758
                                        if( clst == 1 )
759
                                        {
760
                                                return FR_INT_ERR;
761
                                        }
762
 
763
                                        if( clst == 0xFFFFFFFF )
764
                                        {
765
                                                return FR_DISK_ERR;
766
                                        }
767
 
768
                                        /* Clean-up streached table */
769
                                        if( move_window(dj->fs, 0) )
770
                                        {
771
                                                return FR_DISK_ERR;                                             /* Flush active window */
772
                                        }
773
 
774
                                        mem_set( dj->fs->win, 0, SS(dj->fs) );           /* Clear window buffer */
775
                                        dj->fs->winsect = clust2sect( dj->fs, clst );   /* Cluster start sector */
776
                                        for( c = 0; c < dj->fs->csize; c++ )
777
                                        {                                               /* Fill the new cluster with 0 */
778
                                                dj->fs->wflag = 1;
779
                                                if( move_window(dj->fs, 0) )
780
                                                {
781
                                                        return FR_DISK_ERR;
782
                                                }
783
 
784
                                                dj->fs->winsect++;
785
                                        }
786
 
787
                                        dj->fs->winsect -= c;   /* Rewind window address */
788
                                        #else
789
                                        return FR_NO_FILE;              /* Report EOT */
790
                                        #endif
791
                                }
792
 
793
                                dj->clust = clst;                       /* Initialize data for new cluster */
794
                                dj->sect = clust2sect( dj->fs, clst );
795
                        }
796
                }
797
        }
798
 
799
        dj->index = i;
800
        dj->dir = dj->fs->win + ( i % (SS(dj->fs) / 32) ) * 32;
801
 
802
        return FR_OK;
803
}
804
 
805
/*-----------------------------------------------------------------------*/
806
 
807
/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry   */
808
 
809
/*-----------------------------------------------------------------------*/
810
#if _USE_LFN
811
static const BYTE LfnOfs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
812
 
813
/* Offset of LFN chars in the directory entry */
814
 
815
static BOOL cmp_lfn
816
        (                                       /* TRUE:Matched, FALSE:Not matched */
817
                WCHAR *lfnbuf,  /* Pointer to the LFN to be compared */
818
                BYTE *dir               /* Pointer to the directory entry containing a part of LFN */
819
        )
820
{
821
        int             i, s;
822
        WCHAR   wc, uc;
823
 
824
        i = ( (dir[LDIR_Ord] & 0xBF) - 1 ) * 13;        /* Get offset in the LFN buffer */
825
        s = 0;
826
        wc = 1;
827
        do
828
        {
829
                uc = LD_WORD( dir + LfnOfs[s] );                /* Pick an LFN character from the entry */
830
                if( wc )
831
                {       /* Last char has not been processed */
832
                        wc = ff_wtoupper( uc ); /* Convert it to upper case */
833
                        if( i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++]) )
834
                        {                                               /* Compare it */
835
                                return FALSE;           /* Not matched */
836
                        }
837
                }
838
                else
839
                {
840
                        if( uc != 0xFFFF )
841
                        {
842
                                return FALSE;           /* Check filler */
843
                        }
844
                }
845
        } while( ++s < 13 );
846
 
847
        /* Repeat until all chars in the entry are checked */
848
 
849
        if( (dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i] )
850
        {                               /* Last segment matched but different length */
851
                return FALSE;
852
        }
853
 
854
        return TRUE;    /* The part of LFN matched */
855
}
856
 
857
static BOOL pick_lfn
858
        (                                       /* TRUE:Succeeded, FALSE:Buffer overflow */
859
                WCHAR *lfnbuf,  /* Pointer to the Unicode-LFN buffer */
860
                BYTE *dir               /* Pointer to the directory entry */
861
        )
862
{
863
        int             i, s;
864
        WCHAR   wc, uc;
865
 
866
        i = ( (dir[LDIR_Ord] & 0x3F) - 1 ) * 13;        /* Offset in the LFN buffer */
867
 
868
        s = 0;
869
        wc = 1;
870
        do
871
        {
872
                uc = LD_WORD( dir + LfnOfs[s] );                /* Pick an LFN character from the entry */
873
                if( wc )
874
                {                                               /* Last char has not been processed */
875
                        if( i >= _MAX_LFN )
876
                        {
877
                                return FALSE;   /* Buffer overflow? */
878
                        }
879
 
880
                        lfnbuf[i++] = wc = uc;  /* Store it */
881
                }
882
                else
883
                {
884
                        if( uc != 0xFFFF )
885
                        {
886
                                return FALSE;           /* Check filler */
887
                        }
888
                }
889
        } while( ++s < 13 );
890
 
891
        /* Read all character in the entry */
892
 
893
        if( dir[LDIR_Ord] & 0x40 )
894
        {                                               /* Put terminator if it is the last LFN part */
895
                if( i >= _MAX_LFN )
896
                {
897
                        return FALSE;   /* Buffer overflow? */
898
                }
899
 
900
                lfnbuf[i] = 0;
901
        }
902
 
903
        return TRUE;
904
}
905
 
906
        #if !_FS_READONLY
907
static void fit_lfn
908
                        (
909
                                const WCHAR *lfnbuf,    /* Pointer to the LFN buffer */
910
                                BYTE            *dir,           /* Pointer to the directory entry */
911
                                BYTE            ord,            /* LFN order (1-20) */
912
                                BYTE            sum                     /* SFN sum */
913
                        )
914
{
915
        int             i, s;
916
        WCHAR   wc;
917
 
918
        dir[LDIR_Chksum] = sum;                         /* Set check sum */
919
        dir[LDIR_Attr] = AM_LFN;                        /* Set attribute. LFN entry */
920
        dir[LDIR_Type] = 0;
921
        ST_WORD( dir + LDIR_FstClusLO, 0 );
922
 
923
        i = ( ord - 1 ) * 13;                           /* Get offset in the LFN buffer */
924
        s = wc = 0;
925
        do
926
        {
927
                if( wc != 0xFFFF )
928
                {
929
                        wc = lfnbuf[i++];                       /* Get an effective char */
930
                }
931
 
932
                ST_WORD( dir + LfnOfs[s], wc ); /* Put it */
933
                if( !wc )
934
                {
935
                        wc = 0xFFFF;                            /* Padding chars following last char */
936
                }
937
        } while( ++s < 13 );
938
        if( wc == 0xFFFF || !lfnbuf[i] )
939
        {
940
                ord |= 0x40;                                    /* Bottom LFN part is the start of LFN sequence */
941
        }
942
 
943
        dir[LDIR_Ord] = ord;                            /* Set the LFN order */
944
}
945
 
946
        #endif
947
#endif
948
 
949
/*-----------------------------------------------------------------------*/
950
 
951
/* Create numbered name                                                  */
952
 
953
/*-----------------------------------------------------------------------*/
954
#if _USE_LFN
955
void gen_numname
956
        (
957
                BYTE            *dst,   /* Pointer to genartated SFN */
958
                const BYTE      *src,   /* Pointer to source SFN to be modified */
959
                const WCHAR *lfn,       /* Pointer to LFN */
960
                WORD            num             /* Sequense number */
961
        )
962
{
963
        char    ns[8];
964
        int             i, j;
965
 
966
        mem_cpy( dst, src, 11 );
967
 
968
        if( num > 5 )
969
        {       /* On many collisions, generate a hash number instead of sequencial number */
970
                do
971
                {
972
                        num = ( num >> 1 ) + ( num << 15 ) + ( WORD ) * lfn++;
973
                } while( *lfn );
974
        }
975
 
976
        /* itoa */
977
        i = 7;
978
        do
979
        {
980
                ns[i--] = ( num % 10 ) + '0';
981
                num /= 10;
982
        } while( num );
983
        ns[i] = '~';
984
 
985
        /* Append the number */
986
        for( j = 0; j < i && dst[j] != ' '; j++ )
987
        {
988
                if( IsDBCS1(dst[j]) )
989
                {
990
                        if( j == i - 1 )
991
                        {
992
                                break;
993
                        }
994
 
995
                        j++;
996
                }
997
        }
998
 
999
        do
1000
        {
1001
                dst[j++] = ( i < 8 ) ? ns[i++] : ' ';
1002
        } while( j < 8 );
1003
}
1004
 
1005
#endif
1006
 
1007
/*-----------------------------------------------------------------------*/
1008
 
1009
/* Calculate sum of an SFN                                               */
1010
 
1011
/*-----------------------------------------------------------------------*/
1012
#if _USE_LFN
1013
static BYTE sum_sfn( const BYTE *dir /* Ptr to directory entry */ )
1014
{
1015
        BYTE    sum = 0;
1016
        int             n = 11;
1017
 
1018
        do
1019
        {
1020
                sum = ( sum >> 1 ) + ( sum << 7 ) +*dir++;
1021
        } while( --n );
1022
        return sum;
1023
}
1024
 
1025
#endif
1026
 
1027
/*-----------------------------------------------------------------------*/
1028
 
1029
/* Directory handling - Find an object in the directory                  */
1030
 
1031
/*-----------------------------------------------------------------------*/
1032
static FRESULT dir_find( DIR *dj /* Pointer to the directory object linked to the file name */ )
1033
{
1034
        FRESULT res;
1035
        BYTE    c, *dir;
1036
        #if _USE_LFN
1037
        BYTE    a, ord, sum;
1038
        #endif
1039
        res = dir_seek( dj, 0 );                 /* Rewind directory object */
1040
        if( res != FR_OK )
1041
        {
1042
                return res;
1043
        }
1044
 
1045
        #if _USE_LFN
1046
        ord = sum = 0xFF;
1047
        #endif
1048
        do
1049
        {
1050
                res = move_window( dj->fs, dj->sect );
1051
                if( res != FR_OK )
1052
                {
1053
                        break;
1054
                }
1055
 
1056
                dir = dj->dir;                                  /* Ptr to the directory entry of current index */
1057
                c = dir[DIR_Name];
1058
                if( c == 0 )
1059
                {
1060
                        res = FR_NO_FILE;
1061
                        break;
1062
                }                                                               /* Reached to end of table */
1063
 
1064
                #if _USE_LFN                                    /* LFN configuration */
1065
                a = dir[DIR_Attr] & AM_MASK;
1066
                if( c == 0xE5 || ((a & AM_VOL) && a != AM_LFN) )
1067
                {                                                               /* An entry without valid data */
1068
                        ord = 0xFF;
1069
                }
1070
                else
1071
                {
1072
                        if( a == AM_LFN )
1073
                        {                                                       /* An LFN entry is found */
1074
                                if( dj->lfn )
1075
                                {
1076
                                        if( c & 0x40 )
1077
                                        {                                       /* Is it start of LFN sequence? */
1078
                                                sum = dir[LDIR_Chksum];
1079
                                                c &= 0xBF;
1080
                                                ord = c;                /* LFN start order */
1081
                                                dj->lfn_idx = dj->index;
1082
                                        }
1083
 
1084
                                        /* Check validity of the LFN entry and compare it with given name */
1085
                                        ord = ( c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir) ) ? ord - 1 : 0xFF;
1086
                                }
1087
                        }
1088
                        else
1089
                        {                                                       /* An SFN entry is found */
1090
                                if( !ord && sum == sum_sfn(dir) )
1091
                                {
1092
                                        break;                          /* LFN matched? */
1093
                                }
1094
 
1095
                                ord = 0xFF;
1096
                                dj->lfn_idx = 0xFFFF;   /* Reset LFN sequence */
1097
                                if( !(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11) )
1098
                                {
1099
                                        break;                          /* SFN matched? */
1100
                                }
1101
                        }
1102
                }
1103
 
1104
                #else /* Non LFN configuration */
1105
                if( !(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11) )
1106
                {       /* Is it a valid entry? */
1107
                        break;
1108
                }
1109
 
1110
                #endif
1111
                res = dir_next( dj, FALSE );    /* Next entry */
1112
        } while( res == FR_OK );
1113
 
1114
        return res;
1115
}
1116
 
1117
/*-----------------------------------------------------------------------*/
1118
 
1119
/* Read an object from the directory                                     */
1120
 
1121
/*-----------------------------------------------------------------------*/
1122
#if _FS_MINIMIZE <= 1
1123
static FRESULT dir_read( DIR *dj /* Pointer to the directory object that pointing the entry to be read */ )
1124
{
1125
        FRESULT res;
1126
        BYTE    c, *dir;
1127
                #if _USE_LFN
1128
        BYTE    a, ord = 0xFF, sum = 0xFF;
1129
                #endif
1130
        res = FR_NO_FILE;
1131
        while( dj->sect )
1132
        {
1133
                res = move_window( dj->fs, dj->sect );
1134
                if( res != FR_OK )
1135
                {
1136
                        break;
1137
                }
1138
 
1139
                dir = dj->dir;                                  /* Ptr to the directory entry of current index */
1140
                c = dir[DIR_Name];
1141
                if( c == 0 )
1142
                {
1143
                        res = FR_NO_FILE;
1144
                        break;
1145
                }                                       /* Reached to end of table */
1146
 
1147
                        #if _USE_LFN    /* LFN configuration */
1148
                a = dir[DIR_Attr] & AM_MASK;
1149
                if( c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN) )
1150
                {                                       /* An entry without valid data */
1151
                        ord = 0xFF;
1152
                }
1153
                else
1154
                {
1155
                        if( a == AM_LFN )
1156
                        {                               /* An LFN entry is found */
1157
                                if( c & 0x40 )
1158
                                {                       /* Is it start of LFN sequence? */
1159
                                        sum = dir[LDIR_Chksum];
1160
                                        c &= 0xBF;
1161
                                        ord = c;
1162
                                        dj->lfn_idx = dj->index;
1163
                                }
1164
 
1165
                                /* Check LFN validity and capture it */
1166
                                ord = ( c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir) ) ? ord - 1 : 0xFF;
1167
                        }
1168
                        else
1169
                        {                               /* An SFN entry is found */
1170
                                if( ord || sum != sum_sfn(dir) )
1171
                                {                       /* Is there a valid LFN? */
1172
                                        dj->lfn_idx = 0xFFFF;   /* It has no LFN. */
1173
                                }
1174
 
1175
                                break;
1176
                        }
1177
                }
1178
 
1179
                        #else /* Non LFN configuration */
1180
                if( c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL) )
1181
                {       /* Is it a valid entry? */
1182
                        break;
1183
                }
1184
 
1185
                        #endif
1186
                res = dir_next( dj, FALSE );    /* Next entry */
1187
                if( res != FR_OK )
1188
                {
1189
                        break;
1190
                }
1191
        }
1192
 
1193
        if( res != FR_OK )
1194
        {
1195
                dj->sect = 0;
1196
        }
1197
 
1198
        return res;
1199
}
1200
 
1201
#endif
1202
 
1203
/*-----------------------------------------------------------------------*/
1204
 
1205
/* Register an object to the directory                                   */
1206
 
1207
/*-----------------------------------------------------------------------*/
1208
#if !_FS_READONLY
1209
static FRESULT dir_register
1210
        (                       /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
1211
                DIR *dj /* Target directory with object name to be created */
1212
        )
1213
{
1214
        FRESULT res;
1215
        BYTE    c, *dir;
1216
                #if _USE_LFN                    /* LFN configuration */
1217
        WORD    n, ne, is;
1218
        BYTE    sn[12], *fn, sum;
1219
        WCHAR   *lfn;
1220
 
1221
        fn = dj->fn;
1222
        lfn = dj->lfn;
1223
        mem_cpy( sn, fn, 12 );
1224
 
1225
        if( _FS_RPATH && (sn[NS] & NS_DOT) )
1226
        {
1227
                return FR_INVALID_NAME; /* Cannot create dot entry */
1228
        }
1229
 
1230
        if( sn[NS] & NS_LOSS )
1231
        {                                       /* When LFN is out of 8.3 format, generate a numbered name */
1232
                fn[NS] = 0;
1233
                dj->lfn = NULL; /* Find only SFN */
1234
                for( n = 1; n < 100; n++ )
1235
                {
1236
                        gen_numname( fn, sn, lfn, n );  /* Generate a numbered name */
1237
                        res = dir_find( dj );                   /* Check if the name collides with existing SFN */
1238
                        if( res != FR_OK )
1239
                        {
1240
                                break;
1241
                        }
1242
                }
1243
 
1244
                if( n == 100 )
1245
                {
1246
                        return FR_DENIED;                               /* Abort if too many collisions */
1247
                }
1248
 
1249
                if( res != FR_NO_FILE )
1250
                {
1251
                        return res;                                             /* Abort if the result is other than 'not collided' */
1252
                }
1253
 
1254
                fn[NS] = sn[NS];
1255
                dj->lfn = lfn;
1256
        }
1257
 
1258
        if( sn[NS] & NS_LFN )
1259
        {                                       /* When LFN is to be created, reserve reserve an SFN + LFN entries. */
1260
                for( ne = 0; lfn[ne]; ne++ );
1261
                ne = ( ne + 25 ) / 13;
1262
        }
1263
        else
1264
        {                                       /* Otherwise reserve only an SFN entry. */
1265
                ne = 1;
1266
        }
1267
 
1268
        /* Reserve contiguous entries */
1269
        res = dir_seek( dj, 0 );
1270
        if( res != FR_OK )
1271
        {
1272
                return res;
1273
        }
1274
 
1275
        n = is = 0;
1276
        do
1277
        {
1278
                res = move_window( dj->fs, dj->sect );
1279
                if( res != FR_OK )
1280
                {
1281
                        break;
1282
                }
1283
 
1284
                c = *dj->dir;   /* Check the entry status */
1285
                if( c == 0xE5 || c == 0 )
1286
                {                               /* Is it a blank entry? */
1287
                        if( n == 0 )
1288
                        {
1289
                                is = dj->index;         /* First index of the contigulus entry */
1290
                        }
1291
 
1292
                        if( ++n == ne )
1293
                        {
1294
                                break;                          /* A contiguous entry that requiered count is found */
1295
                        }
1296
                }
1297
                else
1298
                {
1299
                        n = 0;                                   /* Not a blank entry. Restart to search */
1300
                }
1301
 
1302
                res = dir_next( dj, TRUE ); /* Next entry with table streach */
1303
        } while( res == FR_OK );
1304
 
1305
        if( res == FR_OK && ne > 1 )
1306
        {       /* Initialize LFN entry if needed */
1307
                res = dir_seek( dj, is );
1308
                if( res == FR_OK )
1309
                {
1310
                        sum = sum_sfn( dj->fn );        /* Sum of the SFN tied to the LFN */
1311
                        ne--;
1312
                        do
1313
                        {       /* Store LFN entries in bottom first */
1314
                                res = move_window( dj->fs, dj->sect );
1315
                                if( res != FR_OK )
1316
                                {
1317
                                        break;
1318
                                }
1319
 
1320
                                fit_lfn( dj->lfn, dj->dir, (BYTE) ne, sum );
1321
                                dj->fs->wflag = 1;
1322
                                res = dir_next( dj, FALSE );    /* Next entry */
1323
                        } while( res == FR_OK && --ne );
1324
                }
1325
        }
1326
 
1327
                #else /* Non LFN configuration */
1328
        res = dir_seek( dj, 0 );
1329
        if( res == FR_OK )
1330
        {
1331
                do
1332
                {                               /* Find a blank entry for the SFN */
1333
                        res = move_window( dj->fs, dj->sect );
1334
                        if( res != FR_OK )
1335
                        {
1336
                                break;
1337
                        }
1338
 
1339
                        c = *dj->dir;
1340
                        if( c == 0xE5 || c == 0 )
1341
                        {
1342
                                break;  /* Is it a blank entry? */
1343
                        }
1344
 
1345
                        res = dir_next( dj, TRUE ); /* Next entry with table streach */
1346
                } while( res == FR_OK );
1347
        }
1348
 
1349
                #endif
1350
        if( res == FR_OK )
1351
        {       /* Initialize the SFN entry */
1352
                res = move_window( dj->fs, dj->sect );
1353
                if( res == FR_OK )
1354
                {
1355
                        dir = dj->dir;
1356
                        mem_set( dir, 0, 32 );           /* Clean the entry */
1357
                        mem_cpy( dir, dj->fn, 11 ); /* Put SFN */
1358
                        dir[DIR_NTres] = *( dj->fn + NS ) & ( NS_BODY | NS_EXT );       /* Put NT flag */
1359
                        dj->fs->wflag = 1;
1360
                }
1361
        }
1362
 
1363
        return res;
1364
}
1365
 
1366
#endif /* !_FS_READONLY */
1367
 
1368
/*-----------------------------------------------------------------------*/
1369
 
1370
/* Remove an object from the directory                                   */
1371
 
1372
/*-----------------------------------------------------------------------*/
1373
#if !_FS_READONLY && !_FS_MINIMIZE
1374
static FRESULT dir_remove
1375
        (                       /* FR_OK: Successful, FR_DISK_ERR: A disk error */
1376
                DIR *dj /* Directory object pointing the entry to be removed */
1377
        )
1378
{
1379
        FRESULT res;
1380
                #if _USE_LFN    /* LFN configuration */
1381
        WORD    i;
1382
 
1383
        i = dj->index;          /* SFN index */
1384
        res = dir_seek( dj, (WORD) ((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx) );       /* Goto the SFN or top of the LFN entries */
1385
        if( res == FR_OK )
1386
        {
1387
                do
1388
                {
1389
                        res = move_window( dj->fs, dj->sect );
1390
                        if( res != FR_OK )
1391
                        {
1392
                                break;
1393
                        }
1394
 
1395
                        *dj->dir = 0xE5;                                /* Mark the entry "deleted" */
1396
                        dj->fs->wflag = 1;
1397
                        if( dj->index >= i )
1398
                        {
1399
                                break;                                          /* When reached SFN, all entries of the object has been deleted. */
1400
                        }
1401
 
1402
                        res = dir_next( dj, FALSE );    /* Next entry */
1403
                } while( res == FR_OK );
1404
                if( res == FR_NO_FILE )
1405
                {
1406
                        res = FR_INT_ERR;
1407
                }
1408
        }
1409
 
1410
                #else /* Non LFN configuration */
1411
        res = dir_seek( dj, dj->index );
1412
        if( res == FR_OK )
1413
        {
1414
                res = move_window( dj->fs, dj->sect );
1415
                if( res == FR_OK )
1416
                {
1417
                        *dj->dir = 0xE5;                                /* Mark the entry "deleted" */
1418
                        dj->fs->wflag = 1;
1419
                }
1420
        }
1421
 
1422
                #endif
1423
        return res;
1424
}
1425
 
1426
#endif /* !_FS_READONLY */
1427
 
1428
/*-----------------------------------------------------------------------*/
1429
 
1430
/* Pick a segment and create the object name in directory form           */
1431
 
1432
/*-----------------------------------------------------------------------*/
1433
static FRESULT create_name
1434
                        (
1435
                                DIR                     *dj,    /* Pointer to the directory object */
1436
                                const XCHAR **path      /* Pointer to pointer to the segment in the path string */
1437
                        )
1438
{
1439
        #ifdef _EXCVT
1440
 
1441
        static const BYTE       cvt[] = _EXCVT;
1442
        #endif
1443
        #if _USE_LFN                                    /* LFN configuration */
1444
        BYTE                            b, cf;
1445
        WCHAR                           w, *lfn;
1446
        int                                     i, ni, si, di;
1447
        const XCHAR                     *p;
1448
 
1449
        /* Create LFN in Unicode */
1450
        si = di = 0;
1451
        p = *path;
1452
        lfn = dj->lfn;
1453
        for( ;; )
1454
        {
1455
                w = p[si++];                            /* Get a character */
1456
                if( w < ' ' || w == '/' || w == '\\' )
1457
                {
1458
                        break;                                  /* Break on end of segment */
1459
                }
1460
 
1461
                if( di >= _MAX_LFN )
1462
                {                                                       /* Reject too long name */
1463
                        return FR_INVALID_NAME;
1464
                }
1465
 
1466
                        #if !_LFN_UNICODE
1467
                w &= 0xFF;
1468
                if( IsDBCS1(w) )
1469
                {                                                       /* If it is a DBC 1st byte */
1470
                        b = p[si++];                    /* Get 2nd byte */
1471
                        if( !IsDBCS2(b) )
1472
                        {                                               /* Reject invalid code for DBC */
1473
                                return FR_INVALID_NAME;
1474
                        }
1475
 
1476
                        w = ( w << 8 ) + b;
1477
                }
1478
 
1479
                w = ff_convert( w, 1 );         /* Convert OEM to Unicode */
1480
                if( !w )
1481
                {
1482
                        return FR_INVALID_NAME; /* Reject invalid code */
1483
                }
1484
 
1485
                        #endif
1486
                if( w < 0x80 && chk_chr("\"*:<>\?|\x7F", w) )
1487
                {                               /* Reject illegal chars for LFN */
1488
                        return FR_INVALID_NAME;
1489
                }
1490
 
1491
                lfn[di++] = w;  /* Store the Unicode char */
1492
        }
1493
 
1494
        *path = &p[si];         /* Rerurn pointer to the next segment */
1495
        cf = ( w < ' ' ) ? NS_LAST : 0; /* Set last segment flag if end of path */
1496
                #if _FS_RPATH
1497
        if( (di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.') )
1498
        {
1499
                lfn[di] = 0;
1500
                for( i = 0; i < 11; i++ )
1501
                {
1502
                        dj->fn[i] = ( i < di ) ? '.' : ' ';
1503
                }
1504
 
1505
                dj->fn[i] = cf | NS_DOT;        /* This is a dot entry */
1506
                return FR_OK;
1507
        }
1508
 
1509
                #endif
1510
        while( di )
1511
        {       /* Strip trailing spaces and dots */
1512
                w = lfn[di - 1];
1513
                if( w != ' ' && w != '.' )
1514
                {
1515
                        break;
1516
                }
1517
 
1518
                di--;
1519
        }
1520
 
1521
        if( !di )
1522
        {
1523
                return FR_INVALID_NAME;                 /* Reject null string */
1524
        }
1525
 
1526
        lfn[di] = 0;                                             /* LFN is created */
1527
 
1528
        /* Create SFN in directory form */
1529
        mem_set( dj->fn, ' ', 11 );
1530
        for( si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++ );
1531
 
1532
        /* Strip leading spaces and dots */
1533
        if( si )
1534
        {
1535
                cf |= NS_LOSS | NS_LFN;
1536
        }
1537
 
1538
        while( di && lfn[di - 1] != '.' )
1539
        {
1540
                di--;                                                   /* Find extension (di<=si: no extension) */
1541
        }
1542
 
1543
        b = i = 0;
1544
        ni = 8;
1545
        for( ;; )
1546
        {
1547
                w = lfn[si++];                                  /* Get an LFN char */
1548
                if( !w )
1549
                {
1550
                        break;                                          /* Break on enf of the LFN */
1551
                }
1552
 
1553
                if( w == ' ' || (w == '.' && si != di) )
1554
                {                                                               /* Remove spaces and dots */
1555
                        cf |= NS_LOSS | NS_LFN;
1556
                        continue;
1557
                }
1558
 
1559
                if( i >= ni || si == di )
1560
                {                                                               /* Extension or end of SFN */
1561
                        if( ni == 11 )
1562
                        {                                                       /* Long extension */
1563
                                cf |= NS_LOSS | NS_LFN;
1564
                                break;
1565
                        }
1566
 
1567
                        if( si != di )
1568
                        {
1569
                                cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
1570
                        }
1571
 
1572
                        if( si > di )
1573
                        {
1574
                                break;                                  /* No extension */
1575
                        }
1576
 
1577
                        si = di;
1578
                        i = 8;
1579
                        ni = 11;                                        /* Enter extension section */
1580
                        b <<= 2;
1581
                        continue;
1582
                }
1583
 
1584
                if( w >= 0x80 )
1585
                {       /* Non ASCII char */
1586
                                #ifdef _EXCVT
1587
                        w = ff_convert( w, 0 );                                  /* Unicode -> OEM code */
1588
                        if( w )
1589
                        {
1590
                                w = cvt[w - 0x80];                                      /* Convert extended char to upper (SBCS) */
1591
                        }
1592
 
1593
                                #else
1594
                        w = ff_convert( ff_wtoupper(w), 0 );     /* Upper converted Unicode -> OEM code */
1595
                                #endif
1596
                        cf |= NS_LFN;                           /* Force create LFN entry */
1597
                }
1598
 
1599
                if( _DF1S && w >= 0x100 )
1600
                {                                                               /* Double byte char */
1601
                        if( i >= ni - 1 )
1602
                        {
1603
                                cf |= NS_LOSS | NS_LFN;
1604
                                i = ni;
1605
                                continue;
1606
                        }
1607
 
1608
                        dj->fn[i++] = ( BYTE ) ( w >> 8 );
1609
                }
1610
                else
1611
                {                                                               /* Single byte char */
1612
                        if( !w || chk_chr("+,;[=]", w) )
1613
                        {                                                       /* Replace illegal chars for SFN */
1614
                                w = '_';
1615
                                cf |= NS_LOSS | NS_LFN; /* Lossy conversion */
1616
                        }
1617
                        else
1618
                        {
1619
                                if( IsUpper(w) )
1620
                                {                                               /* ASCII large capital */
1621
                                        b |= 2;
1622
                                }
1623
                                else
1624
                                {
1625
                                        if( IsLower(w) )
1626
                                        {                                       /* ASCII small capital */
1627
                                                b |= 1;
1628
                                                w -= 0x20;
1629
                                        }
1630
                                }
1631
                        }
1632
                }
1633
 
1634
                dj->fn[i++] = ( BYTE ) w;
1635
        }
1636
 
1637
        if( dj->fn[0] == 0xE5 )
1638
        {
1639
                dj->fn[0] = 0x05;                                /* If the first char collides with deleted mark, replace it with 0x05 */
1640
        }
1641
 
1642
        if( ni == 8 )
1643
        {
1644
                b <<= 2;
1645
        }
1646
 
1647
        if( (b & 0x0C) == 0x0C || (b & 0x03) == 0x03 )
1648
        {                                               /* Create LFN entry when there are composite capitals */
1649
                cf |= NS_LFN;
1650
        }
1651
 
1652
        if( !(cf & NS_LFN) )
1653
        {                                               /* When LFN is in 8.3 format without extended char, NT flags are created */
1654
                if( (b & 0x03) == 0x01 )
1655
                {
1656
                        cf |= NS_EXT;   /* NT flag (Extension has only small capital) */
1657
                }
1658
 
1659
                if( (b & 0x0C) == 0x04 )
1660
                {
1661
                        cf |= NS_BODY;  /* NT flag (Filename has only small capital) */
1662
                }
1663
        }
1664
 
1665
        dj->fn[NS] = cf;                /* SFN is created */
1666
 
1667
        return FR_OK;
1668
 
1669
        #else /* Non-LFN configuration */
1670
        BYTE            b, c, d, *sfn;
1671
        int                     ni, si, i;
1672
        const char      *p;
1673
 
1674
        /* Create file name in directory form */
1675
        sfn = dj->fn;
1676
        mem_set( sfn, ' ', 11 );
1677
        si = i = b = 0;
1678
        ni = 8;
1679
        p = *path;
1680
                #if _FS_RPATH
1681
        if( p[si] == '.' )
1682
        {                                               /* Is this a dot entry? */
1683
                for( ;; )
1684
                {
1685
                        c = p[si++];
1686
                        if( c != '.' || si >= 3 )
1687
                        {
1688
                                break;
1689
                        }
1690
 
1691
                        sfn[i++] = c;
1692
                }
1693
 
1694
                if( c != '/' && c != '\\' && c > ' ' )
1695
                {
1696
                        return FR_INVALID_NAME;
1697
                }
1698
 
1699
                *path = &p[si];         /* Rerurn pointer to the next segment */
1700
                sfn[NS] = ( c <= ' ' ) ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
1701
                return FR_OK;
1702
        }
1703
 
1704
                #endif
1705
        for( ;; )
1706
        {
1707
                c = p[si++];
1708
                if( c <= ' ' || c == '/' || c == '\\' )
1709
                {
1710
                        break;                                  /* Break on end of segment */
1711
                }
1712
 
1713
                if( c == '.' || i >= ni )
1714
                {
1715
                        if( ni != 8 || c != '.' )
1716
                        {
1717
                                return FR_INVALID_NAME;
1718
                        }
1719
 
1720
                        i = 8;
1721
                        ni = 11;
1722
                        b <<= 2;
1723
                        continue;
1724
                }
1725
 
1726
                if( c >= 0x80 )
1727
                {                                                       /* Extended char */
1728
                                #ifdef _EXCVT
1729
                        c = cvt[c - 0x80];              /* Convert extend char (SBCS) */
1730
                                #else
1731
                        b |= 3;                                 /* Eliminate NT flag if ext char is exist */
1732
                                        #if !_DF1S              /* ASCII only cfg */
1733
                        return FR_INVALID_NAME;
1734
                                        #endif
1735
                                #endif
1736
                }
1737
 
1738
                if( IsDBCS1(c) )
1739
                {                                                       /* DBC 1st byte? */
1740
                        d = p[si++];                    /* Get 2nd byte */
1741
                        if( !IsDBCS2(d) || i >= ni - 1 )
1742
                        {                                               /* Reject invalid DBC */
1743
                                return FR_INVALID_NAME;
1744
                        }
1745
 
1746
                        sfn[i++] = c;
1747
                        sfn[i++] = d;
1748
                }
1749
                else
1750
                {                                                       /* Single byte code */
1751
                        if( chk_chr(" \"*+,[=]|\x7F", c) )
1752
                        {                                               /* Reject illegal chrs for SFN */
1753
                                return FR_INVALID_NAME;
1754
                        }
1755
 
1756
                        if( IsUpper(c) )
1757
                        {                                               /* ASCII large capital? */
1758
                                b |= 2;
1759
                        }
1760
                        else
1761
                        {
1762
                                if( IsLower(c) )
1763
                                {                                       /* ASCII small capital? */
1764
                                        b |= 1;
1765
                                        c -= 0x20;
1766
                                }
1767
                        }
1768
 
1769
                        sfn[i++] = c;
1770
                }
1771
        }
1772
 
1773
        *path = &p[si];                                 /* Return pointer to the next segment */
1774
        c = ( c <= ' ' ) ? NS_LAST : 0; /* Set last segment flag if end of path */
1775
 
1776
        if( !i )
1777
        {
1778
                return FR_INVALID_NAME;         /* Reject null string */
1779
        }
1780
 
1781
        if( sfn[0] == 0xE5 )
1782
        {
1783
                sfn[0] = 0x05;                           /* When first char collides with 0xE5, replace it with 0x05 */
1784
        }
1785
 
1786
        if( ni == 8 )
1787
        {
1788
                b <<= 2;
1789
        }
1790
 
1791
        if( (b & 0x03) == 0x01 )
1792
        {
1793
                c |= NS_EXT;                            /* NT flag (Extension has only small capital) */
1794
        }
1795
 
1796
        if( (b & 0x0C) == 0x04 )
1797
        {
1798
                c |= NS_BODY;                           /* NT flag (Filename has only small capital) */
1799
        }
1800
 
1801
        sfn[NS] = c;                                    /* Store NT flag, File name is created */
1802
 
1803
        return FR_OK;
1804
        #endif
1805
}
1806
 
1807
/*-----------------------------------------------------------------------*/
1808
 
1809
/* Get file information from directory entry                             */
1810
 
1811
/*-----------------------------------------------------------------------*/
1812
#if _FS_MINIMIZE <= 1
1813
static void get_fileinfo
1814
        (                                       /* No return code */
1815
                DIR *dj,                /* Pointer to the directory object */
1816
                FILINFO *fno    /* Pointer to the file information to be filled */
1817
        )
1818
{
1819
        int             i;
1820
        BYTE    c, nt, *dir;
1821
        char    *p;
1822
 
1823
        p = fno->fname;
1824
        if( dj->sect )
1825
        {
1826
                dir = dj->dir;
1827
                nt = dir[DIR_NTres];                    /* NT flag */
1828
                for( i = 0; i < 8; i++ )
1829
                {                                                               /* Copy name body */
1830
                        c = dir[i];
1831
                        if( c == ' ' )
1832
                        {
1833
                                break;
1834
                        }
1835
 
1836
                        if( c == 0x05 )
1837
                        {
1838
                                c = 0xE5;
1839
                        }
1840
 
1841
                        if( _USE_LFN && (nt & NS_BODY) && IsUpper(c) )
1842
                        {
1843
                                c += 0x20;
1844
                        }
1845
 
1846
                        *p++ = c;
1847
                }
1848
 
1849
                if( dir[8] != ' ' )
1850
                {                                                               /* Copy name extension */
1851
                        *p++ = '.';
1852
                        for( i = 8; i < 11; i++ )
1853
                        {
1854
                                c = dir[i];
1855
                                if( c == ' ' )
1856
                                {
1857
                                        break;
1858
                                }
1859
 
1860
                                if( _USE_LFN && (nt & NS_EXT) && IsUpper(c) )
1861
                                {
1862
                                        c += 0x20;
1863
                                }
1864
 
1865
                                *p++ = c;
1866
                        }
1867
                }
1868
 
1869
                fno->fattrib = dir[DIR_Attr];   /* Attribute */
1870
                fno->fsize = LD_DWORD( dir + DIR_FileSize );    /* Size */
1871
                fno->fdate = LD_WORD( dir + DIR_WrtDate );              /* Date */
1872
                fno->ftime = LD_WORD( dir + DIR_WrtTime );              /* Time */
1873
        }
1874
 
1875
        *p = 0;
1876
 
1877
                #if _USE_LFN
1878
        if( fno->lfname )
1879
        {
1880
                XCHAR   *tp = fno->lfname;
1881
                WCHAR   w, *lfn;
1882
 
1883
                i = 0;
1884
                if( dj->sect && dj->lfn_idx != 0xFFFF )
1885
                {               /* Get LFN if available */
1886
                        lfn = dj->lfn;
1887
                        while( (w = *lfn++) != 0 )
1888
                        {       /* Get an LFN char */
1889
                                                #if !_LFN_UNICODE
1890
                                w = ff_convert( w, 0 ); /* Unicode -> OEM conversion */
1891
                                if( !w )
1892
                                {
1893
                                        i = 0;
1894
                                        break;
1895
                                }                                               /* Could not convert, no LFN */
1896
 
1897
                                if( _DF1S && w >= 0x100 )
1898
                                {                                               /* Put 1st byte if it is a DBC */
1899
                                        tp[i++] = ( XCHAR ) ( w >> 8 );
1900
                                }
1901
 
1902
                                                #endif
1903
                                if( i >= fno->lfsize - 1 )
1904
                                {
1905
                                        i = 0;
1906
                                        break;
1907
                                }                                               /* Buffer overrun, no LFN */
1908
 
1909
                                tp[i++] = ( XCHAR ) w;
1910
                        }
1911
                }
1912
 
1913
                tp[i] = 0;                                               /* Terminator */
1914
        }
1915
 
1916
                #endif
1917
}
1918
 
1919
#endif /* _FS_MINIMIZE <= 1 */
1920
 
1921
/*-----------------------------------------------------------------------*/
1922
 
1923
/* Follow a file path                                                    */
1924
 
1925
/*-----------------------------------------------------------------------*/
1926
static FRESULT follow_path
1927
        (                                               /* FR_OK(0): successful, !=0: error code */
1928
                DIR *dj,                        /* Directory object to return last directory and found object */
1929
                const XCHAR *path       /* Full-path string to find a file or directory */
1930
        )
1931
{
1932
        FRESULT res;
1933
        BYTE    *dir, last;
1934
 
1935
        while( !_USE_LFN && *path == ' ' )
1936
        {
1937
                path++;                                         /* Skip leading spaces */
1938
        }
1939
 
1940
        #if _FS_RPATH
1941
        if( *path == '/' || *path == '\\' )
1942
        {                                                               /* There is a heading separator */
1943
                path++;
1944
                dj->sclust = 0;                          /* Strip it and start from the root dir */
1945
        }
1946
        else
1947
        {                                                               /* No heading saparator */
1948
                dj->sclust = dj->fs->cdir;      /* Start from the current dir */
1949
        }
1950
 
1951
        #else
1952
        if( *path == '/' || *path == '\\' )
1953
        {                               /* Strip heading separator if exist */
1954
                path++;
1955
        }
1956
 
1957
        dj->sclust = 0; /* Start from the root dir */
1958
        #endif
1959
        if( (UINT) * path < ' ' )
1960
        {                               /* Null path means the start directory itself */
1961
                res = dir_seek( dj, 0 );
1962
                dj->dir = NULL;
1963
        }
1964
        else
1965
        {                               /* Follow path */
1966
                for( ;; )
1967
                {
1968
                        res = create_name( dj, &path ); /* Get a segment */
1969
                        if( res != FR_OK )
1970
                        {
1971
                                break;
1972
                        }
1973
 
1974
                        res = dir_find( dj );                   /* Find it */
1975
                        last = *( dj->fn + NS ) & NS_LAST;
1976
                        if( res != FR_OK )
1977
                        {                               /* Could not find the object */
1978
                                if( res == FR_NO_FILE && !last )
1979
                                {
1980
                                        res = FR_NO_PATH;
1981
                                }
1982
 
1983
                                break;
1984
                        }
1985
 
1986
                        if( last )
1987
                        {
1988
                                break;          /* Last segment match. Function completed. */
1989
                        }
1990
 
1991
                        dir = dj->dir;  /* There is next segment. Follow the sub directory */
1992
                        if( !(dir[DIR_Attr] & AM_DIR) )
1993
                        {                               /* Cannot follow because it is a file */
1994
                                res = FR_NO_PATH;
1995
                                break;
1996
                        }
1997
 
1998
                        dj->sclust = ( (DWORD) LD_WORD(dir + DIR_FstClusHI) << 16 ) | LD_WORD( dir + DIR_FstClusLO );
1999
                }
2000
        }
2001
 
2002
        return res;
2003
}
2004
 
2005
/*-----------------------------------------------------------------------*/
2006
 
2007
/* Load boot record and check if it is an FAT boot record                */
2008
 
2009
/*-----------------------------------------------------------------------*/
2010
static BYTE check_fs
2011
        (                               /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
2012
                FATFS *fs,      /* File system object */
2013
                DWORD sect      /* Sector# (lba) to check if it is an FAT boot record or not */
2014
        )
2015
{
2016
        if( disk_read(fs->drive, fs->win, sect, 1) != RES_OK )
2017
        {       /* Load boot record */
2018
                return 3;
2019
        }
2020
 
2021
        if( LD_WORD(&fs->win[BS_55AA]) != 0xAA55 )
2022
        {       /* Check record signature (always placed at offset 510 even if the sector size is >512) */
2023
                return 2;
2024
        }
2025
 
2026
        if( (LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146 )
2027
        {       /* Check "FAT" string */
2028
                return 0;
2029
        }
2030
 
2031
        if( (LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146 )
2032
        {
2033
                return 0;
2034
        }
2035
 
2036
        return 1;
2037
}
2038
 
2039
/*-----------------------------------------------------------------------*/
2040
 
2041
/* Make sure that the file system is valid                               */
2042
 
2043
/*-----------------------------------------------------------------------*/
2044
FRESULT chk_mounted
2045
        (                                               /* FR_OK(0): successful, !=0: any error occured */
2046
                const XCHAR **path, /* Pointer to pointer to the path name (drive number) */
2047
                FATFS **rfs,            /* Pointer to pointer to the found file system object */
2048
                BYTE chk_wp                     /* !=0: Check media write protection for write access */
2049
        )
2050
{
2051
        BYTE            fmt, *tbl;
2052
        UINT            vol;
2053
        DSTATUS         stat;
2054
        DWORD           bsect, fsize, tsect, mclst;
2055
        const XCHAR *p = *path;
2056
        FATFS           *fs;
2057
 
2058
        /* Get logical drive number from the path name */
2059
        vol = p[0] - '0';                        /* Is there a drive number? */
2060
        if( vol <= 9 && p[1] == ':' )
2061
        {                                                       /* Found a drive number, get and strip it */
2062
                p += 2;
2063
                *path = p;                              /* Return pointer to the path name */
2064
        }
2065
        else
2066
        {                                                       /* No drive number is given */
2067
                #if _FS_RPATH
2068
                vol = Drive;                    /* Use current drive */
2069
                #else
2070
                vol = 0;                         /* Use drive 0 */
2071
                #endif
2072
        }
2073
 
2074
        /* Check if the logical drive is valid or not */
2075
        if( vol >= _DRIVES )
2076
        {                                                       /* Is the drive number valid? */
2077
                return FR_INVALID_DRIVE;
2078
        }
2079
 
2080
        *rfs = fs = FatFs[vol];         /* Returen pointer to the corresponding file system object */
2081
        if( !fs )
2082
        {
2083
                return FR_NOT_ENABLED;  /* Is the file system object available? */
2084
        }
2085
 
2086
        ENTER_FF( fs );                         /* Lock file system */
2087
 
2088
        if( fs->fs_type )
2089
        {                                               /* If the logical drive has been mounted */
2090
                stat = disk_status( fs->drive );
2091
                if( !(stat & STA_NOINIT) )
2092
                {                                       /* and the physical drive is kept initialized (has not been changed), */
2093
                        #if !_FS_READONLY
2094
                        if( chk_wp && (stat & STA_PROTECT) )
2095
                        {                               /* Check write protection if needed */
2096
                                return FR_WRITE_PROTECTED;
2097
                        }
2098
 
2099
                        #endif
2100
                        return FR_OK;   /* The file system object is valid */
2101
                }
2102
        }
2103
 
2104
        /* The logical drive must be mounted. Following code attempts to mount the volume */
2105
        fs->fs_type = 0;         /* Clear the file system object */
2106
        fs->drive = ( BYTE ) LD2PD( vol );              /* Bind the logical drive and a physical drive */
2107
        stat = disk_initialize( fs->drive );    /* Initialize low level disk I/O layer */
2108
        if( stat & STA_NOINIT )
2109
        {                                       /* Check if the drive is ready */
2110
                return FR_NOT_READY;
2111
        }
2112
 
2113
        #if _MAX_SS != 512      /* Get disk sector size if needed */
2114
        if( disk_ioctl(fs->drive, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS )
2115
        {
2116
                return FR_NO_FILESYSTEM;
2117
        }
2118
 
2119
        #endif
2120
        #if !_FS_READONLY
2121
        if( chk_wp && (stat & STA_PROTECT) )
2122
        {                                       /* Check disk write protection if needed */
2123
                return FR_WRITE_PROTECTED;
2124
        }
2125
 
2126
        #endif
2127
 
2128
        /* Search FAT partition on the drive */
2129
        fmt = check_fs( fs, bsect = 0 ); /* Check sector 0 as an SFD format */
2130
        if( fmt == 1 )
2131
        {       /* Not an FAT boot record, it may be patitioned */
2132
                /* Check a partition listed in top of the partition table */
2133
                tbl = &fs->win[MBR_Table + LD2PT( vol ) * 16];  /* Partition table */
2134
                if( tbl[4] )
2135
                {       /* Is the partition existing? */
2136
                        bsect = LD_DWORD( &tbl[8] );    /* Partition offset in LBA */
2137
                        fmt = check_fs( fs, bsect );    /* Check the partition */
2138
                }
2139
        }
2140
 
2141
        if( fmt == 3 )
2142
        {
2143
                return FR_DISK_ERR;
2144
        }
2145
 
2146
        if( fmt || LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs) )
2147
        {       /* No valid FAT patition is found */
2148
                return FR_NO_FILESYSTEM;
2149
        }
2150
 
2151
        /* Initialize the file system object */
2152
        fsize = LD_WORD( fs->win + BPB_FATSz16 );                                       /* Number of sectors per FAT */
2153
        if( !fsize )
2154
        {
2155
                fsize = LD_DWORD( fs->win + BPB_FATSz32 );
2156
        }
2157
 
2158
        fs->sects_fat = fsize;
2159
        fs->n_fats = fs->win[BPB_NumFATs];                                                      /* Number of FAT copies */
2160
        fsize *= fs->n_fats;                                                                            /* (Number of sectors in FAT area) */
2161
        fs->fatbase = bsect + LD_WORD( fs->win + BPB_RsvdSecCnt );      /* FAT start sector (lba) */
2162
        fs->csize = fs->win[BPB_SecPerClus];                                            /* Number of sectors per cluster */
2163
        fs->n_rootdir = LD_WORD( fs->win + BPB_RootEntCnt );            /* Nmuber of root directory entries */
2164
        tsect = LD_WORD( fs->win + BPB_TotSec16 );                                      /* Number of sectors on the volume */
2165
        if( !tsect )
2166
        {
2167
                tsect = LD_DWORD( fs->win + BPB_TotSec32 );
2168
        }
2169
 
2170
        fs->max_clust = mclst =
2171
                (
2172
                        tsect /* Last cluster# + 1 (Number of clusters + 2) */ -
2173
                        LD_WORD(fs->win + BPB_RsvdSecCnt) -
2174
                        fsize -
2175
                        fs->n_rootdir /
2176
                        (SS(fs) / 32)
2177
                ) /
2178
                fs->csize +
2179
                2;
2180
 
2181
        fmt = FS_FAT12;         /* Determine the FAT sub type */
2182
        if( mclst >= 0xFF7 )
2183
        {
2184
                fmt = FS_FAT16; /* Number of clusters >= 0xFF5 */
2185
        }
2186
 
2187
        if( mclst >= 0xFFF7 )
2188
        {
2189
                fmt = FS_FAT32; /* Number of clusters >= 0xFFF5 */
2190
        }
2191
 
2192
        if( fmt == FS_FAT32 )
2193
        {
2194
                fs->dirbase = LD_DWORD( fs->win + BPB_RootClus );                                       /* Root directory start cluster */
2195
        }
2196
        else
2197
        {
2198
                fs->dirbase = fs->fatbase + fsize;                                                                      /* Root directory start sector (lba) */
2199
        }
2200
 
2201
        fs->database = fs->fatbase + fsize + fs->n_rootdir / ( SS(fs) / 32 );   /* Data start sector (lba) */
2202
 
2203
        #if !_FS_READONLY
2204
 
2205
        /* Initialize allocation information */
2206
        fs->free_clust = 0xFFFFFFFF;
2207
        fs->wflag = 0;
2208
 
2209
        /* Get fsinfo if needed */
2210
        if( fmt == FS_FAT32 )
2211
        {
2212
                fs->fsi_flag = 0;
2213
                fs->fsi_sector = bsect + LD_WORD( fs->win + BPB_FSInfo );
2214
                if
2215
                (
2216
                        disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
2217
                        LD_WORD(fs->win + BS_55AA) == 0xAA55 &&
2218
                        LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 &&
2219
                        LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272
2220
                )
2221
                {
2222
                        fs->last_clust = LD_DWORD( fs->win + FSI_Nxt_Free );
2223
                        fs->free_clust = LD_DWORD( fs->win + FSI_Free_Count );
2224
                }
2225
        }
2226
 
2227
        #endif
2228
        fs->fs_type = fmt;      /* FAT sub-type */
2229
        fs->winsect = 0; /* Invalidate sector cache */
2230
        #if _FS_RPATH
2231
        fs->cdir = 0;            /* Current directory (root dir) */
2232
        #endif
2233
        fs->id = ++Fsid;        /* File system mount ID */
2234
 
2235
        return FR_OK;
2236
}
2237
 
2238
/*-----------------------------------------------------------------------*/
2239
 
2240
/* Check if the file/dir object is valid or not                          */
2241
 
2242
/*-----------------------------------------------------------------------*/
2243
static FRESULT validate
2244
        (                               /* FR_OK(0): The object is valid, !=0: Invalid */
2245
                FATFS *fs,      /* Pointer to the file system object */
2246
                WORD id         /* Member id of the target object to be checked */
2247
        )
2248
{
2249
        if( !fs || !fs->fs_type || fs->id != id )
2250
        {
2251
                return FR_INVALID_OBJECT;
2252
        }
2253
 
2254
        ENTER_FF( fs ); /* Lock file system */
2255
 
2256
        if( disk_status(fs->drive) & STA_NOINIT )
2257
        {
2258
                return FR_NOT_READY;
2259
        }
2260
 
2261
        return FR_OK;
2262
}
2263
 
2264
/*--------------------------------------------------------------------------
2265
 
2266
   Public Functions
2267
 
2268
--------------------------------------------------------------------------*/
2269
 
2270
/*-----------------------------------------------------------------------*/
2271
 
2272
/* Mount/Unmount a Locical Drive                                         */
2273
 
2274
/*-----------------------------------------------------------------------*/
2275
FRESULT f_mount
2276
                (
2277
                        BYTE    vol,    /* Logical drive number to be mounted/unmounted */
2278
                        FATFS   *fs             /* Pointer to new file system object (NULL for unmount)*/
2279
                )
2280
{
2281
        FATFS   *rfs;
2282
 
2283
        if( vol >= _DRIVES )
2284
        {                                               /* Check if the drive number is valid */
2285
                return FR_INVALID_DRIVE;
2286
        }
2287
 
2288
        rfs = FatFs[vol];               /* Get current fs object */
2289
 
2290
        if( rfs )
2291
        {
2292
                #if _FS_REENTRANT       /* Discard sync object of the current volume */
2293
                if( !ff_del_syncobj(rfs->sobj) )
2294
                {
2295
                        return FR_INT_ERR;
2296
                }
2297
 
2298
                #endif
2299
                rfs->fs_type = 0;        /* Clear old fs object */
2300
        }
2301
 
2302
        if( fs )
2303
        {
2304
                fs->fs_type = 0; /* Clear new fs object */
2305
                #if _FS_REENTRANT       /* Create sync object for the new volume */
2306
                if( !ff_cre_syncobj(vol, &fs->sobj) )
2307
                {
2308
                        return FR_INT_ERR;
2309
                }
2310
 
2311
                #endif
2312
        }
2313
 
2314
        FatFs[vol] = fs;                /* Register new fs object */
2315
 
2316
        return FR_OK;
2317
}
2318
 
2319
/*-----------------------------------------------------------------------*/
2320
 
2321
/* Open or Create a File                                                 */
2322
 
2323
/*-----------------------------------------------------------------------*/
2324
FRESULT f_open
2325
                (
2326
                        FIL                     *fp,    /* Pointer to the blank file object */
2327
                        const XCHAR *path,      /* Pointer to the file name */
2328
                        BYTE            mode    /* Access mode and file open mode flags */
2329
                )
2330
{
2331
        FRESULT res;
2332
        DIR             dj;
2333
        NAMEBUF( sfn, lfn );
2334
 
2335
        BYTE    *dir;
2336
 
2337
        fp->fs = NULL;                                  /* Clear file object */
2338
        #if !_FS_READONLY
2339
        mode &= ( FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW );
2340
        res = chk_mounted( &path, &dj.fs, (BYTE) (mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) );
2341
        #else
2342
        mode &= FA_READ;
2343
        res = chk_mounted( &path, &dj.fs, 0 );
2344
        #endif
2345
        if( res != FR_OK )
2346
        {
2347
                LEAVE_FF( dj.fs, res );
2348
        }
2349
 
2350
        INITBUF( dj, sfn, lfn );
2351
        res = follow_path( &dj, path ); /* Follow the file path */
2352
 
2353
        #if !_FS_READONLY
2354
 
2355
        /* Create or Open a file */
2356
        if( mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW) )
2357
        {
2358
                DWORD   ps, cl;
2359
 
2360
                if( res != FR_OK )
2361
                {                                       /* No file, create new */
2362
                        if( res == FR_NO_FILE )
2363
                        {                               /* There is no file to open, create a new entry */
2364
                                res = dir_register( &dj );
2365
                        }
2366
 
2367
                        if( res != FR_OK )
2368
                        {
2369
                                LEAVE_FF( dj.fs, res );
2370
                        }
2371
 
2372
                        mode |= FA_CREATE_ALWAYS;
2373
                        dir = dj.dir;   /* Created entry (SFN entry) */
2374
                }
2375
                else
2376
                {                                       /* Any object is already existing */
2377
                        if( mode & FA_CREATE_NEW )
2378
                        {                               /* Cannot create new */
2379
                                LEAVE_FF( dj.fs, FR_EXIST );
2380
                        }
2381
 
2382
                        dir = dj.dir;
2383
                        if( !dir || (dir[DIR_Attr] & (AM_RDO | AM_DIR)) )
2384
                        {                               /* Cannot overwrite it (R/O or DIR) */
2385
                                LEAVE_FF( dj.fs, FR_DENIED );
2386
                        }
2387
 
2388
                        if( mode & FA_CREATE_ALWAYS )
2389
                        {                               /* Resize it to zero on over write mode */
2390
                                cl = ( (DWORD) LD_WORD(dir + DIR_FstClusHI) << 16 ) | LD_WORD( dir + DIR_FstClusLO );   /* Get start cluster */
2391
                                ST_WORD( dir + DIR_FstClusHI, 0 );       /* cluster = 0 */
2392
                                ST_WORD( dir + DIR_FstClusLO, 0 );
2393
                                ST_DWORD( dir + DIR_FileSize, 0 );       /* size = 0 */
2394
                                dj.fs->wflag = 1;
2395
                                ps = dj.fs->winsect;                            /* Remove the cluster chain */
2396
                                if( cl )
2397
                                {
2398
                                        res = remove_chain( dj.fs, cl );
2399
                                        if( res )
2400
                                        {
2401
                                                LEAVE_FF( dj.fs, res );
2402
                                        }
2403
 
2404
                                        dj.fs->last_clust = cl - 1;             /* Reuse the cluster hole */
2405
                                }
2406
 
2407
                                res = move_window( dj.fs, ps );
2408
                                if( res != FR_OK )
2409
                                {
2410
                                        LEAVE_FF( dj.fs, res );
2411
                                }
2412
                        }
2413
                }
2414
 
2415
                if( mode & FA_CREATE_ALWAYS )
2416
                {
2417
                        dir[DIR_Attr] = 0;                                               /* Reset attribute */
2418
                        ps = get_fattime();
2419
                        ST_DWORD( dir + DIR_CrtTime, ps );              /* Created time */
2420
                        dj.fs->wflag = 1;
2421
                        mode |= FA__WRITTEN;                                    /* Set file changed flag */
2422
                }
2423
        }
2424
 
2425
        /* Open an existing file */
2426
        else
2427
        {
2428
                #endif /* !_FS_READONLY */
2429
                if( res != FR_OK )
2430
                {
2431
                        LEAVE_FF( dj.fs, res );                                 /* Follow failed */
2432
                }
2433
 
2434
                dir = dj.dir;
2435
                if( !dir || (dir[DIR_Attr] & AM_DIR) )
2436
                {       /* It is a directory */
2437
                        LEAVE_FF( dj.fs, FR_NO_FILE );
2438
                }
2439
 
2440
                #if !_FS_READONLY
2441
                if( (mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO) )
2442
                {       /* R/O violation */
2443
                        LEAVE_FF( dj.fs, FR_DENIED );
2444
                }
2445
        }
2446
 
2447
        fp->dir_sect = dj.fs->winsect;                          /* Pointer to the directory entry */
2448
        fp->dir_ptr = dj.dir;
2449
        #endif
2450
        fp->flag = mode;                                                        /* File access mode */
2451
        fp->org_clust =                                                         /* File start cluster */
2452
        ( (DWORD) LD_WORD(dir + DIR_FstClusHI) << 16 ) | LD_WORD( dir + DIR_FstClusLO );
2453
        fp->fsize = LD_DWORD( dir + DIR_FileSize ); /* File size */
2454
        fp->fptr = 0;
2455
        fp->csect = 255;        /* File pointer */
2456
        fp->dsect = 0;
2457
        fp->fs = dj.fs;
2458
        fp->id = dj.fs->id; /* Owner file system object of the file */
2459
 
2460
        LEAVE_FF( dj.fs, FR_OK );
2461
}
2462
 
2463
/*-----------------------------------------------------------------------*/
2464
 
2465
/* Read File                                                             */
2466
 
2467
/*-----------------------------------------------------------------------*/
2468
FRESULT f_read
2469
                (
2470
                        FIL             *fp,    /* Pointer to the file object */
2471
                        void    *buff,  /* Pointer to data buffer */
2472
                        UINT    btr,    /* Number of bytes to read */
2473
                        UINT    *br             /* Pointer to number of bytes read */
2474
                )
2475
{
2476
        FRESULT res;
2477
        DWORD   clst, sect, remain;
2478
        UINT    rcnt, cc;
2479
        BYTE    *rbuff = buff;
2480
 
2481
        *br = 0; /* Initialize bytes read */
2482
 
2483
        res = validate( fp->fs, fp->id );       /* Check validity of the object */
2484
        if( res != FR_OK )
2485
        {
2486
                LEAVE_FF( fp->fs, res );
2487
        }
2488
 
2489
        if( fp->flag & FA__ERROR )
2490
        {       /* Check abort flag */
2491
                LEAVE_FF( fp->fs, FR_INT_ERR );
2492
        }
2493
 
2494
        if( !(fp->flag & FA_READ) )
2495
        {       /* Check access mode */
2496
                LEAVE_FF( fp->fs, FR_DENIED );
2497
        }
2498
 
2499
        remain = fp->fsize - fp->fptr;
2500
        if( btr > remain )
2501
        {
2502
                btr = ( UINT ) remain;                          /* Truncate btr by remaining bytes */
2503
        }
2504
 
2505
        for( ; btr; /* Repeat until all data transferred */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt )
2506
        {
2507
                if( (fp->fptr % SS(fp->fs)) == 0 )
2508
                {                                                                       /* On the sector boundary? */
2509
                        if( fp->csect >= fp->fs->csize )
2510
                        {                                                               /* On the cluster boundary? */
2511
                                clst = ( fp->fptr == 0 ) ?       /* On the top of the file? */
2512
                                fp->org_clust : get_fat( fp->fs, fp->curr_clust );
2513
                                if( clst <= 1 )
2514
                                {
2515
                                        ABORT( fp->fs, FR_INT_ERR );
2516
                                }
2517
 
2518
                                if( clst == 0xFFFFFFFF )
2519
                                {
2520
                                        ABORT( fp->fs, FR_DISK_ERR );
2521
                                }
2522
 
2523
                                fp->curr_clust = clst;          /* Update current cluster */
2524
                                fp->csect = 0;                           /* Reset sector offset in the cluster */
2525
                        }
2526
 
2527
                        sect = clust2sect( fp->fs, fp->curr_clust );    /* Get current sector */
2528
                        if( !sect )
2529
                        {
2530
                                ABORT( fp->fs, FR_INT_ERR );
2531
                        }
2532
 
2533
                        sect += fp->csect;
2534
                        cc = btr / SS( fp->fs );                                                /* When remaining bytes >= sector size, */
2535
                        if( cc )
2536
                        {               /* Read maximum contiguous sectors directly */
2537
                                if( fp->csect + cc > fp->fs->csize )
2538
                                {       /* Clip at cluster boundary */
2539
                                        cc = fp->fs->csize - fp->csect;
2540
                                }
2541
 
2542
                                if( disk_read(fp->fs->drive, rbuff, sect, (BYTE) cc) != RES_OK )
2543
                                {
2544
                                        ABORT( fp->fs, FR_DISK_ERR );
2545
                                }
2546
 
2547
                                #if !_FS_READONLY && _FS_MINIMIZE <= 2
2548
                                        #if _FS_TINY
2549
                                if( fp->fs->wflag && fp->fs->winsect - sect < cc )
2550
                                {       /* Replace one of the read sectors with cached data if it contains a dirty sector */
2551
                                        mem_cpy( rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs) );
2552
                                }
2553
 
2554
                                        #else
2555
                                if( (fp->flag & FA__DIRTY) && fp->dsect - sect < cc )
2556
                                {       /* Replace one of the read sectors with cached data if it contains a dirty sector */
2557
                                        mem_cpy( rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs) );
2558
                                }
2559
 
2560
                                        #endif
2561
                                #endif
2562
                                fp->csect += ( BYTE ) cc;       /* Next sector address in the cluster */
2563
                                rcnt = SS( fp->fs ) * cc;       /* Number of bytes transferred */
2564
                                continue;
2565
                        }
2566
 
2567
                        #if !_FS_TINY
2568
                                #if !_FS_READONLY
2569
                        if( fp->flag & FA__DIRTY )
2570
                        {                               /* Write sector I/O buffer if needed */
2571
                                if( disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK )
2572
                                {
2573
                                        ABORT( fp->fs, FR_DISK_ERR );
2574
                                }
2575
 
2576
                                fp->flag &= ~FA__DIRTY;
2577
                        }
2578
 
2579
                                #endif
2580
                        if( fp->dsect != sect )
2581
                        {                               /* Fill sector buffer with file data */
2582
                                if( disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK )
2583
                                {
2584
                                        ABORT( fp->fs, FR_DISK_ERR );
2585
                                }
2586
                        }
2587
 
2588
                        #endif
2589
                        fp->dsect = sect;
2590
                        fp->csect++;    /* Next sector address in the cluster */
2591
                }
2592
 
2593
                rcnt = SS( fp->fs ) - ( fp->fptr % SS(fp->fs) );        /* Get partial sector data from sector buffer */
2594
                if( rcnt > btr )
2595
                {
2596
                        rcnt = btr;
2597
                }
2598
 
2599
                #if _FS_TINY
2600
                if( move_window(fp->fs, fp->dsect) )
2601
                {       /* Move sector window */
2602
                        ABORT( fp->fs, FR_DISK_ERR );
2603
                }
2604
 
2605
                mem_cpy( rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt );    /* Pick partial sector */
2606
                #else
2607
                mem_cpy( rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt );                /* Pick partial sector */
2608
                #endif
2609
        }
2610
 
2611
        LEAVE_FF( fp->fs, FR_OK );
2612
}
2613
 
2614
#if !_FS_READONLY
2615
 
2616
/*-----------------------------------------------------------------------*/
2617
 
2618
/* Write File                                                            */
2619
 
2620
/*-----------------------------------------------------------------------*/
2621
FRESULT f_write
2622
                (
2623
                        FIL                     *fp,    /* Pointer to the file object */
2624
                        const void      *buff,  /* Pointer to the data to be written */
2625
                        UINT            btw,    /* Number of bytes to write */
2626
                        UINT            *bw             /* Pointer to number of bytes written */
2627
                )
2628
{
2629
        FRESULT         res;
2630
        DWORD           clst, sect;
2631
        UINT            wcnt, cc;
2632
        const BYTE      *wbuff = buff;
2633
 
2634
        *bw = 0; /* Initialize bytes written */
2635
 
2636
        res = validate( fp->fs, fp->id );       /* Check validity of the object */
2637
        if( res != FR_OK )
2638
        {
2639
                LEAVE_FF( fp->fs, res );
2640
        }
2641
 
2642
        if( fp->flag & FA__ERROR )
2643
        {                               /* Check abort flag */
2644
                LEAVE_FF( fp->fs, FR_INT_ERR );
2645
        }
2646
 
2647
        if( !(fp->flag & FA_WRITE) )
2648
        {                               /* Check access mode */
2649
                LEAVE_FF( fp->fs, FR_DENIED );
2650
        }
2651
 
2652
        if( fp->fsize + btw < fp->fsize )
2653
        {
2654
                btw = 0; /* File size cannot reach 4GB */
2655
        }
2656
 
2657
        for( ; btw; /* Repeat until all data transferred */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt )
2658
        {
2659
                if( (fp->fptr % SS(fp->fs)) == 0 )
2660
                {                       /* On the sector boundary? */
2661
                        if( fp->csect >= fp->fs->csize )
2662
                        {               /* On the cluster boundary? */
2663
                                if( fp->fptr == 0 )
2664
                                {       /* On the top of the file? */
2665
                                        clst = fp->org_clust;   /* Follow from the origin */
2666
                                        if( clst == 0 )
2667
                                        {                                               /* When there is no cluster chain, */
2668
                                                fp->org_clust = clst = create_chain( fp->fs, 0 );        /* Create a new cluster chain */
2669
                                        }
2670
                                }
2671
                                else
2672
                                {       /* Middle or end of the file */
2673
                                        clst = create_chain( fp->fs, fp->curr_clust );  /* Follow or streach cluster chain */
2674
                                }
2675
 
2676
                                if( clst == 0 )
2677
                                {
2678
                                        break;                          /* Could not allocate a new cluster (disk full) */
2679
                                }
2680
 
2681
                                if( clst == 1 )
2682
                                {
2683
                                        ABORT( fp->fs, FR_INT_ERR );
2684
                                }
2685
 
2686
                                if( clst == 0xFFFFFFFF )
2687
                                {
2688
                                        ABORT( fp->fs, FR_DISK_ERR );
2689
                                }
2690
 
2691
                                fp->curr_clust = clst;  /* Update current cluster */
2692
                                fp->csect = 0;                   /* Reset sector address in the cluster */
2693
                        }
2694
 
2695
                                #if _FS_TINY
2696
                        if( fp->fs->winsect == fp->dsect && move_window(fp->fs, 0) )
2697
                        {       /* Write back data buffer prior to following direct transfer */
2698
                                ABORT( fp->fs, FR_DISK_ERR );
2699
                        }
2700
 
2701
                                #else
2702
                        if( fp->flag & FA__DIRTY )
2703
                        {       /* Write back data buffer prior to following direct transfer */
2704
                                if( disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK )
2705
                                {
2706
                                        ABORT( fp->fs, FR_DISK_ERR );
2707
                                }
2708
 
2709
                                fp->flag &= ~FA__DIRTY;
2710
                        }
2711
 
2712
                                #endif
2713
                        sect = clust2sect( fp->fs, fp->curr_clust );    /* Get current sector */
2714
                        if( !sect )
2715
                        {
2716
                                ABORT( fp->fs, FR_INT_ERR );
2717
                        }
2718
 
2719
                        sect += fp->csect;
2720
                        cc = btw / SS( fp->fs );                                                /* When remaining bytes >= sector size, */
2721
                        if( cc )
2722
                        {               /* Write maximum contiguous sectors directly */
2723
                                if( fp->csect + cc > fp->fs->csize )
2724
                                {       /* Clip at cluster boundary */
2725
                                        cc = fp->fs->csize - fp->csect;
2726
                                }
2727
 
2728
                                if( disk_write(fp->fs->drive, wbuff, sect, (BYTE) cc) != RES_OK )
2729
                                {
2730
                                        ABORT( fp->fs, FR_DISK_ERR );
2731
                                }
2732
 
2733
                                        #if _FS_TINY
2734
                                if( fp->fs->winsect - sect < cc )
2735
                                {       /* Refill sector cache if it gets dirty by the direct write */
2736
                                        mem_cpy( fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs) );
2737
                                        fp->fs->wflag = 0;
2738
                                }
2739
 
2740
                                        #else
2741
                                if( fp->dsect - sect < cc )
2742
                                {       /* Refill sector cache if it gets dirty by the direct write */
2743
                                        mem_cpy( fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs) );
2744
                                        fp->flag &= ~FA__DIRTY;
2745
                                }
2746
 
2747
                                        #endif
2748
                                fp->csect += ( BYTE ) cc;       /* Next sector address in the cluster */
2749
                                wcnt = SS( fp->fs ) * cc;       /* Number of bytes transferred */
2750
                                continue;
2751
                        }
2752
 
2753
                                #if _FS_TINY
2754
                        if( fp->fptr >= fp->fsize )
2755
                        {                               /* Avoid silly buffer filling at growing edge */
2756
                                if( move_window(fp->fs, 0) )
2757
                                {
2758
                                        ABORT( fp->fs, FR_DISK_ERR );
2759
                                }
2760
 
2761
                                fp->fs->winsect = sect;
2762
                        }
2763
 
2764
                                #else
2765
                        if( fp->dsect != sect )
2766
                        {                               /* Fill sector buffer with file data */
2767
                                if( fp->fptr < fp->fsize && disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK )
2768
                                {
2769
                                        ABORT( fp->fs, FR_DISK_ERR );
2770
                                }
2771
                        }
2772
 
2773
                                #endif
2774
                        fp->dsect = sect;
2775
                        fp->csect++;    /* Next sector address in the cluster */
2776
                }
2777
 
2778
                wcnt = SS( fp->fs ) - ( fp->fptr % SS(fp->fs) );        /* Put partial sector into file I/O buffer */
2779
                if( wcnt > btw )
2780
                {
2781
                        wcnt = btw;
2782
                }
2783
 
2784
                        #if _FS_TINY
2785
                if( move_window(fp->fs, fp->dsect) )
2786
                {       /* Move sector window */
2787
                        ABORT( fp->fs, FR_DISK_ERR );
2788
                }
2789
 
2790
                mem_cpy( &fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt );    /* Fit partial sector */
2791
                fp->fs->wflag = 1;
2792
                        #else
2793
                mem_cpy( &fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt );                /* Fit partial sector */
2794
                fp->flag |= FA__DIRTY;
2795
                        #endif
2796
        }
2797
 
2798
        if( fp->fptr > fp->fsize )
2799
        {
2800
                fp->fsize = fp->fptr;   /* Update file size if needed */
2801
        }
2802
 
2803
        fp->flag |= FA__WRITTEN;        /* Set file changed flag */
2804
 
2805
        LEAVE_FF( fp->fs, FR_OK );
2806
}
2807
 
2808
/*-----------------------------------------------------------------------*/
2809
 
2810
/* Synchronize the File Object                                           */
2811
 
2812
/*-----------------------------------------------------------------------*/
2813
FRESULT f_sync( FIL *fp /* Pointer to the file object */ )
2814
{
2815
        FRESULT res;
2816
        DWORD   tim;
2817
        BYTE    *dir;
2818
 
2819
        res = validate( fp->fs, fp->id );       /* Check validity of the object */
2820
        if( res == FR_OK )
2821
        {
2822
                if( fp->flag & FA__WRITTEN )
2823
                {                                               /* Has the file been written? */
2824
                                #if !_FS_TINY   /* Write-back dirty buffer */
2825
                        if( fp->flag & FA__DIRTY )
2826
                        {
2827
                                if( disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK )
2828
                                {
2829
                                        LEAVE_FF( fp->fs, FR_DISK_ERR );
2830
                                }
2831
 
2832
                                fp->flag &= ~FA__DIRTY;
2833
                        }
2834
 
2835
                                #endif
2836
 
2837
                        /* Update the directory entry */
2838
                        res = move_window( fp->fs, fp->dir_sect );
2839
                        if( res == FR_OK )
2840
                        {
2841
                                dir = fp->dir_ptr;
2842
                                dir[DIR_Attr] |= AM_ARC;                                                /* Set archive bit */
2843
                                ST_DWORD( dir + DIR_FileSize, fp->fsize );              /* Update file size */
2844
                                ST_WORD( dir + DIR_FstClusLO, fp->org_clust );  /* Update start cluster */
2845
                                ST_WORD( dir + DIR_FstClusHI, fp->org_clust >> 16 );
2846
                                tim = get_fattime();    /* Updated time */
2847
                                ST_DWORD( dir + DIR_WrtTime, tim );
2848
                                fp->flag &= ~FA__WRITTEN;
2849
                                fp->fs->wflag = 1;
2850
                                res = sync( fp->fs );
2851
                        }
2852
                }
2853
        }
2854
 
2855
        LEAVE_FF( fp->fs, res );
2856
}
2857
 
2858
#endif /* !_FS_READONLY */
2859
 
2860
/*-----------------------------------------------------------------------*/
2861
 
2862
/* Close File                                                            */
2863
 
2864
/*-----------------------------------------------------------------------*/
2865
FRESULT f_close( FIL *fp /* Pointer to the file object to be closed */ )
2866
{
2867
        FRESULT res;
2868
 
2869
        #if _FS_READONLY
2870
        res = validate( fp->fs, fp->id );
2871
        if( res == FR_OK )
2872
        {
2873
                fp->fs = NULL;
2874
        }
2875
 
2876
        LEAVE_FF( fp->fs, res );
2877
        #else
2878
        res = f_sync( fp );
2879
        if( res == FR_OK )
2880
        {
2881
                fp->fs = NULL;
2882
        }
2883
 
2884
        return res;
2885
        #endif
2886
}
2887
 
2888
/*-----------------------------------------------------------------------*/
2889
 
2890
/* Change Current Drive/Directory                                        */
2891
 
2892
/*-----------------------------------------------------------------------*/
2893
#if _FS_RPATH
2894
FRESULT f_chdrive( BYTE drv /* Drive number */ )
2895
{
2896
        if( drv >= _DRIVES )
2897
        {
2898
                return FR_INVALID_DRIVE;
2899
        }
2900
 
2901
        Drive = drv;
2902
 
2903
        return FR_OK;
2904
}
2905
 
2906
FRESULT f_chdir( const XCHAR *path /* Pointer to the directory path */ )
2907
{
2908
        FRESULT res;
2909
        DIR             dj;
2910
        NAMEBUF( sfn, lfn );
2911
 
2912
        BYTE    *dir;
2913
 
2914
        res = chk_mounted( &path, &dj.fs, 0 );
2915
        if( res == FR_OK )
2916
        {
2917
                INITBUF( dj, sfn, lfn );
2918
                res = follow_path( &dj, path ); /* Follow the file path */
2919
                if( res == FR_OK )
2920
                {                                       /* Follow completed */
2921
                        dir = dj.dir;   /* Pointer to the entry */
2922
                        if( !dir )
2923
                        {
2924
                                dj.fs->cdir = 0;         /* No entry (root dir) */
2925
                        }
2926
                        else
2927
                        {
2928
                                if( dir[DIR_Attr] & AM_DIR )
2929
                                {                                               /* Reached to the dir */
2930
                                        dj.fs->cdir = ( (DWORD) LD_WORD(dir + DIR_FstClusHI) << 16 ) | LD_WORD( dir + DIR_FstClusLO );
2931
                                }
2932
                                else
2933
                                {
2934
                                        res = FR_NO_PATH;       /* Could not reach the dir (it is a file) */
2935
                                }
2936
                        }
2937
                }
2938
 
2939
                if( res == FR_NO_FILE )
2940
                {
2941
                        res = FR_NO_PATH;
2942
                }
2943
        }
2944
 
2945
        LEAVE_FF( dj.fs, res );
2946
}
2947
 
2948
#endif
2949
#if _FS_MINIMIZE <= 2
2950
 
2951
/*-----------------------------------------------------------------------*/
2952
 
2953
/* Seek File R/W Pointer                                                 */
2954
 
2955
/*-----------------------------------------------------------------------*/
2956
FRESULT f_lseek( FIL *fp, /* Pointer to the file object */ DWORD ofs /* File pointer from top of file */ )
2957
{
2958
        FRESULT res;
2959
        DWORD   clst, bcs, nsect, ifptr;
2960
 
2961
        res = validate( fp->fs, fp->id );       /* Check validity of the object */
2962
        if( res != FR_OK )
2963
        {
2964
                LEAVE_FF( fp->fs, res );
2965
        }
2966
 
2967
        if( fp->flag & FA__ERROR )
2968
        {                                       /* Check abort flag */
2969
                LEAVE_FF( fp->fs, FR_INT_ERR );
2970
        }
2971
 
2972
        if( ofs > fp->fsize /* In read-only mode, clip offset with the file size */
2973
                #if !_FS_READONLY
2974
        && !(fp->flag & FA_WRITE)
2975
                #endif
2976
        )
2977
        {
2978
                ofs = fp->fsize;
2979
        }
2980
 
2981
        ifptr = fp->fptr;
2982
        fp->fptr = nsect = 0;
2983
        fp->csect = 255;
2984
        if( ofs > 0 )
2985
        {
2986
                bcs = ( DWORD ) fp->fs->csize * SS( fp->fs );   /* Cluster size (byte) */
2987
                if( ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs )
2988
                {       /* When seek to same or following cluster, */
2989
                        fp->fptr = ( ifptr - 1 ) &~( bcs - 1 ); /* start from the current cluster */
2990
                        ofs -= fp->fptr;
2991
                        clst = fp->curr_clust;
2992
                }
2993
                else
2994
                {       /* When seek to back cluster, */
2995
                        clst = fp->org_clust;   /* start from the first cluster */
2996
                                #if !_FS_READONLY
2997
                        if( clst == 0 )
2998
                        {                                               /* If no cluster chain, create a new chain */
2999
                                clst = create_chain( fp->fs, 0 );
3000
                                if( clst == 1 )
3001
                                {
3002
                                        ABORT( fp->fs, FR_INT_ERR );
3003
                                }
3004
 
3005
                                if( clst == 0xFFFFFFFF )
3006
                                {
3007
                                        ABORT( fp->fs, FR_DISK_ERR );
3008
                                }
3009
 
3010
                                fp->org_clust = clst;
3011
                        }
3012
 
3013
                                #endif
3014
                        fp->curr_clust = clst;
3015
                }
3016
 
3017
                if( clst != 0 )
3018
                {
3019
                        while( ofs > bcs )
3020
                        {                                               /* Cluster following loop */
3021
                                        #if !_FS_READONLY
3022
                                if( fp->flag & FA_WRITE )
3023
                                {                                       /* Check if in write mode or not */
3024
                                        clst = create_chain( fp->fs, clst );    /* Force streached if in write mode */
3025
                                        if( clst == 0 )
3026
                                        {       /* When disk gets full, clip file size */
3027
                                                ofs = bcs;
3028
                                                break;
3029
                                        }
3030
                                }
3031
                                else
3032
                                                #endif
3033
                                        clst = get_fat( fp->fs, clst );         /* Follow cluster chain if not in write mode */
3034
                                if( clst == 0xFFFFFFFF )
3035
                                {
3036
                                        ABORT( fp->fs, FR_DISK_ERR );
3037
                                }
3038
 
3039
                                if( clst <= 1 || clst >= fp->fs->max_clust )
3040
                                {
3041
                                        ABORT( fp->fs, FR_INT_ERR );
3042
                                }
3043
 
3044
                                fp->curr_clust = clst;
3045
                                fp->fptr += bcs;
3046
                                ofs -= bcs;
3047
                        }
3048
 
3049
                        fp->fptr += ofs;
3050
                        fp->csect = ( BYTE ) ( ofs / SS(fp->fs) );      /* Sector offset in the cluster */
3051
                        if( ofs % SS(fp->fs) )
3052
                        {
3053
                                nsect = clust2sect( fp->fs, clst );             /* Current sector */
3054
                                if( !nsect )
3055
                                {
3056
                                        ABORT( fp->fs, FR_INT_ERR );
3057
                                }
3058
 
3059
                                nsect += fp->csect;
3060
                                fp->csect++;
3061
                        }
3062
                }
3063
        }
3064
 
3065
        if( fp->fptr % SS(fp->fs) && nsect != fp->dsect )
3066
        {
3067
                        #if !_FS_TINY
3068
                                #if !_FS_READONLY
3069
                if( fp->flag & FA__DIRTY )
3070
                {       /* Write-back dirty buffer if needed */
3071
                        if( disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK )
3072
                        {
3073
                                ABORT( fp->fs, FR_DISK_ERR );
3074
                        }
3075
 
3076
                        fp->flag &= ~FA__DIRTY;
3077
                }
3078
 
3079
                                #endif
3080
                if( disk_read(fp->fs->drive, fp->buf, nsect, 1) != RES_OK )
3081
                {
3082
                        ABORT( fp->fs, FR_DISK_ERR );
3083
                }
3084
 
3085
                        #endif
3086
                fp->dsect = nsect;
3087
        }
3088
 
3089
                #if !_FS_READONLY
3090
        if( fp->fptr > fp->fsize )
3091
        {               /* Set changed flag if the file size is extended */
3092
                fp->fsize = fp->fptr;
3093
                fp->flag |= FA__WRITTEN;
3094
        }
3095
 
3096
                #endif
3097
        LEAVE_FF( fp->fs, res );
3098
}
3099
 
3100
        #if _FS_MINIMIZE <= 1
3101
 
3102
/*-----------------------------------------------------------------------*/
3103
 
3104
/* Create a Directroy Object                                             */
3105
 
3106
/*-----------------------------------------------------------------------*/
3107
FRESULT f_opendir( DIR *dj, /* Pointer to directory object to create */ const XCHAR *path /* Pointer to the directory path */ )
3108
{
3109
        FRESULT res;
3110
        NAMEBUF( sfn, lfn );
3111
 
3112
        BYTE    *dir;
3113
 
3114
        res = chk_mounted( &path, &dj->fs, 0 );
3115
        if( res == FR_OK )
3116
        {
3117
                INITBUF( (*dj), sfn, lfn );
3118
                res = follow_path( dj, path );  /* Follow the path to the directory */
3119
                if( res == FR_OK )
3120
                {                       /* Follow completed */
3121
                        dir = dj->dir;
3122
                        if( dir )
3123
                        {               /* It is not the root dir */
3124
                                if( dir[DIR_Attr] & AM_DIR )
3125
                                {       /* The object is a directory */
3126
                                        dj->sclust = ( (DWORD) LD_WORD(dir + DIR_FstClusHI) << 16 ) | LD_WORD( dir + DIR_FstClusLO );
3127
                                }
3128
                                else
3129
                                {       /* The object is not a directory */
3130
                                        res = FR_NO_PATH;
3131
                                }
3132
                        }
3133
 
3134
                        if( res == FR_OK )
3135
                        {
3136
                                dj->id = dj->fs->id;
3137
                                res = dir_seek( dj, 0 ); /* Rewind dir */
3138
                        }
3139
                }
3140
 
3141
                if( res == FR_NO_FILE )
3142
                {
3143
                        res = FR_NO_PATH;
3144
                }
3145
        }
3146
 
3147
        LEAVE_FF( dj->fs, res );
3148
}
3149
 
3150
/*-----------------------------------------------------------------------*/
3151
 
3152
/* Read Directory Entry in Sequense                                      */
3153
 
3154
/*-----------------------------------------------------------------------*/
3155
FRESULT f_readdir( DIR *dj, /* Pointer to the open directory object */ FILINFO *fno /* Pointer to file information to return */ )
3156
{
3157
        FRESULT res;
3158
        NAMEBUF( sfn, lfn );
3159
 
3160
        res = validate( dj->fs, dj->id );       /* Check validity of the object */
3161
        if( res == FR_OK )
3162
        {
3163
                INITBUF( (*dj), sfn, lfn );
3164
                if( !fno )
3165
                {
3166
                        res = dir_seek( dj, 0 );
3167
                }
3168
                else
3169
                {
3170
                        res = dir_read( dj );
3171
                        if( res == FR_NO_FILE )
3172
                        {
3173
                                dj->sect = 0;
3174
                                res = FR_OK;
3175
                        }
3176
 
3177
                        if( res == FR_OK )
3178
                        {       /* A valid entry is found */
3179
                                get_fileinfo( dj, fno );                /* Get the object information */
3180
                                res = dir_next( dj, FALSE );    /* Increment index for next */
3181
                                if( res == FR_NO_FILE )
3182
                                {
3183
                                        dj->sect = 0;
3184
                                        res = FR_OK;
3185
                                }
3186
                        }
3187
                }
3188
        }
3189
 
3190
        LEAVE_FF( dj->fs, res );
3191
}
3192
 
3193
                #if _FS_MINIMIZE == 0
3194
 
3195
/*-----------------------------------------------------------------------*/
3196
 
3197
/* Get File Status                                                       */
3198
 
3199
/*-----------------------------------------------------------------------*/
3200
FRESULT f_stat( const XCHAR *path, /* Pointer to the file path */ FILINFO *fno /* Pointer to file information to return */ )
3201
{
3202
        FRESULT res;
3203
        DIR             dj;
3204
        NAMEBUF( sfn, lfn );
3205
 
3206
        res = chk_mounted( &path, &dj.fs, 0 );
3207
        if( res == FR_OK )
3208
        {
3209
                INITBUF( dj, sfn, lfn );
3210
                res = follow_path( &dj, path ); /* Follow the file path */
3211
                if( res == FR_OK )
3212
                {               /* Follwo completed */
3213
                        if( dj.dir )
3214
                        {       /* Found an object */
3215
                                get_fileinfo( &dj, fno );
3216
                        }
3217
                        else
3218
                        {       /* It is root dir */
3219
                                res = FR_INVALID_NAME;
3220
                        }
3221
                }
3222
        }
3223
 
3224
        LEAVE_FF( dj.fs, res );
3225
}
3226
 
3227
                        #if !_FS_READONLY
3228
 
3229
/*-----------------------------------------------------------------------*/
3230
 
3231
/* Get Number of Free Clusters                                           */
3232
 
3233
/*-----------------------------------------------------------------------*/
3234
FRESULT f_getfree
3235
                (
3236
                        const XCHAR *path,      /* Pointer to the logical drive number (root dir) */
3237
                        DWORD           *nclst, /* Pointer to the variable to return number of free clusters */
3238
                        FATFS           **fatfs /* Pointer to pointer to corresponding file system object to return */
3239
                )
3240
{
3241
        FRESULT res;
3242
        DWORD   n, clst, sect, stat;
3243
        UINT    i;
3244
        BYTE    fat, *p;
3245
 
3246
        /* Get drive number */
3247
        res = chk_mounted( &path, fatfs, 0 );
3248
        if( res != FR_OK )
3249
        {
3250
                LEAVE_FF( *fatfs, res );
3251
        }
3252
 
3253
        /* If number of free cluster is valid, return it without cluster scan. */
3254
        if( (*fatfs)->free_clust <= (*fatfs)->max_clust - 2 )
3255
        {
3256
                *nclst = ( *fatfs )->free_clust;
3257
                LEAVE_FF( *fatfs, FR_OK );
3258
        }
3259
 
3260
        /* Get number of free clusters */
3261
        fat = ( *fatfs )->fs_type;
3262
        n = 0;
3263
        if( fat == FS_FAT12 )
3264
        {
3265
                clst = 2;
3266
                do
3267
                {
3268
                        stat = get_fat( *fatfs, clst );
3269
                        if( stat == 0xFFFFFFFF )
3270
                        {
3271
                                LEAVE_FF( *fatfs, FR_DISK_ERR );
3272
                        }
3273
 
3274
                        if( stat == 1 )
3275
                        {
3276
                                LEAVE_FF( *fatfs, FR_INT_ERR );
3277
                        }
3278
 
3279
                        if( stat == 0 )
3280
                        {
3281
                                n++;
3282
                        }
3283
                } while( ++clst < (*fatfs)->max_clust );
3284
        }
3285
        else
3286
        {
3287
                clst = ( *fatfs )->max_clust;
3288
                sect = ( *fatfs )->fatbase;
3289
                i = 0;
3290
                p = 0;
3291
                do
3292
                {
3293
                        if( !i )
3294
                        {
3295
                                res = move_window( *fatfs, sect++ );
3296
                                if( res != FR_OK )
3297
                                {
3298
                                        LEAVE_FF( *fatfs, res );
3299
                                }
3300
 
3301
                                p = ( *fatfs )->win;
3302
                                i = SS( *fatfs );
3303
                        }
3304
 
3305
                        if( fat == FS_FAT16 )
3306
                        {
3307
                                if( LD_WORD(p) == 0 )
3308
                                {
3309
                                        n++;
3310
                                }
3311
 
3312
                                p += 2;
3313
                                i -= 2;
3314
                        }
3315
                        else
3316
                        {
3317
                                if( (LD_DWORD(p) & 0x0FFFFFFF) == 0 )
3318
                                {
3319
                                        n++;
3320
                                }
3321
 
3322
                                p += 4;
3323
                                i -= 4;
3324
                        }
3325
                } while( --clst );
3326
        }
3327
 
3328
        ( *fatfs )->free_clust = n;
3329
        if( fat == FS_FAT32 )
3330
        {
3331
                ( *fatfs )->fsi_flag = 1;
3332
        }
3333
 
3334
        *nclst = n;
3335
 
3336
        LEAVE_FF( *fatfs, FR_OK );
3337
}
3338
 
3339
/*-----------------------------------------------------------------------*/
3340
 
3341
/* Truncate File                                                         */
3342
 
3343
/*-----------------------------------------------------------------------*/
3344
FRESULT f_truncate( FIL *fp /* Pointer to the file object */ )
3345
{
3346
        FRESULT res;
3347
        DWORD   ncl;
3348
 
3349
        res = validate( fp->fs, fp->id );       /* Check validity of the object */
3350
        if( res != FR_OK )
3351
        {
3352
                LEAVE_FF( fp->fs, res );
3353
        }
3354
 
3355
        if( fp->flag & FA__ERROR )
3356
        {       /* Check abort flag */
3357
                LEAVE_FF( fp->fs, FR_INT_ERR );
3358
        }
3359
 
3360
        if( !(fp->flag & FA_WRITE) )
3361
        {       /* Check access mode */
3362
                LEAVE_FF( fp->fs, FR_DENIED );
3363
        }
3364
 
3365
        if( fp->fsize > fp->fptr )
3366
        {
3367
                fp->fsize = fp->fptr;   /* Set file size to current R/W point */
3368
                fp->flag |= FA__WRITTEN;
3369
                if( fp->fptr == 0 )
3370
                {                                               /* When set file size to zero, remove entire cluster chain */
3371
                        res = remove_chain( fp->fs, fp->org_clust );
3372
                        fp->org_clust = 0;
3373
                }
3374
                else
3375
                {                                               /* When truncate a part of the file, remove remaining clusters */
3376
                        ncl = get_fat( fp->fs, fp->curr_clust );
3377
                        res = FR_OK;
3378
                        if( ncl == 0xFFFFFFFF )
3379
                        {
3380
                                res = FR_DISK_ERR;
3381
                        }
3382
 
3383
                        if( ncl == 1 )
3384
                        {
3385
                                res = FR_INT_ERR;
3386
                        }
3387
 
3388
                        if( res == FR_OK && ncl < fp->fs->max_clust )
3389
                        {
3390
                                res = put_fat( fp->fs, fp->curr_clust, 0x0FFFFFFF );
3391
                                if( res == FR_OK )
3392
                                {
3393
                                        res = remove_chain( fp->fs, ncl );
3394
                                }
3395
                        }
3396
                }
3397
        }
3398
 
3399
        if( res != FR_OK )
3400
        {
3401
                fp->flag |= FA__ERROR;
3402
        }
3403
 
3404
        LEAVE_FF( fp->fs, res );
3405
}
3406
 
3407
/*-----------------------------------------------------------------------*/
3408
 
3409
/* Delete a File or Directory                                            */
3410
 
3411
/*-----------------------------------------------------------------------*/
3412
FRESULT f_unlink( const XCHAR *path /* Pointer to the file or directory path */ )
3413
{
3414
        FRESULT res;
3415
        DIR             dj, sdj;
3416
        NAMEBUF( sfn, lfn );
3417
 
3418
        BYTE    *dir;
3419
        DWORD   dclst;
3420
 
3421
        res = chk_mounted( &path, &dj.fs, 1 );
3422
        if( res != FR_OK )
3423
        {
3424
                LEAVE_FF( dj.fs, res );
3425
        }
3426
 
3427
        INITBUF( dj, sfn, lfn );
3428
        res = follow_path( &dj, path ); /* Follow the file path */
3429
        if( _FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT) )
3430
        {
3431
                res = FR_INVALID_NAME;
3432
        }
3433
 
3434
        if( res != FR_OK )
3435
        {
3436
                LEAVE_FF( dj.fs, res );         /* Follow failed */
3437
        }
3438
 
3439
        dir = dj.dir;
3440
        if( !dir )
3441
        {       /* Is it the root directory? */
3442
                LEAVE_FF( dj.fs, FR_INVALID_NAME );
3443
        }
3444
 
3445
        if( dir[DIR_Attr] & AM_RDO )
3446
        {       /* Is it a R/O object? */
3447
                LEAVE_FF( dj.fs, FR_DENIED );
3448
        }
3449
 
3450
        dclst = ( (DWORD) LD_WORD(dir + DIR_FstClusHI) << 16 ) | LD_WORD( dir + DIR_FstClusLO );
3451
 
3452
        if( dir[DIR_Attr] & AM_DIR )
3453
        {       /* It is a sub-directory */
3454
                if( dclst < 2 )
3455
                {
3456
                        LEAVE_FF( dj.fs, FR_INT_ERR );
3457
                }
3458
 
3459
                mem_cpy( &sdj, &dj, sizeof(DIR) );              /* Check if the sub-dir is empty or not */
3460
                sdj.sclust = dclst;
3461
                res = dir_seek( &sdj, 2 );
3462
                if( res != FR_OK )
3463
                {
3464
                        LEAVE_FF( dj.fs, res );
3465
                }
3466
 
3467
                res = dir_read( &sdj );
3468
                if( res == FR_OK )
3469
                {
3470
                        res = FR_DENIED;                                        /* Not empty sub-dir */
3471
                }
3472
 
3473
                if( res != FR_NO_FILE )
3474
                {
3475
                        LEAVE_FF( dj.fs, res );
3476
                }
3477
        }
3478
 
3479
        res = dir_remove( &dj );                                        /* Remove directory entry */
3480
        if( res == FR_OK )
3481
        {
3482
                if( dclst )
3483
                {
3484
                        res = remove_chain( dj.fs, dclst ); /* Remove the cluster chain */
3485
                }
3486
 
3487
                if( res == FR_OK )
3488
                {
3489
                        res = sync( dj.fs );
3490
                }
3491
        }
3492
 
3493
        LEAVE_FF( dj.fs, res );
3494
}
3495
 
3496
/*-----------------------------------------------------------------------*/
3497
 
3498
/* Create a Directory                                                    */
3499
 
3500
/*-----------------------------------------------------------------------*/
3501
FRESULT f_mkdir( const XCHAR *path /* Pointer to the directory path */ )
3502
{
3503
        FRESULT res;
3504
        DIR             dj;
3505
        NAMEBUF( sfn, lfn );
3506
 
3507
        BYTE    *dir, n;
3508
        DWORD   dsect, dclst, pclst, tim;
3509
 
3510
        res = chk_mounted( &path, &dj.fs, 1 );
3511
        if( res != FR_OK )
3512
        {
3513
                LEAVE_FF( dj.fs, res );
3514
        }
3515
 
3516
        INITBUF( dj, sfn, lfn );
3517
        res = follow_path( &dj, path ); /* Follow the file path */
3518
        if( res == FR_OK )
3519
        {
3520
                res = FR_EXIST;                         /* Any file or directory is already existing */
3521
        }
3522
 
3523
        if( _FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT) )
3524
        {
3525
                res = FR_INVALID_NAME;
3526
        }
3527
 
3528
        if( res != FR_NO_FILE )
3529
        {       /* Any error occured */
3530
                LEAVE_FF( dj.fs, res );
3531
        }
3532
 
3533
        dclst = create_chain( dj.fs, 0 );                /* Allocate a new cluster for new directory table */
3534
        res = FR_OK;
3535
        if( dclst == 0 )
3536
        {
3537
                res = FR_DENIED;
3538
        }
3539
 
3540
        if( dclst == 1 )
3541
        {
3542
                res = FR_INT_ERR;
3543
        }
3544
 
3545
        if( dclst == 0xFFFFFFFF )
3546
        {
3547
                res = FR_DISK_ERR;
3548
        }
3549
 
3550
        if( res == FR_OK )
3551
        {
3552
                res = move_window( dj.fs, 0 );
3553
        }
3554
 
3555
        if( res != FR_OK )
3556
        {
3557
                LEAVE_FF( dj.fs, res );
3558
        }
3559
 
3560
        dsect = clust2sect( dj.fs, dclst );
3561
 
3562
        dir = dj.fs->win;                                               /* Initialize the new directory table */
3563
        mem_set( dir, 0, SS(dj.fs) );
3564
        mem_set( dir + DIR_Name, ' ', 8 + 3 );  /* Create "." entry */
3565
        dir[DIR_Name] = '.';
3566
        dir[DIR_Attr] = AM_DIR;
3567
        tim = get_fattime();
3568
        ST_DWORD( dir + DIR_WrtTime, tim );
3569
        ST_WORD( dir + DIR_FstClusLO, dclst );
3570
        ST_WORD( dir + DIR_FstClusHI, dclst >> 16 );
3571
        mem_cpy( dir + 32, dir, 32 );                   /* Create ".." entry */
3572
        dir[33] = '.';
3573
        pclst = dj.sclust;
3574
        if( dj.fs->fs_type == FS_FAT32 && pclst == dj.fs->dirbase )
3575
        {
3576
                pclst = 0;
3577
        }
3578
 
3579
        ST_WORD( dir + 32 + DIR_FstClusLO, pclst );
3580
        ST_WORD( dir + 32 + DIR_FstClusHI, pclst >> 16 );
3581
        for( n = 0; n < dj.fs->csize; n++ )
3582
        {       /* Write dot entries and clear left sectors */
3583
                dj.fs->winsect = dsect++;
3584
                dj.fs->wflag = 1;
3585
                res = move_window( dj.fs, 0 );
3586
                if( res )
3587
                {
3588
                        LEAVE_FF( dj.fs, res );
3589
                }
3590
 
3591
                mem_set( dir, 0, SS(dj.fs) );
3592
        }
3593
 
3594
        res = dir_register( &dj );
3595
        if( res != FR_OK )
3596
        {
3597
                remove_chain( dj.fs, dclst );
3598
        }
3599
        else
3600
        {
3601
                dir = dj.dir;
3602
                dir[DIR_Attr] = AM_DIR;                                 /* Attribute */
3603
                ST_DWORD( dir + DIR_WrtTime, tim );             /* Crated time */
3604
                ST_WORD( dir + DIR_FstClusLO, dclst );  /* Table start cluster */
3605
                ST_WORD( dir + DIR_FstClusHI, dclst >> 16 );
3606
                dj.fs->wflag = 1;
3607
                res = sync( dj.fs );
3608
        }
3609
 
3610
        LEAVE_FF( dj.fs, res );
3611
}
3612
 
3613
/*-----------------------------------------------------------------------*/
3614
 
3615
/* Change File Attribute                                                 */
3616
 
3617
/*-----------------------------------------------------------------------*/
3618
FRESULT f_chmod( const XCHAR *path, /* Pointer to the file path */ BYTE value, /* Attribute bits */ BYTE mask /* Attribute mask to change */ )
3619
{
3620
        FRESULT res;
3621
        DIR             dj;
3622
        NAMEBUF( sfn, lfn );
3623
 
3624
        BYTE    *dir;
3625
 
3626
        res = chk_mounted( &path, &dj.fs, 1 );
3627
        if( res == FR_OK )
3628
        {
3629
                INITBUF( dj, sfn, lfn );
3630
                res = follow_path( &dj, path ); /* Follow the file path */
3631
                if( _FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT) )
3632
                {
3633
                        res = FR_INVALID_NAME;
3634
                }
3635
 
3636
                if( res == FR_OK )
3637
                {
3638
                        dir = dj.dir;
3639
                        if( !dir )
3640
                        {       /* Is it a root directory? */
3641
                                res = FR_INVALID_NAME;
3642
                        }
3643
                        else
3644
                        {       /* File or sub directory */
3645
                                mask &= AM_RDO | AM_HID | AM_SYS | AM_ARC;      /* Valid attribute mask */
3646
                                dir[DIR_Attr] = ( value & mask ) | ( dir[DIR_Attr] & (BYTE)~mask ); /* Apply attribute change */
3647
                                dj.fs->wflag = 1;
3648
                                res = sync( dj.fs );
3649
                        }
3650
                }
3651
        }
3652
 
3653
        LEAVE_FF( dj.fs, res );
3654
}
3655
 
3656
/*-----------------------------------------------------------------------*/
3657
 
3658
/* Change Timestamp                                                      */
3659
 
3660
/*-----------------------------------------------------------------------*/
3661
FRESULT f_utime( const XCHAR *path, /* Pointer to the file/directory name */ const FILINFO *fno /* Pointer to the timestamp to be set */ )
3662
{
3663
        FRESULT res;
3664
        DIR             dj;
3665
        NAMEBUF( sfn, lfn );
3666
 
3667
        BYTE    *dir;
3668
 
3669
        res = chk_mounted( &path, &dj.fs, 1 );
3670
        if( res == FR_OK )
3671
        {
3672
                INITBUF( dj, sfn, lfn );
3673
                res = follow_path( &dj, path ); /* Follow the file path */
3674
                if( _FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT) )
3675
                {
3676
                        res = FR_INVALID_NAME;
3677
                }
3678
 
3679
                if( res == FR_OK )
3680
                {
3681
                        dir = dj.dir;
3682
                        if( !dir )
3683
                        {       /* Root directory */
3684
                                res = FR_INVALID_NAME;
3685
                        }
3686
                        else
3687
                        {       /* File or sub-directory */
3688
                                ST_WORD( dir + DIR_WrtTime, fno->ftime );
3689
                                ST_WORD( dir + DIR_WrtDate, fno->fdate );
3690
                                dj.fs->wflag = 1;
3691
                                res = sync( dj.fs );
3692
                        }
3693
                }
3694
        }
3695
 
3696
        LEAVE_FF( dj.fs, res );
3697
}
3698
 
3699
/*-----------------------------------------------------------------------*/
3700
 
3701
/* Rename File/Directory                                                 */
3702
 
3703
/*-----------------------------------------------------------------------*/
3704
FRESULT f_rename( const XCHAR *path_old, /* Pointer to the old name */ const XCHAR *path_new /* Pointer to the new name */ )
3705
{
3706
        FRESULT res;
3707
        DIR             dj_old, dj_new;
3708
        NAMEBUF( sfn, lfn );
3709
 
3710
        BYTE    buf[21], *dir;
3711
        DWORD   dw;
3712
 
3713
        INITBUF( dj_old, sfn, lfn );
3714
        res = chk_mounted( &path_old, &dj_old.fs, 1 );
3715
        if( res == FR_OK )
3716
        {
3717
                dj_new.fs = dj_old.fs;
3718
                res = follow_path( &dj_old, path_old ); /* Check old object */
3719
                if( _FS_RPATH && res == FR_OK && (dj_old.fn[NS] & NS_DOT) )
3720
                {
3721
                        res = FR_INVALID_NAME;
3722
                }
3723
        }
3724
 
3725
        if( res != FR_OK )
3726
        {
3727
                LEAVE_FF( dj_old.fs, res );                             /* The old object is not found */
3728
        }
3729
 
3730
        if( !dj_old.dir )
3731
        {
3732
                LEAVE_FF( dj_old.fs, FR_NO_FILE );              /* Is root dir? */
3733
        }
3734
 
3735
        mem_cpy( buf, dj_old.dir + DIR_Attr, 21 );      /* Save the object information */
3736
 
3737
        mem_cpy( &dj_new, &dj_old, sizeof(DIR) );
3738
        res = follow_path( &dj_new, path_new );         /* Check new object */
3739
        if( res == FR_OK )
3740
        {
3741
                res = FR_EXIST;                                 /* The new object name is already existing */
3742
        }
3743
 
3744
        if( res == FR_NO_FILE )
3745
        {                                                                       /* Is it a valid path and no name collision? */
3746
                res = dir_register( &dj_new );  /* Register the new object */
3747
                if( res == FR_OK )
3748
                {
3749
                        dir = dj_new.dir;                       /* Copy object information into new entry */
3750
                        mem_cpy( dir + 13, buf + 2, 19 );
3751
                        dir[DIR_Attr] = buf[0] | AM_ARC;
3752
                        dj_old.fs->wflag = 1;
3753
                        if( dir[DIR_Attr] & AM_DIR )
3754
                        {       /* Update .. entry in the directory if needed */
3755
                                dw = clust2sect( dj_new.fs, (DWORD) LD_WORD(dir + DIR_FstClusHI) | LD_WORD(dir + DIR_FstClusLO) );
3756
                                if( !dw )
3757
                                {
3758
                                        res = FR_INT_ERR;
3759
                                }
3760
                                else
3761
                                {
3762
                                        res = move_window( dj_new.fs, dw );
3763
                                        dir = dj_new.fs->win + 32;
3764
                                        if( res == FR_OK && dir[1] == '.' )
3765
                                        {
3766
                                                dw = ( dj_new.fs->fs_type == FS_FAT32 && dj_new.sclust == dj_new.fs->dirbase ) ? 0 : dj_new.sclust;
3767
                                                ST_WORD( dir + DIR_FstClusLO, dw );
3768
                                                ST_WORD( dir + DIR_FstClusHI, dw >> 16 );
3769
                                                dj_new.fs->wflag = 1;
3770
                                        }
3771
                                }
3772
                        }
3773
 
3774
                        if( res == FR_OK )
3775
                        {
3776
                                res = dir_remove( &dj_old );    /* Remove old entry */
3777
                                if( res == FR_OK )
3778
                                {
3779
                                        res = sync( dj_old.fs );
3780
                                }
3781
                        }
3782
                }
3783
        }
3784
 
3785
        LEAVE_FF( dj_old.fs, res );
3786
}
3787
 
3788
                        #endif /* !_FS_READONLY */
3789
                #endif /* _FS_MINIMIZE == 0 */
3790
        #endif /* _FS_MINIMIZE <= 1 */
3791
#endif /* _FS_MINIMIZE <= 2 */
3792
 
3793
/*-----------------------------------------------------------------------*/
3794
 
3795
/* Forward data to the stream directly (Available on only _FS_TINY cfg)  */
3796
 
3797
/*-----------------------------------------------------------------------*/
3798
#if _USE_FORWARD && _FS_TINY
3799
FRESULT f_forward
3800
                (
3801
                        FIL *fp,        /* Pointer to the file object */
3802
                        UINT (*func) ( const BYTE *, UINT ),    /* Pointer to the streaming function */
3803
                        UINT btr,       /* Number of bytes to forward */
3804
                        UINT *bf        /* Pointer to number of bytes forwarded */
3805
                )
3806
{
3807
        FRESULT res;
3808
        DWORD   remain, clst, sect;
3809
        UINT    rcnt;
3810
 
3811
        *bf = 0;
3812
 
3813
        res = validate( fp->fs, fp->id );       /* Check validity of the object */
3814
        if( res != FR_OK )
3815
        {
3816
                LEAVE_FF( fp->fs, res );
3817
        }
3818
 
3819
        if( fp->flag & FA__ERROR )
3820
        {       /* Check error flag */
3821
                LEAVE_FF( fp->fs, FR_INT_ERR );
3822
        }
3823
 
3824
        if( !(fp->flag & FA_READ) )
3825
        {       /* Check access mode */
3826
                LEAVE_FF( fp->fs, FR_DENIED );
3827
        }
3828
 
3829
        remain = fp->fsize - fp->fptr;
3830
        if( btr > remain )
3831
        {
3832
                btr = ( UINT ) remain;          /* Truncate btr by remaining bytes */
3833
        }
3834
 
3835
        for
3836
        (
3837
                ;
3838
                btr && (*func) (NULL, 0);        /* Repeat until all data transferred or stream becomes busy */
3839
                fp->fptr += rcnt, *bf += rcnt, btr -= rcnt
3840
        )
3841
        {
3842
                if( (fp->fptr % SS(fp->fs)) == 0 )
3843
                {               /* On the sector boundary? */
3844
                        if( fp->csect >= fp->fs->csize )
3845
                        {       /* On the cluster boundary? */
3846
                                clst = ( fp->fptr == 0 ) ?                               /* On the top of the file? */
3847
                                fp->org_clust : get_fat( fp->fs, fp->curr_clust );
3848
                                if( clst <= 1 )
3849
                                {
3850
                                        ABORT( fp->fs, FR_INT_ERR );
3851
                                }
3852
 
3853
                                if( clst == 0xFFFFFFFF )
3854
                                {
3855
                                        ABORT( fp->fs, FR_DISK_ERR );
3856
                                }
3857
 
3858
                                fp->curr_clust = clst;                                  /* Update current cluster */
3859
                                fp->csect = 0;                                                   /* Reset sector address in the cluster */
3860
                        }
3861
 
3862
                        fp->csect++;                                                            /* Next sector address in the cluster */
3863
                }
3864
 
3865
                sect = clust2sect( fp->fs, fp->curr_clust );    /* Get current data sector */
3866
                if( !sect )
3867
                {
3868
                        ABORT( fp->fs, FR_INT_ERR );
3869
                }
3870
 
3871
                sect += fp->csect - 1;
3872
                if( move_window(fp->fs, sect) )
3873
                {       /* Move sector window */
3874
                        ABORT( fp->fs, FR_DISK_ERR );
3875
                }
3876
 
3877
                fp->dsect = sect;
3878
                rcnt = SS( fp->fs ) - ( WORD ) ( fp->fptr % SS(fp->fs) );       /* Forward data from sector window */
3879
                if( rcnt > btr )
3880
                {
3881
                        rcnt = btr;
3882
                }
3883
 
3884
                rcnt = ( *func ) ( &fp->fs->win[(WORD) fp->fptr % SS(fp->fs)], rcnt );
3885
                if( !rcnt )
3886
                {
3887
                        ABORT( fp->fs, FR_INT_ERR );
3888
                }
3889
        }
3890
 
3891
        LEAVE_FF( fp->fs, FR_OK );
3892
}
3893
 
3894
#endif /* _USE_FORWARD */
3895
 
3896
#if _USE_MKFS && !_FS_READONLY
3897
 
3898
/*-----------------------------------------------------------------------*/
3899
 
3900
/* Create File System on the Drive                                       */
3901
 
3902
/*-----------------------------------------------------------------------*/
3903
        #define N_ROOTDIR       512                     /* Multiple of 32 and <= 2048 */
3904
        #define N_FATS          1                       /* 1 or 2 */
3905
        #define MAX_SECTOR      131072000UL /* Maximum partition size */
3906
        #define MIN_SECTOR      2000UL          /* Minimum partition size */
3907
 
3908
FRESULT f_mkfs
3909
                (
3910
                        BYTE    drv,            /* Logical drive number */
3911
                        BYTE    partition,      /* Partitioning rule 0:FDISK, 1:SFD */
3912
                        WORD    allocsize       /* Allocation unit size [bytes] */
3913
                )
3914
{
3915
        static const DWORD      sstbl[] = { 2048000, 1024000, 512000, 256000, 128000, 64000, 32000, 16000, 8000, 4000, 0 };
3916
        static const WORD       cstbl[] = { 32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512 };
3917
        BYTE                            fmt, m, *tbl;
3918
        DWORD                           b_part, b_fat, b_dir, b_data;   /* Area offset (LBA) */
3919
        DWORD                           n_part, n_rsv, n_fat, n_dir;    /* Area size */
3920
        DWORD                           n_clst, d, n;
3921
        WORD                            as;
3922
        FATFS                           *fs;
3923
        DSTATUS                         stat;
3924
 
3925
        /* Check validity of the parameters */
3926
        if( drv >= _DRIVES )
3927
        {
3928
                return FR_INVALID_DRIVE;
3929
        }
3930
 
3931
        if( partition >= 2 )
3932
        {
3933
                return FR_MKFS_ABORTED;
3934
        }
3935
 
3936
        /* Check mounted drive and clear work area */
3937
        fs = FatFs[drv];
3938
        if( !fs )
3939
        {
3940
                return FR_NOT_ENABLED;
3941
        }
3942
 
3943
        fs->fs_type = 0;
3944
        drv = LD2PD( drv );
3945
 
3946
        /* Get disk statics */
3947
        stat = disk_initialize( drv );
3948
        if( stat & STA_NOINIT )
3949
        {
3950
                return FR_NOT_READY;
3951
        }
3952
 
3953
        if( stat & STA_PROTECT )
3954
        {
3955
                return FR_WRITE_PROTECTED;
3956
        }
3957
 
3958
                #if _MAX_SS != 512                              /* Get disk sector size */
3959
        if( disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS )
3960
        {
3961
                return FR_MKFS_ABORTED;
3962
        }
3963
 
3964
                #endif
3965
        if( disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR )
3966
        {
3967
                return FR_MKFS_ABORTED;
3968
        }
3969
 
3970
        if( n_part > MAX_SECTOR )
3971
        {
3972
                n_part = MAX_SECTOR;
3973
        }
3974
 
3975
        b_part = ( !partition ) ? 63 : 0;        /* Boot sector */
3976
        n_part -= b_part;
3977
        for( d = 512; d <= 32768U && d != allocsize; d <<= 1 );
3978
 
3979
        /* Check validity of the allocation unit size */
3980
        if( d != allocsize )
3981
        {
3982
                allocsize = 0;
3983
        }
3984
 
3985
        if( !allocsize )
3986
        {                                               /* Auto selection of cluster size */
3987
                d = n_part;
3988
                for( as = SS(fs); as > 512U; as >>= 1 )
3989
                {
3990
                        d >>= 1;
3991
                }
3992
 
3993
                for( n = 0; d < sstbl[n]; n++ );
3994
                allocsize = cstbl[n];
3995
        }
3996
 
3997
        if( allocsize < SS(fs) )
3998
        {
3999
                allocsize = SS( fs );
4000
        }
4001
 
4002
        allocsize /= SS( fs );  /* Number of sectors per cluster */
4003
 
4004
        /* Pre-compute number of clusters and FAT type */
4005
        n_clst = n_part / allocsize;
4006
        fmt = FS_FAT12;
4007
        if( n_clst >= 0xFF5 )
4008
        {
4009
                fmt = FS_FAT16;
4010
        }
4011
 
4012
        if( n_clst >= 0xFFF5 )
4013
        {
4014
                fmt = FS_FAT32;
4015
        }
4016
 
4017
        /* Determine offset and size of FAT structure */
4018
        switch( fmt )
4019
        {
4020
                case FS_FAT12:
4021
                        n_fat = ( (n_clst * 3 + 1) / 2 + 3 + SS(fs) - 1 ) / SS( fs );
4022
                        n_rsv = 1 + partition;
4023
                        n_dir = N_ROOTDIR * 32 / SS( fs );
4024
                        break;
4025
 
4026
                case FS_FAT16:
4027
                        n_fat = ( (n_clst * 2) + 4 + SS(fs) - 1 ) / SS( fs );
4028
                        n_rsv = 1 + partition;
4029
                        n_dir = N_ROOTDIR * 32 / SS( fs );
4030
                        break;
4031
 
4032
                default:
4033
                        n_fat = ( (n_clst * 4) + 8 + SS(fs) - 1 ) / SS( fs );
4034
                        n_rsv = 33 - partition;
4035
                        n_dir = 0;
4036
        }
4037
 
4038
        b_fat = b_part + n_rsv; /* FATs start sector */
4039
        b_dir = b_fat + n_fat * N_FATS;         /* Directory start sector */
4040
        b_data = b_dir + n_dir;                         /* Data start sector */
4041
 
4042
        /* Align data start sector to erase block boundary (for flash memory media) */
4043
        if( disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK )
4044
        {
4045
                return FR_MKFS_ABORTED;
4046
        }
4047
 
4048
        n = ( b_data + n - 1 ) &~( n - 1 );
4049
        n_fat += ( n - b_data ) / N_FATS;
4050
 
4051
        /* b_dir and b_data are no longer used below */
4052
 
4053
        /* Determine number of cluster and final check of validity of the FAT type */
4054
        n_clst = ( n_part - n_rsv - n_fat * N_FATS - n_dir ) / allocsize;
4055
        if( (fmt == FS_FAT16 && n_clst < 0xFF5) || (fmt == FS_FAT32 && n_clst < 0xFFF5) )
4056
        {
4057
                return FR_MKFS_ABORTED;
4058
        }
4059
 
4060
        /* Create partition table if needed */
4061
        if( !partition )
4062
        {
4063
                DWORD   n_disk = b_part + n_part;
4064
 
4065
                mem_set( fs->win, 0, SS(fs) );
4066
                tbl = fs->win + MBR_Table;
4067
                ST_DWORD( tbl, 0x00010180 );    /* Partition start in CHS */
4068
                if( n_disk < 63UL * 255 * 1024 )
4069
                {       /* Partition end in CHS */
4070
                        n_disk = n_disk / 63 / 255;
4071
                        tbl[7] = ( BYTE ) n_disk;
4072
                        tbl[6] = ( BYTE ) ( (n_disk >> 2) | 63 );
4073
                }
4074
                else
4075
                {
4076
                        ST_WORD( &tbl[6], 0xFFFF );
4077
                }
4078
 
4079
                tbl[5] = 254;
4080
                if( fmt != FS_FAT32 )
4081
                {       /* System ID */
4082
                        tbl[4] = ( n_part < 0x10000 ) ? 0x04 : 0x06;
4083
                }
4084
                else
4085
                {
4086
                        tbl[4] = 0x0c;
4087
                }
4088
 
4089
                ST_DWORD( tbl + 8, 63 );                                                        /* Partition start in LBA */
4090
                ST_DWORD( tbl + 12, n_part );                                           /* Partition size in LBA */
4091
                ST_WORD( tbl + 64, 0xAA55 );                                            /* Signature */
4092
                if( disk_write(drv, fs->win, 0, 1) != RES_OK )
4093
                {
4094
                        return FR_DISK_ERR;
4095
                }
4096
 
4097
                partition = 0xF8;
4098
        }
4099
        else
4100
        {
4101
                partition = 0xF0;
4102
        }
4103
 
4104
        /* Create boot record */
4105
        tbl = fs->win;                                                                                  /* Clear buffer */
4106
        mem_set( tbl, 0, SS(fs) );
4107
        ST_DWORD( tbl + BS_jmpBoot, 0x90FEEB );                                 /* Boot code (jmp $, nop) */
4108
        ST_WORD( tbl + BPB_BytsPerSec, SS(fs) );                                /* Sector size */
4109
        tbl[BPB_SecPerClus] = ( BYTE ) allocsize;                               /* Sectors per cluster */
4110
        ST_WORD( tbl + BPB_RsvdSecCnt, n_rsv );                                 /* Reserved sectors */
4111
        tbl[BPB_NumFATs] = N_FATS;                                                              /* Number of FATs */
4112
        ST_WORD( tbl + BPB_RootEntCnt, SS(fs) / 32 * n_dir );   /* Number of rootdir entries */
4113
        if( n_part < 0x10000 )
4114
        {       /* Number of total sectors */
4115
                ST_WORD( tbl + BPB_TotSec16, n_part );
4116
        }
4117
        else
4118
        {
4119
                ST_DWORD( tbl + BPB_TotSec32, n_part );
4120
        }
4121
 
4122
        tbl[BPB_Media] = partition;                                                                     /* Media descripter */
4123
        ST_WORD( tbl + BPB_SecPerTrk, 63 );                                                     /* Number of sectors per track */
4124
        ST_WORD( tbl + BPB_NumHeads, 255 );                                                     /* Number of heads */
4125
        ST_DWORD( tbl + BPB_HiddSec, b_part );                                          /* Hidden sectors */
4126
        n = get_fattime();                                                                                      /* Use current time as a VSN */
4127
        if( fmt != FS_FAT32 )
4128
        {
4129
                ST_DWORD( tbl + BS_VolID, n );                                                  /* Volume serial number */
4130
                ST_WORD( tbl + BPB_FATSz16, n_fat );                                    /* Number of secters per FAT */
4131
                tbl[BS_DrvNum] = 0x80;                                                                  /* Drive number */
4132
                tbl[BS_BootSig] = 0x29;                                                                 /* Extended boot signature */
4133
                mem_cpy( tbl + BS_VolLab, "NO NAME    FAT     ", 19 );  /* Volume lavel, FAT signature */
4134
        }
4135
        else
4136
        {
4137
                ST_DWORD( tbl + BS_VolID32, n );                                                /* Volume serial number */
4138
                ST_DWORD( tbl + BPB_FATSz32, n_fat );                                   /* Number of secters per FAT */
4139
                ST_DWORD( tbl + BPB_RootClus, 2 );                                              /* Root directory cluster (2) */
4140
                ST_WORD( tbl + BPB_FSInfo, 1 );         /* FSInfo record offset (bs+1) */
4141
                ST_WORD( tbl + BPB_BkBootSec, 6 );      /* Backup boot record offset (bs+6) */
4142
                tbl[BS_DrvNum32] = 0x80;                        /* Drive number */
4143
                tbl[BS_BootSig32] = 0x29;                       /* Extended boot signature */
4144
                mem_cpy( tbl + BS_VolLab32, "NO NAME    FAT32   ", 19 );        /* Volume lavel, FAT signature */
4145
        }
4146
 
4147
        ST_WORD( tbl + BS_55AA, 0xAA55 );                       /* Signature */
4148
        if( SS(fs) > 512U )
4149
        {
4150
                ST_WORD( tbl + SS(fs) - 2, 0xAA55 );
4151
        }
4152
 
4153
        if( disk_write(drv, tbl, b_part + 0, 1) != RES_OK )
4154
        {
4155
                return FR_DISK_ERR;
4156
        }
4157
 
4158
        if( fmt == FS_FAT32 )
4159
        {
4160
                disk_write( drv, tbl, b_part + 6, 1 );
4161
        }
4162
 
4163
        /* Initialize FAT area */
4164
        for( m = 0; m < N_FATS; m++ )
4165
        {
4166
                mem_set( tbl, 0, SS(fs) );                               /* 1st sector of the FAT  */
4167
                if( fmt != FS_FAT32 )
4168
                {
4169
                        n = ( fmt == FS_FAT12 ) ? 0x00FFFF00 : 0xFFFFFF00;
4170
                        n |= partition;
4171
                        ST_DWORD( tbl, n );                                     /* Reserve cluster #0-1 (FAT12/16) */
4172
                }
4173
                else
4174
                {
4175
                        ST_DWORD( tbl + 0, 0xFFFFFFF8 ); /* Reserve cluster #0-1 (FAT32) */
4176
                        ST_DWORD( tbl + 4, 0xFFFFFFFF );
4177
                        ST_DWORD( tbl + 8, 0x0FFFFFFF );        /* Reserve cluster #2 for root dir */
4178
                }
4179
 
4180
                if( disk_write(drv, tbl, b_fat++, 1) != RES_OK )
4181
                {
4182
                        return FR_DISK_ERR;
4183
                }
4184
 
4185
                mem_set( tbl, 0, SS(fs) );                               /* Following FAT entries are filled by zero */
4186
                for( n = 1; n < n_fat; n++ )
4187
                {
4188
                        if( disk_write(drv, tbl, b_fat++, 1) != RES_OK )
4189
                        {
4190
                                return FR_DISK_ERR;
4191
                        }
4192
                }
4193
        }
4194
 
4195
        /* Initialize Root directory */
4196
        m = ( BYTE ) ( (fmt == FS_FAT32) ? allocsize : n_dir );
4197
        do
4198
        {
4199
                if( disk_write(drv, tbl, b_fat++, 1) != RES_OK )
4200
                {
4201
                        return FR_DISK_ERR;
4202
                }
4203
        } while( --m );
4204
 
4205
        /* Create FSInfo record if needed */
4206
        if( fmt == FS_FAT32 )
4207
        {
4208
                ST_WORD( tbl + BS_55AA, 0xAA55 );
4209
                ST_DWORD( tbl + FSI_LeadSig, 0x41615252 );
4210
                ST_DWORD( tbl + FSI_StrucSig, 0x61417272 );
4211
                ST_DWORD( tbl + FSI_Free_Count, n_clst - 1 );
4212
                ST_DWORD( tbl + FSI_Nxt_Free, 0xFFFFFFFF );
4213
                disk_write( drv, tbl, b_part + 1, 1 );
4214
                disk_write( drv, tbl, b_part + 7, 1 );
4215
        }
4216
 
4217
        return( disk_ioctl(drv, CTRL_SYNC, ( void * ) NULL) == RES_OK ) ? FR_OK : FR_DISK_ERR;
4218
}
4219
 
4220
#endif /* _USE_MKFS && !_FS_READONLY */
4221
 
4222
#if _USE_STRFUNC
4223
 
4224
/*-----------------------------------------------------------------------*/
4225
 
4226
/* Get a string from the file                                            */
4227
 
4228
/*-----------------------------------------------------------------------*/
4229
char *f_gets
4230
        (
4231
                char    *buff,  /* Pointer to the string buffer to read */
4232
                int             len,    /* Size of string buffer */
4233
                FIL             *fil    /* Pointer to the file object */
4234
        )
4235
{
4236
        int             i = 0;
4237
        char    *p = buff;
4238
        UINT    rc;
4239
 
4240
        while( i < len - 1 )
4241
        {                                               /* Read bytes until buffer gets filled */
4242
                f_read( fil, p, 1, &rc );
4243
                if( rc != 1 )
4244
                {
4245
                        break;                  /* Break when no data to read */
4246
                }
4247
 
4248
                        #if _USE_STRFUNC >= 2
4249
                if( *p == '\r' )
4250
                {
4251
                        continue;               /* Strip '\r' */
4252
                }
4253
 
4254
                        #endif
4255
                i++;
4256
                if( *p++ == '\n' )
4257
                {
4258
                        break;                  /* Break when reached end of line */
4259
                }
4260
        }
4261
 
4262
        *p = 0;
4263
        return i ? buff : NULL; /* When no data read (eof or error), return with error. */
4264
}
4265
 
4266
        #if !_FS_READONLY
4267
                #include <stdarg.h>
4268
 
4269
/*-----------------------------------------------------------------------*/
4270
 
4271
/* Put a character to the file                                           */
4272
 
4273
/*-----------------------------------------------------------------------*/
4274
int f_putc( int chr, /* A character to be output */ FIL *fil /* Ponter to the file object */ )
4275
{
4276
        UINT    bw;
4277
        char    c;
4278
 
4279
                        #if _USE_STRFUNC >= 2
4280
        if( chr == '\n' )
4281
        {
4282
                f_putc( '\r', fil );    /* LF -> CRLF conversion */
4283
        }
4284
 
4285
                        #endif
4286
        if( !fil )
4287
        {       /* Special value may be used to switch the destination to any other device */
4288
                /*      put_console(chr);       */
4289
                return chr;
4290
        }
4291
 
4292
        c = ( char ) chr;
4293
        f_write( fil, &c, 1, &bw ); /* Write a byte to the file */
4294
        return bw ? chr : EOF;          /* Return the result */
4295
}
4296
 
4297
/*-----------------------------------------------------------------------*/
4298
 
4299
/* Put a string to the file                                              */
4300
 
4301
/*-----------------------------------------------------------------------*/
4302
int f_puts( const char *str, /* Pointer to the string to be output */ FIL *fil /* Pointer to the file object */ )
4303
{
4304
        int n;
4305
 
4306
        for( n = 0; *str; str++, n++ )
4307
        {
4308
                if( f_putc(*str, fil) == EOF )
4309
                {
4310
                        return EOF;
4311
                }
4312
        }
4313
 
4314
        return n;
4315
}
4316
 
4317
/*-----------------------------------------------------------------------*/
4318
 
4319
/* Put a formatted string to the file                                    */
4320
 
4321
/*-----------------------------------------------------------------------*/
4322
int f_printf( FIL *fil, /* Pointer to the file object */ const char *str, /* Pointer to the format string */ ... /* Optional arguments... */ )
4323
{
4324
        va_list arp;
4325
        UCHAR   c, f, r;
4326
        ULONG   val;
4327
        char    s[16];
4328
        int             i, w, res, cc;
4329
 
4330
        va_start( arp, str );
4331
 
4332
        for( cc = res = 0; cc != EOF; res += cc )
4333
        {
4334
                c = *str++;
4335
                if( c == 0 )
4336
                {
4337
                        break;  /* End of string */
4338
                }
4339
 
4340
                if( c != '%' )
4341
                {                       /* Non escape cahracter */
4342
                        cc = f_putc( c, fil );
4343
                        if( cc != EOF )
4344
                        {
4345
                                cc = 1;
4346
                        }
4347
 
4348
                        continue;
4349
                }
4350
 
4351
                w = f = 0;
4352
                c = *str++;
4353
                if( c == '0' )
4354
                {                       /* Flag: '0' padding */
4355
                        f = 1;
4356
                        c = *str++;
4357
                }
4358
 
4359
                while( c >= '0' && c <= '9' )
4360
                {                       /* Precision */
4361
                        w = w * 10 + ( c - '0' );
4362
                        c = *str++;
4363
                }
4364
 
4365
                if( c == 'l' )
4366
                {                       /* Prefix: Size is long int */
4367
                        f |= 2;
4368
                        c = *str++;
4369
                }
4370
 
4371
                if( c == 's' )
4372
                {                       /* Type is string */
4373
                        cc = f_puts( va_arg(arp, char *), fil );
4374
                        continue;
4375
                }
4376
 
4377
                if( c == 'c' )
4378
                {                       /* Type is character */
4379
                        cc = f_putc( va_arg(arp, int), fil );
4380
                        if( cc != EOF )
4381
                        {
4382
                                cc = 1;
4383
                        }
4384
 
4385
                        continue;
4386
                }
4387
 
4388
                r = 0;
4389
                if( c == 'd' )
4390
                {
4391
                        r = 10; /* Type is signed decimal */
4392
                }
4393
 
4394
                if( c == 'u' )
4395
                {
4396
                        r = 10; /* Type is unsigned decimal */
4397
                }
4398
 
4399
                if( c == 'X' )
4400
                {
4401
                        r = 16; /* Type is unsigned hexdecimal */
4402
                }
4403
 
4404
                if( r == 0 )
4405
                {
4406
                        break;  /* Unknown type */
4407
                }
4408
 
4409
                if( f & 2 )
4410
                {                       /* Get the value */
4411
                        val = ( ULONG ) va_arg( arp, long );
4412
                }
4413
                else
4414
                {
4415
                        val = ( c == 'd' ) ? ( ULONG ) ( long ) va_arg( arp, int ) : ( ULONG ) va_arg( arp, unsigned int );
4416
                }
4417
 
4418
                /* Put numeral string */
4419
                if( c == 'd' )
4420
                {
4421
                        if( val & 0x80000000 )
4422
                        {
4423
                                val = 0 - val;
4424
                                f |= 4;
4425
                        }
4426
                }
4427
 
4428
                i = sizeof( s ) - 1;
4429
                s[i] = 0;
4430
                do
4431
                {
4432
                        c = ( UCHAR ) ( val % r + '0' );
4433
                        if( c > '9' )
4434
                        {
4435
                                c += 7;
4436
                        }
4437
 
4438
                        s[--i] = c;
4439
                        val /= r;
4440
                } while( i && val );
4441
                if( i && (f & 4) )
4442
                {
4443
                        s[--i] = '-';
4444
                }
4445
 
4446
                w = sizeof( s ) - 1 - w;
4447
                while( i && i > w )
4448
                {
4449
                        s[--i] = ( f & 1 ) ? '0' : ' ';
4450
                }
4451
 
4452
                cc = f_puts( &s[i], fil );
4453
        }
4454
 
4455
        va_end( arp );
4456
        return( cc == EOF ) ? cc : res;
4457
}
4458
 
4459
        #endif /* !_FS_READONLY */
4460
#endif /* _USE_STRFUNC */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.