OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [FileSystem/] [FatFs-0.7e/] [src/] [Copy of 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
 
79
#include "ff.h"                 /* FatFs configurations and declarations */
80
#include "diskio.h"             /* Declarations of low level disk I/O functions */
81
 
82
/*--------------------------------------------------------------------------
83
 
84
   Module Private Definitions
85
 
86
---------------------------------------------------------------------------*/
87
 
88
#if _FATFS != 0x007E
89
#error Wrong include file (ff.h).
90
#endif
91
 
92
#if _FS_REENTRANT
93
#if _USE_LFN == 1
94
#error Static LFN work area must not be used in re-entrant configuration.
95
#endif
96
#define ENTER_FF(fs)            { if (!lock_fs(fs)) return FR_TIMEOUT; }
97
#define LEAVE_FF(fs, res)       { unlock_fs(fs, res); return res; }
98
 
99
#else
100
#define ENTER_FF(fs)
101
#define LEAVE_FF(fs, res)       return res
102
 
103
#endif
104
 
105
#define ABORT(fs, res)          { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
106
 
107
#ifndef NULL
108
#define NULL    0
109
#endif
110
 
111
/* Name status flags */
112
#define NS                      11              /* Offset of name status byte */
113
#define NS_LOSS         0x01    /* Out of 8.3 format */
114
#define NS_LFN          0x02    /* Force to create LFN entry */
115
#define NS_LAST         0x04    /* Last segment */
116
#define NS_BODY         0x08    /* Lower case flag (body) */
117
#define NS_EXT          0x10    /* Lower case flag (ext) */
118
#define NS_DOT          0x20    /* Dot entry */
119
 
120
 
121
 
122
 
123
/*--------------------------------------------------------------------------
124
 
125
   Private Work Area
126
 
127
---------------------------------------------------------------------------*/
128
 
129
#if _DRIVES < 1 || _DRIVES > 9
130
#error Number of drives must be 1-9.
131
#endif
132
static
133
FATFS *FatFs[_DRIVES];  /* Pointer to the file system objects (logical drives) */
134
 
135
static
136
WORD Fsid;                              /* File system mount ID */
137
 
138
#if _FS_RPATH
139
static
140
BYTE Drive;                             /* Current drive */
141
#endif
142
 
143
 
144
#if _USE_LFN == 1       /* LFN with static LFN working buffer */
145
static
146
WCHAR LfnBuf[_MAX_LFN + 1];
147
#define NAMEBUF(sp,lp)  BYTE sp[12]; WCHAR *lp = LfnBuf
148
#define INITBUF(dj,sp,lp)       dj.fn = sp; dj.lfn = lp
149
 
150
#elif _USE_LFN > 1      /* LFN with dynamic LFN working buffer */
151
#define NAMEBUF(sp,lp)  BYTE sp[12]; WCHAR lbuf[_MAX_LFN + 1], *lp = lbuf
152
#define INITBUF(dj,sp,lp)       dj.fn = sp; dj.lfn = lp
153
 
154
#else                           /* No LFN */
155
#define NAMEBUF(sp,lp)  BYTE sp[12]
156
#define INITBUF(dj,sp,lp)       dj.fn = sp
157
 
158
#endif
159
 
160
 
161
 
162
 
163
/*--------------------------------------------------------------------------
164
 
165
   Module Private Functions
166
 
167
---------------------------------------------------------------------------*/
168
 
169
 
170
/*-----------------------------------------------------------------------*/
171
/* String functions                                                      */
172
/*-----------------------------------------------------------------------*/
173
 
174
/* Copy memory to memory */
175
static
176
void mem_cpy (void* dst, const void* src, int cnt) {
177
        char *d = (char*)dst;
178
        const char *s = (const char *)src;
179
        while (cnt--) *d++ = *s++;
180
}
181
 
182
/* Fill memory */
183
static
184
void mem_set (void* dst, int val, int cnt) {
185
        char *d = (char*)dst;
186
        while (cnt--) *d++ = (char)val;
187
}
188
 
189
/* Compare memory to memory */
190
static
191
int mem_cmp (const void* dst, const void* src, int cnt) {
192
        const char *d = (const char *)dst, *s = (const char *)src;
193
        int r = 0;
194
        while (cnt-- && (r = *d++ - *s++) == 0) ;
195
        return r;
196
}
197
 
198
/* Check if chr is contained in the string */
199
static
200
int chk_chr (const char* str, int chr) {
201
        while (*str && *str != chr) str++;
202
        return *str;
203
}
204
 
205
 
206
 
207
/*-----------------------------------------------------------------------*/
208
/* Request/Release grant to access the volume                            */
209
/*-----------------------------------------------------------------------*/
210
#if _FS_REENTRANT
211
 
212
static
213
BOOL lock_fs (
214
        FATFS *fs               /* File system object */
215
)
216
{
217
        return ff_req_grant(fs->sobj);
218
}
219
 
220
 
221
static
222
void unlock_fs (
223
        FATFS *fs,              /* File system object */
224
        FRESULT res             /* Result code to be returned */
225
)
226
{
227
        if (res != FR_NOT_ENABLED &&
228
                res != FR_INVALID_DRIVE &&
229
                res != FR_INVALID_OBJECT &&
230
                res != FR_TIMEOUT) {
231
                ff_rel_grant(fs->sobj);
232
        }
233
}
234
#endif
235
 
236
 
237
 
238
/*-----------------------------------------------------------------------*/
239
/* Change window offset                                                  */
240
/*-----------------------------------------------------------------------*/
241
 
242
static
243
FRESULT move_window (
244
        FATFS *fs,              /* File system object */
245
        DWORD sector    /* Sector number to make apperance in the fs->win[] */
246
)                                       /* Move to zero only writes back dirty window */
247
{
248
        DWORD wsect;
249
 
250
 
251
        wsect = fs->winsect;
252
        if (wsect != sector) {  /* Changed current window */
253
#if !_FS_READONLY
254
                if (fs->wflag) {        /* Write back dirty window if needed */
255
                        if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
256
                                return FR_DISK_ERR;
257
                        fs->wflag = 0;
258
                        if (wsect < (fs->fatbase + fs->sects_fat)) {    /* In FAT area */
259
                                BYTE nf;
260
                                for (nf = fs->n_fats; nf > 1; nf--) {   /* Refrect the change to all FAT copies */
261
                                        wsect += fs->sects_fat;
262
                                        disk_write(fs->drive, fs->win, wsect, 1);
263
                                }
264
                        }
265
                }
266
#endif
267
                if (sector) {
268
                        if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK)
269
                                return FR_DISK_ERR;
270
                        fs->winsect = sector;
271
                }
272
        }
273
 
274
        return FR_OK;
275
}
276
 
277
 
278
 
279
 
280
/*-----------------------------------------------------------------------*/
281
/* Clean-up cached data                                                  */
282
/*-----------------------------------------------------------------------*/
283
#if !_FS_READONLY
284
static
285
FRESULT sync (  /* FR_OK: successful, FR_DISK_ERR: failed */
286
        FATFS *fs       /* File system object */
287
)
288
{
289
        FRESULT res;
290
 
291
 
292
        res = move_window(fs, 0);
293
        if (res == FR_OK) {
294
                /* Update FSInfo sector if needed */
295
                if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
296
                        fs->winsect = 0;
297
                        mem_set(fs->win, 0, 512);
298
                        ST_WORD(fs->win+BS_55AA, 0xAA55);
299
                        ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
300
                        ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
301
                        ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
302
                        ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
303
                        disk_write(fs->drive, fs->win, fs->fsi_sector, 1);
304
                        fs->fsi_flag = 0;
305
                }
306
                /* Make sure that no pending write process in the physical drive */
307
                if (disk_ioctl(fs->drive, CTRL_SYNC, (void*)NULL) != RES_OK)
308
                        res = FR_DISK_ERR;
309
        }
310
 
311
        return res;
312
}
313
#endif
314
 
315
 
316
 
317
 
318
/*-----------------------------------------------------------------------*/
319
/* FAT access - Read value of a FAT entry                                */
320
/*-----------------------------------------------------------------------*/
321
 
322
 
323
DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */
324
        FATFS *fs,      /* File system object */
325
        DWORD clst      /* Cluster# to get the link information */
326
)
327
{
328
        UINT wc, bc;
329
        DWORD fsect;
330
 
331
 
332
        if (clst < 2 || clst >= fs->max_clust)  /* Range check */
333
                return 1;
334
 
335
        fsect = fs->fatbase;
336
        switch (fs->fs_type) {
337
        case FS_FAT12 :
338
                bc = clst; bc += bc / 2;
339
                if (move_window(fs, fsect + (bc / SS(fs)))) break;
340
                wc = fs->win[bc & (SS(fs) - 1)]; bc++;
341
                if (move_window(fs, fsect + (bc / SS(fs)))) break;
342
                wc |= (WORD)fs->win[bc & (SS(fs) - 1)] << 8;
343
                return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
344
 
345
        case FS_FAT16 :
346
                if (move_window(fs, fsect + (clst / (SS(fs) / 2)))) break;
347
                return LD_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)]);
348
 
349
        case FS_FAT32 :
350
                if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break;
351
                return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF;
352
        }
353
 
354
        return 0xFFFFFFFF;      /* An error occured at the disk I/O layer */
355
}
356
 
357
 
358
 
359
 
360
/*-----------------------------------------------------------------------*/
361
/* FAT access - Change value of a FAT entry                              */
362
/*-----------------------------------------------------------------------*/
363
#if !_FS_READONLY
364
 
365
FRESULT put_fat (
366
        FATFS *fs,      /* File system object */
367
        DWORD clst,     /* Cluster# to be changed in range of 2 to fs->max_clust - 1 */
368
        DWORD val       /* New value to mark the cluster */
369
)
370
{
371
        UINT bc;
372
        BYTE *p;
373
        DWORD fsect;
374
        FRESULT res;
375
 
376
 
377
        if (clst < 2 || clst >= fs->max_clust) {        /* Range check */
378
                res = FR_INT_ERR;
379
 
380
        } else {
381
                fsect = fs->fatbase;
382
                switch (fs->fs_type) {
383
                case FS_FAT12 :
384
                        bc = clst; bc += bc / 2;
385
                        res = move_window(fs, fsect + (bc / SS(fs)));
386
                        if (res != FR_OK) break;
387
                        p = &fs->win[bc & (SS(fs) - 1)];
388
                        *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
389
                        bc++;
390
                        fs->wflag = 1;
391
                        res = move_window(fs, fsect + (bc / SS(fs)));
392
                        if (res != FR_OK) break;
393
                        p = &fs->win[bc & (SS(fs) - 1)];
394
                        *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
395
                        break;
396
 
397
                case FS_FAT16 :
398
                        res = move_window(fs, fsect + (clst / (SS(fs) / 2)));
399
                        if (res != FR_OK) break;
400
                        ST_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)], (WORD)val);
401
                        break;
402
 
403
                case FS_FAT32 :
404
                        res = move_window(fs, fsect + (clst / (SS(fs) / 4)));
405
                        if (res != FR_OK) break;
406
                        ST_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)], val);
407
                        break;
408
 
409
                default :
410
                        res = FR_INT_ERR;
411
                }
412
                fs->wflag = 1;
413
        }
414
 
415
        return res;
416
}
417
#endif /* !_FS_READONLY */
418
 
419
 
420
 
421
 
422
/*-----------------------------------------------------------------------*/
423
/* FAT handling - Remove a cluster chain                                 */
424
/*-----------------------------------------------------------------------*/
425
#if !_FS_READONLY
426
static
427
FRESULT remove_chain (
428
        FATFS *fs,                      /* File system object */
429
        DWORD clst                      /* Cluster# to remove a chain from */
430
)
431
{
432
        FRESULT res;
433
        DWORD nxt;
434
 
435
 
436
        if (clst < 2 || clst >= fs->max_clust) {        /* Check the range of cluster# */
437
                res = FR_INT_ERR;
438
 
439
        } else {
440
                res = FR_OK;
441
                while (clst < fs->max_clust) {                  /* Not a last link? */
442
                        nxt = get_fat(fs, clst);                        /* Get cluster status */
443
                        if (nxt == 0) break;                             /* Empty cluster? */
444
                        if (nxt == 1) { res = FR_INT_ERR; break; }      /* Internal error? */
445
                        if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }    /* Disk error? */
446
                        res = put_fat(fs, clst, 0);                      /* Mark the cluster "empty" */
447
                        if (res != FR_OK) break;
448
                        if (fs->free_clust != 0xFFFFFFFF) {     /* Update FSInfo */
449
                                fs->free_clust++;
450
                                fs->fsi_flag = 1;
451
                        }
452
                        clst = nxt;     /* Next cluster */
453
                }
454
        }
455
 
456
        return res;
457
}
458
#endif
459
 
460
 
461
 
462
 
463
/*-----------------------------------------------------------------------*/
464
/* FAT handling - Stretch or Create a cluster chain                      */
465
/*-----------------------------------------------------------------------*/
466
#if !_FS_READONLY
467
static
468
DWORD create_chain (    /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
469
        FATFS *fs,                      /* File system object */
470
        DWORD clst                      /* Cluster# to stretch. 0 means create a new chain. */
471
)
472
{
473
        DWORD cs, ncl, scl, mcl;
474
 
475
 
476
        mcl = fs->max_clust;
477
        if (clst == 0) {         /* Create new chain */
478
                scl = fs->last_clust;                   /* Get suggested start point */
479
                if (scl == 0 || scl >= mcl) scl = 1;
480
        }
481
        else {                                  /* Stretch existing chain */
482
                cs = get_fat(fs, clst);                 /* Check the cluster status */
483
                if (cs < 2) return 1;                   /* It is an invalid cluster */
484
                if (cs < mcl) return cs;                /* It is already followed by next cluster */
485
                scl = clst;
486
        }
487
 
488
        ncl = scl;                              /* Start cluster */
489
        for (;;) {
490
                ncl++;                                                  /* Next cluster */
491
                if (ncl >= mcl) {                               /* Wrap around */
492
                        ncl = 2;
493
                        if (ncl > scl) return 0; /* No free custer */
494
                }
495
                cs = get_fat(fs, ncl);                  /* Get the cluster status */
496
                if (cs == 0) break;                              /* Found a free cluster */
497
                if (cs == 0xFFFFFFFF || cs == 1)/* An error occured */
498
                        return cs;
499
                if (ncl == scl) return 0;                /* No free custer */
500
        }
501
 
502
        if (put_fat(fs, ncl, 0x0FFFFFFF))       /* Mark the new cluster "in use" */
503
                return 0xFFFFFFFF;
504
        if (clst != 0) {                                 /* Link it to the previous one if needed */
505
                if (put_fat(fs, clst, ncl))
506
                        return 0xFFFFFFFF;
507
        }
508
 
509
        fs->last_clust = ncl;                           /* Update FSINFO */
510
        if (fs->free_clust != 0xFFFFFFFF) {
511
                fs->free_clust--;
512
                fs->fsi_flag = 1;
513
        }
514
 
515
        return ncl;             /* Return new cluster number */
516
}
517
#endif /* !_FS_READONLY */
518
 
519
 
520
 
521
 
522
/*-----------------------------------------------------------------------*/
523
/* Get sector# from cluster#                                             */
524
/*-----------------------------------------------------------------------*/
525
 
526
 
527
DWORD clust2sect (      /* !=0: Sector number, 0: Failed - invalid cluster# */
528
        FATFS *fs,              /* File system object */
529
        DWORD clst              /* Cluster# to be converted */
530
)
531
{
532
        clst -= 2;
533
        if (clst >= (fs->max_clust - 2)) return 0;               /* Invalid cluster# */
534
        return clst * fs->csize + fs->database;
535
}
536
 
537
 
538
 
539
 
540
/*-----------------------------------------------------------------------*/
541
/* Directory handling - Seek directory index                             */
542
/*-----------------------------------------------------------------------*/
543
 
544
static
545
FRESULT dir_seek (
546
        DIR *dj,                /* Pointer to directory object */
547
        WORD idx                /* Directory index number */
548
)
549
{
550
        DWORD clst;
551
        WORD ic;
552
 
553
 
554
        dj->index = idx;
555
        clst = dj->sclust;
556
        if (clst == 1 || clst >= dj->fs->max_clust)     /* Check start cluster range */
557
                return FR_INT_ERR;
558
        if (!clst && dj->fs->fs_type == FS_FAT32)       /* Replace cluster# 0 with root cluster# if in FAT32 */
559
                clst = dj->fs->dirbase;
560
 
561
        if (clst == 0) { /* Static table */
562
                dj->clust = clst;
563
                if (idx >= dj->fs->n_rootdir)           /* Index is out of range */
564
                        return FR_INT_ERR;
565
                dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32);   /* Sector# */
566
        }
567
        else {                          /* Dynamic table */
568
                ic = SS(dj->fs) / 32 * dj->fs->csize;   /* Entries per cluster */
569
                while (idx >= ic) {     /* Follow cluster chain */
570
                        clst = get_fat(dj->fs, clst);                           /* Get next cluster */
571
                        if (clst == 0xFFFFFFFF) return FR_DISK_ERR;     /* Disk error */
572
                        if (clst < 2 || clst >= dj->fs->max_clust)      /* Reached to end of table or int error */
573
                                return FR_INT_ERR;
574
                        idx -= ic;
575
                }
576
                dj->clust = clst;
577
                dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32);  /* Sector# */
578
        }
579
 
580
        dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */
581
 
582
        return FR_OK;   /* Seek succeeded */
583
}
584
 
585
 
586
 
587
 
588
/*-----------------------------------------------------------------------*/
589
/* Directory handling - Move directory index next                        */
590
/*-----------------------------------------------------------------------*/
591
 
592
static
593
FRESULT dir_next (      /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
594
        DIR *dj,                /* Pointer to directory object */
595
        BOOL streach    /* FALSE: Do not streach table, TRUE: Streach table if needed */
596
)
597
{
598
        DWORD clst;
599
        WORD i;
600
 
601
 
602
        i = dj->index + 1;
603
        if (!i || !dj->sect)    /* Report EOT when index has reached 65535 */
604
                return FR_NO_FILE;
605
 
606
        if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */
607
                dj->sect++;                                     /* Next sector */
608
 
609
                if (dj->clust == 0) {    /* Static table */
610
                        if (i >= dj->fs->n_rootdir)     /* Report EOT when end of table */
611
                                return FR_NO_FILE;
612
                }
613
                else {                                  /* Dynamic table */
614
                        if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) {      /* Cluster changed? */
615
                                clst = get_fat(dj->fs, dj->clust);                              /* Get next cluster */
616
                                if (clst <= 1) return FR_INT_ERR;
617
                                if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
618
                                if (clst >= dj->fs->max_clust) {                                /* When it reached end of dynamic table */
619
#if !_FS_READONLY
620
                                        BYTE c;
621
                                        if (!streach) return FR_NO_FILE;                        /* When do not streach, report EOT */
622
                                        clst = create_chain(dj->fs, dj->clust);         /* Streach cluster chain */
623
                                        if (clst == 0) return FR_DENIED;                 /* No free cluster */
624
                                        if (clst == 1) return FR_INT_ERR;
625
                                        if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
626
                                        /* Clean-up streached table */
627
                                        if (move_window(dj->fs, 0)) return FR_DISK_ERR;  /* Flush active window */
628
                                        mem_set(dj->fs->win, 0, SS(dj->fs));                     /* Clear window buffer */
629
                                        dj->fs->winsect = clust2sect(dj->fs, clst);     /* Cluster start sector */
630
                                        for (c = 0; c < dj->fs->csize; c++) {            /* Fill the new cluster with 0 */
631
                                                dj->fs->wflag = 1;
632
                                                if (move_window(dj->fs, 0)) return FR_DISK_ERR;
633
                                                dj->fs->winsect++;
634
                                        }
635
                                        dj->fs->winsect -= c;                                           /* Rewind window address */
636
#else
637
                                        return FR_NO_FILE;                      /* Report EOT */
638
#endif
639
                                }
640
                                dj->clust = clst;                               /* Initialize data for new cluster */
641
                                dj->sect = clust2sect(dj->fs, clst);
642
                        }
643
                }
644
        }
645
 
646
        dj->index = i;
647
        dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
648
 
649
        return FR_OK;
650
}
651
 
652
 
653
 
654
 
655
/*-----------------------------------------------------------------------*/
656
/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry   */
657
/*-----------------------------------------------------------------------*/
658
#if _USE_LFN
659
static
660
const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};      /* Offset of LFN chars in the directory entry */
661
 
662
 
663
static
664
BOOL cmp_lfn (                  /* TRUE:Matched, FALSE:Not matched */
665
        WCHAR *lfnbuf,          /* Pointer to the LFN to be compared */
666
        BYTE *dir                       /* Pointer to the directory entry containing a part of LFN */
667
)
668
{
669
        int i, s;
670
        WCHAR wc, uc;
671
 
672
 
673
        i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13;  /* Get offset in the LFN buffer */
674
        s = 0; wc = 1;
675
        do {
676
                uc = LD_WORD(dir+LfnOfs[s]);    /* Pick an LFN character from the entry */
677
                if (wc) {       /* Last char has not been processed */
678
                        wc = ff_wtoupper(uc);           /* Convert it to upper case */
679
                        if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++]))    /* Compare it */
680
                                return FALSE;                   /* Not matched */
681
                } else {
682
                        if (uc != 0xFFFF) return FALSE; /* Check filler */
683
                }
684
        } while (++s < 13);                             /* Repeat until all chars in the entry are checked */
685
 
686
        if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i])  /* Last segment matched but different length */
687
                return FALSE;
688
 
689
        return TRUE;                                    /* The part of LFN matched */
690
}
691
 
692
 
693
 
694
static
695
BOOL pick_lfn (                 /* TRUE:Succeeded, FALSE:Buffer overflow */
696
        WCHAR *lfnbuf,          /* Pointer to the Unicode-LFN buffer */
697
        BYTE *dir                       /* Pointer to the directory entry */
698
)
699
{
700
        int i, s;
701
        WCHAR wc, uc;
702
 
703
 
704
        i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;  /* Offset in the LFN buffer */
705
 
706
        s = 0; wc = 1;
707
        do {
708
                uc = LD_WORD(dir+LfnOfs[s]);                    /* Pick an LFN character from the entry */
709
                if (wc) {       /* Last char has not been processed */
710
                        if (i >= _MAX_LFN) return FALSE;        /* Buffer overflow? */
711
                        lfnbuf[i++] = wc = uc;                          /* Store it */
712
                } else {
713
                        if (uc != 0xFFFF) return FALSE;         /* Check filler */
714
                }
715
        } while (++s < 13);                                             /* Read all character in the entry */
716
 
717
        if (dir[LDIR_Ord] & 0x40) {                             /* Put terminator if it is the last LFN part */
718
                if (i >= _MAX_LFN) return FALSE;        /* Buffer overflow? */
719
                lfnbuf[i] = 0;
720
        }
721
 
722
        return TRUE;
723
}
724
 
725
 
726
#if !_FS_READONLY
727
static
728
void fit_lfn (
729
        const WCHAR *lfnbuf,    /* Pointer to the LFN buffer */
730
        BYTE *dir,                              /* Pointer to the directory entry */
731
        BYTE ord,                               /* LFN order (1-20) */
732
        BYTE sum                                /* SFN sum */
733
)
734
{
735
        int i, s;
736
        WCHAR wc;
737
 
738
 
739
        dir[LDIR_Chksum] = sum;                 /* Set check sum */
740
        dir[LDIR_Attr] = AM_LFN;                /* Set attribute. LFN entry */
741
        dir[LDIR_Type] = 0;
742
        ST_WORD(dir+LDIR_FstClusLO, 0);
743
 
744
        i = (ord - 1) * 13;                             /* Get offset in the LFN buffer */
745
        s = wc = 0;
746
        do {
747
                if (wc != 0xFFFF) wc = lfnbuf[i++];     /* Get an effective char */
748
                ST_WORD(dir+LfnOfs[s], wc);     /* Put it */
749
                if (!wc) wc = 0xFFFF;           /* Padding chars following last char */
750
        } while (++s < 13);
751
        if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40;    /* Bottom LFN part is the start of LFN sequence */
752
        dir[LDIR_Ord] = ord;                    /* Set the LFN order */
753
}
754
 
755
#endif
756
#endif
757
 
758
 
759
 
760
/*-----------------------------------------------------------------------*/
761
/* Create numbered name                                                  */
762
/*-----------------------------------------------------------------------*/
763
#if _USE_LFN
764
void gen_numname (
765
        BYTE *dst,                      /* Pointer to genartated SFN */
766
        const BYTE *src,        /* Pointer to source SFN to be modified */
767
        const WCHAR *lfn,       /* Pointer to LFN */
768
        WORD num                        /* Sequense number */
769
)
770
{
771
        char ns[8];
772
        int i, j;
773
 
774
 
775
        mem_cpy(dst, src, 11);
776
 
777
        if (num > 5) {  /* On many collisions, generate a hash number instead of sequencial number */
778
                do num = (num >> 1) + (num << 15) + (WORD)*lfn++; while (*lfn);
779
        }
780
 
781
        /* itoa */
782
        i = 7;
783
        do {
784
                ns[i--] = (num % 10) + '0';
785
                num /= 10;
786
        } while (num);
787
        ns[i] = '~';
788
 
789
        /* Append the number */
790
        for (j = 0; j < i && dst[j] != ' '; j++) {
791
                if (IsDBCS1(dst[j])) {
792
                        if (j == i - 1) break;
793
                        j++;
794
                }
795
        }
796
        do {
797
                dst[j++] = (i < 8) ? ns[i++] : ' ';
798
        } while (j < 8);
799
}
800
#endif
801
 
802
 
803
 
804
 
805
/*-----------------------------------------------------------------------*/
806
/* Calculate sum of an SFN                                               */
807
/*-----------------------------------------------------------------------*/
808
#if _USE_LFN
809
static
810
BYTE sum_sfn (
811
        const BYTE *dir         /* Ptr to directory entry */
812
)
813
{
814
        BYTE sum = 0;
815
        int n = 11;
816
 
817
        do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
818
        return sum;
819
}
820
#endif
821
 
822
 
823
 
824
 
825
/*-----------------------------------------------------------------------*/
826
/* Directory handling - Find an object in the directory                  */
827
/*-----------------------------------------------------------------------*/
828
 
829
static
830
FRESULT dir_find (
831
        DIR *dj                 /* Pointer to the directory object linked to the file name */
832
)
833
{
834
        FRESULT res;
835
        BYTE c, *dir;
836
#if _USE_LFN
837
        BYTE a, ord, sum;
838
#endif
839
 
840
        res = dir_seek(dj, 0);                   /* Rewind directory object */
841
        if (res != FR_OK) return res;
842
 
843
#if _USE_LFN
844
        ord = sum = 0xFF;
845
#endif
846
        do {
847
                res = move_window(dj->fs, dj->sect);
848
                if (res != FR_OK) break;
849
                dir = dj->dir;                                  /* Ptr to the directory entry of current index */
850
                c = dir[DIR_Name];
851
                if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
852
#if _USE_LFN    /* LFN configuration */
853
                a = dir[DIR_Attr] & AM_MASK;
854
                if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) {       /* An entry without valid data */
855
                        ord = 0xFF;
856
                } else {
857
                        if (a == AM_LFN) {                      /* An LFN entry is found */
858
                                if (dj->lfn) {
859
                                        if (c & 0x40) {         /* Is it start of LFN sequence? */
860
                                                sum = dir[LDIR_Chksum];
861
                                                c &= 0xBF; ord = c;     /* LFN start order */
862
                                                dj->lfn_idx = dj->index;
863
                                        }
864
                                        /* Check validity of the LFN entry and compare it with given name */
865
                                        ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
866
                                }
867
                        } else {                                        /* An SFN entry is found */
868
                                if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
869
                                ord = 0xFF; dj->lfn_idx = 0xFFFF;       /* Reset LFN sequence */
870
                                if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break;        /* SFN matched? */
871
                        }
872
                }
873
#else           /* Non LFN configuration */
874
                if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
875
                        break;
876
#endif
877
                res = dir_next(dj, FALSE);              /* Next entry */
878
        } while (res == FR_OK);
879
 
880
        return res;
881
}
882
 
883
 
884
 
885
 
886
/*-----------------------------------------------------------------------*/
887
/* Read an object from the directory                                     */
888
/*-----------------------------------------------------------------------*/
889
#if _FS_MINIMIZE <= 1
890
static
891
FRESULT dir_read (
892
        DIR *dj                 /* Pointer to the directory object that pointing the entry to be read */
893
)
894
{
895
        FRESULT res;
896
        BYTE c, *dir;
897
#if _USE_LFN
898
        BYTE a, ord = 0xFF, sum = 0xFF;
899
#endif
900
 
901
        res = FR_NO_FILE;
902
        while (dj->sect) {
903
                res = move_window(dj->fs, dj->sect);
904
                if (res != FR_OK) break;
905
                dir = dj->dir;                                  /* Ptr to the directory entry of current index */
906
                c = dir[DIR_Name];
907
                if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
908
#if _USE_LFN    /* LFN configuration */
909
                a = dir[DIR_Attr] & AM_MASK;
910
                if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) {   /* An entry without valid data */
911
                        ord = 0xFF;
912
                } else {
913
                        if (a == AM_LFN) {                      /* An LFN entry is found */
914
                                if (c & 0x40) {                 /* Is it start of LFN sequence? */
915
                                        sum = dir[LDIR_Chksum];
916
                                        c &= 0xBF; ord = c;
917
                                        dj->lfn_idx = dj->index;
918
                                }
919
                                /* Check LFN validity and capture it */
920
                                ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
921
                        } else {                                        /* An SFN entry is found */
922
                                if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
923
                                        dj->lfn_idx = 0xFFFF;           /* It has no LFN. */
924
                                break;
925
                        }
926
                }
927
#else           /* Non LFN configuration */
928
                if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL))  /* Is it a valid entry? */
929
                        break;
930
#endif
931
                res = dir_next(dj, FALSE);                              /* Next entry */
932
                if (res != FR_OK) break;
933
        }
934
 
935
        if (res != FR_OK) dj->sect = 0;
936
 
937
        return res;
938
}
939
#endif
940
 
941
 
942
 
943
/*-----------------------------------------------------------------------*/
944
/* Register an object to the directory                                   */
945
/*-----------------------------------------------------------------------*/
946
#if !_FS_READONLY
947
static
948
FRESULT dir_register (  /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
949
        DIR *dj                         /* Target directory with object name to be created */
950
)
951
{
952
        FRESULT res;
953
        BYTE c, *dir;
954
#if _USE_LFN    /* LFN configuration */
955
        WORD n, ne, is;
956
        BYTE sn[12], *fn, sum;
957
        WCHAR *lfn;
958
 
959
 
960
        fn = dj->fn; lfn = dj->lfn;
961
        mem_cpy(sn, fn, 12);
962
 
963
        if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME;     /* Cannot create dot entry */
964
 
965
        if (sn[NS] & NS_LOSS) {                 /* When LFN is out of 8.3 format, generate a numbered name */
966
                fn[NS] = 0; dj->lfn = NULL;                      /* Find only SFN */
967
                for (n = 1; n < 100; n++) {
968
                        gen_numname(fn, sn, lfn, n);    /* Generate a numbered name */
969
                        res = dir_find(dj);                             /* Check if the name collides with existing SFN */
970
                        if (res != FR_OK) break;
971
                }
972
                if (n == 100) return FR_DENIED;         /* Abort if too many collisions */
973
                if (res != FR_NO_FILE) return res;      /* Abort if the result is other than 'not collided' */
974
                fn[NS] = sn[NS]; dj->lfn = lfn;
975
        }
976
 
977
        if (sn[NS] & NS_LFN) {                  /* When LFN is to be created, reserve reserve an SFN + LFN entries. */
978
                for (ne = 0; lfn[ne]; ne++) ;
979
                ne = (ne + 25) / 13;
980
        } else {                                                /* Otherwise reserve only an SFN entry. */
981
                ne = 1;
982
        }
983
 
984
        /* Reserve contiguous entries */
985
        res = dir_seek(dj, 0);
986
        if (res != FR_OK) return res;
987
        n = is = 0;
988
        do {
989
                res = move_window(dj->fs, dj->sect);
990
                if (res != FR_OK) break;
991
                c = *dj->dir;                           /* Check the entry status */
992
                if (c == 0xE5 || c == 0) {       /* Is it a blank entry? */
993
                        if (n == 0) is = dj->index;      /* First index of the contigulus entry */
994
                        if (++n == ne) break;   /* A contiguous entry that requiered count is found */
995
                } else {
996
                        n = 0;                                   /* Not a blank entry. Restart to search */
997
                }
998
                res = dir_next(dj, TRUE);       /* Next entry with table streach */
999
        } while (res == FR_OK);
1000
 
1001
        if (res == FR_OK && ne > 1) {   /* Initialize LFN entry if needed */
1002
                res = dir_seek(dj, is);
1003
                if (res == FR_OK) {
1004
                        sum = sum_sfn(dj->fn);  /* Sum of the SFN tied to the LFN */
1005
                        ne--;
1006
                        do {                                    /* Store LFN entries in bottom first */
1007
                                res = move_window(dj->fs, dj->sect);
1008
                                if (res != FR_OK) break;
1009
                                fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
1010
                                dj->fs->wflag = 1;
1011
                                res = dir_next(dj, FALSE);      /* Next entry */
1012
                        } while (res == FR_OK && --ne);
1013
                }
1014
        }
1015
 
1016
#else   /* Non LFN configuration */
1017
        res = dir_seek(dj, 0);
1018
        if (res == FR_OK) {
1019
                do {    /* Find a blank entry for the SFN */
1020
                        res = move_window(dj->fs, dj->sect);
1021
                        if (res != FR_OK) break;
1022
                        c = *dj->dir;
1023
                        if (c == 0xE5 || c == 0) break;  /* Is it a blank entry? */
1024
                        res = dir_next(dj, TRUE);               /* Next entry with table streach */
1025
                } while (res == FR_OK);
1026
        }
1027
#endif
1028
 
1029
        if (res == FR_OK) {             /* Initialize the SFN entry */
1030
                res = move_window(dj->fs, dj->sect);
1031
                if (res == FR_OK) {
1032
                        dir = dj->dir;
1033
                        mem_set(dir, 0, 32);             /* Clean the entry */
1034
                        mem_cpy(dir, dj->fn, 11);       /* Put SFN */
1035
                        dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);     /* Put NT flag */
1036
                        dj->fs->wflag = 1;
1037
                }
1038
        }
1039
 
1040
        return res;
1041
}
1042
#endif /* !_FS_READONLY */
1043
 
1044
 
1045
 
1046
 
1047
/*-----------------------------------------------------------------------*/
1048
/* Remove an object from the directory                                   */
1049
/*-----------------------------------------------------------------------*/
1050
#if !_FS_READONLY && !_FS_MINIMIZE
1051
static
1052
FRESULT dir_remove (    /* FR_OK: Successful, FR_DISK_ERR: A disk error */
1053
        DIR *dj                         /* Directory object pointing the entry to be removed */
1054
)
1055
{
1056
        FRESULT res;
1057
#if _USE_LFN    /* LFN configuration */
1058
        WORD i;
1059
 
1060
        i = dj->index;  /* SFN index */
1061
        res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));  /* Goto the SFN or top of the LFN entries */
1062
        if (res == FR_OK) {
1063
                do {
1064
                        res = move_window(dj->fs, dj->sect);
1065
                        if (res != FR_OK) break;
1066
                        *dj->dir = 0xE5;                        /* Mark the entry "deleted" */
1067
                        dj->fs->wflag = 1;
1068
                        if (dj->index >= i) break;      /* When reached SFN, all entries of the object has been deleted. */
1069
                        res = dir_next(dj, FALSE);      /* Next entry */
1070
                } while (res == FR_OK);
1071
                if (res == FR_NO_FILE) res = FR_INT_ERR;
1072
        }
1073
 
1074
#else                   /* Non LFN configuration */
1075
        res = dir_seek(dj, dj->index);
1076
        if (res == FR_OK) {
1077
                res = move_window(dj->fs, dj->sect);
1078
                if (res == FR_OK) {
1079
                        *dj->dir = 0xE5;                        /* Mark the entry "deleted" */
1080
                        dj->fs->wflag = 1;
1081
                }
1082
        }
1083
#endif
1084
 
1085
        return res;
1086
}
1087
#endif /* !_FS_READONLY */
1088
 
1089
 
1090
 
1091
 
1092
/*-----------------------------------------------------------------------*/
1093
/* Pick a segment and create the object name in directory form           */
1094
/*-----------------------------------------------------------------------*/
1095
 
1096
static
1097
FRESULT create_name (
1098
        DIR *dj,                        /* Pointer to the directory object */
1099
        const XCHAR **path      /* Pointer to pointer to the segment in the path string */
1100
)
1101
{
1102
#ifdef _EXCVT
1103
        static const BYTE cvt[] = _EXCVT;
1104
#endif
1105
 
1106
#if _USE_LFN    /* LFN configuration */
1107
        BYTE b, cf;
1108
        WCHAR w, *lfn;
1109
        int i, ni, si, di;
1110
        const XCHAR *p;
1111
 
1112
        /* Create LFN in Unicode */
1113
        si = di = 0;
1114
        p = *path;
1115
        lfn = dj->lfn;
1116
        for (;;) {
1117
                w = p[si++];                                    /* Get a character */
1118
                if (w < ' ' || w == '/' || w == '\\') break;    /* Break on end of segment */
1119
                if (di >= _MAX_LFN)                             /* Reject too long name */
1120
                        return FR_INVALID_NAME;
1121
#if !_LFN_UNICODE
1122
                w &= 0xFF;
1123
                if (IsDBCS1(w)) {                               /* If it is a DBC 1st byte */
1124
                        b = p[si++];                            /* Get 2nd byte */
1125
                        if (!IsDBCS2(b))                        /* Reject invalid code for DBC */
1126
                                return FR_INVALID_NAME;
1127
                        w = (w << 8) + b;
1128
                }
1129
                w = ff_convert(w, 1);                   /* Convert OEM to Unicode */
1130
                if (!w) return FR_INVALID_NAME; /* Reject invalid code */
1131
#endif
1132
                if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
1133
                        return FR_INVALID_NAME;
1134
                lfn[di++] = w;                                  /* Store the Unicode char */
1135
        }
1136
        *path = &p[si];                                         /* Rerurn pointer to the next segment */
1137
        cf = (w < ' ') ? NS_LAST : 0;            /* Set last segment flag if end of path */
1138
#if _FS_RPATH
1139
        if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
1140
                (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
1141
                lfn[di] = 0;
1142
                for (i = 0; i < 11; i++)
1143
                        dj->fn[i] = (i < di) ? '.' : ' ';
1144
                dj->fn[i] = cf | NS_DOT;                /* This is a dot entry */
1145
                return FR_OK;
1146
        }
1147
#endif
1148
        while (di) {                                            /* Strip trailing spaces and dots */
1149
                w = lfn[di - 1];
1150
                if (w != ' ' && w != '.') break;
1151
                di--;
1152
        }
1153
        if (!di) return FR_INVALID_NAME;        /* Reject null string */
1154
 
1155
        lfn[di] = 0;                                             /* LFN is created */
1156
 
1157
        /* Create SFN in directory form */
1158
        mem_set(dj->fn, ' ', 11);
1159
        for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ;   /* Strip leading spaces and dots */
1160
        if (si) cf |= NS_LOSS | NS_LFN;
1161
        while (di && lfn[di - 1] != '.') di--;  /* Find extension (di<=si: no extension) */
1162
 
1163
        b = i = 0; ni = 8;
1164
        for (;;) {
1165
                w = lfn[si++];                                  /* Get an LFN char */
1166
                if (!w) break;                                  /* Break on enf of the LFN */
1167
                if (w == ' ' || (w == '.' && si != di)) {       /* Remove spaces and dots */
1168
                        cf |= NS_LOSS | NS_LFN; continue;
1169
                }
1170
 
1171
                if (i >= ni || si == di) {              /* Extension or end of SFN */
1172
                        if (ni == 11) {                         /* Long extension */
1173
                                cf |= NS_LOSS | NS_LFN; break;
1174
                        }
1175
                        if (si != di) cf |= NS_LOSS | NS_LFN;   /* Out of 8.3 format */
1176
                        if (si > di) break;                     /* No extension */
1177
                        si = di; i = 8; ni = 11;        /* Enter extension section */
1178
                        b <<= 2; continue;
1179
                }
1180
 
1181
                if (w >= 0x80) {                                /* Non ASCII char */
1182
#ifdef _EXCVT
1183
                        w = ff_convert(w, 0);            /* Unicode -> OEM code */
1184
                        if (w) w = cvt[w - 0x80];       /* Convert extended char to upper (SBCS) */
1185
#else
1186
                        w = ff_convert(ff_wtoupper(w), 0);       /* Upper converted Unicode -> OEM code */
1187
#endif
1188
                        cf |= NS_LFN;                           /* Force create LFN entry */
1189
                }
1190
 
1191
                if (_DF1S && w >= 0x100) {              /* Double byte char */
1192
                        if (i >= ni - 1) {
1193
                                cf |= NS_LOSS | NS_LFN; i = ni; continue;
1194
                        }
1195
                        dj->fn[i++] = (BYTE)(w >> 8);
1196
                } else {                                                /* Single byte char */
1197
                        if (!w || chk_chr("+,;[=]", w)) {               /* Replace illegal chars for SFN */
1198
                                w = '_'; cf |= NS_LOSS | NS_LFN;        /* Lossy conversion */
1199
                        } else {
1200
                                if (IsUpper(w)) {               /* ASCII large capital */
1201
                                        b |= 2;
1202
                                } else {
1203
                                        if (IsLower(w)) {       /* ASCII small capital */
1204
                                                b |= 1; w -= 0x20;
1205
                                        }
1206
                                }
1207
                        }
1208
                }
1209
                dj->fn[i++] = (BYTE)w;
1210
        }
1211
 
1212
        if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05;  /* If the first char collides with deleted mark, replace it with 0x05 */
1213
 
1214
        if (ni == 8) b <<= 2;
1215
        if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03)   /* Create LFN entry when there are composite capitals */
1216
                cf |= NS_LFN;
1217
        if (!(cf & NS_LFN)) {                                           /* When LFN is in 8.3 format without extended char, NT flags are created */
1218
                if ((b & 0x03) == 0x01) cf |= NS_EXT;   /* NT flag (Extension has only small capital) */
1219
                if ((b & 0x0C) == 0x04) cf |= NS_BODY;  /* NT flag (Filename has only small capital) */
1220
        }
1221
 
1222
        dj->fn[NS] = cf;        /* SFN is created */
1223
 
1224
        return FR_OK;
1225
 
1226
 
1227
#else   /* Non-LFN configuration */
1228
        BYTE b, c, d, *sfn;
1229
        int ni, si, i;
1230
        const char *p;
1231
 
1232
        /* Create file name in directory form */
1233
        sfn = dj->fn;
1234
        mem_set(sfn, ' ', 11);
1235
        si = i = b = 0; ni = 8;
1236
        p = *path;
1237
#if _FS_RPATH
1238
        if (p[si] == '.') { /* Is this a dot entry? */
1239
                for (;;) {
1240
                        c = p[si++];
1241
                        if (c != '.' || si >= 3) break;
1242
                        sfn[i++] = c;
1243
                }
1244
                if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
1245
                *path = &p[si];                                                                 /* Rerurn pointer to the next segment */
1246
                sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;       /* Set last segment flag if end of path */
1247
                return FR_OK;
1248
        }
1249
#endif
1250
        for (;;) {
1251
                c = p[si++];
1252
                if (c <= ' ' || c == '/' || c == '\\') break;   /* Break on end of segment */
1253
                if (c == '.' || i >= ni) {
1254
                        if (ni != 8 || c != '.') return FR_INVALID_NAME;
1255
                        i = 8; ni = 11;
1256
                        b <<= 2; continue;
1257
                }
1258
                if (c >= 0x80) {                                /* Extended char */
1259
#ifdef _EXCVT
1260
                        c = cvt[c - 0x80];                      /* Convert extend char (SBCS) */
1261
#else
1262
                        b |= 3;                                         /* Eliminate NT flag if ext char is exist */
1263
#if !_DF1S      /* ASCII only cfg */
1264
                        return FR_INVALID_NAME;
1265
#endif
1266
#endif
1267
                }
1268
                if (IsDBCS1(c)) {                               /* DBC 1st byte? */
1269
                        d = p[si++];                            /* Get 2nd byte */
1270
                        if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
1271
                                return FR_INVALID_NAME;
1272
                        sfn[i++] = c;
1273
                        sfn[i++] = d;
1274
                } else {                                                /* Single byte code */
1275
                        if (chk_chr(" \"*+,[=]|\x7F", c))       /* Reject illegal chrs for SFN */
1276
                                return FR_INVALID_NAME;
1277
                        if (IsUpper(c)) {                       /* ASCII large capital? */
1278
                                b |= 2;
1279
                        } else {
1280
                                if (IsLower(c)) {               /* ASCII small capital? */
1281
                                        b |= 1; c -= 0x20;
1282
                                }
1283
                        }
1284
                        sfn[i++] = c;
1285
                }
1286
        }
1287
        *path = &p[si];                                         /* Rerurn pointer to the next segment */
1288
        c = (c <= ' ') ? NS_LAST : 0;            /* Set last segment flag if end of path */
1289
 
1290
        if (!i) return FR_INVALID_NAME;         /* Reject null string */
1291
        if (sfn[0] == 0xE5) sfn[0] = 0x05;        /* When first char collides with 0xE5, replace it with 0x05 */
1292
 
1293
        if (ni == 8) b <<= 2;
1294
        if ((b & 0x03) == 0x01) c |= NS_EXT;    /* NT flag (Extension has only small capital) */
1295
        if ((b & 0x0C) == 0x04) c |= NS_BODY;   /* NT flag (Filename has only small capital) */
1296
 
1297
        sfn[NS] = c;            /* Store NT flag, File name is created */
1298
 
1299
        return FR_OK;
1300
#endif
1301
}
1302
 
1303
 
1304
 
1305
 
1306
/*-----------------------------------------------------------------------*/
1307
/* Get file information from directory entry                             */
1308
/*-----------------------------------------------------------------------*/
1309
#if _FS_MINIMIZE <= 1
1310
static
1311
void get_fileinfo (             /* No return code */
1312
        DIR *dj,                        /* Pointer to the directory object */
1313
        FILINFO *fno            /* Pointer to the file information to be filled */
1314
)
1315
{
1316
        int i;
1317
        BYTE c, nt, *dir;
1318
        char *p;
1319
 
1320
 
1321
        p = fno->fname;
1322
        if (dj->sect) {
1323
                dir = dj->dir;
1324
                nt = dir[DIR_NTres];            /* NT flag */
1325
                for (i = 0; i < 8; i++) {        /* Copy name body */
1326
                        c = dir[i];
1327
                        if (c == ' ') break;
1328
                        if (c == 0x05) c = 0xE5;
1329
                        if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
1330
                        *p++ = c;
1331
                }
1332
                if (dir[8] != ' ') {            /* Copy name extension */
1333
                        *p++ = '.';
1334
                        for (i = 8; i < 11; i++) {
1335
                                c = dir[i];
1336
                                if (c == ' ') break;
1337
                                if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
1338
                                *p++ = c;
1339
                        }
1340
                }
1341
                fno->fattrib = dir[DIR_Attr];                           /* Attribute */
1342
                fno->fsize = LD_DWORD(dir+DIR_FileSize);        /* Size */
1343
                fno->fdate = LD_WORD(dir+DIR_WrtDate);          /* Date */
1344
                fno->ftime = LD_WORD(dir+DIR_WrtTime);          /* Time */
1345
        }
1346
        *p = 0;
1347
 
1348
#if _USE_LFN
1349
        if (fno->lfname) {
1350
                XCHAR *tp = fno->lfname;
1351
                WCHAR w, *lfn;
1352
 
1353
                i = 0;
1354
                if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
1355
                        lfn = dj->lfn;
1356
                        while ((w = *lfn++) != 0) {                      /* Get an LFN char */
1357
#if !_LFN_UNICODE
1358
                                w = ff_convert(w, 0);                    /* Unicode -> OEM conversion */
1359
                                if (!w) { i = 0; break; }                /* Could not convert, no LFN */
1360
                                if (_DF1S && w >= 0x100)                /* Put 1st byte if it is a DBC */
1361
                                        tp[i++] = (XCHAR)(w >> 8);
1362
#endif
1363
                                if (i >= fno->lfsize - 1) { i = 0; break; }      /* Buffer overrun, no LFN */
1364
                                tp[i++] = (XCHAR)w;
1365
                        }
1366
                }
1367
                tp[i] = 0;       /* Terminator */
1368
        }
1369
#endif
1370
}
1371
#endif /* _FS_MINIMIZE <= 1 */
1372
 
1373
 
1374
 
1375
 
1376
/*-----------------------------------------------------------------------*/
1377
/* Follow a file path                                                    */
1378
/*-----------------------------------------------------------------------*/
1379
 
1380
static
1381
FRESULT follow_path (   /* FR_OK(0): successful, !=0: error code */
1382
        DIR *dj,                        /* Directory object to return last directory and found object */
1383
        const XCHAR *path       /* Full-path string to find a file or directory */
1384
)
1385
{
1386
        FRESULT res;
1387
        BYTE *dir, last;
1388
 
1389
 
1390
        while (!_USE_LFN && *path == ' ') path++;       /* Skip leading spaces */
1391
#if _FS_RPATH
1392
        if (*path == '/' || *path == '\\') { /* There is a heading separator */
1393
                path++; dj->sclust = 0;          /* Strip it and start from the root dir */
1394
        } else {                                                        /* No heading saparator */
1395
                dj->sclust = dj->fs->cdir;      /* Start from the current dir */
1396
        }
1397
#else
1398
        if (*path == '/' || *path == '\\')      /* Strip heading separator if exist */
1399
                path++;
1400
        dj->sclust = 0;                                          /* Start from the root dir */
1401
#endif
1402
 
1403
        if ((UINT)*path < ' ') {                        /* Null path means the start directory itself */
1404
                res = dir_seek(dj, 0);
1405
                dj->dir = NULL;
1406
 
1407
        } else {                                                        /* Follow path */
1408
                for (;;) {
1409
                        res = create_name(dj, &path);   /* Get a segment */
1410
                        if (res != FR_OK) break;
1411
                        res = dir_find(dj);                             /* Find it */
1412
                        last = *(dj->fn+NS) & NS_LAST;
1413
                        if (res != FR_OK) {                             /* Could not find the object */
1414
                                if (res == FR_NO_FILE && !last)
1415
                                        res = FR_NO_PATH;
1416
                                break;
1417
                        }
1418
                        if (last) break;                                /* Last segment match. Function completed. */
1419
                        dir = dj->dir;                                  /* There is next segment. Follow the sub directory */
1420
                        if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
1421
                                res = FR_NO_PATH; break;
1422
                        }
1423
                        dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
1424
                }
1425
        }
1426
 
1427
        return res;
1428
}
1429
 
1430
 
1431
 
1432
 
1433
/*-----------------------------------------------------------------------*/
1434
/* Load boot record and check if it is an FAT boot record                */
1435
/*-----------------------------------------------------------------------*/
1436
 
1437
static
1438
BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
1439
        FATFS *fs,      /* File system object */
1440
        DWORD sect      /* Sector# (lba) to check if it is an FAT boot record or not */
1441
)
1442
{
1443
        if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK)   /* Load boot record */
1444
                return 3;
1445
        if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)               /* Check record signature (always placed at offset 510 even if the sector size is >512) */
1446
                return 2;
1447
 
1448
        if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
1449
                return 0;
1450
        if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
1451
                return 0;
1452
 
1453
        return 1;
1454
}
1455
 
1456
 
1457
 
1458
 
1459
/*-----------------------------------------------------------------------*/
1460
/* Make sure that the file system is valid                               */
1461
/*-----------------------------------------------------------------------*/
1462
 
1463
 
1464
FRESULT chk_mounted (   /* FR_OK(0): successful, !=0: any error occured */
1465
        const XCHAR **path,     /* Pointer to pointer to the path name (drive number) */
1466
        FATFS **rfs,            /* Pointer to pointer to the found file system object */
1467
        BYTE chk_wp                     /* !=0: Check media write protection for write access */
1468
)
1469
{
1470
        BYTE fmt, *tbl;
1471
        UINT vol;
1472
        DSTATUS stat;
1473
        DWORD bsect, fsize, tsect, mclst;
1474
        const XCHAR *p = *path;
1475
        FATFS *fs;
1476
 
1477
        /* Get logical drive number from the path name */
1478
        vol = p[0] - '0';                                /* Is there a drive number? */
1479
        if (vol <= 9 && p[1] == ':') {  /* Found a drive number, get and strip it */
1480
                p += 2; *path = p;                      /* Return pointer to the path name */
1481
        } else {                                                /* No drive number is given */
1482
#if _FS_RPATH
1483
                vol = Drive;                            /* Use current drive */
1484
#else
1485
                vol = 0;                                 /* Use drive 0 */
1486
#endif
1487
        }
1488
 
1489
        /* Check if the logical drive is valid or not */
1490
        if (vol >= _DRIVES)                     /* Is the drive number valid? */
1491
                return FR_INVALID_DRIVE;
1492
        *rfs = fs = FatFs[vol];                 /* Returen pointer to the corresponding file system object */
1493
        if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
1494
 
1495
        ENTER_FF(fs);                                   /* Lock file system */
1496
 
1497
        if (fs->fs_type) {                              /* If the logical drive has been mounted */
1498
                stat = disk_status(fs->drive);
1499
                if (!(stat & STA_NOINIT)) {     /* and the physical drive is kept initialized (has not been changed), */
1500
#if !_FS_READONLY
1501
                        if (chk_wp && (stat & STA_PROTECT))     /* Check write protection if needed */
1502
                                return FR_WRITE_PROTECTED;
1503
#endif
1504
                        return FR_OK;                   /* The file system object is valid */
1505
                }
1506
        }
1507
 
1508
        /* The logical drive must be mounted. Following code attempts to mount the volume */
1509
 
1510
        fs->fs_type = 0;                                 /* Clear the file system object */
1511
        fs->drive = (BYTE)LD2PD(vol);           /* Bind the logical drive and a physical drive */
1512
        stat = disk_initialize(fs->drive);      /* Initialize low level disk I/O layer */
1513
        if (stat & STA_NOINIT)                          /* Check if the drive is ready */
1514
                return FR_NOT_READY;
1515
#if _MAX_SS != 512                                              /* Get disk sector size if needed */
1516
        if (disk_ioctl(fs->drive, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
1517
                return FR_NO_FILESYSTEM;
1518
#endif
1519
#if !_FS_READONLY
1520
        if (chk_wp && (stat & STA_PROTECT))     /* Check disk write protection if needed */
1521
                return FR_WRITE_PROTECTED;
1522
#endif
1523
        /* Search FAT partition on the drive */
1524
        fmt = check_fs(fs, bsect = 0);           /* Check sector 0 as an SFD format */
1525
        if (fmt == 1) {                                         /* Not an FAT boot record, it may be patitioned */
1526
                /* Check a partition listed in top of the partition table */
1527
                tbl = &fs->win[MBR_Table + LD2PT(vol) * 16];    /* Partition table */
1528
                if (tbl[4]) {                                                                   /* Is the partition existing? */
1529
                        bsect = LD_DWORD(&tbl[8]);                                      /* Partition offset in LBA */
1530
                        fmt = check_fs(fs, bsect);                                      /* Check the partition */
1531
                }
1532
        }
1533
        if (fmt == 3) return FR_DISK_ERR;
1534
        if (fmt || LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))   /* No valid FAT patition is found */
1535
                return FR_NO_FILESYSTEM;
1536
 
1537
        /* Initialize the file system object */
1538
        fsize = LD_WORD(fs->win+BPB_FATSz16);                           /* Number of sectors per FAT */
1539
        if (!fsize) fsize = LD_DWORD(fs->win+BPB_FATSz32);
1540
        fs->sects_fat = fsize;
1541
        fs->n_fats = fs->win[BPB_NumFATs];                                      /* Number of FAT copies */
1542
        fsize *= fs->n_fats;                                                            /* (Number of sectors in FAT area) */
1543
        fs->fatbase = bsect + LD_WORD(fs->win+BPB_RsvdSecCnt); /* FAT start sector (lba) */
1544
        fs->csize = fs->win[BPB_SecPerClus];                            /* Number of sectors per cluster */
1545
        fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);        /* Nmuber of root directory entries */
1546
        tsect = LD_WORD(fs->win+BPB_TotSec16);                          /* Number of sectors on the volume */
1547
        if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
1548
        fs->max_clust = mclst = (tsect                                          /* Last cluster# + 1 (Number of clusters + 2) */
1549
                - LD_WORD(fs->win+BPB_RsvdSecCnt) - fsize - fs->n_rootdir / (SS(fs)/32)
1550
                ) / fs->csize + 2;
1551
 
1552
        fmt = FS_FAT12;                                                                         /* Determine the FAT sub type */
1553
        if (mclst >= 0xFF7) fmt = FS_FAT16;                                     /* Number of clusters >= 0xFF5 */
1554
        if (mclst >= 0xFFF7) fmt = FS_FAT32;                            /* Number of clusters >= 0xFFF5 */
1555
 
1556
        if (fmt == FS_FAT32)
1557
                fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);   /* Root directory start cluster */
1558
        else
1559
                fs->dirbase = fs->fatbase + fsize;                              /* Root directory start sector (lba) */
1560
        fs->database = fs->fatbase + fsize + fs->n_rootdir / (SS(fs)/32);       /* Data start sector (lba) */
1561
 
1562
#if !_FS_READONLY
1563
        /* Initialize allocation information */
1564
        fs->free_clust = 0xFFFFFFFF;
1565
        fs->wflag = 0;
1566
        /* Get fsinfo if needed */
1567
        if (fmt == FS_FAT32) {
1568
                fs->fsi_flag = 0;
1569
                fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
1570
                if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
1571
                        LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
1572
                        LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
1573
                        LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
1574
                        fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
1575
                        fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
1576
                }
1577
        }
1578
#endif
1579
        fs->fs_type = fmt;              /* FAT sub-type */
1580
        fs->winsect = 0;         /* Invalidate sector cache */
1581
#if _FS_RPATH
1582
        fs->cdir = 0;                    /* Current directory (root dir) */
1583
#endif
1584
        fs->id = ++Fsid;                /* File system mount ID */
1585
 
1586
        return FR_OK;
1587
}
1588
 
1589
 
1590
 
1591
 
1592
/*-----------------------------------------------------------------------*/
1593
/* Check if the file/dir object is valid or not                          */
1594
/*-----------------------------------------------------------------------*/
1595
 
1596
static
1597
FRESULT validate (      /* FR_OK(0): The object is valid, !=0: Invalid */
1598
        FATFS *fs,              /* Pointer to the file system object */
1599
        WORD id                 /* Member id of the target object to be checked */
1600
)
1601
{
1602
        if (!fs || !fs->fs_type || fs->id != id)
1603
                return FR_INVALID_OBJECT;
1604
 
1605
        ENTER_FF(fs);           /* Lock file system */
1606
 
1607
        if (disk_status(fs->drive) & STA_NOINIT)
1608
                return FR_NOT_READY;
1609
 
1610
        return FR_OK;
1611
}
1612
 
1613
 
1614
 
1615
 
1616
/*--------------------------------------------------------------------------
1617
 
1618
   Public Functions
1619
 
1620
--------------------------------------------------------------------------*/
1621
 
1622
 
1623
 
1624
/*-----------------------------------------------------------------------*/
1625
/* Mount/Unmount a Locical Drive                                         */
1626
/*-----------------------------------------------------------------------*/
1627
 
1628
FRESULT f_mount (
1629
        BYTE vol,               /* Logical drive number to be mounted/unmounted */
1630
        FATFS *fs               /* Pointer to new file system object (NULL for unmount)*/
1631
)
1632
{
1633
        FATFS *rfs;
1634
 
1635
 
1636
        if (vol >= _DRIVES)                             /* Check if the drive number is valid */
1637
                return FR_INVALID_DRIVE;
1638
        rfs = FatFs[vol];                               /* Get current fs object */
1639
 
1640
        if (rfs) {
1641
#if _FS_REENTRANT                                       /* Discard sync object of the current volume */
1642
                if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
1643
#endif
1644
                rfs->fs_type = 0;                        /* Clear old fs object */
1645
        }
1646
 
1647
        if (fs) {
1648
                fs->fs_type = 0;                 /* Clear new fs object */
1649
#if _FS_REENTRANT                                       /* Create sync object for the new volume */
1650
                if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
1651
#endif
1652
        }
1653
        FatFs[vol] = fs;                                /* Register new fs object */
1654
 
1655
        return FR_OK;
1656
}
1657
 
1658
 
1659
 
1660
 
1661
/*-----------------------------------------------------------------------*/
1662
/* Open or Create a File                                                 */
1663
/*-----------------------------------------------------------------------*/
1664
 
1665
FRESULT f_open (
1666
        FIL *fp,                        /* Pointer to the blank file object */
1667
        const XCHAR *path,      /* Pointer to the file name */
1668
        BYTE mode                       /* Access mode and file open mode flags */
1669
)
1670
{
1671
        FRESULT res;
1672
        DIR dj;
1673
        NAMEBUF(sfn, lfn);
1674
        BYTE *dir;
1675
 
1676
 
1677
        fp->fs = NULL;          /* Clear file object */
1678
#if !_FS_READONLY
1679
        mode &= (FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW);
1680
        res = chk_mounted(&path, &dj.fs, (BYTE)(mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)));
1681
#else
1682
        mode &= FA_READ;
1683
        res = chk_mounted(&path, &dj.fs, 0);
1684
#endif
1685
        if (res != FR_OK) LEAVE_FF(dj.fs, res);
1686
        INITBUF(dj, sfn, lfn);
1687
        res = follow_path(&dj, path);   /* Follow the file path */
1688
 
1689
#if !_FS_READONLY
1690
        /* Create or Open a file */
1691
        if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
1692
                DWORD ps, cl;
1693
 
1694
                if (res != FR_OK) {                     /* No file, create new */
1695
                        if (res == FR_NO_FILE)  /* There is no file to open, create a new entry */
1696
                                res = dir_register(&dj);
1697
                        if (res != FR_OK) LEAVE_FF(dj.fs, res);
1698
                        mode |= FA_CREATE_ALWAYS;
1699
                        dir = dj.dir;                   /* Created entry (SFN entry) */
1700
                }
1701
                else {                                          /* Any object is already existing */
1702
                        if (mode & FA_CREATE_NEW)                       /* Cannot create new */
1703
                                LEAVE_FF(dj.fs, FR_EXIST);
1704
                        dir = dj.dir;
1705
                        if (!dir || (dir[DIR_Attr] & (AM_RDO | AM_DIR)))        /* Cannot overwrite it (R/O or DIR) */
1706
                                LEAVE_FF(dj.fs, FR_DENIED);
1707
                        if (mode & FA_CREATE_ALWAYS) {          /* Resize it to zero on over write mode */
1708
                                cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);    /* Get start cluster */
1709
                                ST_WORD(dir+DIR_FstClusHI, 0);   /* cluster = 0 */
1710
                                ST_WORD(dir+DIR_FstClusLO, 0);
1711
                                ST_DWORD(dir+DIR_FileSize, 0);   /* size = 0 */
1712
                                dj.fs->wflag = 1;
1713
                                ps = dj.fs->winsect;                    /* Remove the cluster chain */
1714
                                if (cl) {
1715
                                        res = remove_chain(dj.fs, cl);
1716
                                        if (res) LEAVE_FF(dj.fs, res);
1717
                                        dj.fs->last_clust = cl - 1;     /* Reuse the cluster hole */
1718
                                }
1719
                                res = move_window(dj.fs, ps);
1720
                                if (res != FR_OK) LEAVE_FF(dj.fs, res);
1721
                        }
1722
                }
1723
                if (mode & FA_CREATE_ALWAYS) {
1724
                        dir[DIR_Attr] = 0;                                       /* Reset attribute */
1725
                        ps = get_fattime();
1726
                        ST_DWORD(dir+DIR_CrtTime, ps);          /* Created time */
1727
                        dj.fs->wflag = 1;
1728
                        mode |= FA__WRITTEN;                            /* Set file changed flag */
1729
                }
1730
        }
1731
        /* Open an existing file */
1732
        else {
1733
#endif /* !_FS_READONLY */
1734
                if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
1735
                dir = dj.dir;
1736
                if (!dir || (dir[DIR_Attr] & AM_DIR))   /* It is a directory */
1737
                        LEAVE_FF(dj.fs, FR_NO_FILE);
1738
#if !_FS_READONLY
1739
                if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
1740
                        LEAVE_FF(dj.fs, FR_DENIED);
1741
        }
1742
        fp->dir_sect = dj.fs->winsect;          /* Pointer to the directory entry */
1743
        fp->dir_ptr = dj.dir;
1744
#endif
1745
        fp->flag = mode;                                        /* File access mode */
1746
        fp->org_clust =                                         /* File start cluster */
1747
                ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
1748
        fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
1749
        fp->fptr = 0; fp->csect = 255;           /* File pointer */
1750
        fp->dsect = 0;
1751
        fp->fs = dj.fs; fp->id = dj.fs->id;     /* Owner file system object of the file */
1752
 
1753
        LEAVE_FF(dj.fs, FR_OK);
1754
}
1755
 
1756
 
1757
 
1758
 
1759
/*-----------------------------------------------------------------------*/
1760
/* Read File                                                             */
1761
/*-----------------------------------------------------------------------*/
1762
 
1763
FRESULT f_read (
1764
        FIL *fp,                /* Pointer to the file object */
1765
        void *buff,             /* Pointer to data buffer */
1766
        UINT btr,               /* Number of bytes to read */
1767
        UINT *br                /* Pointer to number of bytes read */
1768
)
1769
{
1770
        FRESULT res;
1771
        DWORD clst, sect, remain;
1772
        UINT rcnt, cc;
1773
        BYTE *rbuff = buff;
1774
 
1775
 
1776
        *br = 0; /* Initialize bytes read */
1777
 
1778
        res = validate(fp->fs, fp->id);                                 /* Check validity of the object */
1779
        if (res != FR_OK) LEAVE_FF(fp->fs, res);
1780
        if (fp->flag & FA__ERROR)                                               /* Check abort flag */
1781
                LEAVE_FF(fp->fs, FR_INT_ERR);
1782
        if (!(fp->flag & FA_READ))                                              /* Check access mode */
1783
                LEAVE_FF(fp->fs, FR_DENIED);
1784
        remain = fp->fsize - fp->fptr;
1785
        if (btr > remain) btr = (UINT)remain;                   /* Truncate btr by remaining bytes */
1786
 
1787
        for ( ;  btr;                                                                   /* Repeat until all data transferred */
1788
                rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
1789
                if ((fp->fptr % SS(fp->fs)) == 0) {                      /* On the sector boundary? */
1790
                        if (fp->csect >= fp->fs->csize) {               /* On the cluster boundary? */
1791
                                clst = (fp->fptr == 0) ?                 /* On the top of the file? */
1792
                                        fp->org_clust : get_fat(fp->fs, fp->curr_clust);
1793
                                if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
1794
                                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
1795
                                fp->curr_clust = clst;                          /* Update current cluster */
1796
                                fp->csect = 0;                                           /* Reset sector offset in the cluster */
1797
                        }
1798
                        sect = clust2sect(fp->fs, fp->curr_clust);      /* Get current sector */
1799
                        if (!sect) ABORT(fp->fs, FR_INT_ERR);
1800
                        sect += fp->csect;
1801
                        cc = btr / SS(fp->fs);                                  /* When remaining bytes >= sector size, */
1802
                        if (cc) {                                                               /* Read maximum contiguous sectors directly */
1803
                                if (fp->csect + cc > fp->fs->csize)     /* Clip at cluster boundary */
1804
                                        cc = fp->fs->csize - fp->csect;
1805
                                if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
1806
                                        ABORT(fp->fs, FR_DISK_ERR);
1807
#if !_FS_READONLY && _FS_MINIMIZE <= 2
1808
#if _FS_TINY
1809
                                if (fp->fs->wflag && fp->fs->winsect - sect < cc)               /* Replace one of the read sectors with cached data if it contains a dirty sector */
1810
                                        mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
1811
#else
1812
                                if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)    /* Replace one of the read sectors with cached data if it contains a dirty sector */
1813
                                        mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
1814
#endif
1815
#endif
1816
                                fp->csect += (BYTE)cc;                          /* Next sector address in the cluster */
1817
                                rcnt = SS(fp->fs) * cc;                         /* Number of bytes transferred */
1818
                                continue;
1819
                        }
1820
#if !_FS_TINY
1821
#if !_FS_READONLY
1822
                        if (fp->flag & FA__DIRTY) {                     /* Write sector I/O buffer if needed */
1823
                                if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
1824
                                        ABORT(fp->fs, FR_DISK_ERR);
1825
                                fp->flag &= ~FA__DIRTY;
1826
                        }
1827
#endif
1828
                        if (fp->dsect != sect) {                        /* Fill sector buffer with file data */
1829
                                if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
1830
                                        ABORT(fp->fs, FR_DISK_ERR);
1831
                        }
1832
#endif
1833
                        fp->dsect = sect;
1834
                        fp->csect++;                                                    /* Next sector address in the cluster */
1835
                }
1836
                rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Get partial sector data from sector buffer */
1837
                if (rcnt > btr) rcnt = btr;
1838
#if _FS_TINY
1839
                if (move_window(fp->fs, fp->dsect))                     /* Move sector window */
1840
                        ABORT(fp->fs, FR_DISK_ERR);
1841
                mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt);      /* Pick partial sector */
1842
#else
1843
                mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt);  /* Pick partial sector */
1844
#endif
1845
        }
1846
 
1847
        LEAVE_FF(fp->fs, FR_OK);
1848
}
1849
 
1850
 
1851
 
1852
 
1853
#if !_FS_READONLY
1854
/*-----------------------------------------------------------------------*/
1855
/* Write File                                                            */
1856
/*-----------------------------------------------------------------------*/
1857
 
1858
FRESULT f_write (
1859
        FIL *fp,                        /* Pointer to the file object */
1860
        const void *buff,       /* Pointer to the data to be written */
1861
        UINT btw,                       /* Number of bytes to write */
1862
        UINT *bw                        /* Pointer to number of bytes written */
1863
)
1864
{
1865
        FRESULT res;
1866
        DWORD clst, sect;
1867
        UINT wcnt, cc;
1868
        const BYTE *wbuff = buff;
1869
 
1870
 
1871
        *bw = 0; /* Initialize bytes written */
1872
 
1873
        res = validate(fp->fs, fp->id);                                 /* Check validity of the object */
1874
        if (res != FR_OK) LEAVE_FF(fp->fs, res);
1875
        if (fp->flag & FA__ERROR)                                               /* Check abort flag */
1876
                LEAVE_FF(fp->fs, FR_INT_ERR);
1877
        if (!(fp->flag & FA_WRITE))                                             /* Check access mode */
1878
                LEAVE_FF(fp->fs, FR_DENIED);
1879
        if (fp->fsize + btw < fp->fsize) btw = 0;                /* File size cannot reach 4GB */
1880
 
1881
        for ( ;  btw;                                                                   /* Repeat until all data transferred */
1882
                wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
1883
                if ((fp->fptr % SS(fp->fs)) == 0) {                      /* On the sector boundary? */
1884
                        if (fp->csect >= fp->fs->csize) {               /* On the cluster boundary? */
1885
                                if (fp->fptr == 0) {                             /* On the top of the file? */
1886
                                        clst = fp->org_clust;                   /* Follow from the origin */
1887
                                        if (clst == 0)                                   /* When there is no cluster chain, */
1888
                                                fp->org_clust = clst = create_chain(fp->fs, 0);  /* Create a new cluster chain */
1889
                                } else {                                                        /* Middle or end of the file */
1890
                                        clst = create_chain(fp->fs, fp->curr_clust);                    /* Follow or streach cluster chain */
1891
                                }
1892
                                if (clst == 0) break;                            /* Could not allocate a new cluster (disk full) */
1893
                                if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
1894
                                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
1895
                                fp->curr_clust = clst;                          /* Update current cluster */
1896
                                fp->csect = 0;                                           /* Reset sector address in the cluster */
1897
                        }
1898
#if _FS_TINY
1899
                        if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0))      /* Write back data buffer prior to following direct transfer */
1900
                                ABORT(fp->fs, FR_DISK_ERR);
1901
#else
1902
                        if (fp->flag & FA__DIRTY) {             /* Write back data buffer prior to following direct transfer */
1903
                                if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
1904
                                        ABORT(fp->fs, FR_DISK_ERR);
1905
                                fp->flag &= ~FA__DIRTY;
1906
                        }
1907
#endif
1908
                        sect = clust2sect(fp->fs, fp->curr_clust);      /* Get current sector */
1909
                        if (!sect) ABORT(fp->fs, FR_INT_ERR);
1910
                        sect += fp->csect;
1911
                        cc = btw / SS(fp->fs);                                  /* When remaining bytes >= sector size, */
1912
                        if (cc) {                                                               /* Write maximum contiguous sectors directly */
1913
                                if (fp->csect + cc > fp->fs->csize)     /* Clip at cluster boundary */
1914
                                        cc = fp->fs->csize - fp->csect;
1915
                                if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK)
1916
                                        ABORT(fp->fs, FR_DISK_ERR);
1917
#if _FS_TINY
1918
                                if (fp->fs->winsect - sect < cc) {      /* Refill sector cache if it gets dirty by the direct write */
1919
                                        mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
1920
                                        fp->fs->wflag = 0;
1921
                                }
1922
#else
1923
                                if (fp->dsect - sect < cc) {            /* Refill sector cache if it gets dirty by the direct write */
1924
                                        mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
1925
                                        fp->flag &= ~FA__DIRTY;
1926
                                }
1927
#endif
1928
                                fp->csect += (BYTE)cc;                          /* Next sector address in the cluster */
1929
                                wcnt = SS(fp->fs) * cc;                         /* Number of bytes transferred */
1930
                                continue;
1931
                        }
1932
#if _FS_TINY
1933
                        if (fp->fptr >= fp->fsize) {                    /* Avoid silly buffer filling at growing edge */
1934
                                if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
1935
                                fp->fs->winsect = sect;
1936
                        }
1937
#else
1938
                        if (fp->dsect != sect) {                                /* Fill sector buffer with file data */
1939
                                if (fp->fptr < fp->fsize &&
1940
                                        disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
1941
                                                ABORT(fp->fs, FR_DISK_ERR);
1942
                        }
1943
#endif
1944
                        fp->dsect = sect;
1945
                        fp->csect++;                                                    /* Next sector address in the cluster */
1946
                }
1947
                wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Put partial sector into file I/O buffer */
1948
                if (wcnt > btw) wcnt = btw;
1949
#if _FS_TINY
1950
                if (move_window(fp->fs, fp->dsect))                     /* Move sector window */
1951
                        ABORT(fp->fs, FR_DISK_ERR);
1952
                mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt);      /* Fit partial sector */
1953
                fp->fs->wflag = 1;
1954
#else
1955
                mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt);  /* Fit partial sector */
1956
                fp->flag |= FA__DIRTY;
1957
#endif
1958
        }
1959
 
1960
        if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
1961
        fp->flag |= FA__WRITTEN;                                                /* Set file changed flag */
1962
 
1963
        LEAVE_FF(fp->fs, FR_OK);
1964
}
1965
 
1966
 
1967
 
1968
 
1969
/*-----------------------------------------------------------------------*/
1970
/* Synchronize the File Object                                           */
1971
/*-----------------------------------------------------------------------*/
1972
 
1973
FRESULT f_sync (
1974
        FIL *fp         /* Pointer to the file object */
1975
)
1976
{
1977
        FRESULT res;
1978
        DWORD tim;
1979
        BYTE *dir;
1980
 
1981
 
1982
        res = validate(fp->fs, fp->id);         /* Check validity of the object */
1983
        if (res == FR_OK) {
1984
                if (fp->flag & FA__WRITTEN) {   /* Has the file been written? */
1985
#if !_FS_TINY   /* Write-back dirty buffer */
1986
                        if (fp->flag & FA__DIRTY) {
1987
                                if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
1988
                                        LEAVE_FF(fp->fs, FR_DISK_ERR);
1989
                                fp->flag &= ~FA__DIRTY;
1990
                        }
1991
#endif
1992
                        /* Update the directory entry */
1993
                        res = move_window(fp->fs, fp->dir_sect);
1994
                        if (res == FR_OK) {
1995
                                dir = fp->dir_ptr;
1996
                                dir[DIR_Attr] |= AM_ARC;                                        /* Set archive bit */
1997
                                ST_DWORD(dir+DIR_FileSize, fp->fsize);          /* Update file size */
1998
                                ST_WORD(dir+DIR_FstClusLO, fp->org_clust);      /* Update start cluster */
1999
                                ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16);
2000
                                tim = get_fattime();                    /* Updated time */
2001
                                ST_DWORD(dir+DIR_WrtTime, tim);
2002
                                fp->flag &= ~FA__WRITTEN;
2003
                                fp->fs->wflag = 1;
2004
                                res = sync(fp->fs);
2005
                        }
2006
                }
2007
        }
2008
 
2009
        LEAVE_FF(fp->fs, res);
2010
}
2011
 
2012
#endif /* !_FS_READONLY */
2013
 
2014
 
2015
 
2016
 
2017
/*-----------------------------------------------------------------------*/
2018
/* Close File                                                            */
2019
/*-----------------------------------------------------------------------*/
2020
 
2021
FRESULT f_close (
2022
        FIL *fp         /* Pointer to the file object to be closed */
2023
)
2024
{
2025
        FRESULT res;
2026
 
2027
 
2028
#if _FS_READONLY
2029
        res = validate(fp->fs, fp->id);
2030
        if (res == FR_OK) fp->fs = NULL;
2031
        LEAVE_FF(fp->fs, res);
2032
#else
2033
        res = f_sync(fp);
2034
        if (res == FR_OK) fp->fs = NULL;
2035
        return res;
2036
#endif
2037
}
2038
 
2039
 
2040
 
2041
 
2042
/*-----------------------------------------------------------------------*/
2043
/* Change Current Drive/Directory                                        */
2044
/*-----------------------------------------------------------------------*/
2045
 
2046
#if _FS_RPATH
2047
 
2048
FRESULT f_chdrive (
2049
        BYTE drv                /* Drive number */
2050
)
2051
{
2052
        if (drv >= _DRIVES) return FR_INVALID_DRIVE;
2053
 
2054
        Drive = drv;
2055
 
2056
        return FR_OK;
2057
}
2058
 
2059
 
2060
 
2061
 
2062
FRESULT f_chdir (
2063
        const XCHAR *path       /* Pointer to the directory path */
2064
)
2065
{
2066
        FRESULT res;
2067
        DIR dj;
2068
        NAMEBUF(sfn, lfn);
2069
        BYTE *dir;
2070
 
2071
 
2072
        res = chk_mounted(&path, &dj.fs, 0);
2073
        if (res == FR_OK) {
2074
                INITBUF(dj, sfn, lfn);
2075
                res = follow_path(&dj, path);           /* Follow the file path */
2076
                if (res == FR_OK) {                                     /* Follow completed */
2077
                        dir = dj.dir;                                   /* Pointer to the entry */
2078
                        if (!dir) {
2079
                                dj.fs->cdir = 0;                 /* No entry (root dir) */
2080
                        } else {
2081
                                if (dir[DIR_Attr] & AM_DIR)     /* Reached to the dir */
2082
                                        dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
2083
                                else
2084
                                        res = FR_NO_PATH;               /* Could not reach the dir (it is a file) */
2085
                        }
2086
                }
2087
                if (res == FR_NO_FILE) res = FR_NO_PATH;
2088
        }
2089
 
2090
        LEAVE_FF(dj.fs, res);
2091
}
2092
 
2093
#endif
2094
 
2095
 
2096
 
2097
#if _FS_MINIMIZE <= 2
2098
/*-----------------------------------------------------------------------*/
2099
/* Seek File R/W Pointer                                                 */
2100
/*-----------------------------------------------------------------------*/
2101
 
2102
FRESULT f_lseek (
2103
        FIL *fp,                /* Pointer to the file object */
2104
        DWORD ofs               /* File pointer from top of file */
2105
)
2106
{
2107
        FRESULT res;
2108
        DWORD clst, bcs, nsect, ifptr;
2109
 
2110
 
2111
        res = validate(fp->fs, fp->id);         /* Check validity of the object */
2112
        if (res != FR_OK) LEAVE_FF(fp->fs, res);
2113
        if (fp->flag & FA__ERROR)                       /* Check abort flag */
2114
                LEAVE_FF(fp->fs, FR_INT_ERR);
2115
        if (ofs > fp->fsize                                     /* In read-only mode, clip offset with the file size */
2116
#if !_FS_READONLY
2117
                 && !(fp->flag & FA_WRITE)
2118
#endif
2119
                ) ofs = fp->fsize;
2120
 
2121
        ifptr = fp->fptr;
2122
        fp->fptr = nsect = 0; fp->csect = 255;
2123
        if (ofs > 0) {
2124
                bcs = (DWORD)fp->fs->csize * SS(fp->fs);        /* Cluster size (byte) */
2125
                if (ifptr > 0 &&
2126
                        (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
2127
                        fp->fptr = (ifptr - 1) & ~(bcs - 1);    /* start from the current cluster */
2128
                        ofs -= fp->fptr;
2129
                        clst = fp->curr_clust;
2130
                } else {                                                                        /* When seek to back cluster, */
2131
                        clst = fp->org_clust;                                   /* start from the first cluster */
2132
#if !_FS_READONLY
2133
                        if (clst == 0) {                                         /* If no cluster chain, create a new chain */
2134
                                clst = create_chain(fp->fs, 0);
2135
                                if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
2136
                                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2137
                                fp->org_clust = clst;
2138
                        }
2139
#endif
2140
                        fp->curr_clust = clst;
2141
                }
2142
                if (clst != 0) {
2143
                        while (ofs > bcs) {                                             /* Cluster following loop */
2144
#if !_FS_READONLY
2145
                                if (fp->flag & FA_WRITE) {                      /* Check if in write mode or not */
2146
                                        clst = create_chain(fp->fs, clst);      /* Force streached if in write mode */
2147
                                        if (clst == 0) {                         /* When disk gets full, clip file size */
2148
                                                ofs = bcs; break;
2149
                                        }
2150
                                } else
2151
#endif
2152
                                        clst = get_fat(fp->fs, clst);   /* Follow cluster chain if not in write mode */
2153
                                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2154
                                if (clst <= 1 || clst >= fp->fs->max_clust) ABORT(fp->fs, FR_INT_ERR);
2155
                                fp->curr_clust = clst;
2156
                                fp->fptr += bcs;
2157
                                ofs -= bcs;
2158
                        }
2159
                        fp->fptr += ofs;
2160
                        fp->csect = (BYTE)(ofs / SS(fp->fs));   /* Sector offset in the cluster */
2161
                        if (ofs % SS(fp->fs)) {
2162
                                nsect = clust2sect(fp->fs, clst);       /* Current sector */
2163
                                if (!nsect) ABORT(fp->fs, FR_INT_ERR);
2164
                                nsect += fp->csect;
2165
                                fp->csect++;
2166
                        }
2167
                }
2168
        }
2169
        if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
2170
#if !_FS_TINY
2171
#if !_FS_READONLY
2172
                if (fp->flag & FA__DIRTY) {                     /* Write-back dirty buffer if needed */
2173
                        if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
2174
                                ABORT(fp->fs, FR_DISK_ERR);
2175
                        fp->flag &= ~FA__DIRTY;
2176
                }
2177
#endif
2178
                if (disk_read(fp->fs->drive, fp->buf, nsect, 1) != RES_OK)
2179
                        ABORT(fp->fs, FR_DISK_ERR);
2180
#endif
2181
                fp->dsect = nsect;
2182
        }
2183
#if !_FS_READONLY
2184
        if (fp->fptr > fp->fsize) {                     /* Set changed flag if the file size is extended */
2185
                fp->fsize = fp->fptr;
2186
                fp->flag |= FA__WRITTEN;
2187
        }
2188
#endif
2189
 
2190
        LEAVE_FF(fp->fs, res);
2191
}
2192
 
2193
 
2194
 
2195
 
2196
#if _FS_MINIMIZE <= 1
2197
/*-----------------------------------------------------------------------*/
2198
/* Create a Directroy Object                                             */
2199
/*-----------------------------------------------------------------------*/
2200
 
2201
FRESULT f_opendir (
2202
        DIR *dj,                        /* Pointer to directory object to create */
2203
        const XCHAR *path       /* Pointer to the directory path */
2204
)
2205
{
2206
        FRESULT res;
2207
        NAMEBUF(sfn, lfn);
2208
        BYTE *dir;
2209
 
2210
 
2211
        res = chk_mounted(&path, &dj->fs, 0);
2212
        if (res == FR_OK) {
2213
                INITBUF((*dj), sfn, lfn);
2214
                res = follow_path(dj, path);                    /* Follow the path to the directory */
2215
                if (res == FR_OK) {                                             /* Follow completed */
2216
                        dir = dj->dir;
2217
                        if (dir) {                                                      /* It is not the root dir */
2218
                                if (dir[DIR_Attr] & AM_DIR) {   /* The object is a directory */
2219
                                        dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
2220
                                } else {                                                /* The object is not a directory */
2221
                                        res = FR_NO_PATH;
2222
                                }
2223
                        }
2224
                        if (res == FR_OK) {
2225
                                dj->id = dj->fs->id;
2226
                                res = dir_seek(dj, 0);                   /* Rewind dir */
2227
                        }
2228
                }
2229
                if (res == FR_NO_FILE) res = FR_NO_PATH;
2230
        }
2231
 
2232
        LEAVE_FF(dj->fs, res);
2233
}
2234
 
2235
 
2236
 
2237
 
2238
/*-----------------------------------------------------------------------*/
2239
/* Read Directory Entry in Sequense                                      */
2240
/*-----------------------------------------------------------------------*/
2241
 
2242
FRESULT f_readdir (
2243
        DIR *dj,                        /* Pointer to the open directory object */
2244
        FILINFO *fno            /* Pointer to file information to return */
2245
)
2246
{
2247
        FRESULT res;
2248
        NAMEBUF(sfn, lfn);
2249
 
2250
 
2251
        res = validate(dj->fs, dj->id);                 /* Check validity of the object */
2252
        if (res == FR_OK) {
2253
                INITBUF((*dj), sfn, lfn);
2254
                if (!fno) {
2255
                        res = dir_seek(dj, 0);
2256
                } else {
2257
                        res = dir_read(dj);
2258
                        if (res == FR_NO_FILE) {
2259
                                dj->sect = 0;
2260
                                res = FR_OK;
2261
                        }
2262
                        if (res == FR_OK) {                             /* A valid entry is found */
2263
                                get_fileinfo(dj, fno);          /* Get the object information */
2264
                                res = dir_next(dj, FALSE);      /* Increment index for next */
2265
                                if (res == FR_NO_FILE) {
2266
                                        dj->sect = 0;
2267
                                        res = FR_OK;
2268
                                }
2269
                        }
2270
                }
2271
        }
2272
 
2273
        LEAVE_FF(dj->fs, res);
2274
}
2275
 
2276
 
2277
 
2278
#if _FS_MINIMIZE == 0
2279
/*-----------------------------------------------------------------------*/
2280
/* Get File Status                                                       */
2281
/*-----------------------------------------------------------------------*/
2282
 
2283
FRESULT f_stat (
2284
        const XCHAR *path,      /* Pointer to the file path */
2285
        FILINFO *fno            /* Pointer to file information to return */
2286
)
2287
{
2288
        FRESULT res;
2289
        DIR dj;
2290
        NAMEBUF(sfn, lfn);
2291
 
2292
 
2293
        res = chk_mounted(&path, &dj.fs, 0);
2294
        if (res == FR_OK) {
2295
                INITBUF(dj, sfn, lfn);
2296
                res = follow_path(&dj, path);   /* Follow the file path */
2297
                if (res == FR_OK) {                             /* Follwo completed */
2298
                        if (dj.dir)     /* Found an object */
2299
                                get_fileinfo(&dj, fno);
2300
                        else            /* It is root dir */
2301
                                res = FR_INVALID_NAME;
2302
                }
2303
        }
2304
 
2305
        LEAVE_FF(dj.fs, res);
2306
}
2307
 
2308
 
2309
 
2310
#if !_FS_READONLY
2311
/*-----------------------------------------------------------------------*/
2312
/* Get Number of Free Clusters                                           */
2313
/*-----------------------------------------------------------------------*/
2314
 
2315
FRESULT f_getfree (
2316
        const XCHAR *path,      /* Pointer to the logical drive number (root dir) */
2317
        DWORD *nclst,           /* Pointer to the variable to return number of free clusters */
2318
        FATFS **fatfs           /* Pointer to pointer to corresponding file system object to return */
2319
)
2320
{
2321
        FRESULT res;
2322
        DWORD n, clst, sect, stat;
2323
        UINT i;
2324
        BYTE fat, *p;
2325
 
2326
 
2327
        /* Get drive number */
2328
        res = chk_mounted(&path, fatfs, 0);
2329
        if (res != FR_OK) LEAVE_FF(*fatfs, res);
2330
 
2331
        /* If number of free cluster is valid, return it without cluster scan. */
2332
        if ((*fatfs)->free_clust <= (*fatfs)->max_clust - 2) {
2333
                *nclst = (*fatfs)->free_clust;
2334
                LEAVE_FF(*fatfs, FR_OK);
2335
        }
2336
 
2337
        /* Get number of free clusters */
2338
        fat = (*fatfs)->fs_type;
2339
        n = 0;
2340
        if (fat == FS_FAT12) {
2341
                clst = 2;
2342
                do {
2343
                        stat = get_fat(*fatfs, clst);
2344
                        if (stat == 0xFFFFFFFF) LEAVE_FF(*fatfs, FR_DISK_ERR);
2345
                        if (stat == 1) LEAVE_FF(*fatfs, FR_INT_ERR);
2346
                        if (stat == 0) n++;
2347
                } while (++clst < (*fatfs)->max_clust);
2348
        } else {
2349
                clst = (*fatfs)->max_clust;
2350
                sect = (*fatfs)->fatbase;
2351
                i = 0; p = 0;
2352
                do {
2353
                        if (!i) {
2354
                                res = move_window(*fatfs, sect++);
2355
                                if (res != FR_OK)
2356
                                        LEAVE_FF(*fatfs, res);
2357
                                p = (*fatfs)->win;
2358
                                i = SS(*fatfs);
2359
                        }
2360
                        if (fat == FS_FAT16) {
2361
                                if (LD_WORD(p) == 0) n++;
2362
                                p += 2; i -= 2;
2363
                        } else {
2364
                                if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
2365
                                p += 4; i -= 4;
2366
                        }
2367
                } while (--clst);
2368
        }
2369
        (*fatfs)->free_clust = n;
2370
        if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
2371
        *nclst = n;
2372
 
2373
        LEAVE_FF(*fatfs, FR_OK);
2374
}
2375
 
2376
 
2377
 
2378
 
2379
/*-----------------------------------------------------------------------*/
2380
/* Truncate File                                                         */
2381
/*-----------------------------------------------------------------------*/
2382
 
2383
FRESULT f_truncate (
2384
        FIL *fp         /* Pointer to the file object */
2385
)
2386
{
2387
        FRESULT res;
2388
        DWORD ncl;
2389
 
2390
 
2391
        res = validate(fp->fs, fp->id);         /* Check validity of the object */
2392
        if (res != FR_OK) LEAVE_FF(fp->fs, res);
2393
        if (fp->flag & FA__ERROR)                       /* Check abort flag */
2394
                LEAVE_FF(fp->fs, FR_INT_ERR);
2395
        if (!(fp->flag & FA_WRITE))                     /* Check access mode */
2396
                LEAVE_FF(fp->fs, FR_DENIED);
2397
 
2398
        if (fp->fsize > fp->fptr) {
2399
                fp->fsize = fp->fptr;   /* Set file size to current R/W point */
2400
                fp->flag |= FA__WRITTEN;
2401
                if (fp->fptr == 0) {     /* When set file size to zero, remove entire cluster chain */
2402
                        res = remove_chain(fp->fs, fp->org_clust);
2403
                        fp->org_clust = 0;
2404
                } else {                                /* When truncate a part of the file, remove remaining clusters */
2405
                        ncl = get_fat(fp->fs, fp->curr_clust);
2406
                        res = FR_OK;
2407
                        if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
2408
                        if (ncl == 1) res = FR_INT_ERR;
2409
                        if (res == FR_OK && ncl < fp->fs->max_clust) {
2410
                                res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
2411
                                if (res == FR_OK) res = remove_chain(fp->fs, ncl);
2412
                        }
2413
                }
2414
        }
2415
        if (res != FR_OK) fp->flag |= FA__ERROR;
2416
 
2417
        LEAVE_FF(fp->fs, res);
2418
}
2419
 
2420
 
2421
 
2422
 
2423
/*-----------------------------------------------------------------------*/
2424
/* Delete a File or Directory                                            */
2425
/*-----------------------------------------------------------------------*/
2426
 
2427
FRESULT f_unlink (
2428
        const XCHAR *path               /* Pointer to the file or directory path */
2429
)
2430
{
2431
        FRESULT res;
2432
        DIR dj, sdj;
2433
        NAMEBUF(sfn, lfn);
2434
        BYTE *dir;
2435
        DWORD dclst;
2436
 
2437
 
2438
        res = chk_mounted(&path, &dj.fs, 1);
2439
        if (res != FR_OK) LEAVE_FF(dj.fs, res);
2440
 
2441
        INITBUF(dj, sfn, lfn);
2442
        res = follow_path(&dj, path);                   /* Follow the file path */
2443
        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
2444
                res = FR_INVALID_NAME;
2445
        if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
2446
 
2447
        dir = dj.dir;
2448
        if (!dir)                                                               /* Is it the root directory? */
2449
                LEAVE_FF(dj.fs, FR_INVALID_NAME);
2450
        if (dir[DIR_Attr] & AM_RDO)                             /* Is it a R/O object? */
2451
                LEAVE_FF(dj.fs, FR_DENIED);
2452
        dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
2453
 
2454
        if (dir[DIR_Attr] & AM_DIR) {                   /* It is a sub-directory */
2455
                if (dclst < 2) LEAVE_FF(dj.fs, FR_INT_ERR);
2456
                mem_cpy(&sdj, &dj, sizeof(DIR));        /* Check if the sub-dir is empty or not */
2457
                sdj.sclust = dclst;
2458
                res = dir_seek(&sdj, 2);
2459
                if (res != FR_OK) LEAVE_FF(dj.fs, res);
2460
                res = dir_read(&sdj);
2461
                if (res == FR_OK) res = FR_DENIED;      /* Not empty sub-dir */
2462
                if (res != FR_NO_FILE) LEAVE_FF(dj.fs, res);
2463
        }
2464
 
2465
        res = dir_remove(&dj);                                  /* Remove directory entry */
2466
        if (res == FR_OK) {
2467
                if (dclst)
2468
                        res = remove_chain(dj.fs, dclst);       /* Remove the cluster chain */
2469
                if (res == FR_OK) res = sync(dj.fs);
2470
        }
2471
 
2472
        LEAVE_FF(dj.fs, res);
2473
}
2474
 
2475
 
2476
 
2477
 
2478
/*-----------------------------------------------------------------------*/
2479
/* Create a Directory                                                    */
2480
/*-----------------------------------------------------------------------*/
2481
 
2482
FRESULT f_mkdir (
2483
        const XCHAR *path               /* Pointer to the directory path */
2484
)
2485
{
2486
        FRESULT res;
2487
        DIR dj;
2488
        NAMEBUF(sfn, lfn);
2489
        BYTE *dir, n;
2490
        DWORD dsect, dclst, pclst, tim;
2491
 
2492
 
2493
        res = chk_mounted(&path, &dj.fs, 1);
2494
        if (res != FR_OK) LEAVE_FF(dj.fs, res);
2495
 
2496
        INITBUF(dj, sfn, lfn);
2497
        res = follow_path(&dj, path);                   /* Follow the file path */
2498
        if (res == FR_OK) res = FR_EXIST;               /* Any file or directory is already existing */
2499
        if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
2500
                res = FR_INVALID_NAME;
2501
        if (res != FR_NO_FILE)                                  /* Any error occured */
2502
                LEAVE_FF(dj.fs, res);
2503
 
2504
        dclst = create_chain(dj.fs, 0);                  /* Allocate a new cluster for new directory table */
2505
        res = FR_OK;
2506
        if (dclst == 0) res = FR_DENIED;
2507
        if (dclst == 1) res = FR_INT_ERR;
2508
        if (dclst == 0xFFFFFFFF) res = FR_DISK_ERR;
2509
        if (res == FR_OK)
2510
                res = move_window(dj.fs, 0);
2511
        if (res != FR_OK) LEAVE_FF(dj.fs, res);
2512
        dsect = clust2sect(dj.fs, dclst);
2513
 
2514
        dir = dj.fs->win;                                               /* Initialize the new directory table */
2515
        mem_set(dir, 0, SS(dj.fs));
2516
        mem_set(dir+DIR_Name, ' ', 8+3);                /* Create "." entry */
2517
        dir[DIR_Name] = '.';
2518
        dir[DIR_Attr] = AM_DIR;
2519
        tim = get_fattime();
2520
        ST_DWORD(dir+DIR_WrtTime, tim);
2521
        ST_WORD(dir+DIR_FstClusLO, dclst);
2522
        ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
2523
        mem_cpy(dir+32, dir, 32);                       /* Create ".." entry */
2524
        dir[33] = '.';
2525
        pclst = dj.sclust;
2526
        if (dj.fs->fs_type == FS_FAT32 && pclst == dj.fs->dirbase)
2527
                pclst = 0;
2528
        ST_WORD(dir+32+DIR_FstClusLO, pclst);
2529
        ST_WORD(dir+32+DIR_FstClusHI, pclst >> 16);
2530
        for (n = 0; n < dj.fs->csize; n++) {     /* Write dot entries and clear left sectors */
2531
                dj.fs->winsect = dsect++;
2532
                dj.fs->wflag = 1;
2533
                res = move_window(dj.fs, 0);
2534
                if (res) LEAVE_FF(dj.fs, res);
2535
                mem_set(dir, 0, SS(dj.fs));
2536
        }
2537
 
2538
        res = dir_register(&dj);
2539
        if (res != FR_OK) {
2540
                remove_chain(dj.fs, dclst);
2541
        } else {
2542
                dir = dj.dir;
2543
                dir[DIR_Attr] = AM_DIR;                                 /* Attribute */
2544
                ST_DWORD(dir+DIR_WrtTime, tim);                 /* Crated time */
2545
                ST_WORD(dir+DIR_FstClusLO, dclst);              /* Table start cluster */
2546
                ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
2547
                dj.fs->wflag = 1;
2548
                res = sync(dj.fs);
2549
        }
2550
 
2551
        LEAVE_FF(dj.fs, res);
2552
}
2553
 
2554
 
2555
 
2556
 
2557
/*-----------------------------------------------------------------------*/
2558
/* Change File Attribute                                                 */
2559
/*-----------------------------------------------------------------------*/
2560
 
2561
FRESULT f_chmod (
2562
        const XCHAR *path,      /* Pointer to the file path */
2563
        BYTE value,                     /* Attribute bits */
2564
        BYTE mask                       /* Attribute mask to change */
2565
)
2566
{
2567
        FRESULT res;
2568
        DIR dj;
2569
        NAMEBUF(sfn, lfn);
2570
        BYTE *dir;
2571
 
2572
 
2573
        res = chk_mounted(&path, &dj.fs, 1);
2574
        if (res == FR_OK) {
2575
                INITBUF(dj, sfn, lfn);
2576
                res = follow_path(&dj, path);           /* Follow the file path */
2577
                if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
2578
                        res = FR_INVALID_NAME;
2579
                if (res == FR_OK) {
2580
                        dir = dj.dir;
2581
                        if (!dir) {                                             /* Is it a root directory? */
2582
                                res = FR_INVALID_NAME;
2583
                        } else {                                                /* File or sub directory */
2584
                                mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;    /* Valid attribute mask */
2585
                                dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
2586
                                dj.fs->wflag = 1;
2587
                                res = sync(dj.fs);
2588
                        }
2589
                }
2590
        }
2591
 
2592
        LEAVE_FF(dj.fs, res);
2593
}
2594
 
2595
 
2596
 
2597
 
2598
/*-----------------------------------------------------------------------*/
2599
/* Change Timestamp                                                      */
2600
/*-----------------------------------------------------------------------*/
2601
 
2602
FRESULT f_utime (
2603
        const XCHAR *path,      /* Pointer to the file/directory name */
2604
        const FILINFO *fno      /* Pointer to the timestamp to be set */
2605
)
2606
{
2607
        FRESULT res;
2608
        DIR dj;
2609
        NAMEBUF(sfn, lfn);
2610
        BYTE *dir;
2611
 
2612
 
2613
        res = chk_mounted(&path, &dj.fs, 1);
2614
        if (res == FR_OK) {
2615
                INITBUF(dj, sfn, lfn);
2616
                res = follow_path(&dj, path);   /* Follow the file path */
2617
                if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
2618
                        res = FR_INVALID_NAME;
2619
                if (res == FR_OK) {
2620
                        dir = dj.dir;
2621
                        if (!dir) {                             /* Root directory */
2622
                                res = FR_INVALID_NAME;
2623
                        } else {                                /* File or sub-directory */
2624
                                ST_WORD(dir+DIR_WrtTime, fno->ftime);
2625
                                ST_WORD(dir+DIR_WrtDate, fno->fdate);
2626
                                dj.fs->wflag = 1;
2627
                                res = sync(dj.fs);
2628
                        }
2629
                }
2630
        }
2631
 
2632
        LEAVE_FF(dj.fs, res);
2633
}
2634
 
2635
 
2636
 
2637
 
2638
/*-----------------------------------------------------------------------*/
2639
/* Rename File/Directory                                                 */
2640
/*-----------------------------------------------------------------------*/
2641
 
2642
FRESULT f_rename (
2643
        const XCHAR *path_old,  /* Pointer to the old name */
2644
        const XCHAR *path_new   /* Pointer to the new name */
2645
)
2646
{
2647
        FRESULT res;
2648
        DIR dj_old, dj_new;
2649
        NAMEBUF(sfn, lfn);
2650
        BYTE buf[21], *dir;
2651
        DWORD dw;
2652
 
2653
 
2654
        INITBUF(dj_old, sfn, lfn);
2655
        res = chk_mounted(&path_old, &dj_old.fs, 1);
2656
        if (res == FR_OK) {
2657
                dj_new.fs = dj_old.fs;
2658
                res = follow_path(&dj_old, path_old);   /* Check old object */
2659
                if (_FS_RPATH && res == FR_OK && (dj_old.fn[NS] & NS_DOT))
2660
                        res = FR_INVALID_NAME;
2661
        }
2662
        if (res != FR_OK) LEAVE_FF(dj_old.fs, res);     /* The old object is not found */
2663
 
2664
        if (!dj_old.dir) LEAVE_FF(dj_old.fs, FR_NO_FILE);       /* Is root dir? */
2665
        mem_cpy(buf, dj_old.dir+DIR_Attr, 21);          /* Save the object information */
2666
 
2667
        mem_cpy(&dj_new, &dj_old, sizeof(DIR));
2668
        res = follow_path(&dj_new, path_new);           /* Check new object */
2669
        if (res == FR_OK) res = FR_EXIST;                       /* The new object name is already existing */
2670
        if (res == FR_NO_FILE) {                                        /* Is it a valid path and no name collision? */
2671
                res = dir_register(&dj_new);                    /* Register the new object */
2672
                if (res == FR_OK) {
2673
                        dir = dj_new.dir;                                       /* Copy object information into new entry */
2674
                        mem_cpy(dir+13, buf+2, 19);
2675
                        dir[DIR_Attr] = buf[0] | AM_ARC;
2676
                        dj_old.fs->wflag = 1;
2677
                        if (dir[DIR_Attr] & AM_DIR) {           /* Update .. entry in the directory if needed */
2678
                                dw = clust2sect(dj_new.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO));
2679
                                if (!dw) {
2680
                                        res = FR_INT_ERR;
2681
                                } else {
2682
                                        res = move_window(dj_new.fs, dw);
2683
                                        dir = dj_new.fs->win+32;
2684
                                        if (res == FR_OK && dir[1] == '.') {
2685
                                                dw = (dj_new.fs->fs_type == FS_FAT32 && dj_new.sclust == dj_new.fs->dirbase) ? 0 : dj_new.sclust;
2686
                                                ST_WORD(dir+DIR_FstClusLO, dw);
2687
                                                ST_WORD(dir+DIR_FstClusHI, dw >> 16);
2688
                                                dj_new.fs->wflag = 1;
2689
                                        }
2690
                                }
2691
                        }
2692
                        if (res == FR_OK) {
2693
                                res = dir_remove(&dj_old);                      /* Remove old entry */
2694
                                if (res == FR_OK)
2695
                                        res = sync(dj_old.fs);
2696
                        }
2697
                }
2698
        }
2699
 
2700
        LEAVE_FF(dj_old.fs, res);
2701
}
2702
 
2703
#endif /* !_FS_READONLY */
2704
#endif /* _FS_MINIMIZE == 0 */
2705
#endif /* _FS_MINIMIZE <= 1 */
2706
#endif /* _FS_MINIMIZE <= 2 */
2707
 
2708
 
2709
 
2710
/*-----------------------------------------------------------------------*/
2711
/* Forward data to the stream directly (Available on only _FS_TINY cfg)  */
2712
/*-----------------------------------------------------------------------*/
2713
#if _USE_FORWARD && _FS_TINY
2714
 
2715
FRESULT f_forward (
2716
        FIL *fp,                                                /* Pointer to the file object */
2717
        UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
2718
        UINT btr,                                               /* Number of bytes to forward */
2719
        UINT *bf                                                /* Pointer to number of bytes forwarded */
2720
)
2721
{
2722
        FRESULT res;
2723
        DWORD remain, clst, sect;
2724
        UINT rcnt;
2725
 
2726
 
2727
        *bf = 0;
2728
 
2729
        res = validate(fp->fs, fp->id);                                 /* Check validity of the object */
2730
        if (res != FR_OK) LEAVE_FF(fp->fs, res);
2731
        if (fp->flag & FA__ERROR)                                               /* Check error flag */
2732
                LEAVE_FF(fp->fs, FR_INT_ERR);
2733
        if (!(fp->flag & FA_READ))                                              /* Check access mode */
2734
                LEAVE_FF(fp->fs, FR_DENIED);
2735
 
2736
        remain = fp->fsize - fp->fptr;
2737
        if (btr > remain) btr = (UINT)remain;                   /* Truncate btr by remaining bytes */
2738
 
2739
        for ( ;  btr && (*func)(NULL, 0);                                /* Repeat until all data transferred or stream becomes busy */
2740
                fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
2741
                if ((fp->fptr % SS(fp->fs)) == 0) {                      /* On the sector boundary? */
2742
                        if (fp->csect >= fp->fs->csize) {               /* On the cluster boundary? */
2743
                                clst = (fp->fptr == 0) ?                 /* On the top of the file? */
2744
                                        fp->org_clust : get_fat(fp->fs, fp->curr_clust);
2745
                                if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
2746
                                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2747
                                fp->curr_clust = clst;                          /* Update current cluster */
2748
                                fp->csect = 0;                                           /* Reset sector address in the cluster */
2749
                        }
2750
                        fp->csect++;                                                    /* Next sector address in the cluster */
2751
                }
2752
                sect = clust2sect(fp->fs, fp->curr_clust);      /* Get current data sector */
2753
                if (!sect) ABORT(fp->fs, FR_INT_ERR);
2754
                sect += fp->csect - 1;
2755
                if (move_window(fp->fs, sect))                          /* Move sector window */
2756
                        ABORT(fp->fs, FR_DISK_ERR);
2757
                fp->dsect = sect;
2758
                rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs));      /* Forward data from sector window */
2759
                if (rcnt > btr) rcnt = btr;
2760
                rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
2761
                if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
2762
        }
2763
 
2764
        LEAVE_FF(fp->fs, FR_OK);
2765
}
2766
#endif /* _USE_FORWARD */
2767
 
2768
 
2769
 
2770
#if _USE_MKFS && !_FS_READONLY
2771
/*-----------------------------------------------------------------------*/
2772
/* Create File System on the Drive                                       */
2773
/*-----------------------------------------------------------------------*/
2774
#define N_ROOTDIR       512                     /* Multiple of 32 and <= 2048 */
2775
#define N_FATS          1                       /* 1 or 2 */
2776
#define MAX_SECTOR      131072000UL     /* Maximum partition size */
2777
#define MIN_SECTOR      2000UL          /* Minimum partition size */
2778
 
2779
 
2780
FRESULT f_mkfs (
2781
        BYTE drv,                       /* Logical drive number */
2782
        BYTE partition,         /* Partitioning rule 0:FDISK, 1:SFD */
2783
        WORD allocsize          /* Allocation unit size [bytes] */
2784
)
2785
{
2786
        static const DWORD sstbl[] = { 2048000, 1024000, 512000, 256000, 128000, 64000, 32000, 16000, 8000, 4000,   0 };
2787
        static const WORD cstbl[] =  {   32768,   16384,   8192,   4096,   2048, 16384,  8192,  4096, 2048, 1024, 512 };
2788
        BYTE fmt, m, *tbl;
2789
        DWORD b_part, b_fat, b_dir, b_data;             /* Area offset (LBA) */
2790
        DWORD n_part, n_rsv, n_fat, n_dir;              /* Area size */
2791
        DWORD n_clst, d, n;
2792
        WORD as;
2793
        FATFS *fs;
2794
        DSTATUS stat;
2795
 
2796
 
2797
        /* Check validity of the parameters */
2798
        if (drv >= _DRIVES) return FR_INVALID_DRIVE;
2799
        if (partition >= 2) return FR_MKFS_ABORTED;
2800
 
2801
        /* Check mounted drive and clear work area */
2802
        fs = FatFs[drv];
2803
        if (!fs) return FR_NOT_ENABLED;
2804
        fs->fs_type = 0;
2805
        drv = LD2PD(drv);
2806
 
2807
        /* Get disk statics */
2808
        stat = disk_initialize(drv);
2809
        if (stat & STA_NOINIT) return FR_NOT_READY;
2810
        if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
2811
#if _MAX_SS != 512                                              /* Get disk sector size */
2812
        if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
2813
                || SS(fs) > _MAX_SS)
2814
                return FR_MKFS_ABORTED;
2815
#endif
2816
        if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)
2817
                return FR_MKFS_ABORTED;
2818
        if (n_part > MAX_SECTOR) n_part = MAX_SECTOR;
2819
        b_part = (!partition) ? 63 : 0;          /* Boot sector */
2820
        n_part -= b_part;
2821
        for (d = 512; d <= 32768U && d != allocsize; d <<= 1) ; /* Check validity of the allocation unit size */
2822
        if (d != allocsize) allocsize = 0;
2823
        if (!allocsize) {                                       /* Auto selection of cluster size */
2824
                d = n_part;
2825
                for (as = SS(fs); as > 512U; as >>= 1) d >>= 1;
2826
                for (n = 0; d < sstbl[n]; n++) ;
2827
                allocsize = cstbl[n];
2828
        }
2829
        if (allocsize < SS(fs)) allocsize = SS(fs);
2830
 
2831
        allocsize /= SS(fs);            /* Number of sectors per cluster */
2832
 
2833
        /* Pre-compute number of clusters and FAT type */
2834
        n_clst = n_part / allocsize;
2835
        fmt = FS_FAT12;
2836
        if (n_clst >= 0xFF5) fmt = FS_FAT16;
2837
        if (n_clst >= 0xFFF5) fmt = FS_FAT32;
2838
 
2839
        /* Determine offset and size of FAT structure */
2840
        switch (fmt) {
2841
        case FS_FAT12:
2842
                n_fat = ((n_clst * 3 + 1) / 2 + 3 + SS(fs) - 1) / SS(fs);
2843
                n_rsv = 1 + partition;
2844
                n_dir = N_ROOTDIR * 32 / SS(fs);
2845
                break;
2846
        case FS_FAT16:
2847
                n_fat = ((n_clst * 2) + 4 + SS(fs) - 1) / SS(fs);
2848
                n_rsv = 1 + partition;
2849
                n_dir = N_ROOTDIR * 32 / SS(fs);
2850
                break;
2851
        default:
2852
                n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
2853
                n_rsv = 33 - partition;
2854
                n_dir = 0;
2855
        }
2856
        b_fat = b_part + n_rsv;                 /* FATs start sector */
2857
        b_dir = b_fat + n_fat * N_FATS; /* Directory start sector */
2858
        b_data = b_dir + n_dir;                 /* Data start sector */
2859
 
2860
        /* Align data start sector to erase block boundary (for flash memory media) */
2861
        if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_MKFS_ABORTED;
2862
        n = (b_data + n - 1) & ~(n - 1);
2863
        n_fat += (n - b_data) / N_FATS;
2864
        /* b_dir and b_data are no longer used below */
2865
 
2866
        /* Determine number of cluster and final check of validity of the FAT type */
2867
        n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize;
2868
        if (   (fmt == FS_FAT16 && n_clst < 0xFF5)
2869
                || (fmt == FS_FAT32 && n_clst < 0xFFF5))
2870
                return FR_MKFS_ABORTED;
2871
 
2872
        /* Create partition table if needed */
2873
        if (!partition) {
2874
                DWORD n_disk = b_part + n_part;
2875
 
2876
                mem_set(fs->win, 0, SS(fs));
2877
                tbl = fs->win+MBR_Table;
2878
                ST_DWORD(tbl, 0x00010180);              /* Partition start in CHS */
2879
                if (n_disk < 63UL * 255 * 1024) {       /* Partition end in CHS */
2880
                        n_disk = n_disk / 63 / 255;
2881
                        tbl[7] = (BYTE)n_disk;
2882
                        tbl[6] = (BYTE)((n_disk >> 2) | 63);
2883
                } else {
2884
                        ST_WORD(&tbl[6], 0xFFFF);
2885
                }
2886
                tbl[5] = 254;
2887
                if (fmt != FS_FAT32)                    /* System ID */
2888
                        tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
2889
                else
2890
                        tbl[4] = 0x0c;
2891
                ST_DWORD(tbl+8, 63);                    /* Partition start in LBA */
2892
                ST_DWORD(tbl+12, n_part);               /* Partition size in LBA */
2893
                ST_WORD(tbl+64, 0xAA55);                /* Signature */
2894
                if (disk_write(drv, fs->win, 0, 1) != RES_OK)
2895
                        return FR_DISK_ERR;
2896
                partition = 0xF8;
2897
        } else {
2898
                partition = 0xF0;
2899
        }
2900
 
2901
        /* Create boot record */
2902
        tbl = fs->win;                                                          /* Clear buffer */
2903
        mem_set(tbl, 0, SS(fs));
2904
        ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB);                     /* Boot code (jmp $, nop) */
2905
        ST_WORD(tbl+BPB_BytsPerSec, SS(fs));            /* Sector size */
2906
        tbl[BPB_SecPerClus] = (BYTE)allocsize;          /* Sectors per cluster */
2907
        ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);                     /* Reserved sectors */
2908
        tbl[BPB_NumFATs] = N_FATS;                                      /* Number of FATs */
2909
        ST_WORD(tbl+BPB_RootEntCnt, SS(fs) / 32 * n_dir); /* Number of rootdir entries */
2910
        if (n_part < 0x10000) {                                         /* Number of total sectors */
2911
                ST_WORD(tbl+BPB_TotSec16, n_part);
2912
        } else {
2913
                ST_DWORD(tbl+BPB_TotSec32, n_part);
2914
        }
2915
        tbl[BPB_Media] = partition;                                     /* Media descripter */
2916
        ST_WORD(tbl+BPB_SecPerTrk, 63);                         /* Number of sectors per track */
2917
        ST_WORD(tbl+BPB_NumHeads, 255);                         /* Number of heads */
2918
        ST_DWORD(tbl+BPB_HiddSec, b_part);                      /* Hidden sectors */
2919
        n = get_fattime();                                                      /* Use current time as a VSN */
2920
        if (fmt != FS_FAT32) {
2921
                ST_DWORD(tbl+BS_VolID, n);                              /* Volume serial number */
2922
                ST_WORD(tbl+BPB_FATSz16, n_fat);                /* Number of secters per FAT */
2923
                tbl[BS_DrvNum] = 0x80;                                  /* Drive number */
2924
                tbl[BS_BootSig] = 0x29;                                 /* Extended boot signature */
2925
                mem_cpy(tbl+BS_VolLab, "NO NAME    FAT     ", 19);      /* Volume lavel, FAT signature */
2926
        } else {
2927
                ST_DWORD(tbl+BS_VolID32, n);                    /* Volume serial number */
2928
                ST_DWORD(tbl+BPB_FATSz32, n_fat);               /* Number of secters per FAT */
2929
                ST_DWORD(tbl+BPB_RootClus, 2);                  /* Root directory cluster (2) */
2930
                ST_WORD(tbl+BPB_FSInfo, 1);                             /* FSInfo record offset (bs+1) */
2931
                ST_WORD(tbl+BPB_BkBootSec, 6);                  /* Backup boot record offset (bs+6) */
2932
                tbl[BS_DrvNum32] = 0x80;                                /* Drive number */
2933
                tbl[BS_BootSig32] = 0x29;                               /* Extended boot signature */
2934
                mem_cpy(tbl+BS_VolLab32, "NO NAME    FAT32   ", 19);    /* Volume lavel, FAT signature */
2935
        }
2936
        ST_WORD(tbl+BS_55AA, 0xAA55);                           /* Signature */
2937
        if (SS(fs) > 512U) {
2938
                ST_WORD(tbl+SS(fs)-2, 0xAA55);
2939
        }
2940
        if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
2941
                return FR_DISK_ERR;
2942
        if (fmt == FS_FAT32)
2943
                disk_write(drv, tbl, b_part+6, 1);
2944
 
2945
        /* Initialize FAT area */
2946
        for (m = 0; m < N_FATS; m++) {
2947
                mem_set(tbl, 0, SS(fs));         /* 1st sector of the FAT  */
2948
                if (fmt != FS_FAT32) {
2949
                        n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
2950
                        n |= partition;
2951
                        ST_DWORD(tbl, n);                               /* Reserve cluster #0-1 (FAT12/16) */
2952
                } else {
2953
                        ST_DWORD(tbl+0, 0xFFFFFFF8);     /* Reserve cluster #0-1 (FAT32) */
2954
                        ST_DWORD(tbl+4, 0xFFFFFFFF);
2955
                        ST_DWORD(tbl+8, 0x0FFFFFFF);    /* Reserve cluster #2 for root dir */
2956
                }
2957
                if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
2958
                        return FR_DISK_ERR;
2959
                mem_set(tbl, 0, SS(fs));         /* Following FAT entries are filled by zero */
2960
                for (n = 1; n < n_fat; n++) {
2961
                        if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
2962
                                return FR_DISK_ERR;
2963
                }
2964
        }
2965
 
2966
        /* Initialize Root directory */
2967
        m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir);
2968
        do {
2969
                if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
2970
                        return FR_DISK_ERR;
2971
        } while (--m);
2972
 
2973
        /* Create FSInfo record if needed */
2974
        if (fmt == FS_FAT32) {
2975
                ST_WORD(tbl+BS_55AA, 0xAA55);
2976
                ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
2977
                ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
2978
                ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
2979
                ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
2980
                disk_write(drv, tbl, b_part+1, 1);
2981
                disk_write(drv, tbl, b_part+7, 1);
2982
        }
2983
 
2984
        return (disk_ioctl(drv, CTRL_SYNC, (void*)NULL) == RES_OK) ? FR_OK : FR_DISK_ERR;
2985
}
2986
 
2987
#endif /* _USE_MKFS && !_FS_READONLY */
2988
 
2989
 
2990
 
2991
 
2992
#if _USE_STRFUNC
2993
/*-----------------------------------------------------------------------*/
2994
/* Get a string from the file                                            */
2995
/*-----------------------------------------------------------------------*/
2996
char* f_gets (
2997
        char* buff,     /* Pointer to the string buffer to read */
2998
        int len,        /* Size of string buffer */
2999
        FIL* fil        /* Pointer to the file object */
3000
)
3001
{
3002
        int i = 0;
3003
        char *p = buff;
3004
        UINT rc;
3005
 
3006
 
3007
        while (i < len - 1) {                   /* Read bytes until buffer gets filled */
3008
                f_read(fil, p, 1, &rc);
3009
                if (rc != 1) break;                     /* Break when no data to read */
3010
#if _USE_STRFUNC >= 2
3011
                if (*p == '\r') continue;       /* Strip '\r' */
3012
#endif
3013
                i++;
3014
                if (*p++ == '\n') break;        /* Break when reached end of line */
3015
        }
3016
        *p = 0;
3017
        return i ? buff : NULL;                 /* When no data read (eof or error), return with error. */
3018
}
3019
 
3020
 
3021
 
3022
#if !_FS_READONLY
3023
#include <stdarg.h>
3024
/*-----------------------------------------------------------------------*/
3025
/* Put a character to the file                                           */
3026
/*-----------------------------------------------------------------------*/
3027
int f_putc (
3028
        int chr,        /* A character to be output */
3029
        FIL* fil        /* Ponter to the file object */
3030
)
3031
{
3032
        UINT bw;
3033
        char c;
3034
 
3035
 
3036
#if _USE_STRFUNC >= 2
3037
        if (chr == '\n') f_putc ('\r', fil);    /* LF -> CRLF conversion */
3038
#endif
3039
        if (!fil) {     /* Special value may be used to switch the destination to any other device */
3040
        /*      put_console(chr);       */
3041
                return chr;
3042
        }
3043
        c = (char)chr;
3044
        f_write(fil, &c, 1, &bw);       /* Write a byte to the file */
3045
        return bw ? chr : EOF;          /* Return the result */
3046
}
3047
 
3048
 
3049
 
3050
 
3051
/*-----------------------------------------------------------------------*/
3052
/* Put a string to the file                                              */
3053
/*-----------------------------------------------------------------------*/
3054
int f_puts (
3055
        const char* str,        /* Pointer to the string to be output */
3056
        FIL* fil                        /* Pointer to the file object */
3057
)
3058
{
3059
        int n;
3060
 
3061
 
3062
        for (n = 0; *str; str++, n++) {
3063
                if (f_putc(*str, fil) == EOF) return EOF;
3064
        }
3065
        return n;
3066
}
3067
 
3068
 
3069
 
3070
 
3071
/*-----------------------------------------------------------------------*/
3072
/* Put a formatted string to the file                                    */
3073
/*-----------------------------------------------------------------------*/
3074
int f_printf (
3075
        FIL* fil,                       /* Pointer to the file object */
3076
        const char* str,        /* Pointer to the format string */
3077
        ...                                     /* Optional arguments... */
3078
)
3079
{
3080
        va_list arp;
3081
        UCHAR c, f, r;
3082
        ULONG val;
3083
        char s[16];
3084
        int i, w, res, cc;
3085
 
3086
 
3087
        va_start(arp, str);
3088
 
3089
        for (cc = res = 0; cc != EOF; res += cc) {
3090
                c = *str++;
3091
                if (c == 0) break;                       /* End of string */
3092
                if (c != '%') {                         /* Non escape cahracter */
3093
                        cc = f_putc(c, fil);
3094
                        if (cc != EOF) cc = 1;
3095
                        continue;
3096
                }
3097
                w = f = 0;
3098
                c = *str++;
3099
                if (c == '0') {                         /* Flag: '0' padding */
3100
                        f = 1; c = *str++;
3101
                }
3102
                while (c >= '0' && c <= '9') {  /* Precision */
3103
                        w = w * 10 + (c - '0');
3104
                        c = *str++;
3105
                }
3106
                if (c == 'l') {                         /* Prefix: Size is long int */
3107
                        f |= 2; c = *str++;
3108
                }
3109
                if (c == 's') {                         /* Type is string */
3110
                        cc = f_puts(va_arg(arp, char*), fil);
3111
                        continue;
3112
                }
3113
                if (c == 'c') {                         /* Type is character */
3114
                        cc = f_putc(va_arg(arp, int), fil);
3115
                        if (cc != EOF) cc = 1;
3116
                        continue;
3117
                }
3118
                r = 0;
3119
                if (c == 'd') r = 10;           /* Type is signed decimal */
3120
                if (c == 'u') r = 10;           /* Type is unsigned decimal */
3121
                if (c == 'X') r = 16;           /* Type is unsigned hexdecimal */
3122
                if (r == 0) break;                       /* Unknown type */
3123
                if (f & 2) {                            /* Get the value */
3124
                        val = (ULONG)va_arg(arp, long);
3125
                } else {
3126
                        val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
3127
                }
3128
                /* Put numeral string */
3129
                if (c == 'd') {
3130
                        if (val & 0x80000000) {
3131
                                val = 0 - val;
3132
                                f |= 4;
3133
                        }
3134
                }
3135
                i = sizeof(s) - 1; s[i] = 0;
3136
                do {
3137
                        c = (UCHAR)(val % r + '0');
3138
                        if (c > '9') c += 7;
3139
                        s[--i] = c;
3140
                        val /= r;
3141
                } while (i && val);
3142
                if (i && (f & 4)) s[--i] = '-';
3143
                w = sizeof(s) - 1 - w;
3144
                while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';
3145
                cc = f_puts(&s[i], fil);
3146
        }
3147
 
3148
        va_end(arp);
3149
        return (cc == EOF) ? cc : res;
3150
}
3151
 
3152
#endif /* !_FS_READONLY */
3153
#endif /* _USE_STRFUNC */

powered by: WebSVN 2.1.0

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