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