Rev 1234 Rev 1858
1 /*--------------------------------------------------------------------------/ 1 /*--------------------------------------------------------------------------/
2 / FatFs - Tiny FAT file system module R0.04b (C)ChaN, 2007 2 / FatFs - Tiny FAT file system module R0.04b (C)ChaN, 2007
3 /---------------------------------------------------------------------------/ 3 /---------------------------------------------------------------------------/
4 / The FatFs module is an experimenal project to implement FAT file system to 4 / The FatFs module is an experimenal project to implement FAT file system to
5 / cheap microcontrollers. This is a free software and is opened for education, 5 / cheap microcontrollers. This is a free software and is opened for education,
6 / research and development under license policy of following trems. 6 / research and development under license policy of following trems.
7 / 7 /
8 / Copyright (C) 2007, ChaN, all right reserved. 8 / Copyright (C) 2007, ChaN, all right reserved.
9 / 9 /
10 / * The FatFs module is a free software and there is no warranty. 10 / * The FatFs module is a free software and there is no warranty.
11 / * You can use, modify and/or redistribute it for personal, non-profit or 11 / * You can use, modify and/or redistribute it for personal, non-profit or
12 / profit use without any restriction under your responsibility. 12 / profit use without any restriction under your responsibility.
13 / * Redistributions of source code must retain the above copyright notice. 13 / * Redistributions of source code must retain the above copyright notice.
14 / 14 /
15 /---------------------------------------------------------------------------/ 15 /---------------------------------------------------------------------------/
16 / Feb 26, 2006 R0.00 Prototype. 16 / Feb 26, 2006 R0.00 Prototype.
17 / Apr 29, 2006 R0.01 First stable version. 17 / Apr 29, 2006 R0.01 First stable version.
18 / Jun 01, 2006 R0.02 Added FAT12 support. 18 / Jun 01, 2006 R0.02 Added FAT12 support.
19 / Removed unbuffered mode. 19 / Removed unbuffered mode.
20 / Fixed a problem on small (<32M) patition. 20 / Fixed a problem on small (<32M) patition.
21 / Jun 10, 2006 R0.02a Added a configuration option (_FS_MINIMUM). 21 / Jun 10, 2006 R0.02a Added a configuration option (_FS_MINIMUM).
22 / Sep 22, 2006 R0.03 Added f_rename(). 22 / Sep 22, 2006 R0.03 Added f_rename().
23 / Changed option _FS_MINIMUM to _FS_MINIMIZE. 23 / Changed option _FS_MINIMUM to _FS_MINIMIZE.
24 / Dec 09, 2006 R0.03a Improved cluster scan algolithm to write files fast. 24 / Dec 09, 2006 R0.03a Improved cluster scan algolithm to write files fast.
25 / Feb 04, 2007 R0.04 Added FAT32 supprt. 25 / Feb 04, 2007 R0.04 Added FAT32 supprt.
26 / Changed some interfaces incidental to FatFs. 26 / Changed some interfaces incidental to FatFs.
27 / Changed f_mountdrv() to f_mount(). 27 / Changed f_mountdrv() to f_mount().
28 / Apr 01, 2007 R0.04a Added a capability of extending file size to f_lseek(). 28 / Apr 01, 2007 R0.04a Added a capability of extending file size to f_lseek().
29 / Added minimization level 3. 29 / Added minimization level 3.
30 / Fixed a problem in FAT32 support. 30 / Fixed a problem in FAT32 support.
31 / xxx xx, 2007 R0.04b Added a configuration option _USE_NTFLAG. 31 / xxx xx, 2007 R0.04b Added a configuration option _USE_NTFLAG.
32 / Added FSInfo support. 32 / Added FSInfo support.
33 / Fixed some problems corresponds to FAT32 support. 33 / Fixed some problems corresponds to FAT32 support.
34 / Fixed DBCS name can result FR_INVALID_NAME. 34 / Fixed DBCS name can result FR_INVALID_NAME.
35 / Fixed short seek (<= csize) collapses the file object. 35 / Fixed short seek (<= csize) collapses the file object.
36 /---------------------------------------------------------------------------*/ 36 /---------------------------------------------------------------------------*/
37   37  
38 #include <string.h> 38 #include <string.h>
39 #include "tff.h" /* Tiny-FatFs declarations */ 39 #include "tff.h" /* Tiny-FatFs declarations */
40 #include "diskio.h" /* Include file for user provided disk functions */ 40 #include "diskio.h" /* Include file for user provided disk functions */
41   41  
42   42  
43 static 43 static
44 FATFS *FatFs; /* Pointer to the file system objects (logical drive) */ 44 FATFS *FatFs; /* Pointer to the file system objects (logical drive) */
45 static 45 static
46 WORD fsid; /* File system mount ID */ 46 WORD fsid; /* File system mount ID */
47   47  
48   48  
49 /*------------------------------------------------------------------------- 49 /*-------------------------------------------------------------------------
50   50  
51 Module Private Functions 51 Module Private Functions
52   52  
53 -------------------------------------------------------------------------*/ 53 -------------------------------------------------------------------------*/
54   54  
55   55  
56 /*-----------------------------------------------------------------------*/ 56 /*-----------------------------------------------------------------------*/
57 /* Change window offset */ 57 /* Change window offset */
58 /*-----------------------------------------------------------------------*/ 58 /*-----------------------------------------------------------------------*/
59   59  
60 static 60 static
61 BOOL move_window ( /* TRUE: successful, FALSE: failed */ 61 BOOL move_window ( /* TRUE: successful, FALSE: failed */
62 DWORD sector /* Sector number to make apperance in the FatFs->win */ 62 DWORD sector /* Sector number to make apperance in the FatFs->win */
63 ) /* Move to zero only writes back dirty window */ 63 ) /* Move to zero only writes back dirty window */
64 { 64 {
65 DWORD wsect; 65 DWORD wsect;
66 FATFS *fs = FatFs; 66 FATFS *fs = FatFs;
67   67  
68   68  
69 wsect = fs->winsect; 69 wsect = fs->winsect;
70 if (wsect != sector) { /* Changed current window */ 70 if (wsect != sector) { /* Changed current window */
71 #if !_FS_READONLY 71 #if !_FS_READONLY
72 BYTE n; 72 BYTE n;
73 if (fs->winflag) { /* Write back dirty window if needed */ 73 if (fs->winflag) { /* Write back dirty window if needed */
74 if (disk_write(0, fs->win, wsect, 1) != RES_OK) 74 if (disk_write(0, fs->win, wsect, 1) != RES_OK)
75 return FALSE; 75 return FALSE;
76 fs->winflag = 0; 76 fs->winflag = 0;
77 if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */ 77 if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */
78 for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to all FAT copies */ 78 for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to all FAT copies */
79 wsect += fs->sects_fat; 79 wsect += fs->sects_fat;
80 disk_write(0, fs->win, wsect, 1); 80 disk_write(0, fs->win, wsect, 1);
81 } 81 }
82 } 82 }
83 } 83 }
84 #endif 84 #endif
85 if (sector) { 85 if (sector) {
86 if (disk_read(0, fs->win, sector, 1) != RES_OK) 86 if (disk_read(0, fs->win, sector, 1) != RES_OK)
87 return FALSE; 87 return FALSE;
88 fs->winsect = sector; 88 fs->winsect = sector;
89 } 89 }
90 } 90 }
91 return TRUE; 91 return TRUE;
92 } 92 }
93   93  
94   94  
95   95  
96   96  
97 /*-----------------------------------------------------------------------*/ 97 /*-----------------------------------------------------------------------*/
98 /* Clean-up cached data */ 98 /* Clean-up cached data */
99 /*-----------------------------------------------------------------------*/ 99 /*-----------------------------------------------------------------------*/
100   100  
101 #if !_FS_READONLY 101 #if !_FS_READONLY
102 static 102 static
103 FRESULT sync (void) /* FR_OK: successful, FR_RW_ERROR: failed */ 103 FRESULT sync (void) /* FR_OK: successful, FR_RW_ERROR: failed */
104 { 104 {
105 FATFS *fs = FatFs; 105 FATFS *fs = FatFs;
106   106  
107   107  
108 fs->winflag = 1; 108 fs->winflag = 1;
109 if (!move_window(0)) return FR_RW_ERROR; 109 if (!move_window(0)) return FR_RW_ERROR;
110 #if _USE_FSINFO 110 #if _USE_FSINFO
111 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { /* Update FSInfo sector if needed */ 111 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { /* Update FSInfo sector if needed */
112 fs->winsect = 0; 112 fs->winsect = 0;
113 memset(fs->win, 0, 512); 113 memset(fs->win, 0, 512);
114 ST_WORD(&fs->win[BS_55AA], 0xAA55); 114 ST_WORD(&fs->win[BS_55AA], 0xAA55);
115 ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252); 115 ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252);
116 ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272); 116 ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272);
117 ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust); 117 ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust);
118 ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust); 118 ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust);
119 disk_write(0, fs->win, fs->fsi_sector, 1); 119 disk_write(0, fs->win, fs->fsi_sector, 1);
120 fs->fsi_flag = 0; 120 fs->fsi_flag = 0;
121 } 121 }
122 #endif 122 #endif
123 if (disk_ioctl(0, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR; 123 if (disk_ioctl(0, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR;
124 return FR_OK; 124 return FR_OK;
125 } 125 }
126 #endif 126 #endif
127   127  
128   128  
129   129  
130   130  
131 /*-----------------------------------------------------------------------*/ 131 /*-----------------------------------------------------------------------*/
132 /* Get a cluster status */ 132 /* Get a cluster status */
133 /*-----------------------------------------------------------------------*/ 133 /*-----------------------------------------------------------------------*/
134   134  
135 static 135 static
136 CLUST get_cluster ( /* 0,>=2: successful, 1: failed */ 136 CLUST get_cluster ( /* 0,>=2: successful, 1: failed */
137 CLUST clust /* Cluster# to get the link information */ 137 CLUST clust /* Cluster# to get the link information */
138 ) 138 )
139 { 139 {
140 WORD wc, bc; 140 WORD wc, bc;
141 DWORD fatsect; 141 DWORD fatsect;
142 FATFS *fs = FatFs; 142 FATFS *fs = FatFs;
143   143  
144   144  
145 if (clust >= 2 && clust < fs->max_clust) { /* Valid cluster# */ 145 if (clust >= 2 && clust < fs->max_clust) { /* Valid cluster# */
146 fatsect = fs->fatbase; 146 fatsect = fs->fatbase;
147 switch (fs->fs_type) { 147 switch (fs->fs_type) {
148 case FS_FAT12 : 148 case FS_FAT12 :
149 bc = (WORD)clust * 3 / 2; 149 bc = (WORD)clust * 3 / 2;
150 if (!move_window(fatsect + bc / 512)) break; 150 if (!move_window(fatsect + bc / 512)) break;
151 wc = fs->win[bc % 512]; bc++; 151 wc = fs->win[bc % 512]; bc++;
152 if (!move_window(fatsect + bc / 512)) break; 152 if (!move_window(fatsect + bc / 512)) break;
153 wc |= (WORD)fs->win[bc % 512] << 8; 153 wc |= (WORD)fs->win[bc % 512] << 8;
154 return (clust & 1) ? (wc >> 4) : (wc & 0xFFF); 154 return (clust & 1) ? (wc >> 4) : (wc & 0xFFF);
155   155  
156 case FS_FAT16 : 156 case FS_FAT16 :
157 if (!move_window(fatsect + clust / 256)) break; 157 if (!move_window(fatsect + clust / 256)) break;
158 return LD_WORD(&fs->win[((WORD)clust * 2) % 512]); 158 return LD_WORD(&fs->win[((WORD)clust * 2) % 512]);
159 #if _FAT32 159 #if _FAT32
160 case FS_FAT32 : 160 case FS_FAT32 :
161 if (!move_window(fatsect + clust / 128)) break; 161 if (!move_window(fatsect + clust / 128)) break;
162 return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF; 162 return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF;
163 #endif 163 #endif
164 } 164 }
165 } 165 }
166   166  
167 return 1; /* There is no cluster information, or an error occured */ 167 return 1; /* There is no cluster information, or an error occured */
168 } 168 }
169   169  
170   170  
171   171  
172   172  
173 /*-----------------------------------------------------------------------*/ 173 /*-----------------------------------------------------------------------*/
174 /* Change a cluster status */ 174 /* Change a cluster status */
175 /*-----------------------------------------------------------------------*/ 175 /*-----------------------------------------------------------------------*/
176   176  
177 #if !_FS_READONLY 177 #if !_FS_READONLY
178 static 178 static
179 BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ 179 BOOL put_cluster ( /* TRUE: successful, FALSE: failed */
180 CLUST clust, /* Cluster# to change */ 180 CLUST clust, /* Cluster# to change */
181 CLUST val /* New value to mark the cluster */ 181 CLUST val /* New value to mark the cluster */
182 ) 182 )
183 { 183 {
184 WORD bc; 184 WORD bc;
185 BYTE *p; 185 BYTE *p;
186 DWORD fatsect; 186 DWORD fatsect;
187 FATFS *fs = FatFs; 187 FATFS *fs = FatFs;
188   188  
189   189  
190 fatsect = fs->fatbase; 190 fatsect = fs->fatbase;
191 switch (fs->fs_type) { 191 switch (fs->fs_type) {
192 case FS_FAT12 : 192 case FS_FAT12 :
193 bc = (WORD)clust * 3 / 2; 193 bc = (WORD)clust * 3 / 2;
194 if (!move_window(fatsect + bc / 512)) return FALSE; 194 if (!move_window(fatsect + bc / 512)) return FALSE;
195 p = &fs->win[bc % 512]; 195 p = &fs->win[bc % 512];
196 *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; 196 *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
197 bc++; 197 bc++;
198 fs->winflag = 1; 198 fs->winflag = 1;
199 if (!move_window(fatsect + bc / 512)) return FALSE; 199 if (!move_window(fatsect + bc / 512)) return FALSE;
200 p = &fs->win[bc % 512]; 200 p = &fs->win[bc % 512];
201 *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); 201 *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
202 break; 202 break;
203   203  
204 case FS_FAT16 : 204 case FS_FAT16 :
205 if (!move_window(fatsect + clust / 256)) return FALSE; 205 if (!move_window(fatsect + clust / 256)) return FALSE;
206 ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val); 206 ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val);
207 break; 207 break;
208 #if _FAT32 208 #if _FAT32
209 case FS_FAT32 : 209 case FS_FAT32 :
210 if (!move_window(fatsect + clust / 128)) return FALSE; 210 if (!move_window(fatsect + clust / 128)) return FALSE;
211 ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val); 211 ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val);
212 break; 212 break;
213 #endif 213 #endif
214 default : 214 default :
215 return FALSE; 215 return FALSE;
216 } 216 }
217 fs->winflag = 1; 217 fs->winflag = 1;
218 return TRUE; 218 return TRUE;
219 } 219 }
220 #endif /* !_FS_READONLY */ 220 #endif /* !_FS_READONLY */
221   221  
222   222  
223   223  
224   224  
225 /*-----------------------------------------------------------------------*/ 225 /*-----------------------------------------------------------------------*/
226 /* Remove a cluster chain */ 226 /* Remove a cluster chain */
227 /*-----------------------------------------------------------------------*/ 227 /*-----------------------------------------------------------------------*/
228   228  
229 #if !_FS_READONLY 229 #if !_FS_READONLY
230 static 230 static
231 BOOL remove_chain ( /* TRUE: successful, FALSE: failed */ 231 BOOL remove_chain ( /* TRUE: successful, FALSE: failed */
232 CLUST clust /* Cluster# to remove chain from */ 232 CLUST clust /* Cluster# to remove chain from */
233 ) 233 )
234 { 234 {
235 CLUST nxt; 235 CLUST nxt;
236 FATFS *fs = FatFs; 236 FATFS *fs = FatFs;
237   237  
238   238  
239 while (clust >= 2 && clust < fs->max_clust) { 239 while (clust >= 2 && clust < fs->max_clust) {
240 nxt = get_cluster(clust); 240 nxt = get_cluster(clust);
241 if (nxt == 1) return FALSE; 241 if (nxt == 1) return FALSE;
242 if (!put_cluster(clust, 0)) return FALSE; 242 if (!put_cluster(clust, 0)) return FALSE;
243 if (fs->free_clust != (CLUST)0xFFFFFFFF) { 243 if (fs->free_clust != (CLUST)0xFFFFFFFF) {
244 fs->free_clust++; 244 fs->free_clust++;
245 #if _USE_FSINFO 245 #if _USE_FSINFO
246 fs->fsi_flag = 1; 246 fs->fsi_flag = 1;
247 #endif 247 #endif
248 } 248 }
249 clust = nxt; 249 clust = nxt;
250 } 250 }
251 return TRUE; 251 return TRUE;
252 } 252 }
253 #endif 253 #endif
254   254  
255   255  
256   256  
257   257  
258 /*-----------------------------------------------------------------------*/ 258 /*-----------------------------------------------------------------------*/
259 /* Stretch or create a cluster chain */ 259 /* Stretch or create a cluster chain */
260 /*-----------------------------------------------------------------------*/ 260 /*-----------------------------------------------------------------------*/
261   261  
262 #if !_FS_READONLY 262 #if !_FS_READONLY
263 static 263 static
264 CLUST create_chain ( /* 0: no free cluster, 1: error, >=2: new cluster number */ 264 CLUST create_chain ( /* 0: no free cluster, 1: error, >=2: new cluster number */
265 CLUST clust /* Cluster# to stretch, 0 means create new */ 265 CLUST clust /* Cluster# to stretch, 0 means create new */
266 ) 266 )
267 { 267 {
268 CLUST cstat, ncl, scl, mcl; 268 CLUST cstat, ncl, scl, mcl;
269 FATFS *fs = FatFs; 269 FATFS *fs = FatFs;
270   270  
271   271  
272 mcl = fs->max_clust; 272 mcl = fs->max_clust;
273 if (clust == 0) { /* Create new chain */ 273 if (clust == 0) { /* Create new chain */
274 scl = fs->last_clust; /* Get last allocated cluster */ 274 scl = fs->last_clust; /* Get last allocated cluster */
275 if (scl < 2 || scl >= mcl) scl = 1; 275 if (scl < 2 || scl >= mcl) scl = 1;
276 } 276 }
277 else { /* Stretch existing chain */ 277 else { /* Stretch existing chain */
278 cstat = get_cluster(clust); /* Check the cluster status */ 278 cstat = get_cluster(clust); /* Check the cluster status */
279 if (cstat < 2) return 1; /* It is an invalid cluster */ 279 if (cstat < 2) return 1; /* It is an invalid cluster */
280 if (cstat < mcl) return cstat; /* It is already followed by next cluster */ 280 if (cstat < mcl) return cstat; /* It is already followed by next cluster */
281 scl = clust; 281 scl = clust;
282 } 282 }
283   283  
284 ncl = scl; /* Start cluster */ 284 ncl = scl; /* Start cluster */
285 for (;;) { 285 for (;;) {
286 ncl++; /* Next cluster */ 286 ncl++; /* Next cluster */
287 if (ncl >= mcl) { /* Wrap around */ 287 if (ncl >= mcl) { /* Wrap around */
288 ncl = 2; 288 ncl = 2;
289 if (ncl > scl) return 0; /* No free custer */ 289 if (ncl > scl) return 0; /* No free custer */
290 } 290 }
291 cstat = get_cluster(ncl); /* Get the cluster status */ 291 cstat = get_cluster(ncl); /* Get the cluster status */
292 if (cstat == 0) break; /* Found a free cluster */ 292 if (cstat == 0) break; /* Found a free cluster */
293 if (cstat == 1) return 1; /* Any error occured */ 293 if (cstat == 1) return 1; /* Any error occured */
294 if (ncl == scl) return 0; /* No free custer */ 294 if (ncl == scl) return 0; /* No free custer */
295 } 295 }
296   296  
297 if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ 297 if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */
298 if (clust && !put_cluster(clust, ncl)) return 1; /* Link it to previous one if needed */ 298 if (clust && !put_cluster(clust, ncl)) return 1; /* Link it to previous one if needed */
299   299  
300 fs->last_clust = ncl; /* Update fsinfo */ 300 fs->last_clust = ncl; /* Update fsinfo */
301 if (fs->free_clust != (CLUST)0xFFFFFFFF) { 301 if (fs->free_clust != (CLUST)0xFFFFFFFF) {
302 fs->free_clust--; 302 fs->free_clust--;
303 #if _USE_FSINFO 303 #if _USE_FSINFO
304 fs->fsi_flag = 1; 304 fs->fsi_flag = 1;
305 #endif 305 #endif
306 } 306 }
307   307  
308 return ncl; /* Return new cluster number */ 308 return ncl; /* Return new cluster number */
309 } 309 }
310 #endif /* !_FS_READONLY */ 310 #endif /* !_FS_READONLY */
311   311  
312   312  
313   313  
314   314  
315 /*-----------------------------------------------------------------------*/ 315 /*-----------------------------------------------------------------------*/
316 /* Get sector# from cluster# */ 316 /* Get sector# from cluster# */
317 /*-----------------------------------------------------------------------*/ 317 /*-----------------------------------------------------------------------*/
318   318  
319 static 319 static
320 DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ 320 DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */
321 CLUST clust /* Cluster# to be converted */ 321 CLUST clust /* Cluster# to be converted */
322 ) 322 )
323 { 323 {
324 FATFS *fs = FatFs; 324 FATFS *fs = FatFs;
325   325  
326   326  
327 clust -= 2; 327 clust -= 2;
328 if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */ 328 if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */
329 return (DWORD)clust * fs->sects_clust + fs->database; 329 return (DWORD)clust * fs->sects_clust + fs->database;
330 } 330 }
331   331  
332   332  
333   333  
334   334  
335 /*-----------------------------------------------------------------------*/ 335 /*-----------------------------------------------------------------------*/
336 /* Move directory pointer to next */ 336 /* Move directory pointer to next */
337 /*-----------------------------------------------------------------------*/ 337 /*-----------------------------------------------------------------------*/
338   338  
339 static 339 static
340 BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ 340 BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */
341 DIR *dirobj /* Pointer to directory object */ 341 DIR *dirobj /* Pointer to directory object */
342 ) 342 )
343 { 343 {
344 CLUST clust; 344 CLUST clust;
345 WORD idx; 345 WORD idx;
346 FATFS *fs = FatFs; 346 FATFS *fs = FatFs;
347   347  
348   348  
349 idx = dirobj->index + 1; 349 idx = dirobj->index + 1;
350 if ((idx & 15) == 0) { /* Table sector changed? */ 350 if ((idx & 15) == 0) { /* Table sector changed? */
351 dirobj->sect++; /* Next sector */ 351 dirobj->sect++; /* Next sector */
352 if (!dirobj->clust) { /* In static table */ 352 if (!dirobj->clust) { /* In static table */
353 if (idx >= fs->n_rootdir) return FALSE; /* Reached to end of table */ 353 if (idx >= fs->n_rootdir) return FALSE; /* Reached to end of table */
354 } else { /* In dynamic table */ 354 } else { /* In dynamic table */
355 if (((idx / 16) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */ 355 if (((idx / 16) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */
356 clust = get_cluster(dirobj->clust); /* Get next cluster */ 356 clust = get_cluster(dirobj->clust); /* Get next cluster */
357 if (clust < 2 || clust >= fs->max_clust) /* Reached to end of table */ 357 if (clust < 2 || clust >= fs->max_clust) /* Reached to end of table */
358 return FALSE; 358 return FALSE;
359 dirobj->clust = clust; /* Initialize for new cluster */ 359 dirobj->clust = clust; /* Initialize for new cluster */
360 dirobj->sect = clust2sect(clust); 360 dirobj->sect = clust2sect(clust);
361 } 361 }
362 } 362 }
363 } 363 }
364 dirobj->index = idx; /* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */ 364 dirobj->index = idx; /* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */
365 return TRUE; 365 return TRUE;
366 } 366 }
367   367  
368   368  
369   369  
370   370  
371 /*-----------------------------------------------------------------------*/ 371 /*-----------------------------------------------------------------------*/
372 /* Get file status from directory entry */ 372 /* Get file status from directory entry */
373 /*-----------------------------------------------------------------------*/ 373 /*-----------------------------------------------------------------------*/
374   374  
375 #if _FS_MINIMIZE <= 1 375 #if _FS_MINIMIZE <= 1
376 static 376 static
377 void get_fileinfo ( /* No return code */ 377 void get_fileinfo ( /* No return code */
378 FILINFO *finfo, /* Ptr to store the File Information */ 378 FILINFO *finfo, /* Ptr to store the File Information */
379 const BYTE *dir /* Ptr to the directory entry */ 379 const BYTE *dir /* Ptr to the directory entry */
380 ) 380 )
381 { 381 {
382 BYTE n, c, a; 382 BYTE n, c, a;
383 char *p; 383 char *p;
384   384  
385   385  
386 p = &finfo->fname[0]; 386 p = &finfo->fname[0];
387 a = _USE_NTFLAG ? dir[DIR_NTres] : 0; /* NT flag */ 387 a = _USE_NTFLAG ? dir[DIR_NTres] : 0; /* NT flag */
388 for (n = 0; n < 8; n++) { /* Convert file name (body) */ 388 for (n = 0; n < 8; n++) { /* Convert file name (body) */
389 c = dir[n]; 389 c = dir[n];
390 if (c == ' ') break; 390 if (c == ' ') break;
391 if (c == 0x05) c = 0xE5; 391 if (c == 0x05) c = 0xE5;
392 if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20; 392 if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20;
393 *p++ = c; 393 *p++ = c;
394 } 394 }
395 if (dir[8] != ' ') { /* Convert file name (extension) */ 395 if (dir[8] != ' ') { /* Convert file name (extension) */
396 *p++ = '.'; 396 *p++ = '.';
397 for (n = 8; n < 11; n++) { 397 for (n = 8; n < 11; n++) {
398 c = dir[n]; 398 c = dir[n];
399 if (c == ' ') break; 399 if (c == ' ') break;
400 if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20; 400 if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20;
401 *p++ = c; 401 *p++ = c;
402 } 402 }
403 } 403 }
404 *p = '\0'; 404 *p = '\0';
405   405  
406 finfo->fattrib = dir[DIR_Attr]; /* Attribute */ 406 finfo->fattrib = dir[DIR_Attr]; /* Attribute */
407 finfo->fsize = LD_DWORD(&dir[DIR_FileSize]); /* Size */ 407 finfo->fsize = LD_DWORD(&dir[DIR_FileSize]); /* Size */
408 finfo->fdate = LD_WORD(&dir[DIR_WrtDate]); /* Date */ 408 finfo->fdate = LD_WORD(&dir[DIR_WrtDate]); /* Date */
409 finfo->ftime = LD_WORD(&dir[DIR_WrtTime]); /* Time */ 409 finfo->ftime = LD_WORD(&dir[DIR_WrtTime]); /* Time */
410 } 410 }
411 #endif /* _FS_MINIMIZE <= 1 */ 411 #endif /* _FS_MINIMIZE <= 1 */
412   412  
413   413  
414   414  
415   415  
416 /*-----------------------------------------------------------------------*/ 416 /*-----------------------------------------------------------------------*/
417 /* Pick a paragraph and create the name in format of directory entry */ 417 /* Pick a paragraph and create the name in format of directory entry */
418 /*-----------------------------------------------------------------------*/ 418 /*-----------------------------------------------------------------------*/
419   419  
420 static 420 static
421 char make_dirfile ( /* 1: error - detected an invalid format, '\0'or'/': next character */ 421 char make_dirfile ( /* 1: error - detected an invalid format, '\0'or'/': next character */
422 const char **path, /* Pointer to the file path pointer */ 422 const char **path, /* Pointer to the file path pointer */
423 char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */ 423 char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */
424 ) 424 )
425 { 425 {
426 BYTE n, t, c, a, b; 426 BYTE n, t, c, a, b;
427   427  
428   428  
429 memset(dirname, ' ', 8+3); /* Fill buffer with spaces */ 429 memset(dirname, ' ', 8+3); /* Fill buffer with spaces */
430 a = 0; b = 0x18; /* NT flag */ 430 a = 0; b = 0x18; /* NT flag */
431 n = 0; t = 8; 431 n = 0; t = 8;
432 for (;;) { 432 for (;;) {
433 c = *(*path)++; 433 c = *(*path)++;
434 if (c == '\0' || c == '/') { /* Reached to end of str or directory separator */ 434 if (c == '\0' || c == '/') { /* Reached to end of str or directory separator */
435 if (n == 0) break; 435 if (n == 0) break;
436 dirname[11] = _USE_NTFLAG ? (a & b) : 0; 436 dirname[11] = _USE_NTFLAG ? (a & b) : 0;
437 return c; 437 return c;
438 } 438 }
439 if (c <= ' ' || c == 0x7F) break; /* Reject invisible chars */ 439 if (c <= ' ' || c == 0x7F) break; /* Reject invisible chars */
440 if (c == '.') { 440 if (c == '.') {
441 if (!(a & 1) && n >= 1 && n <= 8) { /* Enter extension part */ 441 if (!(a & 1) && n >= 1 && n <= 8) { /* Enter extension part */
442 n = 8; t = 11; continue; 442 n = 8; t = 11; continue;
443 } 443 }
444 break; 444 break;
445 } 445 }
446 if (_USE_SJIS && 446 if (_USE_SJIS &&
447 ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ 447 ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */
448 (c >= 0xE0 && c <= 0xFC))) { 448 (c >= 0xE0 && c <= 0xFC))) {
449 if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ 449 if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */
450 c = 0x05; 450 c = 0x05;
451 a ^= 1; goto md_l2; 451 a ^= 1; goto md_l2;
452 } 452 }
453 if (c == '"') break; /* Reject " */ 453 if (c == '"') break; /* Reject " */
454 if (c <= ')') goto md_l1; /* Accept ! # $ % & ' ( ) */ 454 if (c <= ')') goto md_l1; /* Accept ! # $ % & ' ( ) */
455 if (c <= ',') break; /* Reject * + , */ 455 if (c <= ',') break; /* Reject * + , */
456 if (c <= '9') goto md_l1; /* Accept - 0-9 */ 456 if (c <= '9') goto md_l1; /* Accept - 0-9 */
457 if (c <= '?') break; /* Reject : ; < = > ? */ 457 if (c <= '?') break; /* Reject : ; < = > ? */
458 if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */ 458 if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */
459 if (c == '|') break; /* Reject | */ 459 if (c == '|') break; /* Reject | */
460 if (c >= '[' && c <= ']') break;/* Reject [ \ ] */ 460 if (c >= '[' && c <= ']') break;/* Reject [ \ ] */
461 if (_USE_NTFLAG && c >= 'A' && c <= 'Z') 461 if (_USE_NTFLAG && c >= 'A' && c <= 'Z')
462 (t == 8) ? (b &= ~0x08) : (b &= ~0x10); 462 (t == 8) ? (b &= ~0x08) : (b &= ~0x10);
463 if (c >= 'a' && c <= 'z') { /* Convert to upper case */ 463 if (c >= 'a' && c <= 'z') { /* Convert to upper case */
464 c -= 0x20; 464 c -= 0x20;
465 if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10); 465 if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
466 } 466 }
467 } 467 }
468 md_l1: 468 md_l1:
469 a &= ~1; 469 a &= ~1;
470 md_l2: 470 md_l2:
471 if (n >= t) break; 471 if (n >= t) break;
472 dirname[n++] = c; 472 dirname[n++] = c;
473 } 473 }
474 return 1; 474 return 1;
475 } 475 }
476   476  
477   477  
478   478  
479 /*-----------------------------------------------------------------------*/ 479 /*-----------------------------------------------------------------------*/
480 /* Trace a file path */ 480 /* Trace a file path */
481 /*-----------------------------------------------------------------------*/ 481 /*-----------------------------------------------------------------------*/
482   482  
483 static 483 static
484 FRESULT trace_path ( /* FR_OK(0): successful, !=0: error code */ 484 FRESULT trace_path ( /* FR_OK(0): successful, !=0: error code */
485 DIR *dirobj, /* Pointer to directory object to return last directory */ 485 DIR *dirobj, /* Pointer to directory object to return last directory */
486 char *fn, /* Pointer to last segment name to return */ 486 char *fn, /* Pointer to last segment name to return */
487 const char *path, /* Full-path string to trace a file or directory */ 487 const char *path, /* Full-path string to trace a file or directory */
488 BYTE **dir /* Directory pointer in Win[] to retutn */ 488 BYTE **dir /* Directory pointer in Win[] to retutn */
489 ) 489 )
490 { 490 {
491 CLUST clust; 491 CLUST clust;
492 char ds; 492 char ds;
493 BYTE *dptr = NULL; 493 BYTE *dptr = NULL;
494 FATFS *fs = FatFs; 494 FATFS *fs = FatFs;
495   495  
496 /* Initialize directory object */ 496 /* Initialize directory object */
497 clust = fs->dirbase; 497 clust = fs->dirbase;
498 #if _FAT32 498 #if _FAT32
499 if (fs->fs_type == FS_FAT32) { 499 if (fs->fs_type == FS_FAT32) {
500 dirobj->clust = dirobj->sclust = clust; 500 dirobj->clust = dirobj->sclust = clust;
501 dirobj->sect = clust2sect(clust); 501 dirobj->sect = clust2sect(clust);
502 } else 502 } else
503 #endif 503 #endif
504 { 504 {
505 dirobj->clust = dirobj->sclust = 0; 505 dirobj->clust = dirobj->sclust = 0;
506 dirobj->sect = clust; 506 dirobj->sect = clust;
507 } 507 }
508 dirobj->index = 0; 508 dirobj->index = 0;
509 dirobj->fs = fs; 509 dirobj->fs = fs;
510   510  
511 if (*path == '\0') { /* Null path means the root directory */ 511 if (*path == '\0') { /* Null path means the root directory */
512 *dir = NULL; return FR_OK; 512 *dir = NULL; return FR_OK;
513 } 513 }
514   514  
515 for (;;) { 515 for (;;) {
516 ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */ 516 ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */
517 if (ds == 1) return FR_INVALID_NAME; 517 if (ds == 1) return FR_INVALID_NAME;
518 for (;;) { 518 for (;;) {
519 if (!move_window(dirobj->sect)) return FR_RW_ERROR; 519 if (!move_window(dirobj->sect)) return FR_RW_ERROR;
520 dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ 520 dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */
521 if (dptr[DIR_Name] == 0) /* Has it reached to end of dir? */ 521 if (dptr[DIR_Name] == 0) /* Has it reached to end of dir? */
522 return !ds ? FR_NO_FILE : FR_NO_PATH; 522 return !ds ? FR_NO_FILE : FR_NO_PATH;
523 if (dptr[DIR_Name] != 0xE5 /* Matched? */ 523 if (dptr[DIR_Name] != 0xE5 /* Matched? */
524 && !(dptr[DIR_Attr] & AM_VOL) 524 && !(dptr[DIR_Attr] & AM_VOL)
525 && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break; 525 && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break;
526 if (!next_dir_entry(dirobj)) /* Next directory pointer */ 526 if (!next_dir_entry(dirobj)) /* Next directory pointer */
527 return !ds ? FR_NO_FILE : FR_NO_PATH; 527 return !ds ? FR_NO_FILE : FR_NO_PATH;
528 } 528 }
529 if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */ 529 if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */
530 if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */ 530 if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */
531 clust = /* Get cluster# of the directory */ 531 clust = /* Get cluster# of the directory */
532 #if _FAT32 532 #if _FAT32
533 ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) | 533 ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) |
534 #endif 534 #endif
535 LD_WORD(&dptr[DIR_FstClusLO]); 535 LD_WORD(&dptr[DIR_FstClusLO]);
536 dirobj->clust = dirobj->sclust = clust; /* Restart scannig with the new directory */ 536 dirobj->clust = dirobj->sclust = clust; /* Restart scannig with the new directory */
537 dirobj->sect = clust2sect(clust); 537 dirobj->sect = clust2sect(clust);
538 dirobj->index = 2; 538 dirobj->index = 2;
539 } 539 }
540 } 540 }
541   541  
542   542  
543   543  
544 /*-----------------------------------------------------------------------*/ 544 /*-----------------------------------------------------------------------*/
545 /* Reserve a directory entry */ 545 /* Reserve a directory entry */
546 /*-----------------------------------------------------------------------*/ 546 /*-----------------------------------------------------------------------*/
547   547  
548 #if !_FS_READONLY 548 #if !_FS_READONLY
549 static 549 static
550 FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */ 550 FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */
551 DIR *dirobj, /* Target directory to create new entry */ 551 DIR *dirobj, /* Target directory to create new entry */
552 BYTE **dir /* Pointer to pointer to created entry to retutn */ 552 BYTE **dir /* Pointer to pointer to created entry to retutn */
553 ) 553 )
554 { 554 {
555 CLUST clust; 555 CLUST clust;
556 DWORD sector; 556 DWORD sector;
557 BYTE c, n, *dptr; 557 BYTE c, n, *dptr;
558 FATFS *fs = FatFs; 558 FATFS *fs = FatFs;
559   559  
560   560  
561 /* Re-initialize directory object */ 561 /* Re-initialize directory object */
562 clust = dirobj->sclust; 562 clust = dirobj->sclust;
563 if (clust) { /* Dyanmic directory table */ 563 if (clust) { /* Dyanmic directory table */
564 dirobj->clust = clust; 564 dirobj->clust = clust;
565 dirobj->sect = clust2sect(clust); 565 dirobj->sect = clust2sect(clust);
566 } else { /* Static directory table */ 566 } else { /* Static directory table */
567 dirobj->sect = fs->dirbase; 567 dirobj->sect = fs->dirbase;
568 } 568 }
569 dirobj->index = 0; 569 dirobj->index = 0;
570   570  
571 do { 571 do {
572 if (!move_window(dirobj->sect)) return FR_RW_ERROR; 572 if (!move_window(dirobj->sect)) return FR_RW_ERROR;
573 dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ 573 dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */
574 c = dptr[DIR_Name]; 574 c = dptr[DIR_Name];
575 if (c == 0 || c == 0xE5) { /* Found an empty entry! */ 575 if (c == 0 || c == 0xE5) { /* Found an empty entry! */
576 *dir = dptr; return FR_OK; 576 *dir = dptr; return FR_OK;
577 } 577 }
578 } while (next_dir_entry(dirobj)); /* Next directory pointer */ 578 } while (next_dir_entry(dirobj)); /* Next directory pointer */
579 /* Reached to end of the directory table */ 579 /* Reached to end of the directory table */
580   580  
581 /* Abort when static table or could not stretch dynamic table */ 581 /* Abort when static table or could not stretch dynamic table */
582 if (!clust || !(clust = create_chain(dirobj->clust))) return FR_DENIED; 582 if (!clust || !(clust = create_chain(dirobj->clust))) return FR_DENIED;
583 if (clust == 1 || !move_window(0)) return FR_RW_ERROR; 583 if (clust == 1 || !move_window(0)) return FR_RW_ERROR;
584   584  
585 fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */ 585 fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */
586 memset(fs->win, 0, 512); 586 memset(fs->win, 0, 512);
587 for (n = fs->sects_clust; n; n--) { 587 for (n = fs->sects_clust; n; n--) {
588 if (disk_write(0, fs->win, sector, 1) != RES_OK) 588 if (disk_write(0, fs->win, sector, 1) != RES_OK)
589 return FR_RW_ERROR; 589 return FR_RW_ERROR;
590 sector++; 590 sector++;
591 } 591 }
592 fs->winflag = 1; 592 fs->winflag = 1;
593 *dir = fs->win; 593 *dir = fs->win;
594 return FR_OK; 594 return FR_OK;
595 } 595 }
596 #endif /* !_FS_READONLY */ 596 #endif /* !_FS_READONLY */
597   597  
598   598  
599   599  
600   600  
601 /*-----------------------------------------------------------------------*/ 601 /*-----------------------------------------------------------------------*/
602 /* Load boot record and check if it is a FAT boot record */ 602 /* Load boot record and check if it is a FAT boot record */
603 /*-----------------------------------------------------------------------*/ 603 /*-----------------------------------------------------------------------*/
604   604  
605 static 605 static
606 BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */ 606 BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */
607 DWORD sect /* Sector# to check if it is a FAT boot record or not */ 607 DWORD sect /* Sector# to check if it is a FAT boot record or not */
608 ) 608 )
609 { 609 {
610 FATFS *fs = FatFs; 610 FATFS *fs = FatFs;
611   611  
612 if (disk_read(0, fs->win, sect, 1) != RES_OK) /* Load boot record */ 612 if (disk_read(0, fs->win, sect, 1) != RES_OK) /* Load boot record */
613 return 2; 613 return 2;
614 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature */ 614 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature */
615 return 2; 615 return 2;
616   616  
617 if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3)) /* Check FAT signature */ 617 if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3)) /* Check FAT signature */
618 return 0; 618 return 0;
619 #if _FAT32 619 #if _FAT32
620 if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80)) 620 if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))
621 return 0; 621 return 0;
622 #endif 622 #endif
623 return 1; 623 return 1;
624 } 624 }
625   625  
626   626  
627   627  
628   628  
629 /*-----------------------------------------------------------------------*/ 629 /*-----------------------------------------------------------------------*/
630 /* Make sure that the file system is valid */ 630 /* Make sure that the file system is valid */
631 /*-----------------------------------------------------------------------*/ 631 /*-----------------------------------------------------------------------*/
632   632  
633 static 633 static
634 FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ 634 FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */
635 const char **path, /* Pointer to pointer to the path name (drive number) */ 635 const char **path, /* Pointer to pointer to the path name (drive number) */
636 BYTE chk_wp /* !=0: Check media write protection for wrinting fuctions */ 636 BYTE chk_wp /* !=0: Check media write protection for wrinting fuctions */
637 ) 637 )
638 { 638 {
639 BYTE fmt; 639 BYTE fmt;
640 DSTATUS stat; 640 DSTATUS stat;
641 DWORD bootsect, fatsize, totalsect, maxclust; 641 DWORD bootsect, fatsize, totalsect, maxclust;
642 const char *p = *path; 642 const char *p = *path;
643 FATFS *fs = FatFs; 643 FATFS *fs = FatFs;
644   644  
645   645  
646   646  
647 while (*p == ' ') p++; /* Strip leading spaces */ 647 while (*p == ' ') p++; /* Strip leading spaces */
648 if (*p == '/') p++; /* Strip heading slash */ 648 if (*p == '/') p++; /* Strip heading slash */
649 *path = p; /* Return pointer to the path name */ 649 *path = p; /* Return pointer to the path name */
650   650  
651 /* Is the file system object registered? */ 651 /* Is the file system object registered? */
652 if (!fs) return FR_NOT_ENABLED; 652 if (!fs) return FR_NOT_ENABLED;
653   653  
654 /* Chekck if the logical drive has been mounted or not */ 654 /* Chekck if the logical drive has been mounted or not */
655 if (fs->fs_type) { 655 if (fs->fs_type) {
656 stat = disk_status(0); 656 stat = disk_status(0);
657 if (!(stat & STA_NOINIT)) { /* If the physical drive is kept initialized */ 657 if (!(stat & STA_NOINIT)) { /* If the physical drive is kept initialized */
658 #if !_FS_READONLY 658 #if !_FS_READONLY
659 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ 659 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
660 return FR_WRITE_PROTECTED; 660 return FR_WRITE_PROTECTED;
661 #endif 661 #endif
662 return FR_OK; /* The file system object is valid */ 662 return FR_OK; /* The file system object is valid */
663 } 663 }
664 } 664 }
665   665  
666 /* The logical drive has not been mounted, following code attempts to mount the logical drive */ 666 /* The logical drive has not been mounted, following code attempts to mount the logical drive */
667   667  
668 memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */ 668 memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */
669 stat = disk_initialize(0); /* Initialize low level disk I/O layer */ 669 stat = disk_initialize(0); /* Initialize low level disk I/O layer */
670 if (stat & STA_NOINIT) /* Check if the drive is ready */ 670 if (stat & STA_NOINIT) /* Check if the drive is ready */
671 return FR_NOT_READY; 671 return FR_NOT_READY;
672 #if !_FS_READONLY 672 #if !_FS_READONLY
673 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ 673 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
674 return FR_WRITE_PROTECTED; 674 return FR_WRITE_PROTECTED;
675 #endif 675 #endif
676   676  
677 /* Search FAT partition on the drive */ 677 /* Search FAT partition on the drive */
678 fmt = check_fs(bootsect = 0); /* Check sector 0 as an SFD format */ 678 fmt = check_fs(bootsect = 0); /* Check sector 0 as an SFD format */
679 if (fmt == 1) { /* Not a FAT boot record, it may be patitioned */ 679 if (fmt == 1) { /* Not a FAT boot record, it may be patitioned */
680 /* Check a partition listed in top of the partition table */ 680 /* Check a partition listed in top of the partition table */
681 if (fs->win[MBR_Table+4]) { /* Is the 1st partition existing? */ 681 if (fs->win[MBR_Table+4]) { /* Is the 1st partition existing? */
682 bootsect = LD_DWORD(&fs->win[MBR_Table+8]); /* Partition offset in LBA */ 682 bootsect = LD_DWORD(&fs->win[MBR_Table+8]); /* Partition offset in LBA */
683 fmt = check_fs(bootsect); /* Check the partition */ 683 fmt = check_fs(bootsect); /* Check the partition */
684 } 684 }
685 } 685 }
686 if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512) /* No valid FAT patition is found */ 686 if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512) /* No valid FAT patition is found */
687 return FR_NO_FILESYSTEM; 687 return FR_NO_FILESYSTEM;
688   688  
689 /* Initialize the file system object */ 689 /* Initialize the file system object */
690 fatsize = LD_WORD(&fs->win[BPB_FATSz16]); /* Number of sectors per FAT */ 690 fatsize = LD_WORD(&fs->win[BPB_FATSz16]); /* Number of sectors per FAT */
691 if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]); 691 if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]);
692 fs->sects_fat = (CLUST)fatsize; 692 fs->sects_fat = (CLUST)fatsize;
693 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ 693 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */
694 fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */ 694 fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */
695 fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */ 695 fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
696 fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ 696 fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
697 fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */ 697 fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */
698 totalsect = LD_WORD(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */ 698 totalsect = LD_WORD(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */
699 if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); 699 if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]);
700 fs->max_clust = maxclust = (totalsect /* Last cluster# + 1 */ 700 fs->max_clust = maxclust = (totalsect /* Last cluster# + 1 */
701 - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / 16 701 - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / 16
702 ) / fs->sects_clust + 2; 702 ) / fs->sects_clust + 2;
703   703  
704 fmt = FS_FAT12; /* Determine the FAT sub type */ 704 fmt = FS_FAT12; /* Determine the FAT sub type */
705 if (maxclust > 0xFF7) fmt = FS_FAT16; 705 if (maxclust > 0xFF7) fmt = FS_FAT16;
706 if (maxclust > 0xFFF7) 706 if (maxclust > 0xFFF7)
707 #if !_FAT32 707 #if !_FAT32
708 return FR_NO_FILESYSTEM; 708 return FR_NO_FILESYSTEM;
709 #else 709 #else
710 fmt = FS_FAT32; 710 fmt = FS_FAT32;
711 if (fmt == FS_FAT32) 711 if (fmt == FS_FAT32)
712 fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]); /* Root directory start cluster */ 712 fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]); /* Root directory start cluster */
713 else 713 else
714 #endif 714 #endif
715 fs->dirbase = fs->fatbase + fatsize; /* Root directory start sector (lba) */ 715 fs->dirbase = fs->fatbase + fatsize; /* Root directory start sector (lba) */
716 fs->database = fs->fatbase + fatsize + fs->n_rootdir / 16; /* Data start sector (lba) */ 716 fs->database = fs->fatbase + fatsize + fs->n_rootdir / 16; /* Data start sector (lba) */
717 fs->fs_type = fmt; /* FAT sub-type */ 717 fs->fs_type = fmt; /* FAT sub-type */
718   718  
719 #if !_FS_READONLY 719 #if !_FS_READONLY
720 fs->free_clust = (CLUST)0xFFFFFFFF; 720 fs->free_clust = (CLUST)0xFFFFFFFF;
721 #if _USE_FSINFO 721 #if _USE_FSINFO
722 /* Load fsinfo sector if needed */ 722 /* Load fsinfo sector if needed */
723 if (fmt == FS_FAT32) { 723 if (fmt == FS_FAT32) {
724 fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]); 724 fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]);
725 if (disk_read(0, fs->win, fs->fsi_sector, 1) == RES_OK && 725 if (disk_read(0, fs->win, fs->fsi_sector, 1) == RES_OK &&
726 LD_WORD(&fs->win[BS_55AA]) == 0xAA55 && 726 LD_WORD(&fs->win[BS_55AA]) == 0xAA55 &&
727 LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 && 727 LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 &&
728 LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272) { 728 LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272) {
729 fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]); 729 fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]);
730 fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]); 730 fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]);
731 } 731 }
732 } 732 }
733 #endif 733 #endif
734 #endif 734 #endif
735 fs->id = ++fsid; /* File system mount ID */ 735 fs->id = ++fsid; /* File system mount ID */
736 return FR_OK; 736 return FR_OK;
737 } 737 }
738   738  
739   739  
740   740  
741   741  
742 /*-----------------------------------------------------------------------*/ 742 /*-----------------------------------------------------------------------*/
743 /* Check if the file/dir object is valid or not */ 743 /* Check if the file/dir object is valid or not */
744 /*-----------------------------------------------------------------------*/ 744 /*-----------------------------------------------------------------------*/
745   745  
746 static 746 static
747 FRESULT validate ( /* FR_OK(0): The id is valid, !=0: Not valid */ 747 FRESULT validate ( /* FR_OK(0): The id is valid, !=0: Not valid */
748 const FATFS *fs, /* Pointer to the file system object */ 748 const FATFS *fs, /* Pointer to the file system object */
749 WORD id /* id member of the target object to be checked */ 749 WORD id /* id member of the target object to be checked */
750 ) 750 )
751 { 751 {
752 if (!fs || fs->id != id) 752 if (!fs || fs->id != id)
753 return FR_INVALID_OBJECT; 753 return FR_INVALID_OBJECT;
754 if (disk_status(0) & STA_NOINIT) 754 if (disk_status(0) & STA_NOINIT)
755 return FR_NOT_READY; 755 return FR_NOT_READY;
756   756  
757 return FR_OK; 757 return FR_OK;
758 } 758 }
759   759  
760   760  
761   761  
762   762  
763 /*-------------------------------------------------------------------------- 763 /*--------------------------------------------------------------------------
764   764  
765 Public Functions 765 Public Functions
766   766  
767 --------------------------------------------------------------------------*/ 767 --------------------------------------------------------------------------*/
768   768  
769   769  
770 /*-----------------------------------------------------------------------*/ 770 /*-----------------------------------------------------------------------*/
771 /* Mount/Unmount a Locical Drive */ 771 /* Mount/Unmount a Locical Drive */
772 /*-----------------------------------------------------------------------*/ 772 /*-----------------------------------------------------------------------*/
773   773  
774 FRESULT f_mount ( 774 FRESULT f_mount (
775 BYTE drv, /* Logical drive number to be mounted/unmounted */ 775 BYTE drv, /* Logical drive number to be mounted/unmounted */
776 FATFS *fs /* Pointer to new file system object (NULL for unmount)*/ 776 FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
777 ) 777 )
778 { 778 {
779 FATFS *fsobj; 779 FATFS *fsobj;
780   780  
781   781  
782 if (drv) return FR_INVALID_DRIVE; 782 if (drv) return FR_INVALID_DRIVE;
783 fsobj = FatFs; 783 fsobj = FatFs;
784 FatFs = fs; 784 FatFs = fs;
785 if (fsobj) memset(fsobj, 0, sizeof(FATFS)); 785 if (fsobj) memset(fsobj, 0, sizeof(FATFS));
786 if (fs) memset(fs, 0, sizeof(FATFS)); 786 if (fs) memset(fs, 0, sizeof(FATFS));
787   787  
788 return FR_OK; 788 return FR_OK;
789 } 789 }
790   790  
791   791  
792   792  
793   793  
794 /*-----------------------------------------------------------------------*/ 794 /*-----------------------------------------------------------------------*/
795 /* Open or Create a File */ 795 /* Open or Create a File */
796 /*-----------------------------------------------------------------------*/ 796 /*-----------------------------------------------------------------------*/
797   797  
798 FRESULT f_open ( 798 FRESULT f_open (
799 FIL *fp, /* Pointer to the blank file object */ 799 FIL *fp, /* Pointer to the blank file object */
800 const char *path, /* Pointer to the file name */ 800 const char *path, /* Pointer to the file name */
801 BYTE mode /* Access mode and file open mode flags */ 801 BYTE mode /* Access mode and file open mode flags */
802 ) 802 )
803 { 803 {
804 FRESULT res; 804 FRESULT res;
805 BYTE *dir; 805 BYTE *dir;
806 DIR dirobj; 806 DIR dirobj;
807 char fn[8+3+1]; 807 char fn[8+3+1];
808 FATFS *fs = FatFs; 808 FATFS *fs = FatFs;
809   809  
810   810  
811 fp->fs = NULL; 811 fp->fs = NULL;
812 #if !_FS_READONLY 812 #if !_FS_READONLY
813 mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW); 813 mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
814 res = auto_mount(&path, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW))); 814 res = auto_mount(&path, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
815 #else 815 #else
816 mode &= FA_READ; 816 mode &= FA_READ;
817 res = auto_mount(&path, 0); 817 res = auto_mount(&path, 0);
818 #endif 818 #endif
819 if (res != FR_OK) return res; 819 if (res != FR_OK) return res;
820   820  
821 /* Trace the file path */ 821 /* Trace the file path */
822 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ 822 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
823   823  
824 #if !_FS_READONLY 824 #if !_FS_READONLY
825 /* Create or Open a File */ 825 /* Create or Open a File */
826 if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) { 826 if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
827 CLUST rs; 827 CLUST rs;
828 DWORD dw; 828 DWORD dw;
829 if (res != FR_OK) { /* No file, create new */ 829 if (res != FR_OK) { /* No file, create new */
830 if (res != FR_NO_FILE) return res; 830 if (res != FR_NO_FILE) return res;
831 res = reserve_direntry(&dirobj, &dir); 831 res = reserve_direntry(&dirobj, &dir);
832 if (res != FR_OK) return res; 832 if (res != FR_OK) return res;
833 memset(dir, 0, 32); /* Initialize the new entry */ 833 memset(dir, 0, 32); /* Initialize the new entry */
834 memcpy(&dir[DIR_Name], fn, 8+3); 834 memcpy(&dir[DIR_Name], fn, 8+3);
835 dir[DIR_NTres] = fn[11]; 835 dir[DIR_NTres] = fn[11];
836 mode |= FA_CREATE_ALWAYS; 836 mode |= FA_CREATE_ALWAYS;
837 } else { /* Any object is already existing */ 837 } else { /* Any object is already existing */
838 if (mode & FA_CREATE_NEW) /* Cannot create new */ 838 if (mode & FA_CREATE_NEW) /* Cannot create new */
839 return FR_EXIST; 839 return FR_EXIST;
840 if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR))) /* Cannot overwrite (R/O or DIR) */ 840 if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR))) /* Cannot overwrite (R/O or DIR) */
841 return FR_DENIED; 841 return FR_DENIED;
842 if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */ 842 if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */
843 #if _FAT32 843 #if _FAT32
844 rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); 844 rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
845 ST_WORD(&dir[DIR_FstClusHI], 0); 845 ST_WORD(&dir[DIR_FstClusHI], 0);
846 #else 846 #else
847 rs = LD_WORD(&dir[DIR_FstClusLO]); 847 rs = LD_WORD(&dir[DIR_FstClusLO]);
848 #endif 848 #endif
849 ST_WORD(&dir[DIR_FstClusLO], 0); /* cluster = 0 */ 849 ST_WORD(&dir[DIR_FstClusLO], 0); /* cluster = 0 */
850 ST_DWORD(&dir[DIR_FileSize], 0); /* size = 0 */ 850 ST_DWORD(&dir[DIR_FileSize], 0); /* size = 0 */
851 fs->winflag = 1; 851 fs->winflag = 1;
852 dw = fs->winsect; /* Remove the cluster chain */ 852 dw = fs->winsect; /* Remove the cluster chain */
853 if (!remove_chain(rs) || !move_window(dw)) 853 if (!remove_chain(rs) || !move_window(dw))
854 return FR_RW_ERROR; 854 return FR_RW_ERROR;
855 fs->last_clust = rs - 1; /* Reuse the cluster hole */ 855 fs->last_clust = rs - 1; /* Reuse the cluster hole */
856 } 856 }
857 } 857 }
858 if (mode & FA_CREATE_ALWAYS) { 858 if (mode & FA_CREATE_ALWAYS) {
859 dir[DIR_Attr] = AM_ARC; /* New attribute */ 859 dir[DIR_Attr] = AM_ARC; /* New attribute */
860 dw = get_fattime(); 860 dw = get_fattime();
861 ST_DWORD(&dir[DIR_WrtTime], dw); /* Updated time */ 861 ST_DWORD(&dir[DIR_WrtTime], dw); /* Updated time */
862 ST_DWORD(&dir[DIR_CrtTime], dw); /* Created time */ 862 ST_DWORD(&dir[DIR_CrtTime], dw); /* Created time */
863 fs->winflag = 1; 863 fs->winflag = 1;
864 } 864 }
865 } 865 }
866 /* Open a File */ 866 /* Open a File */
867 else { 867 else {
868 #endif /* !_FS_READONLY */ 868 #endif /* !_FS_READONLY */
869 if (res != FR_OK) return res; /* Trace failed */ 869 if (res != FR_OK) return res; /* Trace failed */
870 if (dir == NULL || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */ 870 if (dir == NULL || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */
871 return FR_NO_FILE; 871 return FR_NO_FILE;
872 #if !_FS_READONLY 872 #if !_FS_READONLY
873 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ 873 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
874 return FR_DENIED; 874 return FR_DENIED;
875 } 875 }
876   876  
877 fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ 877 fp->dir_sect = fs->winsect; /* Pointer to the directory entry */
878 fp->dir_ptr = dir; 878 fp->dir_ptr = dir;
879 #endif 879 #endif
880 fp->flag = mode; /* File access mode */ 880 fp->flag = mode; /* File access mode */
881 fp->org_clust = /* File start cluster */ 881 fp->org_clust = /* File start cluster */
882 #if _FAT32 882 #if _FAT32
883 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | 883 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
884 #endif 884 #endif
885 LD_WORD(&dir[DIR_FstClusLO]); 885 LD_WORD(&dir[DIR_FstClusLO]);
886 fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */ 886 fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */
887 fp->fptr = 0; /* File ptr */ 887 fp->fptr = 0; /* File ptr */
888 fp->sect_clust = 1; /* Sector counter */ 888 fp->sect_clust = 1; /* Sector counter */
889 fp->fs = fs; fp->id = fs->id; /* Owner file system object of the file */ 889 fp->fs = fs; fp->id = fs->id; /* Owner file system object of the file */
890   890  
891 return FR_OK; 891 return FR_OK;
892 } 892 }
893   893  
894   894  
895   895  
896   896  
897 /*-----------------------------------------------------------------------*/ 897 /*-----------------------------------------------------------------------*/
898 /* Read File */ 898 /* Read File */
899 /*-----------------------------------------------------------------------*/ 899 /*-----------------------------------------------------------------------*/
900   900  
901 FRESULT f_read ( 901 FRESULT f_read (
902 FIL *fp, /* Pointer to the file object */ 902 FIL *fp, /* Pointer to the file object */
903 void *buff, /* Pointer to data buffer */ 903 void *buff, /* Pointer to data buffer */
904 WORD btr, /* Number of bytes to read */ 904 WORD btr, /* Number of bytes to read */
905 WORD *br /* Pointer to number of bytes read */ 905 WORD *br /* Pointer to number of bytes read */
906 ) 906 )
907 { 907 {
908 DWORD sect, remain; 908 DWORD sect, remain;
909 WORD rcnt; 909 WORD rcnt;
910 CLUST clust; 910 CLUST clust;
911 BYTE cc, *rbuff = buff; 911 BYTE cc, *rbuff = buff;
912 FRESULT res; 912 FRESULT res;
913 FATFS *fs = fp->fs; 913 FATFS *fs = fp->fs;
914   914  
915   915  
916 *br = 0; 916 *br = 0;
917 res = validate(fs, fp->id); /* Check validity of the object */ 917 res = validate(fs, fp->id); /* Check validity of the object */
918 if (res) return res; 918 if (res) return res;
919 if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ 919 if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */
920 if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */ 920 if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */
921 remain = fp->fsize - fp->fptr; 921 remain = fp->fsize - fp->fptr;
922 if (btr > remain) btr = (WORD)remain; /* Truncate read count by number of bytes left */ 922 if (btr > remain) btr = (WORD)remain; /* Truncate read count by number of bytes left */
923   923  
924 for ( ; btr; /* Repeat until all data transferred */ 924 for ( ; btr; /* Repeat until all data transferred */
925 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { 925 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
926 if ((fp->fptr % 512) == 0) { /* On the sector boundary */ 926 if ((fp->fptr % 512) == 0) { /* On the sector boundary */
927 if (--fp->sect_clust) { /* Decrement left sector counter */ 927 if (--fp->sect_clust) { /* Decrement left sector counter */
928 sect = fp->curr_sect + 1; /* Get current sector */ 928 sect = fp->curr_sect + 1; /* Get current sector */
929 } else { /* On the cluster boundary, get next cluster */ 929 } else { /* On the cluster boundary, get next cluster */
930 clust = (fp->fptr == 0) ? 930 clust = (fp->fptr == 0) ?
931 fp->org_clust : get_cluster(fp->curr_clust); 931 fp->org_clust : get_cluster(fp->curr_clust);
932 if (clust < 2 || clust >= fs->max_clust) 932 if (clust < 2 || clust >= fs->max_clust)
933 goto fr_error; 933 goto fr_error;
934 fp->curr_clust = clust; /* Current cluster */ 934 fp->curr_clust = clust; /* Current cluster */
935 sect = clust2sect(clust); /* Get current sector */ 935 sect = clust2sect(clust); /* Get current sector */
936 fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ 936 fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */
937 } 937 }
938 fp->curr_sect = sect; /* Update current sector */ 938 fp->curr_sect = sect; /* Update current sector */
939 cc = btr / 512; /* When left bytes >= 512, */ 939 cc = btr / 512; /* When left bytes >= 512, */
940 if (cc) { /* Read maximum contiguous sectors directly */ 940 if (cc) { /* Read maximum contiguous sectors directly */
941 if (cc > fp->sect_clust) cc = fp->sect_clust; 941 if (cc > fp->sect_clust) cc = fp->sect_clust;
942 if (disk_read(0, rbuff, sect, cc) != RES_OK) 942 if (disk_read(0, rbuff, sect, cc) != RES_OK)
943 goto fr_error; 943 goto fr_error;
944 fp->sect_clust -= cc - 1; 944 fp->sect_clust -= cc - 1;
945 fp->curr_sect += cc - 1; 945 fp->curr_sect += cc - 1;
946 rcnt = cc * 512; continue; 946 rcnt = cc * 512; continue;
947 } 947 }
948 } 948 }
949 if (!move_window(fp->curr_sect)) goto fr_error; /* Move sector window */ 949 if (!move_window(fp->curr_sect)) goto fr_error; /* Move sector window */
950 rcnt = 512 - (WORD)(fp->fptr % 512); /* Copy fractional bytes from sector window */ 950 rcnt = 512 - (WORD)(fp->fptr % 512); /* Copy fractional bytes from sector window */
951 if (rcnt > btr) rcnt = btr; 951 if (rcnt > btr) rcnt = btr;
952 memcpy(rbuff, &fs->win[(WORD)fp->fptr % 512], rcnt); 952 memcpy(rbuff, &fs->win[(WORD)fp->fptr % 512], rcnt);
953 } 953 }
954   954  
955 return FR_OK; 955 return FR_OK;
956   956  
957 fr_error: /* Abort this function due to an unrecoverable error */ 957 fr_error: /* Abort this function due to an unrecoverable error */
958 fp->flag |= FA__ERROR; 958 fp->flag |= FA__ERROR;
959 return FR_RW_ERROR; 959 return FR_RW_ERROR;
960 } 960 }
961   961  
962   962  
963   963  
964   964  
965 #if !_FS_READONLY 965 #if !_FS_READONLY
966 /*-----------------------------------------------------------------------*/ 966 /*-----------------------------------------------------------------------*/
967 /* Write File */ 967 /* Write File */
968 /*-----------------------------------------------------------------------*/ 968 /*-----------------------------------------------------------------------*/
969   969  
970 FRESULT f_write ( 970 FRESULT f_write (
971 FIL *fp, /* Pointer to the file object */ 971 FIL *fp, /* Pointer to the file object */
972 const void *buff, /* Pointer to the data to be written */ 972 const void *buff, /* Pointer to the data to be written */
973 WORD btw, /* Number of bytes to write */ 973 WORD btw, /* Number of bytes to write */
974 WORD *bw /* Pointer to number of bytes written */ 974 WORD *bw /* Pointer to number of bytes written */
975 ) 975 )
976 { 976 {
977 DWORD sect; 977 DWORD sect;
978 WORD wcnt; 978 WORD wcnt;
979 CLUST clust; 979 CLUST clust;
980 BYTE cc; 980 BYTE cc;
981 FRESULT res; 981 FRESULT res;
982 const BYTE *wbuff = buff; 982 const BYTE *wbuff = buff;
983 FATFS *fs = fp->fs; 983 FATFS *fs = fp->fs;
984   984  
985   985  
986 *bw = 0; 986 *bw = 0;
987 res = validate(fs, fp->id); /* Check validity of the object */ 987 res = validate(fs, fp->id); /* Check validity of the object */
988 if (res) return res; 988 if (res) return res;
989 if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ 989 if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */
990 if (!(fp->flag & FA_WRITE)) return FR_DENIED; /* Check access mode */ 990 if (!(fp->flag & FA_WRITE)) return FR_DENIED; /* Check access mode */
991 if (fp->fsize + btw < fp->fsize) return FR_OK; /* File size cannot reach 4GB */ 991 if (fp->fsize + btw < fp->fsize) return FR_OK; /* File size cannot reach 4GB */
992   992  
993 for ( ; btw; /* Repeat until all data transferred */ 993 for ( ; btw; /* Repeat until all data transferred */
994 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { 994 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
995 if ((fp->fptr % 512) == 0) { /* On the sector boundary */ 995 if ((fp->fptr % 512) == 0) { /* On the sector boundary */
996 if (--(fp->sect_clust)) { /* Decrement left sector counter */ 996 if (--(fp->sect_clust)) { /* Decrement left sector counter */
997 sect = fp->curr_sect + 1; /* Get current sector */ 997 sect = fp->curr_sect + 1; /* Get current sector */
998 } else { /* On the cluster boundary, get next cluster */ 998 } else { /* On the cluster boundary, get next cluster */
999 if (fp->fptr == 0) { /* Is top of the file */ 999 if (fp->fptr == 0) { /* Is top of the file */
1000 clust = fp->org_clust; 1000 clust = fp->org_clust;
1001 if (clust == 0) /* No cluster is created yet */ 1001 if (clust == 0) /* No cluster is created yet */
1002 fp->org_clust = clust = create_chain(0); /* Create a new cluster chain */ 1002 fp->org_clust = clust = create_chain(0); /* Create a new cluster chain */
1003 } else { /* Middle or end of file */ 1003 } else { /* Middle or end of file */
1004 clust = create_chain(fp->curr_clust); /* Trace or streach cluster chain */ 1004 clust = create_chain(fp->curr_clust); /* Trace or streach cluster chain */
1005 } 1005 }
1006 if (clust == 0) break; /* Disk full */ 1006 if (clust == 0) break; /* Disk full */
1007 if (clust == 1 || clust >= fs->max_clust) goto fw_error; 1007 if (clust == 1 || clust >= fs->max_clust) goto fw_error;
1008 fp->curr_clust = clust; /* Current cluster */ 1008 fp->curr_clust = clust; /* Current cluster */
1009 sect = clust2sect(clust); /* Get current sector */ 1009 sect = clust2sect(clust); /* Get current sector */
1010 fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ 1010 fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */
1011 } 1011 }
1012 fp->curr_sect = sect; /* Update current sector */ 1012 fp->curr_sect = sect; /* Update current sector */
1013 cc = btw / 512; /* When left bytes >= 512, */ 1013 cc = btw / 512; /* When left bytes >= 512, */
1014 if (cc) { /* Write maximum contiguous sectors directly */ 1014 if (cc) { /* Write maximum contiguous sectors directly */
1015 if (cc > fp->sect_clust) cc = fp->sect_clust; 1015 if (cc > fp->sect_clust) cc = fp->sect_clust;
1016 if (disk_write(0, wbuff, sect, cc) != RES_OK) 1016 if (disk_write(0, wbuff, sect, cc) != RES_OK)
1017 goto fw_error; 1017 goto fw_error;
1018 fp->sect_clust -= cc - 1; 1018 fp->sect_clust -= cc - 1;
1019 fp->curr_sect += cc - 1; 1019 fp->curr_sect += cc - 1;
1020 wcnt = cc * 512; continue; 1020 wcnt = cc * 512; continue;
1021 } 1021 }
1022 if (fp->fptr >= fp->fsize) { /* Flush R/W window if needed */ 1022 if (fp->fptr >= fp->fsize) { /* Flush R/W window if needed */
1023 if (!move_window(0)) goto fw_error; 1023 if (!move_window(0)) goto fw_error;
1024 fs->winsect = fp->curr_sect; 1024 fs->winsect = fp->curr_sect;
1025 } 1025 }
1026 } 1026 }
1027 if (!move_window(fp->curr_sect)) /* Move sector window */ 1027 if (!move_window(fp->curr_sect)) /* Move sector window */
1028 goto fw_error; 1028 goto fw_error;
1029 wcnt = 512 - (WORD)(fp->fptr % 512); /* Copy fractional bytes bytes to sector window */ 1029 wcnt = 512 - (WORD)(fp->fptr % 512); /* Copy fractional bytes bytes to sector window */
1030 if (wcnt > btw) wcnt = btw; 1030 if (wcnt > btw) wcnt = btw;
1031 memcpy(&fs->win[(WORD)fp->fptr % 512], wbuff, wcnt); 1031 memcpy(&fs->win[(WORD)fp->fptr % 512], wbuff, wcnt);
1032 fs->winflag = 1; 1032 fs->winflag = 1;
1033 } 1033 }
1034   1034  
1035 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ 1035 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
1036 fp->flag |= FA__WRITTEN; /* Set file changed flag */ 1036 fp->flag |= FA__WRITTEN; /* Set file changed flag */
1037 return FR_OK; 1037 return FR_OK;
1038   1038  
1039 fw_error: /* Abort this function due to an unrecoverable error */ 1039 fw_error: /* Abort this function due to an unrecoverable error */
1040 fp->flag |= FA__ERROR; 1040 fp->flag |= FA__ERROR;
1041 return FR_RW_ERROR; 1041 return FR_RW_ERROR;
1042 } 1042 }
1043   1043  
1044   1044  
1045   1045  
1046   1046  
1047 /*-----------------------------------------------------------------------*/ 1047 /*-----------------------------------------------------------------------*/
1048 /* Synchronize between File and Disk */ 1048 /* Synchronize between File and Disk */
1049 /*-----------------------------------------------------------------------*/ 1049 /*-----------------------------------------------------------------------*/
1050   1050  
1051 FRESULT f_sync ( 1051 FRESULT f_sync (
1052 FIL *fp /* Pointer to the file object */ 1052 FIL *fp /* Pointer to the file object */
1053 ) 1053 )
1054 { 1054 {
1055 DWORD tim; 1055 DWORD tim;
1056 BYTE *dir; 1056 BYTE *dir;
1057 FRESULT res; 1057 FRESULT res;
1058 FATFS *fs = fp->fs; 1058 FATFS *fs = fp->fs;
1059   1059  
1060   1060  
1061 res = validate(fs, fp->id); /* Check validity of the object */ 1061 res = validate(fs, fp->id); /* Check validity of the object */
1062 if (res == FR_OK) { 1062 if (res == FR_OK) {
1063 if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ 1063 if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
1064 /* Update the directory entry */ 1064 /* Update the directory entry */
1065 if (!move_window(fp->dir_sect)) 1065 if (!move_window(fp->dir_sect))
1066 return FR_RW_ERROR; 1066 return FR_RW_ERROR;
1067 dir = fp->dir_ptr; 1067 dir = fp->dir_ptr;
1068 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ 1068 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
1069 ST_DWORD(&dir[DIR_FileSize], fp->fsize); /* Update file size */ 1069 ST_DWORD(&dir[DIR_FileSize], fp->fsize); /* Update file size */
1070 ST_WORD(&dir[DIR_FstClusLO], fp->org_clust); /* Update start cluster */ 1070 ST_WORD(&dir[DIR_FstClusLO], fp->org_clust); /* Update start cluster */
1071 #if _FAT32 1071 #if _FAT32
1072 ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16); 1072 ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16);
1073 #endif 1073 #endif
1074 tim = get_fattime(); /* Updated time */ 1074 tim = get_fattime(); /* Updated time */
1075 ST_DWORD(&dir[DIR_WrtTime], tim); 1075 ST_DWORD(&dir[DIR_WrtTime], tim);
1076 fp->flag &= ~FA__WRITTEN; 1076 fp->flag &= ~FA__WRITTEN;
1077 res = sync(); 1077 res = sync();
1078 } 1078 }
1079 } 1079 }
1080 return res; 1080 return res;
1081 } 1081 }
1082   1082  
1083 #endif /* !_FS_READONLY */ 1083 #endif /* !_FS_READONLY */
1084   1084  
1085   1085  
1086   1086  
1087   1087  
1088 /*-----------------------------------------------------------------------*/ 1088 /*-----------------------------------------------------------------------*/
1089 /* Close File */ 1089 /* Close File */
1090 /*-----------------------------------------------------------------------*/ 1090 /*-----------------------------------------------------------------------*/
1091   1091  
1092 FRESULT f_close ( 1092 FRESULT f_close (
1093 FIL *fp /* Pointer to the file object to be closed */ 1093 FIL *fp /* Pointer to the file object to be closed */
1094 ) 1094 )
1095 { 1095 {
1096 FRESULT res; 1096 FRESULT res;
1097   1097  
1098   1098  
1099 #if !_FS_READONLY 1099 #if !_FS_READONLY
1100 res = f_sync(fp); 1100 res = f_sync(fp);
1101 #else 1101 #else
1102 res = validate(fp->fs, fp->id); 1102 res = validate(fp->fs, fp->id);
1103 #endif 1103 #endif
1104 if (res == FR_OK) 1104 if (res == FR_OK)
1105 fp->fs = NULL; 1105 fp->fs = NULL;
1106   1106  
1107 return res; 1107 return res;
1108 } 1108 }
1109   1109  
1110   1110  
1111   1111  
1112   1112  
1113 #if _FS_MINIMIZE <= 2 1113 #if _FS_MINIMIZE <= 2
1114 /*-----------------------------------------------------------------------*/ 1114 /*-----------------------------------------------------------------------*/
1115 /* Seek File Pointer */ 1115 /* Seek File Pointer */
1116 /*-----------------------------------------------------------------------*/ 1116 /*-----------------------------------------------------------------------*/
1117   1117  
1118 FRESULT f_lseek ( 1118 FRESULT f_lseek (
1119 FIL *fp, /* Pointer to the file object */ 1119 FIL *fp, /* Pointer to the file object */
1120 DWORD ofs /* File pointer from top of file */ 1120 DWORD ofs /* File pointer from top of file */
1121 ) 1121 )
1122 { 1122 {
1123 CLUST clust; 1123 CLUST clust;
1124 DWORD csize; 1124 DWORD csize;
1125 BYTE csect; 1125 BYTE csect;
1126 FRESULT res; 1126 FRESULT res;
1127 FATFS *fs = fp->fs; 1127 FATFS *fs = fp->fs;
1128   1128  
1129   1129  
1130 res = validate(fs, fp->id); /* Check validity of the object */ 1130 res = validate(fs, fp->id); /* Check validity of the object */
1131 if (res) return res; 1131 if (res) return res;
1132   1132  
1133 if (fp->flag & FA__ERROR) return FR_RW_ERROR; 1133 if (fp->flag & FA__ERROR) return FR_RW_ERROR;
1134 #if !_FS_READONLY 1134 #if !_FS_READONLY
1135 if (ofs > fp->fsize && !(fp->flag & FA_WRITE)) 1135 if (ofs > fp->fsize && !(fp->flag & FA_WRITE))
1136 #else 1136 #else
1137 if (ofs > fp->fsize) 1137 if (ofs > fp->fsize)
1138 #endif 1138 #endif
1139 ofs = fp->fsize; 1139 ofs = fp->fsize;
1140 fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */ 1140 fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */
1141   1141  
1142 /* Move file R/W pointer if needed */ 1142 /* Move file R/W pointer if needed */
1143 if (ofs) { 1143 if (ofs) {
1144 clust = fp->org_clust; /* Get start cluster */ 1144 clust = fp->org_clust; /* Get start cluster */
1145 #if !_FS_READONLY 1145 #if !_FS_READONLY
1146 if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */ 1146 if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */
1147 clust = create_chain(0); 1147 clust = create_chain(0);
1148 if (clust == 1) goto fk_error; 1148 if (clust == 1) goto fk_error;
1149 fp->org_clust = clust; 1149 fp->org_clust = clust;
1150 } 1150 }
1151 #endif 1151 #endif
1152 if (clust) { /* If the file has a cluster chain, it can be followed */ 1152 if (clust) { /* If the file has a cluster chain, it can be followed */
1153 csize = (DWORD)fs->sects_clust * 512; /* Cluster size in unit of byte */ 1153 csize = (DWORD)fs->sects_clust * 512; /* Cluster size in unit of byte */
1154 for (;;) { /* Loop to skip leading clusters */ 1154 for (;;) { /* Loop to skip leading clusters */
1155 fp->curr_clust = clust; /* Update current cluster */ 1155 fp->curr_clust = clust; /* Update current cluster */
1156 if (ofs <= csize) break; 1156 if (ofs <= csize) break;
1157 #if !_FS_READONLY 1157 #if !_FS_READONLY
1158 if (fp->flag & FA_WRITE) /* Check if in write mode or not */ 1158 if (fp->flag & FA_WRITE) /* Check if in write mode or not */
1159 clust = create_chain(clust); /* Force streached if in write mode */ 1159 clust = create_chain(clust); /* Force streached if in write mode */
1160 else 1160 else
1161 #endif 1161 #endif
1162 clust = get_cluster(clust); /* Only follow cluster chain if not in write mode */ 1162 clust = get_cluster(clust); /* Only follow cluster chain if not in write mode */
1163 if (clust == 0) { /* Stop if could not follow the cluster chain */ 1163 if (clust == 0) { /* Stop if could not follow the cluster chain */
1164 ofs = csize; break; 1164 ofs = csize; break;
1165 } 1165 }
1166 if (clust == 1 || clust >= fs->max_clust) goto fk_error; 1166 if (clust == 1 || clust >= fs->max_clust) goto fk_error;
1167 fp->fptr += csize; /* Update R/W pointer */ 1167 fp->fptr += csize; /* Update R/W pointer */
1168 ofs -= csize; 1168 ofs -= csize;
1169 } 1169 }
1170 csect = (BYTE)((ofs - 1) / 512); /* Sector offset in the cluster */ 1170 csect = (BYTE)((ofs - 1) / 512); /* Sector offset in the cluster */
1171 fp->curr_sect = clust2sect(clust) + csect; /* Current sector */ 1171 fp->curr_sect = clust2sect(clust) + csect; /* Current sector */
1172 fp->sect_clust = fs->sects_clust - csect; /* Left sector counter in the cluster */ 1172 fp->sect_clust = fs->sects_clust - csect; /* Left sector counter in the cluster */
1173 fp->fptr += ofs; /* Update file R/W pointer */ 1173 fp->fptr += ofs; /* Update file R/W pointer */
1174 } 1174 }
1175 } 1175 }
1176 #if !_FS_READONLY 1176 #if !_FS_READONLY
1177 if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */ 1177 if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */
1178 fp->fsize = fp->fptr; 1178 fp->fsize = fp->fptr;
1179 fp->flag |= FA__WRITTEN; 1179 fp->flag |= FA__WRITTEN;
1180 } 1180 }
1181 #endif 1181 #endif
1182   1182  
1183 return FR_OK; 1183 return FR_OK;
1184   1184  
1185 fk_error: /* Abort this function due to an unrecoverable error */ 1185 fk_error: /* Abort this function due to an unrecoverable error */
1186 fp->flag |= FA__ERROR; 1186 fp->flag |= FA__ERROR;
1187 return FR_RW_ERROR; 1187 return FR_RW_ERROR;
1188 } 1188 }
1189   1189  
1190   1190  
1191   1191  
1192   1192  
1193 #if _FS_MINIMIZE <= 1 1193 #if _FS_MINIMIZE <= 1
1194 /*-----------------------------------------------------------------------*/ 1194 /*-----------------------------------------------------------------------*/
1195 /* Open a directroy */ 1195 /* Open a directroy */
1196 /*-----------------------------------------------------------------------*/ 1196 /*-----------------------------------------------------------------------*/
1197   1197  
1198 FRESULT f_opendir ( 1198 FRESULT f_opendir (
1199 DIR *dirobj, /* Pointer to directory object to create */ 1199 DIR *dirobj, /* Pointer to directory object to create */
1200 const char *path /* Pointer to the directory path */ 1200 const char *path /* Pointer to the directory path */
1201 ) 1201 )
1202 { 1202 {
1203 BYTE *dir; 1203 BYTE *dir;
1204 char fn[8+3+1]; 1204 char fn[8+3+1];
1205 FRESULT res; 1205 FRESULT res;
1206 FATFS *fs = FatFs; 1206 FATFS *fs = FatFs;
1207   1207  
1208   1208  
1209 res = auto_mount(&path, 0); 1209 res = auto_mount(&path, 0);
1210 if (res != FR_OK) return res; 1210 if (res != FR_OK) return res;
1211   1211  
1212 res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */ 1212 res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */
1213 if (res == FR_OK) { /* Trace completed */ 1213 if (res == FR_OK) { /* Trace completed */
1214 if (dir != NULL) { /* It is not the root dir */ 1214 if (dir != NULL) { /* It is not the root dir */
1215 if (dir[DIR_Attr] & AM_DIR) { /* The entry is a directory */ 1215 if (dir[DIR_Attr] & AM_DIR) { /* The entry is a directory */
1216 dirobj->clust = 1216 dirobj->clust =
1217 #if _FAT32 1217 #if _FAT32
1218 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | 1218 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
1219 #endif 1219 #endif
1220 LD_WORD(&dir[DIR_FstClusLO]); 1220 LD_WORD(&dir[DIR_FstClusLO]);
1221 dirobj->sect = clust2sect(dirobj->clust); 1221 dirobj->sect = clust2sect(dirobj->clust);
1222 dirobj->index = 2; 1222 dirobj->index = 2;
1223 } else { /* The entry is not a directory */ 1223 } else { /* The entry is not a directory */
1224 res = FR_NO_FILE; 1224 res = FR_NO_FILE;
1225 } 1225 }
1226 } 1226 }
1227 dirobj->id = fs->id; 1227 dirobj->id = fs->id;
1228 } 1228 }
1229 return res; 1229 return res;
1230 } 1230 }
1231   1231  
1232   1232  
1233   1233  
1234   1234  
1235 /*-----------------------------------------------------------------------*/ 1235 /*-----------------------------------------------------------------------*/
1236 /* Read Directory Entry in Sequense */ 1236 /* Read Directory Entry in Sequense */
1237 /*-----------------------------------------------------------------------*/ 1237 /*-----------------------------------------------------------------------*/
1238   1238  
1239 FRESULT f_readdir ( 1239 FRESULT f_readdir (
1240 DIR *dirobj, /* Pointer to the directory object */ 1240 DIR *dirobj, /* Pointer to the directory object */
1241 FILINFO *finfo /* Pointer to file information to return */ 1241 FILINFO *finfo /* Pointer to file information to return */
1242 ) 1242 )
1243 { 1243 {
1244 BYTE *dir, c; 1244 BYTE *dir, c;
1245 FRESULT res; 1245 FRESULT res;
1246 FATFS *fs = dirobj->fs; 1246 FATFS *fs = dirobj->fs;
1247   1247  
1248   1248  
1249 res = validate(fs, dirobj->id); /* Check validity of the object */ 1249 res = validate(fs, dirobj->id); /* Check validity of the object */
1250 if (res) return res; 1250 if (res) return res;
1251   1251  
1252 finfo->fname[0] = 0; 1252 finfo->fname[0] = 0;
1253 while (dirobj->sect) { 1253 while (dirobj->sect) {
1254 if (!move_window(dirobj->sect)) 1254 if (!move_window(dirobj->sect))
1255 return FR_RW_ERROR; 1255 return FR_RW_ERROR;
1256 dir = &fs->win[(dirobj->index & 15) * 32]; /* pointer to the directory entry */ 1256 dir = &fs->win[(dirobj->index & 15) * 32]; /* pointer to the directory entry */
1257 c = dir[DIR_Name]; 1257 c = dir[DIR_Name];
1258 if (c == 0) break; /* Has it reached to end of dir? */ 1258 if (c == 0) break; /* Has it reached to end of dir? */
1259 if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */ 1259 if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
1260 get_fileinfo(finfo, dir); 1260 get_fileinfo(finfo, dir);
1261 if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */ 1261 if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */
1262 if (finfo->fname[0]) break; /* Found valid entry */ 1262 if (finfo->fname[0]) break; /* Found valid entry */
1263 } 1263 }
1264   1264  
1265 return FR_OK; 1265 return FR_OK;
1266 } 1266 }
1267   1267  
1268   1268  
1269   1269  
1270   1270  
1271 #if _FS_MINIMIZE == 0 1271 #if _FS_MINIMIZE == 0
1272 /*-----------------------------------------------------------------------*/ 1272 /*-----------------------------------------------------------------------*/
1273 /* Get File Status */ 1273 /* Get File Status */
1274 /*-----------------------------------------------------------------------*/ 1274 /*-----------------------------------------------------------------------*/
1275   1275  
1276 FRESULT f_stat ( 1276 FRESULT f_stat (
1277 const char *path, /* Pointer to the file path */ 1277 const char *path, /* Pointer to the file path */
1278 FILINFO *finfo /* Pointer to file information to return */ 1278 FILINFO *finfo /* Pointer to file information to return */
1279 ) 1279 )
1280 { 1280 {
1281 BYTE *dir; 1281 BYTE *dir;
1282 char fn[8+3+1]; 1282 char fn[8+3+1];
1283 FRESULT res; 1283 FRESULT res;
1284 DIR dirobj; 1284 DIR dirobj;
1285   1285  
1286   1286  
1287 res = auto_mount(&path, 0); 1287 res = auto_mount(&path, 0);
1288 if (res != FR_OK) return res; 1288 if (res != FR_OK) return res;
1289   1289  
1290 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ 1290 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
1291 if (res == FR_OK) { /* Trace completed */ 1291 if (res == FR_OK) { /* Trace completed */
1292 if (dir) /* Found an object */ 1292 if (dir) /* Found an object */
1293 get_fileinfo(finfo, dir); 1293 get_fileinfo(finfo, dir);
1294 else /* It is root dir */ 1294 else /* It is root dir */
1295 res = FR_INVALID_NAME; 1295 res = FR_INVALID_NAME;
1296 } 1296 }
1297   1297  
1298 return res; 1298 return res;
1299 } 1299 }
1300   1300  
1301   1301  
1302   1302  
1303   1303  
1304 #if !_FS_READONLY 1304 #if !_FS_READONLY
1305 /*-----------------------------------------------------------------------*/ 1305 /*-----------------------------------------------------------------------*/
1306 /* Get Number of Free Clusters */ 1306 /* Get Number of Free Clusters */
1307 /*-----------------------------------------------------------------------*/ 1307 /*-----------------------------------------------------------------------*/
1308   1308  
1309 FRESULT f_getfree ( 1309 FRESULT f_getfree (
1310 const char *drv, /* Logical drive number */ 1310 const char *drv, /* Logical drive number */
1311 DWORD *nclust, /* Pointer to the double word to return number of free clusters */ 1311 DWORD *nclust, /* Pointer to the double word to return number of free clusters */
1312 FATFS **fatfs /* Pointer to pointer to the file system object to return */ 1312 FATFS **fatfs /* Pointer to pointer to the file system object to return */
1313 ) 1313 )
1314 { 1314 {
1315 DWORD n, sect; 1315 DWORD n, sect;
1316 CLUST clust; 1316 CLUST clust;
1317 BYTE fat, f, *p; 1317 BYTE fat, f, *p;
1318 FRESULT res; 1318 FRESULT res;
1319 FATFS *fs; 1319 FATFS *fs;
1320   1320  
1321   1321  
1322 /* Get drive number */ 1322 /* Get drive number */
1323 res = auto_mount(&drv, 0); 1323 res = auto_mount(&drv, 0);
1324 if (res != FR_OK) return res; 1324 if (res != FR_OK) return res;
1325 *fatfs = fs = FatFs; 1325 *fatfs = fs = FatFs;
1326   1326  
1327 /* If number of free cluster is valid, return it without cluster scan. */ 1327 /* If number of free cluster is valid, return it without cluster scan. */
1328 if (fs->free_clust <= fs->max_clust - 2) { 1328 if (fs->free_clust <= fs->max_clust - 2) {
1329 *nclust = fs->free_clust; 1329 *nclust = fs->free_clust;
1330 return FR_OK; 1330 return FR_OK;
1331 } 1331 }
1332   1332  
1333 /* Count number of free clusters */ 1333 /* Count number of free clusters */
1334 fat = fs->fs_type; 1334 fat = fs->fs_type;
1335 n = 0; 1335 n = 0;
1336 if (fat == FS_FAT12) { 1336 if (fat == FS_FAT12) {
1337 clust = 2; 1337 clust = 2;
1338 do { 1338 do {
1339 if ((WORD)get_cluster(clust) == 0) n++; 1339 if ((WORD)get_cluster(clust) == 0) n++;
1340 } while (++clust < fs->max_clust); 1340 } while (++clust < fs->max_clust);
1341 } else { 1341 } else {
1342 clust = fs->max_clust; 1342 clust = fs->max_clust;
1343 sect = fs->fatbase; 1343 sect = fs->fatbase;
1344 f = 0; p = 0; 1344 f = 0; p = 0;
1345 do { 1345 do {
1346 if (!f) { 1346 if (!f) {
1347 if (!move_window(sect++)) return FR_RW_ERROR; 1347 if (!move_window(sect++)) return FR_RW_ERROR;
1348 p = fs->win; 1348 p = fs->win;
1349 } 1349 }
1350 if (!_FAT32 || fat == FS_FAT16) { 1350 if (!_FAT32 || fat == FS_FAT16) {
1351 if (LD_WORD(p) == 0) n++; 1351 if (LD_WORD(p) == 0) n++;
1352 p += 2; f += 1; 1352 p += 2; f += 1;
1353 } else { 1353 } else {
1354 if (LD_DWORD(p) == 0) n++; 1354 if (LD_DWORD(p) == 0) n++;
1355 p += 4; f += 2; 1355 p += 4; f += 2;
1356 } 1356 }
1357 } while (--clust); 1357 } while (--clust);
1358 } 1358 }
1359 fs->free_clust = n; 1359 fs->free_clust = n;
1360 #if _USE_FSINFO 1360 #if _USE_FSINFO
1361 if (fat == FS_FAT32) fs->fsi_flag = 1; 1361 if (fat == FS_FAT32) fs->fsi_flag = 1;
1362 #endif 1362 #endif
1363   1363  
1364 *nclust = n; 1364 *nclust = n;
1365 return FR_OK; 1365 return FR_OK;
1366 } 1366 }
1367   1367  
1368   1368  
1369   1369  
1370   1370  
1371 /*-----------------------------------------------------------------------*/ 1371 /*-----------------------------------------------------------------------*/
1372 /* Delete a File or a Directory */ 1372 /* Delete a File or a Directory */
1373 /*-----------------------------------------------------------------------*/ 1373 /*-----------------------------------------------------------------------*/
1374   1374  
1375 FRESULT f_unlink ( 1375 FRESULT f_unlink (
1376 const char *path /* Pointer to the file or directory path */ 1376 const char *path /* Pointer to the file or directory path */
1377 ) 1377 )
1378 { 1378 {
1379 BYTE *dir, *sdir; 1379 BYTE *dir, *sdir;
1380 DWORD dsect; 1380 DWORD dsect;
1381 char fn[8+3+1]; 1381 char fn[8+3+1];
1382 CLUST dclust; 1382 CLUST dclust;
1383 FRESULT res; 1383 FRESULT res;
1384 DIR dirobj; 1384 DIR dirobj;
1385 FATFS *fs = FatFs; 1385 FATFS *fs = FatFs;
1386   1386  
1387   1387  
1388 res = auto_mount(&path, 1); 1388 res = auto_mount(&path, 1);
1389 if (res != FR_OK) return res; 1389 if (res != FR_OK) return res;
1390   1390  
1391 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ 1391 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
1392 if (res != FR_OK) return res; /* Trace failed */ 1392 if (res != FR_OK) return res; /* Trace failed */
1393 if (dir == NULL) return FR_INVALID_NAME; /* It is the root directory */ 1393 if (dir == NULL) return FR_INVALID_NAME; /* It is the root directory */
1394 if (dir[DIR_Attr] & AM_RDO) return FR_DENIED; /* It is a R/O object */ 1394 if (dir[DIR_Attr] & AM_RDO) return FR_DENIED; /* It is a R/O object */
1395 dsect = fs->winsect; 1395 dsect = fs->winsect;
1396 dclust = 1396 dclust =
1397 #if _FAT32 1397 #if _FAT32
1398 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | 1398 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
1399 #endif 1399 #endif
1400 LD_WORD(&dir[DIR_FstClusLO]); 1400 LD_WORD(&dir[DIR_FstClusLO]);
1401 if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */ 1401 if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */
1402 dirobj.clust = dclust; /* Check if the sub-dir is empty or not */ 1402 dirobj.clust = dclust; /* Check if the sub-dir is empty or not */
1403 dirobj.sect = clust2sect(dclust); 1403 dirobj.sect = clust2sect(dclust);
1404 dirobj.index = 2; 1404 dirobj.index = 2;
1405 do { 1405 do {
1406 if (!move_window(dirobj.sect)) return FR_RW_ERROR; 1406 if (!move_window(dirobj.sect)) return FR_RW_ERROR;
1407 sdir = &fs->win[(dirobj.index & 15) * 32]; 1407 sdir = &fs->win[(dirobj.index & 15) * 32];
1408 if (sdir[DIR_Name] == 0) break; 1408 if (sdir[DIR_Name] == 0) break;
1409 if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL)) 1409 if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL))
1410 return FR_DENIED; /* The directory is not empty */ 1410 return FR_DENIED; /* The directory is not empty */
1411 } while (next_dir_entry(&dirobj)); 1411 } while (next_dir_entry(&dirobj));
1412 } 1412 }
1413   1413  
1414 if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */ 1414 if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */
1415 dir[DIR_Name] = 0xE5; 1415 dir[DIR_Name] = 0xE5;
1416 fs->winflag = 1; 1416 fs->winflag = 1;
1417 if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ 1417 if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */
1418   1418  
1419 return sync(); 1419 return sync();
1420 } 1420 }
1421   1421  
1422   1422  
1423   1423  
1424   1424  
1425 /*-----------------------------------------------------------------------*/ 1425 /*-----------------------------------------------------------------------*/
1426 /* Create a Directory */ 1426 /* Create a Directory */
1427 /*-----------------------------------------------------------------------*/ 1427 /*-----------------------------------------------------------------------*/
1428   1428  
1429 FRESULT f_mkdir ( 1429 FRESULT f_mkdir (
1430 const char *path /* Pointer to the directory path */ 1430 const char *path /* Pointer to the directory path */
1431 ) 1431 )
1432 { 1432 {
1433 BYTE *dir, *fw, n; 1433 BYTE *dir, *fw, n;
1434 char fn[8+3+1]; 1434 char fn[8+3+1];
1435 DWORD sect, dsect, tim; 1435 DWORD sect, dsect, tim;
1436 CLUST dclust, pclust; 1436 CLUST dclust, pclust;
1437 FRESULT res; 1437 FRESULT res;
1438 DIR dirobj; 1438 DIR dirobj;
1439 FATFS *fs = FatFs; 1439 FATFS *fs = FatFs;
1440   1440  
1441   1441  
1442 res = auto_mount(&path, 1); 1442 res = auto_mount(&path, 1);
1443 if (res != FR_OK) return res; 1443 if (res != FR_OK) return res;
1444   1444  
1445 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ 1445 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
1446 if (res == FR_OK) return FR_EXIST; /* Any file or directory is already existing */ 1446 if (res == FR_OK) return FR_EXIST; /* Any file or directory is already existing */
1447 if (res != FR_NO_FILE) return res; 1447 if (res != FR_NO_FILE) return res;
1448   1448  
1449 res = reserve_direntry(&dirobj, &dir); /* Reserve a directory entry */ 1449 res = reserve_direntry(&dirobj, &dir); /* Reserve a directory entry */
1450 if (res != FR_OK) return res; 1450 if (res != FR_OK) return res;
1451 sect = fs->winsect; 1451 sect = fs->winsect;
1452 dclust = create_chain(0); /* Allocate a cluster for new directory table */ 1452 dclust = create_chain(0); /* Allocate a cluster for new directory table */
1453 if (dclust == 1) return FR_RW_ERROR; 1453 if (dclust == 1) return FR_RW_ERROR;
1454 dsect = clust2sect(dclust); 1454 dsect = clust2sect(dclust);
1455 if (!dsect) return FR_DENIED; 1455 if (!dsect) return FR_DENIED;
1456 if (!move_window(dsect)) return FR_RW_ERROR; 1456 if (!move_window(dsect)) return FR_RW_ERROR;
1457   1457  
1458 fw = fs->win; 1458 fw = fs->win;
1459 memset(fw, 0, 512); /* Clear the directory table */ 1459 memset(fw, 0, 512); /* Clear the directory table */
1460 for (n = 1; n < fs->sects_clust; n++) { 1460 for (n = 1; n < fs->sects_clust; n++) {
1461 if (disk_write(0, fw, ++dsect, 1) != RES_OK) 1461 if (disk_write(0, fw, ++dsect, 1) != RES_OK)
1462 return FR_RW_ERROR; 1462 return FR_RW_ERROR;
1463 } 1463 }
1464   1464  
1465 memset(&fw[DIR_Name], ' ', 8+3); /* Create "." entry */ 1465 memset(&fw[DIR_Name], ' ', 8+3); /* Create "." entry */
1466 fw[DIR_Name] = '.'; 1466 fw[DIR_Name] = '.';
1467 fw[DIR_Attr] = AM_DIR; 1467 fw[DIR_Attr] = AM_DIR;
1468 tim = get_fattime(); 1468 tim = get_fattime();
1469 ST_DWORD(&fw[DIR_WrtTime], tim); 1469 ST_DWORD(&fw[DIR_WrtTime], tim);
1470 memcpy(&fw[32], &fw[0], 32); fw[33] = '.'; /* Create ".." entry */ 1470 memcpy(&fw[32], &fw[0], 32); fw[33] = '.'; /* Create ".." entry */
1471 pclust = dirobj.sclust; 1471 pclust = dirobj.sclust;
1472 #if _FAT32 1472 #if _FAT32
1473 ST_WORD(&fw[ DIR_FstClusHI], dclust >> 16); 1473 ST_WORD(&fw[ DIR_FstClusHI], dclust >> 16);
1474 if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0; 1474 if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0;
1475 ST_WORD(&fw[32+DIR_FstClusHI], pclust >> 16); 1475 ST_WORD(&fw[32+DIR_FstClusHI], pclust >> 16);
1476 #endif 1476 #endif
1477 ST_WORD(&fw[ DIR_FstClusLO], dclust); 1477 ST_WORD(&fw[ DIR_FstClusLO], dclust);
1478 ST_WORD(&fw[32+DIR_FstClusLO], pclust); 1478 ST_WORD(&fw[32+DIR_FstClusLO], pclust);
1479 fs->winflag = 1; 1479 fs->winflag = 1;
1480   1480  
1481 if (!move_window(sect)) return FR_RW_ERROR; 1481 if (!move_window(sect)) return FR_RW_ERROR;
1482 memset(&dir[0], 0, 32); /* Clean-up the new entry */ 1482 memset(&dir[0], 0, 32); /* Clean-up the new entry */
1483 memcpy(&dir[DIR_Name], fn, 8+3); /* Name */ 1483 memcpy(&dir[DIR_Name], fn, 8+3); /* Name */
1484 dir[DIR_NTres] = fn[11]; 1484 dir[DIR_NTres] = fn[11];
1485 dir[DIR_Attr] = AM_DIR; /* Attribute */ 1485 dir[DIR_Attr] = AM_DIR; /* Attribute */
1486 ST_DWORD(&dir[DIR_WrtTime], tim); /* Crated time */ 1486 ST_DWORD(&dir[DIR_WrtTime], tim); /* Crated time */
1487 ST_WORD(&dir[DIR_FstClusLO], dclust); /* Table start cluster */ 1487 ST_WORD(&dir[DIR_FstClusLO], dclust); /* Table start cluster */
1488 #if _FAT32 1488 #if _FAT32
1489 ST_WORD(&dir[DIR_FstClusHI], dclust >> 16); 1489 ST_WORD(&dir[DIR_FstClusHI], dclust >> 16);
1490 #endif 1490 #endif
1491   1491  
1492 return sync(); 1492 return sync();
1493 } 1493 }
1494   1494  
1495   1495  
1496   1496  
1497   1497  
1498 /*-----------------------------------------------------------------------*/ 1498 /*-----------------------------------------------------------------------*/
1499 /* Change File Attribute */ 1499 /* Change File Attribute */
1500 /*-----------------------------------------------------------------------*/ 1500 /*-----------------------------------------------------------------------*/
1501   1501  
1502 FRESULT f_chmod ( 1502 FRESULT f_chmod (
1503 const char *path, /* Pointer to the file path */ 1503 const char *path, /* Pointer to the file path */
1504 BYTE value, /* Attribute bits */ 1504 BYTE value, /* Attribute bits */
1505 BYTE mask /* Attribute mask to change */ 1505 BYTE mask /* Attribute mask to change */
1506 ) 1506 )
1507 { 1507 {
1508 FRESULT res; 1508 FRESULT res;
1509 BYTE *dir; 1509 BYTE *dir;
1510 DIR dirobj; 1510 DIR dirobj;
1511 char fn[8+3+1]; 1511 char fn[8+3+1];
1512   1512  
1513   1513  
1514 res = auto_mount(&path, 1); 1514 res = auto_mount(&path, 1);
1515 if (res == FR_OK) { 1515 if (res == FR_OK) {
1516 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ 1516 res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
1517 if (res == FR_OK) { /* Trace completed */ 1517 if (res == FR_OK) { /* Trace completed */
1518 if (dir == NULL) { 1518 if (dir == NULL) {
1519 res = FR_INVALID_NAME; 1519 res = FR_INVALID_NAME;
1520 } else { 1520 } else {
1521 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ 1521 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
1522 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 1522 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
1523 res = sync(); 1523 res = sync();
1524 } 1524 }
1525 } 1525 }
1526 } 1526 }
1527 return res; 1527 return res;
1528 } 1528 }
1529   1529  
1530   1530  
1531   1531  
1532   1532  
1533 /*-----------------------------------------------------------------------*/ 1533 /*-----------------------------------------------------------------------*/
1534 /* Rename File/Directory */ 1534 /* Rename File/Directory */
1535 /*-----------------------------------------------------------------------*/ 1535 /*-----------------------------------------------------------------------*/
1536   1536  
1537 FRESULT f_rename ( 1537 FRESULT f_rename (
1538 const char *path_old, /* Pointer to the old name */ 1538 const char *path_old, /* Pointer to the old name */
1539 const char *path_new /* Pointer to the new name */ 1539 const char *path_new /* Pointer to the new name */
1540 ) 1540 )
1541 { 1541 {
1542 FRESULT res; 1542 FRESULT res;
1543 DWORD sect_old; 1543 DWORD sect_old;
1544 BYTE *dir_old, *dir_new, direntry[32-11]; 1544 BYTE *dir_old, *dir_new, direntry[32-11];
1545 DIR dirobj; 1545 DIR dirobj;
1546 char fn[8+3+1]; 1546 char fn[8+3+1];
1547 FATFS *fs = FatFs; 1547 FATFS *fs = FatFs;
1548   1548  
1549   1549  
1550 res = auto_mount(&path_old, 1); 1550 res = auto_mount(&path_old, 1);
1551 if (res != FR_OK) return res; 1551 if (res != FR_OK) return res;
1552   1552  
1553 res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ 1553 res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */
1554 if (res != FR_OK) return res; /* The old object is not found */ 1554 if (res != FR_OK) return res; /* The old object is not found */
1555 if (!dir_old) return FR_NO_FILE; 1555 if (!dir_old) return FR_NO_FILE;
1556 sect_old = fs->winsect; /* Save the object information */ 1556 sect_old = fs->winsect; /* Save the object information */
1557 memcpy(direntry, &dir_old[11], 32-11); 1557 memcpy(direntry, &dir_old[11], 32-11);
1558   1558  
1559 res = trace_path(&dirobj, fn, path_new, &dir_new); /* Check new object */ 1559 res = trace_path(&dirobj, fn, path_new, &dir_new); /* Check new object */
1560 if (res == FR_OK) return FR_EXIST; /* The new object name is already existing */ 1560 if (res == FR_OK) return FR_EXIST; /* The new object name is already existing */
1561 if (res != FR_NO_FILE) return res; /* Is there no old name? */ 1561 if (res != FR_NO_FILE) return res; /* Is there no old name? */
1562 res = reserve_direntry(&dirobj, &dir_new); /* Reserve a directory entry */ 1562 res = reserve_direntry(&dirobj, &dir_new); /* Reserve a directory entry */
1563 if (res != FR_OK) return res; 1563 if (res != FR_OK) return res;
1564   1564  
1565 memcpy(&dir_new[DIR_Attr], direntry, 32-11); /* Create new entry */ 1565 memcpy(&dir_new[DIR_Attr], direntry, 32-11); /* Create new entry */
1566 memcpy(&dir_new[DIR_Name], fn, 8+3); 1566 memcpy(&dir_new[DIR_Name], fn, 8+3);
1567 dir_new[DIR_NTres] = fn[11]; 1567 dir_new[DIR_NTres] = fn[11];
1568 fs->winflag = 1; 1568 fs->winflag = 1;
1569   1569  
1570 if (!move_window(sect_old)) return FR_RW_ERROR; /* Remove old entry */ 1570 if (!move_window(sect_old)) return FR_RW_ERROR; /* Remove old entry */
1571 dir_old[DIR_Name] = 0xE5; 1571 dir_old[DIR_Name] = 0xE5;
1572   1572  
1573 return sync(); 1573 return sync();
1574 } 1574 }
1575   1575  
1576 #endif /* !_FS_READONLY */ 1576 #endif /* !_FS_READONLY */
1577 #endif /* _FS_MINIMIZE == 0 */ 1577 #endif /* _FS_MINIMIZE == 0 */
1578 #endif /* _FS_MINIMIZE <= 1 */ 1578 #endif /* _FS_MINIMIZE <= 1 */
1579 #endif /* _FS_MINIMIZE <= 2 */ 1579 #endif /* _FS_MINIMIZE <= 2 */
1580   1580