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.
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 #if _FS_HEAPBUF 02254 if (!fs->win) { 02255 fs->win = (BYTE*)ff_memalloc(SS(fs)); /* Allocate buffer to back window if necessary */ 02256 if (!fs->win) 02257 return FR_NOT_ENOUGH_CORE; 02258 } 02259 #endif 02260 /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ 02261 bsect = 0; 02262 fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ 02263 if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ 02264 for (i = 0; i < 4; i++) { /* Get partition offset */ 02265 pt = fs->win + MBR_Table + i * SZ_PTE; 02266 br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; 02267 } 02268 i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ 02269 if (i) i--; 02270 do { /* Find an FAT volume */ 02271 bsect = br[i]; 02272 fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ 02273 } while (!LD2PT(vol) && fmt && ++i < 4); 02274 } 02275 if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ 02276 if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ 02277 02278 /* An FAT volume is found. Following code initializes the file system object */ 02279 02280 if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ 02281 return FR_NO_FILESYSTEM; 02282 02283 fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ 02284 if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32); 02285 fs->fsize = fasize; 02286 02287 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ 02288 if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ 02289 return FR_NO_FILESYSTEM; 02290 fasize *= fs->n_fats; /* Number of sectors for FAT area */ 02291 02292 fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ 02293 if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ 02294 return FR_NO_FILESYSTEM; 02295 02296 fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ 02297 if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ 02298 return FR_NO_FILESYSTEM; 02299 02300 tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ 02301 if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32); 02302 02303 nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ 02304 if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ 02305 02306 /* Determine the FAT sub type */ 02307 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + FATFS_DIR */ 02308 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 02309 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ 02310 if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 02311 fmt = FS_FAT12; 02312 if (nclst >= MIN_FAT16) fmt = FS_FAT16; 02313 if (nclst >= MIN_FAT32) fmt = FS_FAT32; 02314 02315 /* Boundaries and Limits */ 02316 fs->n_fatent = nclst + 2; /* Number of FAT entries */ 02317 fs->volbase = bsect; /* Volume start sector */ 02318 fs->fatbase = bsect + nrsv; /* FAT start sector */ 02319 fs->database = bsect + sysect; /* Data start sector */ 02320 if (fmt == FS_FAT32) { 02321 if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ 02322 fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ 02323 szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ 02324 } else { 02325 if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ 02326 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ 02327 szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ 02328 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); 02329 } 02330 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ 02331 return FR_NO_FILESYSTEM; 02332 02333 #if !_FS_READONLY 02334 /* Initialize cluster allocation information */ 02335 fs->last_clust = fs->free_clust = 0xFFFFFFFF; 02336 02337 /* Get fsinfo if available */ 02338 fs->fsi_flag = 0x80; 02339 #if (_FS_NOFSINFO & 3) != 3 02340 if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */ 02341 && LD_WORD(fs->win + BPB_FSInfo) == 1 02342 && move_window(fs, bsect + 1) == FR_OK) 02343 { 02344 fs->fsi_flag = 0; 02345 if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ 02346 && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 02347 && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) 02348 { 02349 #if (_FS_NOFSINFO & 1) == 0 02350 fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); 02351 #endif 02352 #if (_FS_NOFSINFO & 2) == 0 02353 fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); 02354 #endif 02355 } 02356 } 02357 #endif 02358 #endif 02359 fs->fs_type = fmt; /* FAT sub-type */ 02360 fs->id = ++Fsid; /* File system mount ID */ 02361 #if _FS_RPATH 02362 fs->cdir = 0; /* Set current directory to root */ 02363 #endif 02364 #if _FS_LOCK /* Clear file lock semaphores */ 02365 clear_lock(fs); 02366 #endif 02367 02368 return FR_OK; 02369 } 02370 02371 02372 02373 02374 /*-----------------------------------------------------------------------*/ 02375 /* Check if the file/directory object is valid or not */ 02376 /*-----------------------------------------------------------------------*/ 02377 02378 static 02379 FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ 02380 void* obj /* Pointer to the object FIL/FATFS_DIR to check validity */ 02381 ) 02382 { 02383 FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/FATFS_DIR structure is identical */ 02384 02385 02386 if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT)) 02387 return FR_INVALID_OBJECT; 02388 02389 ENTER_FF(fil->fs); /* Lock file system */ 02390 02391 return FR_OK; 02392 } 02393 02394 02395 02396 02397 /*-------------------------------------------------------------------------- 02398 02399 Public Functions 02400 02401 ---------------------------------------------------------------------------*/ 02402 02403 02404 02405 /*-----------------------------------------------------------------------*/ 02406 /* Mount/Unmount a Logical Drive */ 02407 /*-----------------------------------------------------------------------*/ 02408 02409 FRESULT f_mount ( 02410 FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ 02411 const TCHAR* path, /* Logical drive number to be mounted/unmounted */ 02412 BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ 02413 ) 02414 { 02415 FATFS *cfs; 02416 int vol; 02417 FRESULT res; 02418 const TCHAR *rp = path; 02419 02420 02421 vol = get_ldnumber(&rp); 02422 if (vol < 0) return FR_INVALID_DRIVE; 02423 cfs = FatFs[vol]; /* Pointer to fs object */ 02424 02425 if (cfs) { 02426 #if _FS_LOCK 02427 clear_lock(cfs); 02428 #endif 02429 #if _FS_REENTRANT /* Discard sync object of the current volume */ 02430 if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; 02431 #endif 02432 cfs->fs_type = 0; /* Clear old fs object */ 02433 #if _FS_HEAPBUF 02434 ff_memfree(cfs->win); /* Clean up window buffer */ 02435 #endif 02436 } 02437 02438 if (fs) { 02439 fs->fs_type = 0; /* Clear new fs object */ 02440 #if _FS_REENTRANT /* Create sync object for the new volume */ 02441 if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; 02442 #endif 02443 #if _FS_HEAPBUF 02444 fs->win = 0; /* NULL buffer to prevent use of uninitialized buffer */ 02445 #endif 02446 } 02447 FatFs[vol] = fs; /* Register new fs object */ 02448 02449 if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ 02450 02451 res = find_volume(&fs, &path, 0); /* Force mounted the volume */ 02452 LEAVE_FF(fs, res); 02453 } 02454 02455 02456 02457 02458 /*-----------------------------------------------------------------------*/ 02459 /* Open or Create a File */ 02460 /*-----------------------------------------------------------------------*/ 02461 02462 FRESULT f_open ( 02463 FIL* fp, /* Pointer to the blank file object */ 02464 const TCHAR* path, /* Pointer to the file name */ 02465 BYTE mode /* Access mode and file open mode flags */ 02466 ) 02467 { 02468 FRESULT res; 02469 FATFS_DIR dj; 02470 BYTE *dir; 02471 DEFINE_NAMEBUF; 02472 #if !_FS_READONLY 02473 DWORD dw, cl; 02474 #endif 02475 02476 02477 if (!fp) return FR_INVALID_OBJECT; 02478 fp->fs = 0; /* Clear file object */ 02479 02480 /* Get logical drive number */ 02481 #if !_FS_READONLY 02482 mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; 02483 res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); 02484 #else 02485 mode &= FA_READ; 02486 res = find_volume(&dj.fs, &path, 0); 02487 #endif 02488 if (res == FR_OK) { 02489 INIT_BUF(dj); 02490 res = follow_path(&dj, path); /* Follow the file path */ 02491 dir = dj.dir; 02492 #if !_FS_READONLY /* R/W configuration */ 02493 if (res == FR_OK) { 02494 if (!dir) /* Default directory itself */ 02495 res = FR_INVALID_NAME; 02496 #if _FS_LOCK 02497 else 02498 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); 02499 #endif 02500 } 02501 /* Create or Open a file */ 02502 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { 02503 if (res != FR_OK) { /* No file, create new */ 02504 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ 02505 #if _FS_LOCK 02506 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; 02507 #else 02508 res = dir_register(&dj); 02509 #endif 02510 mode |= FA_CREATE_ALWAYS; /* File is created */ 02511 dir = dj.dir; /* New entry */ 02512 } 02513 else { /* Any object is already existing */ 02514 if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or FATFS_DIR) */ 02515 res = FR_DENIED; 02516 } else { 02517 if (mode & FA_CREATE_NEW) /* Cannot create as new file */ 02518 res = FR_EXIST; 02519 } 02520 } 02521 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ 02522 dw = GET_FATTIME(); 02523 ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */ 02524 ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */ 02525 dir[DIR_Attr] = 0; /* Reset attribute */ 02526 ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */ 02527 cl = ld_clust(dj.fs, dir); /* Get cluster chain */ 02528 st_clust(dir, 0); /* Reset cluster */ 02529 dj.fs->wflag = 1; 02530 if (cl) { /* Remove the cluster chain if exist */ 02531 dw = dj.fs->winsect; 02532 res = remove_chain(dj.fs, cl); 02533 if (res == FR_OK) { 02534 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ 02535 res = move_window(dj.fs, dw); 02536 } 02537 } 02538 } 02539 } 02540 else { /* Open an existing file */ 02541 if (res == FR_OK) { /* Following succeeded */ 02542 if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ 02543 res = FR_NO_FILE; 02544 } else { 02545 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ 02546 res = FR_DENIED; 02547 } 02548 } 02549 } 02550 if (res == FR_OK) { 02551 if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ 02552 mode |= FA__WRITTEN; 02553 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ 02554 fp->dir_ptr = dir; 02555 #if _FS_LOCK 02556 fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); 02557 if (!fp->lockid) res = FR_INT_ERR; 02558 #endif 02559 } 02560 02561 #else /* R/O configuration */ 02562 if (res == FR_OK) { /* Follow succeeded */ 02563 dir = dj.dir; 02564 if (!dir) { /* Current directory itself */ 02565 res = FR_INVALID_NAME; 02566 } else { 02567 if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ 02568 res = FR_NO_FILE; 02569 } 02570 } 02571 #endif 02572 FREE_BUF(); 02573 02574 if (res == FR_OK) { 02575 fp->flag = mode; /* File access mode */ 02576 fp->err = 0; /* Clear error flag */ 02577 fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ 02578 fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ 02579 fp->fptr = 0; /* File pointer */ 02580 fp->dsect = 0; 02581 #if _USE_FASTSEEK 02582 fp->cltbl = 0; /* Normal seek mode */ 02583 #endif 02584 fp->fs = dj.fs; /* Validate file object */ 02585 fp->id = fp->fs->id; 02586 #if !_FS_TINY && _FS_HEAPBUF 02587 fp->buf = (BYTE*)ff_memalloc(SS(dj.fs)); /* Allocate buffer if necessary */ 02588 if (!fp->buf) 02589 return FR_NOT_ENOUGH_CORE; 02590 #endif 02591 } 02592 } 02593 02594 LEAVE_FF(dj.fs, res); 02595 } 02596 02597 02598 02599 02600 /*-----------------------------------------------------------------------*/ 02601 /* Read File */ 02602 /*-----------------------------------------------------------------------*/ 02603 02604 FRESULT f_read ( 02605 FIL* fp, /* Pointer to the file object */ 02606 void* buff, /* Pointer to data buffer */ 02607 UINT btr, /* Number of bytes to read */ 02608 UINT* br /* Pointer to number of bytes read */ 02609 ) 02610 { 02611 FRESULT res; 02612 DWORD clst, sect, remain; 02613 UINT rcnt, cc; 02614 BYTE csect, *rbuff = (BYTE*)buff; 02615 02616 02617 *br = 0; /* Clear read byte counter */ 02618 02619 res = validate(fp); /* Check validity */ 02620 if (res != FR_OK) LEAVE_FF(fp->fs, res); 02621 if (fp->err) /* Check error */ 02622 LEAVE_FF(fp->fs, (FRESULT)fp->err); 02623 if (!(fp->flag & FA_READ)) /* Check access mode */ 02624 LEAVE_FF(fp->fs, FR_DENIED); 02625 remain = fp->fsize - fp->fptr; 02626 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ 02627 02628 for ( ; btr; /* Repeat until all data read */ 02629 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { 02630 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ 02631 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ 02632 if (!csect) { /* On the cluster boundary? */ 02633 if (fp->fptr == 0) { /* On the top of the file? */ 02634 clst = fp->sclust; /* Follow from the origin */ 02635 } else { /* Middle or end of the file */ 02636 #if _USE_FASTSEEK 02637 if (fp->cltbl) 02638 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 02639 else 02640 #endif 02641 clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ 02642 } 02643 if (clst < 2) ABORT(fp->fs, FR_INT_ERR); 02644 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 02645 fp->clust = clst; /* Update current cluster */ 02646 } 02647 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ 02648 if (!sect) ABORT(fp->fs, FR_INT_ERR); 02649 sect += csect; 02650 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ 02651 if (cc) { /* Read maximum contiguous sectors directly */ 02652 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ 02653 cc = fp->fs->csize - csect; 02654 if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) 02655 ABORT(fp->fs, FR_DISK_ERR); 02656 #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ 02657 #if _FS_TINY 02658 if (fp->fs->wflag && fp->fs->winsect - sect < cc) 02659 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); 02660 #else 02661 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) 02662 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); 02663 #endif 02664 #endif 02665 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ 02666 continue; 02667 } 02668 #if !_FS_TINY 02669 if (fp->dsect != sect) { /* Load data sector if not in cache */ 02670 #if !_FS_READONLY 02671 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ 02672 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 02673 ABORT(fp->fs, FR_DISK_ERR); 02674 fp->flag &= ~FA__DIRTY; 02675 } 02676 #endif 02677 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ 02678 ABORT(fp->fs, FR_DISK_ERR); 02679 } 02680 #endif 02681 fp->dsect = sect; 02682 } 02683 rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ 02684 if (rcnt > btr) rcnt = btr; 02685 #if _FS_TINY 02686 if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ 02687 ABORT(fp->fs, FR_DISK_ERR); 02688 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ 02689 #else 02690 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ 02691 #endif 02692 } 02693 02694 LEAVE_FF(fp->fs, FR_OK); 02695 } 02696 02697 02698 02699 02700 #if !_FS_READONLY 02701 /*-----------------------------------------------------------------------*/ 02702 /* Write File */ 02703 /*-----------------------------------------------------------------------*/ 02704 02705 FRESULT f_write ( 02706 FIL* fp, /* Pointer to the file object */ 02707 const void *buff, /* Pointer to the data to be written */ 02708 UINT btw, /* Number of bytes to write */ 02709 UINT* bw /* Pointer to number of bytes written */ 02710 ) 02711 { 02712 FRESULT res; 02713 DWORD clst, sect; 02714 UINT wcnt, cc; 02715 const BYTE *wbuff = (const BYTE*)buff; 02716 BYTE csect; 02717 bool need_sync = false; 02718 02719 *bw = 0; /* Clear write byte counter */ 02720 02721 res = validate(fp); /* Check validity */ 02722 if (res != FR_OK) LEAVE_FF(fp->fs, res); 02723 if (fp->err) /* Check error */ 02724 LEAVE_FF(fp->fs, (FRESULT)fp->err); 02725 if (!(fp->flag & FA_WRITE)) /* Check access mode */ 02726 LEAVE_FF(fp->fs, FR_DENIED); 02727 if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ 02728 02729 for ( ; btw; /* Repeat until all data written */ 02730 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { 02731 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ 02732 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ 02733 if (!csect) { /* On the cluster boundary? */ 02734 if (fp->fptr == 0) { /* On the top of the file? */ 02735 clst = fp->sclust; /* Follow from the origin */ 02736 if (clst == 0) /* When no cluster is allocated, */ 02737 clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ 02738 } else { /* Middle or end of the file */ 02739 #if _USE_FASTSEEK 02740 if (fp->cltbl) 02741 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 02742 else 02743 #endif 02744 clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ 02745 } 02746 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ 02747 if (clst == 1) ABORT(fp->fs, FR_INT_ERR); 02748 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 02749 fp->clust = clst; /* Update current cluster */ 02750 if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ 02751 02752 #if FLUSH_ON_NEW_CLUSTER 02753 // We do not need to flush for the first cluster 02754 if (fp->fptr != 0) { 02755 need_sync = true; 02756 } 02757 #endif 02758 } 02759 #if _FS_TINY 02760 if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ 02761 ABORT(fp->fs, FR_DISK_ERR); 02762 #else 02763 if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ 02764 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 02765 ABORT(fp->fs, FR_DISK_ERR); 02766 fp->flag &= ~FA__DIRTY; 02767 } 02768 #endif 02769 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ 02770 if (!sect) ABORT(fp->fs, FR_INT_ERR); 02771 sect += csect; 02772 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ 02773 if (cc) { /* Write maximum contiguous sectors directly */ 02774 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ 02775 cc = fp->fs->csize - csect; 02776 if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) 02777 ABORT(fp->fs, FR_DISK_ERR); 02778 #if _FS_MINIMIZE <= 2 02779 #if _FS_TINY 02780 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 02781 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); 02782 fp->fs->wflag = 0; 02783 } 02784 #else 02785 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 02786 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); 02787 fp->flag &= ~FA__DIRTY; 02788 } 02789 #endif 02790 #endif 02791 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ 02792 #if FLUSH_ON_NEW_SECTOR 02793 need_sync = true; 02794 #endif 02795 continue; 02796 } 02797 #if _FS_TINY 02798 if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ 02799 if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); 02800 fp->fs->winsect = sect; 02801 } 02802 #else 02803 if (fp->dsect != sect) { /* Fill sector cache with file data */ 02804 if (fp->fptr < fp->fsize && 02805 disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) 02806 ABORT(fp->fs, FR_DISK_ERR); 02807 } 02808 #endif 02809 fp->dsect = sect; 02810 } 02811 wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ 02812 if (wcnt > btw) wcnt = btw; 02813 #if _FS_TINY 02814 if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ 02815 ABORT(fp->fs, FR_DISK_ERR); 02816 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ 02817 fp->fs->wflag = 1; 02818 #else 02819 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ 02820 fp->flag |= FA__DIRTY; 02821 #endif 02822 } 02823 02824 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ 02825 fp->flag |= FA__WRITTEN; /* Set file change flag */ 02826 02827 if (need_sync) { 02828 f_sync (fp); 02829 } 02830 02831 LEAVE_FF(fp->fs, FR_OK); 02832 } 02833 02834 02835 02836 02837 /*-----------------------------------------------------------------------*/ 02838 /* Synchronize the File */ 02839 /*-----------------------------------------------------------------------*/ 02840 02841 FRESULT f_sync ( 02842 FIL* fp /* Pointer to the file object */ 02843 ) 02844 { 02845 FRESULT res; 02846 DWORD tm; 02847 BYTE *dir; 02848 02849 02850 res = validate(fp); /* Check validity of the object */ 02851 if (res == FR_OK) { 02852 if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */ 02853 #if !_FS_TINY 02854 if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */ 02855 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 02856 LEAVE_FF(fp->fs, FR_DISK_ERR); 02857 fp->flag &= ~FA__DIRTY; 02858 } 02859 #endif 02860 /* Update the directory entry */ 02861 res = move_window(fp->fs, fp->dir_sect); 02862 if (res == FR_OK) { 02863 dir = fp->dir_ptr; 02864 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ 02865 ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ 02866 st_clust(dir, fp->sclust); /* Update start cluster */ 02867 tm = GET_FATTIME(); /* Update modified time */ 02868 ST_DWORD(dir + DIR_WrtTime, tm); 02869 ST_WORD(dir + DIR_LstAccDate, 0); 02870 fp->flag &= ~FA__WRITTEN; 02871 fp->fs->wflag = 1; 02872 res = sync_fs(fp->fs); 02873 } 02874 } 02875 } 02876 02877 LEAVE_FF(fp->fs, res); 02878 } 02879 02880 #endif /* !_FS_READONLY */ 02881 02882 02883 02884 02885 /*-----------------------------------------------------------------------*/ 02886 /* Close File */ 02887 /*-----------------------------------------------------------------------*/ 02888 02889 FRESULT f_close ( 02890 FIL *fp /* Pointer to the file object to be closed */ 02891 ) 02892 { 02893 FRESULT res; 02894 02895 02896 #if !_FS_READONLY 02897 res = f_sync(fp); /* Flush cached data */ 02898 if (res == FR_OK) 02899 #endif 02900 { 02901 res = validate(fp); /* Lock volume */ 02902 if (res == FR_OK) { 02903 #if _FS_REENTRANT 02904 FATFS *fs = fp->fs; 02905 #endif 02906 #if _FS_LOCK 02907 res = dec_lock(fp->lockid); /* Decrement file open counter */ 02908 if (res == FR_OK) 02909 #endif 02910 fp->fs = 0; /* Invalidate file object */ 02911 #if _FS_REENTRANT 02912 unlock_fs(fs, FR_OK); /* Unlock volume */ 02913 #endif 02914 #if !_FS_TINY && _FS_HEAPBUF 02915 ff_memfree(fp->buf); /* Deallocate buffer */ 02916 #endif 02917 } 02918 } 02919 return res; 02920 } 02921 02922 02923 02924 02925 /*-----------------------------------------------------------------------*/ 02926 /* Change Current Directory or Current Drive, Get Current Directory */ 02927 /*-----------------------------------------------------------------------*/ 02928 02929 #if _FS_RPATH >= 1 02930 #if _VOLUMES >= 2 02931 FRESULT f_chdrive ( 02932 const TCHAR* path /* Drive number */ 02933 ) 02934 { 02935 int vol; 02936 02937 02938 vol = get_ldnumber(&path); 02939 if (vol < 0) return FR_INVALID_DRIVE; 02940 02941 CurrVol = (BYTE)vol; 02942 02943 return FR_OK; 02944 } 02945 #endif 02946 02947 02948 FRESULT f_chdir ( 02949 const TCHAR* path /* Pointer to the directory path */ 02950 ) 02951 { 02952 FRESULT res; 02953 FATFS_DIR dj; 02954 DEFINE_NAMEBUF; 02955 02956 02957 /* Get logical drive number */ 02958 res = find_volume(&dj.fs, &path, 0); 02959 if (res == FR_OK) { 02960 INIT_BUF(dj); 02961 res = follow_path(&dj, path); /* Follow the path */ 02962 FREE_BUF(); 02963 if (res == FR_OK) { /* Follow completed */ 02964 if (!dj.dir) { 02965 dj.fs->cdir = dj.sclust; /* Start directory itself */ 02966 } else { 02967 if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ 02968 dj.fs->cdir = ld_clust(dj.fs, dj.dir); 02969 else 02970 res = FR_NO_PATH; /* Reached but a file */ 02971 } 02972 } 02973 if (res == FR_NO_FILE) res = FR_NO_PATH; 02974 } 02975 02976 LEAVE_FF(dj.fs, res); 02977 } 02978 02979 02980 #if _FS_RPATH >= 2 02981 FRESULT f_getcwd ( 02982 TCHAR* buff, /* Pointer to the directory path */ 02983 UINT len /* Size of path */ 02984 ) 02985 { 02986 FRESULT res; 02987 FATFS_DIR dj; 02988 UINT i, n; 02989 DWORD ccl; 02990 TCHAR *tp; 02991 FILINFO fno; 02992 DEFINE_NAMEBUF; 02993 02994 02995 *buff = 0; 02996 /* Get logical drive number */ 02997 res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ 02998 if (res == FR_OK) { 02999 INIT_BUF(dj); 03000 i = len; /* Bottom of buffer (directory stack base) */ 03001 dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ 03002 while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ 03003 res = dir_sdi(&dj, 1); /* Get parent directory */ 03004 if (res != FR_OK) break; 03005 res = dir_read(&dj, 0); 03006 if (res != FR_OK) break; 03007 dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ 03008 res = dir_sdi(&dj, 0); 03009 if (res != FR_OK) break; 03010 do { /* Find the entry links to the child directory */ 03011 res = dir_read(&dj, 0); 03012 if (res != FR_OK) break; 03013 if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ 03014 res = dir_next(&dj, 0); 03015 } while (res == FR_OK); 03016 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ 03017 if (res != FR_OK) break; 03018 #if _USE_LFN 03019 fno.lfname = buff; 03020 fno.lfsize = i; 03021 #endif 03022 get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ 03023 tp = fno.fname; 03024 #if _USE_LFN 03025 if (*buff) tp = buff; 03026 #endif 03027 for (n = 0; tp[n]; n++) ; 03028 if (i < n + 3) { 03029 res = FR_NOT_ENOUGH_CORE; break; 03030 } 03031 while (n) buff[--i] = tp[--n]; 03032 buff[--i] = '/'; 03033 } 03034 tp = buff; 03035 if (res == FR_OK) { 03036 #if _VOLUMES >= 2 03037 *tp++ = '0' + CurrVol; /* Put drive number */ 03038 *tp++ = ':'; 03039 #endif 03040 if (i == len) { /* Root-directory */ 03041 *tp++ = '/'; 03042 } else { /* Sub-directroy */ 03043 do /* Add stacked path str */ 03044 *tp++ = buff[i++]; 03045 while (i < len); 03046 } 03047 } 03048 *tp = 0; 03049 FREE_BUF(); 03050 } 03051 03052 LEAVE_FF(dj.fs, res); 03053 } 03054 #endif /* _FS_RPATH >= 2 */ 03055 #endif /* _FS_RPATH >= 1 */ 03056 03057 03058 03059 #if _FS_MINIMIZE <= 2 03060 /*-----------------------------------------------------------------------*/ 03061 /* Seek File R/W Pointer */ 03062 /*-----------------------------------------------------------------------*/ 03063 03064 FRESULT f_lseek ( 03065 FIL* fp, /* Pointer to the file object */ 03066 DWORD ofs /* File pointer from top of file */ 03067 ) 03068 { 03069 FRESULT res; 03070 DWORD clst, bcs, nsect, ifptr; 03071 #if _USE_FASTSEEK 03072 DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; 03073 #endif 03074 03075 03076 res = validate(fp); /* Check validity of the object */ 03077 if (res != FR_OK) LEAVE_FF(fp->fs, res); 03078 if (fp->err) /* Check error */ 03079 LEAVE_FF(fp->fs, (FRESULT)fp->err); 03080 03081 #if _USE_FASTSEEK 03082 if (fp->cltbl) { /* Fast seek */ 03083 if (ofs == CREATE_LINKMAP) { /* Create CLMT */ 03084 tbl = fp->cltbl; 03085 tlen = *tbl++; ulen = 2; /* Given table size and required table size */ 03086 cl = fp->sclust; /* Top of the chain */ 03087 if (cl) { 03088 do { 03089 /* Get a fragment */ 03090 tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ 03091 do { 03092 pcl = cl; ncl++; 03093 cl = get_fat(fp->fs, cl); 03094 if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); 03095 if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 03096 } while (cl == pcl + 1); 03097 if (ulen <= tlen) { /* Store the length and top of the fragment */ 03098 *tbl++ = ncl; *tbl++ = tcl; 03099 } 03100 } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ 03101 } 03102 *fp->cltbl = ulen; /* Number of items used */ 03103 if (ulen <= tlen) 03104 *tbl = 0; /* Terminate table */ 03105 else 03106 res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ 03107 03108 } else { /* Fast seek */ 03109 if (ofs > fp->fsize) /* Clip offset at the file size */ 03110 ofs = fp->fsize; 03111 fp->fptr = ofs; /* Set file pointer */ 03112 if (ofs) { 03113 fp->clust = clmt_clust(fp, ofs - 1); 03114 dsc = clust2sect(fp->fs, fp->clust); 03115 if (!dsc) ABORT(fp->fs, FR_INT_ERR); 03116 dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); 03117 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ 03118 #if !_FS_TINY 03119 #if !_FS_READONLY 03120 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ 03121 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 03122 ABORT(fp->fs, FR_DISK_ERR); 03123 fp->flag &= ~FA__DIRTY; 03124 } 03125 #endif 03126 if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ 03127 ABORT(fp->fs, FR_DISK_ERR); 03128 #endif 03129 fp->dsect = dsc; 03130 } 03131 } 03132 } 03133 } else 03134 #endif 03135 03136 /* Normal Seek */ 03137 { 03138 if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ 03139 #if !_FS_READONLY 03140 && !(fp->flag & FA_WRITE) 03141 #endif 03142 ) ofs = fp->fsize; 03143 03144 ifptr = fp->fptr; 03145 fp->fptr = nsect = 0; 03146 if (ofs) { 03147 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ 03148 if (ifptr > 0 && 03149 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ 03150 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ 03151 ofs -= fp->fptr; 03152 clst = fp->clust; 03153 } else { /* When seek to back cluster, */ 03154 clst = fp->sclust; /* start from the first cluster */ 03155 #if !_FS_READONLY 03156 if (clst == 0) { /* If no cluster chain, create a new chain */ 03157 clst = create_chain(fp->fs, 0); 03158 if (clst == 1) ABORT(fp->fs, FR_INT_ERR); 03159 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 03160 fp->sclust = clst; 03161 } 03162 #endif 03163 fp->clust = clst; 03164 } 03165 if (clst != 0) { 03166 while (ofs > bcs) { /* Cluster following loop */ 03167 #if !_FS_READONLY 03168 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ 03169 clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ 03170 if (clst == 0) { /* When disk gets full, clip file size */ 03171 ofs = bcs; break; 03172 } 03173 } else 03174 #endif 03175 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ 03176 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 03177 if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); 03178 fp->clust = clst; 03179 fp->fptr += bcs; 03180 ofs -= bcs; 03181 } 03182 fp->fptr += ofs; 03183 if (ofs % SS(fp->fs)) { 03184 nsect = clust2sect(fp->fs, clst); /* Current sector */ 03185 if (!nsect) ABORT(fp->fs, FR_INT_ERR); 03186 nsect += ofs / SS(fp->fs); 03187 } 03188 } 03189 } 03190 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ 03191 #if !_FS_TINY 03192 #if !_FS_READONLY 03193 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ 03194 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 03195 ABORT(fp->fs, FR_DISK_ERR); 03196 fp->flag &= ~FA__DIRTY; 03197 } 03198 #endif 03199 if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ 03200 ABORT(fp->fs, FR_DISK_ERR); 03201 #endif 03202 fp->dsect = nsect; 03203 } 03204 #if !_FS_READONLY 03205 if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ 03206 fp->fsize = fp->fptr; 03207 fp->flag |= FA__WRITTEN; 03208 } 03209 #endif 03210 } 03211 03212 LEAVE_FF(fp->fs, res); 03213 } 03214 03215 03216 03217 #if _FS_MINIMIZE <= 1 03218 /*-----------------------------------------------------------------------*/ 03219 /* Create a Directory Object */ 03220 /*-----------------------------------------------------------------------*/ 03221 03222 FRESULT f_opendir ( 03223 FATFS_DIR* dp, /* Pointer to directory object to create */ 03224 const TCHAR* path /* Pointer to the directory path */ 03225 ) 03226 { 03227 FRESULT res; 03228 FATFS* fs; 03229 DEFINE_NAMEBUF; 03230 03231 03232 if (!dp) return FR_INVALID_OBJECT; 03233 03234 /* Get logical drive number */ 03235 res = find_volume(&fs, &path, 0); 03236 if (res == FR_OK) { 03237 dp->fs = fs; 03238 INIT_BUF(*dp); 03239 res = follow_path(dp, path); /* Follow the path to the directory */ 03240 FREE_BUF(); 03241 if (res == FR_OK) { /* Follow completed */ 03242 if (dp->dir) { /* It is not the origin directory itself */ 03243 if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ 03244 dp->sclust = ld_clust(fs, dp->dir); 03245 else /* The object is a file */ 03246 res = FR_NO_PATH; 03247 } 03248 if (res == FR_OK) { 03249 dp->id = fs->id; 03250 res = dir_sdi(dp, 0); /* Rewind directory */ 03251 #if _FS_LOCK 03252 if (res == FR_OK) { 03253 if (dp->sclust) { 03254 dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ 03255 if (!dp->lockid) 03256 res = FR_TOO_MANY_OPEN_FILES; 03257 } else { 03258 dp->lockid = 0; /* Root directory need not to be locked */ 03259 } 03260 } 03261 #endif 03262 } 03263 } 03264 if (res == FR_NO_FILE) res = FR_NO_PATH; 03265 } 03266 if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ 03267 03268 LEAVE_FF(fs, res); 03269 } 03270 03271 03272 03273 03274 /*-----------------------------------------------------------------------*/ 03275 /* Close Directory */ 03276 /*-----------------------------------------------------------------------*/ 03277 03278 FRESULT f_closedir ( 03279 FATFS_DIR *dp /* Pointer to the directory object to be closed */ 03280 ) 03281 { 03282 FRESULT res; 03283 03284 03285 res = validate(dp); 03286 if (res == FR_OK) { 03287 #if _FS_REENTRANT 03288 FATFS *fs = dp->fs; 03289 #endif 03290 #if _FS_LOCK 03291 if (dp->lockid) /* Decrement sub-directory open counter */ 03292 res = dec_lock(dp->lockid); 03293 if (res == FR_OK) 03294 #endif 03295 dp->fs = 0; /* Invalidate directory object */ 03296 #if _FS_REENTRANT 03297 unlock_fs(fs, FR_OK); /* Unlock volume */ 03298 #endif 03299 } 03300 return res; 03301 } 03302 03303 03304 03305 03306 /*-----------------------------------------------------------------------*/ 03307 /* Read Directory Entries in Sequence */ 03308 /*-----------------------------------------------------------------------*/ 03309 03310 FRESULT f_readdir ( 03311 FATFS_DIR* dp, /* Pointer to the open directory object */ 03312 FILINFO* fno /* Pointer to file information to return */ 03313 ) 03314 { 03315 FRESULT res; 03316 DEFINE_NAMEBUF; 03317 03318 03319 res = validate(dp); /* Check validity of the object */ 03320 if (res == FR_OK) { 03321 if (!fno) { 03322 res = dir_sdi(dp, 0); /* Rewind the directory object */ 03323 } else { 03324 INIT_BUF(*dp); 03325 res = dir_read(dp, 0); /* Read an item */ 03326 if (res == FR_NO_FILE) { /* Reached end of directory */ 03327 dp->sect = 0; 03328 res = FR_OK; 03329 } 03330 if (res == FR_OK) { /* A valid entry is found */ 03331 get_fileinfo(dp, fno); /* Get the object information */ 03332 res = dir_next(dp, 0); /* Increment index for next */ 03333 if (res == FR_NO_FILE) { 03334 dp->sect = 0; 03335 res = FR_OK; 03336 } 03337 } 03338 FREE_BUF(); 03339 } 03340 } 03341 03342 LEAVE_FF(dp->fs, res); 03343 } 03344 03345 03346 03347 #if _USE_FIND 03348 /*-----------------------------------------------------------------------*/ 03349 /* Find next file */ 03350 /*-----------------------------------------------------------------------*/ 03351 03352 FRESULT f_findnext ( 03353 FATFS_DIR* dp, /* Pointer to the open directory object */ 03354 FILINFO* fno /* Pointer to the file information structure */ 03355 ) 03356 { 03357 FRESULT res; 03358 03359 03360 for (;;) { 03361 res = f_readdir(dp, fno); /* Get a directory item */ 03362 if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ 03363 #if _USE_LFN 03364 if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */ 03365 #endif 03366 if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */ 03367 } 03368 return res; 03369 03370 } 03371 03372 03373 03374 /*-----------------------------------------------------------------------*/ 03375 /* Find first file */ 03376 /*-----------------------------------------------------------------------*/ 03377 03378 FRESULT f_findfirst ( 03379 FATFS_DIR* dp, /* Pointer to the blank directory object */ 03380 FILINFO* fno, /* Pointer to the file information structure */ 03381 const TCHAR* path, /* Pointer to the directory to open */ 03382 const TCHAR* pattern /* Pointer to the matching pattern */ 03383 ) 03384 { 03385 FRESULT res; 03386 03387 03388 dp->pat = pattern; /* Save pointer to pattern string */ 03389 res = f_opendir(dp, path); /* Open the target directory */ 03390 if (res == FR_OK) 03391 res = f_findnext(dp, fno); /* Find the first item */ 03392 return res; 03393 } 03394 03395 #endif /* _USE_FIND */ 03396 03397 03398 03399 #if _FS_MINIMIZE == 0 03400 /*-----------------------------------------------------------------------*/ 03401 /* Get File Status */ 03402 /*-----------------------------------------------------------------------*/ 03403 03404 FRESULT f_stat ( 03405 const TCHAR* path, /* Pointer to the file path */ 03406 FILINFO* fno /* Pointer to file information to return */ 03407 ) 03408 { 03409 FRESULT res; 03410 FATFS_DIR dj; 03411 DEFINE_NAMEBUF; 03412 03413 03414 /* Get logical drive number */ 03415 res = find_volume(&dj.fs, &path, 0); 03416 if (res == FR_OK) { 03417 INIT_BUF(dj); 03418 res = follow_path(&dj, path); /* Follow the file path */ 03419 if (res == FR_OK) { /* Follow completed */ 03420 if (dj.dir) { /* Found an object */ 03421 if (fno) get_fileinfo(&dj, fno); 03422 } else { /* It is root directory */ 03423 res = FR_INVALID_NAME; 03424 } 03425 } 03426 FREE_BUF(); 03427 } 03428 03429 LEAVE_FF(dj.fs, res); 03430 } 03431 03432 03433 03434 #if !_FS_READONLY 03435 /*-----------------------------------------------------------------------*/ 03436 /* Get Number of Free Clusters */ 03437 /*-----------------------------------------------------------------------*/ 03438 03439 FRESULT f_getfree ( 03440 const TCHAR* path, /* Path name of the logical drive number */ 03441 DWORD* nclst, /* Pointer to a variable to return number of free clusters */ 03442 FATFS** fatfs /* Pointer to return pointer to corresponding file system object */ 03443 ) 03444 { 03445 FRESULT res; 03446 FATFS *fs; 03447 DWORD nfree, clst, sect, stat; 03448 UINT i; 03449 BYTE fat, *p; 03450 03451 03452 /* Get logical drive number */ 03453 res = find_volume(fatfs, &path, 0); 03454 fs = *fatfs; 03455 if (res == FR_OK) { 03456 /* If free_clust is valid, return it without full cluster scan */ 03457 if (fs->free_clust <= fs->n_fatent - 2) { 03458 *nclst = fs->free_clust; 03459 } else { 03460 /* Get number of free clusters */ 03461 fat = fs->fs_type; 03462 nfree = 0; 03463 if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */ 03464 clst = 2; 03465 do { 03466 stat = get_fat(fs, clst); 03467 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } 03468 if (stat == 1) { res = FR_INT_ERR; break; } 03469 if (stat == 0) nfree++; 03470 } while (++clst < fs->n_fatent); 03471 } else { /* Sector alighed entries: Accelerate the FAT search. */ 03472 clst = fs->n_fatent; sect = fs->fatbase; 03473 i = 0; p = 0; 03474 do { 03475 if (!i) { 03476 res = move_window(fs, sect++); 03477 if (res != FR_OK) break; 03478 p = fs->win; 03479 i = SS(fs); 03480 } 03481 if (fat == FS_FAT16) { 03482 if (LD_WORD(p) == 0) nfree++; 03483 p += 2; i -= 2; 03484 } else { 03485 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++; 03486 p += 4; i -= 4; 03487 } 03488 } while (--clst); 03489 } 03490 fs->free_clust = nfree; /* free_clust is valid */ 03491 fs->fsi_flag |= 1; /* FSInfo is to be updated */ 03492 *nclst = nfree; /* Return the free clusters */ 03493 } 03494 } 03495 LEAVE_FF(fs, res); 03496 } 03497 03498 03499 03500 03501 /*-----------------------------------------------------------------------*/ 03502 /* Truncate File */ 03503 /*-----------------------------------------------------------------------*/ 03504 03505 FRESULT f_truncate ( 03506 FIL* fp /* Pointer to the file object */ 03507 ) 03508 { 03509 FRESULT res; 03510 DWORD ncl; 03511 03512 03513 res = validate(fp); /* Check validity of the object */ 03514 if (res == FR_OK) { 03515 if (fp->err) { /* Check error */ 03516 res = (FRESULT)fp->err; 03517 } else { 03518 if (!(fp->flag & FA_WRITE)) /* Check access mode */ 03519 res = FR_DENIED; 03520 } 03521 } 03522 if (res == FR_OK) { 03523 if (fp->fsize > fp->fptr) { 03524 fp->fsize = fp->fptr; /* Set file size to current R/W point */ 03525 fp->flag |= FA__WRITTEN; 03526 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ 03527 res = remove_chain(fp->fs, fp->sclust); 03528 fp->sclust = 0; 03529 } else { /* When truncate a part of the file, remove remaining clusters */ 03530 ncl = get_fat(fp->fs, fp->clust); 03531 res = FR_OK; 03532 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; 03533 if (ncl == 1) res = FR_INT_ERR; 03534 if (res == FR_OK && ncl < fp->fs->n_fatent) { 03535 res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); 03536 if (res == FR_OK) res = remove_chain(fp->fs, ncl); 03537 } 03538 } 03539 #if !_FS_TINY 03540 if (res == FR_OK && (fp->flag & FA__DIRTY)) { 03541 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 03542 res = FR_DISK_ERR; 03543 else 03544 fp->flag &= ~FA__DIRTY; 03545 } 03546 #endif 03547 } 03548 if (res != FR_OK) fp->err = (FRESULT)res; 03549 } 03550 03551 LEAVE_FF(fp->fs, res); 03552 } 03553 03554 03555 03556 03557 /*-----------------------------------------------------------------------*/ 03558 /* Delete a File or Directory */ 03559 /*-----------------------------------------------------------------------*/ 03560 03561 FRESULT f_unlink ( 03562 const TCHAR* path /* Pointer to the file or directory path */ 03563 ) 03564 { 03565 FRESULT res; 03566 FATFS_DIR dj, sdj; 03567 BYTE *dir; 03568 DWORD dclst = 0; 03569 DEFINE_NAMEBUF; 03570 03571 03572 /* Get logical drive number */ 03573 res = find_volume(&dj.fs, &path, 1); 03574 if (res == FR_OK) { 03575 INIT_BUF(dj); 03576 res = follow_path(&dj, path); /* Follow the file path */ 03577 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) 03578 res = FR_INVALID_NAME; /* Cannot remove dot entry */ 03579 #if _FS_LOCK 03580 if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */ 03581 #endif 03582 if (res == FR_OK) { /* The object is accessible */ 03583 dir = dj.dir; 03584 if (!dir) { 03585 res = FR_INVALID_NAME; /* Cannot remove the origin directory */ 03586 } else { 03587 if (dir[DIR_Attr] & AM_RDO) 03588 res = FR_DENIED; /* Cannot remove R/O object */ 03589 } 03590 if (res == FR_OK) { 03591 dclst = ld_clust(dj.fs, dir); 03592 if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ 03593 #if _FS_RPATH 03594 if (dclst == dj.fs->cdir) { /* Is it the current directory? */ 03595 res = FR_DENIED; 03596 } else 03597 #endif 03598 { 03599 mem_cpy(&sdj, &dj, sizeof (FATFS_DIR)); /* Open the sub-directory */ 03600 sdj.sclust = dclst; 03601 res = dir_sdi(&sdj, 2); 03602 if (res == FR_OK) { 03603 res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */ 03604 if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */ 03605 if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */ 03606 } 03607 } 03608 } 03609 } 03610 if (res == FR_OK) { 03611 res = dir_remove(&dj); /* Remove the directory entry */ 03612 if (res == FR_OK && dclst) /* Remove the cluster chain if exist */ 03613 res = remove_chain(dj.fs, dclst); 03614 if (res == FR_OK) res = sync_fs(dj.fs); 03615 } 03616 } 03617 FREE_BUF(); 03618 } 03619 03620 LEAVE_FF(dj.fs, res); 03621 } 03622 03623 03624 03625 03626 /*-----------------------------------------------------------------------*/ 03627 /* Create a Directory */ 03628 /*-----------------------------------------------------------------------*/ 03629 03630 FRESULT f_mkdir ( 03631 const TCHAR* path /* Pointer to the directory path */ 03632 ) 03633 { 03634 FRESULT res; 03635 FATFS_DIR dj; 03636 BYTE *dir, n; 03637 DWORD dsc, dcl, pcl, tm = GET_FATTIME(); 03638 DEFINE_NAMEBUF; 03639 03640 03641 /* Get logical drive number */ 03642 res = find_volume(&dj.fs, &path, 1); 03643 if (res == FR_OK) { 03644 INIT_BUF(dj); 03645 res = follow_path(&dj, path); /* Follow the file path */ 03646 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ 03647 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) 03648 res = FR_INVALID_NAME; 03649 if (res == FR_NO_FILE) { /* Can create a new directory */ 03650 dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ 03651 res = FR_OK; 03652 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ 03653 if (dcl == 1) res = FR_INT_ERR; 03654 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; 03655 if (res == FR_OK) /* Flush FAT */ 03656 res = sync_window(dj.fs); 03657 if (res == FR_OK) { /* Initialize the new directory table */ 03658 dsc = clust2sect(dj.fs, dcl); 03659 dir = dj.fs->win; 03660 mem_set(dir, 0, SS(dj.fs)); 03661 mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ 03662 dir[DIR_Name] = '.'; 03663 dir[DIR_Attr] = AM_DIR; 03664 ST_DWORD(dir + DIR_WrtTime, tm); 03665 st_clust(dir, dcl); 03666 mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ 03667 dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust; 03668 if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) 03669 pcl = 0; 03670 st_clust(dir + SZ_DIRE, pcl); 03671 for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ 03672 dj.fs->winsect = dsc++; 03673 dj.fs->wflag = 1; 03674 res = sync_window(dj.fs); 03675 if (res != FR_OK) break; 03676 mem_set(dir, 0, SS(dj.fs)); 03677 } 03678 } 03679 if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ 03680 if (res != FR_OK) { 03681 remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ 03682 } else { 03683 dir = dj.dir; 03684 dir[DIR_Attr] = AM_DIR; /* Attribute */ 03685 ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ 03686 st_clust(dir, dcl); /* Table start cluster */ 03687 dj.fs->wflag = 1; 03688 res = sync_fs(dj.fs); 03689 } 03690 } 03691 FREE_BUF(); 03692 } 03693 03694 LEAVE_FF(dj.fs, res); 03695 } 03696 03697 03698 03699 03700 /*-----------------------------------------------------------------------*/ 03701 /* Change Attribute */ 03702 /*-----------------------------------------------------------------------*/ 03703 03704 FRESULT f_chmod ( 03705 const TCHAR* path, /* Pointer to the file path */ 03706 BYTE attr, /* Attribute bits */ 03707 BYTE mask /* Attribute mask to change */ 03708 ) 03709 { 03710 FRESULT res; 03711 FATFS_DIR dj; 03712 BYTE *dir; 03713 DEFINE_NAMEBUF; 03714 03715 03716 res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */ 03717 if (res == FR_OK) { 03718 INIT_BUF(dj); 03719 res = follow_path(&dj, path); /* Follow the file path */ 03720 FREE_BUF(); 03721 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) 03722 res = FR_INVALID_NAME; 03723 if (res == FR_OK) { 03724 dir = dj.dir; 03725 if (!dir) { /* Is it a root directory? */ 03726 res = FR_INVALID_NAME; 03727 } else { /* File or sub directory */ 03728 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ 03729 dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 03730 dj.fs->wflag = 1; 03731 res = sync_fs(dj.fs); 03732 } 03733 } 03734 } 03735 03736 LEAVE_FF(dj.fs, res); 03737 } 03738 03739 03740 03741 03742 /*-----------------------------------------------------------------------*/ 03743 /* Rename File/Directory */ 03744 /*-----------------------------------------------------------------------*/ 03745 03746 FRESULT f_rename ( 03747 const TCHAR* path_old, /* Pointer to the object to be renamed */ 03748 const TCHAR* path_new /* Pointer to the new name */ 03749 ) 03750 { 03751 FRESULT res; 03752 FATFS_DIR djo, djn; 03753 BYTE buf[21], *dir; 03754 DWORD dw; 03755 DEFINE_NAMEBUF; 03756 03757 03758 /* Get logical drive number of the source object */ 03759 res = find_volume(&djo.fs, &path_old, 1); 03760 if (res == FR_OK) { 03761 djn.fs = djo.fs; 03762 INIT_BUF(djo); 03763 res = follow_path(&djo, path_old); /* Check old object */ 03764 if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) 03765 res = FR_INVALID_NAME; 03766 #if _FS_LOCK 03767 if (res == FR_OK) res = chk_lock(&djo, 2); 03768 #endif 03769 if (res == FR_OK) { /* Old object is found */ 03770 if (!djo.dir) { /* Is root dir? */ 03771 res = FR_NO_FILE; 03772 } else { 03773 mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */ 03774 mem_cpy(&djn, &djo, sizeof (FATFS_DIR)); /* Duplicate the directory object */ 03775 if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ 03776 res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */ 03777 else 03778 res = FR_INVALID_DRIVE; 03779 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ 03780 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ 03781 res = dir_register(&djn); /* Register the new entry */ 03782 if (res == FR_OK) { 03783 /* Start of critical section where any interruption can cause a cross-link */ 03784 dir = djn.dir; /* Copy information about object except name */ 03785 mem_cpy(dir + 13, buf + 2, 19); 03786 dir[DIR_Attr] = buf[0] | AM_ARC; 03787 djo.fs->wflag = 1; 03788 if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */ 03789 dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); 03790 if (!dw) { 03791 res = FR_INT_ERR; 03792 } else { 03793 res = move_window(djo.fs, dw); 03794 dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */ 03795 if (res == FR_OK && dir[1] == '.') { 03796 st_clust(dir, djn.sclust); 03797 djo.fs->wflag = 1; 03798 } 03799 } 03800 } 03801 if (res == FR_OK) { 03802 res = dir_remove(&djo); /* Remove old entry */ 03803 if (res == FR_OK) 03804 res = sync_fs(djo.fs); 03805 } 03806 /* End of critical section */ 03807 } 03808 } 03809 } 03810 } 03811 FREE_BUF(); 03812 } 03813 03814 LEAVE_FF(djo.fs, res); 03815 } 03816 03817 03818 03819 03820 /*-----------------------------------------------------------------------*/ 03821 /* Change Timestamp */ 03822 /*-----------------------------------------------------------------------*/ 03823 03824 FRESULT f_utime ( 03825 const TCHAR* path, /* Pointer to the file/directory name */ 03826 const FILINFO* fno /* Pointer to the time stamp to be set */ 03827 ) 03828 { 03829 FRESULT res; 03830 FATFS_DIR dj; 03831 BYTE *dir; 03832 DEFINE_NAMEBUF; 03833 03834 03835 /* Get logical drive number */ 03836 res = find_volume(&dj.fs, &path, 1); 03837 if (res == FR_OK) { 03838 INIT_BUF(dj); 03839 res = follow_path(&dj, path); /* Follow the file path */ 03840 FREE_BUF(); 03841 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) 03842 res = FR_INVALID_NAME; 03843 if (res == FR_OK) { 03844 dir = dj.dir; 03845 if (!dir) { /* Root directory */ 03846 res = FR_INVALID_NAME; 03847 } else { /* File or sub-directory */ 03848 ST_WORD(dir + DIR_WrtTime, fno->ftime); 03849 ST_WORD(dir + DIR_WrtDate, fno->fdate); 03850 dj.fs->wflag = 1; 03851 res = sync_fs(dj.fs); 03852 } 03853 } 03854 } 03855 03856 LEAVE_FF(dj.fs, res); 03857 } 03858 03859 #endif /* !_FS_READONLY */ 03860 #endif /* _FS_MINIMIZE == 0 */ 03861 #endif /* _FS_MINIMIZE <= 1 */ 03862 #endif /* _FS_MINIMIZE <= 2 */ 03863 03864 03865 03866 03867 #if _USE_LABEL 03868 /*-----------------------------------------------------------------------*/ 03869 /* Get volume label */ 03870 /*-----------------------------------------------------------------------*/ 03871 03872 FRESULT f_getlabel ( 03873 const TCHAR* path, /* Path name of the logical drive number */ 03874 TCHAR* label, /* Pointer to a buffer to return the volume label */ 03875 DWORD* vsn /* Pointer to a variable to return the volume serial number */ 03876 ) 03877 { 03878 FRESULT res; 03879 FATFS_DIR dj; 03880 UINT i, j; 03881 #if _USE_LFN && _LFN_UNICODE 03882 WCHAR w; 03883 #endif 03884 03885 03886 /* Get logical drive number */ 03887 res = find_volume(&dj.fs, &path, 0); 03888 03889 /* Get volume label */ 03890 if (res == FR_OK && label) { 03891 dj.sclust = 0; /* Open root directory */ 03892 res = dir_sdi(&dj, 0); 03893 if (res == FR_OK) { 03894 res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ 03895 if (res == FR_OK) { /* A volume label is exist */ 03896 #if _USE_LFN && _LFN_UNICODE 03897 i = j = 0; 03898 do { 03899 w = (i < 11) ? dj.dir[i++] : ' '; 03900 if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) 03901 w = w << 8 | dj.dir[i++]; 03902 label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ 03903 } while (j < 11); 03904 #else 03905 mem_cpy(label, dj.dir, 11); 03906 #endif 03907 j = 11; 03908 do { 03909 label[j] = 0; 03910 if (!j) break; 03911 } while (label[--j] == ' '); 03912 } 03913 if (res == FR_NO_FILE) { /* No label, return nul string */ 03914 label[0] = 0; 03915 res = FR_OK; 03916 } 03917 } 03918 } 03919 03920 /* Get volume serial number */ 03921 if (res == FR_OK && vsn) { 03922 res = move_window(dj.fs, dj.fs->volbase); 03923 if (res == FR_OK) { 03924 i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; 03925 *vsn = LD_DWORD(&dj.fs->win[i]); 03926 } 03927 } 03928 03929 LEAVE_FF(dj.fs, res); 03930 } 03931 03932 03933 03934 #if !_FS_READONLY 03935 /*-----------------------------------------------------------------------*/ 03936 /* Set volume label */ 03937 /*-----------------------------------------------------------------------*/ 03938 03939 FRESULT f_setlabel ( 03940 const TCHAR* label /* Pointer to the volume label to set */ 03941 ) 03942 { 03943 FRESULT res; 03944 FATFS_DIR dj; 03945 BYTE vn[11]; 03946 UINT i, j, sl; 03947 WCHAR w; 03948 DWORD tm; 03949 03950 03951 /* Get logical drive number */ 03952 res = find_volume(&dj.fs, &label, 1); 03953 if (res) LEAVE_FF(dj.fs, res); 03954 03955 /* Create a volume label in directory form */ 03956 vn[0] = 0; 03957 for (sl = 0; label[sl]; sl++) ; /* Get name length */ 03958 for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */ 03959 if (sl) { /* Create volume label in directory form */ 03960 i = j = 0; 03961 do { 03962 #if _USE_LFN && _LFN_UNICODE 03963 w = ff_convert(ff_wtoupper(label[i++]), 0); 03964 #else 03965 w = (BYTE)label[i++]; 03966 if (IsDBCS1(w)) 03967 w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; 03968 #if _USE_LFN 03969 w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); 03970 #else 03971 if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ 03972 #ifdef _EXCVT 03973 if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ 03974 #else 03975 if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ 03976 #endif 03977 #endif 03978 #endif 03979 if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ 03980 LEAVE_FF(dj.fs, FR_INVALID_NAME); 03981 if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); 03982 vn[j++] = (BYTE)w; 03983 } while (i < sl); 03984 while (j < 11) vn[j++] = ' '; /* Fill remaining name field */ 03985 if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ 03986 } 03987 03988 /* Set volume label */ 03989 dj.sclust = 0; /* Open root directory */ 03990 res = dir_sdi(&dj, 0); 03991 if (res == FR_OK) { 03992 res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ 03993 if (res == FR_OK) { /* A volume label is found */ 03994 if (vn[0]) { 03995 mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ 03996 tm = GET_FATTIME(); 03997 ST_DWORD(dj.dir + DIR_WrtTime, tm); 03998 } else { 03999 dj.dir[0] = DDEM; /* Remove the volume label */ 04000 } 04001 dj.fs->wflag = 1; 04002 res = sync_fs(dj.fs); 04003 } else { /* No volume label is found or error */ 04004 if (res == FR_NO_FILE) { 04005 res = FR_OK; 04006 if (vn[0]) { /* Create volume label as new */ 04007 res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ 04008 if (res == FR_OK) { 04009 mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ 04010 mem_cpy(dj.dir, vn, 11); 04011 dj.dir[DIR_Attr] = AM_VOL; 04012 tm = GET_FATTIME(); 04013 ST_DWORD(dj.dir + DIR_WrtTime, tm); 04014 dj.fs->wflag = 1; 04015 res = sync_fs(dj.fs); 04016 } 04017 } 04018 } 04019 } 04020 } 04021 04022 LEAVE_FF(dj.fs, res); 04023 } 04024 04025 #endif /* !_FS_READONLY */ 04026 #endif /* _USE_LABEL */ 04027 04028 04029 04030 /*-----------------------------------------------------------------------*/ 04031 /* Forward data to the stream directly (available on only tiny cfg) */ 04032 /*-----------------------------------------------------------------------*/ 04033 #if _USE_FORWARD && _FS_TINY 04034 04035 FRESULT f_forward ( 04036 FIL* fp, /* Pointer to the file object */ 04037 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ 04038 UINT btf, /* Number of bytes to forward */ 04039 UINT* bf /* Pointer to number of bytes forwarded */ 04040 ) 04041 { 04042 FRESULT res; 04043 DWORD remain, clst, sect; 04044 UINT rcnt; 04045 BYTE csect; 04046 04047 04048 *bf = 0; /* Clear transfer byte counter */ 04049 04050 res = validate(fp); /* Check validity of the object */ 04051 if (res != FR_OK) LEAVE_FF(fp->fs, res); 04052 if (fp->err) /* Check error */ 04053 LEAVE_FF(fp->fs, (FRESULT)fp->err); 04054 if (!(fp->flag & FA_READ)) /* Check access mode */ 04055 LEAVE_FF(fp->fs, FR_DENIED); 04056 04057 remain = fp->fsize - fp->fptr; 04058 if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ 04059 04060 for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ 04061 fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { 04062 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ 04063 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ 04064 if (!csect) { /* On the cluster boundary? */ 04065 clst = (fp->fptr == 0) ? /* On the top of the file? */ 04066 fp->sclust : get_fat(fp->fs, fp->clust); 04067 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); 04068 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 04069 fp->clust = clst; /* Update current cluster */ 04070 } 04071 } 04072 sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ 04073 if (!sect) ABORT(fp->fs, FR_INT_ERR); 04074 sect += csect; 04075 if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ 04076 ABORT(fp->fs, FR_DISK_ERR); 04077 fp->dsect = sect; 04078 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ 04079 if (rcnt > btf) rcnt = btf; 04080 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); 04081 if (!rcnt) ABORT(fp->fs, FR_INT_ERR); 04082 } 04083 04084 LEAVE_FF(fp->fs, FR_OK); 04085 } 04086 #endif /* _USE_FORWARD */ 04087 04088 04089 04090 #if _USE_MKFS && !_FS_READONLY 04091 /*-----------------------------------------------------------------------*/ 04092 /* Create file system on the logical drive */ 04093 /*-----------------------------------------------------------------------*/ 04094 #define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ 04095 #define N_FATS 1 /* Number of FATs (1 or 2) */ 04096 04097 04098 FRESULT f_mkfs ( 04099 const TCHAR* path, /* Logical drive number */ 04100 BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ 04101 UINT au /* Size of allocation unit in unit of byte or sector */ 04102 ) 04103 { 04104 static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; 04105 static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; 04106 int vol; 04107 BYTE fmt, md, sys, *tbl, pdrv, part; 04108 DWORD n_clst, vs, n, wsect; 04109 UINT i; 04110 DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ 04111 DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ 04112 FATFS *fs; 04113 DSTATUS stat; 04114 #if _USE_TRIM 04115 DWORD eb[2]; 04116 #endif 04117 04118 04119 /* Check mounted drive and clear work area */ 04120 if (sfd > 1) return FR_INVALID_PARAMETER; 04121 vol = get_ldnumber(&path); 04122 if (vol < 0) return FR_INVALID_DRIVE; 04123 fs = FatFs[vol]; 04124 if (!fs) return FR_NOT_ENABLED; 04125 fs->fs_type = 0; 04126 pdrv = LD2PD(vol); /* Physical drive */ 04127 part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ 04128 04129 /* Get disk statics */ 04130 stat = disk_initialize(pdrv); 04131 if (stat & STA_NOINIT) return FR_NOT_READY; 04132 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 04133 #if _MAX_SS != _MIN_SS /* Get disk sector size */ 04134 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) 04135 return FR_DISK_ERR; 04136 #endif 04137 #if _FS_HEAPBUF 04138 if (!fs->win) { 04139 fs->win = (BYTE*)ff_memalloc(SS(fs)); /* Allocate buffer to back window if necessary */ 04140 if (!fs->win) 04141 return FR_NOT_ENOUGH_CORE; 04142 } 04143 #endif 04144 if (_MULTI_PARTITION && part) { 04145 /* Get partition information from partition table in the MBR */ 04146 if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; 04147 if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; 04148 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; 04149 if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ 04150 b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ 04151 n_vol = LD_DWORD(tbl + 12); /* Volume size */ 04152 } else { 04153 /* Create a partition in this function */ 04154 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < ((sfd) ? 64 : 128)) 04155 return FR_DISK_ERR; 04156 b_vol = (sfd) ? 0 : 63; /* Volume start sector */ 04157 n_vol -= b_vol; /* Volume size */ 04158 } 04159 04160 if (au & (au - 1)) au = 0; 04161 if (!au) { /* AU auto selection */ 04162 vs = n_vol / (2000 / (SS(fs) / 512)); 04163 for (i = 0; vs < vst[i]; i++) ; 04164 au = cst[i]; 04165 } 04166 if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */ 04167 if (!au) au = 1; 04168 if (au > 128) au = 128; 04169 04170 /* Pre-compute number of clusters and FAT sub-type */ 04171 n_clst = n_vol / au; 04172 fmt = FS_FAT12; 04173 if (n_clst >= MIN_FAT16) fmt = FS_FAT16; 04174 if (n_clst >= MIN_FAT32) fmt = FS_FAT32; 04175 04176 /* Determine offset and size of FAT structure */ 04177 if (fmt == FS_FAT32) { 04178 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); 04179 n_rsv = 32; 04180 n_dir = 0; 04181 } else { 04182 n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; 04183 n_fat = (n_fat + SS(fs) - 1) / SS(fs); 04184 n_rsv = 1; 04185 n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); 04186 } 04187 b_fat = b_vol + n_rsv; /* FAT area start sector */ 04188 b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ 04189 b_data = b_dir + n_dir; /* Data area start sector */ 04190 if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ 04191 04192 /* Align data start sector to erase block boundary (for flash memory media) */ 04193 if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; 04194 n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ 04195 n = (n - b_data) / N_FATS; 04196 if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ 04197 n_rsv += n; 04198 b_fat += n; 04199 } else { /* FAT12/16: Expand FAT size */ 04200 n_fat += n; 04201 } 04202 04203 /* Determine number of clusters and final check of validity of the FAT sub-type */ 04204 n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; 04205 if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) 04206 || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) 04207 return FR_MKFS_ABORTED; 04208 04209 /* Determine system ID in the partition table */ 04210 if (fmt == FS_FAT32) { 04211 sys = 0x0C; /* FAT32X */ 04212 } else { 04213 if (fmt == FS_FAT12 && n_vol < 0x10000) { 04214 sys = 0x01; /* FAT12(<65536) */ 04215 } else { 04216 sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ 04217 } 04218 } 04219 04220 if (_MULTI_PARTITION && part) { 04221 /* Update system ID in the partition table */ 04222 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; 04223 tbl[4] = sys; 04224 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ 04225 return FR_DISK_ERR; 04226 md = 0xF8; 04227 } else { 04228 if (sfd) { /* No partition table (SFD) */ 04229 md = 0xF0; 04230 } else { /* Create partition table (FDISK) */ 04231 mem_set(fs->win, 0, SS(fs)); 04232 tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */ 04233 tbl[1] = 1; /* Partition start head */ 04234 tbl[2] = 1; /* Partition start sector */ 04235 tbl[3] = 0; /* Partition start cylinder */ 04236 tbl[4] = sys; /* System type */ 04237 tbl[5] = 254; /* Partition end head */ 04238 n = (b_vol + n_vol) / 63 / 255; 04239 tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ 04240 tbl[7] = (BYTE)n; /* End cylinder */ 04241 ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ 04242 ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ 04243 ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ 04244 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */ 04245 return FR_DISK_ERR; 04246 md = 0xF8; 04247 } 04248 } 04249 04250 /* Create BPB in the VBR */ 04251 tbl = fs->win; /* Clear sector */ 04252 mem_set(tbl, 0, SS(fs)); 04253 mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ 04254 i = SS(fs); /* Sector size */ 04255 ST_WORD(tbl + BPB_BytsPerSec, i); 04256 tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ 04257 ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ 04258 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ 04259 i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ 04260 ST_WORD(tbl + BPB_RootEntCnt, i); 04261 if (n_vol < 0x10000) { /* Number of total sectors */ 04262 ST_WORD(tbl + BPB_TotSec16, n_vol); 04263 } else { 04264 ST_DWORD(tbl + BPB_TotSec32, n_vol); 04265 } 04266 tbl[BPB_Media] = md; /* Media descriptor */ 04267 ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ 04268 ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ 04269 ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ 04270 n = GET_FATTIME(); /* Use current time as VSN */ 04271 if (fmt == FS_FAT32) { 04272 ST_DWORD(tbl + BS_VolID32, n); /* VSN */ 04273 ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ 04274 ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ 04275 ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ 04276 ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */ 04277 tbl[BS_DrvNum32] = 0x80; /* Drive number */ 04278 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ 04279 mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ 04280 } else { 04281 ST_DWORD(tbl + BS_VolID, n); /* VSN */ 04282 ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ 04283 tbl[BS_DrvNum] = 0x80; /* Drive number */ 04284 tbl[BS_BootSig] = 0x29; /* Extended boot signature */ 04285 mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ 04286 } 04287 ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ 04288 if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ 04289 return FR_DISK_ERR; 04290 if (fmt == FS_FAT32) /* Write it to the backup VBR if needed (VBR + 6) */ 04291 disk_write(pdrv, tbl, b_vol + 6, 1); 04292 04293 /* Initialize FAT area */ 04294 wsect = b_fat; 04295 for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ 04296 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ 04297 n = md; /* Media descriptor byte */ 04298 if (fmt != FS_FAT32) { 04299 n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; 04300 ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ 04301 } else { 04302 n |= 0xFFFFFF00; 04303 ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ 04304 ST_DWORD(tbl + 4, 0xFFFFFFFF); 04305 ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ 04306 } 04307 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) 04308 return FR_DISK_ERR; 04309 mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ 04310 for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ 04311 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) 04312 return FR_DISK_ERR; 04313 } 04314 } 04315 04316 /* Initialize root directory */ 04317 i = (fmt == FS_FAT32) ? au : (UINT)n_dir; 04318 do { 04319 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) 04320 return FR_DISK_ERR; 04321 } while (--i); 04322 04323 #if _USE_TRIM /* Erase data area if needed */ 04324 { 04325 eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; 04326 disk_ioctl(pdrv, CTRL_TRIM, eb); 04327 } 04328 #endif 04329 04330 /* Create FSINFO if needed */ 04331 if (fmt == FS_FAT32) { 04332 ST_DWORD(tbl + FSI_LeadSig, 0x41615252); 04333 ST_DWORD(tbl + FSI_StrucSig, 0x61417272); 04334 ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ 04335 ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ 04336 ST_WORD(tbl + BS_55AA, 0xAA55); 04337 disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ 04338 disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ 04339 } 04340 04341 return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; 04342 } 04343 04344 04345 04346 #if _MULTI_PARTITION 04347 /*-----------------------------------------------------------------------*/ 04348 /* Create partition table on the physical drive */ 04349 /*-----------------------------------------------------------------------*/ 04350 04351 FRESULT f_fdisk ( 04352 BYTE pdrv, /* Physical drive number */ 04353 const DWORD szt[], /* Pointer to the size table for each partitions */ 04354 void* work /* Pointer to the working buffer */ 04355 ) 04356 { 04357 UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; 04358 BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; 04359 DSTATUS stat; 04360 DWORD sz_disk, sz_part, s_part; 04361 04362 04363 stat = disk_initialize(pdrv); 04364 if (stat & STA_NOINIT) return FR_NOT_READY; 04365 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 04366 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; 04367 04368 /* Determine CHS in the table regardless of the drive geometry */ 04369 for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; 04370 if (n == 256) n--; 04371 e_hd = n - 1; 04372 sz_cyl = 63 * n; 04373 tot_cyl = sz_disk / sz_cyl; 04374 04375 /* Create partition table */ 04376 mem_set(buf, 0, _MAX_SS); 04377 p = buf + MBR_Table; b_cyl = 0; 04378 for (i = 0; i < 4; i++, p += SZ_PTE) { 04379 p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; 04380 if (!p_cyl) continue; 04381 s_part = (DWORD)sz_cyl * b_cyl; 04382 sz_part = (DWORD)sz_cyl * p_cyl; 04383 if (i == 0) { /* Exclude first track of cylinder 0 */ 04384 s_hd = 1; 04385 s_part += 63; sz_part -= 63; 04386 } else { 04387 s_hd = 0; 04388 } 04389 e_cyl = b_cyl + p_cyl - 1; 04390 if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; 04391 04392 /* Set partition table */ 04393 p[1] = s_hd; /* Start head */ 04394 p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ 04395 p[3] = (BYTE)b_cyl; /* Start cylinder */ 04396 p[4] = 0x06; /* System type (temporary setting) */ 04397 p[5] = e_hd; /* End head */ 04398 p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ 04399 p[7] = (BYTE)e_cyl; /* End cylinder */ 04400 ST_DWORD(p + 8, s_part); /* Start sector in LBA */ 04401 ST_DWORD(p + 12, sz_part); /* Partition size */ 04402 04403 /* Next partition */ 04404 b_cyl += p_cyl; 04405 } 04406 ST_WORD(p, 0xAA55); 04407 04408 /* Write it to the MBR */ 04409 return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; 04410 } 04411 04412 04413 #endif /* _MULTI_PARTITION */ 04414 #endif /* _USE_MKFS && !_FS_READONLY */ 04415 04416 04417 04418 04419 #if _USE_STRFUNC 04420 /*-----------------------------------------------------------------------*/ 04421 /* Get a string from the file */ 04422 /*-----------------------------------------------------------------------*/ 04423 04424 TCHAR* f_gets ( 04425 TCHAR* buff, /* Pointer to the string buffer to read */ 04426 int len, /* Size of string buffer (characters) */ 04427 FIL* fp /* Pointer to the file object */ 04428 ) 04429 { 04430 int n = 0; 04431 TCHAR c, *p = buff; 04432 BYTE s[2]; 04433 UINT rc; 04434 04435 04436 while (n < len - 1) { /* Read characters until buffer gets filled */ 04437 #if _USE_LFN && _LFN_UNICODE 04438 #if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ 04439 f_read(fp, s, 1, &rc); 04440 if (rc != 1) break; 04441 c = s[0]; 04442 if (c >= 0x80) { 04443 if (c < 0xC0) continue; /* Skip stray trailer */ 04444 if (c < 0xE0) { /* Two-byte sequence */ 04445 f_read(fp, s, 1, &rc); 04446 if (rc != 1) break; 04447 c = (c & 0x1F) << 6 | (s[0] & 0x3F); 04448 if (c < 0x80) c = '?'; 04449 } else { 04450 if (c < 0xF0) { /* Three-byte sequence */ 04451 f_read(fp, s, 2, &rc); 04452 if (rc != 2) break; 04453 c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); 04454 if (c < 0x800) c = '?'; 04455 } else { /* Reject four-byte sequence */ 04456 c = '?'; 04457 } 04458 } 04459 } 04460 #elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ 04461 f_read(fp, s, 2, &rc); 04462 if (rc != 2) break; 04463 c = s[1] + (s[0] << 8); 04464 #elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ 04465 f_read(fp, s, 2, &rc); 04466 if (rc != 2) break; 04467 c = s[0] + (s[1] << 8); 04468 #else /* Read a character in ANSI/OEM */ 04469 f_read(fp, s, 1, &rc); 04470 if (rc != 1) break; 04471 c = s[0]; 04472 if (IsDBCS1(c)) { 04473 f_read(fp, s, 1, &rc); 04474 if (rc != 1) break; 04475 c = (c << 8) + s[0]; 04476 } 04477 c = ff_convert(c, 1); /* OEM -> Unicode */ 04478 if (!c) c = '?'; 04479 #endif 04480 #else /* Read a character without conversion */ 04481 f_read(fp, s, 1, &rc); 04482 if (rc != 1) break; 04483 c = s[0]; 04484 #endif 04485 if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */ 04486 *p++ = c; 04487 n++; 04488 if (c == '\n') break; /* Break on EOL */ 04489 } 04490 *p = 0; 04491 return n ? buff : 0; /* When no data read (eof or error), return with error. */ 04492 } 04493 04494 04495 04496 04497 #if !_FS_READONLY 04498 #include <stdarg.h> 04499 /*-----------------------------------------------------------------------*/ 04500 /* Put a character to the file */ 04501 /*-----------------------------------------------------------------------*/ 04502 04503 typedef struct { 04504 FIL* fp; 04505 int idx, nchr; 04506 BYTE buf[64]; 04507 } putbuff; 04508 04509 04510 static 04511 void putc_bfd ( 04512 putbuff* pb, 04513 TCHAR c 04514 ) 04515 { 04516 UINT bw; 04517 int i; 04518 04519 04520 if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ 04521 putc_bfd(pb, '\r'); 04522 04523 i = pb->idx; /* Buffer write index (-1:error) */ 04524 if (i < 0) return; 04525 04526 #if _USE_LFN && _LFN_UNICODE 04527 #if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ 04528 if (c < 0x80) { /* 7-bit */ 04529 pb->buf[i++] = (BYTE)c; 04530 } else { 04531 if (c < 0x800) { /* 11-bit */ 04532 pb->buf[i++] = (BYTE)(0xC0 | c >> 6); 04533 } else { /* 16-bit */ 04534 pb->buf[i++] = (BYTE)(0xE0 | c >> 12); 04535 pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); 04536 } 04537 pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); 04538 } 04539 #elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ 04540 pb->buf[i++] = (BYTE)(c >> 8); 04541 pb->buf[i++] = (BYTE)c; 04542 #elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ 04543 pb->buf[i++] = (BYTE)c; 04544 pb->buf[i++] = (BYTE)(c >> 8); 04545 #else /* Write a character in ANSI/OEM */ 04546 c = ff_convert(c, 0); /* Unicode -> OEM */ 04547 if (!c) c = '?'; 04548 if (c >= 0x100) 04549 pb->buf[i++] = (BYTE)(c >> 8); 04550 pb->buf[i++] = (BYTE)c; 04551 #endif 04552 #else /* Write a character without conversion */ 04553 pb->buf[i++] = (BYTE)c; 04554 #endif 04555 04556 if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ 04557 f_write(pb->fp, pb->buf, (UINT)i, &bw); 04558 i = (bw == (UINT)i) ? 0 : -1; 04559 } 04560 pb->idx = i; 04561 pb->nchr++; 04562 } 04563 04564 04565 04566 int f_putc ( 04567 TCHAR c, /* A character to be output */ 04568 FIL* fp /* Pointer to the file object */ 04569 ) 04570 { 04571 putbuff pb; 04572 UINT nw; 04573 04574 04575 pb.fp = fp; /* Initialize output buffer */ 04576 pb.nchr = pb.idx = 0; 04577 04578 putc_bfd(&pb, c); /* Put a character */ 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 string to the file */ 04591 /*-----------------------------------------------------------------------*/ 04592 04593 int f_puts ( 04594 const TCHAR* str, /* Pointer to the string to be output */ 04595 FIL* fp /* Pointer to the file object */ 04596 ) 04597 { 04598 putbuff pb; 04599 UINT nw; 04600 04601 04602 pb.fp = fp; /* Initialize output buffer */ 04603 pb.nchr = pb.idx = 0; 04604 04605 while (*str) /* Put the string */ 04606 putc_bfd(&pb, *str++); 04607 04608 if ( pb.idx >= 0 /* Flush buffered characters to the file */ 04609 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK 04610 && (UINT)pb.idx == nw) return pb.nchr; 04611 return EOF; 04612 } 04613 04614 04615 04616 04617 /*-----------------------------------------------------------------------*/ 04618 /* Put a formatted string to the file */ 04619 /*-----------------------------------------------------------------------*/ 04620 04621 int f_printf ( 04622 FIL* fp, /* Pointer to the file object */ 04623 const TCHAR* fmt, /* Pointer to the format string */ 04624 ... /* Optional arguments... */ 04625 ) 04626 { 04627 va_list arp; 04628 BYTE f, r; 04629 UINT nw, i, j, w; 04630 DWORD v; 04631 TCHAR c, d, s[16], *p; 04632 putbuff pb; 04633 04634 04635 pb.fp = fp; /* Initialize output buffer */ 04636 pb.nchr = pb.idx = 0; 04637 04638 va_start(arp, fmt); 04639 04640 for (;;) { 04641 c = *fmt++; 04642 if (c == 0) break; /* End of string */ 04643 if (c != '%') { /* Non escape character */ 04644 putc_bfd(&pb, c); 04645 continue; 04646 } 04647 w = f = 0; 04648 c = *fmt++; 04649 if (c == '0') { /* Flag: '0' padding */ 04650 f = 1; c = *fmt++; 04651 } else { 04652 if (c == '-') { /* Flag: left justified */ 04653 f = 2; c = *fmt++; 04654 } 04655 } 04656 while (IsDigit(c)) { /* Precision */ 04657 w = w * 10 + c - '0'; 04658 c = *fmt++; 04659 } 04660 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ 04661 f |= 4; c = *fmt++; 04662 } 04663 if (!c) break; 04664 d = c; 04665 if (IsLower(d)) d -= 0x20; 04666 switch (d) { /* Type is... */ 04667 case 'S' : /* String */ 04668 p = va_arg(arp, TCHAR*); 04669 for (j = 0; p[j]; j++) ; 04670 if (!(f & 2)) { 04671 while (j++ < w) putc_bfd(&pb, ' '); 04672 } 04673 while (*p) putc_bfd(&pb, *p++); 04674 while (j++ < w) putc_bfd(&pb, ' '); 04675 continue; 04676 case 'C' : /* Character */ 04677 putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; 04678 case 'B' : /* Binary */ 04679 r = 2; break; 04680 case 'O' : /* Octal */ 04681 r = 8; break; 04682 case 'D' : /* Signed decimal */ 04683 case 'U' : /* Unsigned decimal */ 04684 r = 10; break; 04685 case 'X' : /* Hexdecimal */ 04686 r = 16; break; 04687 default: /* Unknown type (pass-through) */ 04688 putc_bfd(&pb, c); continue; 04689 } 04690 04691 /* Get an argument and put it in numeral */ 04692 v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); 04693 if (d == 'D' && (v & 0x80000000)) { 04694 v = 0 - v; 04695 f |= 8; 04696 } 04697 i = 0; 04698 do { 04699 d = (TCHAR)(v % r); v /= r; 04700 if (d > 9) d += (c == 'x') ? 0x27 : 0x07; 04701 s[i++] = d + '0'; 04702 } while (v && i < sizeof s / sizeof s[0]); 04703 if (f & 8) s[i++] = '-'; 04704 j = i; d = (f & 1) ? '0' : ' '; 04705 while (!(f & 2) && j++ < w) putc_bfd(&pb, d); 04706 do putc_bfd(&pb, s[--i]); while (i); 04707 while (j++ < w) putc_bfd(&pb, d); 04708 } 04709 04710 va_end(arp); 04711 04712 if ( pb.idx >= 0 /* Flush buffered characters to the file */ 04713 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK 04714 && (UINT)pb.idx == nw) return pb.nchr; 04715 return EOF; 04716 } 04717 04718 #endif /* !_FS_READONLY */ 04719 #endif /* _USE_STRFUNC */
Generated on Thu Jul 14 2022 14:36:15 by
