Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of FATFileSystem by
ff.cpp
00001 /*----------------------------------------------------------------------------/ 00002 / FatFs - FAT file system module R0.11a (C)ChaN, 2015 / 00003 /-----------------------------------------------------------------------------/ 00004 / FatFs module is a free software that opened under license policy of 00005 / following conditions. 00006 / 00007 / Copyright (C) 2015, ChaN, all right reserved. 00008 / 00009 / 1. Redistributions of source code must retain the above copyright notice, 00010 / this condition and the following disclaimer. 00011 / 00012 / This software is provided by the copyright holder and contributors "AS IS" 00013 / and any warranties related to this software are DISCLAIMED. 00014 / The copyright owner or contributors be NOT LIABLE for any damages caused 00015 / by use of this software. 00016 /----------------------------------------------------------------------------*/ 00017 00018 00019 #include "ff.h" /* Declarations of FatFs API */ 00020 #include "diskio.h" /* Declarations of disk I/O functions */ 00021 00022 00023 /*-------------------------------------------------------------------------- 00024 00025 Module Private Definitions 00026 00027 ---------------------------------------------------------------------------*/ 00028 00029 #if _FATFS != 64180 /* Revision ID */ 00030 #error Wrong include file (ff.h). 00031 #endif 00032 00033 00034 /* Reentrancy related */ 00035 #if _FS_REENTRANT 00036 #if _USE_LFN == 1 00037 #error Static LFN work area cannot be used at thread-safe configuration 00038 #endif 00039 #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } 00040 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } 00041 #else 00042 #define ENTER_FF(fs) 00043 #define LEAVE_FF(fs, res) return res 00044 #endif 00045 00046 #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } 00047 00048 00049 /* Definitions of sector size */ 00050 #if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) 00051 #error Wrong sector size configuration 00052 #endif 00053 #if _MAX_SS == _MIN_SS 00054 #define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ 00055 #else 00056 #define SS(fs) ((fs)->ssize) /* Variable sector size */ 00057 #endif 00058 00059 00060 /* Timestamp feature */ 00061 #if _FS_NORTC == 1 00062 #if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 00063 #error Invalid _FS_NORTC settings 00064 #endif 00065 #define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) 00066 #else 00067 #define GET_FATTIME() get_fattime() 00068 #endif 00069 00070 00071 /* File access control feature */ 00072 #if _FS_LOCK 00073 #if _FS_READONLY 00074 #error _FS_LOCK must be 0 at read-only configuration 00075 #endif 00076 typedef struct { 00077 FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ 00078 DWORD clu; /* Object ID 2, directory (0:root) */ 00079 WORD idx; /* Object ID 3, directory index */ 00080 WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ 00081 } FILESEM; 00082 #endif 00083 00084 00085 00086 /* DBCS code ranges and SBCS upper conversion tables */ 00087 00088 #if _CODE_PAGE == 932 /* Japanese Shift-JIS */ 00089 #define _DF1S 0x81 /* DBC 1st byte range 1 start */ 00090 #define _DF1E 0x9F /* DBC 1st byte range 1 end */ 00091 #define _DF2S 0xE0 /* DBC 1st byte range 2 start */ 00092 #define _DF2E 0xFC /* DBC 1st byte range 2 end */ 00093 #define _DS1S 0x40 /* DBC 2nd byte range 1 start */ 00094 #define _DS1E 0x7E /* DBC 2nd byte range 1 end */ 00095 #define _DS2S 0x80 /* DBC 2nd byte range 2 start */ 00096 #define _DS2E 0xFC /* DBC 2nd byte range 2 end */ 00097 00098 #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ 00099 #define _DF1S 0x81 00100 #define _DF1E 0xFE 00101 #define _DS1S 0x40 00102 #define _DS1E 0x7E 00103 #define _DS2S 0x80 00104 #define _DS2E 0xFE 00105 00106 #elif _CODE_PAGE == 949 /* Korean */ 00107 #define _DF1S 0x81 00108 #define _DF1E 0xFE 00109 #define _DS1S 0x41 00110 #define _DS1E 0x5A 00111 #define _DS2S 0x61 00112 #define _DS2E 0x7A 00113 #define _DS3S 0x81 00114 #define _DS3E 0xFE 00115 00116 #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ 00117 #define _DF1S 0x81 00118 #define _DF1E 0xFE 00119 #define _DS1S 0x40 00120 #define _DS1E 0x7E 00121 #define _DS2S 0xA1 00122 #define _DS2E 0xFE 00123 00124 #elif _CODE_PAGE == 437 /* U.S. */ 00125 #define _DF1S 0 00126 #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 00127 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00128 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00129 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00130 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00131 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00132 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00133 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00134 00135 #elif _CODE_PAGE == 720 /* Arabic */ 00136 #define _DF1S 0 00137 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00138 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00139 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00140 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00141 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00142 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00143 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00144 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00145 00146 #elif _CODE_PAGE == 737 /* Greek */ 00147 #define _DF1S 0 00148 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00149 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 00150 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ 00151 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00152 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00153 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00154 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00155 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00156 00157 #elif _CODE_PAGE == 771 /* KBL */ 00158 #define _DF1S 0 00159 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00160 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00161 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00162 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00163 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00164 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ 00165 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00166 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} 00167 00168 #elif _CODE_PAGE == 775 /* Baltic */ 00169 #define _DF1S 0 00170 #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ 00171 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 00172 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00173 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00174 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00175 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00176 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ 00177 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00178 00179 #elif _CODE_PAGE == 850 /* Latin 1 */ 00180 #define _DF1S 0 00181 #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ 00182 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ 00183 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00184 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00185 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00186 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ 00187 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ 00188 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00189 00190 #elif _CODE_PAGE == 852 /* Latin 2 */ 00191 #define _DF1S 0 00192 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ 00193 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ 00194 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ 00195 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 00196 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00197 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00198 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ 00199 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} 00200 00201 #elif _CODE_PAGE == 855 /* Cyrillic */ 00202 #define _DF1S 0 00203 #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ 00204 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 00205 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ 00206 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 00207 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00208 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 00209 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ 00210 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} 00211 00212 #elif _CODE_PAGE == 857 /* Turkish */ 00213 #define _DF1S 0 00214 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ 00215 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 00216 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00217 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00218 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00219 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00220 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ 00221 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00222 00223 #elif _CODE_PAGE == 860 /* Portuguese */ 00224 #define _DF1S 0 00225 #define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ 00226 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00227 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00228 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00229 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00230 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00231 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00232 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00233 00234 #elif _CODE_PAGE == 861 /* Icelandic */ 00235 #define _DF1S 0 00236 #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ 00237 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 00238 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00239 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00240 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00241 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00242 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00243 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00244 00245 #elif _CODE_PAGE == 862 /* Hebrew */ 00246 #define _DF1S 0 00247 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00248 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00249 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00250 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00251 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00252 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00253 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00254 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00255 00256 #elif _CODE_PAGE == 863 /* Canadian-French */ 00257 #define _DF1S 0 00258 #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ 00259 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ 00260 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00261 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00262 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00263 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00264 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00265 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00266 00267 #elif _CODE_PAGE == 864 /* Arabic */ 00268 #define _DF1S 0 00269 #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 00270 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00271 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00272 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00273 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00274 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00275 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00276 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00277 00278 #elif _CODE_PAGE == 865 /* Nordic */ 00279 #define _DF1S 0 00280 #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 00281 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00282 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00283 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00284 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00285 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00286 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00287 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00288 00289 #elif _CODE_PAGE == 866 /* Russian */ 00290 #define _DF1S 0 00291 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00292 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00293 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00294 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00295 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00296 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00297 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00298 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00299 00300 #elif _CODE_PAGE == 869 /* Greek 2 */ 00301 #define _DF1S 0 00302 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00303 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ 00304 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00305 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00306 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00307 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ 00308 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ 00309 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} 00310 00311 #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ 00312 #if _USE_LFN 00313 #error Cannot use LFN feature without valid code page. 00314 #endif 00315 #define _DF1S 0 00316 00317 #else 00318 #error Unknown code page 00319 00320 #endif 00321 00322 00323 /* Character code support macros */ 00324 #define IsUpper(c) (((c)>='A')&&((c)<='Z')) 00325 #define IsLower(c) (((c)>='a')&&((c)<='z')) 00326 #define IsDigit(c) (((c)>='0')&&((c)<='9')) 00327 00328 #if _DF1S /* Code page is DBCS */ 00329 00330 #ifdef _DF2S /* Two 1st byte areas */ 00331 #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) 00332 #else /* One 1st byte area */ 00333 #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) 00334 #endif 00335 00336 #ifdef _DS3S /* Three 2nd byte areas */ 00337 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) 00338 #else /* Two 2nd byte areas */ 00339 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) 00340 #endif 00341 00342 #else /* Code page is SBCS */ 00343 00344 #define IsDBCS1(c) 0 00345 #define IsDBCS2(c) 0 00346 00347 #endif /* _DF1S */ 00348 00349 00350 /* Name status flags */ 00351 #define NSFLAG 11 /* Index of name status byte in fn[] */ 00352 #define NS_LOSS 0x01 /* Out of 8.3 format */ 00353 #define NS_LFN 0x02 /* Force to create LFN entry */ 00354 #define NS_LAST 0x04 /* Last segment */ 00355 #define NS_BODY 0x08 /* Lower case flag (body) */ 00356 #define NS_EXT 0x10 /* Lower case flag (ext) */ 00357 #define NS_DOT 0x20 /* Dot entry */ 00358 00359 00360 /* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ 00361 #define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */ 00362 #define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */ 00363 00364 00365 /* FatFs refers the members in the FAT structures as byte array instead of 00366 / structure members because the structure is not binary compatible between 00367 / different platforms */ 00368 00369 #define BS_jmpBoot 0 /* x86 jump instruction (3) */ 00370 #define BS_OEMName 3 /* OEM name (8) */ 00371 #define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ 00372 #define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ 00373 #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ 00374 #define BPB_NumFATs 16 /* Number of FAT copies (1) */ 00375 #define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */ 00376 #define BPB_TotSec16 19 /* Volume size [sector] (2) */ 00377 #define BPB_Media 21 /* Media descriptor (1) */ 00378 #define BPB_FATSz16 22 /* FAT size [sector] (2) */ 00379 #define BPB_SecPerTrk 24 /* Track size [sector] (2) */ 00380 #define BPB_NumHeads 26 /* Number of heads (2) */ 00381 #define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ 00382 #define BPB_TotSec32 32 /* Volume size [sector] (4) */ 00383 #define BS_DrvNum 36 /* Physical drive number (1) */ 00384 #define BS_NTres 37 /* Error flag (1) */ 00385 #define BS_BootSig 38 /* Extended boot signature (1) */ 00386 #define BS_VolID 39 /* Volume serial number (4) */ 00387 #define BS_VolLab 43 /* Volume label (8) */ 00388 #define BS_FilSysType 54 /* File system type (1) */ 00389 #define BPB_FATSz32 36 /* FAT size [sector] (4) */ 00390 #define BPB_ExtFlags 40 /* Extended flags (2) */ 00391 #define BPB_FSVer 42 /* File system version (2) */ 00392 #define BPB_RootClus 44 /* Root directory first cluster (4) */ 00393 #define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ 00394 #define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ 00395 #define BS_DrvNum32 64 /* Physical drive number (1) */ 00396 #define BS_NTres32 65 /* Error flag (1) */ 00397 #define BS_BootSig32 66 /* Extended boot signature (1) */ 00398 #define BS_VolID32 67 /* Volume serial number (4) */ 00399 #define BS_VolLab32 71 /* Volume label (8) */ 00400 #define BS_FilSysType32 82 /* File system type (1) */ 00401 #define FSI_LeadSig 0 /* FSI: Leading signature (4) */ 00402 #define FSI_StrucSig 484 /* FSI: Structure signature (4) */ 00403 #define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ 00404 #define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ 00405 #define MBR_Table 446 /* MBR: Partition table offset (2) */ 00406 #define SZ_PTE 16 /* MBR: Size of a partition table entry */ 00407 #define BS_55AA 510 /* Signature word (2) */ 00408 00409 #define DIR_Name 0 /* Short file name (11) */ 00410 #define DIR_Attr 11 /* Attribute (1) */ 00411 #define DIR_NTres 12 /* Lower case flag (1) */ 00412 #define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ 00413 #define DIR_CrtTime 14 /* Created time (2) */ 00414 #define DIR_CrtDate 16 /* Created date (2) */ 00415 #define DIR_LstAccDate 18 /* Last accessed date (2) */ 00416 #define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ 00417 #define DIR_WrtTime 22 /* Modified time (2) */ 00418 #define DIR_WrtDate 24 /* Modified date (2) */ 00419 #define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ 00420 #define DIR_FileSize 28 /* File size (4) */ 00421 #define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ 00422 #define LDIR_Attr 11 /* LFN attribute (1) */ 00423 #define LDIR_Type 12 /* LFN type (1) */ 00424 #define LDIR_Chksum 13 /* Checksum of corresponding SFN entry */ 00425 #define LDIR_FstClusLO 26 /* Must be zero (0) */ 00426 #define SZ_DIRE 32 /* Size of a directory entry */ 00427 #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ 00428 #define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ 00429 #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ 00430 00431 00432 00433 00434 /*-------------------------------------------------------------------------- 00435 00436 Module Private Work Area 00437 00438 ---------------------------------------------------------------------------*/ 00439 00440 /* Remark: Uninitialized variables with static duration are guaranteed 00441 / zero/null at start-up. If not, either the linker or start-up routine 00442 / being used is not compliance with ANSI-C standard. 00443 */ 00444 00445 #if _VOLUMES < 1 || _VOLUMES > 9 00446 #error Wrong _VOLUMES setting 00447 #endif 00448 static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ 00449 static WORD Fsid; /* File system mount ID */ 00450 00451 #if _FS_RPATH && _VOLUMES >= 2 00452 static BYTE CurrVol; /* Current drive */ 00453 #endif 00454 00455 #if _FS_LOCK 00456 static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ 00457 #endif 00458 00459 #if _USE_LFN == 0 /* Non LFN feature */ 00460 #define DEFINE_NAMEBUF BYTE sfn[12] 00461 #define INIT_BUF(dobj) (dobj).fn = sfn 00462 #define FREE_BUF() 00463 #else 00464 #if _MAX_LFN < 12 || _MAX_LFN > 255 00465 #error Wrong _MAX_LFN setting 00466 #endif 00467 #if _USE_LFN == 1 /* LFN feature with static working buffer */ 00468 static WCHAR LfnBuf[_MAX_LFN + 1]; 00469 #define DEFINE_NAMEBUF BYTE sfn[12] 00470 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } 00471 #define FREE_BUF() 00472 #elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ 00473 #define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1] 00474 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } 00475 #define FREE_BUF() 00476 #elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ 00477 #define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn 00478 #define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; } 00479 #define FREE_BUF() ff_memfree(lfn) 00480 #else 00481 #error Wrong _USE_LFN setting 00482 #endif 00483 #endif 00484 00485 #ifdef _EXCVT 00486 static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ 00487 #endif 00488 00489 00490 00491 00492 00493 00494 /*-------------------------------------------------------------------------- 00495 00496 Module Private Functions 00497 00498 ---------------------------------------------------------------------------*/ 00499 00500 00501 /*-----------------------------------------------------------------------*/ 00502 /* String functions */ 00503 /*-----------------------------------------------------------------------*/ 00504 00505 /* Copy memory to memory */ 00506 static 00507 void mem_cpy (void* dst, const void* src, UINT cnt) { 00508 BYTE *d = (BYTE*)dst; 00509 const BYTE *s = (const BYTE*)src; 00510 00511 #if _WORD_ACCESS == 1 00512 while (cnt >= sizeof (int)) { 00513 *(int*)d = *(int*)s; 00514 d += sizeof (int); s += sizeof (int); 00515 cnt -= sizeof (int); 00516 } 00517 #endif 00518 while (cnt--) 00519 *d++ = *s++; 00520 } 00521 00522 /* Fill memory */ 00523 static 00524 void mem_set (void* dst, int val, UINT cnt) { 00525 BYTE *d = (BYTE*)dst; 00526 00527 while (cnt--) 00528 *d++ = (BYTE)val; 00529 } 00530 00531 /* Compare memory to memory */ 00532 static 00533 int mem_cmp (const void* dst, const void* src, UINT cnt) { 00534 const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; 00535 int r = 0; 00536 00537 while (cnt-- && (r = *d++ - *s++) == 0) ; 00538 return r; 00539 } 00540 00541 /* Check if chr is contained in the string */ 00542 static 00543 int chk_chr (const char* str, int chr) { 00544 while (*str && *str != chr) str++; 00545 return *str; 00546 } 00547 00548 00549 00550 00551 /*-----------------------------------------------------------------------*/ 00552 /* Request/Release grant to access the volume */ 00553 /*-----------------------------------------------------------------------*/ 00554 #if _FS_REENTRANT 00555 static 00556 int lock_fs ( 00557 FATFS* fs /* File system object */ 00558 ) 00559 { 00560 return ff_req_grant(fs->sobj); 00561 } 00562 00563 00564 static 00565 void unlock_fs ( 00566 FATFS* fs, /* File system object */ 00567 FRESULT res /* Result code to be returned */ 00568 ) 00569 { 00570 if (fs && 00571 res != FR_NOT_ENABLED && 00572 res != FR_INVALID_DRIVE && 00573 res != FR_INVALID_OBJECT && 00574 res != FR_TIMEOUT) { 00575 ff_rel_grant(fs->sobj); 00576 } 00577 } 00578 #endif 00579 00580 00581 00582 00583 /*-----------------------------------------------------------------------*/ 00584 /* File lock control functions */ 00585 /*-----------------------------------------------------------------------*/ 00586 #if _FS_LOCK 00587 00588 static 00589 FRESULT chk_lock ( /* Check if the file can be accessed */ 00590 FATFS_DIR* dp, /* Directory object pointing the file to be checked */ 00591 int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ 00592 ) 00593 { 00594 UINT i, be; 00595 00596 /* Search file semaphore table */ 00597 for (i = be = 0; i < _FS_LOCK; i++) { 00598 if (Files[i].fs) { /* Existing entry */ 00599 if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */ 00600 Files[i].clu == dp->sclust && 00601 Files[i].idx == dp->index) break; 00602 } else { /* Blank entry */ 00603 be = 1; 00604 } 00605 } 00606 if (i == _FS_LOCK) /* The object is not opened */ 00607 return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ 00608 00609 /* The object has been opened. Reject any open against writing file and all write mode open */ 00610 return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; 00611 } 00612 00613 00614 static 00615 int enq_lock (void) /* Check if an entry is available for a new object */ 00616 { 00617 UINT i; 00618 00619 for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; 00620 return (i == _FS_LOCK) ? 0 : 1; 00621 } 00622 00623 00624 static 00625 UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ 00626 FATFS_DIR* dp, /* Directory object pointing the file to register or increment */ 00627 int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ 00628 ) 00629 { 00630 UINT i; 00631 00632 00633 for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ 00634 if (Files[i].fs == dp->fs && 00635 Files[i].clu == dp->sclust && 00636 Files[i].idx == dp->index) break; 00637 } 00638 00639 if (i == _FS_LOCK) { /* Not opened. Register it as new. */ 00640 for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; 00641 if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ 00642 Files[i].fs = dp->fs; 00643 Files[i].clu = dp->sclust; 00644 Files[i].idx = dp->index; 00645 Files[i].ctr = 0; 00646 } 00647 00648 if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ 00649 00650 Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ 00651 00652 return i + 1; 00653 } 00654 00655 00656 static 00657 FRESULT dec_lock ( /* Decrement object open counter */ 00658 UINT i /* Semaphore index (1..) */ 00659 ) 00660 { 00661 WORD n; 00662 FRESULT res; 00663 00664 00665 if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ 00666 n = Files[i].ctr; 00667 if (n == 0x100) n = 0; /* If write mode open, delete the entry */ 00668 if (n) n--; /* Decrement read mode open count */ 00669 Files[i].ctr = n; 00670 if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */ 00671 res = FR_OK; 00672 } else { 00673 res = FR_INT_ERR; /* Invalid index nunber */ 00674 } 00675 return res; 00676 } 00677 00678 00679 static 00680 void clear_lock ( /* Clear lock entries of the volume */ 00681 FATFS *fs 00682 ) 00683 { 00684 UINT i; 00685 00686 for (i = 0; i < _FS_LOCK; i++) { 00687 if (Files[i].fs == fs) Files[i].fs = 0; 00688 } 00689 } 00690 #endif 00691 00692 00693 00694 00695 /*-----------------------------------------------------------------------*/ 00696 /* Move/Flush disk access window in the file system object */ 00697 /*-----------------------------------------------------------------------*/ 00698 #if !_FS_READONLY 00699 static 00700 FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */ 00701 FATFS* fs /* File system object */ 00702 ) 00703 { 00704 DWORD wsect; 00705 UINT nf; 00706 FRESULT res = FR_OK; 00707 00708 00709 if (fs->wflag) { /* Write back the sector if it is dirty */ 00710 wsect = fs->winsect; /* Current sector number */ 00711 if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { 00712 res = FR_DISK_ERR; 00713 } else { 00714 fs->wflag = 0; 00715 if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ 00716 for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ 00717 wsect += fs->fsize; 00718 disk_write(fs->drv, fs->win, wsect, 1); 00719 } 00720 } 00721 } 00722 } 00723 return res; 00724 } 00725 #endif 00726 00727 00728 static 00729 FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */ 00730 FATFS* fs, /* File system object */ 00731 DWORD sector /* Sector number to make appearance in the fs->win[] */ 00732 ) 00733 { 00734 FRESULT res = FR_OK; 00735 00736 00737 if (sector != fs->winsect) { /* Window offset changed? */ 00738 #if !_FS_READONLY 00739 res = sync_window(fs); /* Write-back changes */ 00740 #endif 00741 if (res == FR_OK) { /* Fill sector window with new data */ 00742 if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { 00743 sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ 00744 res = FR_DISK_ERR; 00745 } 00746 fs->winsect = sector; 00747 } 00748 } 00749 return res; 00750 } 00751 00752 00753 00754 00755 /*-----------------------------------------------------------------------*/ 00756 /* Synchronize file system and strage device */ 00757 /*-----------------------------------------------------------------------*/ 00758 #if !_FS_READONLY 00759 static 00760 FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ 00761 FATFS* fs /* File system object */ 00762 ) 00763 { 00764 FRESULT res; 00765 00766 00767 res = sync_window(fs); 00768 if (res == FR_OK) { 00769 /* Update FSInfo sector if needed */ 00770 if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { 00771 /* Create FSInfo structure */ 00772 mem_set(fs->win, 0, SS(fs)); 00773 ST_WORD(fs->win + BS_55AA, 0xAA55); 00774 ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); 00775 ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); 00776 ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); 00777 ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); 00778 /* Write it into the FSInfo sector */ 00779 fs->winsect = fs->volbase + 1; 00780 disk_write(fs->drv, fs->win, fs->winsect, 1); 00781 fs->fsi_flag = 0; 00782 } 00783 /* Make sure that no pending write process in the physical drive */ 00784 if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) 00785 res = FR_DISK_ERR; 00786 } 00787 00788 return res; 00789 } 00790 #endif 00791 00792 00793 00794 00795 /*-----------------------------------------------------------------------*/ 00796 /* Get sector# from cluster# */ 00797 /*-----------------------------------------------------------------------*/ 00798 /* Hidden API for hacks and disk tools */ 00799 00800 DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ 00801 FATFS* fs, /* File system object */ 00802 DWORD clst /* Cluster# to be converted */ 00803 ) 00804 { 00805 clst -= 2; 00806 if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ 00807 return clst * fs->csize + fs->database; 00808 } 00809 00810 00811 00812 00813 /*-----------------------------------------------------------------------*/ 00814 /* FAT access - Read value of a FAT entry */ 00815 /*-----------------------------------------------------------------------*/ 00816 /* Hidden API for hacks and disk tools */ 00817 00818 DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ 00819 FATFS* fs, /* File system object */ 00820 DWORD clst /* FAT index number (cluster number) to get the value */ 00821 ) 00822 { 00823 UINT wc, bc; 00824 BYTE *p; 00825 DWORD val; 00826 00827 00828 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ 00829 val = 1; /* Internal error */ 00830 00831 } else { 00832 val = 0xFFFFFFFF; /* Default value falls on disk error */ 00833 00834 switch (fs->fs_type) { 00835 case FS_FAT12 : 00836 bc = (UINT)clst; bc += bc / 2; 00837 if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; 00838 wc = fs->win[bc++ % SS(fs)]; 00839 if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; 00840 wc |= fs->win[bc % SS(fs)] << 8; 00841 val = clst & 1 ? wc >> 4 : (wc & 0xFFF); 00842 break; 00843 00844 case FS_FAT16 : 00845 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; 00846 p = &fs->win[clst * 2 % SS(fs)]; 00847 val = LD_WORD(p); 00848 break; 00849 00850 case FS_FAT32 : 00851 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; 00852 p = &fs->win[clst * 4 % SS(fs)]; 00853 val = LD_DWORD(p) & 0x0FFFFFFF; 00854 break; 00855 00856 default: 00857 val = 1; /* Internal error */ 00858 } 00859 } 00860 00861 return val; 00862 } 00863 00864 00865 00866 00867 /*-----------------------------------------------------------------------*/ 00868 /* FAT access - Change value of a FAT entry */ 00869 /*-----------------------------------------------------------------------*/ 00870 /* Hidden API for hacks and disk tools */ 00871 00872 #if !_FS_READONLY 00873 FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ 00874 FATFS* fs, /* File system object */ 00875 DWORD clst, /* FAT index number (cluster number) to be changed */ 00876 DWORD val /* New value to be set to the entry */ 00877 ) 00878 { 00879 UINT bc; 00880 BYTE *p; 00881 FRESULT res; 00882 00883 00884 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ 00885 res = FR_INT_ERR; 00886 00887 } else { 00888 switch (fs->fs_type) { 00889 case FS_FAT12 : 00890 bc = (UINT)clst; bc += bc / 2; 00891 res = move_window(fs, fs->fatbase + (bc / SS(fs))); 00892 if (res != FR_OK) break; 00893 p = &fs->win[bc++ % SS(fs)]; 00894 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; 00895 fs->wflag = 1; 00896 res = move_window(fs, fs->fatbase + (bc / SS(fs))); 00897 if (res != FR_OK) break; 00898 p = &fs->win[bc % SS(fs)]; 00899 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); 00900 fs->wflag = 1; 00901 break; 00902 00903 case FS_FAT16 : 00904 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); 00905 if (res != FR_OK) break; 00906 p = &fs->win[clst * 2 % SS(fs)]; 00907 ST_WORD(p, (WORD)val); 00908 fs->wflag = 1; 00909 break; 00910 00911 case FS_FAT32 : 00912 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); 00913 if (res != FR_OK) break; 00914 p = &fs->win[clst * 4 % SS(fs)]; 00915 val |= LD_DWORD(p) & 0xF0000000; 00916 ST_DWORD(p, val); 00917 fs->wflag = 1; 00918 break; 00919 00920 default : 00921 res = FR_INT_ERR; 00922 } 00923 } 00924 00925 return res; 00926 } 00927 #endif /* !_FS_READONLY */ 00928 00929 00930 00931 00932 /*-----------------------------------------------------------------------*/ 00933 /* FAT handling - Remove a cluster chain */ 00934 /*-----------------------------------------------------------------------*/ 00935 #if !_FS_READONLY 00936 static 00937 FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ 00938 FATFS* fs, /* File system object */ 00939 DWORD clst /* Cluster# to remove a chain from */ 00940 ) 00941 { 00942 FRESULT res; 00943 DWORD nxt; 00944 #if _USE_TRIM 00945 DWORD scl = clst, ecl = clst, rt[2]; 00946 #endif 00947 00948 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ 00949 res = FR_INT_ERR; 00950 00951 } else { 00952 res = FR_OK; 00953 while (clst < fs->n_fatent) { /* Not a last link? */ 00954 nxt = get_fat(fs, clst); /* Get cluster status */ 00955 if (nxt == 0) break; /* Empty cluster? */ 00956 if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ 00957 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ 00958 res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ 00959 if (res != FR_OK) break; 00960 if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ 00961 fs->free_clust++; 00962 fs->fsi_flag |= 1; 00963 } 00964 #if _USE_TRIM 00965 if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ 00966 ecl = nxt; 00967 } else { /* End of contiguous clusters */ 00968 rt[0] = clust2sect(fs, scl); /* Start sector */ 00969 rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ 00970 disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */ 00971 scl = ecl = nxt; 00972 } 00973 #endif 00974 clst = nxt; /* Next cluster */ 00975 } 00976 } 00977 00978 return res; 00979 } 00980 #endif 00981 00982 00983 00984 00985 /*-----------------------------------------------------------------------*/ 00986 /* FAT handling - Stretch or Create a cluster chain */ 00987 /*-----------------------------------------------------------------------*/ 00988 #if !_FS_READONLY 00989 static 00990 DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ 00991 FATFS* fs, /* File system object */ 00992 DWORD clst /* Cluster# to stretch, 0:Create a new chain */ 00993 ) 00994 { 00995 DWORD cs, ncl, scl; 00996 FRESULT res; 00997 00998 00999 if (clst == 0) { /* Create a new chain */ 01000 scl = fs->last_clust; /* Get suggested start point */ 01001 if (!scl || scl >= fs->n_fatent) scl = 1; 01002 } 01003 else { /* Stretch the current chain */ 01004 cs = get_fat(fs, clst); /* Check the cluster status */ 01005 if (cs < 2) return 1; /* Invalid value */ 01006 if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ 01007 if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ 01008 scl = clst; 01009 } 01010 01011 ncl = scl; /* Start cluster */ 01012 for (;;) { 01013 ncl++; /* Next cluster */ 01014 if (ncl >= fs->n_fatent) { /* Check wrap around */ 01015 ncl = 2; 01016 if (ncl > scl) return 0; /* No free cluster */ 01017 } 01018 cs = get_fat(fs, ncl); /* Get the cluster status */ 01019 if (cs == 0) break; /* Found a free cluster */ 01020 if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ 01021 return cs; 01022 if (ncl == scl) return 0; /* No free cluster */ 01023 } 01024 01025 res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ 01026 if (res == FR_OK && clst != 0) { 01027 res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ 01028 } 01029 if (res == FR_OK) { 01030 fs->last_clust = ncl; /* Update FSINFO */ 01031 if (fs->free_clust != 0xFFFFFFFF) { 01032 fs->free_clust--; 01033 fs->fsi_flag |= 1; 01034 } 01035 } else { 01036 ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; 01037 } 01038 01039 return ncl; /* Return new cluster number or error code */ 01040 } 01041 #endif /* !_FS_READONLY */ 01042 01043 01044 01045 01046 /*-----------------------------------------------------------------------*/ 01047 /* FAT handling - Convert offset into cluster with link map table */ 01048 /*-----------------------------------------------------------------------*/ 01049 01050 #if _USE_FASTSEEK 01051 static 01052 DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ 01053 FIL* fp, /* Pointer to the file object */ 01054 DWORD ofs /* File offset to be converted to cluster# */ 01055 ) 01056 { 01057 DWORD cl, ncl, *tbl; 01058 01059 01060 tbl = fp->cltbl + 1; /* Top of CLMT */ 01061 cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ 01062 for (;;) { 01063 ncl = *tbl++; /* Number of cluters in the fragment */ 01064 if (!ncl) return 0; /* End of table? (error) */ 01065 if (cl < ncl) break; /* In this fragment? */ 01066 cl -= ncl; tbl++; /* Next fragment */ 01067 } 01068 return cl + *tbl; /* Return the cluster number */ 01069 } 01070 #endif /* _USE_FASTSEEK */ 01071 01072 01073 01074 01075 /*-----------------------------------------------------------------------*/ 01076 /* Directory handling - Set directory index */ 01077 /*-----------------------------------------------------------------------*/ 01078 01079 static 01080 FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ 01081 FATFS_DIR* dp, /* Pointer to directory object */ 01082 UINT idx /* Index of directory table */ 01083 ) 01084 { 01085 DWORD clst, sect; 01086 UINT ic; 01087 01088 01089 dp->index = (WORD)idx; /* Current index */ 01090 clst = dp->sclust; /* Table start cluster (0:root) */ 01091 if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ 01092 return FR_INT_ERR; 01093 if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ 01094 clst = dp->fs->dirbase; 01095 01096 if (clst == 0) { /* Static table (root-directory in FAT12/16) */ 01097 if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ 01098 return FR_INT_ERR; 01099 sect = dp->fs->dirbase; 01100 } 01101 else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ 01102 ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */ 01103 while (idx >= ic) { /* Follow cluster chain */ 01104 clst = get_fat(dp->fs, clst); /* Get next cluster */ 01105 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ 01106 if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */ 01107 return FR_INT_ERR; 01108 idx -= ic; 01109 } 01110 sect = clust2sect(dp->fs, clst); 01111 } 01112 dp->clust = clst; /* Current cluster# */ 01113 if (!sect) return FR_INT_ERR; 01114 dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */ 01115 dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */ 01116 01117 return FR_OK; 01118 } 01119 01120 01121 01122 01123 /*-----------------------------------------------------------------------*/ 01124 /* Directory handling - Move directory table index next */ 01125 /*-----------------------------------------------------------------------*/ 01126 01127 static 01128 FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ 01129 FATFS_DIR* dp, /* Pointer to the directory object */ 01130 int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ 01131 ) 01132 { 01133 DWORD clst; 01134 UINT i; 01135 #if !_FS_READONLY 01136 UINT c; 01137 #endif 01138 01139 01140 i = dp->index + 1; 01141 if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ 01142 return FR_NO_FILE; 01143 01144 if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */ 01145 dp->sect++; /* Next sector */ 01146 01147 if (!dp->clust) { /* Static table */ 01148 if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */ 01149 return FR_NO_FILE; 01150 } 01151 else { /* Dynamic table */ 01152 if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ 01153 clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ 01154 if (clst <= 1) return FR_INT_ERR; 01155 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; 01156 if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */ 01157 #if !_FS_READONLY 01158 if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */ 01159 clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */ 01160 if (clst == 0) return FR_DENIED; /* No free cluster */ 01161 if (clst == 1) return FR_INT_ERR; 01162 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; 01163 /* Clean-up stretched table */ 01164 if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */ 01165 mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */ 01166 dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */ 01167 for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */ 01168 dp->fs->wflag = 1; 01169 if (sync_window(dp->fs)) return FR_DISK_ERR; 01170 dp->fs->winsect++; 01171 } 01172 dp->fs->winsect -= c; /* Rewind window offset */ 01173 #else 01174 if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */ 01175 return FR_NO_FILE; /* Report EOT */ 01176 #endif 01177 } 01178 dp->clust = clst; /* Initialize data for new cluster */ 01179 dp->sect = clust2sect(dp->fs, clst); 01180 } 01181 } 01182 } 01183 01184 dp->index = (WORD)i; /* Current index */ 01185 dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */ 01186 01187 return FR_OK; 01188 } 01189 01190 01191 01192 01193 /*-----------------------------------------------------------------------*/ 01194 /* Directory handling - Reserve directory entry */ 01195 /*-----------------------------------------------------------------------*/ 01196 01197 #if !_FS_READONLY 01198 static 01199 FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ 01200 FATFS_DIR* dp, /* Pointer to the directory object */ 01201 UINT nent /* Number of contiguous entries to allocate (1-21) */ 01202 ) 01203 { 01204 FRESULT res; 01205 UINT n; 01206 01207 01208 res = dir_sdi(dp, 0); 01209 if (res == FR_OK) { 01210 n = 0; 01211 do { 01212 res = move_window(dp->fs, dp->sect); 01213 if (res != FR_OK) break; 01214 if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */ 01215 if (++n == nent) break; /* A block of contiguous free entries is found */ 01216 } else { 01217 n = 0; /* Not a blank entry. Restart to search */ 01218 } 01219 res = dir_next(dp, 1); /* Next entry with table stretch enabled */ 01220 } while (res == FR_OK); 01221 } 01222 if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ 01223 return res; 01224 } 01225 #endif 01226 01227 01228 01229 01230 /*-----------------------------------------------------------------------*/ 01231 /* Directory handling - Load/Store start cluster number */ 01232 /*-----------------------------------------------------------------------*/ 01233 01234 static 01235 DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ 01236 FATFS* fs, /* Pointer to the fs object */ 01237 const BYTE* dir /* Pointer to the SFN entry */ 01238 ) 01239 { 01240 DWORD cl; 01241 01242 cl = LD_WORD(dir + DIR_FstClusLO); 01243 if (fs->fs_type == FS_FAT32) 01244 cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16; 01245 01246 return cl; 01247 } 01248 01249 01250 #if !_FS_READONLY 01251 static 01252 void st_clust ( 01253 BYTE* dir, /* Pointer to the SFN entry */ 01254 DWORD cl /* Value to be set */ 01255 ) 01256 { 01257 ST_WORD(dir + DIR_FstClusLO, cl); 01258 ST_WORD(dir + DIR_FstClusHI, cl >> 16); 01259 } 01260 #endif 01261 01262 01263 01264 01265 /*-----------------------------------------------------------------------*/ 01266 /* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ 01267 /*-----------------------------------------------------------------------*/ 01268 #if _USE_LFN 01269 static 01270 const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ 01271 01272 01273 static 01274 int cmp_lfn ( /* 1:matched, 0:not matched */ 01275 WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ 01276 BYTE* dir /* Pointer to the directory entry containing the part of LFN */ 01277 ) 01278 { 01279 UINT i, s; 01280 WCHAR wc, uc; 01281 01282 01283 if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ 01284 01285 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ 01286 01287 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ 01288 uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */ 01289 if (wc) { 01290 if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) /* Compare it */ 01291 return 0; /* Not matched */ 01292 wc = uc; 01293 } else { 01294 if (uc != 0xFFFF) return 0; /* Check filler */ 01295 } 01296 } 01297 01298 if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ 01299 return 0; 01300 01301 return 1; /* The part of LFN matched */ 01302 } 01303 01304 01305 01306 static 01307 int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ 01308 WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ 01309 BYTE* dir /* Pointer to the LFN entry */ 01310 ) 01311 { 01312 UINT i, s; 01313 WCHAR wc, uc; 01314 01315 01316 if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ 01317 01318 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ 01319 01320 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ 01321 uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */ 01322 if (wc) { 01323 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ 01324 lfnbuf[i++] = wc = uc; /* Store it */ 01325 } else { 01326 if (uc != 0xFFFF) return 0; /* Check filler */ 01327 } 01328 } 01329 01330 if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ 01331 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ 01332 lfnbuf[i] = 0; 01333 } 01334 01335 return 1; /* The part of LFN is valid */ 01336 } 01337 01338 01339 #if !_FS_READONLY 01340 static 01341 void fit_lfn ( 01342 const WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ 01343 BYTE* dir, /* Pointer to the LFN entry to be processed */ 01344 BYTE ord, /* LFN order (1-20) */ 01345 BYTE sum /* Checksum of the corresponding SFN */ 01346 ) 01347 { 01348 UINT i, s; 01349 WCHAR wc; 01350 01351 01352 dir[LDIR_Chksum] = sum; /* Set checksum */ 01353 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ 01354 dir[LDIR_Type] = 0; 01355 ST_WORD(dir + LDIR_FstClusLO, 0); 01356 01357 i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ 01358 s = wc = 0; 01359 do { 01360 if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ 01361 ST_WORD(dir+LfnOfs[s], wc); /* Put it */ 01362 if (!wc) wc = 0xFFFF; /* Padding characters following last character */ 01363 } while (++s < 13); 01364 if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */ 01365 dir[LDIR_Ord] = ord; /* Set the LFN order */ 01366 } 01367 01368 #endif 01369 #endif 01370 01371 01372 01373 01374 /*-----------------------------------------------------------------------*/ 01375 /* Create numbered name */ 01376 /*-----------------------------------------------------------------------*/ 01377 #if _USE_LFN 01378 static 01379 void gen_numname ( 01380 BYTE* dst, /* Pointer to the buffer to store numbered SFN */ 01381 const BYTE* src, /* Pointer to SFN */ 01382 const WCHAR* lfn, /* Pointer to LFN */ 01383 UINT seq /* Sequence number */ 01384 ) 01385 { 01386 BYTE ns[8], c; 01387 UINT i, j; 01388 WCHAR wc; 01389 DWORD sr; 01390 01391 01392 mem_cpy(dst, src, 11); 01393 01394 if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ 01395 sr = seq; 01396 while (*lfn) { /* Create a CRC */ 01397 wc = *lfn++; 01398 for (i = 0; i < 16; i++) { 01399 sr = (sr << 1) + (wc & 1); 01400 wc >>= 1; 01401 if (sr & 0x10000) sr ^= 0x11021; 01402 } 01403 } 01404 seq = (UINT)sr; 01405 } 01406 01407 /* itoa (hexdecimal) */ 01408 i = 7; 01409 do { 01410 c = (seq % 16) + '0'; 01411 if (c > '9') c += 7; 01412 ns[i--] = c; 01413 seq /= 16; 01414 } while (seq); 01415 ns[i] = '~'; 01416 01417 /* Append the number */ 01418 for (j = 0; j < i && dst[j] != ' '; j++) { 01419 if (IsDBCS1(dst[j])) { 01420 if (j == i - 1) break; 01421 j++; 01422 } 01423 } 01424 do { 01425 dst[j++] = (i < 8) ? ns[i++] : ' '; 01426 } while (j < 8); 01427 } 01428 #endif 01429 01430 01431 01432 01433 /*-----------------------------------------------------------------------*/ 01434 /* Calculate checksum of an SFN entry */ 01435 /*-----------------------------------------------------------------------*/ 01436 #if _USE_LFN 01437 static 01438 BYTE sum_sfn ( 01439 const BYTE* dir /* Pointer to the SFN entry */ 01440 ) 01441 { 01442 BYTE sum = 0; 01443 UINT n = 11; 01444 01445 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); 01446 return sum; 01447 } 01448 #endif 01449 01450 01451 01452 01453 /*-----------------------------------------------------------------------*/ 01454 /* Directory handling - Find an object in the directory */ 01455 /*-----------------------------------------------------------------------*/ 01456 01457 static 01458 FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ 01459 FATFS_DIR* dp /* Pointer to the directory object linked to the file name */ 01460 ) 01461 { 01462 FRESULT res; 01463 BYTE c, *dir; 01464 #if _USE_LFN 01465 BYTE a, ord, sum; 01466 #endif 01467 01468 res = dir_sdi(dp, 0); /* Rewind directory object */ 01469 if (res != FR_OK) return res; 01470 01471 #if _USE_LFN 01472 ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ 01473 #endif 01474 do { 01475 res = move_window(dp->fs, dp->sect); 01476 if (res != FR_OK) break; 01477 dir = dp->dir; /* Ptr to the directory entry of current index */ 01478 c = dir[DIR_Name]; 01479 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ 01480 #if _USE_LFN /* LFN configuration */ 01481 a = dir[DIR_Attr] & AM_MASK; 01482 if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ 01483 ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ 01484 } else { 01485 if (a == AM_LFN) { /* An LFN entry is found */ 01486 if (dp->lfn) { 01487 if (c & LLEF) { /* Is it start of LFN sequence? */ 01488 sum = dir[LDIR_Chksum]; 01489 c &= ~LLEF; ord = c; /* LFN start order */ 01490 dp->lfn_idx = dp->index; /* Start index of LFN */ 01491 } 01492 /* Check validity of the LFN entry and compare it with given name */ 01493 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; 01494 } 01495 } else { /* An SFN entry is found */ 01496 if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ 01497 if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */ 01498 ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ 01499 } 01500 } 01501 #else /* Non LFN configuration */ 01502 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ 01503 break; 01504 #endif 01505 res = dir_next(dp, 0); /* Next entry */ 01506 } while (res == FR_OK); 01507 01508 return res; 01509 } 01510 01511 01512 01513 01514 /*-----------------------------------------------------------------------*/ 01515 /* Read an object from the directory */ 01516 /*-----------------------------------------------------------------------*/ 01517 #if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 01518 static 01519 FRESULT dir_read ( 01520 FATFS_DIR* dp, /* Pointer to the directory object */ 01521 int vol /* Filtered by 0:file/directory or 1:volume label */ 01522 ) 01523 { 01524 FRESULT res; 01525 BYTE a, c, *dir; 01526 #if _USE_LFN 01527 BYTE ord = 0xFF, sum = 0xFF; 01528 #endif 01529 01530 res = FR_NO_FILE; 01531 while (dp->sect) { 01532 res = move_window(dp->fs, dp->sect); 01533 if (res != FR_OK) break; 01534 dir = dp->dir; /* Ptr to the directory entry of current index */ 01535 c = dir[DIR_Name]; 01536 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ 01537 a = dir[DIR_Attr] & AM_MASK; 01538 #if _USE_LFN /* LFN configuration */ 01539 if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ 01540 ord = 0xFF; 01541 } else { 01542 if (a == AM_LFN) { /* An LFN entry is found */ 01543 if (c & LLEF) { /* Is it start of LFN sequence? */ 01544 sum = dir[LDIR_Chksum]; 01545 c &= ~LLEF; ord = c; 01546 dp->lfn_idx = dp->index; 01547 } 01548 /* Check LFN validity and capture it */ 01549 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; 01550 } else { /* An SFN entry is found */ 01551 if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ 01552 dp->lfn_idx = 0xFFFF; /* It has no LFN. */ 01553 break; 01554 } 01555 } 01556 #else /* Non LFN configuration */ 01557 if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */ 01558 break; 01559 #endif 01560 res = dir_next(dp, 0); /* Next entry */ 01561 if (res != FR_OK) break; 01562 } 01563 01564 if (res != FR_OK) dp->sect = 0; 01565 01566 return res; 01567 } 01568 #endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ 01569 01570 01571 01572 01573 /*-----------------------------------------------------------------------*/ 01574 /* Register an object to the directory */ 01575 /*-----------------------------------------------------------------------*/ 01576 #if !_FS_READONLY 01577 static 01578 FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ 01579 FATFS_DIR* dp /* Target directory with object name to be created */ 01580 ) 01581 { 01582 FRESULT res; 01583 #if _USE_LFN /* LFN configuration */ 01584 UINT n, nent; 01585 BYTE sn[12], *fn, sum; 01586 WCHAR *lfn; 01587 01588 01589 fn = dp->fn; lfn = dp->lfn; 01590 mem_cpy(sn, fn, 12); 01591 01592 if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */ 01593 return FR_INVALID_NAME; 01594 01595 if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ 01596 fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ 01597 for (n = 1; n < 100; n++) { 01598 gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ 01599 res = dir_find(dp); /* Check if the name collides with existing SFN */ 01600 if (res != FR_OK) break; 01601 } 01602 if (n == 100) return FR_DENIED; /* Abort if too many collisions */ 01603 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ 01604 fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn; 01605 } 01606 01607 if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */ 01608 for (n = 0; lfn[n]; n++) ; 01609 nent = (n + 25) / 13; 01610 } else { /* Otherwise allocate an entry for an SFN */ 01611 nent = 1; 01612 } 01613 res = dir_alloc(dp, nent); /* Allocate entries */ 01614 01615 if (res == FR_OK && --nent) { /* Set LFN entry if needed */ 01616 res = dir_sdi(dp, dp->index - nent); 01617 if (res == FR_OK) { 01618 sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ 01619 do { /* Store LFN entries in bottom first */ 01620 res = move_window(dp->fs, dp->sect); 01621 if (res != FR_OK) break; 01622 fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); 01623 dp->fs->wflag = 1; 01624 res = dir_next(dp, 0); /* Next entry */ 01625 } while (res == FR_OK && --nent); 01626 } 01627 } 01628 #else /* Non LFN configuration */ 01629 res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ 01630 #endif 01631 01632 if (res == FR_OK) { /* Set SFN entry */ 01633 res = move_window(dp->fs, dp->sect); 01634 if (res == FR_OK) { 01635 mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */ 01636 mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ 01637 #if _USE_LFN 01638 dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ 01639 #endif 01640 dp->fs->wflag = 1; 01641 } 01642 } 01643 01644 return res; 01645 } 01646 #endif /* !_FS_READONLY */ 01647 01648 01649 01650 01651 /*-----------------------------------------------------------------------*/ 01652 /* Remove an object from the directory */ 01653 /*-----------------------------------------------------------------------*/ 01654 #if !_FS_READONLY && !_FS_MINIMIZE 01655 static 01656 FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ 01657 FATFS_DIR* dp /* Directory object pointing the entry to be removed */ 01658 ) 01659 { 01660 FRESULT res; 01661 #if _USE_LFN /* LFN configuration */ 01662 UINT i; 01663 01664 i = dp->index; /* SFN index */ 01665 res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ 01666 if (res == FR_OK) { 01667 do { 01668 res = move_window(dp->fs, dp->sect); 01669 if (res != FR_OK) break; 01670 mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ 01671 *dp->dir = DDEM; 01672 dp->fs->wflag = 1; 01673 if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ 01674 res = dir_next(dp, 0); /* Next entry */ 01675 } while (res == FR_OK); 01676 if (res == FR_NO_FILE) res = FR_INT_ERR; 01677 } 01678 01679 #else /* Non LFN configuration */ 01680 res = dir_sdi(dp, dp->index); 01681 if (res == FR_OK) { 01682 res = move_window(dp->fs, dp->sect); 01683 if (res == FR_OK) { 01684 mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ 01685 *dp->dir = DDEM; 01686 dp->fs->wflag = 1; 01687 } 01688 } 01689 #endif 01690 01691 return res; 01692 } 01693 #endif /* !_FS_READONLY */ 01694 01695 01696 01697 01698 /*-----------------------------------------------------------------------*/ 01699 /* Get file information from directory entry */ 01700 /*-----------------------------------------------------------------------*/ 01701 #if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 01702 static 01703 void get_fileinfo ( /* No return code */ 01704 FATFS_DIR* dp, /* Pointer to the directory object */ 01705 FILINFO* fno /* Pointer to the file information to be filled */ 01706 ) 01707 { 01708 UINT i; 01709 TCHAR *p, c; 01710 BYTE *dir; 01711 #if _USE_LFN 01712 WCHAR w, *lfn; 01713 #endif 01714 01715 p = fno->fname; 01716 if (dp->sect) { /* Get SFN */ 01717 dir = dp->dir; 01718 i = 0; 01719 while (i < 11) { /* Copy name body and extension */ 01720 c = (TCHAR)dir[i++]; 01721 if (c == ' ') continue; /* Skip padding spaces */ 01722 if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ 01723 if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */ 01724 #if _USE_LFN 01725 if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) 01726 c += 0x20; /* To lower */ 01727 #if _LFN_UNICODE 01728 if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) 01729 c = c << 8 | dir[i++]; 01730 c = ff_convert(c, 1); /* OEM -> Unicode */ 01731 if (!c) c = '?'; 01732 #endif 01733 #endif 01734 *p++ = c; 01735 } 01736 fno->fattrib = dir[DIR_Attr]; /* Attribute */ 01737 fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */ 01738 fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */ 01739 fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */ 01740 } 01741 *p = 0; /* Terminate SFN string by a \0 */ 01742 01743 #if _USE_LFN 01744 if (fno->lfname) { 01745 i = 0; p = fno->lfname; 01746 if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ 01747 lfn = dp->lfn; 01748 while ((w = *lfn++) != 0) { /* Get an LFN character */ 01749 #if !_LFN_UNICODE 01750 w = ff_convert(w, 0); /* Unicode -> OEM */ 01751 if (!w) { i = 0; break; } /* No LFN if it could not be converted */ 01752 if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ 01753 p[i++] = (TCHAR)(w >> 8); 01754 #endif 01755 if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */ 01756 p[i++] = (TCHAR)w; 01757 } 01758 } 01759 p[i] = 0; /* Terminate LFN string by a \0 */ 01760 } 01761 #endif 01762 } 01763 #endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ 01764 01765 01766 01767 01768 /*-----------------------------------------------------------------------*/ 01769 /* Pattern matching */ 01770 /*-----------------------------------------------------------------------*/ 01771 #if _USE_FIND && _FS_MINIMIZE <= 1 01772 static 01773 WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ 01774 const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ 01775 ) 01776 { 01777 WCHAR chr; 01778 01779 #if !_LFN_UNICODE 01780 chr = (BYTE)*(*ptr)++; /* Get a byte */ 01781 if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ 01782 if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */ 01783 chr = chr << 8 | (BYTE)*(*ptr)++; 01784 #ifdef _EXCVT 01785 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ 01786 #endif 01787 #else 01788 chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ 01789 #endif 01790 return chr; 01791 } 01792 01793 01794 static 01795 int pattern_matching ( /* 0:mismatched, 1:matched */ 01796 const TCHAR* pat, /* Matching pattern */ 01797 const TCHAR* nam, /* String to be tested */ 01798 int skip, /* Number of pre-skip chars (number of ?s) */ 01799 int inf /* Infinite search (* specified) */ 01800 ) 01801 { 01802 const TCHAR *pp, *np; 01803 WCHAR pc, nc; 01804 int nm, nx; 01805 01806 01807 while (skip--) { /* Pre-skip name chars */ 01808 if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ 01809 } 01810 if (!*pat && inf) return 1; /* (short circuit) */ 01811 01812 do { 01813 pp = pat; np = nam; /* Top of pattern and name to match */ 01814 for (;;) { 01815 if (*pp == '?' || *pp == '*') { /* Wildcard? */ 01816 nm = nx = 0; 01817 do { /* Analyze the wildcard chars */ 01818 if (*pp++ == '?') nm++; else nx = 1; 01819 } while (*pp == '?' || *pp == '*'); 01820 if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ 01821 nc = *np; break; /* Branch mismatched */ 01822 } 01823 pc = get_achar(&pp); /* Get a pattern char */ 01824 nc = get_achar(&np); /* Get a name char */ 01825 if (pc != nc) break; /* Branch mismatched? */ 01826 if (!pc) return 1; /* Branch matched? (matched at end of both strings) */ 01827 } 01828 get_achar(&nam); /* nam++ */ 01829 } while (inf && nc); /* Retry until end of name if infinite search is specified */ 01830 01831 return 0; 01832 } 01833 #endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ 01834 01835 01836 01837 01838 /*-----------------------------------------------------------------------*/ 01839 /* Pick a top segment and create the object name in directory form */ 01840 /*-----------------------------------------------------------------------*/ 01841 01842 static 01843 FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ 01844 FATFS_DIR* dp, /* Pointer to the directory object */ 01845 const TCHAR** path /* Pointer to pointer to the segment in the path string */ 01846 ) 01847 { 01848 #if _USE_LFN /* LFN configuration */ 01849 BYTE b, cf; 01850 WCHAR w, *lfn; 01851 UINT i, ni, si, di; 01852 const TCHAR *p; 01853 01854 /* Create LFN in Unicode */ 01855 for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ 01856 lfn = dp->lfn; 01857 si = di = 0; 01858 for (;;) { 01859 w = p[si++]; /* Get a character */ 01860 if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ 01861 if (di >= _MAX_LFN) /* Reject too long name */ 01862 return FR_INVALID_NAME; 01863 #if !_LFN_UNICODE 01864 w &= 0xFF; 01865 if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ 01866 b = (BYTE)p[si++]; /* Get 2nd byte */ 01867 w = (w << 8) + b; /* Create a DBC */ 01868 if (!IsDBCS2(b)) 01869 return FR_INVALID_NAME; /* Reject invalid sequence */ 01870 } 01871 w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ 01872 if (!w) return FR_INVALID_NAME; /* Reject invalid code */ 01873 #endif 01874 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ 01875 return FR_INVALID_NAME; 01876 lfn[di++] = w; /* Store the Unicode character */ 01877 } 01878 *path = &p[si]; /* Return pointer to the next segment */ 01879 cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ 01880 #if _FS_RPATH 01881 if ((di == 1 && lfn[di - 1] == '.') || 01882 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot entry? */ 01883 lfn[di] = 0; 01884 for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ 01885 dp->fn[i] = (i < di) ? '.' : ' '; 01886 dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ 01887 return FR_OK; 01888 } 01889 #endif 01890 while (di) { /* Snip off trailing spaces and dots if exist */ 01891 w = lfn[di - 1]; 01892 if (w != ' ' && w != '.') break; 01893 di--; 01894 } 01895 if (!di) return FR_INVALID_NAME; /* Reject nul string */ 01896 lfn[di] = 0; /* LFN is created */ 01897 01898 /* Create SFN in directory form */ 01899 mem_set(dp->fn, ' ', 11); 01900 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ 01901 if (si) cf |= NS_LOSS | NS_LFN; 01902 while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ 01903 01904 b = i = 0; ni = 8; 01905 for (;;) { 01906 w = lfn[si++]; /* Get an LFN character */ 01907 if (!w) break; /* Break on end of the LFN */ 01908 if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ 01909 cf |= NS_LOSS | NS_LFN; continue; 01910 } 01911 01912 if (i >= ni || si == di) { /* Extension or end of SFN */ 01913 if (ni == 11) { /* Long extension */ 01914 cf |= NS_LOSS | NS_LFN; break; 01915 } 01916 if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ 01917 if (si > di) break; /* No extension */ 01918 si = di; i = 8; ni = 11; /* Enter extension section */ 01919 b <<= 2; continue; 01920 } 01921 01922 if (w >= 0x80) { /* Non ASCII character */ 01923 #ifdef _EXCVT 01924 w = ff_convert(w, 0); /* Unicode -> OEM code */ 01925 if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ 01926 #else 01927 w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ 01928 #endif 01929 cf |= NS_LFN; /* Force create LFN entry */ 01930 } 01931 01932 if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */ 01933 if (i >= ni - 1) { 01934 cf |= NS_LOSS | NS_LFN; i = ni; continue; 01935 } 01936 dp->fn[i++] = (BYTE)(w >> 8); 01937 } else { /* SBC */ 01938 if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ 01939 w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ 01940 } else { 01941 if (IsUpper(w)) { /* ASCII large capital */ 01942 b |= 2; 01943 } else { 01944 if (IsLower(w)) { /* ASCII small capital */ 01945 b |= 1; w -= 0x20; 01946 } 01947 } 01948 } 01949 } 01950 dp->fn[i++] = (BYTE)w; 01951 } 01952 01953 if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ 01954 01955 if (ni == 8) b <<= 2; 01956 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ 01957 cf |= NS_LFN; 01958 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ 01959 if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ 01960 if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ 01961 } 01962 01963 dp->fn[NSFLAG] = cf; /* SFN is created */ 01964 01965 return FR_OK; 01966 01967 01968 #else /* Non-LFN configuration */ 01969 BYTE b, c, d, *sfn; 01970 UINT ni, si, i; 01971 const char *p; 01972 01973 /* Create file name in directory form */ 01974 for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Skip duplicated separator */ 01975 sfn = dp->fn; 01976 mem_set(sfn, ' ', 11); 01977 si = i = b = 0; ni = 8; 01978 #if _FS_RPATH 01979 if (p[si] == '.') { /* Is this a dot entry? */ 01980 for (;;) { 01981 c = (BYTE)p[si++]; 01982 if (c != '.' || si >= 3) break; 01983 sfn[i++] = c; 01984 } 01985 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; 01986 *path = &p[si]; /* Return pointer to the next segment */ 01987 sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ 01988 return FR_OK; 01989 } 01990 #endif 01991 for (;;) { 01992 c = (BYTE)p[si++]; 01993 if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ 01994 if (c == '.' || i >= ni) { 01995 if (ni != 8 || c != '.') return FR_INVALID_NAME; 01996 i = 8; ni = 11; 01997 b <<= 2; continue; 01998 } 01999 if (c >= 0x80) { /* Extended character? */ 02000 b |= 3; /* Eliminate NT flag */ 02001 #ifdef _EXCVT 02002 c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ 02003 #else 02004 #if !_DF1S 02005 return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ 02006 #endif 02007 #endif 02008 } 02009 if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ 02010 d = (BYTE)p[si++]; /* Get 2nd byte */ 02011 if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ 02012 return FR_INVALID_NAME; 02013 sfn[i++] = c; 02014 sfn[i++] = d; 02015 } else { /* SBC */ 02016 if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ 02017 return FR_INVALID_NAME; 02018 if (IsUpper(c)) { /* ASCII large capital? */ 02019 b |= 2; 02020 } else { 02021 if (IsLower(c)) { /* ASCII small capital? */ 02022 b |= 1; c -= 0x20; 02023 } 02024 } 02025 sfn[i++] = c; 02026 } 02027 } 02028 *path = &p[si]; /* Return pointer to the next segment */ 02029 c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ 02030 02031 if (!i) return FR_INVALID_NAME; /* Reject nul string */ 02032 if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */ 02033 02034 if (ni == 8) b <<= 2; 02035 if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ 02036 if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ 02037 02038 sfn[NSFLAG] = c; /* Store NT flag, File name is created */ 02039 02040 return FR_OK; 02041 #endif 02042 } 02043 02044 02045 02046 02047 /*-----------------------------------------------------------------------*/ 02048 /* Follow a file path */ 02049 /*-----------------------------------------------------------------------*/ 02050 02051 static 02052 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ 02053 FATFS_DIR* dp, /* Directory object to return last directory and found object */ 02054 const TCHAR* path /* Full-path string to find a file or directory */ 02055 ) 02056 { 02057 FRESULT res; 02058 BYTE *dir, ns; 02059 02060 02061 #if _FS_RPATH 02062 if (*path == '/' || *path == '\\') { /* There is a heading separator */ 02063 path++; dp->sclust = 0; /* Strip it and start from the root directory */ 02064 } else { /* No heading separator */ 02065 dp->sclust = dp->fs->cdir; /* Start from the current directory */ 02066 } 02067 #else 02068 if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ 02069 path++; 02070 dp->sclust = 0; /* Always start from the root directory */ 02071 #endif 02072 02073 if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ 02074 res = dir_sdi(dp, 0); 02075 dp->dir = 0; 02076 } else { /* Follow path */ 02077 for (;;) { 02078 res = create_name(dp, &path); /* Get a segment name of the path */ 02079 if (res != FR_OK) break; 02080 res = dir_find(dp); /* Find an object with the sagment name */ 02081 ns = dp->fn[NSFLAG]; 02082 if (res != FR_OK) { /* Failed to find the object */ 02083 if (res == FR_NO_FILE) { /* Object is not found */ 02084 if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */ 02085 dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */ 02086 if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ 02087 res = FR_OK; /* Ended at the root directroy. Function completed. */ 02088 } else { /* Could not find the object */ 02089 if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ 02090 } 02091 } 02092 break; 02093 } 02094 if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ 02095 dir = dp->dir; /* Follow the sub-directory */ 02096 if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */ 02097 res = FR_NO_PATH; break; 02098 } 02099 dp->sclust = ld_clust(dp->fs, dir); 02100 } 02101 } 02102 02103 return res; 02104 } 02105 02106 02107 02108 02109 /*-----------------------------------------------------------------------*/ 02110 /* Get logical drive number from path name */ 02111 /*-----------------------------------------------------------------------*/ 02112 02113 static 02114 int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ 02115 const TCHAR** path /* Pointer to pointer to the path name */ 02116 ) 02117 { 02118 const TCHAR *tp, *tt; 02119 UINT i; 02120 int vol = -1; 02121 #if _STR_VOLUME_ID /* Find string drive id */ 02122 static const char* const str[] = {_VOLUME_STRS}; 02123 const char *sp; 02124 char c; 02125 TCHAR tc; 02126 #endif 02127 02128 02129 if (*path) { /* If the pointer is not a null */ 02130 for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ 02131 if (*tt == ':') { /* If a ':' is exist in the path name */ 02132 tp = *path; 02133 i = *tp++ - '0'; 02134 if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ 02135 if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ 02136 vol = (int)i; 02137 *path = ++tt; 02138 } 02139 } 02140 #if _STR_VOLUME_ID 02141 else { /* No numeric drive number, find string drive id */ 02142 i = 0; tt++; 02143 do { 02144 sp = str[i]; tp = *path; 02145 do { /* Compare a string drive id with path name */ 02146 c = *sp++; tc = *tp++; 02147 if (IsLower(tc)) tc -= 0x20; 02148 } while (c && (TCHAR)c == tc); 02149 } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */ 02150 if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ 02151 vol = (int)i; 02152 *path = tt; 02153 } 02154 } 02155 #endif 02156 return vol; 02157 } 02158 #if _FS_RPATH && _VOLUMES >= 2 02159 vol = CurrVol; /* Current drive */ 02160 #else 02161 vol = 0; /* Drive 0 */ 02162 #endif 02163 } 02164 return vol; 02165 } 02166 02167 02168 02169 02170 /*-----------------------------------------------------------------------*/ 02171 /* Load a sector and check if it is an FAT boot sector */ 02172 /*-----------------------------------------------------------------------*/ 02173 02174 static 02175 BYTE check_fs ( /* 0:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk error */ 02176 FATFS* fs, /* File system object */ 02177 DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ 02178 ) 02179 { 02180 fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ 02181 if (move_window(fs, sect) != FR_OK) /* Load boot record */ 02182 return 3; 02183 02184 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ 02185 return 2; 02186 02187 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ 02188 return 0; 02189 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ 02190 return 0; 02191 02192 return 1; 02193 } 02194 02195 02196 02197 02198 /*-----------------------------------------------------------------------*/ 02199 /* Find logical drive and check if the volume is mounted */ 02200 /*-----------------------------------------------------------------------*/ 02201 02202 static 02203 FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ 02204 FATFS** rfs, /* Pointer to pointer to the found file system object */ 02205 const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ 02206 BYTE wmode /* !=0: Check write protection for write access */ 02207 ) 02208 { 02209 BYTE fmt, *pt; 02210 int vol; 02211 DSTATUS stat; 02212 DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; 02213 WORD nrsv; 02214 FATFS *fs; 02215 UINT i; 02216 02217 02218 /* Get logical drive number from the path name */ 02219 *rfs = 0; 02220 vol = get_ldnumber(path); 02221 if (vol < 0) return FR_INVALID_DRIVE; 02222 02223 /* Check if the file system object is valid or not */ 02224 fs = FatFs[vol]; /* Get pointer to the file system object */ 02225 if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ 02226 02227 ENTER_FF(fs); /* Lock the volume */ 02228 *rfs = fs; /* Return pointer to the file system object */ 02229 02230 if (fs->fs_type) { /* If the volume has been mounted */ 02231 stat = disk_status(fs->drv); 02232 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ 02233 if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ 02234 return FR_WRITE_PROTECTED; 02235 return FR_OK; /* The file system object is valid */ 02236 } 02237 } 02238 02239 /* The file system object is not valid. */ 02240 /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ 02241 02242 fs->fs_type = 0; /* Clear the file system object */ 02243 fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ 02244 stat = disk_initialize(fs->drv); /* Initialize the physical drive */ 02245 if (stat & STA_NOINIT) /* Check if the initialization succeeded */ 02246 return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ 02247 if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */ 02248 return FR_WRITE_PROTECTED; 02249 #if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ 02250 if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK 02251 || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; 02252 #endif 02253 /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ 02254 bsect = 0; 02255 fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ 02256 if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ 02257 for (i = 0; i < 4; i++) { /* Get partition offset */ 02258 pt = fs->win + MBR_Table + i * SZ_PTE; 02259 br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; 02260 } 02261 i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ 02262 if (i) i--; 02263 do { /* Find an FAT volume */ 02264 bsect = br[i]; 02265 fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ 02266 } while (!LD2PT(vol) && fmt && ++i < 4); 02267 } 02268 if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ 02269 if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ 02270 02271 /* An FAT volume is found. Following code initializes the file system object */ 02272 02273 if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ 02274 return FR_NO_FILESYSTEM; 02275 02276 fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ 02277 if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32); 02278 fs->fsize = fasize; 02279 02280 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ 02281 if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ 02282 return FR_NO_FILESYSTEM; 02283 fasize *= fs->n_fats; /* Number of sectors for FAT area */ 02284 02285 fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ 02286 if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ 02287 return FR_NO_FILESYSTEM; 02288 02289 fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ 02290 if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ 02291 return FR_NO_FILESYSTEM; 02292 02293 tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ 02294 if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32); 02295 02296 nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ 02297 if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ 02298 02299 /* Determine the FAT sub type */ 02300 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + FATFS_DIR */ 02301 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 02302 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ 02303 if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 02304 fmt = FS_FAT12; 02305 if (nclst >= MIN_FAT16) fmt = FS_FAT16; 02306 if (nclst >= MIN_FAT32) fmt = FS_FAT32; 02307 02308 /* Boundaries and Limits */ 02309 fs->n_fatent = nclst + 2; /* Number of FAT entries */ 02310 fs->volbase = bsect; /* Volume start sector */ 02311 fs->fatbase = bsect + nrsv; /* FAT start sector */ 02312 fs->database = bsect + sysect; /* Data start sector */ 02313 if (fmt == FS_FAT32) { 02314 if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ 02315 fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ 02316 szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ 02317 } else { 02318 if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ 02319 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ 02320 szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ 02321 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); 02322 } 02323 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ 02324 return FR_NO_FILESYSTEM; 02325 02326 #if !_FS_READONLY 02327 /* Initialize cluster allocation information */ 02328 fs->last_clust = fs->free_clust = 0xFFFFFFFF; 02329 02330 /* Get fsinfo if available */ 02331 fs->fsi_flag = 0x80; 02332 #if (_FS_NOFSINFO & 3) != 3 02333 if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */ 02334 && LD_WORD(fs->win + BPB_FSInfo) == 1 02335 && move_window(fs, bsect + 1) == FR_OK) 02336 { 02337 fs->fsi_flag = 0; 02338 if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ 02339 && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 02340 && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) 02341 { 02342 #if (_FS_NOFSINFO & 1) == 0 02343 fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); 02344 #endif 02345 #if (_FS_NOFSINFO & 2) == 0 02346 fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); 02347 #endif 02348 } 02349 } 02350 #endif 02351 #endif 02352 fs->fs_type = fmt; /* FAT sub-type */ 02353 fs->id = ++Fsid; /* File system mount ID */ 02354 #if _FS_RPATH 02355 fs->cdir = 0; /* Set current directory to root */ 02356 #endif 02357 #if _FS_LOCK /* Clear file lock semaphores */ 02358 clear_lock(fs); 02359 #endif 02360 02361 return FR_OK; 02362 } 02363 02364 02365 02366 02367 /*-----------------------------------------------------------------------*/ 02368 /* Check if the file/directory object is valid or not */ 02369 /*-----------------------------------------------------------------------*/ 02370 02371 static 02372 FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ 02373 void* obj /* Pointer to the object FIL/FATFS_DIR to check validity */ 02374 ) 02375 { 02376 FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/FATFS_DIR structure is identical */ 02377 02378 02379 if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT)) 02380 return FR_INVALID_OBJECT; 02381 02382 ENTER_FF(fil->fs); /* Lock file system */ 02383 02384 return FR_OK; 02385 } 02386 02387 02388 02389 02390 /*-------------------------------------------------------------------------- 02391 02392 Public Functions 02393 02394 ---------------------------------------------------------------------------*/ 02395 02396 02397 02398 /*-----------------------------------------------------------------------*/ 02399 /* Mount/Unmount a Logical Drive */ 02400 /*-----------------------------------------------------------------------*/ 02401 02402 FRESULT f_mount ( 02403 FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ 02404 const TCHAR* path, /* Logical drive number to be mounted/unmounted */ 02405 BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ 02406 ) 02407 { 02408 FATFS *cfs; 02409 int vol; 02410 FRESULT res; 02411 const TCHAR *rp = path; 02412 02413 02414 vol = get_ldnumber(&rp); 02415 if (vol < 0) return FR_INVALID_DRIVE; 02416 cfs = FatFs[vol]; /* Pointer to fs object */ 02417 02418 if (cfs) { 02419 #if _FS_LOCK 02420 clear_lock(cfs); 02421 #endif 02422 #if _FS_REENTRANT /* Discard sync object of the current volume */ 02423 if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; 02424 #endif 02425 cfs->fs_type = 0; /* Clear old fs object */ 02426 } 02427 02428 if (fs) { 02429 fs->fs_type = 0; /* Clear new fs object */ 02430 #if _FS_REENTRANT /* Create sync object for the new volume */ 02431 if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; 02432 #endif 02433 } 02434 FatFs[vol] = fs; /* Register new fs object */ 02435 02436 if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ 02437 02438 res = find_volume(&fs, &path, 0); /* Force mounted the volume */ 02439 LEAVE_FF(fs, res); 02440 } 02441 02442 02443 02444 02445 /*-----------------------------------------------------------------------*/ 02446 /* Open or Create a File */ 02447 /*-----------------------------------------------------------------------*/ 02448 02449 FRESULT f_open ( 02450 FIL* fp, /* Pointer to the blank file object */ 02451 const TCHAR* path, /* Pointer to the file name */ 02452 BYTE mode /* Access mode and file open mode flags */ 02453 ) 02454 { 02455 FRESULT res; 02456 FATFS_DIR dj; 02457 BYTE *dir; 02458 DEFINE_NAMEBUF; 02459 #if !_FS_READONLY 02460 DWORD dw, cl; 02461 #endif 02462 02463 02464 if (!fp) return FR_INVALID_OBJECT; 02465 fp->fs = 0; /* Clear file object */ 02466 02467 /* Get logical drive number */ 02468 #if !_FS_READONLY 02469 mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; 02470 res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); 02471 #else 02472 mode &= FA_READ; 02473 res = find_volume(&dj.fs, &path, 0); 02474 #endif 02475 if (res == FR_OK) { 02476 INIT_BUF(dj); 02477 res = follow_path(&dj, path); /* Follow the file path */ 02478 dir = dj.dir; 02479 #if !_FS_READONLY /* R/W configuration */ 02480 if (res == FR_OK) { 02481 if (!dir) /* Default directory itself */ 02482 res = FR_INVALID_NAME; 02483 #if _FS_LOCK 02484 else 02485 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); 02486 #endif 02487 } 02488 /* Create or Open a file */ 02489 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { 02490 if (res != FR_OK) { /* No file, create new */ 02491 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ 02492 #if _FS_LOCK 02493 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; 02494 #else 02495 res = dir_register(&dj); 02496 #endif 02497 mode |= FA_CREATE_ALWAYS; /* File is created */ 02498 dir = dj.dir; /* New entry */ 02499 } 02500 else { /* Any object is already existing */ 02501 if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or FATFS_DIR) */ 02502 res = FR_DENIED; 02503 } else { 02504 if (mode & FA_CREATE_NEW) /* Cannot create as new file */ 02505 res = FR_EXIST; 02506 } 02507 } 02508 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ 02509 dw = GET_FATTIME(); 02510 ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */ 02511 ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */ 02512 dir[DIR_Attr] = 0; /* Reset attribute */ 02513 ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */ 02514 cl = ld_clust(dj.fs, dir); /* Get cluster chain */ 02515 st_clust(dir, 0); /* Reset cluster */ 02516 dj.fs->wflag = 1; 02517 if (cl) { /* Remove the cluster chain if exist */ 02518 dw = dj.fs->winsect; 02519 res = remove_chain(dj.fs, cl); 02520 if (res == FR_OK) { 02521 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ 02522 res = move_window(dj.fs, dw); 02523 } 02524 } 02525 } 02526 } 02527 else { /* Open an existing file */ 02528 if (res == FR_OK) { /* Following succeeded */ 02529 if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ 02530 res = FR_NO_FILE; 02531 } else { 02532 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ 02533 res = FR_DENIED; 02534 } 02535 } 02536 } 02537 if (res == FR_OK) { 02538 if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ 02539 mode |= FA__WRITTEN; 02540 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ 02541 fp->dir_ptr = dir; 02542 #if _FS_LOCK 02543 fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); 02544 if (!fp->lockid) res = FR_INT_ERR; 02545 #endif 02546 } 02547 02548 #else /* R/O configuration */ 02549 if (res == FR_OK) { /* Follow succeeded */ 02550 dir = dj.dir; 02551 if (!dir) { /* Current directory itself */ 02552 res = FR_INVALID_NAME; 02553 } else { 02554 if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ 02555 res = FR_NO_FILE; 02556 } 02557 } 02558 #endif 02559 FREE_BUF(); 02560 02561 if (res == FR_OK) { 02562 fp->flag = mode; /* File access mode */ 02563 fp->err = 0; /* Clear error flag */ 02564 fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ 02565 fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ 02566 fp->fptr = 0; /* File pointer */ 02567 fp->dsect = 0; 02568 #if _USE_FASTSEEK 02569 fp->cltbl = 0; /* Normal seek mode */ 02570 #endif 02571 fp->fs = dj.fs; /* Validate file object */ 02572 fp->id = fp->fs->id; 02573 } 02574 } 02575 02576 LEAVE_FF(dj.fs, res); 02577 } 02578 02579 02580 02581 02582 /*-----------------------------------------------------------------------*/ 02583 /* Read File */ 02584 /*-----------------------------------------------------------------------*/ 02585 02586 FRESULT f_read ( 02587 FIL* fp, /* Pointer to the file object */ 02588 void* buff, /* Pointer to data buffer */ 02589 UINT btr, /* Number of bytes to read */ 02590 UINT* br /* Pointer to number of bytes read */ 02591 ) 02592 { 02593 FRESULT res; 02594 DWORD clst, sect, remain; 02595 UINT rcnt, cc; 02596 BYTE csect, *rbuff = (BYTE*)buff; 02597 02598 02599 *br = 0; /* Clear read byte counter */ 02600 02601 res = validate(fp); /* Check validity */ 02602 if (res != FR_OK) LEAVE_FF(fp->fs, res); 02603 if (fp->err) /* Check error */ 02604 LEAVE_FF(fp->fs, (FRESULT)fp->err); 02605 if (!(fp->flag & FA_READ)) /* Check access mode */ 02606 LEAVE_FF(fp->fs, FR_DENIED); 02607 remain = fp->fsize - fp->fptr; 02608 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ 02609 02610 for ( ; btr; /* Repeat until all data read */ 02611 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { 02612 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ 02613 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ 02614 if (!csect) { /* On the cluster boundary? */ 02615 if (fp->fptr == 0) { /* On the top of the file? */ 02616 clst = fp->sclust; /* Follow from the origin */ 02617 } else { /* Middle or end of the file */ 02618 #if _USE_FASTSEEK 02619 if (fp->cltbl) 02620 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 02621 else 02622 #endif 02623 clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ 02624 } 02625 if (clst < 2) ABORT(fp->fs, FR_INT_ERR); 02626 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 02627 fp->clust = clst; /* Update current cluster */ 02628 } 02629 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ 02630 if (!sect) ABORT(fp->fs, FR_INT_ERR); 02631 sect += csect; 02632 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ 02633 if (cc) { /* Read maximum contiguous sectors directly */ 02634 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ 02635 cc = fp->fs->csize - csect; 02636 if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) 02637 ABORT(fp->fs, FR_DISK_ERR); 02638 #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ 02639 #if _FS_TINY 02640 if (fp->fs->wflag && fp->fs->winsect - sect < cc) 02641 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); 02642 #else 02643 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) 02644 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); 02645 #endif 02646 #endif 02647 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ 02648 continue; 02649 } 02650 #if !_FS_TINY 02651 if (fp->dsect != sect) { /* Load data sector if not in cache */ 02652 #if !_FS_READONLY 02653 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ 02654 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 02655 ABORT(fp->fs, FR_DISK_ERR); 02656 fp->flag &= ~FA__DIRTY; 02657 } 02658 #endif 02659 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ 02660 ABORT(fp->fs, FR_DISK_ERR); 02661 } 02662 #endif 02663 fp->dsect = sect; 02664 } 02665 rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ 02666 if (rcnt > btr) rcnt = btr; 02667 #if _FS_TINY 02668 if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ 02669 ABORT(fp->fs, FR_DISK_ERR); 02670 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ 02671 #else 02672 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ 02673 #endif 02674 } 02675 02676 LEAVE_FF(fp->fs, FR_OK); 02677 } 02678 02679 02680 02681 02682 #if !_FS_READONLY 02683 /*-----------------------------------------------------------------------*/ 02684 /* Write File */ 02685 /*-----------------------------------------------------------------------*/ 02686 02687 FRESULT f_write ( 02688 FIL* fp, /* Pointer to the file object */ 02689 const void *buff, /* Pointer to the data to be written */ 02690 UINT btw, /* Number of bytes to write */ 02691 UINT* bw /* Pointer to number of bytes written */ 02692 ) 02693 { 02694 FRESULT res; 02695 DWORD clst, sect; 02696 UINT wcnt, cc; 02697 const BYTE *wbuff = (const BYTE*)buff; 02698 BYTE csect; 02699 bool need_sync = false; 02700 02701 *bw = 0; /* Clear write byte counter */ 02702 02703 res = validate(fp); /* Check validity */ 02704 if (res != FR_OK) LEAVE_FF(fp->fs, res); 02705 if (fp->err) /* Check error */ 02706 LEAVE_FF(fp->fs, (FRESULT)fp->err); 02707 if (!(fp->flag & FA_WRITE)) /* Check access mode */ 02708 LEAVE_FF(fp->fs, FR_DENIED); 02709 if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ 02710 02711 for ( ; btw; /* Repeat until all data written */ 02712 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { 02713 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ 02714 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ 02715 if (!csect) { /* On the cluster boundary? */ 02716 if (fp->fptr == 0) { /* On the top of the file? */ 02717 clst = fp->sclust; /* Follow from the origin */ 02718 if (clst == 0) /* When no cluster is allocated, */ 02719 clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ 02720 } else { /* Middle or end of the file */ 02721 #if _USE_FASTSEEK 02722 if (fp->cltbl) 02723 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 02724 else 02725 #endif 02726 clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ 02727 } 02728 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ 02729 if (clst == 1) ABORT(fp->fs, FR_INT_ERR); 02730 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 02731 fp->clust = clst; /* Update current cluster */ 02732 if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ 02733 02734 #if FLUSH_ON_NEW_CLUSTER 02735 // We do not need to flush for the first cluster 02736 if (fp->fptr != 0) { 02737 need_sync = true; 02738 } 02739 #endif 02740 } 02741 #if _FS_TINY 02742 if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ 02743 ABORT(fp->fs, FR_DISK_ERR); 02744 #else 02745 if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ 02746 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 02747 ABORT(fp->fs, FR_DISK_ERR); 02748 fp->flag &= ~FA__DIRTY; 02749 } 02750 #endif 02751 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ 02752 if (!sect) ABORT(fp->fs, FR_INT_ERR); 02753 sect += csect; 02754 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ 02755 if (cc) { /* Write maximum contiguous sectors directly */ 02756 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ 02757 cc = fp->fs->csize - csect; 02758 if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) 02759 ABORT(fp->fs, FR_DISK_ERR); 02760 #if _FS_MINIMIZE <= 2 02761 #if _FS_TINY 02762 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 02763 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); 02764 fp->fs->wflag = 0; 02765 } 02766 #else 02767 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 02768 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); 02769 fp->flag &= ~FA__DIRTY; 02770 } 02771 #endif 02772 #endif 02773 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ 02774 #if FLUSH_ON_NEW_SECTOR 02775 need_sync = true; 02776 #endif 02777 continue; 02778 } 02779 #if _FS_TINY 02780 if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ 02781 if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); 02782 fp->fs->winsect = sect; 02783 } 02784 #else 02785 if (fp->dsect != sect) { /* Fill sector cache with file data */ 02786 if (fp->fptr < fp->fsize && 02787 disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) 02788 ABORT(fp->fs, FR_DISK_ERR); 02789 } 02790 #endif 02791 fp->dsect = sect; 02792 } 02793 wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ 02794 if (wcnt > btw) wcnt = btw; 02795 #if _FS_TINY 02796 if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ 02797 ABORT(fp->fs, FR_DISK_ERR); 02798 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ 02799 fp->fs->wflag = 1; 02800 #else 02801 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ 02802 fp->flag |= FA__DIRTY; 02803 #endif 02804 } 02805 02806 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ 02807 fp->flag |= FA__WRITTEN; /* Set file change flag */ 02808 02809 if (need_sync) { 02810 f_sync (fp); 02811 } 02812 02813 LEAVE_FF(fp->fs, FR_OK); 02814 } 02815 02816 02817 02818 02819 /*-----------------------------------------------------------------------*/ 02820 /* Synchronize the File */ 02821 /*-----------------------------------------------------------------------*/ 02822 02823 FRESULT f_sync ( 02824 FIL* fp /* Pointer to the file object */ 02825 ) 02826 { 02827 FRESULT res; 02828 DWORD tm; 02829 BYTE *dir; 02830 02831 02832 res = validate(fp); /* Check validity of the object */ 02833 if (res == FR_OK) { 02834 if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */ 02835 #if !_FS_TINY 02836 if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */ 02837 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 02838 LEAVE_FF(fp->fs, FR_DISK_ERR); 02839 fp->flag &= ~FA__DIRTY; 02840 } 02841 #endif 02842 /* Update the directory entry */ 02843 res = move_window(fp->fs, fp->dir_sect); 02844 if (res == FR_OK) { 02845 dir = fp->dir_ptr; 02846 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ 02847 ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ 02848 st_clust(dir, fp->sclust); /* Update start cluster */ 02849 tm = GET_FATTIME(); /* Update modified time */ 02850 ST_DWORD(dir + DIR_WrtTime, tm); 02851 ST_WORD(dir + DIR_LstAccDate, 0); 02852 fp->flag &= ~FA__WRITTEN; 02853 fp->fs->wflag = 1; 02854 res = sync_fs(fp->fs); 02855 } 02856 } 02857 } 02858 02859 LEAVE_FF(fp->fs, res); 02860 } 02861 02862 #endif /* !_FS_READONLY */ 02863 02864 02865 02866 02867 /*-----------------------------------------------------------------------*/ 02868 /* Close File */ 02869 /*-----------------------------------------------------------------------*/ 02870 02871 FRESULT f_close ( 02872 FIL *fp /* Pointer to the file object to be closed */ 02873 ) 02874 { 02875 FRESULT res; 02876 02877 02878 #if !_FS_READONLY 02879 res = f_sync(fp); /* Flush cached data */ 02880 if (res == FR_OK) 02881 #endif 02882 { 02883 res = validate(fp); /* Lock volume */ 02884 if (res == FR_OK) { 02885 #if _FS_REENTRANT 02886 FATFS *fs = fp->fs; 02887 #endif 02888 #if _FS_LOCK 02889 res = dec_lock(fp->lockid); /* Decrement file open counter */ 02890 if (res == FR_OK) 02891 #endif 02892 fp->fs = 0; /* Invalidate file object */ 02893 #if _FS_REENTRANT 02894 unlock_fs(fs, FR_OK); /* Unlock volume */ 02895 #endif 02896 } 02897 } 02898 return res; 02899 } 02900 02901 02902 02903 02904 /*-----------------------------------------------------------------------*/ 02905 /* Change Current Directory or Current Drive, Get Current Directory */ 02906 /*-----------------------------------------------------------------------*/ 02907 02908 #if _FS_RPATH >= 1 02909 #if _VOLUMES >= 2 02910 FRESULT f_chdrive ( 02911 const TCHAR* path /* Drive number */ 02912 ) 02913 { 02914 int vol; 02915 02916 02917 vol = get_ldnumber(&path); 02918 if (vol < 0) return FR_INVALID_DRIVE; 02919 02920 CurrVol = (BYTE)vol; 02921 02922 return FR_OK; 02923 } 02924 #endif 02925 02926 02927 FRESULT f_chdir ( 02928 const TCHAR* path /* Pointer to the directory path */ 02929 ) 02930 { 02931 FRESULT res; 02932 FATFS_DIR dj; 02933 DEFINE_NAMEBUF; 02934 02935 02936 /* Get logical drive number */ 02937 res = find_volume(&dj.fs, &path, 0); 02938 if (res == FR_OK) { 02939 INIT_BUF(dj); 02940 res = follow_path(&dj, path); /* Follow the path */ 02941 FREE_BUF(); 02942 if (res == FR_OK) { /* Follow completed */ 02943 if (!dj.dir) { 02944 dj.fs->cdir = dj.sclust; /* Start directory itself */ 02945 } else { 02946 if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ 02947 dj.fs->cdir = ld_clust(dj.fs, dj.dir); 02948 else 02949 res = FR_NO_PATH; /* Reached but a file */ 02950 } 02951 } 02952 if (res == FR_NO_FILE) res = FR_NO_PATH; 02953 } 02954 02955 LEAVE_FF(dj.fs, res); 02956 } 02957 02958 02959 #if _FS_RPATH >= 2 02960 FRESULT f_getcwd ( 02961 TCHAR* buff, /* Pointer to the directory path */ 02962 UINT len /* Size of path */ 02963 ) 02964 { 02965 FRESULT res; 02966 FATFS_DIR dj; 02967 UINT i, n; 02968 DWORD ccl; 02969 TCHAR *tp; 02970 FILINFO fno; 02971 DEFINE_NAMEBUF; 02972 02973 02974 *buff = 0; 02975 /* Get logical drive number */ 02976 res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ 02977 if (res == FR_OK) { 02978 INIT_BUF(dj); 02979 i = len; /* Bottom of buffer (directory stack base) */ 02980 dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ 02981 while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ 02982 res = dir_sdi(&dj, 1); /* Get parent directory */ 02983 if (res != FR_OK) break; 02984 res = dir_read(&dj, 0); 02985 if (res != FR_OK) break; 02986 dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ 02987 res = dir_sdi(&dj, 0); 02988 if (res != FR_OK) break; 02989 do { /* Find the entry links to the child directory */ 02990 res = dir_read(&dj, 0); 02991 if (res != FR_OK) break; 02992 if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ 02993 res = dir_next(&dj, 0); 02994 } while (res == FR_OK); 02995 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ 02996 if (res != FR_OK) break; 02997 #if _USE_LFN 02998 fno.lfname = buff; 02999 fno.lfsize = i; 03000 #endif 03001 get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ 03002 tp = fno.fname; 03003 #if _USE_LFN 03004 if (*buff) tp = buff; 03005 #endif 03006 for (n = 0; tp[n]; n++) ; 03007 if (i < n + 3) { 03008 res = FR_NOT_ENOUGH_CORE; break; 03009 } 03010 while (n) buff[--i] = tp[--n]; 03011 buff[--i] = '/'; 03012 } 03013 tp = buff; 03014 if (res == FR_OK) { 03015 #if _VOLUMES >= 2 03016 *tp++ = '0' + CurrVol; /* Put drive number */ 03017 *tp++ = ':'; 03018 #endif 03019 if (i == len) { /* Root-directory */ 03020 *tp++ = '/'; 03021 } else { /* Sub-directroy */ 03022 do /* Add stacked path str */ 03023 *tp++ = buff[i++]; 03024 while (i < len); 03025 } 03026 } 03027 *tp = 0; 03028 FREE_BUF(); 03029 } 03030 03031 LEAVE_FF(dj.fs, res); 03032 } 03033 #endif /* _FS_RPATH >= 2 */ 03034 #endif /* _FS_RPATH >= 1 */ 03035 03036 03037 03038 #if _FS_MINIMIZE <= 2 03039 /*-----------------------------------------------------------------------*/ 03040 /* Seek File R/W Pointer */ 03041 /*-----------------------------------------------------------------------*/ 03042 03043 FRESULT f_lseek ( 03044 FIL* fp, /* Pointer to the file object */ 03045 DWORD ofs /* File pointer from top of file */ 03046 ) 03047 { 03048 FRESULT res; 03049 DWORD clst, bcs, nsect, ifptr; 03050 #if _USE_FASTSEEK 03051 DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; 03052 #endif 03053 03054 03055 res = validate(fp); /* Check validity of the object */ 03056 if (res != FR_OK) LEAVE_FF(fp->fs, res); 03057 if (fp->err) /* Check error */ 03058 LEAVE_FF(fp->fs, (FRESULT)fp->err); 03059 03060 #if _USE_FASTSEEK 03061 if (fp->cltbl) { /* Fast seek */ 03062 if (ofs == CREATE_LINKMAP) { /* Create CLMT */ 03063 tbl = fp->cltbl; 03064 tlen = *tbl++; ulen = 2; /* Given table size and required table size */ 03065 cl = fp->sclust; /* Top of the chain */ 03066 if (cl) { 03067 do { 03068 /* Get a fragment */ 03069 tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ 03070 do { 03071 pcl = cl; ncl++; 03072 cl = get_fat(fp->fs, cl); 03073 if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); 03074 if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 03075 } while (cl == pcl + 1); 03076 if (ulen <= tlen) { /* Store the length and top of the fragment */ 03077 *tbl++ = ncl; *tbl++ = tcl; 03078 } 03079 } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ 03080 } 03081 *fp->cltbl = ulen; /* Number of items used */ 03082 if (ulen <= tlen) 03083 *tbl = 0; /* Terminate table */ 03084 else 03085 res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ 03086 03087 } else { /* Fast seek */ 03088 if (ofs > fp->fsize) /* Clip offset at the file size */ 03089 ofs = fp->fsize; 03090 fp->fptr = ofs; /* Set file pointer */ 03091 if (ofs) { 03092 fp->clust = clmt_clust(fp, ofs - 1); 03093 dsc = clust2sect(fp->fs, fp->clust); 03094 if (!dsc) ABORT(fp->fs, FR_INT_ERR); 03095 dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); 03096 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ 03097 #if !_FS_TINY 03098 #if !_FS_READONLY 03099 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ 03100 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 03101 ABORT(fp->fs, FR_DISK_ERR); 03102 fp->flag &= ~FA__DIRTY; 03103 } 03104 #endif 03105 if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ 03106 ABORT(fp->fs, FR_DISK_ERR); 03107 #endif 03108 fp->dsect = dsc; 03109 } 03110 } 03111 } 03112 } else 03113 #endif 03114 03115 /* Normal Seek */ 03116 { 03117 if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ 03118 #if !_FS_READONLY 03119 && !(fp->flag & FA_WRITE) 03120 #endif 03121 ) ofs = fp->fsize; 03122 03123 ifptr = fp->fptr; 03124 fp->fptr = nsect = 0; 03125 if (ofs) { 03126 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ 03127 if (ifptr > 0 && 03128 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ 03129 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ 03130 ofs -= fp->fptr; 03131 clst = fp->clust; 03132 } else { /* When seek to back cluster, */ 03133 clst = fp->sclust; /* start from the first cluster */ 03134 #if !_FS_READONLY 03135 if (clst == 0) { /* If no cluster chain, create a new chain */ 03136 clst = create_chain(fp->fs, 0); 03137 if (clst == 1) ABORT(fp->fs, FR_INT_ERR); 03138 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 03139 fp->sclust = clst; 03140 } 03141 #endif 03142 fp->clust = clst; 03143 } 03144 if (clst != 0) { 03145 while (ofs > bcs) { /* Cluster following loop */ 03146 #if !_FS_READONLY 03147 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ 03148 clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ 03149 if (clst == 0) { /* When disk gets full, clip file size */ 03150 ofs = bcs; break; 03151 } 03152 } else 03153 #endif 03154 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ 03155 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 03156 if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); 03157 fp->clust = clst; 03158 fp->fptr += bcs; 03159 ofs -= bcs; 03160 } 03161 fp->fptr += ofs; 03162 if (ofs % SS(fp->fs)) { 03163 nsect = clust2sect(fp->fs, clst); /* Current sector */ 03164 if (!nsect) ABORT(fp->fs, FR_INT_ERR); 03165 nsect += ofs / SS(fp->fs); 03166 } 03167 } 03168 } 03169 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ 03170 #if !_FS_TINY 03171 #if !_FS_READONLY 03172 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ 03173 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 03174 ABORT(fp->fs, FR_DISK_ERR); 03175 fp->flag &= ~FA__DIRTY; 03176 } 03177 #endif 03178 if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ 03179 ABORT(fp->fs, FR_DISK_ERR); 03180 #endif 03181 fp->dsect = nsect; 03182 } 03183 #if !_FS_READONLY 03184 if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ 03185 fp->fsize = fp->fptr; 03186 fp->flag |= FA__WRITTEN; 03187 } 03188 #endif 03189 } 03190 03191 LEAVE_FF(fp->fs, res); 03192 } 03193 03194 03195 03196 #if _FS_MINIMIZE <= 1 03197 /*-----------------------------------------------------------------------*/ 03198 /* Create a Directory Object */ 03199 /*-----------------------------------------------------------------------*/ 03200 03201 FRESULT f_opendir ( 03202 FATFS_DIR* dp, /* Pointer to directory object to create */ 03203 const TCHAR* path /* Pointer to the directory path */ 03204 ) 03205 { 03206 FRESULT res; 03207 FATFS* fs; 03208 DEFINE_NAMEBUF; 03209 03210 03211 if (!dp) return FR_INVALID_OBJECT; 03212 03213 /* Get logical drive number */ 03214 res = find_volume(&fs, &path, 0); 03215 if (res == FR_OK) { 03216 dp->fs = fs; 03217 INIT_BUF(*dp); 03218 res = follow_path(dp, path); /* Follow the path to the directory */ 03219 FREE_BUF(); 03220 if (res == FR_OK) { /* Follow completed */ 03221 if (dp->dir) { /* It is not the origin directory itself */ 03222 if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ 03223 dp->sclust = ld_clust(fs, dp->dir); 03224 else /* The object is a file */ 03225 res = FR_NO_PATH; 03226 } 03227 if (res == FR_OK) { 03228 dp->id = fs->id; 03229 res = dir_sdi(dp, 0); /* Rewind directory */ 03230 #if _FS_LOCK 03231 if (res == FR_OK) { 03232 if (dp->sclust) { 03233 dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ 03234 if (!dp->lockid) 03235 res = FR_TOO_MANY_OPEN_FILES; 03236 } else { 03237 dp->lockid = 0; /* Root directory need not to be locked */ 03238 } 03239 } 03240 #endif 03241 } 03242 } 03243 if (res == FR_NO_FILE) res = FR_NO_PATH; 03244 } 03245 if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ 03246 03247 LEAVE_FF(fs, res); 03248 } 03249 03250 03251 03252 03253 /*-----------------------------------------------------------------------*/ 03254 /* Close Directory */ 03255 /*-----------------------------------------------------------------------*/ 03256 03257 FRESULT f_closedir ( 03258 FATFS_DIR *dp /* Pointer to the directory object to be closed */ 03259 ) 03260 { 03261 FRESULT res; 03262 03263 03264 res = validate(dp); 03265 if (res == FR_OK) { 03266 #if _FS_REENTRANT 03267 FATFS *fs = dp->fs; 03268 #endif 03269 #if _FS_LOCK 03270 if (dp->lockid) /* Decrement sub-directory open counter */ 03271 res = dec_lock(dp->lockid); 03272 if (res == FR_OK) 03273 #endif 03274 dp->fs = 0; /* Invalidate directory object */ 03275 #if _FS_REENTRANT 03276 unlock_fs(fs, FR_OK); /* Unlock volume */ 03277 #endif 03278 } 03279 return res; 03280 } 03281 03282 03283 03284 03285 /*-----------------------------------------------------------------------*/ 03286 /* Read Directory Entries in Sequence */ 03287 /*-----------------------------------------------------------------------*/ 03288 03289 FRESULT f_readdir ( 03290 FATFS_DIR* dp, /* Pointer to the open directory object */ 03291 FILINFO* fno /* Pointer to file information to return */ 03292 ) 03293 { 03294 FRESULT res; 03295 DEFINE_NAMEBUF; 03296 03297 03298 res = validate(dp); /* Check validity of the object */ 03299 if (res == FR_OK) { 03300 if (!fno) { 03301 res = dir_sdi(dp, 0); /* Rewind the directory object */ 03302 } else { 03303 INIT_BUF(*dp); 03304 res = dir_read(dp, 0); /* Read an item */ 03305 if (res == FR_NO_FILE) { /* Reached end of directory */ 03306 dp->sect = 0; 03307 res = FR_OK; 03308 } 03309 if (res == FR_OK) { /* A valid entry is found */ 03310 get_fileinfo(dp, fno); /* Get the object information */ 03311 res = dir_next(dp, 0); /* Increment index for next */ 03312 if (res == FR_NO_FILE) { 03313 dp->sect = 0; 03314 res = FR_OK; 03315 } 03316 } 03317 FREE_BUF(); 03318 } 03319 } 03320 03321 LEAVE_FF(dp->fs, res); 03322 } 03323 03324 03325 03326 #if _USE_FIND 03327 /*-----------------------------------------------------------------------*/ 03328 /* Find next file */ 03329 /*-----------------------------------------------------------------------*/ 03330 03331 FRESULT f_findnext ( 03332 FATFS_DIR* dp, /* Pointer to the open directory object */ 03333 FILINFO* fno /* Pointer to the file information structure */ 03334 ) 03335 { 03336 FRESULT res; 03337 03338 03339 for (;;) { 03340 res = f_readdir(dp, fno); /* Get a directory item */ 03341 if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ 03342 #if _USE_LFN 03343 if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */ 03344 #endif 03345 if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */ 03346 } 03347 return res; 03348 03349 } 03350 03351 03352 03353 /*-----------------------------------------------------------------------*/ 03354 /* Find first file */ 03355 /*-----------------------------------------------------------------------*/ 03356 03357 FRESULT f_findfirst ( 03358 FATFS_DIR* dp, /* Pointer to the blank directory object */ 03359 FILINFO* fno, /* Pointer to the file information structure */ 03360 const TCHAR* path, /* Pointer to the directory to open */ 03361 const TCHAR* pattern /* Pointer to the matching pattern */ 03362 ) 03363 { 03364 FRESULT res; 03365 03366 03367 dp->pat = pattern; /* Save pointer to pattern string */ 03368 res = f_opendir(dp, path); /* Open the target directory */ 03369 if (res == FR_OK) 03370 res = f_findnext(dp, fno); /* Find the first item */ 03371 return res; 03372 } 03373 03374 #endif /* _USE_FIND */ 03375 03376 03377 03378 #if _FS_MINIMIZE == 0 03379 /*-----------------------------------------------------------------------*/ 03380 /* Get File Status */ 03381 /*-----------------------------------------------------------------------*/ 03382 03383 FRESULT f_stat ( 03384 const TCHAR* path, /* Pointer to the file path */ 03385 FILINFO* fno /* Pointer to file information to return */ 03386 ) 03387 { 03388 FRESULT res; 03389 FATFS_DIR dj; 03390 DEFINE_NAMEBUF; 03391 03392 03393 /* Get logical drive number */ 03394 res = find_volume(&dj.fs, &path, 0); 03395 if (res == FR_OK) { 03396 INIT_BUF(dj); 03397 res = follow_path(&dj, path); /* Follow the file path */ 03398 if (res == FR_OK) { /* Follow completed */ 03399 if (dj.dir) { /* Found an object */ 03400 if (fno) get_fileinfo(&dj, fno); 03401 } else { /* It is root directory */ 03402 res = FR_INVALID_NAME; 03403 } 03404 } 03405 FREE_BUF(); 03406 } 03407 03408 LEAVE_FF(dj.fs, res); 03409 } 03410 03411 03412 03413 #if !_FS_READONLY 03414 /*-----------------------------------------------------------------------*/ 03415 /* Get Number of Free Clusters */ 03416 /*-----------------------------------------------------------------------*/ 03417 03418 FRESULT f_getfree ( 03419 const TCHAR* path, /* Path name of the logical drive number */ 03420 DWORD* nclst, /* Pointer to a variable to return number of free clusters */ 03421 FATFS** fatfs /* Pointer to return pointer to corresponding file system object */ 03422 ) 03423 { 03424 FRESULT res; 03425 FATFS *fs; 03426 DWORD nfree, clst, sect, stat; 03427 UINT i; 03428 BYTE fat, *p; 03429 03430 03431 /* Get logical drive number */ 03432 res = find_volume(fatfs, &path, 0); 03433 fs = *fatfs; 03434 if (res == FR_OK) { 03435 /* If free_clust is valid, return it without full cluster scan */ 03436 if (fs->free_clust <= fs->n_fatent - 2) { 03437 *nclst = fs->free_clust; 03438 } else { 03439 /* Get number of free clusters */ 03440 fat = fs->fs_type; 03441 nfree = 0; 03442 if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */ 03443 clst = 2; 03444 do { 03445 stat = get_fat(fs, clst); 03446 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } 03447 if (stat == 1) { res = FR_INT_ERR; break; } 03448 if (stat == 0) nfree++; 03449 } while (++clst < fs->n_fatent); 03450 } else { /* Sector alighed entries: Accelerate the FAT search. */ 03451 clst = fs->n_fatent; sect = fs->fatbase; 03452 i = 0; p = 0; 03453 do { 03454 if (!i) { 03455 res = move_window(fs, sect++); 03456 if (res != FR_OK) break; 03457 p = fs->win; 03458 i = SS(fs); 03459 } 03460 if (fat == FS_FAT16) { 03461 if (LD_WORD(p) == 0) nfree++; 03462 p += 2; i -= 2; 03463 } else { 03464 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++; 03465 p += 4; i -= 4; 03466 } 03467 } while (--clst); 03468 } 03469 fs->free_clust = nfree; /* free_clust is valid */ 03470 fs->fsi_flag |= 1; /* FSInfo is to be updated */ 03471 *nclst = nfree; /* Return the free clusters */ 03472 } 03473 } 03474 LEAVE_FF(fs, res); 03475 } 03476 03477 03478 03479 03480 /*-----------------------------------------------------------------------*/ 03481 /* Truncate File */ 03482 /*-----------------------------------------------------------------------*/ 03483 03484 FRESULT f_truncate ( 03485 FIL* fp /* Pointer to the file object */ 03486 ) 03487 { 03488 FRESULT res; 03489 DWORD ncl; 03490 03491 03492 res = validate(fp); /* Check validity of the object */ 03493 if (res == FR_OK) { 03494 if (fp->err) { /* Check error */ 03495 res = (FRESULT)fp->err; 03496 } else { 03497 if (!(fp->flag & FA_WRITE)) /* Check access mode */ 03498 res = FR_DENIED; 03499 } 03500 } 03501 if (res == FR_OK) { 03502 if (fp->fsize > fp->fptr) { 03503 fp->fsize = fp->fptr; /* Set file size to current R/W point */ 03504 fp->flag |= FA__WRITTEN; 03505 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ 03506 res = remove_chain(fp->fs, fp->sclust); 03507 fp->sclust = 0; 03508 } else { /* When truncate a part of the file, remove remaining clusters */ 03509 ncl = get_fat(fp->fs, fp->clust); 03510 res = FR_OK; 03511 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; 03512 if (ncl == 1) res = FR_INT_ERR; 03513 if (res == FR_OK && ncl < fp->fs->n_fatent) { 03514 res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); 03515 if (res == FR_OK) res = remove_chain(fp->fs, ncl); 03516 } 03517 } 03518 #if !_FS_TINY 03519 if (res == FR_OK && (fp->flag & FA__DIRTY)) { 03520 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 03521 res = FR_DISK_ERR; 03522 else 03523 fp->flag &= ~FA__DIRTY; 03524 } 03525 #endif 03526 } 03527 if (res != FR_OK) fp->err = (FRESULT)res; 03528 } 03529 03530 LEAVE_FF(fp->fs, res); 03531 } 03532 03533 03534 03535 03536 /*-----------------------------------------------------------------------*/ 03537 /* Delete a File or Directory */ 03538 /*-----------------------------------------------------------------------*/ 03539 03540 FRESULT f_unlink ( 03541 const TCHAR* path /* Pointer to the file or directory path */ 03542 ) 03543 { 03544 FRESULT res; 03545 FATFS_DIR dj, sdj; 03546 BYTE *dir; 03547 DWORD dclst = 0; 03548 DEFINE_NAMEBUF; 03549 03550 03551 /* Get logical drive number */ 03552 res = find_volume(&dj.fs, &path, 1); 03553 if (res == FR_OK) { 03554 INIT_BUF(dj); 03555 res = follow_path(&dj, path); /* Follow the file path */ 03556 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) 03557 res = FR_INVALID_NAME; /* Cannot remove dot entry */ 03558 #if _FS_LOCK 03559 if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */ 03560 #endif 03561 if (res == FR_OK) { /* The object is accessible */ 03562 dir = dj.dir; 03563 if (!dir) { 03564 res = FR_INVALID_NAME; /* Cannot remove the origin directory */ 03565 } else { 03566 if (dir[DIR_Attr] & AM_RDO) 03567 res = FR_DENIED; /* Cannot remove R/O object */ 03568 } 03569 if (res == FR_OK) { 03570 dclst = ld_clust(dj.fs, dir); 03571 if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ 03572 #if _FS_RPATH 03573 if (dclst == dj.fs->cdir) { /* Is it the current directory? */ 03574 res = FR_DENIED; 03575 } else 03576 #endif 03577 { 03578 mem_cpy(&sdj, &dj, sizeof (FATFS_DIR)); /* Open the sub-directory */ 03579 sdj.sclust = dclst; 03580 res = dir_sdi(&sdj, 2); 03581 if (res == FR_OK) { 03582 res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */ 03583 if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */ 03584 if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */ 03585 } 03586 } 03587 } 03588 } 03589 if (res == FR_OK) { 03590 res = dir_remove(&dj); /* Remove the directory entry */ 03591 if (res == FR_OK && dclst) /* Remove the cluster chain if exist */ 03592 res = remove_chain(dj.fs, dclst); 03593 if (res == FR_OK) res = sync_fs(dj.fs); 03594 } 03595 } 03596 FREE_BUF(); 03597 } 03598 03599 LEAVE_FF(dj.fs, res); 03600 } 03601 03602 03603 03604 03605 /*-----------------------------------------------------------------------*/ 03606 /* Create a Directory */ 03607 /*-----------------------------------------------------------------------*/ 03608 03609 FRESULT f_mkdir ( 03610 const TCHAR* path /* Pointer to the directory path */ 03611 ) 03612 { 03613 FRESULT res; 03614 FATFS_DIR dj; 03615 BYTE *dir, n; 03616 DWORD dsc, dcl, pcl, tm = GET_FATTIME(); 03617 DEFINE_NAMEBUF; 03618 03619 03620 /* Get logical drive number */ 03621 res = find_volume(&dj.fs, &path, 1); 03622 if (res == FR_OK) { 03623 INIT_BUF(dj); 03624 res = follow_path(&dj, path); /* Follow the file path */ 03625 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ 03626 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) 03627 res = FR_INVALID_NAME; 03628 if (res == FR_NO_FILE) { /* Can create a new directory */ 03629 dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ 03630 res = FR_OK; 03631 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ 03632 if (dcl == 1) res = FR_INT_ERR; 03633 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; 03634 if (res == FR_OK) /* Flush FAT */ 03635 res = sync_window(dj.fs); 03636 if (res == FR_OK) { /* Initialize the new directory table */ 03637 dsc = clust2sect(dj.fs, dcl); 03638 dir = dj.fs->win; 03639 mem_set(dir, 0, SS(dj.fs)); 03640 mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ 03641 dir[DIR_Name] = '.'; 03642 dir[DIR_Attr] = AM_DIR; 03643 ST_DWORD(dir + DIR_WrtTime, tm); 03644 st_clust(dir, dcl); 03645 mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ 03646 dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust; 03647 if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) 03648 pcl = 0; 03649 st_clust(dir + SZ_DIRE, pcl); 03650 for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ 03651 dj.fs->winsect = dsc++; 03652 dj.fs->wflag = 1; 03653 res = sync_window(dj.fs); 03654 if (res != FR_OK) break; 03655 mem_set(dir, 0, SS(dj.fs)); 03656 } 03657 } 03658 if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ 03659 if (res != FR_OK) { 03660 remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ 03661 } else { 03662 dir = dj.dir; 03663 dir[DIR_Attr] = AM_DIR; /* Attribute */ 03664 ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ 03665 st_clust(dir, dcl); /* Table start cluster */ 03666 dj.fs->wflag = 1; 03667 res = sync_fs(dj.fs); 03668 } 03669 } 03670 FREE_BUF(); 03671 } 03672 03673 LEAVE_FF(dj.fs, res); 03674 } 03675 03676 03677 03678 03679 /*-----------------------------------------------------------------------*/ 03680 /* Change Attribute */ 03681 /*-----------------------------------------------------------------------*/ 03682 03683 FRESULT f_chmod ( 03684 const TCHAR* path, /* Pointer to the file path */ 03685 BYTE attr, /* Attribute bits */ 03686 BYTE mask /* Attribute mask to change */ 03687 ) 03688 { 03689 FRESULT res; 03690 FATFS_DIR dj; 03691 BYTE *dir; 03692 DEFINE_NAMEBUF; 03693 03694 03695 res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */ 03696 if (res == FR_OK) { 03697 INIT_BUF(dj); 03698 res = follow_path(&dj, path); /* Follow the file path */ 03699 FREE_BUF(); 03700 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) 03701 res = FR_INVALID_NAME; 03702 if (res == FR_OK) { 03703 dir = dj.dir; 03704 if (!dir) { /* Is it a root directory? */ 03705 res = FR_INVALID_NAME; 03706 } else { /* File or sub directory */ 03707 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ 03708 dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 03709 dj.fs->wflag = 1; 03710 res = sync_fs(dj.fs); 03711 } 03712 } 03713 } 03714 03715 LEAVE_FF(dj.fs, res); 03716 } 03717 03718 03719 03720 03721 /*-----------------------------------------------------------------------*/ 03722 /* Rename File/Directory */ 03723 /*-----------------------------------------------------------------------*/ 03724 03725 FRESULT f_rename ( 03726 const TCHAR* path_old, /* Pointer to the object to be renamed */ 03727 const TCHAR* path_new /* Pointer to the new name */ 03728 ) 03729 { 03730 FRESULT res; 03731 FATFS_DIR djo, djn; 03732 BYTE buf[21], *dir; 03733 DWORD dw; 03734 DEFINE_NAMEBUF; 03735 03736 03737 /* Get logical drive number of the source object */ 03738 res = find_volume(&djo.fs, &path_old, 1); 03739 if (res == FR_OK) { 03740 djn.fs = djo.fs; 03741 INIT_BUF(djo); 03742 res = follow_path(&djo, path_old); /* Check old object */ 03743 if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) 03744 res = FR_INVALID_NAME; 03745 #if _FS_LOCK 03746 if (res == FR_OK) res = chk_lock(&djo, 2); 03747 #endif 03748 if (res == FR_OK) { /* Old object is found */ 03749 if (!djo.dir) { /* Is root dir? */ 03750 res = FR_NO_FILE; 03751 } else { 03752 mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */ 03753 mem_cpy(&djn, &djo, sizeof (FATFS_DIR)); /* Duplicate the directory object */ 03754 if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ 03755 res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */ 03756 else 03757 res = FR_INVALID_DRIVE; 03758 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ 03759 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ 03760 res = dir_register(&djn); /* Register the new entry */ 03761 if (res == FR_OK) { 03762 /* Start of critical section where any interruption can cause a cross-link */ 03763 dir = djn.dir; /* Copy information about object except name */ 03764 mem_cpy(dir + 13, buf + 2, 19); 03765 dir[DIR_Attr] = buf[0] | AM_ARC; 03766 djo.fs->wflag = 1; 03767 if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */ 03768 dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); 03769 if (!dw) { 03770 res = FR_INT_ERR; 03771 } else { 03772 res = move_window(djo.fs, dw); 03773 dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */ 03774 if (res == FR_OK && dir[1] == '.') { 03775 st_clust(dir, djn.sclust); 03776 djo.fs->wflag = 1; 03777 } 03778 } 03779 } 03780 if (res == FR_OK) { 03781 res = dir_remove(&djo); /* Remove old entry */ 03782 if (res == FR_OK) 03783 res = sync_fs(djo.fs); 03784 } 03785 /* End of critical section */ 03786 } 03787 } 03788 } 03789 } 03790 FREE_BUF(); 03791 } 03792 03793 LEAVE_FF(djo.fs, res); 03794 } 03795 03796 03797 03798 03799 /*-----------------------------------------------------------------------*/ 03800 /* Change Timestamp */ 03801 /*-----------------------------------------------------------------------*/ 03802 03803 FRESULT f_utime ( 03804 const TCHAR* path, /* Pointer to the file/directory name */ 03805 const FILINFO* fno /* Pointer to the time stamp to be set */ 03806 ) 03807 { 03808 FRESULT res; 03809 FATFS_DIR dj; 03810 BYTE *dir; 03811 DEFINE_NAMEBUF; 03812 03813 03814 /* Get logical drive number */ 03815 res = find_volume(&dj.fs, &path, 1); 03816 if (res == FR_OK) { 03817 INIT_BUF(dj); 03818 res = follow_path(&dj, path); /* Follow the file path */ 03819 FREE_BUF(); 03820 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) 03821 res = FR_INVALID_NAME; 03822 if (res == FR_OK) { 03823 dir = dj.dir; 03824 if (!dir) { /* Root directory */ 03825 res = FR_INVALID_NAME; 03826 } else { /* File or sub-directory */ 03827 ST_WORD(dir + DIR_WrtTime, fno->ftime); 03828 ST_WORD(dir + DIR_WrtDate, fno->fdate); 03829 dj.fs->wflag = 1; 03830 res = sync_fs(dj.fs); 03831 } 03832 } 03833 } 03834 03835 LEAVE_FF(dj.fs, res); 03836 } 03837 03838 #endif /* !_FS_READONLY */ 03839 #endif /* _FS_MINIMIZE == 0 */ 03840 #endif /* _FS_MINIMIZE <= 1 */ 03841 #endif /* _FS_MINIMIZE <= 2 */ 03842 03843 03844 03845 03846 #if _USE_LABEL 03847 /*-----------------------------------------------------------------------*/ 03848 /* Get volume label */ 03849 /*-----------------------------------------------------------------------*/ 03850 03851 FRESULT f_getlabel ( 03852 const TCHAR* path, /* Path name of the logical drive number */ 03853 TCHAR* label, /* Pointer to a buffer to return the volume label */ 03854 DWORD* vsn /* Pointer to a variable to return the volume serial number */ 03855 ) 03856 { 03857 FRESULT res; 03858 FATFS_DIR dj; 03859 UINT i, j; 03860 #if _USE_LFN && _LFN_UNICODE 03861 WCHAR w; 03862 #endif 03863 03864 03865 /* Get logical drive number */ 03866 res = find_volume(&dj.fs, &path, 0); 03867 03868 /* Get volume label */ 03869 if (res == FR_OK && label) { 03870 dj.sclust = 0; /* Open root directory */ 03871 res = dir_sdi(&dj, 0); 03872 if (res == FR_OK) { 03873 res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ 03874 if (res == FR_OK) { /* A volume label is exist */ 03875 #if _USE_LFN && _LFN_UNICODE 03876 i = j = 0; 03877 do { 03878 w = (i < 11) ? dj.dir[i++] : ' '; 03879 if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) 03880 w = w << 8 | dj.dir[i++]; 03881 label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ 03882 } while (j < 11); 03883 #else 03884 mem_cpy(label, dj.dir, 11); 03885 #endif 03886 j = 11; 03887 do { 03888 label[j] = 0; 03889 if (!j) break; 03890 } while (label[--j] == ' '); 03891 } 03892 if (res == FR_NO_FILE) { /* No label, return nul string */ 03893 label[0] = 0; 03894 res = FR_OK; 03895 } 03896 } 03897 } 03898 03899 /* Get volume serial number */ 03900 if (res == FR_OK && vsn) { 03901 res = move_window(dj.fs, dj.fs->volbase); 03902 if (res == FR_OK) { 03903 i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; 03904 *vsn = LD_DWORD(&dj.fs->win[i]); 03905 } 03906 } 03907 03908 LEAVE_FF(dj.fs, res); 03909 } 03910 03911 03912 03913 #if !_FS_READONLY 03914 /*-----------------------------------------------------------------------*/ 03915 /* Set volume label */ 03916 /*-----------------------------------------------------------------------*/ 03917 03918 FRESULT f_setlabel ( 03919 const TCHAR* label /* Pointer to the volume label to set */ 03920 ) 03921 { 03922 FRESULT res; 03923 FATFS_DIR dj; 03924 BYTE vn[11]; 03925 UINT i, j, sl; 03926 WCHAR w; 03927 DWORD tm; 03928 03929 03930 /* Get logical drive number */ 03931 res = find_volume(&dj.fs, &label, 1); 03932 if (res) LEAVE_FF(dj.fs, res); 03933 03934 /* Create a volume label in directory form */ 03935 vn[0] = 0; 03936 for (sl = 0; label[sl]; sl++) ; /* Get name length */ 03937 for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */ 03938 if (sl) { /* Create volume label in directory form */ 03939 i = j = 0; 03940 do { 03941 #if _USE_LFN && _LFN_UNICODE 03942 w = ff_convert(ff_wtoupper(label[i++]), 0); 03943 #else 03944 w = (BYTE)label[i++]; 03945 if (IsDBCS1(w)) 03946 w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; 03947 #if _USE_LFN 03948 w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); 03949 #else 03950 if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ 03951 #ifdef _EXCVT 03952 if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ 03953 #else 03954 if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ 03955 #endif 03956 #endif 03957 #endif 03958 if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ 03959 LEAVE_FF(dj.fs, FR_INVALID_NAME); 03960 if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); 03961 vn[j++] = (BYTE)w; 03962 } while (i < sl); 03963 while (j < 11) vn[j++] = ' '; /* Fill remaining name field */ 03964 if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ 03965 } 03966 03967 /* Set volume label */ 03968 dj.sclust = 0; /* Open root directory */ 03969 res = dir_sdi(&dj, 0); 03970 if (res == FR_OK) { 03971 res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ 03972 if (res == FR_OK) { /* A volume label is found */ 03973 if (vn[0]) { 03974 mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ 03975 tm = GET_FATTIME(); 03976 ST_DWORD(dj.dir + DIR_WrtTime, tm); 03977 } else { 03978 dj.dir[0] = DDEM; /* Remove the volume label */ 03979 } 03980 dj.fs->wflag = 1; 03981 res = sync_fs(dj.fs); 03982 } else { /* No volume label is found or error */ 03983 if (res == FR_NO_FILE) { 03984 res = FR_OK; 03985 if (vn[0]) { /* Create volume label as new */ 03986 res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ 03987 if (res == FR_OK) { 03988 mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ 03989 mem_cpy(dj.dir, vn, 11); 03990 dj.dir[DIR_Attr] = AM_VOL; 03991 tm = GET_FATTIME(); 03992 ST_DWORD(dj.dir + DIR_WrtTime, tm); 03993 dj.fs->wflag = 1; 03994 res = sync_fs(dj.fs); 03995 } 03996 } 03997 } 03998 } 03999 } 04000 04001 LEAVE_FF(dj.fs, res); 04002 } 04003 04004 #endif /* !_FS_READONLY */ 04005 #endif /* _USE_LABEL */ 04006 04007 04008 04009 /*-----------------------------------------------------------------------*/ 04010 /* Forward data to the stream directly (available on only tiny cfg) */ 04011 /*-----------------------------------------------------------------------*/ 04012 #if _USE_FORWARD && _FS_TINY 04013 04014 FRESULT f_forward ( 04015 FIL* fp, /* Pointer to the file object */ 04016 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ 04017 UINT btf, /* Number of bytes to forward */ 04018 UINT* bf /* Pointer to number of bytes forwarded */ 04019 ) 04020 { 04021 FRESULT res; 04022 DWORD remain, clst, sect; 04023 UINT rcnt; 04024 BYTE csect; 04025 04026 04027 *bf = 0; /* Clear transfer byte counter */ 04028 04029 res = validate(fp); /* Check validity of the object */ 04030 if (res != FR_OK) LEAVE_FF(fp->fs, res); 04031 if (fp->err) /* Check error */ 04032 LEAVE_FF(fp->fs, (FRESULT)fp->err); 04033 if (!(fp->flag & FA_READ)) /* Check access mode */ 04034 LEAVE_FF(fp->fs, FR_DENIED); 04035 04036 remain = fp->fsize - fp->fptr; 04037 if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ 04038 04039 for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ 04040 fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { 04041 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ 04042 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ 04043 if (!csect) { /* On the cluster boundary? */ 04044 clst = (fp->fptr == 0) ? /* On the top of the file? */ 04045 fp->sclust : get_fat(fp->fs, fp->clust); 04046 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); 04047 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 04048 fp->clust = clst; /* Update current cluster */ 04049 } 04050 } 04051 sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ 04052 if (!sect) ABORT(fp->fs, FR_INT_ERR); 04053 sect += csect; 04054 if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ 04055 ABORT(fp->fs, FR_DISK_ERR); 04056 fp->dsect = sect; 04057 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ 04058 if (rcnt > btf) rcnt = btf; 04059 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); 04060 if (!rcnt) ABORT(fp->fs, FR_INT_ERR); 04061 } 04062 04063 LEAVE_FF(fp->fs, FR_OK); 04064 } 04065 #endif /* _USE_FORWARD */ 04066 04067 04068 04069 #if _USE_MKFS && !_FS_READONLY 04070 /*-----------------------------------------------------------------------*/ 04071 /* Create file system on the logical drive */ 04072 /*-----------------------------------------------------------------------*/ 04073 #define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ 04074 #define N_FATS 1 /* Number of FATs (1 or 2) */ 04075 04076 04077 FRESULT f_mkfs ( 04078 const TCHAR* path, /* Logical drive number */ 04079 BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ 04080 UINT au /* Size of allocation unit in unit of byte or sector */ 04081 ) 04082 { 04083 static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; 04084 static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; 04085 int vol; 04086 BYTE fmt, md, sys, *tbl, pdrv, part; 04087 DWORD n_clst, vs, n, wsect; 04088 UINT i; 04089 DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ 04090 DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ 04091 FATFS *fs; 04092 DSTATUS stat; 04093 #if _USE_TRIM 04094 DWORD eb[2]; 04095 #endif 04096 04097 04098 /* Check mounted drive and clear work area */ 04099 if (sfd > 1) return FR_INVALID_PARAMETER; 04100 vol = get_ldnumber(&path); 04101 if (vol < 0) return FR_INVALID_DRIVE; 04102 fs = FatFs[vol]; 04103 if (!fs) return FR_NOT_ENABLED; 04104 fs->fs_type = 0; 04105 pdrv = LD2PD(vol); /* Physical drive */ 04106 part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ 04107 04108 /* Get disk statics */ 04109 stat = disk_initialize(pdrv); 04110 if (stat & STA_NOINIT) return FR_NOT_READY; 04111 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 04112 #if _MAX_SS != _MIN_SS /* Get disk sector size */ 04113 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) 04114 return FR_DISK_ERR; 04115 #endif 04116 if (_MULTI_PARTITION && part) { 04117 /* Get partition information from partition table in the MBR */ 04118 if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; 04119 if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; 04120 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; 04121 if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ 04122 b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ 04123 n_vol = LD_DWORD(tbl + 12); /* Volume size */ 04124 } else { 04125 /* Create a partition in this function */ 04126 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) 04127 return FR_DISK_ERR; 04128 b_vol = (sfd) ? 0 : 63; /* Volume start sector */ 04129 n_vol -= b_vol; /* Volume size */ 04130 } 04131 04132 if (au & (au - 1)) au = 0; 04133 if (!au) { /* AU auto selection */ 04134 vs = n_vol / (2000 / (SS(fs) / 512)); 04135 for (i = 0; vs < vst[i]; i++) ; 04136 au = cst[i]; 04137 } 04138 if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */ 04139 if (!au) au = 1; 04140 if (au > 128) au = 128; 04141 04142 /* Pre-compute number of clusters and FAT sub-type */ 04143 n_clst = n_vol / au; 04144 fmt = FS_FAT12; 04145 if (n_clst >= MIN_FAT16) fmt = FS_FAT16; 04146 if (n_clst >= MIN_FAT32) fmt = FS_FAT32; 04147 04148 /* Determine offset and size of FAT structure */ 04149 if (fmt == FS_FAT32) { 04150 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); 04151 n_rsv = 32; 04152 n_dir = 0; 04153 } else { 04154 n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; 04155 n_fat = (n_fat + SS(fs) - 1) / SS(fs); 04156 n_rsv = 1; 04157 n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); 04158 } 04159 b_fat = b_vol + n_rsv; /* FAT area start sector */ 04160 b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ 04161 b_data = b_dir + n_dir; /* Data area start sector */ 04162 if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ 04163 04164 /* Align data start sector to erase block boundary (for flash memory media) */ 04165 if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; 04166 n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ 04167 n = (n - b_data) / N_FATS; 04168 if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ 04169 n_rsv += n; 04170 b_fat += n; 04171 } else { /* FAT12/16: Expand FAT size */ 04172 n_fat += n; 04173 } 04174 04175 /* Determine number of clusters and final check of validity of the FAT sub-type */ 04176 n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; 04177 if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) 04178 || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) 04179 return FR_MKFS_ABORTED; 04180 04181 /* Determine system ID in the partition table */ 04182 if (fmt == FS_FAT32) { 04183 sys = 0x0C; /* FAT32X */ 04184 } else { 04185 if (fmt == FS_FAT12 && n_vol < 0x10000) { 04186 sys = 0x01; /* FAT12(<65536) */ 04187 } else { 04188 sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ 04189 } 04190 } 04191 04192 if (_MULTI_PARTITION && part) { 04193 /* Update system ID in the partition table */ 04194 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; 04195 tbl[4] = sys; 04196 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ 04197 return FR_DISK_ERR; 04198 md = 0xF8; 04199 } else { 04200 if (sfd) { /* No partition table (SFD) */ 04201 md = 0xF0; 04202 } else { /* Create partition table (FDISK) */ 04203 mem_set(fs->win, 0, SS(fs)); 04204 tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */ 04205 tbl[1] = 1; /* Partition start head */ 04206 tbl[2] = 1; /* Partition start sector */ 04207 tbl[3] = 0; /* Partition start cylinder */ 04208 tbl[4] = sys; /* System type */ 04209 tbl[5] = 254; /* Partition end head */ 04210 n = (b_vol + n_vol) / 63 / 255; 04211 tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ 04212 tbl[7] = (BYTE)n; /* End cylinder */ 04213 ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ 04214 ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ 04215 ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ 04216 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */ 04217 return FR_DISK_ERR; 04218 md = 0xF8; 04219 } 04220 } 04221 04222 /* Create BPB in the VBR */ 04223 tbl = fs->win; /* Clear sector */ 04224 mem_set(tbl, 0, SS(fs)); 04225 mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ 04226 i = SS(fs); /* Sector size */ 04227 ST_WORD(tbl + BPB_BytsPerSec, i); 04228 tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ 04229 ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ 04230 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ 04231 i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ 04232 ST_WORD(tbl + BPB_RootEntCnt, i); 04233 if (n_vol < 0x10000) { /* Number of total sectors */ 04234 ST_WORD(tbl + BPB_TotSec16, n_vol); 04235 } else { 04236 ST_DWORD(tbl + BPB_TotSec32, n_vol); 04237 } 04238 tbl[BPB_Media] = md; /* Media descriptor */ 04239 ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ 04240 ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ 04241 ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ 04242 n = GET_FATTIME(); /* Use current time as VSN */ 04243 if (fmt == FS_FAT32) { 04244 ST_DWORD(tbl + BS_VolID32, n); /* VSN */ 04245 ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ 04246 ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ 04247 ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ 04248 ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */ 04249 tbl[BS_DrvNum32] = 0x80; /* Drive number */ 04250 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ 04251 mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ 04252 } else { 04253 ST_DWORD(tbl + BS_VolID, n); /* VSN */ 04254 ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ 04255 tbl[BS_DrvNum] = 0x80; /* Drive number */ 04256 tbl[BS_BootSig] = 0x29; /* Extended boot signature */ 04257 mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ 04258 } 04259 ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ 04260 if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ 04261 return FR_DISK_ERR; 04262 if (fmt == FS_FAT32) /* Write it to the backup VBR if needed (VBR + 6) */ 04263 disk_write(pdrv, tbl, b_vol + 6, 1); 04264 04265 /* Initialize FAT area */ 04266 wsect = b_fat; 04267 for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ 04268 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ 04269 n = md; /* Media descriptor byte */ 04270 if (fmt != FS_FAT32) { 04271 n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; 04272 ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ 04273 } else { 04274 n |= 0xFFFFFF00; 04275 ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ 04276 ST_DWORD(tbl + 4, 0xFFFFFFFF); 04277 ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ 04278 } 04279 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) 04280 return FR_DISK_ERR; 04281 mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ 04282 for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ 04283 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) 04284 return FR_DISK_ERR; 04285 } 04286 } 04287 04288 /* Initialize root directory */ 04289 i = (fmt == FS_FAT32) ? au : (UINT)n_dir; 04290 do { 04291 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) 04292 return FR_DISK_ERR; 04293 } while (--i); 04294 04295 #if _USE_TRIM /* Erase data area if needed */ 04296 { 04297 eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; 04298 disk_ioctl(pdrv, CTRL_TRIM, eb); 04299 } 04300 #endif 04301 04302 /* Create FSINFO if needed */ 04303 if (fmt == FS_FAT32) { 04304 ST_DWORD(tbl + FSI_LeadSig, 0x41615252); 04305 ST_DWORD(tbl + FSI_StrucSig, 0x61417272); 04306 ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ 04307 ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ 04308 ST_WORD(tbl + BS_55AA, 0xAA55); 04309 disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ 04310 disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ 04311 } 04312 04313 return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; 04314 } 04315 04316 04317 04318 #if _MULTI_PARTITION 04319 /*-----------------------------------------------------------------------*/ 04320 /* Create partition table on the physical drive */ 04321 /*-----------------------------------------------------------------------*/ 04322 04323 FRESULT f_fdisk ( 04324 BYTE pdrv, /* Physical drive number */ 04325 const DWORD szt[], /* Pointer to the size table for each partitions */ 04326 void* work /* Pointer to the working buffer */ 04327 ) 04328 { 04329 UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; 04330 BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; 04331 DSTATUS stat; 04332 DWORD sz_disk, sz_part, s_part; 04333 04334 04335 stat = disk_initialize(pdrv); 04336 if (stat & STA_NOINIT) return FR_NOT_READY; 04337 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 04338 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; 04339 04340 /* Determine CHS in the table regardless of the drive geometry */ 04341 for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; 04342 if (n == 256) n--; 04343 e_hd = n - 1; 04344 sz_cyl = 63 * n; 04345 tot_cyl = sz_disk / sz_cyl; 04346 04347 /* Create partition table */ 04348 mem_set(buf, 0, _MAX_SS); 04349 p = buf + MBR_Table; b_cyl = 0; 04350 for (i = 0; i < 4; i++, p += SZ_PTE) { 04351 p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; 04352 if (!p_cyl) continue; 04353 s_part = (DWORD)sz_cyl * b_cyl; 04354 sz_part = (DWORD)sz_cyl * p_cyl; 04355 if (i == 0) { /* Exclude first track of cylinder 0 */ 04356 s_hd = 1; 04357 s_part += 63; sz_part -= 63; 04358 } else { 04359 s_hd = 0; 04360 } 04361 e_cyl = b_cyl + p_cyl - 1; 04362 if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; 04363 04364 /* Set partition table */ 04365 p[1] = s_hd; /* Start head */ 04366 p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ 04367 p[3] = (BYTE)b_cyl; /* Start cylinder */ 04368 p[4] = 0x06; /* System type (temporary setting) */ 04369 p[5] = e_hd; /* End head */ 04370 p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ 04371 p[7] = (BYTE)e_cyl; /* End cylinder */ 04372 ST_DWORD(p + 8, s_part); /* Start sector in LBA */ 04373 ST_DWORD(p + 12, sz_part); /* Partition size */ 04374 04375 /* Next partition */ 04376 b_cyl += p_cyl; 04377 } 04378 ST_WORD(p, 0xAA55); 04379 04380 /* Write it to the MBR */ 04381 return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; 04382 } 04383 04384 04385 #endif /* _MULTI_PARTITION */ 04386 #endif /* _USE_MKFS && !_FS_READONLY */ 04387 04388 04389 04390 04391 #if _USE_STRFUNC 04392 /*-----------------------------------------------------------------------*/ 04393 /* Get a string from the file */ 04394 /*-----------------------------------------------------------------------*/ 04395 04396 TCHAR* f_gets ( 04397 TCHAR* buff, /* Pointer to the string buffer to read */ 04398 int len, /* Size of string buffer (characters) */ 04399 FIL* fp /* Pointer to the file object */ 04400 ) 04401 { 04402 int n = 0; 04403 TCHAR c, *p = buff; 04404 BYTE s[2]; 04405 UINT rc; 04406 04407 04408 while (n < len - 1) { /* Read characters until buffer gets filled */ 04409 #if _USE_LFN && _LFN_UNICODE 04410 #if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ 04411 f_read(fp, s, 1, &rc); 04412 if (rc != 1) break; 04413 c = s[0]; 04414 if (c >= 0x80) { 04415 if (c < 0xC0) continue; /* Skip stray trailer */ 04416 if (c < 0xE0) { /* Two-byte sequence */ 04417 f_read(fp, s, 1, &rc); 04418 if (rc != 1) break; 04419 c = (c & 0x1F) << 6 | (s[0] & 0x3F); 04420 if (c < 0x80) c = '?'; 04421 } else { 04422 if (c < 0xF0) { /* Three-byte sequence */ 04423 f_read(fp, s, 2, &rc); 04424 if (rc != 2) break; 04425 c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); 04426 if (c < 0x800) c = '?'; 04427 } else { /* Reject four-byte sequence */ 04428 c = '?'; 04429 } 04430 } 04431 } 04432 #elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ 04433 f_read(fp, s, 2, &rc); 04434 if (rc != 2) break; 04435 c = s[1] + (s[0] << 8); 04436 #elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ 04437 f_read(fp, s, 2, &rc); 04438 if (rc != 2) break; 04439 c = s[0] + (s[1] << 8); 04440 #else /* Read a character in ANSI/OEM */ 04441 f_read(fp, s, 1, &rc); 04442 if (rc != 1) break; 04443 c = s[0]; 04444 if (IsDBCS1(c)) { 04445 f_read(fp, s, 1, &rc); 04446 if (rc != 1) break; 04447 c = (c << 8) + s[0]; 04448 } 04449 c = ff_convert(c, 1); /* OEM -> Unicode */ 04450 if (!c) c = '?'; 04451 #endif 04452 #else /* Read a character without conversion */ 04453 f_read(fp, s, 1, &rc); 04454 if (rc != 1) break; 04455 c = s[0]; 04456 #endif 04457 if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */ 04458 *p++ = c; 04459 n++; 04460 if (c == '\n') break; /* Break on EOL */ 04461 } 04462 *p = 0; 04463 return n ? buff : 0; /* When no data read (eof or error), return with error. */ 04464 } 04465 04466 04467 04468 04469 #if !_FS_READONLY 04470 #include <stdarg.h> 04471 /*-----------------------------------------------------------------------*/ 04472 /* Put a character to the file */ 04473 /*-----------------------------------------------------------------------*/ 04474 04475 typedef struct { 04476 FIL* fp; 04477 int idx, nchr; 04478 BYTE buf[64]; 04479 } putbuff; 04480 04481 04482 static 04483 void putc_bfd ( 04484 putbuff* pb, 04485 TCHAR c 04486 ) 04487 { 04488 UINT bw; 04489 int i; 04490 04491 04492 if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ 04493 putc_bfd(pb, '\r'); 04494 04495 i = pb->idx; /* Buffer write index (-1:error) */ 04496 if (i < 0) return; 04497 04498 #if _USE_LFN && _LFN_UNICODE 04499 #if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ 04500 if (c < 0x80) { /* 7-bit */ 04501 pb->buf[i++] = (BYTE)c; 04502 } else { 04503 if (c < 0x800) { /* 11-bit */ 04504 pb->buf[i++] = (BYTE)(0xC0 | c >> 6); 04505 } else { /* 16-bit */ 04506 pb->buf[i++] = (BYTE)(0xE0 | c >> 12); 04507 pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); 04508 } 04509 pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); 04510 } 04511 #elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ 04512 pb->buf[i++] = (BYTE)(c >> 8); 04513 pb->buf[i++] = (BYTE)c; 04514 #elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ 04515 pb->buf[i++] = (BYTE)c; 04516 pb->buf[i++] = (BYTE)(c >> 8); 04517 #else /* Write a character in ANSI/OEM */ 04518 c = ff_convert(c, 0); /* Unicode -> OEM */ 04519 if (!c) c = '?'; 04520 if (c >= 0x100) 04521 pb->buf[i++] = (BYTE)(c >> 8); 04522 pb->buf[i++] = (BYTE)c; 04523 #endif 04524 #else /* Write a character without conversion */ 04525 pb->buf[i++] = (BYTE)c; 04526 #endif 04527 04528 if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ 04529 f_write(pb->fp, pb->buf, (UINT)i, &bw); 04530 i = (bw == (UINT)i) ? 0 : -1; 04531 } 04532 pb->idx = i; 04533 pb->nchr++; 04534 } 04535 04536 04537 04538 int f_putc ( 04539 TCHAR c, /* A character to be output */ 04540 FIL* fp /* Pointer to the file object */ 04541 ) 04542 { 04543 putbuff pb; 04544 UINT nw; 04545 04546 04547 pb.fp = fp; /* Initialize output buffer */ 04548 pb.nchr = pb.idx = 0; 04549 04550 putc_bfd(&pb, c); /* Put a character */ 04551 04552 if ( pb.idx >= 0 /* Flush buffered characters to the file */ 04553 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK 04554 && (UINT)pb.idx == nw) return pb.nchr; 04555 return EOF; 04556 } 04557 04558 04559 04560 04561 /*-----------------------------------------------------------------------*/ 04562 /* Put a string to the file */ 04563 /*-----------------------------------------------------------------------*/ 04564 04565 int f_puts ( 04566 const TCHAR* str, /* Pointer to the string to be output */ 04567 FIL* fp /* Pointer to the file object */ 04568 ) 04569 { 04570 putbuff pb; 04571 UINT nw; 04572 04573 04574 pb.fp = fp; /* Initialize output buffer */ 04575 pb.nchr = pb.idx = 0; 04576 04577 while (*str) /* Put the string */ 04578 putc_bfd(&pb, *str++); 04579 04580 if ( pb.idx >= 0 /* Flush buffered characters to the file */ 04581 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK 04582 && (UINT)pb.idx == nw) return pb.nchr; 04583 return EOF; 04584 } 04585 04586 04587 04588 04589 /*-----------------------------------------------------------------------*/ 04590 /* Put a formatted string to the file */ 04591 /*-----------------------------------------------------------------------*/ 04592 04593 int f_printf ( 04594 FIL* fp, /* Pointer to the file object */ 04595 const TCHAR* fmt, /* Pointer to the format string */ 04596 ... /* Optional arguments... */ 04597 ) 04598 { 04599 va_list arp; 04600 BYTE f, r; 04601 UINT nw, i, j, w; 04602 DWORD v; 04603 TCHAR c, d, s[16], *p; 04604 putbuff pb; 04605 04606 04607 pb.fp = fp; /* Initialize output buffer */ 04608 pb.nchr = pb.idx = 0; 04609 04610 va_start(arp, fmt); 04611 04612 for (;;) { 04613 c = *fmt++; 04614 if (c == 0) break; /* End of string */ 04615 if (c != '%') { /* Non escape character */ 04616 putc_bfd(&pb, c); 04617 continue; 04618 } 04619 w = f = 0; 04620 c = *fmt++; 04621 if (c == '0') { /* Flag: '0' padding */ 04622 f = 1; c = *fmt++; 04623 } else { 04624 if (c == '-') { /* Flag: left justified */ 04625 f = 2; c = *fmt++; 04626 } 04627 } 04628 while (IsDigit(c)) { /* Precision */ 04629 w = w * 10 + c - '0'; 04630 c = *fmt++; 04631 } 04632 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ 04633 f |= 4; c = *fmt++; 04634 } 04635 if (!c) break; 04636 d = c; 04637 if (IsLower(d)) d -= 0x20; 04638 switch (d) { /* Type is... */ 04639 case 'S' : /* String */ 04640 p = va_arg(arp, TCHAR*); 04641 for (j = 0; p[j]; j++) ; 04642 if (!(f & 2)) { 04643 while (j++ < w) putc_bfd(&pb, ' '); 04644 } 04645 while (*p) putc_bfd(&pb, *p++); 04646 while (j++ < w) putc_bfd(&pb, ' '); 04647 continue; 04648 case 'C' : /* Character */ 04649 putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; 04650 case 'B' : /* Binary */ 04651 r = 2; break; 04652 case 'O' : /* Octal */ 04653 r = 8; break; 04654 case 'D' : /* Signed decimal */ 04655 case 'U' : /* Unsigned decimal */ 04656 r = 10; break; 04657 case 'X' : /* Hexdecimal */ 04658 r = 16; break; 04659 default: /* Unknown type (pass-through) */ 04660 putc_bfd(&pb, c); continue; 04661 } 04662 04663 /* Get an argument and put it in numeral */ 04664 v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); 04665 if (d == 'D' && (v & 0x80000000)) { 04666 v = 0 - v; 04667 f |= 8; 04668 } 04669 i = 0; 04670 do { 04671 d = (TCHAR)(v % r); v /= r; 04672 if (d > 9) d += (c == 'x') ? 0x27 : 0x07; 04673 s[i++] = d + '0'; 04674 } while (v && i < sizeof s / sizeof s[0]); 04675 if (f & 8) s[i++] = '-'; 04676 j = i; d = (f & 1) ? '0' : ' '; 04677 while (!(f & 2) && j++ < w) putc_bfd(&pb, d); 04678 do putc_bfd(&pb, s[--i]); while (i); 04679 while (j++ < w) putc_bfd(&pb, d); 04680 } 04681 04682 va_end(arp); 04683 04684 if ( pb.idx >= 0 /* Flush buffered characters to the file */ 04685 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK 04686 && (UINT)pb.idx == nw) return pb.nchr; 04687 return EOF; 04688 } 04689 04690 #endif /* !_FS_READONLY */ 04691 #endif /* _USE_STRFUNC */
Generated on Thu Jul 28 2022 16:31:07 by
