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