Subversion Repositories NedoOS

Rev

Rev 1056 | Details | Compare with Previous | Last modification | View Log

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