1 /*----------------------------------------------------------------------------/
2 / Petit FatFs - FAT file system module R0.02a (C)ChaN, 2010
3 /-----------------------------------------------------------------------------/
4 / Petit FatFs module is an open source software to implement FAT file system to
5 / small embedded systems. This is a free software and is opened for education,
6 / research and commercial developments under license policy of following trems.
8 / Copyright (C) 2010, ChaN, all right reserved.
10 / * The Petit FatFs module is a free software and there is NO WARRANTY.
11 / * No restriction on use. You can use, modify and redistribute it for
12 / personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
13 / * Redistributions of source code must retain the above copyright notice.
15 /-----------------------------------------------------------------------------/
16 / Jun 15,'09 R0.01a First release. (Branched from FatFs R0.07b.)
18 / Dec 14,'09 R0.02 Added multiple code page support.
19 / Added write funciton.
20 / Changed stream read mode interface.
21 / Dec 07,'10 R0.02a Added some configuration options.
22 / Fixed fails to open objects with DBCS character.
23 /----------------------------------------------------------------------------*/
25 #include "pff.h" /* Petit FatFs configurations and declarations */
26 #include "diskio.h" /* Declarations of low level disk I/O functions */
30 /*--------------------------------------------------------------------------
32 Module Private Definitions
34 ---------------------------------------------------------------------------*/
38 #define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
40 #define LD_CLUST(dir) LD_WORD(dir+DIR_FstClusLO)
44 /*--------------------------------------------------------*/
45 /* DBCS code ranges and SBCS extend char conversion table */
47 #if _CODE_PAGE == 932 /* Japanese Shift-JIS */
48 #define _DF1S 0x81 /* DBC 1st byte range 1 start */
49 #define _DF1E 0x9F /* DBC 1st byte range 1 end */
50 #define _DF2S 0xE0 /* DBC 1st byte range 2 start */
51 #define _DF2E 0xFC /* DBC 1st byte range 2 end */
52 #define _DS1S 0x40 /* DBC 2nd byte range 1 start */
53 #define _DS1E 0x7E /* DBC 2nd byte range 1 end */
54 #define _DS2S 0x80 /* DBC 2nd byte range 2 start */
55 #define _DS2E 0xFC /* DBC 2nd byte range 2 end */
57 #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
65 #elif _CODE_PAGE == 949 /* Korean */
75 #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
83 #elif _CODE_PAGE == 437 /* U.S. (OEM) */
85 #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, \
86 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, \
87 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, \
88 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}
90 #elif _CODE_PAGE == 720 /* Arabic (OEM) */
92 #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, \
93 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, \
94 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, \
95 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}
97 #elif _CODE_PAGE == 737 /* Greek (OEM) */
99 #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, \
100 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, \
101 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, \
102 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}
104 #elif _CODE_PAGE == 775 /* Baltic (OEM) */
106 #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, \
107 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, \
108 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, \
109 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}
111 #elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
113 #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, \
114 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, \
115 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, \
116 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}
118 #elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
120 #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, \
121 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, \
122 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, \
123 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}
125 #elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
127 #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, \
128 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, \
129 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, \
130 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}
132 #elif _CODE_PAGE == 857 /* Turkish (OEM) */
134 #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, \
135 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, \
136 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, \
137 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}
139 #elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
141 #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, \
142 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, \
143 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, \
144 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}
146 #elif _CODE_PAGE == 862 /* Hebrew (OEM) */
148 #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, \
149 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, \
150 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, \
151 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}
153 #elif _CODE_PAGE == 866 /* Russian (OEM) */
155 #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, \
156 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, \
157 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, \
158 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}
160 #elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
162 #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, \
163 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, \
164 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, \
165 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}
167 #elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
169 #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, \
170 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, \
171 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, \
172 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}
174 #elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
176 #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, \
177 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, \
178 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, \
179 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}
181 #elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
183 #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, \
184 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, \
185 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, \
186 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}
188 #elif _CODE_PAGE == 1253 /* Greek (Windows) */
190 #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, \
191 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, \
192 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, \
193 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}
195 #elif _CODE_PAGE == 1254 /* Turkish (Windows) */
197 #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, \
198 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, \
199 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, \
200 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}
202 #elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
204 #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, \
205 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, \
206 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, \
207 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}
209 #elif _CODE_PAGE == 1256 /* Arabic (Windows) */
211 #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, \
212 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, \
213 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, \
214 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}
216 #elif _CODE_PAGE == 1257 /* Baltic (Windows) */
218 #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, \
219 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, \
220 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, \
221 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}
223 #elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
225 #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, \
226 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, \
227 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, \
228 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}
230 #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
234 #error Unknown code page
240 /* Character code support macros */
242 #define IsUpper(c) (((c)>='A')&&((c)<='Z'))
243 #define IsLower(c) (((c)>='a')&&((c)<='z'))
245 #if _DF1S /* DBCS configuration */
247 #ifdef _DF2S /* Two 1st byte areas */
248 #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
249 #else /* One 1st byte area */
250 #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
253 #ifdef _DS3S /* Three 2nd byte areas */
254 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
255 #else /* Two 2nd byte areas */
256 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
259 #else /* SBCS configuration */
267 /* FatFs refers the members in the FAT structures with byte offset instead
268 / of structure member because there are incompatibility of the packing option
269 / between various compilers. */
273 #define BPB_BytsPerSec 11
274 #define BPB_SecPerClus 13
275 #define BPB_RsvdSecCnt 14
276 #define BPB_NumFATs 16
277 #define BPB_RootEntCnt 17
278 #define BPB_TotSec16 19
280 #define BPB_FATSz16 22
281 #define BPB_SecPerTrk 24
282 #define BPB_NumHeads 26
283 #define BPB_HiddSec 28
284 #define BPB_TotSec32 32
288 #define BS_BootSig 38
291 #define BS_FilSysType 54
293 #define BPB_FATSz32 36
294 #define BPB_ExtFlags 40
296 #define BPB_RootClus 44
297 #define BPB_FSInfo 48
298 #define BPB_BkBootSec 50
299 #define BS_DrvNum32 64
300 #define BS_BootSig32 66
301 #define BS_VolID32 67
302 #define BS_VolLab32 71
303 #define BS_FilSysType32 82
305 #define MBR_Table 446
310 #define DIR_CrtTime 14
311 #define DIR_CrtDate 16
312 #define DIR_FstClusHI 20
313 #define DIR_WrtTime 22
314 #define DIR_WrtDate 24
315 #define DIR_FstClusLO 26
316 #define DIR_FileSize 28
320 /*--------------------------------------------------------------------------
324 ---------------------------------------------------------------------------*/
328 FATFS
*FatFs
; /* Pointer to the file system object (logical drive) */
333 void mem_set (void* dst
, int val
, int cnt
) {
334 char *d
= (char*)dst
;
335 while (cnt
--) *d
++ = (char)val
;
338 /* Compare memory to memory */
340 int mem_cmp (const void* dst
, const void* src
, int cnt
) {
341 const char *d
= (const char *)dst
, *s
= (const char *)src
;
343 while (cnt
-- && (r
= *d
++ - *s
++) == 0) ;
349 /*-----------------------------------------------------------------------*/
350 /* FAT access - Read value of a FAT entry */
351 /*-----------------------------------------------------------------------*/
354 CLUST
get_fat ( /* 1:IO error, Else:Cluster status */
355 CLUST clst
/* Cluster# to get the link information */
363 if (clst
< 2 || clst
>= fs
->n_fatent
) /* Range check */
366 switch (fs
->fs_type
) {
369 bc
= (WORD
)clst
; bc
+= bc
/ 2;
370 ofs
= bc
% 512; bc
/= 512;
372 if (disk_readp(buf
, fs
->fatbase
+ bc
, ofs
, 2)) break;
374 if (disk_readp(buf
, fs
->fatbase
+ bc
, 511, 1)) break;
375 if (disk_readp(buf
+1, fs
->fatbase
+ bc
+ 1, 0, 1)) break;
378 return (clst
& 1) ?
(wc
>> 4) : (wc
& 0xFFF);
381 if (disk_readp(buf
, fs
->fatbase
+ clst
/ 256, (WORD
)(((WORD
)clst
% 256) * 2), 2)) break;
385 if (disk_readp(buf
, fs
->fatbase
+ clst
/ 128, (WORD
)(((WORD
)clst
% 128) * 4), 4)) break;
386 return LD_DWORD(buf
) & 0x0FFFFFFF;
390 return 1; /* An error occured at the disk I/O layer */
396 /*-----------------------------------------------------------------------*/
397 /* Get sector# from cluster# */
398 /*-----------------------------------------------------------------------*/
401 DWORD
clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
402 CLUST clst
/* Cluster# to be converted */
409 if (clst
>= (fs
->n_fatent
- 2)) return 0; /* Invalid cluster# */
410 return (DWORD
)clst
* fs
->csize
+ fs
->database
;
416 /*-----------------------------------------------------------------------*/
417 /* Directory handling - Rewind directory index */
418 /*-----------------------------------------------------------------------*/
422 DIR *dj
/* Pointer to directory object */
431 if (clst
== 1 || clst
>= fs
->n_fatent
) /* Check start cluster range */
433 if (_FS_FAT32
&& !clst
&& fs
->fs_type
== FS_FAT32
) /* Replace cluster# 0 with root cluster# if in FAT32 */
434 clst
= (CLUST
)fs
->dirbase
;
435 dj
->clust
= clst
; /* Current cluster */
436 dj
->sect
= clst ?
clust2sect(clst
) : fs
->dirbase
; /* Current sector */
438 return FR_OK
; /* Seek succeeded */
444 /*-----------------------------------------------------------------------*/
445 /* Directory handling - Move directory index next */
446 /*-----------------------------------------------------------------------*/
449 FRESULT
dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table */
450 DIR *dj
/* Pointer to directory object */
459 if (!i
|| !dj
->sect
) /* Report EOT when index has reached 65535 */
462 if (!(i
% 16)) { /* Sector changed? */
463 dj
->sect
++; /* Next sector */
465 if (dj
->clust
== 0) { /* Static table */
466 if (i
>= fs
->n_rootdir
) /* Report EOT when end of table */
469 else { /* Dynamic table */
470 if (((i
/ 16) & (fs
->csize
-1)) == 0) { /* Cluster changed? */
471 clst
= get_fat(dj
->clust
); /* Get next cluster */
472 if (clst
<= 1) return FR_DISK_ERR
;
473 if (clst
>= fs
->n_fatent
) /* When it reached end of dynamic table */
474 return FR_NO_FILE
; /* Report EOT */
475 dj
->clust
= clst
; /* Initialize data for new cluster */
476 dj
->sect
= clust2sect(clst
);
489 /*-----------------------------------------------------------------------*/
490 /* Directory handling - Find an object in the directory */
491 /*-----------------------------------------------------------------------*/
495 DIR *dj
, /* Pointer to the directory object linked to the file name */
496 BYTE
*dir
/* 32-byte working buffer */
503 res
= dir_rewind(dj
); /* Rewind directory object */
504 if (res
!= FR_OK
) return res
;
507 res
= disk_readp(dir
, dj
->sect
, (WORD
)((dj
->index
% 16) * 32), 32) /* Read an entry */
508 ? FR_DISK_ERR
: FR_OK
;
509 if (res
!= FR_OK
) break;
510 c
= dir
[DIR_Name
]; /* First character */
511 if (c
== 0) { res
= FR_NO_FILE
; break; } /* Reached to end of table */
512 if (!(dir
[DIR_Attr
] & AM_VOL
) && !mem_cmp(dir
, dj
->fn
, 11)) /* Is it a valid entry? */
514 res
= dir_next(dj
); /* Next entry */
515 } while (res
== FR_OK
);
523 /*-----------------------------------------------------------------------*/
524 /* Read an object from the directory */
525 /*-----------------------------------------------------------------------*/
529 DIR *dj
, /* Pointer to the directory object to store read object name */
530 BYTE
*dir
/* 32-byte working buffer */
539 res
= disk_readp(dir
, dj
->sect
, (WORD
)((dj
->index
% 16) * 32), 32) /* Read an entry */
540 ? FR_DISK_ERR
: FR_OK
;
541 if (res
!= FR_OK
) break;
543 if (c
== 0) { res
= FR_NO_FILE
; break; } /* Reached to end of table */
544 a
= dir
[DIR_Attr
] & AM_MASK
;
545 if (c
!= 0xE5 && c
!= '.' && !(a
& AM_VOL
)) /* Is it a valid entry? */
547 res
= dir_next(dj
); /* Next entry */
548 if (res
!= FR_OK
) break;
551 if (res
!= FR_OK
) dj
->sect
= 0;
559 /*-----------------------------------------------------------------------*/
560 /* Pick a segment and create the object name in directory form */
561 /*-----------------------------------------------------------------------*/
564 static const BYTE cvt
[] = _EXCVT
;
568 FRESULT
create_name (
569 DIR *dj
, /* Pointer to the directory object */
570 const char **path
/* Pointer to pointer to the segment in the path string */
573 BYTE c
, d
, ni
, si
, i
, *sfn
;
576 /* Create file name in directory form */
578 mem_set(sfn
, ' ', 11);
583 if (c
<= ' ' || c
== '/') break; /* Break on end of segment */
584 if (c
== '.' || i
>= ni
) {
585 if (ni
!= 8 || c
!= '.') break;
590 if (c
>= 0x80) /* To upper extended char (SBCS) */
593 if (IsDBCS1(c
) && i
< ni
- 1) { /* DBC 1st byte? */
594 d
= p
[si
++]; /* Get 2nd byte */
597 } else { /* Single byte code */
598 if (IsLower(c
)) c
-= 0x20; /* toupper */
602 *path
= &p
[si
]; /* Rerurn pointer to the next segment */
604 sfn
[11] = (c
<= ' ') ?
1 : 0; /* Set last segment flag if end of path */
612 /*-----------------------------------------------------------------------*/
613 /* Get file information from directory entry */
614 /*-----------------------------------------------------------------------*/
617 void get_fileinfo ( /* No return code */
618 DIR *dj
, /* Pointer to the directory object */
619 BYTE
*dir
, /* 32-byte working buffer */
620 FILINFO
*fno
/* Pointer to store the file information */
629 for (i
= 0; i
< 8; i
++) { /* Copy file name body */
632 if (c
== 0x05) c
= 0xE5;
635 if (dir
[8] != ' ') { /* Copy file name extension */
637 for (i
= 8; i
< 11; i
++) {
643 fno
->fattrib
= dir
[DIR_Attr
]; /* Attribute */
644 fno
->fsize
= LD_DWORD(dir
+DIR_FileSize
); /* Size */
645 fno
->fdate
= LD_WORD(dir
+DIR_WrtDate
); /* Date */
646 fno
->ftime
= LD_WORD(dir
+DIR_WrtTime
); /* Time */
650 #endif /* _USE_DIR */
654 /*-----------------------------------------------------------------------*/
655 /* Follow a file path */
656 /*-----------------------------------------------------------------------*/
659 FRESULT
follow_path ( /* FR_OK(0): successful, !=0: error code */
660 DIR *dj
, /* Directory object to return last directory and found object */
661 BYTE
*dir
, /* 32-byte working buffer */
662 const char *path
/* Full-path string to find a file or directory */
668 while (*path
== ' ') path
++; /* Skip leading spaces */
669 if (*path
== '/') path
++; /* Strip heading separator */
670 dj
->sclust
= 0; /* Set start directory (always root dir) */
672 if ((BYTE
)*path
<= ' ') { /* Null path means the root directory */
673 res
= dir_rewind(dj
);
676 } else { /* Follow path */
678 res
= create_name(dj
, &path
); /* Get a segment */
679 if (res
!= FR_OK
) break;
680 res
= dir_find(dj
, dir
); /* Find it */
681 if (res
!= FR_OK
) { /* Could not find the object */
682 if (res
== FR_NO_FILE
&& !*(dj
->fn
+11))
686 if (*(dj
->fn
+11)) break; /* Last segment match. Function completed. */
687 if (!(dir
[DIR_Attr
] & AM_DIR
)) { /* Cannot follow because it is a file */
688 res
= FR_NO_PATH
; break;
690 dj
->sclust
= LD_CLUST(dir
);
700 /*-----------------------------------------------------------------------*/
701 /* Check a sector if it is an FAT boot record */
702 /*-----------------------------------------------------------------------*/
705 BYTE
check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
706 BYTE
*buf
, /* Working buffer */
707 DWORD sect
/* Sector# (lba) to check if it is an FAT boot record or not */
710 if (disk_readp(buf
, sect
, 510, 2)) /* Read the boot sector */
712 if (LD_WORD(buf
) != 0xAA55) /* Check record signature */
715 if (!disk_readp(buf
, sect
, BS_FilSysType
, 2) && LD_WORD(buf
) == 0x4146) /* Check FAT12/16 */
717 if (_FS_FAT32
&& !disk_readp(buf
, sect
, BS_FilSysType32
, 2) && LD_WORD(buf
) == 0x4146) /* Check FAT32 */
725 /*--------------------------------------------------------------------------
729 --------------------------------------------------------------------------*/
733 /*-----------------------------------------------------------------------*/
734 /* Mount/Unmount a Locical Drive */
735 /*-----------------------------------------------------------------------*/
738 FATFS
*fs
/* Pointer to new file system object (NULL: Unmount) */
742 DWORD bsect
, fsize
, tsect
, mclst
;
746 if (!fs
) return FR_OK
; /* Unregister fs object */
748 if (disk_initialize() & STA_NOINIT
) /* Check if the drive is ready or not */
751 /* Search FAT partition on the drive */
753 fmt
= check_fs(buf
, bsect
); /* Check sector 0 as an SFD format */
754 if (fmt
== 1) { /* Not an FAT boot record, it may be FDISK format */
755 /* Check a partition listed in top of the partition table */
756 if (disk_readp(buf
, bsect
, MBR_Table
, 16)) { /* 1st partition entry */
759 if (buf
[4]) { /* Is the partition existing? */
760 bsect
= LD_DWORD(&buf
[8]); /* Partition offset in LBA */
761 fmt
= check_fs(buf
, bsect
); /* Check the partition */
765 if (fmt
== 3) return FR_DISK_ERR
;
766 if (fmt
) return FR_NO_FILESYSTEM
; /* No valid FAT patition is found */
768 /* Initialize the file system object */
769 if (disk_readp(buf
, bsect
, 13, sizeof(buf
))) return FR_DISK_ERR
;
771 fsize
= LD_WORD(buf
+BPB_FATSz16
-13); /* Number of sectors per FAT */
772 if (!fsize
) fsize
= LD_DWORD(buf
+BPB_FATSz32
-13);
774 fsize
*= buf
[BPB_NumFATs
-13]; /* Number of sectors in FAT area */
775 fs
->fatbase
= bsect
+ LD_WORD(buf
+BPB_RsvdSecCnt
-13); /* FAT start sector (lba) */
776 fs
->csize
= buf
[BPB_SecPerClus
-13]; /* Number of sectors per cluster */
777 fs
->n_rootdir
= LD_WORD(buf
+BPB_RootEntCnt
-13); /* Nmuber of root directory entries */
778 tsect
= LD_WORD(buf
+BPB_TotSec16
-13); /* Number of sectors on the file system */
779 if (!tsect
) tsect
= LD_DWORD(buf
+BPB_TotSec32
-13);
780 mclst
= (tsect
/* Last cluster# + 1 */
781 - LD_WORD(buf
+BPB_RsvdSecCnt
-13) - fsize
- fs
->n_rootdir
/ 16
783 fs
->n_fatent
= (CLUST
)mclst
;
785 fmt
= FS_FAT16
; /* Determine the FAT sub type */
786 if (mclst
< 0xFF7) /* Number of clusters < 0xFF5 */
790 return FR_NO_FILESYSTEM
;
792 if (mclst
>= 0xFFF7) /* Number of clusters >= 0xFFF5 */
796 return FR_NO_FILESYSTEM
;
799 fs
->fs_type
= fmt
; /* FAT sub-type */
800 if (_FS_FAT32
&& fmt
== FS_FAT32
)
801 fs
->dirbase
= LD_DWORD(buf
+(BPB_RootClus
-13)); /* Root directory start cluster */
803 fs
->dirbase
= fs
->fatbase
+ fsize
; /* Root directory start sector (lba) */
804 fs
->database
= fs
->fatbase
+ fsize
+ fs
->n_rootdir
/ 16; /* Data start sector (lba) */
815 /*-----------------------------------------------------------------------*/
816 /* Open or Create a File */
817 /*-----------------------------------------------------------------------*/
820 const char *path
/* Pointer to the file name */
825 BYTE sp
[12], dir
[32];
829 if (!fs
) /* Check file system */
830 return FR_NOT_ENABLED
;
834 res
= follow_path(&dj
, dir
, path
); /* Follow the file path */
835 if (res
!= FR_OK
) return res
; /* Follow failed */
836 if (!dir
[0] || (dir
[DIR_Attr
] & AM_DIR
)) /* It is a directory */
839 fs
->org_clust
= LD_CLUST(dir
); /* File start cluster */
840 fs
->fsize
= LD_DWORD(dir
+DIR_FileSize
); /* File size */
841 fs
->fptr
= 0; /* File pointer */
842 fs
->flag
= FA_OPENED
;
850 /*-----------------------------------------------------------------------*/
852 /*-----------------------------------------------------------------------*/
856 void* buff
, /* Pointer to the read buffer (NULL:Forward data to the stream)*/
857 WORD btr
, /* Number of bytes to read */
858 WORD
* br
/* Pointer to number of bytes read */
865 BYTE cs
, *rbuff
= buff
;
870 if (!fs
) return FR_NOT_ENABLED
; /* Check file system */
871 if (!(fs
->flag
& FA_OPENED
)) /* Check if opened */
872 return FR_NOT_OPENED
;
874 remain
= fs
->fsize
- fs
->fptr
;
875 if (btr
> remain
) btr
= (WORD
)remain
; /* Truncate btr by remaining bytes */
877 while (btr
) { /* Repeat until all data transferred */
878 if ((fs
->fptr
% 512) == 0) { /* On the sector boundary? */
879 cs
= (BYTE
)(fs
->fptr
/ 512 & (fs
->csize
- 1)); /* Sector offset in the cluster */
880 if (!cs
) { /* On the cluster boundary? */
881 clst
= (fs
->fptr
== 0) ?
/* On the top of the file? */
882 fs
->org_clust
: get_fat(fs
->curr_clust
);
883 if (clst
<= 1) goto fr_abort
;
884 fs
->curr_clust
= clst
; /* Update current cluster */
886 sect
= clust2sect(fs
->curr_clust
); /* Get current sector */
887 if (!sect
) goto fr_abort
;
888 fs
->dsect
= sect
+ cs
;
890 rcnt
= (WORD
)(512 - (fs
->fptr
% 512)); /* Get partial sector data from sector buffer */
891 if (rcnt
> btr
) rcnt
= btr
;
892 dr
= disk_readp(!buff ?
0 : rbuff
, fs
->dsect
, (WORD
)(fs
->fptr
% 512), rcnt
);
893 if (dr
) goto fr_abort
;
894 fs
->fptr
+= rcnt
; rbuff
+= rcnt
; /* Update pointers and counters */
895 btr
-= rcnt
; *br
+= rcnt
;
908 /*-----------------------------------------------------------------------*/
910 /*-----------------------------------------------------------------------*/
914 const void* buff
, /* Pointer to the data to be written */
915 WORD btw
, /* Number of bytes to write (0:Finalize the current write operation) */
916 WORD
* bw
/* Pointer to number of bytes written */
921 const BYTE
*p
= buff
;
928 if (!fs
) return FR_NOT_ENABLED
; /* Check file system */
929 if (!(fs
->flag
& FA_OPENED
)) /* Check if opened */
930 return FR_NOT_OPENED
;
932 if (!btw
) { /* Finalize request */
933 if ((fs
->flag
& FA__WIP
) && disk_writep(0, 0)) goto fw_abort
;
934 fs
->flag
&= ~FA__WIP
;
936 } else { /* Write data request */
937 if (!(fs
->flag
& FA__WIP
)) /* Round-down fptr to the sector boundary */
938 fs
->fptr
&= 0xFFFFFE00;
940 remain
= fs
->fsize
- fs
->fptr
;
941 if (btw
> remain
) btw
= (WORD
)remain
; /* Truncate btw by remaining bytes */
943 while (btw
) { /* Repeat until all data transferred */
944 if (((WORD
)fs
->fptr
% 512) == 0) { /* On the sector boundary? */
945 cs
= (BYTE
)(fs
->fptr
/ 512 & (fs
->csize
- 1)); /* Sector offset in the cluster */
946 if (!cs
) { /* On the cluster boundary? */
947 clst
= (fs
->fptr
== 0) ?
/* On the top of the file? */
948 fs
->org_clust
: get_fat(fs
->curr_clust
);
949 if (clst
<= 1) goto fw_abort
;
950 fs
->curr_clust
= clst
; /* Update current cluster */
952 sect
= clust2sect(fs
->curr_clust
); /* Get current sector */
953 if (!sect
) goto fw_abort
;
954 fs
->dsect
= sect
+ cs
;
955 if (disk_writep(0, fs
->dsect
)) goto fw_abort
; /* Initiate a sector write operation */
958 wcnt
= 512 - ((WORD
)fs
->fptr
% 512); /* Number of bytes to write to the sector */
959 if (wcnt
> btw
) wcnt
= btw
;
960 if (disk_writep(p
, wcnt
)) goto fw_abort
; /* Send data to the sector */
961 fs
->fptr
+= wcnt
; p
+= wcnt
; /* Update pointers and counters */
962 btw
-= wcnt
; *bw
+= wcnt
;
963 if (((WORD
)fs
->fptr
% 512) == 0) {
964 if (disk_writep(0, 0)) goto fw_abort
; /* Finalize the currtent secter write operation */
965 fs
->flag
&= ~FA__WIP
;
979 /*-----------------------------------------------------------------------*/
980 /* Seek File R/W Pointer */
981 /*-----------------------------------------------------------------------*/
985 DWORD ofs
/* File pointer from top of file */
989 DWORD bcs
, sect
, ifptr
;
993 if (!fs
) return FR_NOT_ENABLED
; /* Check file system */
994 if (!(fs
->flag
& FA_OPENED
)) /* Check if opened */
995 return FR_NOT_OPENED
;
997 if (ofs
> fs
->fsize
) ofs
= fs
->fsize
; /* Clip offset with the file size */
1001 bcs
= (DWORD
)fs
->csize
* 512; /* Cluster size (byte) */
1003 (ofs
- 1) / bcs
>= (ifptr
- 1) / bcs
) { /* When seek to same or following cluster, */
1004 fs
->fptr
= (ifptr
- 1) & ~(bcs
- 1); /* start from the current cluster */
1006 clst
= fs
->curr_clust
;
1007 } else { /* When seek to back cluster, */
1008 clst
= fs
->org_clust
; /* start from the first cluster */
1009 fs
->curr_clust
= clst
;
1011 while (ofs
> bcs
) { /* Cluster following loop */
1012 clst
= get_fat(clst
); /* Follow cluster chain */
1013 if (clst
<= 1 || clst
>= fs
->n_fatent
) goto fe_abort
;
1014 fs
->curr_clust
= clst
;
1019 sect
= clust2sect(clst
); /* Current sector */
1020 if (!sect
) goto fe_abort
;
1021 fs
->dsect
= sect
+ (fs
->fptr
/ 512 & (fs
->csize
- 1));
1034 /*-----------------------------------------------------------------------*/
1035 /* Create a Directroy Object */
1036 /*-----------------------------------------------------------------------*/
1039 FRESULT
pf_opendir (
1040 DIR *dj
, /* Pointer to directory object to create */
1041 const char *path
/* Pointer to the directory path */
1045 BYTE sp
[12], dir
[32];
1049 if (!fs
) { /* Check file system */
1050 res
= FR_NOT_ENABLED
;
1053 res
= follow_path(dj
, dir
, path
); /* Follow the path to the directory */
1054 if (res
== FR_OK
) { /* Follow completed */
1055 if (dir
[0]) { /* It is not the root dir */
1056 if (dir
[DIR_Attr
] & AM_DIR
) /* The object is a directory */
1057 dj
->sclust
= LD_CLUST(dir
);
1058 else /* The object is not a directory */
1062 res
= dir_rewind(dj
); /* Rewind dir */
1064 if (res
== FR_NO_FILE
) res
= FR_NO_PATH
;
1073 /*-----------------------------------------------------------------------*/
1074 /* Read Directory Entry in Sequense */
1075 /*-----------------------------------------------------------------------*/
1077 FRESULT
pf_readdir (
1078 DIR *dj
, /* Pointer to the open directory object */
1079 FILINFO
*fno
/* Pointer to file information to return */
1083 BYTE sp
[12], dir
[32];
1087 if (!fs
) { /* Check file system */
1088 res
= FR_NOT_ENABLED
;
1092 res
= dir_rewind(dj
);
1094 res
= dir_read(dj
, dir
);
1095 if (res
== FR_NO_FILE
) {
1099 if (res
== FR_OK
) { /* A valid entry is found */
1100 get_fileinfo(dj
, dir
, fno
); /* Get the object information */
1101 res
= dir_next(dj
); /* Increment index for next */
1102 if (res
== FR_NO_FILE
) {
1113 #endif /* _USE_DIR */