SD

Committer:
mikekelly99
Date:
Tue Nov 17 17:03:36 2020 +0000
Revision:
0:6db20bbdc767
Wow, never committed the code once so first and final commit, code produces the lat and long values as well as speed.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mikekelly99 0:6db20bbdc767 1 /*----------------------------------------------------------------------------/
mikekelly99 0:6db20bbdc767 2 / FatFs - FAT file system module R0.11a (C)ChaN, 2015 /
mikekelly99 0:6db20bbdc767 3 /-----------------------------------------------------------------------------/
mikekelly99 0:6db20bbdc767 4 / FatFs module is a free software that opened under license policy of
mikekelly99 0:6db20bbdc767 5 / following conditions.
mikekelly99 0:6db20bbdc767 6 /
mikekelly99 0:6db20bbdc767 7 / Copyright (C) 2015, ChaN, all right reserved.
mikekelly99 0:6db20bbdc767 8 /
mikekelly99 0:6db20bbdc767 9 / 1. Redistributions of source code must retain the above copyright notice,
mikekelly99 0:6db20bbdc767 10 / this condition and the following disclaimer.
mikekelly99 0:6db20bbdc767 11 /
mikekelly99 0:6db20bbdc767 12 / This software is provided by the copyright holder and contributors "AS IS"
mikekelly99 0:6db20bbdc767 13 / and any warranties related to this software are DISCLAIMED.
mikekelly99 0:6db20bbdc767 14 / The copyright owner or contributors be NOT LIABLE for any damages caused
mikekelly99 0:6db20bbdc767 15 / by use of this software.
mikekelly99 0:6db20bbdc767 16 /----------------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 17
mikekelly99 0:6db20bbdc767 18
mikekelly99 0:6db20bbdc767 19 #include "ff.h" /* Declarations of FatFs API */
mikekelly99 0:6db20bbdc767 20 #include "diskio.h" /* Declarations of disk I/O functions */
mikekelly99 0:6db20bbdc767 21
mikekelly99 0:6db20bbdc767 22
mikekelly99 0:6db20bbdc767 23 /*--------------------------------------------------------------------------
mikekelly99 0:6db20bbdc767 24
mikekelly99 0:6db20bbdc767 25 Module Private Definitions
mikekelly99 0:6db20bbdc767 26
mikekelly99 0:6db20bbdc767 27 ---------------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 28
mikekelly99 0:6db20bbdc767 29 #if _FATFS != 64180 /* Revision ID */
mikekelly99 0:6db20bbdc767 30 #error Wrong include file (ff.h).
mikekelly99 0:6db20bbdc767 31 #endif
mikekelly99 0:6db20bbdc767 32
mikekelly99 0:6db20bbdc767 33
mikekelly99 0:6db20bbdc767 34 /* Reentrancy related */
mikekelly99 0:6db20bbdc767 35 #if _FS_REENTRANT
mikekelly99 0:6db20bbdc767 36 #if _USE_LFN == 1
mikekelly99 0:6db20bbdc767 37 #error Static LFN work area cannot be used at thread-safe configuration
mikekelly99 0:6db20bbdc767 38 #endif
mikekelly99 0:6db20bbdc767 39 #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
mikekelly99 0:6db20bbdc767 40 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
mikekelly99 0:6db20bbdc767 41 #else
mikekelly99 0:6db20bbdc767 42 #define ENTER_FF(fs)
mikekelly99 0:6db20bbdc767 43 #define LEAVE_FF(fs, res) return res
mikekelly99 0:6db20bbdc767 44 #endif
mikekelly99 0:6db20bbdc767 45
mikekelly99 0:6db20bbdc767 46 #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }
mikekelly99 0:6db20bbdc767 47
mikekelly99 0:6db20bbdc767 48
mikekelly99 0:6db20bbdc767 49 /* Definitions of sector size */
mikekelly99 0:6db20bbdc767 50 #if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096)
mikekelly99 0:6db20bbdc767 51 #error Wrong sector size configuration
mikekelly99 0:6db20bbdc767 52 #endif
mikekelly99 0:6db20bbdc767 53 #if _MAX_SS == _MIN_SS
mikekelly99 0:6db20bbdc767 54 #define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */
mikekelly99 0:6db20bbdc767 55 #else
mikekelly99 0:6db20bbdc767 56 #define SS(fs) ((fs)->ssize) /* Variable sector size */
mikekelly99 0:6db20bbdc767 57 #endif
mikekelly99 0:6db20bbdc767 58
mikekelly99 0:6db20bbdc767 59
mikekelly99 0:6db20bbdc767 60 /* Timestamp feature */
mikekelly99 0:6db20bbdc767 61 #if _FS_NORTC == 1
mikekelly99 0:6db20bbdc767 62 #if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31
mikekelly99 0:6db20bbdc767 63 #error Invalid _FS_NORTC settings
mikekelly99 0:6db20bbdc767 64 #endif
mikekelly99 0:6db20bbdc767 65 #define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16)
mikekelly99 0:6db20bbdc767 66 #else
mikekelly99 0:6db20bbdc767 67 #define GET_FATTIME() get_fattime()
mikekelly99 0:6db20bbdc767 68 #endif
mikekelly99 0:6db20bbdc767 69
mikekelly99 0:6db20bbdc767 70
mikekelly99 0:6db20bbdc767 71 /* File access control feature */
mikekelly99 0:6db20bbdc767 72 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 73 #if _FS_READONLY
mikekelly99 0:6db20bbdc767 74 #error _FS_LOCK must be 0 at read-only configuration
mikekelly99 0:6db20bbdc767 75 #endif
mikekelly99 0:6db20bbdc767 76 typedef struct {
mikekelly99 0:6db20bbdc767 77 FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */
mikekelly99 0:6db20bbdc767 78 DWORD clu; /* Object ID 2, directory (0:root) */
mikekelly99 0:6db20bbdc767 79 WORD idx; /* Object ID 3, directory index */
mikekelly99 0:6db20bbdc767 80 WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */
mikekelly99 0:6db20bbdc767 81 } FILESEM;
mikekelly99 0:6db20bbdc767 82 #endif
mikekelly99 0:6db20bbdc767 83
mikekelly99 0:6db20bbdc767 84
mikekelly99 0:6db20bbdc767 85
mikekelly99 0:6db20bbdc767 86 /* DBCS code ranges and SBCS upper conversion tables */
mikekelly99 0:6db20bbdc767 87
mikekelly99 0:6db20bbdc767 88 #if _CODE_PAGE == 932 /* Japanese Shift-JIS */
mikekelly99 0:6db20bbdc767 89 #define _DF1S 0x81 /* DBC 1st byte range 1 start */
mikekelly99 0:6db20bbdc767 90 #define _DF1E 0x9F /* DBC 1st byte range 1 end */
mikekelly99 0:6db20bbdc767 91 #define _DF2S 0xE0 /* DBC 1st byte range 2 start */
mikekelly99 0:6db20bbdc767 92 #define _DF2E 0xFC /* DBC 1st byte range 2 end */
mikekelly99 0:6db20bbdc767 93 #define _DS1S 0x40 /* DBC 2nd byte range 1 start */
mikekelly99 0:6db20bbdc767 94 #define _DS1E 0x7E /* DBC 2nd byte range 1 end */
mikekelly99 0:6db20bbdc767 95 #define _DS2S 0x80 /* DBC 2nd byte range 2 start */
mikekelly99 0:6db20bbdc767 96 #define _DS2E 0xFC /* DBC 2nd byte range 2 end */
mikekelly99 0:6db20bbdc767 97
mikekelly99 0:6db20bbdc767 98 #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
mikekelly99 0:6db20bbdc767 99 #define _DF1S 0x81
mikekelly99 0:6db20bbdc767 100 #define _DF1E 0xFE
mikekelly99 0:6db20bbdc767 101 #define _DS1S 0x40
mikekelly99 0:6db20bbdc767 102 #define _DS1E 0x7E
mikekelly99 0:6db20bbdc767 103 #define _DS2S 0x80
mikekelly99 0:6db20bbdc767 104 #define _DS2E 0xFE
mikekelly99 0:6db20bbdc767 105
mikekelly99 0:6db20bbdc767 106 #elif _CODE_PAGE == 949 /* Korean */
mikekelly99 0:6db20bbdc767 107 #define _DF1S 0x81
mikekelly99 0:6db20bbdc767 108 #define _DF1E 0xFE
mikekelly99 0:6db20bbdc767 109 #define _DS1S 0x41
mikekelly99 0:6db20bbdc767 110 #define _DS1E 0x5A
mikekelly99 0:6db20bbdc767 111 #define _DS2S 0x61
mikekelly99 0:6db20bbdc767 112 #define _DS2E 0x7A
mikekelly99 0:6db20bbdc767 113 #define _DS3S 0x81
mikekelly99 0:6db20bbdc767 114 #define _DS3E 0xFE
mikekelly99 0:6db20bbdc767 115
mikekelly99 0:6db20bbdc767 116 #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
mikekelly99 0:6db20bbdc767 117 #define _DF1S 0x81
mikekelly99 0:6db20bbdc767 118 #define _DF1E 0xFE
mikekelly99 0:6db20bbdc767 119 #define _DS1S 0x40
mikekelly99 0:6db20bbdc767 120 #define _DS1E 0x7E
mikekelly99 0:6db20bbdc767 121 #define _DS2S 0xA1
mikekelly99 0:6db20bbdc767 122 #define _DS2E 0xFE
mikekelly99 0:6db20bbdc767 123
mikekelly99 0:6db20bbdc767 124 #elif _CODE_PAGE == 437 /* U.S. */
mikekelly99 0:6db20bbdc767 125 #define _DF1S 0
mikekelly99 0:6db20bbdc767 126 #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 127 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 128 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 129 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 130 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 131 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 132 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 133 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 134
mikekelly99 0:6db20bbdc767 135 #elif _CODE_PAGE == 720 /* Arabic */
mikekelly99 0:6db20bbdc767 136 #define _DF1S 0
mikekelly99 0:6db20bbdc767 137 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 138 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 139 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 140 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 141 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 142 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 143 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 144 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 145
mikekelly99 0:6db20bbdc767 146 #elif _CODE_PAGE == 737 /* Greek */
mikekelly99 0:6db20bbdc767 147 #define _DF1S 0
mikekelly99 0:6db20bbdc767 148 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 149 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
mikekelly99 0:6db20bbdc767 150 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \
mikekelly99 0:6db20bbdc767 151 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 152 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 153 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 154 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 155 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 156
mikekelly99 0:6db20bbdc767 157 #elif _CODE_PAGE == 771 /* KBL */
mikekelly99 0:6db20bbdc767 158 #define _DF1S 0
mikekelly99 0:6db20bbdc767 159 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 160 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 161 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 162 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 163 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 164 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \
mikekelly99 0:6db20bbdc767 165 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 166 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 167
mikekelly99 0:6db20bbdc767 168 #elif _CODE_PAGE == 775 /* Baltic */
mikekelly99 0:6db20bbdc767 169 #define _DF1S 0
mikekelly99 0:6db20bbdc767 170 #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 171 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 172 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 173 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 174 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 175 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 176 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 177 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 178
mikekelly99 0:6db20bbdc767 179 #elif _CODE_PAGE == 850 /* Latin 1 */
mikekelly99 0:6db20bbdc767 180 #define _DF1S 0
mikekelly99 0:6db20bbdc767 181 #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \
mikekelly99 0:6db20bbdc767 182 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 183 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 184 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 185 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 186 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \
mikekelly99 0:6db20bbdc767 187 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 188 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 189
mikekelly99 0:6db20bbdc767 190 #elif _CODE_PAGE == 852 /* Latin 2 */
mikekelly99 0:6db20bbdc767 191 #define _DF1S 0
mikekelly99 0:6db20bbdc767 192 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 193 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \
mikekelly99 0:6db20bbdc767 194 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 195 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
mikekelly99 0:6db20bbdc767 196 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 197 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 198 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \
mikekelly99 0:6db20bbdc767 199 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 200
mikekelly99 0:6db20bbdc767 201 #elif _CODE_PAGE == 855 /* Cyrillic */
mikekelly99 0:6db20bbdc767 202 #define _DF1S 0
mikekelly99 0:6db20bbdc767 203 #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \
mikekelly99 0:6db20bbdc767 204 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
mikekelly99 0:6db20bbdc767 205 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 206 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 207 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 208 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
mikekelly99 0:6db20bbdc767 209 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 210 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 211
mikekelly99 0:6db20bbdc767 212 #elif _CODE_PAGE == 857 /* Turkish */
mikekelly99 0:6db20bbdc767 213 #define _DF1S 0
mikekelly99 0:6db20bbdc767 214 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 215 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
mikekelly99 0:6db20bbdc767 216 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 217 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 218 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 219 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 220 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 221 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 222
mikekelly99 0:6db20bbdc767 223 #elif _CODE_PAGE == 860 /* Portuguese */
mikekelly99 0:6db20bbdc767 224 #define _DF1S 0
mikekelly99 0:6db20bbdc767 225 #define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 226 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 227 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 228 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 229 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 230 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 231 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 232 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 233
mikekelly99 0:6db20bbdc767 234 #elif _CODE_PAGE == 861 /* Icelandic */
mikekelly99 0:6db20bbdc767 235 #define _DF1S 0
mikekelly99 0:6db20bbdc767 236 #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 237 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 238 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 239 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 240 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 241 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 242 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 243 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 244
mikekelly99 0:6db20bbdc767 245 #elif _CODE_PAGE == 862 /* Hebrew */
mikekelly99 0:6db20bbdc767 246 #define _DF1S 0
mikekelly99 0:6db20bbdc767 247 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 248 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 249 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 250 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 251 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 252 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 253 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 254 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 255
mikekelly99 0:6db20bbdc767 256 #elif _CODE_PAGE == 863 /* Canadian-French */
mikekelly99 0:6db20bbdc767 257 #define _DF1S 0
mikekelly99 0:6db20bbdc767 258 #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \
mikekelly99 0:6db20bbdc767 259 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \
mikekelly99 0:6db20bbdc767 260 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 261 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 262 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 263 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 264 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 265 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 266
mikekelly99 0:6db20bbdc767 267 #elif _CODE_PAGE == 864 /* Arabic */
mikekelly99 0:6db20bbdc767 268 #define _DF1S 0
mikekelly99 0:6db20bbdc767 269 #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 270 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 271 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 272 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 273 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 274 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 275 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 276 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 277
mikekelly99 0:6db20bbdc767 278 #elif _CODE_PAGE == 865 /* Nordic */
mikekelly99 0:6db20bbdc767 279 #define _DF1S 0
mikekelly99 0:6db20bbdc767 280 #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 281 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 282 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 283 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 284 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 285 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 286 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
mikekelly99 0:6db20bbdc767 287 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 288
mikekelly99 0:6db20bbdc767 289 #elif _CODE_PAGE == 866 /* Russian */
mikekelly99 0:6db20bbdc767 290 #define _DF1S 0
mikekelly99 0:6db20bbdc767 291 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 292 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 293 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 294 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 295 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 296 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
mikekelly99 0:6db20bbdc767 297 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
mikekelly99 0:6db20bbdc767 298 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 299
mikekelly99 0:6db20bbdc767 300 #elif _CODE_PAGE == 869 /* Greek 2 */
mikekelly99 0:6db20bbdc767 301 #define _DF1S 0
mikekelly99 0:6db20bbdc767 302 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
mikekelly99 0:6db20bbdc767 303 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \
mikekelly99 0:6db20bbdc767 304 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
mikekelly99 0:6db20bbdc767 305 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
mikekelly99 0:6db20bbdc767 306 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
mikekelly99 0:6db20bbdc767 307 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \
mikekelly99 0:6db20bbdc767 308 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \
mikekelly99 0:6db20bbdc767 309 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}
mikekelly99 0:6db20bbdc767 310
mikekelly99 0:6db20bbdc767 311 #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
mikekelly99 0:6db20bbdc767 312 #if _USE_LFN
mikekelly99 0:6db20bbdc767 313 #error Cannot use LFN feature without valid code page.
mikekelly99 0:6db20bbdc767 314 #endif
mikekelly99 0:6db20bbdc767 315 #define _DF1S 0
mikekelly99 0:6db20bbdc767 316
mikekelly99 0:6db20bbdc767 317 #else
mikekelly99 0:6db20bbdc767 318 #error Unknown code page
mikekelly99 0:6db20bbdc767 319
mikekelly99 0:6db20bbdc767 320 #endif
mikekelly99 0:6db20bbdc767 321
mikekelly99 0:6db20bbdc767 322
mikekelly99 0:6db20bbdc767 323 /* Character code support macros */
mikekelly99 0:6db20bbdc767 324 #define IsUpper(c) (((c)>='A')&&((c)<='Z'))
mikekelly99 0:6db20bbdc767 325 #define IsLower(c) (((c)>='a')&&((c)<='z'))
mikekelly99 0:6db20bbdc767 326 #define IsDigit(c) (((c)>='0')&&((c)<='9'))
mikekelly99 0:6db20bbdc767 327
mikekelly99 0:6db20bbdc767 328 #if _DF1S /* Code page is DBCS */
mikekelly99 0:6db20bbdc767 329
mikekelly99 0:6db20bbdc767 330 #ifdef _DF2S /* Two 1st byte areas */
mikekelly99 0:6db20bbdc767 331 #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
mikekelly99 0:6db20bbdc767 332 #else /* One 1st byte area */
mikekelly99 0:6db20bbdc767 333 #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
mikekelly99 0:6db20bbdc767 334 #endif
mikekelly99 0:6db20bbdc767 335
mikekelly99 0:6db20bbdc767 336 #ifdef _DS3S /* Three 2nd byte areas */
mikekelly99 0:6db20bbdc767 337 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
mikekelly99 0:6db20bbdc767 338 #else /* Two 2nd byte areas */
mikekelly99 0:6db20bbdc767 339 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
mikekelly99 0:6db20bbdc767 340 #endif
mikekelly99 0:6db20bbdc767 341
mikekelly99 0:6db20bbdc767 342 #else /* Code page is SBCS */
mikekelly99 0:6db20bbdc767 343
mikekelly99 0:6db20bbdc767 344 #define IsDBCS1(c) 0
mikekelly99 0:6db20bbdc767 345 #define IsDBCS2(c) 0
mikekelly99 0:6db20bbdc767 346
mikekelly99 0:6db20bbdc767 347 #endif /* _DF1S */
mikekelly99 0:6db20bbdc767 348
mikekelly99 0:6db20bbdc767 349
mikekelly99 0:6db20bbdc767 350 /* Name status flags */
mikekelly99 0:6db20bbdc767 351 #define NSFLAG 11 /* Index of name status byte in fn[] */
mikekelly99 0:6db20bbdc767 352 #define NS_LOSS 0x01 /* Out of 8.3 format */
mikekelly99 0:6db20bbdc767 353 #define NS_LFN 0x02 /* Force to create LFN entry */
mikekelly99 0:6db20bbdc767 354 #define NS_LAST 0x04 /* Last segment */
mikekelly99 0:6db20bbdc767 355 #define NS_BODY 0x08 /* Lower case flag (body) */
mikekelly99 0:6db20bbdc767 356 #define NS_EXT 0x10 /* Lower case flag (ext) */
mikekelly99 0:6db20bbdc767 357 #define NS_DOT 0x20 /* Dot entry */
mikekelly99 0:6db20bbdc767 358
mikekelly99 0:6db20bbdc767 359
mikekelly99 0:6db20bbdc767 360 /* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */
mikekelly99 0:6db20bbdc767 361 #define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */
mikekelly99 0:6db20bbdc767 362 #define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */
mikekelly99 0:6db20bbdc767 363
mikekelly99 0:6db20bbdc767 364
mikekelly99 0:6db20bbdc767 365 /* FatFs refers the members in the FAT structures as byte array instead of
mikekelly99 0:6db20bbdc767 366 / structure members because the structure is not binary compatible between
mikekelly99 0:6db20bbdc767 367 / different platforms */
mikekelly99 0:6db20bbdc767 368
mikekelly99 0:6db20bbdc767 369 #define BS_jmpBoot 0 /* x86 jump instruction (3) */
mikekelly99 0:6db20bbdc767 370 #define BS_OEMName 3 /* OEM name (8) */
mikekelly99 0:6db20bbdc767 371 #define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
mikekelly99 0:6db20bbdc767 372 #define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
mikekelly99 0:6db20bbdc767 373 #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
mikekelly99 0:6db20bbdc767 374 #define BPB_NumFATs 16 /* Number of FAT copies (1) */
mikekelly99 0:6db20bbdc767 375 #define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */
mikekelly99 0:6db20bbdc767 376 #define BPB_TotSec16 19 /* Volume size [sector] (2) */
mikekelly99 0:6db20bbdc767 377 #define BPB_Media 21 /* Media descriptor (1) */
mikekelly99 0:6db20bbdc767 378 #define BPB_FATSz16 22 /* FAT size [sector] (2) */
mikekelly99 0:6db20bbdc767 379 #define BPB_SecPerTrk 24 /* Track size [sector] (2) */
mikekelly99 0:6db20bbdc767 380 #define BPB_NumHeads 26 /* Number of heads (2) */
mikekelly99 0:6db20bbdc767 381 #define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
mikekelly99 0:6db20bbdc767 382 #define BPB_TotSec32 32 /* Volume size [sector] (4) */
mikekelly99 0:6db20bbdc767 383 #define BS_DrvNum 36 /* Physical drive number (1) */
mikekelly99 0:6db20bbdc767 384 #define BS_NTres 37 /* Error flag (1) */
mikekelly99 0:6db20bbdc767 385 #define BS_BootSig 38 /* Extended boot signature (1) */
mikekelly99 0:6db20bbdc767 386 #define BS_VolID 39 /* Volume serial number (4) */
mikekelly99 0:6db20bbdc767 387 #define BS_VolLab 43 /* Volume label (8) */
mikekelly99 0:6db20bbdc767 388 #define BS_FilSysType 54 /* File system type (1) */
mikekelly99 0:6db20bbdc767 389 #define BPB_FATSz32 36 /* FAT size [sector] (4) */
mikekelly99 0:6db20bbdc767 390 #define BPB_ExtFlags 40 /* Extended flags (2) */
mikekelly99 0:6db20bbdc767 391 #define BPB_FSVer 42 /* File system version (2) */
mikekelly99 0:6db20bbdc767 392 #define BPB_RootClus 44 /* Root directory first cluster (4) */
mikekelly99 0:6db20bbdc767 393 #define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */
mikekelly99 0:6db20bbdc767 394 #define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
mikekelly99 0:6db20bbdc767 395 #define BS_DrvNum32 64 /* Physical drive number (1) */
mikekelly99 0:6db20bbdc767 396 #define BS_NTres32 65 /* Error flag (1) */
mikekelly99 0:6db20bbdc767 397 #define BS_BootSig32 66 /* Extended boot signature (1) */
mikekelly99 0:6db20bbdc767 398 #define BS_VolID32 67 /* Volume serial number (4) */
mikekelly99 0:6db20bbdc767 399 #define BS_VolLab32 71 /* Volume label (8) */
mikekelly99 0:6db20bbdc767 400 #define BS_FilSysType32 82 /* File system type (1) */
mikekelly99 0:6db20bbdc767 401 #define FSI_LeadSig 0 /* FSI: Leading signature (4) */
mikekelly99 0:6db20bbdc767 402 #define FSI_StrucSig 484 /* FSI: Structure signature (4) */
mikekelly99 0:6db20bbdc767 403 #define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
mikekelly99 0:6db20bbdc767 404 #define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
mikekelly99 0:6db20bbdc767 405 #define MBR_Table 446 /* MBR: Partition table offset (2) */
mikekelly99 0:6db20bbdc767 406 #define SZ_PTE 16 /* MBR: Size of a partition table entry */
mikekelly99 0:6db20bbdc767 407 #define BS_55AA 510 /* Signature word (2) */
mikekelly99 0:6db20bbdc767 408
mikekelly99 0:6db20bbdc767 409 #define DIR_Name 0 /* Short file name (11) */
mikekelly99 0:6db20bbdc767 410 #define DIR_Attr 11 /* Attribute (1) */
mikekelly99 0:6db20bbdc767 411 #define DIR_NTres 12 /* Lower case flag (1) */
mikekelly99 0:6db20bbdc767 412 #define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */
mikekelly99 0:6db20bbdc767 413 #define DIR_CrtTime 14 /* Created time (2) */
mikekelly99 0:6db20bbdc767 414 #define DIR_CrtDate 16 /* Created date (2) */
mikekelly99 0:6db20bbdc767 415 #define DIR_LstAccDate 18 /* Last accessed date (2) */
mikekelly99 0:6db20bbdc767 416 #define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */
mikekelly99 0:6db20bbdc767 417 #define DIR_WrtTime 22 /* Modified time (2) */
mikekelly99 0:6db20bbdc767 418 #define DIR_WrtDate 24 /* Modified date (2) */
mikekelly99 0:6db20bbdc767 419 #define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */
mikekelly99 0:6db20bbdc767 420 #define DIR_FileSize 28 /* File size (4) */
mikekelly99 0:6db20bbdc767 421 #define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
mikekelly99 0:6db20bbdc767 422 #define LDIR_Attr 11 /* LFN attribute (1) */
mikekelly99 0:6db20bbdc767 423 #define LDIR_Type 12 /* LFN type (1) */
mikekelly99 0:6db20bbdc767 424 #define LDIR_Chksum 13 /* Checksum of corresponding SFN entry */
mikekelly99 0:6db20bbdc767 425 #define LDIR_FstClusLO 26 /* Must be zero (0) */
mikekelly99 0:6db20bbdc767 426 #define SZ_DIRE 32 /* Size of a directory entry */
mikekelly99 0:6db20bbdc767 427 #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */
mikekelly99 0:6db20bbdc767 428 #define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */
mikekelly99 0:6db20bbdc767 429 #define RDDEM 0x05 /* Replacement of the character collides with DDEM */
mikekelly99 0:6db20bbdc767 430
mikekelly99 0:6db20bbdc767 431
mikekelly99 0:6db20bbdc767 432
mikekelly99 0:6db20bbdc767 433
mikekelly99 0:6db20bbdc767 434 /*--------------------------------------------------------------------------
mikekelly99 0:6db20bbdc767 435
mikekelly99 0:6db20bbdc767 436 Module Private Work Area
mikekelly99 0:6db20bbdc767 437
mikekelly99 0:6db20bbdc767 438 ---------------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 439
mikekelly99 0:6db20bbdc767 440 /* Remark: Uninitialized variables with static duration are guaranteed
mikekelly99 0:6db20bbdc767 441 / zero/null at start-up. If not, either the linker or start-up routine
mikekelly99 0:6db20bbdc767 442 / being used is not compliance with ANSI-C standard.
mikekelly99 0:6db20bbdc767 443 */
mikekelly99 0:6db20bbdc767 444
mikekelly99 0:6db20bbdc767 445 #if _VOLUMES < 1 || _VOLUMES > 9
mikekelly99 0:6db20bbdc767 446 #error Wrong _VOLUMES setting
mikekelly99 0:6db20bbdc767 447 #endif
mikekelly99 0:6db20bbdc767 448 static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
mikekelly99 0:6db20bbdc767 449 static WORD Fsid; /* File system mount ID */
mikekelly99 0:6db20bbdc767 450
mikekelly99 0:6db20bbdc767 451 #if _FS_RPATH && _VOLUMES >= 2
mikekelly99 0:6db20bbdc767 452 static BYTE CurrVol; /* Current drive */
mikekelly99 0:6db20bbdc767 453 #endif
mikekelly99 0:6db20bbdc767 454
mikekelly99 0:6db20bbdc767 455 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 456 static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */
mikekelly99 0:6db20bbdc767 457 #endif
mikekelly99 0:6db20bbdc767 458
mikekelly99 0:6db20bbdc767 459 #if _USE_LFN == 0 /* Non LFN feature */
mikekelly99 0:6db20bbdc767 460 #define DEFINE_NAMEBUF BYTE sfn[12]
mikekelly99 0:6db20bbdc767 461 #define INIT_BUF(dobj) (dobj).fn = sfn
mikekelly99 0:6db20bbdc767 462 #define FREE_BUF()
mikekelly99 0:6db20bbdc767 463 #else
mikekelly99 0:6db20bbdc767 464 #if _MAX_LFN < 12 || _MAX_LFN > 255
mikekelly99 0:6db20bbdc767 465 #error Wrong _MAX_LFN setting
mikekelly99 0:6db20bbdc767 466 #endif
mikekelly99 0:6db20bbdc767 467 #if _USE_LFN == 1 /* LFN feature with static working buffer */
mikekelly99 0:6db20bbdc767 468 static WCHAR LfnBuf[_MAX_LFN + 1];
mikekelly99 0:6db20bbdc767 469 #define DEFINE_NAMEBUF BYTE sfn[12]
mikekelly99 0:6db20bbdc767 470 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
mikekelly99 0:6db20bbdc767 471 #define FREE_BUF()
mikekelly99 0:6db20bbdc767 472 #elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */
mikekelly99 0:6db20bbdc767 473 #define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1]
mikekelly99 0:6db20bbdc767 474 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
mikekelly99 0:6db20bbdc767 475 #define FREE_BUF()
mikekelly99 0:6db20bbdc767 476 #elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */
mikekelly99 0:6db20bbdc767 477 #define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn
mikekelly99 0:6db20bbdc767 478 #define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; }
mikekelly99 0:6db20bbdc767 479 #define FREE_BUF() ff_memfree(lfn)
mikekelly99 0:6db20bbdc767 480 #else
mikekelly99 0:6db20bbdc767 481 #error Wrong _USE_LFN setting
mikekelly99 0:6db20bbdc767 482 #endif
mikekelly99 0:6db20bbdc767 483 #endif
mikekelly99 0:6db20bbdc767 484
mikekelly99 0:6db20bbdc767 485 #ifdef _EXCVT
mikekelly99 0:6db20bbdc767 486 static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */
mikekelly99 0:6db20bbdc767 487 #endif
mikekelly99 0:6db20bbdc767 488
mikekelly99 0:6db20bbdc767 489
mikekelly99 0:6db20bbdc767 490
mikekelly99 0:6db20bbdc767 491
mikekelly99 0:6db20bbdc767 492
mikekelly99 0:6db20bbdc767 493
mikekelly99 0:6db20bbdc767 494 /*--------------------------------------------------------------------------
mikekelly99 0:6db20bbdc767 495
mikekelly99 0:6db20bbdc767 496 Module Private Functions
mikekelly99 0:6db20bbdc767 497
mikekelly99 0:6db20bbdc767 498 ---------------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 499
mikekelly99 0:6db20bbdc767 500
mikekelly99 0:6db20bbdc767 501 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 502 /* String functions */
mikekelly99 0:6db20bbdc767 503 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 504
mikekelly99 0:6db20bbdc767 505 /* Copy memory to memory */
mikekelly99 0:6db20bbdc767 506 static
mikekelly99 0:6db20bbdc767 507 void mem_cpy (void* dst, const void* src, UINT cnt) {
mikekelly99 0:6db20bbdc767 508 BYTE *d = (BYTE*)dst;
mikekelly99 0:6db20bbdc767 509 const BYTE *s = (const BYTE*)src;
mikekelly99 0:6db20bbdc767 510
mikekelly99 0:6db20bbdc767 511 #if _WORD_ACCESS == 1
mikekelly99 0:6db20bbdc767 512 while (cnt >= sizeof (int)) {
mikekelly99 0:6db20bbdc767 513 *(int*)d = *(int*)s;
mikekelly99 0:6db20bbdc767 514 d += sizeof (int); s += sizeof (int);
mikekelly99 0:6db20bbdc767 515 cnt -= sizeof (int);
mikekelly99 0:6db20bbdc767 516 }
mikekelly99 0:6db20bbdc767 517 #endif
mikekelly99 0:6db20bbdc767 518 while (cnt--)
mikekelly99 0:6db20bbdc767 519 *d++ = *s++;
mikekelly99 0:6db20bbdc767 520 }
mikekelly99 0:6db20bbdc767 521
mikekelly99 0:6db20bbdc767 522 /* Fill memory */
mikekelly99 0:6db20bbdc767 523 static
mikekelly99 0:6db20bbdc767 524 void mem_set (void* dst, int val, UINT cnt) {
mikekelly99 0:6db20bbdc767 525 BYTE *d = (BYTE*)dst;
mikekelly99 0:6db20bbdc767 526
mikekelly99 0:6db20bbdc767 527 while (cnt--)
mikekelly99 0:6db20bbdc767 528 *d++ = (BYTE)val;
mikekelly99 0:6db20bbdc767 529 }
mikekelly99 0:6db20bbdc767 530
mikekelly99 0:6db20bbdc767 531 /* Compare memory to memory */
mikekelly99 0:6db20bbdc767 532 static
mikekelly99 0:6db20bbdc767 533 int mem_cmp (const void* dst, const void* src, UINT cnt) {
mikekelly99 0:6db20bbdc767 534 const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
mikekelly99 0:6db20bbdc767 535 int r = 0;
mikekelly99 0:6db20bbdc767 536
mikekelly99 0:6db20bbdc767 537 while (cnt-- && (r = *d++ - *s++) == 0) ;
mikekelly99 0:6db20bbdc767 538 return r;
mikekelly99 0:6db20bbdc767 539 }
mikekelly99 0:6db20bbdc767 540
mikekelly99 0:6db20bbdc767 541 /* Check if chr is contained in the string */
mikekelly99 0:6db20bbdc767 542 static
mikekelly99 0:6db20bbdc767 543 int chk_chr (const char* str, int chr) {
mikekelly99 0:6db20bbdc767 544 while (*str && *str != chr) str++;
mikekelly99 0:6db20bbdc767 545 return *str;
mikekelly99 0:6db20bbdc767 546 }
mikekelly99 0:6db20bbdc767 547
mikekelly99 0:6db20bbdc767 548
mikekelly99 0:6db20bbdc767 549
mikekelly99 0:6db20bbdc767 550
mikekelly99 0:6db20bbdc767 551 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 552 /* Request/Release grant to access the volume */
mikekelly99 0:6db20bbdc767 553 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 554 #if _FS_REENTRANT
mikekelly99 0:6db20bbdc767 555 static
mikekelly99 0:6db20bbdc767 556 int lock_fs (
mikekelly99 0:6db20bbdc767 557 FATFS* fs /* File system object */
mikekelly99 0:6db20bbdc767 558 )
mikekelly99 0:6db20bbdc767 559 {
mikekelly99 0:6db20bbdc767 560 return ff_req_grant(fs->sobj);
mikekelly99 0:6db20bbdc767 561 }
mikekelly99 0:6db20bbdc767 562
mikekelly99 0:6db20bbdc767 563
mikekelly99 0:6db20bbdc767 564 static
mikekelly99 0:6db20bbdc767 565 void unlock_fs (
mikekelly99 0:6db20bbdc767 566 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 567 FRESULT res /* Result code to be returned */
mikekelly99 0:6db20bbdc767 568 )
mikekelly99 0:6db20bbdc767 569 {
mikekelly99 0:6db20bbdc767 570 if (fs &&
mikekelly99 0:6db20bbdc767 571 res != FR_NOT_ENABLED &&
mikekelly99 0:6db20bbdc767 572 res != FR_INVALID_DRIVE &&
mikekelly99 0:6db20bbdc767 573 res != FR_INVALID_OBJECT &&
mikekelly99 0:6db20bbdc767 574 res != FR_TIMEOUT) {
mikekelly99 0:6db20bbdc767 575 ff_rel_grant(fs->sobj);
mikekelly99 0:6db20bbdc767 576 }
mikekelly99 0:6db20bbdc767 577 }
mikekelly99 0:6db20bbdc767 578 #endif
mikekelly99 0:6db20bbdc767 579
mikekelly99 0:6db20bbdc767 580
mikekelly99 0:6db20bbdc767 581
mikekelly99 0:6db20bbdc767 582
mikekelly99 0:6db20bbdc767 583 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 584 /* File lock control functions */
mikekelly99 0:6db20bbdc767 585 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 586 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 587
mikekelly99 0:6db20bbdc767 588 static
mikekelly99 0:6db20bbdc767 589 FRESULT chk_lock ( /* Check if the file can be accessed */
mikekelly99 0:6db20bbdc767 590 FATFS_DIR* dp, /* Directory object pointing the file to be checked */
mikekelly99 0:6db20bbdc767 591 int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */
mikekelly99 0:6db20bbdc767 592 )
mikekelly99 0:6db20bbdc767 593 {
mikekelly99 0:6db20bbdc767 594 UINT i, be;
mikekelly99 0:6db20bbdc767 595
mikekelly99 0:6db20bbdc767 596 /* Search file semaphore table */
mikekelly99 0:6db20bbdc767 597 for (i = be = 0; i < _FS_LOCK; i++) {
mikekelly99 0:6db20bbdc767 598 if (Files[i].fs) { /* Existing entry */
mikekelly99 0:6db20bbdc767 599 if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */
mikekelly99 0:6db20bbdc767 600 Files[i].clu == dp->sclust &&
mikekelly99 0:6db20bbdc767 601 Files[i].idx == dp->index) break;
mikekelly99 0:6db20bbdc767 602 } else { /* Blank entry */
mikekelly99 0:6db20bbdc767 603 be = 1;
mikekelly99 0:6db20bbdc767 604 }
mikekelly99 0:6db20bbdc767 605 }
mikekelly99 0:6db20bbdc767 606 if (i == _FS_LOCK) /* The object is not opened */
mikekelly99 0:6db20bbdc767 607 return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */
mikekelly99 0:6db20bbdc767 608
mikekelly99 0:6db20bbdc767 609 /* The object has been opened. Reject any open against writing file and all write mode open */
mikekelly99 0:6db20bbdc767 610 return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
mikekelly99 0:6db20bbdc767 611 }
mikekelly99 0:6db20bbdc767 612
mikekelly99 0:6db20bbdc767 613
mikekelly99 0:6db20bbdc767 614 static
mikekelly99 0:6db20bbdc767 615 int enq_lock (void) /* Check if an entry is available for a new object */
mikekelly99 0:6db20bbdc767 616 {
mikekelly99 0:6db20bbdc767 617 UINT i;
mikekelly99 0:6db20bbdc767 618
mikekelly99 0:6db20bbdc767 619 for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
mikekelly99 0:6db20bbdc767 620 return (i == _FS_LOCK) ? 0 : 1;
mikekelly99 0:6db20bbdc767 621 }
mikekelly99 0:6db20bbdc767 622
mikekelly99 0:6db20bbdc767 623
mikekelly99 0:6db20bbdc767 624 static
mikekelly99 0:6db20bbdc767 625 UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */
mikekelly99 0:6db20bbdc767 626 FATFS_DIR* dp, /* Directory object pointing the file to register or increment */
mikekelly99 0:6db20bbdc767 627 int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
mikekelly99 0:6db20bbdc767 628 )
mikekelly99 0:6db20bbdc767 629 {
mikekelly99 0:6db20bbdc767 630 UINT i;
mikekelly99 0:6db20bbdc767 631
mikekelly99 0:6db20bbdc767 632
mikekelly99 0:6db20bbdc767 633 for (i = 0; i < _FS_LOCK; i++) { /* Find the object */
mikekelly99 0:6db20bbdc767 634 if (Files[i].fs == dp->fs &&
mikekelly99 0:6db20bbdc767 635 Files[i].clu == dp->sclust &&
mikekelly99 0:6db20bbdc767 636 Files[i].idx == dp->index) break;
mikekelly99 0:6db20bbdc767 637 }
mikekelly99 0:6db20bbdc767 638
mikekelly99 0:6db20bbdc767 639 if (i == _FS_LOCK) { /* Not opened. Register it as new. */
mikekelly99 0:6db20bbdc767 640 for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
mikekelly99 0:6db20bbdc767 641 if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */
mikekelly99 0:6db20bbdc767 642 Files[i].fs = dp->fs;
mikekelly99 0:6db20bbdc767 643 Files[i].clu = dp->sclust;
mikekelly99 0:6db20bbdc767 644 Files[i].idx = dp->index;
mikekelly99 0:6db20bbdc767 645 Files[i].ctr = 0;
mikekelly99 0:6db20bbdc767 646 }
mikekelly99 0:6db20bbdc767 647
mikekelly99 0:6db20bbdc767 648 if (acc && Files[i].ctr) return 0; /* Access violation (int err) */
mikekelly99 0:6db20bbdc767 649
mikekelly99 0:6db20bbdc767 650 Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
mikekelly99 0:6db20bbdc767 651
mikekelly99 0:6db20bbdc767 652 return i + 1;
mikekelly99 0:6db20bbdc767 653 }
mikekelly99 0:6db20bbdc767 654
mikekelly99 0:6db20bbdc767 655
mikekelly99 0:6db20bbdc767 656 static
mikekelly99 0:6db20bbdc767 657 FRESULT dec_lock ( /* Decrement object open counter */
mikekelly99 0:6db20bbdc767 658 UINT i /* Semaphore index (1..) */
mikekelly99 0:6db20bbdc767 659 )
mikekelly99 0:6db20bbdc767 660 {
mikekelly99 0:6db20bbdc767 661 WORD n;
mikekelly99 0:6db20bbdc767 662 FRESULT res;
mikekelly99 0:6db20bbdc767 663
mikekelly99 0:6db20bbdc767 664
mikekelly99 0:6db20bbdc767 665 if (--i < _FS_LOCK) { /* Shift index number origin from 0 */
mikekelly99 0:6db20bbdc767 666 n = Files[i].ctr;
mikekelly99 0:6db20bbdc767 667 if (n == 0x100) n = 0; /* If write mode open, delete the entry */
mikekelly99 0:6db20bbdc767 668 if (n) n--; /* Decrement read mode open count */
mikekelly99 0:6db20bbdc767 669 Files[i].ctr = n;
mikekelly99 0:6db20bbdc767 670 if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */
mikekelly99 0:6db20bbdc767 671 res = FR_OK;
mikekelly99 0:6db20bbdc767 672 } else {
mikekelly99 0:6db20bbdc767 673 res = FR_INT_ERR; /* Invalid index nunber */
mikekelly99 0:6db20bbdc767 674 }
mikekelly99 0:6db20bbdc767 675 return res;
mikekelly99 0:6db20bbdc767 676 }
mikekelly99 0:6db20bbdc767 677
mikekelly99 0:6db20bbdc767 678
mikekelly99 0:6db20bbdc767 679 static
mikekelly99 0:6db20bbdc767 680 void clear_lock ( /* Clear lock entries of the volume */
mikekelly99 0:6db20bbdc767 681 FATFS *fs
mikekelly99 0:6db20bbdc767 682 )
mikekelly99 0:6db20bbdc767 683 {
mikekelly99 0:6db20bbdc767 684 UINT i;
mikekelly99 0:6db20bbdc767 685
mikekelly99 0:6db20bbdc767 686 for (i = 0; i < _FS_LOCK; i++) {
mikekelly99 0:6db20bbdc767 687 if (Files[i].fs == fs) Files[i].fs = 0;
mikekelly99 0:6db20bbdc767 688 }
mikekelly99 0:6db20bbdc767 689 }
mikekelly99 0:6db20bbdc767 690 #endif
mikekelly99 0:6db20bbdc767 691
mikekelly99 0:6db20bbdc767 692
mikekelly99 0:6db20bbdc767 693
mikekelly99 0:6db20bbdc767 694
mikekelly99 0:6db20bbdc767 695 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 696 /* Move/Flush disk access window in the file system object */
mikekelly99 0:6db20bbdc767 697 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 698 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 699 static
mikekelly99 0:6db20bbdc767 700 FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 701 FATFS* fs /* File system object */
mikekelly99 0:6db20bbdc767 702 )
mikekelly99 0:6db20bbdc767 703 {
mikekelly99 0:6db20bbdc767 704 DWORD wsect;
mikekelly99 0:6db20bbdc767 705 UINT nf;
mikekelly99 0:6db20bbdc767 706 FRESULT res = FR_OK;
mikekelly99 0:6db20bbdc767 707
mikekelly99 0:6db20bbdc767 708
mikekelly99 0:6db20bbdc767 709 if (fs->wflag) { /* Write back the sector if it is dirty */
mikekelly99 0:6db20bbdc767 710 wsect = fs->winsect; /* Current sector number */
mikekelly99 0:6db20bbdc767 711 if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) {
mikekelly99 0:6db20bbdc767 712 res = FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 713 } else {
mikekelly99 0:6db20bbdc767 714 fs->wflag = 0;
mikekelly99 0:6db20bbdc767 715 if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */
mikekelly99 0:6db20bbdc767 716 for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */
mikekelly99 0:6db20bbdc767 717 wsect += fs->fsize;
mikekelly99 0:6db20bbdc767 718 disk_write(fs->drv, fs->win, wsect, 1);
mikekelly99 0:6db20bbdc767 719 }
mikekelly99 0:6db20bbdc767 720 }
mikekelly99 0:6db20bbdc767 721 }
mikekelly99 0:6db20bbdc767 722 }
mikekelly99 0:6db20bbdc767 723 return res;
mikekelly99 0:6db20bbdc767 724 }
mikekelly99 0:6db20bbdc767 725 #endif
mikekelly99 0:6db20bbdc767 726
mikekelly99 0:6db20bbdc767 727
mikekelly99 0:6db20bbdc767 728 static
mikekelly99 0:6db20bbdc767 729 FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 730 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 731 DWORD sector /* Sector number to make appearance in the fs->win[] */
mikekelly99 0:6db20bbdc767 732 )
mikekelly99 0:6db20bbdc767 733 {
mikekelly99 0:6db20bbdc767 734 FRESULT res = FR_OK;
mikekelly99 0:6db20bbdc767 735
mikekelly99 0:6db20bbdc767 736
mikekelly99 0:6db20bbdc767 737 if (sector != fs->winsect) { /* Window offset changed? */
mikekelly99 0:6db20bbdc767 738 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 739 res = sync_window(fs); /* Write-back changes */
mikekelly99 0:6db20bbdc767 740 #endif
mikekelly99 0:6db20bbdc767 741 if (res == FR_OK) { /* Fill sector window with new data */
mikekelly99 0:6db20bbdc767 742 if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) {
mikekelly99 0:6db20bbdc767 743 sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */
mikekelly99 0:6db20bbdc767 744 res = FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 745 }
mikekelly99 0:6db20bbdc767 746 fs->winsect = sector;
mikekelly99 0:6db20bbdc767 747 }
mikekelly99 0:6db20bbdc767 748 }
mikekelly99 0:6db20bbdc767 749 return res;
mikekelly99 0:6db20bbdc767 750 }
mikekelly99 0:6db20bbdc767 751
mikekelly99 0:6db20bbdc767 752
mikekelly99 0:6db20bbdc767 753
mikekelly99 0:6db20bbdc767 754
mikekelly99 0:6db20bbdc767 755 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 756 /* Synchronize file system and strage device */
mikekelly99 0:6db20bbdc767 757 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 758 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 759 static
mikekelly99 0:6db20bbdc767 760 FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 761 FATFS* fs /* File system object */
mikekelly99 0:6db20bbdc767 762 )
mikekelly99 0:6db20bbdc767 763 {
mikekelly99 0:6db20bbdc767 764 FRESULT res;
mikekelly99 0:6db20bbdc767 765
mikekelly99 0:6db20bbdc767 766
mikekelly99 0:6db20bbdc767 767 res = sync_window(fs);
mikekelly99 0:6db20bbdc767 768 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 769 /* Update FSInfo sector if needed */
mikekelly99 0:6db20bbdc767 770 if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
mikekelly99 0:6db20bbdc767 771 /* Create FSInfo structure */
mikekelly99 0:6db20bbdc767 772 mem_set(fs->win, 0, SS(fs));
mikekelly99 0:6db20bbdc767 773 ST_WORD(fs->win + BS_55AA, 0xAA55);
mikekelly99 0:6db20bbdc767 774 ST_DWORD(fs->win + FSI_LeadSig, 0x41615252);
mikekelly99 0:6db20bbdc767 775 ST_DWORD(fs->win + FSI_StrucSig, 0x61417272);
mikekelly99 0:6db20bbdc767 776 ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust);
mikekelly99 0:6db20bbdc767 777 ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust);
mikekelly99 0:6db20bbdc767 778 /* Write it into the FSInfo sector */
mikekelly99 0:6db20bbdc767 779 fs->winsect = fs->volbase + 1;
mikekelly99 0:6db20bbdc767 780 disk_write(fs->drv, fs->win, fs->winsect, 1);
mikekelly99 0:6db20bbdc767 781 fs->fsi_flag = 0;
mikekelly99 0:6db20bbdc767 782 }
mikekelly99 0:6db20bbdc767 783 /* Make sure that no pending write process in the physical drive */
mikekelly99 0:6db20bbdc767 784 if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)
mikekelly99 0:6db20bbdc767 785 res = FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 786 }
mikekelly99 0:6db20bbdc767 787
mikekelly99 0:6db20bbdc767 788 return res;
mikekelly99 0:6db20bbdc767 789 }
mikekelly99 0:6db20bbdc767 790 #endif
mikekelly99 0:6db20bbdc767 791
mikekelly99 0:6db20bbdc767 792
mikekelly99 0:6db20bbdc767 793
mikekelly99 0:6db20bbdc767 794
mikekelly99 0:6db20bbdc767 795 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 796 /* Get sector# from cluster# */
mikekelly99 0:6db20bbdc767 797 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 798 /* Hidden API for hacks and disk tools */
mikekelly99 0:6db20bbdc767 799
mikekelly99 0:6db20bbdc767 800 DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */
mikekelly99 0:6db20bbdc767 801 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 802 DWORD clst /* Cluster# to be converted */
mikekelly99 0:6db20bbdc767 803 )
mikekelly99 0:6db20bbdc767 804 {
mikekelly99 0:6db20bbdc767 805 clst -= 2;
mikekelly99 0:6db20bbdc767 806 if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */
mikekelly99 0:6db20bbdc767 807 return clst * fs->csize + fs->database;
mikekelly99 0:6db20bbdc767 808 }
mikekelly99 0:6db20bbdc767 809
mikekelly99 0:6db20bbdc767 810
mikekelly99 0:6db20bbdc767 811
mikekelly99 0:6db20bbdc767 812
mikekelly99 0:6db20bbdc767 813 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 814 /* FAT access - Read value of a FAT entry */
mikekelly99 0:6db20bbdc767 815 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 816 /* Hidden API for hacks and disk tools */
mikekelly99 0:6db20bbdc767 817
mikekelly99 0:6db20bbdc767 818 DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */
mikekelly99 0:6db20bbdc767 819 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 820 DWORD clst /* FAT index number (cluster number) to get the value */
mikekelly99 0:6db20bbdc767 821 )
mikekelly99 0:6db20bbdc767 822 {
mikekelly99 0:6db20bbdc767 823 UINT wc, bc;
mikekelly99 0:6db20bbdc767 824 BYTE *p;
mikekelly99 0:6db20bbdc767 825 DWORD val;
mikekelly99 0:6db20bbdc767 826
mikekelly99 0:6db20bbdc767 827
mikekelly99 0:6db20bbdc767 828 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
mikekelly99 0:6db20bbdc767 829 val = 1; /* Internal error */
mikekelly99 0:6db20bbdc767 830
mikekelly99 0:6db20bbdc767 831 } else {
mikekelly99 0:6db20bbdc767 832 val = 0xFFFFFFFF; /* Default value falls on disk error */
mikekelly99 0:6db20bbdc767 833
mikekelly99 0:6db20bbdc767 834 switch (fs->fs_type) {
mikekelly99 0:6db20bbdc767 835 case FS_FAT12 :
mikekelly99 0:6db20bbdc767 836 bc = (UINT)clst; bc += bc / 2;
mikekelly99 0:6db20bbdc767 837 if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
mikekelly99 0:6db20bbdc767 838 wc = fs->win[bc++ % SS(fs)];
mikekelly99 0:6db20bbdc767 839 if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
mikekelly99 0:6db20bbdc767 840 wc |= fs->win[bc % SS(fs)] << 8;
mikekelly99 0:6db20bbdc767 841 val = clst & 1 ? wc >> 4 : (wc & 0xFFF);
mikekelly99 0:6db20bbdc767 842 break;
mikekelly99 0:6db20bbdc767 843
mikekelly99 0:6db20bbdc767 844 case FS_FAT16 :
mikekelly99 0:6db20bbdc767 845 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;
mikekelly99 0:6db20bbdc767 846 p = &fs->win[clst * 2 % SS(fs)];
mikekelly99 0:6db20bbdc767 847 val = LD_WORD(p);
mikekelly99 0:6db20bbdc767 848 break;
mikekelly99 0:6db20bbdc767 849
mikekelly99 0:6db20bbdc767 850 case FS_FAT32 :
mikekelly99 0:6db20bbdc767 851 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
mikekelly99 0:6db20bbdc767 852 p = &fs->win[clst * 4 % SS(fs)];
mikekelly99 0:6db20bbdc767 853 val = LD_DWORD(p) & 0x0FFFFFFF;
mikekelly99 0:6db20bbdc767 854 break;
mikekelly99 0:6db20bbdc767 855
mikekelly99 0:6db20bbdc767 856 default:
mikekelly99 0:6db20bbdc767 857 val = 1; /* Internal error */
mikekelly99 0:6db20bbdc767 858 }
mikekelly99 0:6db20bbdc767 859 }
mikekelly99 0:6db20bbdc767 860
mikekelly99 0:6db20bbdc767 861 return val;
mikekelly99 0:6db20bbdc767 862 }
mikekelly99 0:6db20bbdc767 863
mikekelly99 0:6db20bbdc767 864
mikekelly99 0:6db20bbdc767 865
mikekelly99 0:6db20bbdc767 866
mikekelly99 0:6db20bbdc767 867 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 868 /* FAT access - Change value of a FAT entry */
mikekelly99 0:6db20bbdc767 869 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 870 /* Hidden API for hacks and disk tools */
mikekelly99 0:6db20bbdc767 871
mikekelly99 0:6db20bbdc767 872 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 873 FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 874 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 875 DWORD clst, /* FAT index number (cluster number) to be changed */
mikekelly99 0:6db20bbdc767 876 DWORD val /* New value to be set to the entry */
mikekelly99 0:6db20bbdc767 877 )
mikekelly99 0:6db20bbdc767 878 {
mikekelly99 0:6db20bbdc767 879 UINT bc;
mikekelly99 0:6db20bbdc767 880 BYTE *p;
mikekelly99 0:6db20bbdc767 881 FRESULT res;
mikekelly99 0:6db20bbdc767 882
mikekelly99 0:6db20bbdc767 883
mikekelly99 0:6db20bbdc767 884 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
mikekelly99 0:6db20bbdc767 885 res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 886
mikekelly99 0:6db20bbdc767 887 } else {
mikekelly99 0:6db20bbdc767 888 switch (fs->fs_type) {
mikekelly99 0:6db20bbdc767 889 case FS_FAT12 :
mikekelly99 0:6db20bbdc767 890 bc = (UINT)clst; bc += bc / 2;
mikekelly99 0:6db20bbdc767 891 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
mikekelly99 0:6db20bbdc767 892 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 893 p = &fs->win[bc++ % SS(fs)];
mikekelly99 0:6db20bbdc767 894 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
mikekelly99 0:6db20bbdc767 895 fs->wflag = 1;
mikekelly99 0:6db20bbdc767 896 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
mikekelly99 0:6db20bbdc767 897 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 898 p = &fs->win[bc % SS(fs)];
mikekelly99 0:6db20bbdc767 899 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
mikekelly99 0:6db20bbdc767 900 fs->wflag = 1;
mikekelly99 0:6db20bbdc767 901 break;
mikekelly99 0:6db20bbdc767 902
mikekelly99 0:6db20bbdc767 903 case FS_FAT16 :
mikekelly99 0:6db20bbdc767 904 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
mikekelly99 0:6db20bbdc767 905 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 906 p = &fs->win[clst * 2 % SS(fs)];
mikekelly99 0:6db20bbdc767 907 ST_WORD(p, (WORD)val);
mikekelly99 0:6db20bbdc767 908 fs->wflag = 1;
mikekelly99 0:6db20bbdc767 909 break;
mikekelly99 0:6db20bbdc767 910
mikekelly99 0:6db20bbdc767 911 case FS_FAT32 :
mikekelly99 0:6db20bbdc767 912 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
mikekelly99 0:6db20bbdc767 913 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 914 p = &fs->win[clst * 4 % SS(fs)];
mikekelly99 0:6db20bbdc767 915 val |= LD_DWORD(p) & 0xF0000000;
mikekelly99 0:6db20bbdc767 916 ST_DWORD(p, val);
mikekelly99 0:6db20bbdc767 917 fs->wflag = 1;
mikekelly99 0:6db20bbdc767 918 break;
mikekelly99 0:6db20bbdc767 919
mikekelly99 0:6db20bbdc767 920 default :
mikekelly99 0:6db20bbdc767 921 res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 922 }
mikekelly99 0:6db20bbdc767 923 }
mikekelly99 0:6db20bbdc767 924
mikekelly99 0:6db20bbdc767 925 return res;
mikekelly99 0:6db20bbdc767 926 }
mikekelly99 0:6db20bbdc767 927 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 928
mikekelly99 0:6db20bbdc767 929
mikekelly99 0:6db20bbdc767 930
mikekelly99 0:6db20bbdc767 931
mikekelly99 0:6db20bbdc767 932 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 933 /* FAT handling - Remove a cluster chain */
mikekelly99 0:6db20bbdc767 934 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 935 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 936 static
mikekelly99 0:6db20bbdc767 937 FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 938 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 939 DWORD clst /* Cluster# to remove a chain from */
mikekelly99 0:6db20bbdc767 940 )
mikekelly99 0:6db20bbdc767 941 {
mikekelly99 0:6db20bbdc767 942 FRESULT res;
mikekelly99 0:6db20bbdc767 943 DWORD nxt;
mikekelly99 0:6db20bbdc767 944 #if _USE_TRIM
mikekelly99 0:6db20bbdc767 945 DWORD scl = clst, ecl = clst, rt[2];
mikekelly99 0:6db20bbdc767 946 #endif
mikekelly99 0:6db20bbdc767 947
mikekelly99 0:6db20bbdc767 948 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
mikekelly99 0:6db20bbdc767 949 res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 950
mikekelly99 0:6db20bbdc767 951 } else {
mikekelly99 0:6db20bbdc767 952 res = FR_OK;
mikekelly99 0:6db20bbdc767 953 while (clst < fs->n_fatent) { /* Not a last link? */
mikekelly99 0:6db20bbdc767 954 nxt = get_fat(fs, clst); /* Get cluster status */
mikekelly99 0:6db20bbdc767 955 if (nxt == 0) break; /* Empty cluster? */
mikekelly99 0:6db20bbdc767 956 if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
mikekelly99 0:6db20bbdc767 957 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
mikekelly99 0:6db20bbdc767 958 res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
mikekelly99 0:6db20bbdc767 959 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 960 if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */
mikekelly99 0:6db20bbdc767 961 fs->free_clust++;
mikekelly99 0:6db20bbdc767 962 fs->fsi_flag |= 1;
mikekelly99 0:6db20bbdc767 963 }
mikekelly99 0:6db20bbdc767 964 #if _USE_TRIM
mikekelly99 0:6db20bbdc767 965 if (ecl + 1 == nxt) { /* Is next cluster contiguous? */
mikekelly99 0:6db20bbdc767 966 ecl = nxt;
mikekelly99 0:6db20bbdc767 967 } else { /* End of contiguous clusters */
mikekelly99 0:6db20bbdc767 968 rt[0] = clust2sect(fs, scl); /* Start sector */
mikekelly99 0:6db20bbdc767 969 rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
mikekelly99 0:6db20bbdc767 970 disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */
mikekelly99 0:6db20bbdc767 971 scl = ecl = nxt;
mikekelly99 0:6db20bbdc767 972 }
mikekelly99 0:6db20bbdc767 973 #endif
mikekelly99 0:6db20bbdc767 974 clst = nxt; /* Next cluster */
mikekelly99 0:6db20bbdc767 975 }
mikekelly99 0:6db20bbdc767 976 }
mikekelly99 0:6db20bbdc767 977
mikekelly99 0:6db20bbdc767 978 return res;
mikekelly99 0:6db20bbdc767 979 }
mikekelly99 0:6db20bbdc767 980 #endif
mikekelly99 0:6db20bbdc767 981
mikekelly99 0:6db20bbdc767 982
mikekelly99 0:6db20bbdc767 983
mikekelly99 0:6db20bbdc767 984
mikekelly99 0:6db20bbdc767 985 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 986 /* FAT handling - Stretch or Create a cluster chain */
mikekelly99 0:6db20bbdc767 987 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 988 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 989 static
mikekelly99 0:6db20bbdc767 990 DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
mikekelly99 0:6db20bbdc767 991 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 992 DWORD clst /* Cluster# to stretch, 0:Create a new chain */
mikekelly99 0:6db20bbdc767 993 )
mikekelly99 0:6db20bbdc767 994 {
mikekelly99 0:6db20bbdc767 995 DWORD cs, ncl, scl;
mikekelly99 0:6db20bbdc767 996 FRESULT res;
mikekelly99 0:6db20bbdc767 997
mikekelly99 0:6db20bbdc767 998
mikekelly99 0:6db20bbdc767 999 if (clst == 0) { /* Create a new chain */
mikekelly99 0:6db20bbdc767 1000 scl = fs->last_clust; /* Get suggested start point */
mikekelly99 0:6db20bbdc767 1001 if (!scl || scl >= fs->n_fatent) scl = 1;
mikekelly99 0:6db20bbdc767 1002 }
mikekelly99 0:6db20bbdc767 1003 else { /* Stretch the current chain */
mikekelly99 0:6db20bbdc767 1004 cs = get_fat(fs, clst); /* Check the cluster status */
mikekelly99 0:6db20bbdc767 1005 if (cs < 2) return 1; /* Invalid value */
mikekelly99 0:6db20bbdc767 1006 if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */
mikekelly99 0:6db20bbdc767 1007 if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
mikekelly99 0:6db20bbdc767 1008 scl = clst;
mikekelly99 0:6db20bbdc767 1009 }
mikekelly99 0:6db20bbdc767 1010
mikekelly99 0:6db20bbdc767 1011 ncl = scl; /* Start cluster */
mikekelly99 0:6db20bbdc767 1012 for (;;) {
mikekelly99 0:6db20bbdc767 1013 ncl++; /* Next cluster */
mikekelly99 0:6db20bbdc767 1014 if (ncl >= fs->n_fatent) { /* Check wrap around */
mikekelly99 0:6db20bbdc767 1015 ncl = 2;
mikekelly99 0:6db20bbdc767 1016 if (ncl > scl) return 0; /* No free cluster */
mikekelly99 0:6db20bbdc767 1017 }
mikekelly99 0:6db20bbdc767 1018 cs = get_fat(fs, ncl); /* Get the cluster status */
mikekelly99 0:6db20bbdc767 1019 if (cs == 0) break; /* Found a free cluster */
mikekelly99 0:6db20bbdc767 1020 if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
mikekelly99 0:6db20bbdc767 1021 return cs;
mikekelly99 0:6db20bbdc767 1022 if (ncl == scl) return 0; /* No free cluster */
mikekelly99 0:6db20bbdc767 1023 }
mikekelly99 0:6db20bbdc767 1024
mikekelly99 0:6db20bbdc767 1025 res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
mikekelly99 0:6db20bbdc767 1026 if (res == FR_OK && clst != 0) {
mikekelly99 0:6db20bbdc767 1027 res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
mikekelly99 0:6db20bbdc767 1028 }
mikekelly99 0:6db20bbdc767 1029 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1030 fs->last_clust = ncl; /* Update FSINFO */
mikekelly99 0:6db20bbdc767 1031 if (fs->free_clust != 0xFFFFFFFF) {
mikekelly99 0:6db20bbdc767 1032 fs->free_clust--;
mikekelly99 0:6db20bbdc767 1033 fs->fsi_flag |= 1;
mikekelly99 0:6db20bbdc767 1034 }
mikekelly99 0:6db20bbdc767 1035 } else {
mikekelly99 0:6db20bbdc767 1036 ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
mikekelly99 0:6db20bbdc767 1037 }
mikekelly99 0:6db20bbdc767 1038
mikekelly99 0:6db20bbdc767 1039 return ncl; /* Return new cluster number or error code */
mikekelly99 0:6db20bbdc767 1040 }
mikekelly99 0:6db20bbdc767 1041 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 1042
mikekelly99 0:6db20bbdc767 1043
mikekelly99 0:6db20bbdc767 1044
mikekelly99 0:6db20bbdc767 1045
mikekelly99 0:6db20bbdc767 1046 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1047 /* FAT handling - Convert offset into cluster with link map table */
mikekelly99 0:6db20bbdc767 1048 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1049
mikekelly99 0:6db20bbdc767 1050 #if _USE_FASTSEEK
mikekelly99 0:6db20bbdc767 1051 static
mikekelly99 0:6db20bbdc767 1052 DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
mikekelly99 0:6db20bbdc767 1053 FIL* fp, /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 1054 DWORD ofs /* File offset to be converted to cluster# */
mikekelly99 0:6db20bbdc767 1055 )
mikekelly99 0:6db20bbdc767 1056 {
mikekelly99 0:6db20bbdc767 1057 DWORD cl, ncl, *tbl;
mikekelly99 0:6db20bbdc767 1058
mikekelly99 0:6db20bbdc767 1059
mikekelly99 0:6db20bbdc767 1060 tbl = fp->cltbl + 1; /* Top of CLMT */
mikekelly99 0:6db20bbdc767 1061 cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */
mikekelly99 0:6db20bbdc767 1062 for (;;) {
mikekelly99 0:6db20bbdc767 1063 ncl = *tbl++; /* Number of cluters in the fragment */
mikekelly99 0:6db20bbdc767 1064 if (!ncl) return 0; /* End of table? (error) */
mikekelly99 0:6db20bbdc767 1065 if (cl < ncl) break; /* In this fragment? */
mikekelly99 0:6db20bbdc767 1066 cl -= ncl; tbl++; /* Next fragment */
mikekelly99 0:6db20bbdc767 1067 }
mikekelly99 0:6db20bbdc767 1068 return cl + *tbl; /* Return the cluster number */
mikekelly99 0:6db20bbdc767 1069 }
mikekelly99 0:6db20bbdc767 1070 #endif /* _USE_FASTSEEK */
mikekelly99 0:6db20bbdc767 1071
mikekelly99 0:6db20bbdc767 1072
mikekelly99 0:6db20bbdc767 1073
mikekelly99 0:6db20bbdc767 1074
mikekelly99 0:6db20bbdc767 1075 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1076 /* Directory handling - Set directory index */
mikekelly99 0:6db20bbdc767 1077 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1078
mikekelly99 0:6db20bbdc767 1079 static
mikekelly99 0:6db20bbdc767 1080 FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 1081 FATFS_DIR* dp, /* Pointer to directory object */
mikekelly99 0:6db20bbdc767 1082 UINT idx /* Index of directory table */
mikekelly99 0:6db20bbdc767 1083 )
mikekelly99 0:6db20bbdc767 1084 {
mikekelly99 0:6db20bbdc767 1085 DWORD clst, sect;
mikekelly99 0:6db20bbdc767 1086 UINT ic;
mikekelly99 0:6db20bbdc767 1087
mikekelly99 0:6db20bbdc767 1088
mikekelly99 0:6db20bbdc767 1089 dp->index = (WORD)idx; /* Current index */
mikekelly99 0:6db20bbdc767 1090 clst = dp->sclust; /* Table start cluster (0:root) */
mikekelly99 0:6db20bbdc767 1091 if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */
mikekelly99 0:6db20bbdc767 1092 return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1093 if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
mikekelly99 0:6db20bbdc767 1094 clst = dp->fs->dirbase;
mikekelly99 0:6db20bbdc767 1095
mikekelly99 0:6db20bbdc767 1096 if (clst == 0) { /* Static table (root-directory in FAT12/16) */
mikekelly99 0:6db20bbdc767 1097 if (idx >= dp->fs->n_rootdir) /* Is index out of range? */
mikekelly99 0:6db20bbdc767 1098 return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1099 sect = dp->fs->dirbase;
mikekelly99 0:6db20bbdc767 1100 }
mikekelly99 0:6db20bbdc767 1101 else { /* Dynamic table (root-directory in FAT32 or sub-directory) */
mikekelly99 0:6db20bbdc767 1102 ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */
mikekelly99 0:6db20bbdc767 1103 while (idx >= ic) { /* Follow cluster chain */
mikekelly99 0:6db20bbdc767 1104 clst = get_fat(dp->fs, clst); /* Get next cluster */
mikekelly99 0:6db20bbdc767 1105 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
mikekelly99 0:6db20bbdc767 1106 if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */
mikekelly99 0:6db20bbdc767 1107 return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1108 idx -= ic;
mikekelly99 0:6db20bbdc767 1109 }
mikekelly99 0:6db20bbdc767 1110 sect = clust2sect(dp->fs, clst);
mikekelly99 0:6db20bbdc767 1111 }
mikekelly99 0:6db20bbdc767 1112 dp->clust = clst; /* Current cluster# */
mikekelly99 0:6db20bbdc767 1113 if (!sect) return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1114 dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */
mikekelly99 0:6db20bbdc767 1115 dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */
mikekelly99 0:6db20bbdc767 1116
mikekelly99 0:6db20bbdc767 1117 return FR_OK;
mikekelly99 0:6db20bbdc767 1118 }
mikekelly99 0:6db20bbdc767 1119
mikekelly99 0:6db20bbdc767 1120
mikekelly99 0:6db20bbdc767 1121
mikekelly99 0:6db20bbdc767 1122
mikekelly99 0:6db20bbdc767 1123 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1124 /* Directory handling - Move directory table index next */
mikekelly99 0:6db20bbdc767 1125 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1126
mikekelly99 0:6db20bbdc767 1127 static
mikekelly99 0:6db20bbdc767 1128 FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */
mikekelly99 0:6db20bbdc767 1129 FATFS_DIR* dp, /* Pointer to the directory object */
mikekelly99 0:6db20bbdc767 1130 int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
mikekelly99 0:6db20bbdc767 1131 )
mikekelly99 0:6db20bbdc767 1132 {
mikekelly99 0:6db20bbdc767 1133 DWORD clst;
mikekelly99 0:6db20bbdc767 1134 UINT i;
mikekelly99 0:6db20bbdc767 1135 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 1136 UINT c;
mikekelly99 0:6db20bbdc767 1137 #endif
mikekelly99 0:6db20bbdc767 1138
mikekelly99 0:6db20bbdc767 1139
mikekelly99 0:6db20bbdc767 1140 i = dp->index + 1;
mikekelly99 0:6db20bbdc767 1141 if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */
mikekelly99 0:6db20bbdc767 1142 return FR_NO_FILE;
mikekelly99 0:6db20bbdc767 1143
mikekelly99 0:6db20bbdc767 1144 if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */
mikekelly99 0:6db20bbdc767 1145 dp->sect++; /* Next sector */
mikekelly99 0:6db20bbdc767 1146
mikekelly99 0:6db20bbdc767 1147 if (!dp->clust) { /* Static table */
mikekelly99 0:6db20bbdc767 1148 if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */
mikekelly99 0:6db20bbdc767 1149 return FR_NO_FILE;
mikekelly99 0:6db20bbdc767 1150 }
mikekelly99 0:6db20bbdc767 1151 else { /* Dynamic table */
mikekelly99 0:6db20bbdc767 1152 if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */
mikekelly99 0:6db20bbdc767 1153 clst = get_fat(dp->fs, dp->clust); /* Get next cluster */
mikekelly99 0:6db20bbdc767 1154 if (clst <= 1) return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1155 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 1156 if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */
mikekelly99 0:6db20bbdc767 1157 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 1158 if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */
mikekelly99 0:6db20bbdc767 1159 clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */
mikekelly99 0:6db20bbdc767 1160 if (clst == 0) return FR_DENIED; /* No free cluster */
mikekelly99 0:6db20bbdc767 1161 if (clst == 1) return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1162 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 1163 /* Clean-up stretched table */
mikekelly99 0:6db20bbdc767 1164 if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */
mikekelly99 0:6db20bbdc767 1165 mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */
mikekelly99 0:6db20bbdc767 1166 dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */
mikekelly99 0:6db20bbdc767 1167 for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */
mikekelly99 0:6db20bbdc767 1168 dp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 1169 if (sync_window(dp->fs)) return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 1170 dp->fs->winsect++;
mikekelly99 0:6db20bbdc767 1171 }
mikekelly99 0:6db20bbdc767 1172 dp->fs->winsect -= c; /* Rewind window offset */
mikekelly99 0:6db20bbdc767 1173 #else
mikekelly99 0:6db20bbdc767 1174 if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */
mikekelly99 0:6db20bbdc767 1175 return FR_NO_FILE; /* Report EOT */
mikekelly99 0:6db20bbdc767 1176 #endif
mikekelly99 0:6db20bbdc767 1177 }
mikekelly99 0:6db20bbdc767 1178 dp->clust = clst; /* Initialize data for new cluster */
mikekelly99 0:6db20bbdc767 1179 dp->sect = clust2sect(dp->fs, clst);
mikekelly99 0:6db20bbdc767 1180 }
mikekelly99 0:6db20bbdc767 1181 }
mikekelly99 0:6db20bbdc767 1182 }
mikekelly99 0:6db20bbdc767 1183
mikekelly99 0:6db20bbdc767 1184 dp->index = (WORD)i; /* Current index */
mikekelly99 0:6db20bbdc767 1185 dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */
mikekelly99 0:6db20bbdc767 1186
mikekelly99 0:6db20bbdc767 1187 return FR_OK;
mikekelly99 0:6db20bbdc767 1188 }
mikekelly99 0:6db20bbdc767 1189
mikekelly99 0:6db20bbdc767 1190
mikekelly99 0:6db20bbdc767 1191
mikekelly99 0:6db20bbdc767 1192
mikekelly99 0:6db20bbdc767 1193 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1194 /* Directory handling - Reserve directory entry */
mikekelly99 0:6db20bbdc767 1195 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1196
mikekelly99 0:6db20bbdc767 1197 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 1198 static
mikekelly99 0:6db20bbdc767 1199 FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 1200 FATFS_DIR* dp, /* Pointer to the directory object */
mikekelly99 0:6db20bbdc767 1201 UINT nent /* Number of contiguous entries to allocate (1-21) */
mikekelly99 0:6db20bbdc767 1202 )
mikekelly99 0:6db20bbdc767 1203 {
mikekelly99 0:6db20bbdc767 1204 FRESULT res;
mikekelly99 0:6db20bbdc767 1205 UINT n;
mikekelly99 0:6db20bbdc767 1206
mikekelly99 0:6db20bbdc767 1207
mikekelly99 0:6db20bbdc767 1208 res = dir_sdi(dp, 0);
mikekelly99 0:6db20bbdc767 1209 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1210 n = 0;
mikekelly99 0:6db20bbdc767 1211 do {
mikekelly99 0:6db20bbdc767 1212 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1213 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1214 if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */
mikekelly99 0:6db20bbdc767 1215 if (++n == nent) break; /* A block of contiguous free entries is found */
mikekelly99 0:6db20bbdc767 1216 } else {
mikekelly99 0:6db20bbdc767 1217 n = 0; /* Not a blank entry. Restart to search */
mikekelly99 0:6db20bbdc767 1218 }
mikekelly99 0:6db20bbdc767 1219 res = dir_next(dp, 1); /* Next entry with table stretch enabled */
mikekelly99 0:6db20bbdc767 1220 } while (res == FR_OK);
mikekelly99 0:6db20bbdc767 1221 }
mikekelly99 0:6db20bbdc767 1222 if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */
mikekelly99 0:6db20bbdc767 1223 return res;
mikekelly99 0:6db20bbdc767 1224 }
mikekelly99 0:6db20bbdc767 1225 #endif
mikekelly99 0:6db20bbdc767 1226
mikekelly99 0:6db20bbdc767 1227
mikekelly99 0:6db20bbdc767 1228
mikekelly99 0:6db20bbdc767 1229
mikekelly99 0:6db20bbdc767 1230 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1231 /* Directory handling - Load/Store start cluster number */
mikekelly99 0:6db20bbdc767 1232 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1233
mikekelly99 0:6db20bbdc767 1234 static
mikekelly99 0:6db20bbdc767 1235 DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */
mikekelly99 0:6db20bbdc767 1236 FATFS* fs, /* Pointer to the fs object */
mikekelly99 0:6db20bbdc767 1237 const BYTE* dir /* Pointer to the SFN entry */
mikekelly99 0:6db20bbdc767 1238 )
mikekelly99 0:6db20bbdc767 1239 {
mikekelly99 0:6db20bbdc767 1240 DWORD cl;
mikekelly99 0:6db20bbdc767 1241
mikekelly99 0:6db20bbdc767 1242 cl = LD_WORD(dir + DIR_FstClusLO);
mikekelly99 0:6db20bbdc767 1243 if (fs->fs_type == FS_FAT32)
mikekelly99 0:6db20bbdc767 1244 cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16;
mikekelly99 0:6db20bbdc767 1245
mikekelly99 0:6db20bbdc767 1246 return cl;
mikekelly99 0:6db20bbdc767 1247 }
mikekelly99 0:6db20bbdc767 1248
mikekelly99 0:6db20bbdc767 1249
mikekelly99 0:6db20bbdc767 1250 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 1251 static
mikekelly99 0:6db20bbdc767 1252 void st_clust (
mikekelly99 0:6db20bbdc767 1253 BYTE* dir, /* Pointer to the SFN entry */
mikekelly99 0:6db20bbdc767 1254 DWORD cl /* Value to be set */
mikekelly99 0:6db20bbdc767 1255 )
mikekelly99 0:6db20bbdc767 1256 {
mikekelly99 0:6db20bbdc767 1257 ST_WORD(dir + DIR_FstClusLO, cl);
mikekelly99 0:6db20bbdc767 1258 ST_WORD(dir + DIR_FstClusHI, cl >> 16);
mikekelly99 0:6db20bbdc767 1259 }
mikekelly99 0:6db20bbdc767 1260 #endif
mikekelly99 0:6db20bbdc767 1261
mikekelly99 0:6db20bbdc767 1262
mikekelly99 0:6db20bbdc767 1263
mikekelly99 0:6db20bbdc767 1264
mikekelly99 0:6db20bbdc767 1265 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1266 /* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
mikekelly99 0:6db20bbdc767 1267 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1268 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1269 static
mikekelly99 0:6db20bbdc767 1270 const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */
mikekelly99 0:6db20bbdc767 1271
mikekelly99 0:6db20bbdc767 1272
mikekelly99 0:6db20bbdc767 1273 static
mikekelly99 0:6db20bbdc767 1274 int cmp_lfn ( /* 1:matched, 0:not matched */
mikekelly99 0:6db20bbdc767 1275 WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */
mikekelly99 0:6db20bbdc767 1276 BYTE* dir /* Pointer to the directory entry containing the part of LFN */
mikekelly99 0:6db20bbdc767 1277 )
mikekelly99 0:6db20bbdc767 1278 {
mikekelly99 0:6db20bbdc767 1279 UINT i, s;
mikekelly99 0:6db20bbdc767 1280 WCHAR wc, uc;
mikekelly99 0:6db20bbdc767 1281
mikekelly99 0:6db20bbdc767 1282
mikekelly99 0:6db20bbdc767 1283 if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
mikekelly99 0:6db20bbdc767 1284
mikekelly99 0:6db20bbdc767 1285 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
mikekelly99 0:6db20bbdc767 1286
mikekelly99 0:6db20bbdc767 1287 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
mikekelly99 0:6db20bbdc767 1288 uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
mikekelly99 0:6db20bbdc767 1289 if (wc) {
mikekelly99 0:6db20bbdc767 1290 if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) /* Compare it */
mikekelly99 0:6db20bbdc767 1291 return 0; /* Not matched */
mikekelly99 0:6db20bbdc767 1292 wc = uc;
mikekelly99 0:6db20bbdc767 1293 } else {
mikekelly99 0:6db20bbdc767 1294 if (uc != 0xFFFF) return 0; /* Check filler */
mikekelly99 0:6db20bbdc767 1295 }
mikekelly99 0:6db20bbdc767 1296 }
mikekelly99 0:6db20bbdc767 1297
mikekelly99 0:6db20bbdc767 1298 if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */
mikekelly99 0:6db20bbdc767 1299 return 0;
mikekelly99 0:6db20bbdc767 1300
mikekelly99 0:6db20bbdc767 1301 return 1; /* The part of LFN matched */
mikekelly99 0:6db20bbdc767 1302 }
mikekelly99 0:6db20bbdc767 1303
mikekelly99 0:6db20bbdc767 1304
mikekelly99 0:6db20bbdc767 1305
mikekelly99 0:6db20bbdc767 1306 static
mikekelly99 0:6db20bbdc767 1307 int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
mikekelly99 0:6db20bbdc767 1308 WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
mikekelly99 0:6db20bbdc767 1309 BYTE* dir /* Pointer to the LFN entry */
mikekelly99 0:6db20bbdc767 1310 )
mikekelly99 0:6db20bbdc767 1311 {
mikekelly99 0:6db20bbdc767 1312 UINT i, s;
mikekelly99 0:6db20bbdc767 1313 WCHAR wc, uc;
mikekelly99 0:6db20bbdc767 1314
mikekelly99 0:6db20bbdc767 1315
mikekelly99 0:6db20bbdc767 1316 if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
mikekelly99 0:6db20bbdc767 1317
mikekelly99 0:6db20bbdc767 1318 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
mikekelly99 0:6db20bbdc767 1319
mikekelly99 0:6db20bbdc767 1320 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
mikekelly99 0:6db20bbdc767 1321 uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
mikekelly99 0:6db20bbdc767 1322 if (wc) {
mikekelly99 0:6db20bbdc767 1323 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
mikekelly99 0:6db20bbdc767 1324 lfnbuf[i++] = wc = uc; /* Store it */
mikekelly99 0:6db20bbdc767 1325 } else {
mikekelly99 0:6db20bbdc767 1326 if (uc != 0xFFFF) return 0; /* Check filler */
mikekelly99 0:6db20bbdc767 1327 }
mikekelly99 0:6db20bbdc767 1328 }
mikekelly99 0:6db20bbdc767 1329
mikekelly99 0:6db20bbdc767 1330 if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
mikekelly99 0:6db20bbdc767 1331 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
mikekelly99 0:6db20bbdc767 1332 lfnbuf[i] = 0;
mikekelly99 0:6db20bbdc767 1333 }
mikekelly99 0:6db20bbdc767 1334
mikekelly99 0:6db20bbdc767 1335 return 1; /* The part of LFN is valid */
mikekelly99 0:6db20bbdc767 1336 }
mikekelly99 0:6db20bbdc767 1337
mikekelly99 0:6db20bbdc767 1338
mikekelly99 0:6db20bbdc767 1339 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 1340 static
mikekelly99 0:6db20bbdc767 1341 void fit_lfn (
mikekelly99 0:6db20bbdc767 1342 const WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
mikekelly99 0:6db20bbdc767 1343 BYTE* dir, /* Pointer to the LFN entry to be processed */
mikekelly99 0:6db20bbdc767 1344 BYTE ord, /* LFN order (1-20) */
mikekelly99 0:6db20bbdc767 1345 BYTE sum /* Checksum of the corresponding SFN */
mikekelly99 0:6db20bbdc767 1346 )
mikekelly99 0:6db20bbdc767 1347 {
mikekelly99 0:6db20bbdc767 1348 UINT i, s;
mikekelly99 0:6db20bbdc767 1349 WCHAR wc;
mikekelly99 0:6db20bbdc767 1350
mikekelly99 0:6db20bbdc767 1351
mikekelly99 0:6db20bbdc767 1352 dir[LDIR_Chksum] = sum; /* Set checksum */
mikekelly99 0:6db20bbdc767 1353 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
mikekelly99 0:6db20bbdc767 1354 dir[LDIR_Type] = 0;
mikekelly99 0:6db20bbdc767 1355 ST_WORD(dir + LDIR_FstClusLO, 0);
mikekelly99 0:6db20bbdc767 1356
mikekelly99 0:6db20bbdc767 1357 i = (ord - 1) * 13; /* Get offset in the LFN working buffer */
mikekelly99 0:6db20bbdc767 1358 s = wc = 0;
mikekelly99 0:6db20bbdc767 1359 do {
mikekelly99 0:6db20bbdc767 1360 if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */
mikekelly99 0:6db20bbdc767 1361 ST_WORD(dir+LfnOfs[s], wc); /* Put it */
mikekelly99 0:6db20bbdc767 1362 if (!wc) wc = 0xFFFF; /* Padding characters following last character */
mikekelly99 0:6db20bbdc767 1363 } while (++s < 13);
mikekelly99 0:6db20bbdc767 1364 if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */
mikekelly99 0:6db20bbdc767 1365 dir[LDIR_Ord] = ord; /* Set the LFN order */
mikekelly99 0:6db20bbdc767 1366 }
mikekelly99 0:6db20bbdc767 1367
mikekelly99 0:6db20bbdc767 1368 #endif
mikekelly99 0:6db20bbdc767 1369 #endif
mikekelly99 0:6db20bbdc767 1370
mikekelly99 0:6db20bbdc767 1371
mikekelly99 0:6db20bbdc767 1372
mikekelly99 0:6db20bbdc767 1373
mikekelly99 0:6db20bbdc767 1374 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1375 /* Create numbered name */
mikekelly99 0:6db20bbdc767 1376 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1377 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1378 static
mikekelly99 0:6db20bbdc767 1379 void gen_numname (
mikekelly99 0:6db20bbdc767 1380 BYTE* dst, /* Pointer to the buffer to store numbered SFN */
mikekelly99 0:6db20bbdc767 1381 const BYTE* src, /* Pointer to SFN */
mikekelly99 0:6db20bbdc767 1382 const WCHAR* lfn, /* Pointer to LFN */
mikekelly99 0:6db20bbdc767 1383 UINT seq /* Sequence number */
mikekelly99 0:6db20bbdc767 1384 )
mikekelly99 0:6db20bbdc767 1385 {
mikekelly99 0:6db20bbdc767 1386 BYTE ns[8], c;
mikekelly99 0:6db20bbdc767 1387 UINT i, j;
mikekelly99 0:6db20bbdc767 1388 WCHAR wc;
mikekelly99 0:6db20bbdc767 1389 DWORD sr;
mikekelly99 0:6db20bbdc767 1390
mikekelly99 0:6db20bbdc767 1391
mikekelly99 0:6db20bbdc767 1392 mem_cpy(dst, src, 11);
mikekelly99 0:6db20bbdc767 1393
mikekelly99 0:6db20bbdc767 1394 if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
mikekelly99 0:6db20bbdc767 1395 sr = seq;
mikekelly99 0:6db20bbdc767 1396 while (*lfn) { /* Create a CRC */
mikekelly99 0:6db20bbdc767 1397 wc = *lfn++;
mikekelly99 0:6db20bbdc767 1398 for (i = 0; i < 16; i++) {
mikekelly99 0:6db20bbdc767 1399 sr = (sr << 1) + (wc & 1);
mikekelly99 0:6db20bbdc767 1400 wc >>= 1;
mikekelly99 0:6db20bbdc767 1401 if (sr & 0x10000) sr ^= 0x11021;
mikekelly99 0:6db20bbdc767 1402 }
mikekelly99 0:6db20bbdc767 1403 }
mikekelly99 0:6db20bbdc767 1404 seq = (UINT)sr;
mikekelly99 0:6db20bbdc767 1405 }
mikekelly99 0:6db20bbdc767 1406
mikekelly99 0:6db20bbdc767 1407 /* itoa (hexdecimal) */
mikekelly99 0:6db20bbdc767 1408 i = 7;
mikekelly99 0:6db20bbdc767 1409 do {
mikekelly99 0:6db20bbdc767 1410 c = (seq % 16) + '0';
mikekelly99 0:6db20bbdc767 1411 if (c > '9') c += 7;
mikekelly99 0:6db20bbdc767 1412 ns[i--] = c;
mikekelly99 0:6db20bbdc767 1413 seq /= 16;
mikekelly99 0:6db20bbdc767 1414 } while (seq);
mikekelly99 0:6db20bbdc767 1415 ns[i] = '~';
mikekelly99 0:6db20bbdc767 1416
mikekelly99 0:6db20bbdc767 1417 /* Append the number */
mikekelly99 0:6db20bbdc767 1418 for (j = 0; j < i && dst[j] != ' '; j++) {
mikekelly99 0:6db20bbdc767 1419 if (IsDBCS1(dst[j])) {
mikekelly99 0:6db20bbdc767 1420 if (j == i - 1) break;
mikekelly99 0:6db20bbdc767 1421 j++;
mikekelly99 0:6db20bbdc767 1422 }
mikekelly99 0:6db20bbdc767 1423 }
mikekelly99 0:6db20bbdc767 1424 do {
mikekelly99 0:6db20bbdc767 1425 dst[j++] = (i < 8) ? ns[i++] : ' ';
mikekelly99 0:6db20bbdc767 1426 } while (j < 8);
mikekelly99 0:6db20bbdc767 1427 }
mikekelly99 0:6db20bbdc767 1428 #endif
mikekelly99 0:6db20bbdc767 1429
mikekelly99 0:6db20bbdc767 1430
mikekelly99 0:6db20bbdc767 1431
mikekelly99 0:6db20bbdc767 1432
mikekelly99 0:6db20bbdc767 1433 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1434 /* Calculate checksum of an SFN entry */
mikekelly99 0:6db20bbdc767 1435 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1436 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1437 static
mikekelly99 0:6db20bbdc767 1438 BYTE sum_sfn (
mikekelly99 0:6db20bbdc767 1439 const BYTE* dir /* Pointer to the SFN entry */
mikekelly99 0:6db20bbdc767 1440 )
mikekelly99 0:6db20bbdc767 1441 {
mikekelly99 0:6db20bbdc767 1442 BYTE sum = 0;
mikekelly99 0:6db20bbdc767 1443 UINT n = 11;
mikekelly99 0:6db20bbdc767 1444
mikekelly99 0:6db20bbdc767 1445 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
mikekelly99 0:6db20bbdc767 1446 return sum;
mikekelly99 0:6db20bbdc767 1447 }
mikekelly99 0:6db20bbdc767 1448 #endif
mikekelly99 0:6db20bbdc767 1449
mikekelly99 0:6db20bbdc767 1450
mikekelly99 0:6db20bbdc767 1451
mikekelly99 0:6db20bbdc767 1452
mikekelly99 0:6db20bbdc767 1453 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1454 /* Directory handling - Find an object in the directory */
mikekelly99 0:6db20bbdc767 1455 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1456
mikekelly99 0:6db20bbdc767 1457 static
mikekelly99 0:6db20bbdc767 1458 FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
mikekelly99 0:6db20bbdc767 1459 FATFS_DIR* dp /* Pointer to the directory object linked to the file name */
mikekelly99 0:6db20bbdc767 1460 )
mikekelly99 0:6db20bbdc767 1461 {
mikekelly99 0:6db20bbdc767 1462 FRESULT res;
mikekelly99 0:6db20bbdc767 1463 BYTE c, *dir;
mikekelly99 0:6db20bbdc767 1464 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1465 BYTE a, ord, sum;
mikekelly99 0:6db20bbdc767 1466 #endif
mikekelly99 0:6db20bbdc767 1467
mikekelly99 0:6db20bbdc767 1468 res = dir_sdi(dp, 0); /* Rewind directory object */
mikekelly99 0:6db20bbdc767 1469 if (res != FR_OK) return res;
mikekelly99 0:6db20bbdc767 1470
mikekelly99 0:6db20bbdc767 1471 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1472 ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
mikekelly99 0:6db20bbdc767 1473 #endif
mikekelly99 0:6db20bbdc767 1474 do {
mikekelly99 0:6db20bbdc767 1475 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1476 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1477 dir = dp->dir; /* Ptr to the directory entry of current index */
mikekelly99 0:6db20bbdc767 1478 c = dir[DIR_Name];
mikekelly99 0:6db20bbdc767 1479 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
mikekelly99 0:6db20bbdc767 1480 #if _USE_LFN /* LFN configuration */
mikekelly99 0:6db20bbdc767 1481 a = dir[DIR_Attr] & AM_MASK;
mikekelly99 0:6db20bbdc767 1482 if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
mikekelly99 0:6db20bbdc767 1483 ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
mikekelly99 0:6db20bbdc767 1484 } else {
mikekelly99 0:6db20bbdc767 1485 if (a == AM_LFN) { /* An LFN entry is found */
mikekelly99 0:6db20bbdc767 1486 if (dp->lfn) {
mikekelly99 0:6db20bbdc767 1487 if (c & LLEF) { /* Is it start of LFN sequence? */
mikekelly99 0:6db20bbdc767 1488 sum = dir[LDIR_Chksum];
mikekelly99 0:6db20bbdc767 1489 c &= ~LLEF; ord = c; /* LFN start order */
mikekelly99 0:6db20bbdc767 1490 dp->lfn_idx = dp->index; /* Start index of LFN */
mikekelly99 0:6db20bbdc767 1491 }
mikekelly99 0:6db20bbdc767 1492 /* Check validity of the LFN entry and compare it with given name */
mikekelly99 0:6db20bbdc767 1493 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF;
mikekelly99 0:6db20bbdc767 1494 }
mikekelly99 0:6db20bbdc767 1495 } else { /* An SFN entry is found */
mikekelly99 0:6db20bbdc767 1496 if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
mikekelly99 0:6db20bbdc767 1497 if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */
mikekelly99 0:6db20bbdc767 1498 ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
mikekelly99 0:6db20bbdc767 1499 }
mikekelly99 0:6db20bbdc767 1500 }
mikekelly99 0:6db20bbdc767 1501 #else /* Non LFN configuration */
mikekelly99 0:6db20bbdc767 1502 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */
mikekelly99 0:6db20bbdc767 1503 break;
mikekelly99 0:6db20bbdc767 1504 #endif
mikekelly99 0:6db20bbdc767 1505 res = dir_next(dp, 0); /* Next entry */
mikekelly99 0:6db20bbdc767 1506 } while (res == FR_OK);
mikekelly99 0:6db20bbdc767 1507
mikekelly99 0:6db20bbdc767 1508 return res;
mikekelly99 0:6db20bbdc767 1509 }
mikekelly99 0:6db20bbdc767 1510
mikekelly99 0:6db20bbdc767 1511
mikekelly99 0:6db20bbdc767 1512
mikekelly99 0:6db20bbdc767 1513
mikekelly99 0:6db20bbdc767 1514 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1515 /* Read an object from the directory */
mikekelly99 0:6db20bbdc767 1516 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1517 #if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2
mikekelly99 0:6db20bbdc767 1518 static
mikekelly99 0:6db20bbdc767 1519 FRESULT dir_read (
mikekelly99 0:6db20bbdc767 1520 FATFS_DIR* dp, /* Pointer to the directory object */
mikekelly99 0:6db20bbdc767 1521 int vol /* Filtered by 0:file/directory or 1:volume label */
mikekelly99 0:6db20bbdc767 1522 )
mikekelly99 0:6db20bbdc767 1523 {
mikekelly99 0:6db20bbdc767 1524 FRESULT res;
mikekelly99 0:6db20bbdc767 1525 BYTE a, c, *dir;
mikekelly99 0:6db20bbdc767 1526 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1527 BYTE ord = 0xFF, sum = 0xFF;
mikekelly99 0:6db20bbdc767 1528 #endif
mikekelly99 0:6db20bbdc767 1529
mikekelly99 0:6db20bbdc767 1530 res = FR_NO_FILE;
mikekelly99 0:6db20bbdc767 1531 while (dp->sect) {
mikekelly99 0:6db20bbdc767 1532 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1533 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1534 dir = dp->dir; /* Ptr to the directory entry of current index */
mikekelly99 0:6db20bbdc767 1535 c = dir[DIR_Name];
mikekelly99 0:6db20bbdc767 1536 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
mikekelly99 0:6db20bbdc767 1537 a = dir[DIR_Attr] & AM_MASK;
mikekelly99 0:6db20bbdc767 1538 #if _USE_LFN /* LFN configuration */
mikekelly99 0:6db20bbdc767 1539 if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
mikekelly99 0:6db20bbdc767 1540 ord = 0xFF;
mikekelly99 0:6db20bbdc767 1541 } else {
mikekelly99 0:6db20bbdc767 1542 if (a == AM_LFN) { /* An LFN entry is found */
mikekelly99 0:6db20bbdc767 1543 if (c & LLEF) { /* Is it start of LFN sequence? */
mikekelly99 0:6db20bbdc767 1544 sum = dir[LDIR_Chksum];
mikekelly99 0:6db20bbdc767 1545 c &= ~LLEF; ord = c;
mikekelly99 0:6db20bbdc767 1546 dp->lfn_idx = dp->index;
mikekelly99 0:6db20bbdc767 1547 }
mikekelly99 0:6db20bbdc767 1548 /* Check LFN validity and capture it */
mikekelly99 0:6db20bbdc767 1549 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF;
mikekelly99 0:6db20bbdc767 1550 } else { /* An SFN entry is found */
mikekelly99 0:6db20bbdc767 1551 if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
mikekelly99 0:6db20bbdc767 1552 dp->lfn_idx = 0xFFFF; /* It has no LFN. */
mikekelly99 0:6db20bbdc767 1553 break;
mikekelly99 0:6db20bbdc767 1554 }
mikekelly99 0:6db20bbdc767 1555 }
mikekelly99 0:6db20bbdc767 1556 #else /* Non LFN configuration */
mikekelly99 0:6db20bbdc767 1557 if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */
mikekelly99 0:6db20bbdc767 1558 break;
mikekelly99 0:6db20bbdc767 1559 #endif
mikekelly99 0:6db20bbdc767 1560 res = dir_next(dp, 0); /* Next entry */
mikekelly99 0:6db20bbdc767 1561 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1562 }
mikekelly99 0:6db20bbdc767 1563
mikekelly99 0:6db20bbdc767 1564 if (res != FR_OK) dp->sect = 0;
mikekelly99 0:6db20bbdc767 1565
mikekelly99 0:6db20bbdc767 1566 return res;
mikekelly99 0:6db20bbdc767 1567 }
mikekelly99 0:6db20bbdc767 1568 #endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */
mikekelly99 0:6db20bbdc767 1569
mikekelly99 0:6db20bbdc767 1570
mikekelly99 0:6db20bbdc767 1571
mikekelly99 0:6db20bbdc767 1572
mikekelly99 0:6db20bbdc767 1573 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1574 /* Register an object to the directory */
mikekelly99 0:6db20bbdc767 1575 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1576 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 1577 static
mikekelly99 0:6db20bbdc767 1578 FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */
mikekelly99 0:6db20bbdc767 1579 FATFS_DIR* dp /* Target directory with object name to be created */
mikekelly99 0:6db20bbdc767 1580 )
mikekelly99 0:6db20bbdc767 1581 {
mikekelly99 0:6db20bbdc767 1582 FRESULT res;
mikekelly99 0:6db20bbdc767 1583 #if _USE_LFN /* LFN configuration */
mikekelly99 0:6db20bbdc767 1584 UINT n, nent;
mikekelly99 0:6db20bbdc767 1585 BYTE sn[12], *fn, sum;
mikekelly99 0:6db20bbdc767 1586 WCHAR *lfn;
mikekelly99 0:6db20bbdc767 1587
mikekelly99 0:6db20bbdc767 1588
mikekelly99 0:6db20bbdc767 1589 fn = dp->fn; lfn = dp->lfn;
mikekelly99 0:6db20bbdc767 1590 mem_cpy(sn, fn, 12);
mikekelly99 0:6db20bbdc767 1591
mikekelly99 0:6db20bbdc767 1592 if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */
mikekelly99 0:6db20bbdc767 1593 return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 1594
mikekelly99 0:6db20bbdc767 1595 if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
mikekelly99 0:6db20bbdc767 1596 fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */
mikekelly99 0:6db20bbdc767 1597 for (n = 1; n < 100; n++) {
mikekelly99 0:6db20bbdc767 1598 gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
mikekelly99 0:6db20bbdc767 1599 res = dir_find(dp); /* Check if the name collides with existing SFN */
mikekelly99 0:6db20bbdc767 1600 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1601 }
mikekelly99 0:6db20bbdc767 1602 if (n == 100) return FR_DENIED; /* Abort if too many collisions */
mikekelly99 0:6db20bbdc767 1603 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
mikekelly99 0:6db20bbdc767 1604 fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn;
mikekelly99 0:6db20bbdc767 1605 }
mikekelly99 0:6db20bbdc767 1606
mikekelly99 0:6db20bbdc767 1607 if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */
mikekelly99 0:6db20bbdc767 1608 for (n = 0; lfn[n]; n++) ;
mikekelly99 0:6db20bbdc767 1609 nent = (n + 25) / 13;
mikekelly99 0:6db20bbdc767 1610 } else { /* Otherwise allocate an entry for an SFN */
mikekelly99 0:6db20bbdc767 1611 nent = 1;
mikekelly99 0:6db20bbdc767 1612 }
mikekelly99 0:6db20bbdc767 1613 res = dir_alloc(dp, nent); /* Allocate entries */
mikekelly99 0:6db20bbdc767 1614
mikekelly99 0:6db20bbdc767 1615 if (res == FR_OK && --nent) { /* Set LFN entry if needed */
mikekelly99 0:6db20bbdc767 1616 res = dir_sdi(dp, dp->index - nent);
mikekelly99 0:6db20bbdc767 1617 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1618 sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */
mikekelly99 0:6db20bbdc767 1619 do { /* Store LFN entries in bottom first */
mikekelly99 0:6db20bbdc767 1620 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1621 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1622 fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum);
mikekelly99 0:6db20bbdc767 1623 dp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 1624 res = dir_next(dp, 0); /* Next entry */
mikekelly99 0:6db20bbdc767 1625 } while (res == FR_OK && --nent);
mikekelly99 0:6db20bbdc767 1626 }
mikekelly99 0:6db20bbdc767 1627 }
mikekelly99 0:6db20bbdc767 1628 #else /* Non LFN configuration */
mikekelly99 0:6db20bbdc767 1629 res = dir_alloc(dp, 1); /* Allocate an entry for SFN */
mikekelly99 0:6db20bbdc767 1630 #endif
mikekelly99 0:6db20bbdc767 1631
mikekelly99 0:6db20bbdc767 1632 if (res == FR_OK) { /* Set SFN entry */
mikekelly99 0:6db20bbdc767 1633 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1634 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1635 mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */
mikekelly99 0:6db20bbdc767 1636 mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */
mikekelly99 0:6db20bbdc767 1637 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1638 dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */
mikekelly99 0:6db20bbdc767 1639 #endif
mikekelly99 0:6db20bbdc767 1640 dp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 1641 }
mikekelly99 0:6db20bbdc767 1642 }
mikekelly99 0:6db20bbdc767 1643
mikekelly99 0:6db20bbdc767 1644 return res;
mikekelly99 0:6db20bbdc767 1645 }
mikekelly99 0:6db20bbdc767 1646 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 1647
mikekelly99 0:6db20bbdc767 1648
mikekelly99 0:6db20bbdc767 1649
mikekelly99 0:6db20bbdc767 1650
mikekelly99 0:6db20bbdc767 1651 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1652 /* Remove an object from the directory */
mikekelly99 0:6db20bbdc767 1653 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1654 #if !_FS_READONLY && !_FS_MINIMIZE
mikekelly99 0:6db20bbdc767 1655 static
mikekelly99 0:6db20bbdc767 1656 FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
mikekelly99 0:6db20bbdc767 1657 FATFS_DIR* dp /* Directory object pointing the entry to be removed */
mikekelly99 0:6db20bbdc767 1658 )
mikekelly99 0:6db20bbdc767 1659 {
mikekelly99 0:6db20bbdc767 1660 FRESULT res;
mikekelly99 0:6db20bbdc767 1661 #if _USE_LFN /* LFN configuration */
mikekelly99 0:6db20bbdc767 1662 UINT i;
mikekelly99 0:6db20bbdc767 1663
mikekelly99 0:6db20bbdc767 1664 i = dp->index; /* SFN index */
mikekelly99 0:6db20bbdc767 1665 res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */
mikekelly99 0:6db20bbdc767 1666 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1667 do {
mikekelly99 0:6db20bbdc767 1668 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1669 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 1670 mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */
mikekelly99 0:6db20bbdc767 1671 *dp->dir = DDEM;
mikekelly99 0:6db20bbdc767 1672 dp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 1673 if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
mikekelly99 0:6db20bbdc767 1674 res = dir_next(dp, 0); /* Next entry */
mikekelly99 0:6db20bbdc767 1675 } while (res == FR_OK);
mikekelly99 0:6db20bbdc767 1676 if (res == FR_NO_FILE) res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 1677 }
mikekelly99 0:6db20bbdc767 1678
mikekelly99 0:6db20bbdc767 1679 #else /* Non LFN configuration */
mikekelly99 0:6db20bbdc767 1680 res = dir_sdi(dp, dp->index);
mikekelly99 0:6db20bbdc767 1681 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1682 res = move_window(dp->fs, dp->sect);
mikekelly99 0:6db20bbdc767 1683 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 1684 mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */
mikekelly99 0:6db20bbdc767 1685 *dp->dir = DDEM;
mikekelly99 0:6db20bbdc767 1686 dp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 1687 }
mikekelly99 0:6db20bbdc767 1688 }
mikekelly99 0:6db20bbdc767 1689 #endif
mikekelly99 0:6db20bbdc767 1690
mikekelly99 0:6db20bbdc767 1691 return res;
mikekelly99 0:6db20bbdc767 1692 }
mikekelly99 0:6db20bbdc767 1693 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 1694
mikekelly99 0:6db20bbdc767 1695
mikekelly99 0:6db20bbdc767 1696
mikekelly99 0:6db20bbdc767 1697
mikekelly99 0:6db20bbdc767 1698 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1699 /* Get file information from directory entry */
mikekelly99 0:6db20bbdc767 1700 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1701 #if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2
mikekelly99 0:6db20bbdc767 1702 static
mikekelly99 0:6db20bbdc767 1703 void get_fileinfo ( /* No return code */
mikekelly99 0:6db20bbdc767 1704 FATFS_DIR* dp, /* Pointer to the directory object */
mikekelly99 0:6db20bbdc767 1705 FILINFO* fno /* Pointer to the file information to be filled */
mikekelly99 0:6db20bbdc767 1706 )
mikekelly99 0:6db20bbdc767 1707 {
mikekelly99 0:6db20bbdc767 1708 UINT i;
mikekelly99 0:6db20bbdc767 1709 TCHAR *p, c;
mikekelly99 0:6db20bbdc767 1710 BYTE *dir;
mikekelly99 0:6db20bbdc767 1711 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1712 WCHAR w, *lfn;
mikekelly99 0:6db20bbdc767 1713 #endif
mikekelly99 0:6db20bbdc767 1714
mikekelly99 0:6db20bbdc767 1715 p = fno->fname;
mikekelly99 0:6db20bbdc767 1716 if (dp->sect) { /* Get SFN */
mikekelly99 0:6db20bbdc767 1717 dir = dp->dir;
mikekelly99 0:6db20bbdc767 1718 i = 0;
mikekelly99 0:6db20bbdc767 1719 while (i < 11) { /* Copy name body and extension */
mikekelly99 0:6db20bbdc767 1720 c = (TCHAR)dir[i++];
mikekelly99 0:6db20bbdc767 1721 if (c == ' ') continue; /* Skip padding spaces */
mikekelly99 0:6db20bbdc767 1722 if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */
mikekelly99 0:6db20bbdc767 1723 if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */
mikekelly99 0:6db20bbdc767 1724 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1725 if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY)))
mikekelly99 0:6db20bbdc767 1726 c += 0x20; /* To lower */
mikekelly99 0:6db20bbdc767 1727 #if _LFN_UNICODE
mikekelly99 0:6db20bbdc767 1728 if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i]))
mikekelly99 0:6db20bbdc767 1729 c = c << 8 | dir[i++];
mikekelly99 0:6db20bbdc767 1730 c = ff_convert(c, 1); /* OEM -> Unicode */
mikekelly99 0:6db20bbdc767 1731 if (!c) c = '?';
mikekelly99 0:6db20bbdc767 1732 #endif
mikekelly99 0:6db20bbdc767 1733 #endif
mikekelly99 0:6db20bbdc767 1734 *p++ = c;
mikekelly99 0:6db20bbdc767 1735 }
mikekelly99 0:6db20bbdc767 1736 fno->fattrib = dir[DIR_Attr]; /* Attribute */
mikekelly99 0:6db20bbdc767 1737 fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */
mikekelly99 0:6db20bbdc767 1738 fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */
mikekelly99 0:6db20bbdc767 1739 fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */
mikekelly99 0:6db20bbdc767 1740 }
mikekelly99 0:6db20bbdc767 1741 *p = 0; /* Terminate SFN string by a \0 */
mikekelly99 0:6db20bbdc767 1742
mikekelly99 0:6db20bbdc767 1743 #if _USE_LFN
mikekelly99 0:6db20bbdc767 1744 if (fno->lfname) {
mikekelly99 0:6db20bbdc767 1745 i = 0; p = fno->lfname;
mikekelly99 0:6db20bbdc767 1746 if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */
mikekelly99 0:6db20bbdc767 1747 lfn = dp->lfn;
mikekelly99 0:6db20bbdc767 1748 while ((w = *lfn++) != 0) { /* Get an LFN character */
mikekelly99 0:6db20bbdc767 1749 #if !_LFN_UNICODE
mikekelly99 0:6db20bbdc767 1750 w = ff_convert(w, 0); /* Unicode -> OEM */
mikekelly99 0:6db20bbdc767 1751 if (!w) { i = 0; break; } /* No LFN if it could not be converted */
mikekelly99 0:6db20bbdc767 1752 if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
mikekelly99 0:6db20bbdc767 1753 p[i++] = (TCHAR)(w >> 8);
mikekelly99 0:6db20bbdc767 1754 #endif
mikekelly99 0:6db20bbdc767 1755 if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */
mikekelly99 0:6db20bbdc767 1756 p[i++] = (TCHAR)w;
mikekelly99 0:6db20bbdc767 1757 }
mikekelly99 0:6db20bbdc767 1758 }
mikekelly99 0:6db20bbdc767 1759 p[i] = 0; /* Terminate LFN string by a \0 */
mikekelly99 0:6db20bbdc767 1760 }
mikekelly99 0:6db20bbdc767 1761 #endif
mikekelly99 0:6db20bbdc767 1762 }
mikekelly99 0:6db20bbdc767 1763 #endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */
mikekelly99 0:6db20bbdc767 1764
mikekelly99 0:6db20bbdc767 1765
mikekelly99 0:6db20bbdc767 1766
mikekelly99 0:6db20bbdc767 1767
mikekelly99 0:6db20bbdc767 1768 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1769 /* Pattern matching */
mikekelly99 0:6db20bbdc767 1770 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1771 #if _USE_FIND && _FS_MINIMIZE <= 1
mikekelly99 0:6db20bbdc767 1772 static
mikekelly99 0:6db20bbdc767 1773 WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */
mikekelly99 0:6db20bbdc767 1774 const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */
mikekelly99 0:6db20bbdc767 1775 )
mikekelly99 0:6db20bbdc767 1776 {
mikekelly99 0:6db20bbdc767 1777 WCHAR chr;
mikekelly99 0:6db20bbdc767 1778
mikekelly99 0:6db20bbdc767 1779 #if !_LFN_UNICODE
mikekelly99 0:6db20bbdc767 1780 chr = (BYTE)*(*ptr)++; /* Get a byte */
mikekelly99 0:6db20bbdc767 1781 if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */
mikekelly99 0:6db20bbdc767 1782 if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */
mikekelly99 0:6db20bbdc767 1783 chr = chr << 8 | (BYTE)*(*ptr)++;
mikekelly99 0:6db20bbdc767 1784 #ifdef _EXCVT
mikekelly99 0:6db20bbdc767 1785 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */
mikekelly99 0:6db20bbdc767 1786 #endif
mikekelly99 0:6db20bbdc767 1787 #else
mikekelly99 0:6db20bbdc767 1788 chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */
mikekelly99 0:6db20bbdc767 1789 #endif
mikekelly99 0:6db20bbdc767 1790 return chr;
mikekelly99 0:6db20bbdc767 1791 }
mikekelly99 0:6db20bbdc767 1792
mikekelly99 0:6db20bbdc767 1793
mikekelly99 0:6db20bbdc767 1794 static
mikekelly99 0:6db20bbdc767 1795 int pattern_matching ( /* 0:mismatched, 1:matched */
mikekelly99 0:6db20bbdc767 1796 const TCHAR* pat, /* Matching pattern */
mikekelly99 0:6db20bbdc767 1797 const TCHAR* nam, /* String to be tested */
mikekelly99 0:6db20bbdc767 1798 int skip, /* Number of pre-skip chars (number of ?s) */
mikekelly99 0:6db20bbdc767 1799 int inf /* Infinite search (* specified) */
mikekelly99 0:6db20bbdc767 1800 )
mikekelly99 0:6db20bbdc767 1801 {
mikekelly99 0:6db20bbdc767 1802 const TCHAR *pp, *np;
mikekelly99 0:6db20bbdc767 1803 WCHAR pc, nc;
mikekelly99 0:6db20bbdc767 1804 int nm, nx;
mikekelly99 0:6db20bbdc767 1805
mikekelly99 0:6db20bbdc767 1806
mikekelly99 0:6db20bbdc767 1807 while (skip--) { /* Pre-skip name chars */
mikekelly99 0:6db20bbdc767 1808 if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */
mikekelly99 0:6db20bbdc767 1809 }
mikekelly99 0:6db20bbdc767 1810 if (!*pat && inf) return 1; /* (short circuit) */
mikekelly99 0:6db20bbdc767 1811
mikekelly99 0:6db20bbdc767 1812 do {
mikekelly99 0:6db20bbdc767 1813 pp = pat; np = nam; /* Top of pattern and name to match */
mikekelly99 0:6db20bbdc767 1814 for (;;) {
mikekelly99 0:6db20bbdc767 1815 if (*pp == '?' || *pp == '*') { /* Wildcard? */
mikekelly99 0:6db20bbdc767 1816 nm = nx = 0;
mikekelly99 0:6db20bbdc767 1817 do { /* Analyze the wildcard chars */
mikekelly99 0:6db20bbdc767 1818 if (*pp++ == '?') nm++; else nx = 1;
mikekelly99 0:6db20bbdc767 1819 } while (*pp == '?' || *pp == '*');
mikekelly99 0:6db20bbdc767 1820 if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */
mikekelly99 0:6db20bbdc767 1821 nc = *np; break; /* Branch mismatched */
mikekelly99 0:6db20bbdc767 1822 }
mikekelly99 0:6db20bbdc767 1823 pc = get_achar(&pp); /* Get a pattern char */
mikekelly99 0:6db20bbdc767 1824 nc = get_achar(&np); /* Get a name char */
mikekelly99 0:6db20bbdc767 1825 if (pc != nc) break; /* Branch mismatched? */
mikekelly99 0:6db20bbdc767 1826 if (!pc) return 1; /* Branch matched? (matched at end of both strings) */
mikekelly99 0:6db20bbdc767 1827 }
mikekelly99 0:6db20bbdc767 1828 get_achar(&nam); /* nam++ */
mikekelly99 0:6db20bbdc767 1829 } while (inf && nc); /* Retry until end of name if infinite search is specified */
mikekelly99 0:6db20bbdc767 1830
mikekelly99 0:6db20bbdc767 1831 return 0;
mikekelly99 0:6db20bbdc767 1832 }
mikekelly99 0:6db20bbdc767 1833 #endif /* _USE_FIND && _FS_MINIMIZE <= 1 */
mikekelly99 0:6db20bbdc767 1834
mikekelly99 0:6db20bbdc767 1835
mikekelly99 0:6db20bbdc767 1836
mikekelly99 0:6db20bbdc767 1837
mikekelly99 0:6db20bbdc767 1838 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1839 /* Pick a top segment and create the object name in directory form */
mikekelly99 0:6db20bbdc767 1840 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 1841
mikekelly99 0:6db20bbdc767 1842 static
mikekelly99 0:6db20bbdc767 1843 FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
mikekelly99 0:6db20bbdc767 1844 FATFS_DIR* dp, /* Pointer to the directory object */
mikekelly99 0:6db20bbdc767 1845 const TCHAR** path /* Pointer to pointer to the segment in the path string */
mikekelly99 0:6db20bbdc767 1846 )
mikekelly99 0:6db20bbdc767 1847 {
mikekelly99 0:6db20bbdc767 1848 #if _USE_LFN /* LFN configuration */
mikekelly99 0:6db20bbdc767 1849 BYTE b, cf;
mikekelly99 0:6db20bbdc767 1850 WCHAR w, *lfn;
mikekelly99 0:6db20bbdc767 1851 UINT i, ni, si, di;
mikekelly99 0:6db20bbdc767 1852 const TCHAR *p;
mikekelly99 0:6db20bbdc767 1853
mikekelly99 0:6db20bbdc767 1854 /* Create LFN in Unicode */
mikekelly99 0:6db20bbdc767 1855 for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
mikekelly99 0:6db20bbdc767 1856 lfn = dp->lfn;
mikekelly99 0:6db20bbdc767 1857 si = di = 0;
mikekelly99 0:6db20bbdc767 1858 for (;;) {
mikekelly99 0:6db20bbdc767 1859 w = p[si++]; /* Get a character */
mikekelly99 0:6db20bbdc767 1860 if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
mikekelly99 0:6db20bbdc767 1861 if (di >= _MAX_LFN) /* Reject too long name */
mikekelly99 0:6db20bbdc767 1862 return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 1863 #if !_LFN_UNICODE
mikekelly99 0:6db20bbdc767 1864 w &= 0xFF;
mikekelly99 0:6db20bbdc767 1865 if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
mikekelly99 0:6db20bbdc767 1866 b = (BYTE)p[si++]; /* Get 2nd byte */
mikekelly99 0:6db20bbdc767 1867 w = (w << 8) + b; /* Create a DBC */
mikekelly99 0:6db20bbdc767 1868 if (!IsDBCS2(b))
mikekelly99 0:6db20bbdc767 1869 return FR_INVALID_NAME; /* Reject invalid sequence */
mikekelly99 0:6db20bbdc767 1870 }
mikekelly99 0:6db20bbdc767 1871 w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
mikekelly99 0:6db20bbdc767 1872 if (!w) return FR_INVALID_NAME; /* Reject invalid code */
mikekelly99 0:6db20bbdc767 1873 #endif
mikekelly99 0:6db20bbdc767 1874 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */
mikekelly99 0:6db20bbdc767 1875 return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 1876 lfn[di++] = w; /* Store the Unicode character */
mikekelly99 0:6db20bbdc767 1877 }
mikekelly99 0:6db20bbdc767 1878 *path = &p[si]; /* Return pointer to the next segment */
mikekelly99 0:6db20bbdc767 1879 cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
mikekelly99 0:6db20bbdc767 1880 #if _FS_RPATH
mikekelly99 0:6db20bbdc767 1881 if ((di == 1 && lfn[di - 1] == '.') ||
mikekelly99 0:6db20bbdc767 1882 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot entry? */
mikekelly99 0:6db20bbdc767 1883 lfn[di] = 0;
mikekelly99 0:6db20bbdc767 1884 for (i = 0; i < 11; i++) /* Create dot name for SFN entry */
mikekelly99 0:6db20bbdc767 1885 dp->fn[i] = (i < di) ? '.' : ' ';
mikekelly99 0:6db20bbdc767 1886 dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
mikekelly99 0:6db20bbdc767 1887 return FR_OK;
mikekelly99 0:6db20bbdc767 1888 }
mikekelly99 0:6db20bbdc767 1889 #endif
mikekelly99 0:6db20bbdc767 1890 while (di) { /* Snip off trailing spaces and dots if exist */
mikekelly99 0:6db20bbdc767 1891 w = lfn[di - 1];
mikekelly99 0:6db20bbdc767 1892 if (w != ' ' && w != '.') break;
mikekelly99 0:6db20bbdc767 1893 di--;
mikekelly99 0:6db20bbdc767 1894 }
mikekelly99 0:6db20bbdc767 1895 if (!di) return FR_INVALID_NAME; /* Reject nul string */
mikekelly99 0:6db20bbdc767 1896 lfn[di] = 0; /* LFN is created */
mikekelly99 0:6db20bbdc767 1897
mikekelly99 0:6db20bbdc767 1898 /* Create SFN in directory form */
mikekelly99 0:6db20bbdc767 1899 mem_set(dp->fn, ' ', 11);
mikekelly99 0:6db20bbdc767 1900 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
mikekelly99 0:6db20bbdc767 1901 if (si) cf |= NS_LOSS | NS_LFN;
mikekelly99 0:6db20bbdc767 1902 while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
mikekelly99 0:6db20bbdc767 1903
mikekelly99 0:6db20bbdc767 1904 b = i = 0; ni = 8;
mikekelly99 0:6db20bbdc767 1905 for (;;) {
mikekelly99 0:6db20bbdc767 1906 w = lfn[si++]; /* Get an LFN character */
mikekelly99 0:6db20bbdc767 1907 if (!w) break; /* Break on end of the LFN */
mikekelly99 0:6db20bbdc767 1908 if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
mikekelly99 0:6db20bbdc767 1909 cf |= NS_LOSS | NS_LFN; continue;
mikekelly99 0:6db20bbdc767 1910 }
mikekelly99 0:6db20bbdc767 1911
mikekelly99 0:6db20bbdc767 1912 if (i >= ni || si == di) { /* Extension or end of SFN */
mikekelly99 0:6db20bbdc767 1913 if (ni == 11) { /* Long extension */
mikekelly99 0:6db20bbdc767 1914 cf |= NS_LOSS | NS_LFN; break;
mikekelly99 0:6db20bbdc767 1915 }
mikekelly99 0:6db20bbdc767 1916 if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
mikekelly99 0:6db20bbdc767 1917 if (si > di) break; /* No extension */
mikekelly99 0:6db20bbdc767 1918 si = di; i = 8; ni = 11; /* Enter extension section */
mikekelly99 0:6db20bbdc767 1919 b <<= 2; continue;
mikekelly99 0:6db20bbdc767 1920 }
mikekelly99 0:6db20bbdc767 1921
mikekelly99 0:6db20bbdc767 1922 if (w >= 0x80) { /* Non ASCII character */
mikekelly99 0:6db20bbdc767 1923 #ifdef _EXCVT
mikekelly99 0:6db20bbdc767 1924 w = ff_convert(w, 0); /* Unicode -> OEM code */
mikekelly99 0:6db20bbdc767 1925 if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */
mikekelly99 0:6db20bbdc767 1926 #else
mikekelly99 0:6db20bbdc767 1927 w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
mikekelly99 0:6db20bbdc767 1928 #endif
mikekelly99 0:6db20bbdc767 1929 cf |= NS_LFN; /* Force create LFN entry */
mikekelly99 0:6db20bbdc767 1930 }
mikekelly99 0:6db20bbdc767 1931
mikekelly99 0:6db20bbdc767 1932 if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */
mikekelly99 0:6db20bbdc767 1933 if (i >= ni - 1) {
mikekelly99 0:6db20bbdc767 1934 cf |= NS_LOSS | NS_LFN; i = ni; continue;
mikekelly99 0:6db20bbdc767 1935 }
mikekelly99 0:6db20bbdc767 1936 dp->fn[i++] = (BYTE)(w >> 8);
mikekelly99 0:6db20bbdc767 1937 } else { /* SBC */
mikekelly99 0:6db20bbdc767 1938 if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */
mikekelly99 0:6db20bbdc767 1939 w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
mikekelly99 0:6db20bbdc767 1940 } else {
mikekelly99 0:6db20bbdc767 1941 if (IsUpper(w)) { /* ASCII large capital */
mikekelly99 0:6db20bbdc767 1942 b |= 2;
mikekelly99 0:6db20bbdc767 1943 } else {
mikekelly99 0:6db20bbdc767 1944 if (IsLower(w)) { /* ASCII small capital */
mikekelly99 0:6db20bbdc767 1945 b |= 1; w -= 0x20;
mikekelly99 0:6db20bbdc767 1946 }
mikekelly99 0:6db20bbdc767 1947 }
mikekelly99 0:6db20bbdc767 1948 }
mikekelly99 0:6db20bbdc767 1949 }
mikekelly99 0:6db20bbdc767 1950 dp->fn[i++] = (BYTE)w;
mikekelly99 0:6db20bbdc767 1951 }
mikekelly99 0:6db20bbdc767 1952
mikekelly99 0:6db20bbdc767 1953 if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */
mikekelly99 0:6db20bbdc767 1954
mikekelly99 0:6db20bbdc767 1955 if (ni == 8) b <<= 2;
mikekelly99 0:6db20bbdc767 1956 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
mikekelly99 0:6db20bbdc767 1957 cf |= NS_LFN;
mikekelly99 0:6db20bbdc767 1958 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */
mikekelly99 0:6db20bbdc767 1959 if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
mikekelly99 0:6db20bbdc767 1960 if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
mikekelly99 0:6db20bbdc767 1961 }
mikekelly99 0:6db20bbdc767 1962
mikekelly99 0:6db20bbdc767 1963 dp->fn[NSFLAG] = cf; /* SFN is created */
mikekelly99 0:6db20bbdc767 1964
mikekelly99 0:6db20bbdc767 1965 return FR_OK;
mikekelly99 0:6db20bbdc767 1966
mikekelly99 0:6db20bbdc767 1967
mikekelly99 0:6db20bbdc767 1968 #else /* Non-LFN configuration */
mikekelly99 0:6db20bbdc767 1969 BYTE b, c, d, *sfn;
mikekelly99 0:6db20bbdc767 1970 UINT ni, si, i;
mikekelly99 0:6db20bbdc767 1971 const char *p;
mikekelly99 0:6db20bbdc767 1972
mikekelly99 0:6db20bbdc767 1973 /* Create file name in directory form */
mikekelly99 0:6db20bbdc767 1974 for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Skip duplicated separator */
mikekelly99 0:6db20bbdc767 1975 sfn = dp->fn;
mikekelly99 0:6db20bbdc767 1976 mem_set(sfn, ' ', 11);
mikekelly99 0:6db20bbdc767 1977 si = i = b = 0; ni = 8;
mikekelly99 0:6db20bbdc767 1978 #if _FS_RPATH
mikekelly99 0:6db20bbdc767 1979 if (p[si] == '.') { /* Is this a dot entry? */
mikekelly99 0:6db20bbdc767 1980 for (;;) {
mikekelly99 0:6db20bbdc767 1981 c = (BYTE)p[si++];
mikekelly99 0:6db20bbdc767 1982 if (c != '.' || si >= 3) break;
mikekelly99 0:6db20bbdc767 1983 sfn[i++] = c;
mikekelly99 0:6db20bbdc767 1984 }
mikekelly99 0:6db20bbdc767 1985 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 1986 *path = &p[si]; /* Return pointer to the next segment */
mikekelly99 0:6db20bbdc767 1987 sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
mikekelly99 0:6db20bbdc767 1988 return FR_OK;
mikekelly99 0:6db20bbdc767 1989 }
mikekelly99 0:6db20bbdc767 1990 #endif
mikekelly99 0:6db20bbdc767 1991 for (;;) {
mikekelly99 0:6db20bbdc767 1992 c = (BYTE)p[si++];
mikekelly99 0:6db20bbdc767 1993 if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
mikekelly99 0:6db20bbdc767 1994 if (c == '.' || i >= ni) {
mikekelly99 0:6db20bbdc767 1995 if (ni != 8 || c != '.') return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 1996 i = 8; ni = 11;
mikekelly99 0:6db20bbdc767 1997 b <<= 2; continue;
mikekelly99 0:6db20bbdc767 1998 }
mikekelly99 0:6db20bbdc767 1999 if (c >= 0x80) { /* Extended character? */
mikekelly99 0:6db20bbdc767 2000 b |= 3; /* Eliminate NT flag */
mikekelly99 0:6db20bbdc767 2001 #ifdef _EXCVT
mikekelly99 0:6db20bbdc767 2002 c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */
mikekelly99 0:6db20bbdc767 2003 #else
mikekelly99 0:6db20bbdc767 2004 #if !_DF1S
mikekelly99 0:6db20bbdc767 2005 return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */
mikekelly99 0:6db20bbdc767 2006 #endif
mikekelly99 0:6db20bbdc767 2007 #endif
mikekelly99 0:6db20bbdc767 2008 }
mikekelly99 0:6db20bbdc767 2009 if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */
mikekelly99 0:6db20bbdc767 2010 d = (BYTE)p[si++]; /* Get 2nd byte */
mikekelly99 0:6db20bbdc767 2011 if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
mikekelly99 0:6db20bbdc767 2012 return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 2013 sfn[i++] = c;
mikekelly99 0:6db20bbdc767 2014 sfn[i++] = d;
mikekelly99 0:6db20bbdc767 2015 } else { /* SBC */
mikekelly99 0:6db20bbdc767 2016 if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
mikekelly99 0:6db20bbdc767 2017 return FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 2018 if (IsUpper(c)) { /* ASCII large capital? */
mikekelly99 0:6db20bbdc767 2019 b |= 2;
mikekelly99 0:6db20bbdc767 2020 } else {
mikekelly99 0:6db20bbdc767 2021 if (IsLower(c)) { /* ASCII small capital? */
mikekelly99 0:6db20bbdc767 2022 b |= 1; c -= 0x20;
mikekelly99 0:6db20bbdc767 2023 }
mikekelly99 0:6db20bbdc767 2024 }
mikekelly99 0:6db20bbdc767 2025 sfn[i++] = c;
mikekelly99 0:6db20bbdc767 2026 }
mikekelly99 0:6db20bbdc767 2027 }
mikekelly99 0:6db20bbdc767 2028 *path = &p[si]; /* Return pointer to the next segment */
mikekelly99 0:6db20bbdc767 2029 c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
mikekelly99 0:6db20bbdc767 2030
mikekelly99 0:6db20bbdc767 2031 if (!i) return FR_INVALID_NAME; /* Reject nul string */
mikekelly99 0:6db20bbdc767 2032 if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */
mikekelly99 0:6db20bbdc767 2033
mikekelly99 0:6db20bbdc767 2034 if (ni == 8) b <<= 2;
mikekelly99 0:6db20bbdc767 2035 if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
mikekelly99 0:6db20bbdc767 2036 if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
mikekelly99 0:6db20bbdc767 2037
mikekelly99 0:6db20bbdc767 2038 sfn[NSFLAG] = c; /* Store NT flag, File name is created */
mikekelly99 0:6db20bbdc767 2039
mikekelly99 0:6db20bbdc767 2040 return FR_OK;
mikekelly99 0:6db20bbdc767 2041 #endif
mikekelly99 0:6db20bbdc767 2042 }
mikekelly99 0:6db20bbdc767 2043
mikekelly99 0:6db20bbdc767 2044
mikekelly99 0:6db20bbdc767 2045
mikekelly99 0:6db20bbdc767 2046
mikekelly99 0:6db20bbdc767 2047 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2048 /* Follow a file path */
mikekelly99 0:6db20bbdc767 2049 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2050
mikekelly99 0:6db20bbdc767 2051 static
mikekelly99 0:6db20bbdc767 2052 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
mikekelly99 0:6db20bbdc767 2053 FATFS_DIR* dp, /* Directory object to return last directory and found object */
mikekelly99 0:6db20bbdc767 2054 const TCHAR* path /* Full-path string to find a file or directory */
mikekelly99 0:6db20bbdc767 2055 )
mikekelly99 0:6db20bbdc767 2056 {
mikekelly99 0:6db20bbdc767 2057 FRESULT res;
mikekelly99 0:6db20bbdc767 2058 BYTE *dir, ns;
mikekelly99 0:6db20bbdc767 2059
mikekelly99 0:6db20bbdc767 2060
mikekelly99 0:6db20bbdc767 2061 #if _FS_RPATH
mikekelly99 0:6db20bbdc767 2062 if (*path == '/' || *path == '\\') { /* There is a heading separator */
mikekelly99 0:6db20bbdc767 2063 path++; dp->sclust = 0; /* Strip it and start from the root directory */
mikekelly99 0:6db20bbdc767 2064 } else { /* No heading separator */
mikekelly99 0:6db20bbdc767 2065 dp->sclust = dp->fs->cdir; /* Start from the current directory */
mikekelly99 0:6db20bbdc767 2066 }
mikekelly99 0:6db20bbdc767 2067 #else
mikekelly99 0:6db20bbdc767 2068 if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
mikekelly99 0:6db20bbdc767 2069 path++;
mikekelly99 0:6db20bbdc767 2070 dp->sclust = 0; /* Always start from the root directory */
mikekelly99 0:6db20bbdc767 2071 #endif
mikekelly99 0:6db20bbdc767 2072
mikekelly99 0:6db20bbdc767 2073 if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */
mikekelly99 0:6db20bbdc767 2074 res = dir_sdi(dp, 0);
mikekelly99 0:6db20bbdc767 2075 dp->dir = 0;
mikekelly99 0:6db20bbdc767 2076 } else { /* Follow path */
mikekelly99 0:6db20bbdc767 2077 for (;;) {
mikekelly99 0:6db20bbdc767 2078 res = create_name(dp, &path); /* Get a segment name of the path */
mikekelly99 0:6db20bbdc767 2079 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 2080 res = dir_find(dp); /* Find an object with the sagment name */
mikekelly99 0:6db20bbdc767 2081 ns = dp->fn[NSFLAG];
mikekelly99 0:6db20bbdc767 2082 if (res != FR_OK) { /* Failed to find the object */
mikekelly99 0:6db20bbdc767 2083 if (res == FR_NO_FILE) { /* Object is not found */
mikekelly99 0:6db20bbdc767 2084 if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */
mikekelly99 0:6db20bbdc767 2085 dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */
mikekelly99 0:6db20bbdc767 2086 if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */
mikekelly99 0:6db20bbdc767 2087 res = FR_OK; /* Ended at the root directroy. Function completed. */
mikekelly99 0:6db20bbdc767 2088 } else { /* Could not find the object */
mikekelly99 0:6db20bbdc767 2089 if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */
mikekelly99 0:6db20bbdc767 2090 }
mikekelly99 0:6db20bbdc767 2091 }
mikekelly99 0:6db20bbdc767 2092 break;
mikekelly99 0:6db20bbdc767 2093 }
mikekelly99 0:6db20bbdc767 2094 if (ns & NS_LAST) break; /* Last segment matched. Function completed. */
mikekelly99 0:6db20bbdc767 2095 dir = dp->dir; /* Follow the sub-directory */
mikekelly99 0:6db20bbdc767 2096 if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */
mikekelly99 0:6db20bbdc767 2097 res = FR_NO_PATH; break;
mikekelly99 0:6db20bbdc767 2098 }
mikekelly99 0:6db20bbdc767 2099 dp->sclust = ld_clust(dp->fs, dir);
mikekelly99 0:6db20bbdc767 2100 }
mikekelly99 0:6db20bbdc767 2101 }
mikekelly99 0:6db20bbdc767 2102
mikekelly99 0:6db20bbdc767 2103 return res;
mikekelly99 0:6db20bbdc767 2104 }
mikekelly99 0:6db20bbdc767 2105
mikekelly99 0:6db20bbdc767 2106
mikekelly99 0:6db20bbdc767 2107
mikekelly99 0:6db20bbdc767 2108
mikekelly99 0:6db20bbdc767 2109 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2110 /* Get logical drive number from path name */
mikekelly99 0:6db20bbdc767 2111 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2112
mikekelly99 0:6db20bbdc767 2113 static
mikekelly99 0:6db20bbdc767 2114 int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */
mikekelly99 0:6db20bbdc767 2115 const TCHAR** path /* Pointer to pointer to the path name */
mikekelly99 0:6db20bbdc767 2116 )
mikekelly99 0:6db20bbdc767 2117 {
mikekelly99 0:6db20bbdc767 2118 const TCHAR *tp, *tt;
mikekelly99 0:6db20bbdc767 2119 UINT i;
mikekelly99 0:6db20bbdc767 2120 int vol = -1;
mikekelly99 0:6db20bbdc767 2121 #if _STR_VOLUME_ID /* Find string drive id */
mikekelly99 0:6db20bbdc767 2122 static const char* const str[] = {_VOLUME_STRS};
mikekelly99 0:6db20bbdc767 2123 const char *sp;
mikekelly99 0:6db20bbdc767 2124 char c;
mikekelly99 0:6db20bbdc767 2125 TCHAR tc;
mikekelly99 0:6db20bbdc767 2126 #endif
mikekelly99 0:6db20bbdc767 2127
mikekelly99 0:6db20bbdc767 2128
mikekelly99 0:6db20bbdc767 2129 if (*path) { /* If the pointer is not a null */
mikekelly99 0:6db20bbdc767 2130 for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */
mikekelly99 0:6db20bbdc767 2131 if (*tt == ':') { /* If a ':' is exist in the path name */
mikekelly99 0:6db20bbdc767 2132 tp = *path;
mikekelly99 0:6db20bbdc767 2133 i = *tp++ - '0';
mikekelly99 0:6db20bbdc767 2134 if (i < 10 && tp == tt) { /* Is there a numeric drive id? */
mikekelly99 0:6db20bbdc767 2135 if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */
mikekelly99 0:6db20bbdc767 2136 vol = (int)i;
mikekelly99 0:6db20bbdc767 2137 *path = ++tt;
mikekelly99 0:6db20bbdc767 2138 }
mikekelly99 0:6db20bbdc767 2139 }
mikekelly99 0:6db20bbdc767 2140 #if _STR_VOLUME_ID
mikekelly99 0:6db20bbdc767 2141 else { /* No numeric drive number, find string drive id */
mikekelly99 0:6db20bbdc767 2142 i = 0; tt++;
mikekelly99 0:6db20bbdc767 2143 do {
mikekelly99 0:6db20bbdc767 2144 sp = str[i]; tp = *path;
mikekelly99 0:6db20bbdc767 2145 do { /* Compare a string drive id with path name */
mikekelly99 0:6db20bbdc767 2146 c = *sp++; tc = *tp++;
mikekelly99 0:6db20bbdc767 2147 if (IsLower(tc)) tc -= 0x20;
mikekelly99 0:6db20bbdc767 2148 } while (c && (TCHAR)c == tc);
mikekelly99 0:6db20bbdc767 2149 } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */
mikekelly99 0:6db20bbdc767 2150 if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */
mikekelly99 0:6db20bbdc767 2151 vol = (int)i;
mikekelly99 0:6db20bbdc767 2152 *path = tt;
mikekelly99 0:6db20bbdc767 2153 }
mikekelly99 0:6db20bbdc767 2154 }
mikekelly99 0:6db20bbdc767 2155 #endif
mikekelly99 0:6db20bbdc767 2156 return vol;
mikekelly99 0:6db20bbdc767 2157 }
mikekelly99 0:6db20bbdc767 2158 #if _FS_RPATH && _VOLUMES >= 2
mikekelly99 0:6db20bbdc767 2159 vol = CurrVol; /* Current drive */
mikekelly99 0:6db20bbdc767 2160 #else
mikekelly99 0:6db20bbdc767 2161 vol = 0; /* Drive 0 */
mikekelly99 0:6db20bbdc767 2162 #endif
mikekelly99 0:6db20bbdc767 2163 }
mikekelly99 0:6db20bbdc767 2164 return vol;
mikekelly99 0:6db20bbdc767 2165 }
mikekelly99 0:6db20bbdc767 2166
mikekelly99 0:6db20bbdc767 2167
mikekelly99 0:6db20bbdc767 2168
mikekelly99 0:6db20bbdc767 2169
mikekelly99 0:6db20bbdc767 2170 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2171 /* Load a sector and check if it is an FAT boot sector */
mikekelly99 0:6db20bbdc767 2172 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2173
mikekelly99 0:6db20bbdc767 2174 static
mikekelly99 0:6db20bbdc767 2175 BYTE check_fs ( /* 0:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk error */
mikekelly99 0:6db20bbdc767 2176 FATFS* fs, /* File system object */
mikekelly99 0:6db20bbdc767 2177 DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
mikekelly99 0:6db20bbdc767 2178 )
mikekelly99 0:6db20bbdc767 2179 {
mikekelly99 0:6db20bbdc767 2180 fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */
mikekelly99 0:6db20bbdc767 2181 if (move_window(fs, sect) != FR_OK) /* Load boot record */
mikekelly99 0:6db20bbdc767 2182 return 3;
mikekelly99 0:6db20bbdc767 2183
mikekelly99 0:6db20bbdc767 2184 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
mikekelly99 0:6db20bbdc767 2185 return 2;
mikekelly99 0:6db20bbdc767 2186
mikekelly99 0:6db20bbdc767 2187 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
mikekelly99 0:6db20bbdc767 2188 return 0;
mikekelly99 0:6db20bbdc767 2189 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
mikekelly99 0:6db20bbdc767 2190 return 0;
mikekelly99 0:6db20bbdc767 2191
mikekelly99 0:6db20bbdc767 2192 return 1;
mikekelly99 0:6db20bbdc767 2193 }
mikekelly99 0:6db20bbdc767 2194
mikekelly99 0:6db20bbdc767 2195
mikekelly99 0:6db20bbdc767 2196
mikekelly99 0:6db20bbdc767 2197
mikekelly99 0:6db20bbdc767 2198 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2199 /* Find logical drive and check if the volume is mounted */
mikekelly99 0:6db20bbdc767 2200 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2201
mikekelly99 0:6db20bbdc767 2202 static
mikekelly99 0:6db20bbdc767 2203 FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
mikekelly99 0:6db20bbdc767 2204 FATFS** rfs, /* Pointer to pointer to the found file system object */
mikekelly99 0:6db20bbdc767 2205 const TCHAR** path, /* Pointer to pointer to the path name (drive number) */
mikekelly99 0:6db20bbdc767 2206 BYTE wmode /* !=0: Check write protection for write access */
mikekelly99 0:6db20bbdc767 2207 )
mikekelly99 0:6db20bbdc767 2208 {
mikekelly99 0:6db20bbdc767 2209 BYTE fmt, *pt;
mikekelly99 0:6db20bbdc767 2210 int vol;
mikekelly99 0:6db20bbdc767 2211 DSTATUS stat;
mikekelly99 0:6db20bbdc767 2212 DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];
mikekelly99 0:6db20bbdc767 2213 WORD nrsv;
mikekelly99 0:6db20bbdc767 2214 FATFS *fs;
mikekelly99 0:6db20bbdc767 2215 UINT i;
mikekelly99 0:6db20bbdc767 2216
mikekelly99 0:6db20bbdc767 2217
mikekelly99 0:6db20bbdc767 2218 /* Get logical drive number from the path name */
mikekelly99 0:6db20bbdc767 2219 *rfs = 0;
mikekelly99 0:6db20bbdc767 2220 vol = get_ldnumber(path);
mikekelly99 0:6db20bbdc767 2221 if (vol < 0) return FR_INVALID_DRIVE;
mikekelly99 0:6db20bbdc767 2222
mikekelly99 0:6db20bbdc767 2223 /* Check if the file system object is valid or not */
mikekelly99 0:6db20bbdc767 2224 fs = FatFs[vol]; /* Get pointer to the file system object */
mikekelly99 0:6db20bbdc767 2225 if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
mikekelly99 0:6db20bbdc767 2226
mikekelly99 0:6db20bbdc767 2227 ENTER_FF(fs); /* Lock the volume */
mikekelly99 0:6db20bbdc767 2228 *rfs = fs; /* Return pointer to the file system object */
mikekelly99 0:6db20bbdc767 2229
mikekelly99 0:6db20bbdc767 2230 if (fs->fs_type) { /* If the volume has been mounted */
mikekelly99 0:6db20bbdc767 2231 stat = disk_status(fs->drv);
mikekelly99 0:6db20bbdc767 2232 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */
mikekelly99 0:6db20bbdc767 2233 if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */
mikekelly99 0:6db20bbdc767 2234 return FR_WRITE_PROTECTED;
mikekelly99 0:6db20bbdc767 2235 return FR_OK; /* The file system object is valid */
mikekelly99 0:6db20bbdc767 2236 }
mikekelly99 0:6db20bbdc767 2237 }
mikekelly99 0:6db20bbdc767 2238
mikekelly99 0:6db20bbdc767 2239 /* The file system object is not valid. */
mikekelly99 0:6db20bbdc767 2240 /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
mikekelly99 0:6db20bbdc767 2241
mikekelly99 0:6db20bbdc767 2242 fs->fs_type = 0; /* Clear the file system object */
mikekelly99 0:6db20bbdc767 2243 fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */
mikekelly99 0:6db20bbdc767 2244 stat = disk_initialize(fs->drv); /* Initialize the physical drive */
mikekelly99 0:6db20bbdc767 2245 if (stat & STA_NOINIT) /* Check if the initialization succeeded */
mikekelly99 0:6db20bbdc767 2246 return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */
mikekelly99 0:6db20bbdc767 2247 if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */
mikekelly99 0:6db20bbdc767 2248 return FR_WRITE_PROTECTED;
mikekelly99 0:6db20bbdc767 2249 #if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */
mikekelly99 0:6db20bbdc767 2250 if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
mikekelly99 0:6db20bbdc767 2251 || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 2252 #endif
mikekelly99 0:6db20bbdc767 2253 /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */
mikekelly99 0:6db20bbdc767 2254 bsect = 0;
mikekelly99 0:6db20bbdc767 2255 fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */
mikekelly99 0:6db20bbdc767 2256 if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */
mikekelly99 0:6db20bbdc767 2257 for (i = 0; i < 4; i++) { /* Get partition offset */
mikekelly99 0:6db20bbdc767 2258 pt = fs->win + MBR_Table + i * SZ_PTE;
mikekelly99 0:6db20bbdc767 2259 br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0;
mikekelly99 0:6db20bbdc767 2260 }
mikekelly99 0:6db20bbdc767 2261 i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */
mikekelly99 0:6db20bbdc767 2262 if (i) i--;
mikekelly99 0:6db20bbdc767 2263 do { /* Find an FAT volume */
mikekelly99 0:6db20bbdc767 2264 bsect = br[i];
mikekelly99 0:6db20bbdc767 2265 fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */
mikekelly99 0:6db20bbdc767 2266 } while (!LD2PT(vol) && fmt && ++i < 4);
mikekelly99 0:6db20bbdc767 2267 }
mikekelly99 0:6db20bbdc767 2268 if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */
mikekelly99 0:6db20bbdc767 2269 if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
mikekelly99 0:6db20bbdc767 2270
mikekelly99 0:6db20bbdc767 2271 /* An FAT volume is found. Following code initializes the file system object */
mikekelly99 0:6db20bbdc767 2272
mikekelly99 0:6db20bbdc767 2273 if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
mikekelly99 0:6db20bbdc767 2274 return FR_NO_FILESYSTEM;
mikekelly99 0:6db20bbdc767 2275
mikekelly99 0:6db20bbdc767 2276 fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */
mikekelly99 0:6db20bbdc767 2277 if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32);
mikekelly99 0:6db20bbdc767 2278 fs->fsize = fasize;
mikekelly99 0:6db20bbdc767 2279
mikekelly99 0:6db20bbdc767 2280 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */
mikekelly99 0:6db20bbdc767 2281 if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */
mikekelly99 0:6db20bbdc767 2282 return FR_NO_FILESYSTEM;
mikekelly99 0:6db20bbdc767 2283 fasize *= fs->n_fats; /* Number of sectors for FAT area */
mikekelly99 0:6db20bbdc767 2284
mikekelly99 0:6db20bbdc767 2285 fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
mikekelly99 0:6db20bbdc767 2286 if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */
mikekelly99 0:6db20bbdc767 2287 return FR_NO_FILESYSTEM;
mikekelly99 0:6db20bbdc767 2288
mikekelly99 0:6db20bbdc767 2289 fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
mikekelly99 0:6db20bbdc767 2290 if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */
mikekelly99 0:6db20bbdc767 2291 return FR_NO_FILESYSTEM;
mikekelly99 0:6db20bbdc767 2292
mikekelly99 0:6db20bbdc767 2293 tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
mikekelly99 0:6db20bbdc767 2294 if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32);
mikekelly99 0:6db20bbdc767 2295
mikekelly99 0:6db20bbdc767 2296 nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
mikekelly99 0:6db20bbdc767 2297 if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */
mikekelly99 0:6db20bbdc767 2298
mikekelly99 0:6db20bbdc767 2299 /* Determine the FAT sub type */
mikekelly99 0:6db20bbdc767 2300 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + FATFS_DIR */
mikekelly99 0:6db20bbdc767 2301 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
mikekelly99 0:6db20bbdc767 2302 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
mikekelly99 0:6db20bbdc767 2303 if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
mikekelly99 0:6db20bbdc767 2304 fmt = FS_FAT12;
mikekelly99 0:6db20bbdc767 2305 if (nclst >= MIN_FAT16) fmt = FS_FAT16;
mikekelly99 0:6db20bbdc767 2306 if (nclst >= MIN_FAT32) fmt = FS_FAT32;
mikekelly99 0:6db20bbdc767 2307
mikekelly99 0:6db20bbdc767 2308 /* Boundaries and Limits */
mikekelly99 0:6db20bbdc767 2309 fs->n_fatent = nclst + 2; /* Number of FAT entries */
mikekelly99 0:6db20bbdc767 2310 fs->volbase = bsect; /* Volume start sector */
mikekelly99 0:6db20bbdc767 2311 fs->fatbase = bsect + nrsv; /* FAT start sector */
mikekelly99 0:6db20bbdc767 2312 fs->database = bsect + sysect; /* Data start sector */
mikekelly99 0:6db20bbdc767 2313 if (fmt == FS_FAT32) {
mikekelly99 0:6db20bbdc767 2314 if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
mikekelly99 0:6db20bbdc767 2315 fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */
mikekelly99 0:6db20bbdc767 2316 szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
mikekelly99 0:6db20bbdc767 2317 } else {
mikekelly99 0:6db20bbdc767 2318 if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
mikekelly99 0:6db20bbdc767 2319 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
mikekelly99 0:6db20bbdc767 2320 szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
mikekelly99 0:6db20bbdc767 2321 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
mikekelly99 0:6db20bbdc767 2322 }
mikekelly99 0:6db20bbdc767 2323 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */
mikekelly99 0:6db20bbdc767 2324 return FR_NO_FILESYSTEM;
mikekelly99 0:6db20bbdc767 2325
mikekelly99 0:6db20bbdc767 2326 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 2327 /* Initialize cluster allocation information */
mikekelly99 0:6db20bbdc767 2328 fs->last_clust = fs->free_clust = 0xFFFFFFFF;
mikekelly99 0:6db20bbdc767 2329
mikekelly99 0:6db20bbdc767 2330 /* Get fsinfo if available */
mikekelly99 0:6db20bbdc767 2331 fs->fsi_flag = 0x80;
mikekelly99 0:6db20bbdc767 2332 #if (_FS_NOFSINFO & 3) != 3
mikekelly99 0:6db20bbdc767 2333 if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */
mikekelly99 0:6db20bbdc767 2334 && LD_WORD(fs->win + BPB_FSInfo) == 1
mikekelly99 0:6db20bbdc767 2335 && move_window(fs, bsect + 1) == FR_OK)
mikekelly99 0:6db20bbdc767 2336 {
mikekelly99 0:6db20bbdc767 2337 fs->fsi_flag = 0;
mikekelly99 0:6db20bbdc767 2338 if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */
mikekelly99 0:6db20bbdc767 2339 && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252
mikekelly99 0:6db20bbdc767 2340 && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272)
mikekelly99 0:6db20bbdc767 2341 {
mikekelly99 0:6db20bbdc767 2342 #if (_FS_NOFSINFO & 1) == 0
mikekelly99 0:6db20bbdc767 2343 fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count);
mikekelly99 0:6db20bbdc767 2344 #endif
mikekelly99 0:6db20bbdc767 2345 #if (_FS_NOFSINFO & 2) == 0
mikekelly99 0:6db20bbdc767 2346 fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free);
mikekelly99 0:6db20bbdc767 2347 #endif
mikekelly99 0:6db20bbdc767 2348 }
mikekelly99 0:6db20bbdc767 2349 }
mikekelly99 0:6db20bbdc767 2350 #endif
mikekelly99 0:6db20bbdc767 2351 #endif
mikekelly99 0:6db20bbdc767 2352 fs->fs_type = fmt; /* FAT sub-type */
mikekelly99 0:6db20bbdc767 2353 fs->id = ++Fsid; /* File system mount ID */
mikekelly99 0:6db20bbdc767 2354 #if _FS_RPATH
mikekelly99 0:6db20bbdc767 2355 fs->cdir = 0; /* Set current directory to root */
mikekelly99 0:6db20bbdc767 2356 #endif
mikekelly99 0:6db20bbdc767 2357 #if _FS_LOCK /* Clear file lock semaphores */
mikekelly99 0:6db20bbdc767 2358 clear_lock(fs);
mikekelly99 0:6db20bbdc767 2359 #endif
mikekelly99 0:6db20bbdc767 2360
mikekelly99 0:6db20bbdc767 2361 return FR_OK;
mikekelly99 0:6db20bbdc767 2362 }
mikekelly99 0:6db20bbdc767 2363
mikekelly99 0:6db20bbdc767 2364
mikekelly99 0:6db20bbdc767 2365
mikekelly99 0:6db20bbdc767 2366
mikekelly99 0:6db20bbdc767 2367 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2368 /* Check if the file/directory object is valid or not */
mikekelly99 0:6db20bbdc767 2369 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2370
mikekelly99 0:6db20bbdc767 2371 static
mikekelly99 0:6db20bbdc767 2372 FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
mikekelly99 0:6db20bbdc767 2373 void* obj /* Pointer to the object FIL/FATFS_DIR to check validity */
mikekelly99 0:6db20bbdc767 2374 )
mikekelly99 0:6db20bbdc767 2375 {
mikekelly99 0:6db20bbdc767 2376 FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/FATFS_DIR structure is identical */
mikekelly99 0:6db20bbdc767 2377
mikekelly99 0:6db20bbdc767 2378
mikekelly99 0:6db20bbdc767 2379 if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT))
mikekelly99 0:6db20bbdc767 2380 return FR_INVALID_OBJECT;
mikekelly99 0:6db20bbdc767 2381
mikekelly99 0:6db20bbdc767 2382 ENTER_FF(fil->fs); /* Lock file system */
mikekelly99 0:6db20bbdc767 2383
mikekelly99 0:6db20bbdc767 2384 return FR_OK;
mikekelly99 0:6db20bbdc767 2385 }
mikekelly99 0:6db20bbdc767 2386
mikekelly99 0:6db20bbdc767 2387
mikekelly99 0:6db20bbdc767 2388
mikekelly99 0:6db20bbdc767 2389
mikekelly99 0:6db20bbdc767 2390 /*--------------------------------------------------------------------------
mikekelly99 0:6db20bbdc767 2391
mikekelly99 0:6db20bbdc767 2392 Public Functions
mikekelly99 0:6db20bbdc767 2393
mikekelly99 0:6db20bbdc767 2394 ---------------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2395
mikekelly99 0:6db20bbdc767 2396
mikekelly99 0:6db20bbdc767 2397
mikekelly99 0:6db20bbdc767 2398 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2399 /* Mount/Unmount a Logical Drive */
mikekelly99 0:6db20bbdc767 2400 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2401
mikekelly99 0:6db20bbdc767 2402 FRESULT f_mount (
mikekelly99 0:6db20bbdc767 2403 FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/
mikekelly99 0:6db20bbdc767 2404 const TCHAR* path, /* Logical drive number to be mounted/unmounted */
mikekelly99 0:6db20bbdc767 2405 BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */
mikekelly99 0:6db20bbdc767 2406 )
mikekelly99 0:6db20bbdc767 2407 {
mikekelly99 0:6db20bbdc767 2408 FATFS *cfs;
mikekelly99 0:6db20bbdc767 2409 int vol;
mikekelly99 0:6db20bbdc767 2410 FRESULT res;
mikekelly99 0:6db20bbdc767 2411 const TCHAR *rp = path;
mikekelly99 0:6db20bbdc767 2412
mikekelly99 0:6db20bbdc767 2413
mikekelly99 0:6db20bbdc767 2414 vol = get_ldnumber(&rp);
mikekelly99 0:6db20bbdc767 2415 if (vol < 0) return FR_INVALID_DRIVE;
mikekelly99 0:6db20bbdc767 2416 cfs = FatFs[vol]; /* Pointer to fs object */
mikekelly99 0:6db20bbdc767 2417
mikekelly99 0:6db20bbdc767 2418 if (cfs) {
mikekelly99 0:6db20bbdc767 2419 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 2420 clear_lock(cfs);
mikekelly99 0:6db20bbdc767 2421 #endif
mikekelly99 0:6db20bbdc767 2422 #if _FS_REENTRANT /* Discard sync object of the current volume */
mikekelly99 0:6db20bbdc767 2423 if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 2424 #endif
mikekelly99 0:6db20bbdc767 2425 cfs->fs_type = 0; /* Clear old fs object */
mikekelly99 0:6db20bbdc767 2426 }
mikekelly99 0:6db20bbdc767 2427
mikekelly99 0:6db20bbdc767 2428 if (fs) {
mikekelly99 0:6db20bbdc767 2429 fs->fs_type = 0; /* Clear new fs object */
mikekelly99 0:6db20bbdc767 2430 #if _FS_REENTRANT /* Create sync object for the new volume */
mikekelly99 0:6db20bbdc767 2431 if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
mikekelly99 0:6db20bbdc767 2432 #endif
mikekelly99 0:6db20bbdc767 2433 }
mikekelly99 0:6db20bbdc767 2434 FatFs[vol] = fs; /* Register new fs object */
mikekelly99 0:6db20bbdc767 2435
mikekelly99 0:6db20bbdc767 2436 if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */
mikekelly99 0:6db20bbdc767 2437
mikekelly99 0:6db20bbdc767 2438 res = find_volume(&fs, &path, 0); /* Force mounted the volume */
mikekelly99 0:6db20bbdc767 2439 LEAVE_FF(fs, res);
mikekelly99 0:6db20bbdc767 2440 }
mikekelly99 0:6db20bbdc767 2441
mikekelly99 0:6db20bbdc767 2442
mikekelly99 0:6db20bbdc767 2443
mikekelly99 0:6db20bbdc767 2444
mikekelly99 0:6db20bbdc767 2445 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2446 /* Open or Create a File */
mikekelly99 0:6db20bbdc767 2447 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2448
mikekelly99 0:6db20bbdc767 2449 FRESULT f_open (
mikekelly99 0:6db20bbdc767 2450 FIL* fp, /* Pointer to the blank file object */
mikekelly99 0:6db20bbdc767 2451 const TCHAR* path, /* Pointer to the file name */
mikekelly99 0:6db20bbdc767 2452 BYTE mode /* Access mode and file open mode flags */
mikekelly99 0:6db20bbdc767 2453 )
mikekelly99 0:6db20bbdc767 2454 {
mikekelly99 0:6db20bbdc767 2455 FRESULT res;
mikekelly99 0:6db20bbdc767 2456 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 2457 BYTE *dir;
mikekelly99 0:6db20bbdc767 2458 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 2459 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 2460 DWORD dw, cl;
mikekelly99 0:6db20bbdc767 2461 #endif
mikekelly99 0:6db20bbdc767 2462
mikekelly99 0:6db20bbdc767 2463
mikekelly99 0:6db20bbdc767 2464 if (!fp) return FR_INVALID_OBJECT;
mikekelly99 0:6db20bbdc767 2465 fp->fs = 0; /* Clear file object */
mikekelly99 0:6db20bbdc767 2466
mikekelly99 0:6db20bbdc767 2467 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 2468 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 2469 mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
mikekelly99 0:6db20bbdc767 2470 res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ));
mikekelly99 0:6db20bbdc767 2471 #else
mikekelly99 0:6db20bbdc767 2472 mode &= FA_READ;
mikekelly99 0:6db20bbdc767 2473 res = find_volume(&dj.fs, &path, 0);
mikekelly99 0:6db20bbdc767 2474 #endif
mikekelly99 0:6db20bbdc767 2475 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2476 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 2477 res = follow_path(&dj, path); /* Follow the file path */
mikekelly99 0:6db20bbdc767 2478 dir = dj.dir;
mikekelly99 0:6db20bbdc767 2479 #if !_FS_READONLY /* R/W configuration */
mikekelly99 0:6db20bbdc767 2480 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2481 if (!dir) /* Default directory itself */
mikekelly99 0:6db20bbdc767 2482 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 2483 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 2484 else
mikekelly99 0:6db20bbdc767 2485 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
mikekelly99 0:6db20bbdc767 2486 #endif
mikekelly99 0:6db20bbdc767 2487 }
mikekelly99 0:6db20bbdc767 2488 /* Create or Open a file */
mikekelly99 0:6db20bbdc767 2489 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
mikekelly99 0:6db20bbdc767 2490 if (res != FR_OK) { /* No file, create new */
mikekelly99 0:6db20bbdc767 2491 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
mikekelly99 0:6db20bbdc767 2492 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 2493 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
mikekelly99 0:6db20bbdc767 2494 #else
mikekelly99 0:6db20bbdc767 2495 res = dir_register(&dj);
mikekelly99 0:6db20bbdc767 2496 #endif
mikekelly99 0:6db20bbdc767 2497 mode |= FA_CREATE_ALWAYS; /* File is created */
mikekelly99 0:6db20bbdc767 2498 dir = dj.dir; /* New entry */
mikekelly99 0:6db20bbdc767 2499 }
mikekelly99 0:6db20bbdc767 2500 else { /* Any object is already existing */
mikekelly99 0:6db20bbdc767 2501 if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or FATFS_DIR) */
mikekelly99 0:6db20bbdc767 2502 res = FR_DENIED;
mikekelly99 0:6db20bbdc767 2503 } else {
mikekelly99 0:6db20bbdc767 2504 if (mode & FA_CREATE_NEW) /* Cannot create as new file */
mikekelly99 0:6db20bbdc767 2505 res = FR_EXIST;
mikekelly99 0:6db20bbdc767 2506 }
mikekelly99 0:6db20bbdc767 2507 }
mikekelly99 0:6db20bbdc767 2508 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
mikekelly99 0:6db20bbdc767 2509 dw = GET_FATTIME();
mikekelly99 0:6db20bbdc767 2510 ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */
mikekelly99 0:6db20bbdc767 2511 ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */
mikekelly99 0:6db20bbdc767 2512 dir[DIR_Attr] = 0; /* Reset attribute */
mikekelly99 0:6db20bbdc767 2513 ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */
mikekelly99 0:6db20bbdc767 2514 cl = ld_clust(dj.fs, dir); /* Get cluster chain */
mikekelly99 0:6db20bbdc767 2515 st_clust(dir, 0); /* Reset cluster */
mikekelly99 0:6db20bbdc767 2516 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 2517 if (cl) { /* Remove the cluster chain if exist */
mikekelly99 0:6db20bbdc767 2518 dw = dj.fs->winsect;
mikekelly99 0:6db20bbdc767 2519 res = remove_chain(dj.fs, cl);
mikekelly99 0:6db20bbdc767 2520 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2521 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
mikekelly99 0:6db20bbdc767 2522 res = move_window(dj.fs, dw);
mikekelly99 0:6db20bbdc767 2523 }
mikekelly99 0:6db20bbdc767 2524 }
mikekelly99 0:6db20bbdc767 2525 }
mikekelly99 0:6db20bbdc767 2526 }
mikekelly99 0:6db20bbdc767 2527 else { /* Open an existing file */
mikekelly99 0:6db20bbdc767 2528 if (res == FR_OK) { /* Following succeeded */
mikekelly99 0:6db20bbdc767 2529 if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
mikekelly99 0:6db20bbdc767 2530 res = FR_NO_FILE;
mikekelly99 0:6db20bbdc767 2531 } else {
mikekelly99 0:6db20bbdc767 2532 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
mikekelly99 0:6db20bbdc767 2533 res = FR_DENIED;
mikekelly99 0:6db20bbdc767 2534 }
mikekelly99 0:6db20bbdc767 2535 }
mikekelly99 0:6db20bbdc767 2536 }
mikekelly99 0:6db20bbdc767 2537 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2538 if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
mikekelly99 0:6db20bbdc767 2539 mode |= FA__WRITTEN;
mikekelly99 0:6db20bbdc767 2540 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
mikekelly99 0:6db20bbdc767 2541 fp->dir_ptr = dir;
mikekelly99 0:6db20bbdc767 2542 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 2543 fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
mikekelly99 0:6db20bbdc767 2544 if (!fp->lockid) res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 2545 #endif
mikekelly99 0:6db20bbdc767 2546 }
mikekelly99 0:6db20bbdc767 2547
mikekelly99 0:6db20bbdc767 2548 #else /* R/O configuration */
mikekelly99 0:6db20bbdc767 2549 if (res == FR_OK) { /* Follow succeeded */
mikekelly99 0:6db20bbdc767 2550 dir = dj.dir;
mikekelly99 0:6db20bbdc767 2551 if (!dir) { /* Current directory itself */
mikekelly99 0:6db20bbdc767 2552 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 2553 } else {
mikekelly99 0:6db20bbdc767 2554 if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
mikekelly99 0:6db20bbdc767 2555 res = FR_NO_FILE;
mikekelly99 0:6db20bbdc767 2556 }
mikekelly99 0:6db20bbdc767 2557 }
mikekelly99 0:6db20bbdc767 2558 #endif
mikekelly99 0:6db20bbdc767 2559 FREE_BUF();
mikekelly99 0:6db20bbdc767 2560
mikekelly99 0:6db20bbdc767 2561 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2562 fp->flag = mode; /* File access mode */
mikekelly99 0:6db20bbdc767 2563 fp->err = 0; /* Clear error flag */
mikekelly99 0:6db20bbdc767 2564 fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */
mikekelly99 0:6db20bbdc767 2565 fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */
mikekelly99 0:6db20bbdc767 2566 fp->fptr = 0; /* File pointer */
mikekelly99 0:6db20bbdc767 2567 fp->dsect = 0;
mikekelly99 0:6db20bbdc767 2568 #if _USE_FASTSEEK
mikekelly99 0:6db20bbdc767 2569 fp->cltbl = 0; /* Normal seek mode */
mikekelly99 0:6db20bbdc767 2570 #endif
mikekelly99 0:6db20bbdc767 2571 fp->fs = dj.fs; /* Validate file object */
mikekelly99 0:6db20bbdc767 2572 fp->id = fp->fs->id;
mikekelly99 0:6db20bbdc767 2573 }
mikekelly99 0:6db20bbdc767 2574 }
mikekelly99 0:6db20bbdc767 2575
mikekelly99 0:6db20bbdc767 2576 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 2577 }
mikekelly99 0:6db20bbdc767 2578
mikekelly99 0:6db20bbdc767 2579
mikekelly99 0:6db20bbdc767 2580
mikekelly99 0:6db20bbdc767 2581
mikekelly99 0:6db20bbdc767 2582 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2583 /* Read File */
mikekelly99 0:6db20bbdc767 2584 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2585
mikekelly99 0:6db20bbdc767 2586 FRESULT f_read (
mikekelly99 0:6db20bbdc767 2587 FIL* fp, /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 2588 void* buff, /* Pointer to data buffer */
mikekelly99 0:6db20bbdc767 2589 UINT btr, /* Number of bytes to read */
mikekelly99 0:6db20bbdc767 2590 UINT* br /* Pointer to number of bytes read */
mikekelly99 0:6db20bbdc767 2591 )
mikekelly99 0:6db20bbdc767 2592 {
mikekelly99 0:6db20bbdc767 2593 FRESULT res;
mikekelly99 0:6db20bbdc767 2594 DWORD clst, sect, remain;
mikekelly99 0:6db20bbdc767 2595 UINT rcnt, cc;
mikekelly99 0:6db20bbdc767 2596 BYTE csect, *rbuff = (BYTE*)buff;
mikekelly99 0:6db20bbdc767 2597
mikekelly99 0:6db20bbdc767 2598
mikekelly99 0:6db20bbdc767 2599 *br = 0; /* Clear read byte counter */
mikekelly99 0:6db20bbdc767 2600
mikekelly99 0:6db20bbdc767 2601 res = validate(fp); /* Check validity */
mikekelly99 0:6db20bbdc767 2602 if (res != FR_OK) LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 2603 if (fp->err) /* Check error */
mikekelly99 0:6db20bbdc767 2604 LEAVE_FF(fp->fs, (FRESULT)fp->err);
mikekelly99 0:6db20bbdc767 2605 if (!(fp->flag & FA_READ)) /* Check access mode */
mikekelly99 0:6db20bbdc767 2606 LEAVE_FF(fp->fs, FR_DENIED);
mikekelly99 0:6db20bbdc767 2607 remain = fp->fsize - fp->fptr;
mikekelly99 0:6db20bbdc767 2608 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
mikekelly99 0:6db20bbdc767 2609
mikekelly99 0:6db20bbdc767 2610 for ( ; btr; /* Repeat until all data read */
mikekelly99 0:6db20bbdc767 2611 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
mikekelly99 0:6db20bbdc767 2612 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
mikekelly99 0:6db20bbdc767 2613 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
mikekelly99 0:6db20bbdc767 2614 if (!csect) { /* On the cluster boundary? */
mikekelly99 0:6db20bbdc767 2615 if (fp->fptr == 0) { /* On the top of the file? */
mikekelly99 0:6db20bbdc767 2616 clst = fp->sclust; /* Follow from the origin */
mikekelly99 0:6db20bbdc767 2617 } else { /* Middle or end of the file */
mikekelly99 0:6db20bbdc767 2618 #if _USE_FASTSEEK
mikekelly99 0:6db20bbdc767 2619 if (fp->cltbl)
mikekelly99 0:6db20bbdc767 2620 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
mikekelly99 0:6db20bbdc767 2621 else
mikekelly99 0:6db20bbdc767 2622 #endif
mikekelly99 0:6db20bbdc767 2623 clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
mikekelly99 0:6db20bbdc767 2624 }
mikekelly99 0:6db20bbdc767 2625 if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 2626 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2627 fp->clust = clst; /* Update current cluster */
mikekelly99 0:6db20bbdc767 2628 }
mikekelly99 0:6db20bbdc767 2629 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
mikekelly99 0:6db20bbdc767 2630 if (!sect) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 2631 sect += csect;
mikekelly99 0:6db20bbdc767 2632 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
mikekelly99 0:6db20bbdc767 2633 if (cc) { /* Read maximum contiguous sectors directly */
mikekelly99 0:6db20bbdc767 2634 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
mikekelly99 0:6db20bbdc767 2635 cc = fp->fs->csize - csect;
mikekelly99 0:6db20bbdc767 2636 if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK)
mikekelly99 0:6db20bbdc767 2637 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2638 #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
mikekelly99 0:6db20bbdc767 2639 #if _FS_TINY
mikekelly99 0:6db20bbdc767 2640 if (fp->fs->wflag && fp->fs->winsect - sect < cc)
mikekelly99 0:6db20bbdc767 2641 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
mikekelly99 0:6db20bbdc767 2642 #else
mikekelly99 0:6db20bbdc767 2643 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
mikekelly99 0:6db20bbdc767 2644 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
mikekelly99 0:6db20bbdc767 2645 #endif
mikekelly99 0:6db20bbdc767 2646 #endif
mikekelly99 0:6db20bbdc767 2647 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
mikekelly99 0:6db20bbdc767 2648 continue;
mikekelly99 0:6db20bbdc767 2649 }
mikekelly99 0:6db20bbdc767 2650 #if !_FS_TINY
mikekelly99 0:6db20bbdc767 2651 if (fp->dsect != sect) { /* Load data sector if not in cache */
mikekelly99 0:6db20bbdc767 2652 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 2653 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
mikekelly99 0:6db20bbdc767 2654 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 2655 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2656 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 2657 }
mikekelly99 0:6db20bbdc767 2658 #endif
mikekelly99 0:6db20bbdc767 2659 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
mikekelly99 0:6db20bbdc767 2660 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2661 }
mikekelly99 0:6db20bbdc767 2662 #endif
mikekelly99 0:6db20bbdc767 2663 fp->dsect = sect;
mikekelly99 0:6db20bbdc767 2664 }
mikekelly99 0:6db20bbdc767 2665 rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
mikekelly99 0:6db20bbdc767 2666 if (rcnt > btr) rcnt = btr;
mikekelly99 0:6db20bbdc767 2667 #if _FS_TINY
mikekelly99 0:6db20bbdc767 2668 if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */
mikekelly99 0:6db20bbdc767 2669 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2670 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
mikekelly99 0:6db20bbdc767 2671 #else
mikekelly99 0:6db20bbdc767 2672 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
mikekelly99 0:6db20bbdc767 2673 #endif
mikekelly99 0:6db20bbdc767 2674 }
mikekelly99 0:6db20bbdc767 2675
mikekelly99 0:6db20bbdc767 2676 LEAVE_FF(fp->fs, FR_OK);
mikekelly99 0:6db20bbdc767 2677 }
mikekelly99 0:6db20bbdc767 2678
mikekelly99 0:6db20bbdc767 2679
mikekelly99 0:6db20bbdc767 2680
mikekelly99 0:6db20bbdc767 2681
mikekelly99 0:6db20bbdc767 2682 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 2683 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2684 /* Write File */
mikekelly99 0:6db20bbdc767 2685 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2686
mikekelly99 0:6db20bbdc767 2687 FRESULT f_write (
mikekelly99 0:6db20bbdc767 2688 FIL* fp, /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 2689 const void *buff, /* Pointer to the data to be written */
mikekelly99 0:6db20bbdc767 2690 UINT btw, /* Number of bytes to write */
mikekelly99 0:6db20bbdc767 2691 UINT* bw /* Pointer to number of bytes written */
mikekelly99 0:6db20bbdc767 2692 )
mikekelly99 0:6db20bbdc767 2693 {
mikekelly99 0:6db20bbdc767 2694 FRESULT res;
mikekelly99 0:6db20bbdc767 2695 DWORD clst, sect;
mikekelly99 0:6db20bbdc767 2696 UINT wcnt, cc;
mikekelly99 0:6db20bbdc767 2697 const BYTE *wbuff = (const BYTE*)buff;
mikekelly99 0:6db20bbdc767 2698 BYTE csect;
mikekelly99 0:6db20bbdc767 2699 bool need_sync = false;
mikekelly99 0:6db20bbdc767 2700
mikekelly99 0:6db20bbdc767 2701 *bw = 0; /* Clear write byte counter */
mikekelly99 0:6db20bbdc767 2702
mikekelly99 0:6db20bbdc767 2703 res = validate(fp); /* Check validity */
mikekelly99 0:6db20bbdc767 2704 if (res != FR_OK) LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 2705 if (fp->err) /* Check error */
mikekelly99 0:6db20bbdc767 2706 LEAVE_FF(fp->fs, (FRESULT)fp->err);
mikekelly99 0:6db20bbdc767 2707 if (!(fp->flag & FA_WRITE)) /* Check access mode */
mikekelly99 0:6db20bbdc767 2708 LEAVE_FF(fp->fs, FR_DENIED);
mikekelly99 0:6db20bbdc767 2709 if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */
mikekelly99 0:6db20bbdc767 2710
mikekelly99 0:6db20bbdc767 2711 for ( ; btw; /* Repeat until all data written */
mikekelly99 0:6db20bbdc767 2712 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
mikekelly99 0:6db20bbdc767 2713 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
mikekelly99 0:6db20bbdc767 2714 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
mikekelly99 0:6db20bbdc767 2715 if (!csect) { /* On the cluster boundary? */
mikekelly99 0:6db20bbdc767 2716 if (fp->fptr == 0) { /* On the top of the file? */
mikekelly99 0:6db20bbdc767 2717 clst = fp->sclust; /* Follow from the origin */
mikekelly99 0:6db20bbdc767 2718 if (clst == 0) /* When no cluster is allocated, */
mikekelly99 0:6db20bbdc767 2719 clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
mikekelly99 0:6db20bbdc767 2720 } else { /* Middle or end of the file */
mikekelly99 0:6db20bbdc767 2721 #if _USE_FASTSEEK
mikekelly99 0:6db20bbdc767 2722 if (fp->cltbl)
mikekelly99 0:6db20bbdc767 2723 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
mikekelly99 0:6db20bbdc767 2724 else
mikekelly99 0:6db20bbdc767 2725 #endif
mikekelly99 0:6db20bbdc767 2726 clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
mikekelly99 0:6db20bbdc767 2727 }
mikekelly99 0:6db20bbdc767 2728 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
mikekelly99 0:6db20bbdc767 2729 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 2730 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2731 fp->clust = clst; /* Update current cluster */
mikekelly99 0:6db20bbdc767 2732 if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */
mikekelly99 0:6db20bbdc767 2733
mikekelly99 0:6db20bbdc767 2734 #if FLUSH_ON_NEW_CLUSTER
mikekelly99 0:6db20bbdc767 2735 // We do not need to flush for the first cluster
mikekelly99 0:6db20bbdc767 2736 if (fp->fptr != 0) {
mikekelly99 0:6db20bbdc767 2737 need_sync = true;
mikekelly99 0:6db20bbdc767 2738 }
mikekelly99 0:6db20bbdc767 2739 #endif
mikekelly99 0:6db20bbdc767 2740 }
mikekelly99 0:6db20bbdc767 2741 #if _FS_TINY
mikekelly99 0:6db20bbdc767 2742 if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */
mikekelly99 0:6db20bbdc767 2743 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2744 #else
mikekelly99 0:6db20bbdc767 2745 if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
mikekelly99 0:6db20bbdc767 2746 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 2747 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2748 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 2749 }
mikekelly99 0:6db20bbdc767 2750 #endif
mikekelly99 0:6db20bbdc767 2751 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
mikekelly99 0:6db20bbdc767 2752 if (!sect) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 2753 sect += csect;
mikekelly99 0:6db20bbdc767 2754 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
mikekelly99 0:6db20bbdc767 2755 if (cc) { /* Write maximum contiguous sectors directly */
mikekelly99 0:6db20bbdc767 2756 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
mikekelly99 0:6db20bbdc767 2757 cc = fp->fs->csize - csect;
mikekelly99 0:6db20bbdc767 2758 if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK)
mikekelly99 0:6db20bbdc767 2759 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2760 #if _FS_MINIMIZE <= 2
mikekelly99 0:6db20bbdc767 2761 #if _FS_TINY
mikekelly99 0:6db20bbdc767 2762 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
mikekelly99 0:6db20bbdc767 2763 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
mikekelly99 0:6db20bbdc767 2764 fp->fs->wflag = 0;
mikekelly99 0:6db20bbdc767 2765 }
mikekelly99 0:6db20bbdc767 2766 #else
mikekelly99 0:6db20bbdc767 2767 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
mikekelly99 0:6db20bbdc767 2768 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
mikekelly99 0:6db20bbdc767 2769 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 2770 }
mikekelly99 0:6db20bbdc767 2771 #endif
mikekelly99 0:6db20bbdc767 2772 #endif
mikekelly99 0:6db20bbdc767 2773 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
mikekelly99 0:6db20bbdc767 2774 #if FLUSH_ON_NEW_SECTOR
mikekelly99 0:6db20bbdc767 2775 need_sync = true;
mikekelly99 0:6db20bbdc767 2776 #endif
mikekelly99 0:6db20bbdc767 2777 continue;
mikekelly99 0:6db20bbdc767 2778 }
mikekelly99 0:6db20bbdc767 2779 #if _FS_TINY
mikekelly99 0:6db20bbdc767 2780 if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */
mikekelly99 0:6db20bbdc767 2781 if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2782 fp->fs->winsect = sect;
mikekelly99 0:6db20bbdc767 2783 }
mikekelly99 0:6db20bbdc767 2784 #else
mikekelly99 0:6db20bbdc767 2785 if (fp->dsect != sect) { /* Fill sector cache with file data */
mikekelly99 0:6db20bbdc767 2786 if (fp->fptr < fp->fsize &&
mikekelly99 0:6db20bbdc767 2787 disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 2788 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2789 }
mikekelly99 0:6db20bbdc767 2790 #endif
mikekelly99 0:6db20bbdc767 2791 fp->dsect = sect;
mikekelly99 0:6db20bbdc767 2792 }
mikekelly99 0:6db20bbdc767 2793 wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
mikekelly99 0:6db20bbdc767 2794 if (wcnt > btw) wcnt = btw;
mikekelly99 0:6db20bbdc767 2795 #if _FS_TINY
mikekelly99 0:6db20bbdc767 2796 if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */
mikekelly99 0:6db20bbdc767 2797 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2798 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
mikekelly99 0:6db20bbdc767 2799 fp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 2800 #else
mikekelly99 0:6db20bbdc767 2801 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
mikekelly99 0:6db20bbdc767 2802 fp->flag |= FA__DIRTY;
mikekelly99 0:6db20bbdc767 2803 #endif
mikekelly99 0:6db20bbdc767 2804 }
mikekelly99 0:6db20bbdc767 2805
mikekelly99 0:6db20bbdc767 2806 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
mikekelly99 0:6db20bbdc767 2807 fp->flag |= FA__WRITTEN; /* Set file change flag */
mikekelly99 0:6db20bbdc767 2808
mikekelly99 0:6db20bbdc767 2809 if (need_sync) {
mikekelly99 0:6db20bbdc767 2810 f_sync (fp);
mikekelly99 0:6db20bbdc767 2811 }
mikekelly99 0:6db20bbdc767 2812
mikekelly99 0:6db20bbdc767 2813 LEAVE_FF(fp->fs, FR_OK);
mikekelly99 0:6db20bbdc767 2814 }
mikekelly99 0:6db20bbdc767 2815
mikekelly99 0:6db20bbdc767 2816
mikekelly99 0:6db20bbdc767 2817
mikekelly99 0:6db20bbdc767 2818
mikekelly99 0:6db20bbdc767 2819 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2820 /* Synchronize the File */
mikekelly99 0:6db20bbdc767 2821 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2822
mikekelly99 0:6db20bbdc767 2823 FRESULT f_sync (
mikekelly99 0:6db20bbdc767 2824 FIL* fp /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 2825 )
mikekelly99 0:6db20bbdc767 2826 {
mikekelly99 0:6db20bbdc767 2827 FRESULT res;
mikekelly99 0:6db20bbdc767 2828 DWORD tm;
mikekelly99 0:6db20bbdc767 2829 BYTE *dir;
mikekelly99 0:6db20bbdc767 2830
mikekelly99 0:6db20bbdc767 2831
mikekelly99 0:6db20bbdc767 2832 res = validate(fp); /* Check validity of the object */
mikekelly99 0:6db20bbdc767 2833 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2834 if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */
mikekelly99 0:6db20bbdc767 2835 #if !_FS_TINY
mikekelly99 0:6db20bbdc767 2836 if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */
mikekelly99 0:6db20bbdc767 2837 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 2838 LEAVE_FF(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 2839 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 2840 }
mikekelly99 0:6db20bbdc767 2841 #endif
mikekelly99 0:6db20bbdc767 2842 /* Update the directory entry */
mikekelly99 0:6db20bbdc767 2843 res = move_window(fp->fs, fp->dir_sect);
mikekelly99 0:6db20bbdc767 2844 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2845 dir = fp->dir_ptr;
mikekelly99 0:6db20bbdc767 2846 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
mikekelly99 0:6db20bbdc767 2847 ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */
mikekelly99 0:6db20bbdc767 2848 st_clust(dir, fp->sclust); /* Update start cluster */
mikekelly99 0:6db20bbdc767 2849 tm = GET_FATTIME(); /* Update modified time */
mikekelly99 0:6db20bbdc767 2850 ST_DWORD(dir + DIR_WrtTime, tm);
mikekelly99 0:6db20bbdc767 2851 ST_WORD(dir + DIR_LstAccDate, 0);
mikekelly99 0:6db20bbdc767 2852 fp->flag &= ~FA__WRITTEN;
mikekelly99 0:6db20bbdc767 2853 fp->fs->wflag = 1;
mikekelly99 0:6db20bbdc767 2854 res = sync_fs(fp->fs);
mikekelly99 0:6db20bbdc767 2855 }
mikekelly99 0:6db20bbdc767 2856 }
mikekelly99 0:6db20bbdc767 2857 }
mikekelly99 0:6db20bbdc767 2858
mikekelly99 0:6db20bbdc767 2859 LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 2860 }
mikekelly99 0:6db20bbdc767 2861
mikekelly99 0:6db20bbdc767 2862 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 2863
mikekelly99 0:6db20bbdc767 2864
mikekelly99 0:6db20bbdc767 2865
mikekelly99 0:6db20bbdc767 2866
mikekelly99 0:6db20bbdc767 2867 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2868 /* Close File */
mikekelly99 0:6db20bbdc767 2869 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2870
mikekelly99 0:6db20bbdc767 2871 FRESULT f_close (
mikekelly99 0:6db20bbdc767 2872 FIL *fp /* Pointer to the file object to be closed */
mikekelly99 0:6db20bbdc767 2873 )
mikekelly99 0:6db20bbdc767 2874 {
mikekelly99 0:6db20bbdc767 2875 FRESULT res;
mikekelly99 0:6db20bbdc767 2876
mikekelly99 0:6db20bbdc767 2877
mikekelly99 0:6db20bbdc767 2878 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 2879 res = f_sync(fp); /* Flush cached data */
mikekelly99 0:6db20bbdc767 2880 if (res == FR_OK)
mikekelly99 0:6db20bbdc767 2881 #endif
mikekelly99 0:6db20bbdc767 2882 {
mikekelly99 0:6db20bbdc767 2883 res = validate(fp); /* Lock volume */
mikekelly99 0:6db20bbdc767 2884 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2885 #if _FS_REENTRANT
mikekelly99 0:6db20bbdc767 2886 FATFS *fs = fp->fs;
mikekelly99 0:6db20bbdc767 2887 #endif
mikekelly99 0:6db20bbdc767 2888 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 2889 res = dec_lock(fp->lockid); /* Decrement file open counter */
mikekelly99 0:6db20bbdc767 2890 if (res == FR_OK)
mikekelly99 0:6db20bbdc767 2891 #endif
mikekelly99 0:6db20bbdc767 2892 fp->fs = 0; /* Invalidate file object */
mikekelly99 0:6db20bbdc767 2893 #if _FS_REENTRANT
mikekelly99 0:6db20bbdc767 2894 unlock_fs(fs, FR_OK); /* Unlock volume */
mikekelly99 0:6db20bbdc767 2895 #endif
mikekelly99 0:6db20bbdc767 2896 }
mikekelly99 0:6db20bbdc767 2897 }
mikekelly99 0:6db20bbdc767 2898 return res;
mikekelly99 0:6db20bbdc767 2899 }
mikekelly99 0:6db20bbdc767 2900
mikekelly99 0:6db20bbdc767 2901
mikekelly99 0:6db20bbdc767 2902
mikekelly99 0:6db20bbdc767 2903
mikekelly99 0:6db20bbdc767 2904 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2905 /* Change Current Directory or Current Drive, Get Current Directory */
mikekelly99 0:6db20bbdc767 2906 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 2907
mikekelly99 0:6db20bbdc767 2908 #if _FS_RPATH >= 1
mikekelly99 0:6db20bbdc767 2909 #if _VOLUMES >= 2
mikekelly99 0:6db20bbdc767 2910 FRESULT f_chdrive (
mikekelly99 0:6db20bbdc767 2911 const TCHAR* path /* Drive number */
mikekelly99 0:6db20bbdc767 2912 )
mikekelly99 0:6db20bbdc767 2913 {
mikekelly99 0:6db20bbdc767 2914 int vol;
mikekelly99 0:6db20bbdc767 2915
mikekelly99 0:6db20bbdc767 2916
mikekelly99 0:6db20bbdc767 2917 vol = get_ldnumber(&path);
mikekelly99 0:6db20bbdc767 2918 if (vol < 0) return FR_INVALID_DRIVE;
mikekelly99 0:6db20bbdc767 2919
mikekelly99 0:6db20bbdc767 2920 CurrVol = (BYTE)vol;
mikekelly99 0:6db20bbdc767 2921
mikekelly99 0:6db20bbdc767 2922 return FR_OK;
mikekelly99 0:6db20bbdc767 2923 }
mikekelly99 0:6db20bbdc767 2924 #endif
mikekelly99 0:6db20bbdc767 2925
mikekelly99 0:6db20bbdc767 2926
mikekelly99 0:6db20bbdc767 2927 FRESULT f_chdir (
mikekelly99 0:6db20bbdc767 2928 const TCHAR* path /* Pointer to the directory path */
mikekelly99 0:6db20bbdc767 2929 )
mikekelly99 0:6db20bbdc767 2930 {
mikekelly99 0:6db20bbdc767 2931 FRESULT res;
mikekelly99 0:6db20bbdc767 2932 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 2933 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 2934
mikekelly99 0:6db20bbdc767 2935
mikekelly99 0:6db20bbdc767 2936 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 2937 res = find_volume(&dj.fs, &path, 0);
mikekelly99 0:6db20bbdc767 2938 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2939 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 2940 res = follow_path(&dj, path); /* Follow the path */
mikekelly99 0:6db20bbdc767 2941 FREE_BUF();
mikekelly99 0:6db20bbdc767 2942 if (res == FR_OK) { /* Follow completed */
mikekelly99 0:6db20bbdc767 2943 if (!dj.dir) {
mikekelly99 0:6db20bbdc767 2944 dj.fs->cdir = dj.sclust; /* Start directory itself */
mikekelly99 0:6db20bbdc767 2945 } else {
mikekelly99 0:6db20bbdc767 2946 if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
mikekelly99 0:6db20bbdc767 2947 dj.fs->cdir = ld_clust(dj.fs, dj.dir);
mikekelly99 0:6db20bbdc767 2948 else
mikekelly99 0:6db20bbdc767 2949 res = FR_NO_PATH; /* Reached but a file */
mikekelly99 0:6db20bbdc767 2950 }
mikekelly99 0:6db20bbdc767 2951 }
mikekelly99 0:6db20bbdc767 2952 if (res == FR_NO_FILE) res = FR_NO_PATH;
mikekelly99 0:6db20bbdc767 2953 }
mikekelly99 0:6db20bbdc767 2954
mikekelly99 0:6db20bbdc767 2955 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 2956 }
mikekelly99 0:6db20bbdc767 2957
mikekelly99 0:6db20bbdc767 2958
mikekelly99 0:6db20bbdc767 2959 #if _FS_RPATH >= 2
mikekelly99 0:6db20bbdc767 2960 FRESULT f_getcwd (
mikekelly99 0:6db20bbdc767 2961 TCHAR* buff, /* Pointer to the directory path */
mikekelly99 0:6db20bbdc767 2962 UINT len /* Size of path */
mikekelly99 0:6db20bbdc767 2963 )
mikekelly99 0:6db20bbdc767 2964 {
mikekelly99 0:6db20bbdc767 2965 FRESULT res;
mikekelly99 0:6db20bbdc767 2966 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 2967 UINT i, n;
mikekelly99 0:6db20bbdc767 2968 DWORD ccl;
mikekelly99 0:6db20bbdc767 2969 TCHAR *tp;
mikekelly99 0:6db20bbdc767 2970 FILINFO fno;
mikekelly99 0:6db20bbdc767 2971 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 2972
mikekelly99 0:6db20bbdc767 2973
mikekelly99 0:6db20bbdc767 2974 *buff = 0;
mikekelly99 0:6db20bbdc767 2975 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 2976 res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */
mikekelly99 0:6db20bbdc767 2977 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 2978 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 2979 i = len; /* Bottom of buffer (directory stack base) */
mikekelly99 0:6db20bbdc767 2980 dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */
mikekelly99 0:6db20bbdc767 2981 while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */
mikekelly99 0:6db20bbdc767 2982 res = dir_sdi(&dj, 1); /* Get parent directory */
mikekelly99 0:6db20bbdc767 2983 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 2984 res = dir_read(&dj, 0);
mikekelly99 0:6db20bbdc767 2985 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 2986 dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */
mikekelly99 0:6db20bbdc767 2987 res = dir_sdi(&dj, 0);
mikekelly99 0:6db20bbdc767 2988 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 2989 do { /* Find the entry links to the child directory */
mikekelly99 0:6db20bbdc767 2990 res = dir_read(&dj, 0);
mikekelly99 0:6db20bbdc767 2991 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 2992 if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */
mikekelly99 0:6db20bbdc767 2993 res = dir_next(&dj, 0);
mikekelly99 0:6db20bbdc767 2994 } while (res == FR_OK);
mikekelly99 0:6db20bbdc767 2995 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
mikekelly99 0:6db20bbdc767 2996 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 2997 #if _USE_LFN
mikekelly99 0:6db20bbdc767 2998 fno.lfname = buff;
mikekelly99 0:6db20bbdc767 2999 fno.lfsize = i;
mikekelly99 0:6db20bbdc767 3000 #endif
mikekelly99 0:6db20bbdc767 3001 get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */
mikekelly99 0:6db20bbdc767 3002 tp = fno.fname;
mikekelly99 0:6db20bbdc767 3003 #if _USE_LFN
mikekelly99 0:6db20bbdc767 3004 if (*buff) tp = buff;
mikekelly99 0:6db20bbdc767 3005 #endif
mikekelly99 0:6db20bbdc767 3006 for (n = 0; tp[n]; n++) ;
mikekelly99 0:6db20bbdc767 3007 if (i < n + 3) {
mikekelly99 0:6db20bbdc767 3008 res = FR_NOT_ENOUGH_CORE; break;
mikekelly99 0:6db20bbdc767 3009 }
mikekelly99 0:6db20bbdc767 3010 while (n) buff[--i] = tp[--n];
mikekelly99 0:6db20bbdc767 3011 buff[--i] = '/';
mikekelly99 0:6db20bbdc767 3012 }
mikekelly99 0:6db20bbdc767 3013 tp = buff;
mikekelly99 0:6db20bbdc767 3014 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3015 #if _VOLUMES >= 2
mikekelly99 0:6db20bbdc767 3016 *tp++ = '0' + CurrVol; /* Put drive number */
mikekelly99 0:6db20bbdc767 3017 *tp++ = ':';
mikekelly99 0:6db20bbdc767 3018 #endif
mikekelly99 0:6db20bbdc767 3019 if (i == len) { /* Root-directory */
mikekelly99 0:6db20bbdc767 3020 *tp++ = '/';
mikekelly99 0:6db20bbdc767 3021 } else { /* Sub-directroy */
mikekelly99 0:6db20bbdc767 3022 do /* Add stacked path str */
mikekelly99 0:6db20bbdc767 3023 *tp++ = buff[i++];
mikekelly99 0:6db20bbdc767 3024 while (i < len);
mikekelly99 0:6db20bbdc767 3025 }
mikekelly99 0:6db20bbdc767 3026 }
mikekelly99 0:6db20bbdc767 3027 *tp = 0;
mikekelly99 0:6db20bbdc767 3028 FREE_BUF();
mikekelly99 0:6db20bbdc767 3029 }
mikekelly99 0:6db20bbdc767 3030
mikekelly99 0:6db20bbdc767 3031 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3032 }
mikekelly99 0:6db20bbdc767 3033 #endif /* _FS_RPATH >= 2 */
mikekelly99 0:6db20bbdc767 3034 #endif /* _FS_RPATH >= 1 */
mikekelly99 0:6db20bbdc767 3035
mikekelly99 0:6db20bbdc767 3036
mikekelly99 0:6db20bbdc767 3037
mikekelly99 0:6db20bbdc767 3038 #if _FS_MINIMIZE <= 2
mikekelly99 0:6db20bbdc767 3039 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3040 /* Seek File R/W Pointer */
mikekelly99 0:6db20bbdc767 3041 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3042
mikekelly99 0:6db20bbdc767 3043 FRESULT f_lseek (
mikekelly99 0:6db20bbdc767 3044 FIL* fp, /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 3045 DWORD ofs /* File pointer from top of file */
mikekelly99 0:6db20bbdc767 3046 )
mikekelly99 0:6db20bbdc767 3047 {
mikekelly99 0:6db20bbdc767 3048 FRESULT res;
mikekelly99 0:6db20bbdc767 3049 DWORD clst, bcs, nsect, ifptr;
mikekelly99 0:6db20bbdc767 3050 #if _USE_FASTSEEK
mikekelly99 0:6db20bbdc767 3051 DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
mikekelly99 0:6db20bbdc767 3052 #endif
mikekelly99 0:6db20bbdc767 3053
mikekelly99 0:6db20bbdc767 3054
mikekelly99 0:6db20bbdc767 3055 res = validate(fp); /* Check validity of the object */
mikekelly99 0:6db20bbdc767 3056 if (res != FR_OK) LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 3057 if (fp->err) /* Check error */
mikekelly99 0:6db20bbdc767 3058 LEAVE_FF(fp->fs, (FRESULT)fp->err);
mikekelly99 0:6db20bbdc767 3059
mikekelly99 0:6db20bbdc767 3060 #if _USE_FASTSEEK
mikekelly99 0:6db20bbdc767 3061 if (fp->cltbl) { /* Fast seek */
mikekelly99 0:6db20bbdc767 3062 if (ofs == CREATE_LINKMAP) { /* Create CLMT */
mikekelly99 0:6db20bbdc767 3063 tbl = fp->cltbl;
mikekelly99 0:6db20bbdc767 3064 tlen = *tbl++; ulen = 2; /* Given table size and required table size */
mikekelly99 0:6db20bbdc767 3065 cl = fp->sclust; /* Top of the chain */
mikekelly99 0:6db20bbdc767 3066 if (cl) {
mikekelly99 0:6db20bbdc767 3067 do {
mikekelly99 0:6db20bbdc767 3068 /* Get a fragment */
mikekelly99 0:6db20bbdc767 3069 tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */
mikekelly99 0:6db20bbdc767 3070 do {
mikekelly99 0:6db20bbdc767 3071 pcl = cl; ncl++;
mikekelly99 0:6db20bbdc767 3072 cl = get_fat(fp->fs, cl);
mikekelly99 0:6db20bbdc767 3073 if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 3074 if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3075 } while (cl == pcl + 1);
mikekelly99 0:6db20bbdc767 3076 if (ulen <= tlen) { /* Store the length and top of the fragment */
mikekelly99 0:6db20bbdc767 3077 *tbl++ = ncl; *tbl++ = tcl;
mikekelly99 0:6db20bbdc767 3078 }
mikekelly99 0:6db20bbdc767 3079 } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */
mikekelly99 0:6db20bbdc767 3080 }
mikekelly99 0:6db20bbdc767 3081 *fp->cltbl = ulen; /* Number of items used */
mikekelly99 0:6db20bbdc767 3082 if (ulen <= tlen)
mikekelly99 0:6db20bbdc767 3083 *tbl = 0; /* Terminate table */
mikekelly99 0:6db20bbdc767 3084 else
mikekelly99 0:6db20bbdc767 3085 res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
mikekelly99 0:6db20bbdc767 3086
mikekelly99 0:6db20bbdc767 3087 } else { /* Fast seek */
mikekelly99 0:6db20bbdc767 3088 if (ofs > fp->fsize) /* Clip offset at the file size */
mikekelly99 0:6db20bbdc767 3089 ofs = fp->fsize;
mikekelly99 0:6db20bbdc767 3090 fp->fptr = ofs; /* Set file pointer */
mikekelly99 0:6db20bbdc767 3091 if (ofs) {
mikekelly99 0:6db20bbdc767 3092 fp->clust = clmt_clust(fp, ofs - 1);
mikekelly99 0:6db20bbdc767 3093 dsc = clust2sect(fp->fs, fp->clust);
mikekelly99 0:6db20bbdc767 3094 if (!dsc) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 3095 dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
mikekelly99 0:6db20bbdc767 3096 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */
mikekelly99 0:6db20bbdc767 3097 #if !_FS_TINY
mikekelly99 0:6db20bbdc767 3098 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3099 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
mikekelly99 0:6db20bbdc767 3100 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 3101 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3102 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 3103 }
mikekelly99 0:6db20bbdc767 3104 #endif
mikekelly99 0:6db20bbdc767 3105 if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */
mikekelly99 0:6db20bbdc767 3106 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3107 #endif
mikekelly99 0:6db20bbdc767 3108 fp->dsect = dsc;
mikekelly99 0:6db20bbdc767 3109 }
mikekelly99 0:6db20bbdc767 3110 }
mikekelly99 0:6db20bbdc767 3111 }
mikekelly99 0:6db20bbdc767 3112 } else
mikekelly99 0:6db20bbdc767 3113 #endif
mikekelly99 0:6db20bbdc767 3114
mikekelly99 0:6db20bbdc767 3115 /* Normal Seek */
mikekelly99 0:6db20bbdc767 3116 {
mikekelly99 0:6db20bbdc767 3117 if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
mikekelly99 0:6db20bbdc767 3118 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3119 && !(fp->flag & FA_WRITE)
mikekelly99 0:6db20bbdc767 3120 #endif
mikekelly99 0:6db20bbdc767 3121 ) ofs = fp->fsize;
mikekelly99 0:6db20bbdc767 3122
mikekelly99 0:6db20bbdc767 3123 ifptr = fp->fptr;
mikekelly99 0:6db20bbdc767 3124 fp->fptr = nsect = 0;
mikekelly99 0:6db20bbdc767 3125 if (ofs) {
mikekelly99 0:6db20bbdc767 3126 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
mikekelly99 0:6db20bbdc767 3127 if (ifptr > 0 &&
mikekelly99 0:6db20bbdc767 3128 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
mikekelly99 0:6db20bbdc767 3129 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
mikekelly99 0:6db20bbdc767 3130 ofs -= fp->fptr;
mikekelly99 0:6db20bbdc767 3131 clst = fp->clust;
mikekelly99 0:6db20bbdc767 3132 } else { /* When seek to back cluster, */
mikekelly99 0:6db20bbdc767 3133 clst = fp->sclust; /* start from the first cluster */
mikekelly99 0:6db20bbdc767 3134 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3135 if (clst == 0) { /* If no cluster chain, create a new chain */
mikekelly99 0:6db20bbdc767 3136 clst = create_chain(fp->fs, 0);
mikekelly99 0:6db20bbdc767 3137 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 3138 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3139 fp->sclust = clst;
mikekelly99 0:6db20bbdc767 3140 }
mikekelly99 0:6db20bbdc767 3141 #endif
mikekelly99 0:6db20bbdc767 3142 fp->clust = clst;
mikekelly99 0:6db20bbdc767 3143 }
mikekelly99 0:6db20bbdc767 3144 if (clst != 0) {
mikekelly99 0:6db20bbdc767 3145 while (ofs > bcs) { /* Cluster following loop */
mikekelly99 0:6db20bbdc767 3146 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3147 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
mikekelly99 0:6db20bbdc767 3148 clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
mikekelly99 0:6db20bbdc767 3149 if (clst == 0) { /* When disk gets full, clip file size */
mikekelly99 0:6db20bbdc767 3150 ofs = bcs; break;
mikekelly99 0:6db20bbdc767 3151 }
mikekelly99 0:6db20bbdc767 3152 } else
mikekelly99 0:6db20bbdc767 3153 #endif
mikekelly99 0:6db20bbdc767 3154 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
mikekelly99 0:6db20bbdc767 3155 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3156 if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 3157 fp->clust = clst;
mikekelly99 0:6db20bbdc767 3158 fp->fptr += bcs;
mikekelly99 0:6db20bbdc767 3159 ofs -= bcs;
mikekelly99 0:6db20bbdc767 3160 }
mikekelly99 0:6db20bbdc767 3161 fp->fptr += ofs;
mikekelly99 0:6db20bbdc767 3162 if (ofs % SS(fp->fs)) {
mikekelly99 0:6db20bbdc767 3163 nsect = clust2sect(fp->fs, clst); /* Current sector */
mikekelly99 0:6db20bbdc767 3164 if (!nsect) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 3165 nsect += ofs / SS(fp->fs);
mikekelly99 0:6db20bbdc767 3166 }
mikekelly99 0:6db20bbdc767 3167 }
mikekelly99 0:6db20bbdc767 3168 }
mikekelly99 0:6db20bbdc767 3169 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
mikekelly99 0:6db20bbdc767 3170 #if !_FS_TINY
mikekelly99 0:6db20bbdc767 3171 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3172 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
mikekelly99 0:6db20bbdc767 3173 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 3174 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3175 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 3176 }
mikekelly99 0:6db20bbdc767 3177 #endif
mikekelly99 0:6db20bbdc767 3178 if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
mikekelly99 0:6db20bbdc767 3179 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 3180 #endif
mikekelly99 0:6db20bbdc767 3181 fp->dsect = nsect;
mikekelly99 0:6db20bbdc767 3182 }
mikekelly99 0:6db20bbdc767 3183 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3184 if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
mikekelly99 0:6db20bbdc767 3185 fp->fsize = fp->fptr;
mikekelly99 0:6db20bbdc767 3186 fp->flag |= FA__WRITTEN;
mikekelly99 0:6db20bbdc767 3187 }
mikekelly99 0:6db20bbdc767 3188 #endif
mikekelly99 0:6db20bbdc767 3189 }
mikekelly99 0:6db20bbdc767 3190
mikekelly99 0:6db20bbdc767 3191 LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 3192 }
mikekelly99 0:6db20bbdc767 3193
mikekelly99 0:6db20bbdc767 3194
mikekelly99 0:6db20bbdc767 3195
mikekelly99 0:6db20bbdc767 3196 #if _FS_MINIMIZE <= 1
mikekelly99 0:6db20bbdc767 3197 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3198 /* Create a Directory Object */
mikekelly99 0:6db20bbdc767 3199 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3200
mikekelly99 0:6db20bbdc767 3201 FRESULT f_opendir (
mikekelly99 0:6db20bbdc767 3202 FATFS_DIR* dp, /* Pointer to directory object to create */
mikekelly99 0:6db20bbdc767 3203 const TCHAR* path /* Pointer to the directory path */
mikekelly99 0:6db20bbdc767 3204 )
mikekelly99 0:6db20bbdc767 3205 {
mikekelly99 0:6db20bbdc767 3206 FRESULT res;
mikekelly99 0:6db20bbdc767 3207 FATFS* fs;
mikekelly99 0:6db20bbdc767 3208 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3209
mikekelly99 0:6db20bbdc767 3210
mikekelly99 0:6db20bbdc767 3211 if (!dp) return FR_INVALID_OBJECT;
mikekelly99 0:6db20bbdc767 3212
mikekelly99 0:6db20bbdc767 3213 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3214 res = find_volume(&fs, &path, 0);
mikekelly99 0:6db20bbdc767 3215 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3216 dp->fs = fs;
mikekelly99 0:6db20bbdc767 3217 INIT_BUF(*dp);
mikekelly99 0:6db20bbdc767 3218 res = follow_path(dp, path); /* Follow the path to the directory */
mikekelly99 0:6db20bbdc767 3219 FREE_BUF();
mikekelly99 0:6db20bbdc767 3220 if (res == FR_OK) { /* Follow completed */
mikekelly99 0:6db20bbdc767 3221 if (dp->dir) { /* It is not the origin directory itself */
mikekelly99 0:6db20bbdc767 3222 if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */
mikekelly99 0:6db20bbdc767 3223 dp->sclust = ld_clust(fs, dp->dir);
mikekelly99 0:6db20bbdc767 3224 else /* The object is a file */
mikekelly99 0:6db20bbdc767 3225 res = FR_NO_PATH;
mikekelly99 0:6db20bbdc767 3226 }
mikekelly99 0:6db20bbdc767 3227 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3228 dp->id = fs->id;
mikekelly99 0:6db20bbdc767 3229 res = dir_sdi(dp, 0); /* Rewind directory */
mikekelly99 0:6db20bbdc767 3230 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 3231 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3232 if (dp->sclust) {
mikekelly99 0:6db20bbdc767 3233 dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */
mikekelly99 0:6db20bbdc767 3234 if (!dp->lockid)
mikekelly99 0:6db20bbdc767 3235 res = FR_TOO_MANY_OPEN_FILES;
mikekelly99 0:6db20bbdc767 3236 } else {
mikekelly99 0:6db20bbdc767 3237 dp->lockid = 0; /* Root directory need not to be locked */
mikekelly99 0:6db20bbdc767 3238 }
mikekelly99 0:6db20bbdc767 3239 }
mikekelly99 0:6db20bbdc767 3240 #endif
mikekelly99 0:6db20bbdc767 3241 }
mikekelly99 0:6db20bbdc767 3242 }
mikekelly99 0:6db20bbdc767 3243 if (res == FR_NO_FILE) res = FR_NO_PATH;
mikekelly99 0:6db20bbdc767 3244 }
mikekelly99 0:6db20bbdc767 3245 if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */
mikekelly99 0:6db20bbdc767 3246
mikekelly99 0:6db20bbdc767 3247 LEAVE_FF(fs, res);
mikekelly99 0:6db20bbdc767 3248 }
mikekelly99 0:6db20bbdc767 3249
mikekelly99 0:6db20bbdc767 3250
mikekelly99 0:6db20bbdc767 3251
mikekelly99 0:6db20bbdc767 3252
mikekelly99 0:6db20bbdc767 3253 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3254 /* Close Directory */
mikekelly99 0:6db20bbdc767 3255 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3256
mikekelly99 0:6db20bbdc767 3257 FRESULT f_closedir (
mikekelly99 0:6db20bbdc767 3258 FATFS_DIR *dp /* Pointer to the directory object to be closed */
mikekelly99 0:6db20bbdc767 3259 )
mikekelly99 0:6db20bbdc767 3260 {
mikekelly99 0:6db20bbdc767 3261 FRESULT res;
mikekelly99 0:6db20bbdc767 3262
mikekelly99 0:6db20bbdc767 3263
mikekelly99 0:6db20bbdc767 3264 res = validate(dp);
mikekelly99 0:6db20bbdc767 3265 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3266 #if _FS_REENTRANT
mikekelly99 0:6db20bbdc767 3267 FATFS *fs = dp->fs;
mikekelly99 0:6db20bbdc767 3268 #endif
mikekelly99 0:6db20bbdc767 3269 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 3270 if (dp->lockid) /* Decrement sub-directory open counter */
mikekelly99 0:6db20bbdc767 3271 res = dec_lock(dp->lockid);
mikekelly99 0:6db20bbdc767 3272 if (res == FR_OK)
mikekelly99 0:6db20bbdc767 3273 #endif
mikekelly99 0:6db20bbdc767 3274 dp->fs = 0; /* Invalidate directory object */
mikekelly99 0:6db20bbdc767 3275 #if _FS_REENTRANT
mikekelly99 0:6db20bbdc767 3276 unlock_fs(fs, FR_OK); /* Unlock volume */
mikekelly99 0:6db20bbdc767 3277 #endif
mikekelly99 0:6db20bbdc767 3278 }
mikekelly99 0:6db20bbdc767 3279 return res;
mikekelly99 0:6db20bbdc767 3280 }
mikekelly99 0:6db20bbdc767 3281
mikekelly99 0:6db20bbdc767 3282
mikekelly99 0:6db20bbdc767 3283
mikekelly99 0:6db20bbdc767 3284
mikekelly99 0:6db20bbdc767 3285 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3286 /* Read Directory Entries in Sequence */
mikekelly99 0:6db20bbdc767 3287 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3288
mikekelly99 0:6db20bbdc767 3289 FRESULT f_readdir (
mikekelly99 0:6db20bbdc767 3290 FATFS_DIR* dp, /* Pointer to the open directory object */
mikekelly99 0:6db20bbdc767 3291 FILINFO* fno /* Pointer to file information to return */
mikekelly99 0:6db20bbdc767 3292 )
mikekelly99 0:6db20bbdc767 3293 {
mikekelly99 0:6db20bbdc767 3294 FRESULT res;
mikekelly99 0:6db20bbdc767 3295 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3296
mikekelly99 0:6db20bbdc767 3297
mikekelly99 0:6db20bbdc767 3298 res = validate(dp); /* Check validity of the object */
mikekelly99 0:6db20bbdc767 3299 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3300 if (!fno) {
mikekelly99 0:6db20bbdc767 3301 res = dir_sdi(dp, 0); /* Rewind the directory object */
mikekelly99 0:6db20bbdc767 3302 } else {
mikekelly99 0:6db20bbdc767 3303 INIT_BUF(*dp);
mikekelly99 0:6db20bbdc767 3304 res = dir_read(dp, 0); /* Read an item */
mikekelly99 0:6db20bbdc767 3305 if (res == FR_NO_FILE) { /* Reached end of directory */
mikekelly99 0:6db20bbdc767 3306 dp->sect = 0;
mikekelly99 0:6db20bbdc767 3307 res = FR_OK;
mikekelly99 0:6db20bbdc767 3308 }
mikekelly99 0:6db20bbdc767 3309 if (res == FR_OK) { /* A valid entry is found */
mikekelly99 0:6db20bbdc767 3310 get_fileinfo(dp, fno); /* Get the object information */
mikekelly99 0:6db20bbdc767 3311 res = dir_next(dp, 0); /* Increment index for next */
mikekelly99 0:6db20bbdc767 3312 if (res == FR_NO_FILE) {
mikekelly99 0:6db20bbdc767 3313 dp->sect = 0;
mikekelly99 0:6db20bbdc767 3314 res = FR_OK;
mikekelly99 0:6db20bbdc767 3315 }
mikekelly99 0:6db20bbdc767 3316 }
mikekelly99 0:6db20bbdc767 3317 FREE_BUF();
mikekelly99 0:6db20bbdc767 3318 }
mikekelly99 0:6db20bbdc767 3319 }
mikekelly99 0:6db20bbdc767 3320
mikekelly99 0:6db20bbdc767 3321 LEAVE_FF(dp->fs, res);
mikekelly99 0:6db20bbdc767 3322 }
mikekelly99 0:6db20bbdc767 3323
mikekelly99 0:6db20bbdc767 3324
mikekelly99 0:6db20bbdc767 3325
mikekelly99 0:6db20bbdc767 3326 #if _USE_FIND
mikekelly99 0:6db20bbdc767 3327 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3328 /* Find next file */
mikekelly99 0:6db20bbdc767 3329 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3330
mikekelly99 0:6db20bbdc767 3331 FRESULT f_findnext (
mikekelly99 0:6db20bbdc767 3332 FATFS_DIR* dp, /* Pointer to the open directory object */
mikekelly99 0:6db20bbdc767 3333 FILINFO* fno /* Pointer to the file information structure */
mikekelly99 0:6db20bbdc767 3334 )
mikekelly99 0:6db20bbdc767 3335 {
mikekelly99 0:6db20bbdc767 3336 FRESULT res;
mikekelly99 0:6db20bbdc767 3337
mikekelly99 0:6db20bbdc767 3338
mikekelly99 0:6db20bbdc767 3339 for (;;) {
mikekelly99 0:6db20bbdc767 3340 res = f_readdir(dp, fno); /* Get a directory item */
mikekelly99 0:6db20bbdc767 3341 if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */
mikekelly99 0:6db20bbdc767 3342 #if _USE_LFN
mikekelly99 0:6db20bbdc767 3343 if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */
mikekelly99 0:6db20bbdc767 3344 #endif
mikekelly99 0:6db20bbdc767 3345 if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */
mikekelly99 0:6db20bbdc767 3346 }
mikekelly99 0:6db20bbdc767 3347 return res;
mikekelly99 0:6db20bbdc767 3348
mikekelly99 0:6db20bbdc767 3349 }
mikekelly99 0:6db20bbdc767 3350
mikekelly99 0:6db20bbdc767 3351
mikekelly99 0:6db20bbdc767 3352
mikekelly99 0:6db20bbdc767 3353 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3354 /* Find first file */
mikekelly99 0:6db20bbdc767 3355 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3356
mikekelly99 0:6db20bbdc767 3357 FRESULT f_findfirst (
mikekelly99 0:6db20bbdc767 3358 FATFS_DIR* dp, /* Pointer to the blank directory object */
mikekelly99 0:6db20bbdc767 3359 FILINFO* fno, /* Pointer to the file information structure */
mikekelly99 0:6db20bbdc767 3360 const TCHAR* path, /* Pointer to the directory to open */
mikekelly99 0:6db20bbdc767 3361 const TCHAR* pattern /* Pointer to the matching pattern */
mikekelly99 0:6db20bbdc767 3362 )
mikekelly99 0:6db20bbdc767 3363 {
mikekelly99 0:6db20bbdc767 3364 FRESULT res;
mikekelly99 0:6db20bbdc767 3365
mikekelly99 0:6db20bbdc767 3366
mikekelly99 0:6db20bbdc767 3367 dp->pat = pattern; /* Save pointer to pattern string */
mikekelly99 0:6db20bbdc767 3368 res = f_opendir(dp, path); /* Open the target directory */
mikekelly99 0:6db20bbdc767 3369 if (res == FR_OK)
mikekelly99 0:6db20bbdc767 3370 res = f_findnext(dp, fno); /* Find the first item */
mikekelly99 0:6db20bbdc767 3371 return res;
mikekelly99 0:6db20bbdc767 3372 }
mikekelly99 0:6db20bbdc767 3373
mikekelly99 0:6db20bbdc767 3374 #endif /* _USE_FIND */
mikekelly99 0:6db20bbdc767 3375
mikekelly99 0:6db20bbdc767 3376
mikekelly99 0:6db20bbdc767 3377
mikekelly99 0:6db20bbdc767 3378 #if _FS_MINIMIZE == 0
mikekelly99 0:6db20bbdc767 3379 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3380 /* Get File Status */
mikekelly99 0:6db20bbdc767 3381 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3382
mikekelly99 0:6db20bbdc767 3383 FRESULT f_stat (
mikekelly99 0:6db20bbdc767 3384 const TCHAR* path, /* Pointer to the file path */
mikekelly99 0:6db20bbdc767 3385 FILINFO* fno /* Pointer to file information to return */
mikekelly99 0:6db20bbdc767 3386 )
mikekelly99 0:6db20bbdc767 3387 {
mikekelly99 0:6db20bbdc767 3388 FRESULT res;
mikekelly99 0:6db20bbdc767 3389 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 3390 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3391
mikekelly99 0:6db20bbdc767 3392
mikekelly99 0:6db20bbdc767 3393 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3394 res = find_volume(&dj.fs, &path, 0);
mikekelly99 0:6db20bbdc767 3395 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3396 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 3397 res = follow_path(&dj, path); /* Follow the file path */
mikekelly99 0:6db20bbdc767 3398 if (res == FR_OK) { /* Follow completed */
mikekelly99 0:6db20bbdc767 3399 if (dj.dir) { /* Found an object */
mikekelly99 0:6db20bbdc767 3400 if (fno) get_fileinfo(&dj, fno);
mikekelly99 0:6db20bbdc767 3401 } else { /* It is root directory */
mikekelly99 0:6db20bbdc767 3402 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3403 }
mikekelly99 0:6db20bbdc767 3404 }
mikekelly99 0:6db20bbdc767 3405 FREE_BUF();
mikekelly99 0:6db20bbdc767 3406 }
mikekelly99 0:6db20bbdc767 3407
mikekelly99 0:6db20bbdc767 3408 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3409 }
mikekelly99 0:6db20bbdc767 3410
mikekelly99 0:6db20bbdc767 3411
mikekelly99 0:6db20bbdc767 3412
mikekelly99 0:6db20bbdc767 3413 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3414 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3415 /* Get Number of Free Clusters */
mikekelly99 0:6db20bbdc767 3416 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3417
mikekelly99 0:6db20bbdc767 3418 FRESULT f_getfree (
mikekelly99 0:6db20bbdc767 3419 const TCHAR* path, /* Path name of the logical drive number */
mikekelly99 0:6db20bbdc767 3420 DWORD* nclst, /* Pointer to a variable to return number of free clusters */
mikekelly99 0:6db20bbdc767 3421 FATFS** fatfs /* Pointer to return pointer to corresponding file system object */
mikekelly99 0:6db20bbdc767 3422 )
mikekelly99 0:6db20bbdc767 3423 {
mikekelly99 0:6db20bbdc767 3424 FRESULT res;
mikekelly99 0:6db20bbdc767 3425 FATFS *fs;
mikekelly99 0:6db20bbdc767 3426 DWORD nfree, clst, sect, stat;
mikekelly99 0:6db20bbdc767 3427 UINT i;
mikekelly99 0:6db20bbdc767 3428 BYTE fat, *p;
mikekelly99 0:6db20bbdc767 3429
mikekelly99 0:6db20bbdc767 3430
mikekelly99 0:6db20bbdc767 3431 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3432 res = find_volume(fatfs, &path, 0);
mikekelly99 0:6db20bbdc767 3433 fs = *fatfs;
mikekelly99 0:6db20bbdc767 3434 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3435 /* If free_clust is valid, return it without full cluster scan */
mikekelly99 0:6db20bbdc767 3436 if (fs->free_clust <= fs->n_fatent - 2) {
mikekelly99 0:6db20bbdc767 3437 *nclst = fs->free_clust;
mikekelly99 0:6db20bbdc767 3438 } else {
mikekelly99 0:6db20bbdc767 3439 /* Get number of free clusters */
mikekelly99 0:6db20bbdc767 3440 fat = fs->fs_type;
mikekelly99 0:6db20bbdc767 3441 nfree = 0;
mikekelly99 0:6db20bbdc767 3442 if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */
mikekelly99 0:6db20bbdc767 3443 clst = 2;
mikekelly99 0:6db20bbdc767 3444 do {
mikekelly99 0:6db20bbdc767 3445 stat = get_fat(fs, clst);
mikekelly99 0:6db20bbdc767 3446 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
mikekelly99 0:6db20bbdc767 3447 if (stat == 1) { res = FR_INT_ERR; break; }
mikekelly99 0:6db20bbdc767 3448 if (stat == 0) nfree++;
mikekelly99 0:6db20bbdc767 3449 } while (++clst < fs->n_fatent);
mikekelly99 0:6db20bbdc767 3450 } else { /* Sector alighed entries: Accelerate the FAT search. */
mikekelly99 0:6db20bbdc767 3451 clst = fs->n_fatent; sect = fs->fatbase;
mikekelly99 0:6db20bbdc767 3452 i = 0; p = 0;
mikekelly99 0:6db20bbdc767 3453 do {
mikekelly99 0:6db20bbdc767 3454 if (!i) {
mikekelly99 0:6db20bbdc767 3455 res = move_window(fs, sect++);
mikekelly99 0:6db20bbdc767 3456 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 3457 p = fs->win;
mikekelly99 0:6db20bbdc767 3458 i = SS(fs);
mikekelly99 0:6db20bbdc767 3459 }
mikekelly99 0:6db20bbdc767 3460 if (fat == FS_FAT16) {
mikekelly99 0:6db20bbdc767 3461 if (LD_WORD(p) == 0) nfree++;
mikekelly99 0:6db20bbdc767 3462 p += 2; i -= 2;
mikekelly99 0:6db20bbdc767 3463 } else {
mikekelly99 0:6db20bbdc767 3464 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++;
mikekelly99 0:6db20bbdc767 3465 p += 4; i -= 4;
mikekelly99 0:6db20bbdc767 3466 }
mikekelly99 0:6db20bbdc767 3467 } while (--clst);
mikekelly99 0:6db20bbdc767 3468 }
mikekelly99 0:6db20bbdc767 3469 fs->free_clust = nfree; /* free_clust is valid */
mikekelly99 0:6db20bbdc767 3470 fs->fsi_flag |= 1; /* FSInfo is to be updated */
mikekelly99 0:6db20bbdc767 3471 *nclst = nfree; /* Return the free clusters */
mikekelly99 0:6db20bbdc767 3472 }
mikekelly99 0:6db20bbdc767 3473 }
mikekelly99 0:6db20bbdc767 3474 LEAVE_FF(fs, res);
mikekelly99 0:6db20bbdc767 3475 }
mikekelly99 0:6db20bbdc767 3476
mikekelly99 0:6db20bbdc767 3477
mikekelly99 0:6db20bbdc767 3478
mikekelly99 0:6db20bbdc767 3479
mikekelly99 0:6db20bbdc767 3480 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3481 /* Truncate File */
mikekelly99 0:6db20bbdc767 3482 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3483
mikekelly99 0:6db20bbdc767 3484 FRESULT f_truncate (
mikekelly99 0:6db20bbdc767 3485 FIL* fp /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 3486 )
mikekelly99 0:6db20bbdc767 3487 {
mikekelly99 0:6db20bbdc767 3488 FRESULT res;
mikekelly99 0:6db20bbdc767 3489 DWORD ncl;
mikekelly99 0:6db20bbdc767 3490
mikekelly99 0:6db20bbdc767 3491
mikekelly99 0:6db20bbdc767 3492 res = validate(fp); /* Check validity of the object */
mikekelly99 0:6db20bbdc767 3493 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3494 if (fp->err) { /* Check error */
mikekelly99 0:6db20bbdc767 3495 res = (FRESULT)fp->err;
mikekelly99 0:6db20bbdc767 3496 } else {
mikekelly99 0:6db20bbdc767 3497 if (!(fp->flag & FA_WRITE)) /* Check access mode */
mikekelly99 0:6db20bbdc767 3498 res = FR_DENIED;
mikekelly99 0:6db20bbdc767 3499 }
mikekelly99 0:6db20bbdc767 3500 }
mikekelly99 0:6db20bbdc767 3501 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3502 if (fp->fsize > fp->fptr) {
mikekelly99 0:6db20bbdc767 3503 fp->fsize = fp->fptr; /* Set file size to current R/W point */
mikekelly99 0:6db20bbdc767 3504 fp->flag |= FA__WRITTEN;
mikekelly99 0:6db20bbdc767 3505 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
mikekelly99 0:6db20bbdc767 3506 res = remove_chain(fp->fs, fp->sclust);
mikekelly99 0:6db20bbdc767 3507 fp->sclust = 0;
mikekelly99 0:6db20bbdc767 3508 } else { /* When truncate a part of the file, remove remaining clusters */
mikekelly99 0:6db20bbdc767 3509 ncl = get_fat(fp->fs, fp->clust);
mikekelly99 0:6db20bbdc767 3510 res = FR_OK;
mikekelly99 0:6db20bbdc767 3511 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 3512 if (ncl == 1) res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 3513 if (res == FR_OK && ncl < fp->fs->n_fatent) {
mikekelly99 0:6db20bbdc767 3514 res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
mikekelly99 0:6db20bbdc767 3515 if (res == FR_OK) res = remove_chain(fp->fs, ncl);
mikekelly99 0:6db20bbdc767 3516 }
mikekelly99 0:6db20bbdc767 3517 }
mikekelly99 0:6db20bbdc767 3518 #if !_FS_TINY
mikekelly99 0:6db20bbdc767 3519 if (res == FR_OK && (fp->flag & FA__DIRTY)) {
mikekelly99 0:6db20bbdc767 3520 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 3521 res = FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 3522 else
mikekelly99 0:6db20bbdc767 3523 fp->flag &= ~FA__DIRTY;
mikekelly99 0:6db20bbdc767 3524 }
mikekelly99 0:6db20bbdc767 3525 #endif
mikekelly99 0:6db20bbdc767 3526 }
mikekelly99 0:6db20bbdc767 3527 if (res != FR_OK) fp->err = (FRESULT)res;
mikekelly99 0:6db20bbdc767 3528 }
mikekelly99 0:6db20bbdc767 3529
mikekelly99 0:6db20bbdc767 3530 LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 3531 }
mikekelly99 0:6db20bbdc767 3532
mikekelly99 0:6db20bbdc767 3533
mikekelly99 0:6db20bbdc767 3534
mikekelly99 0:6db20bbdc767 3535
mikekelly99 0:6db20bbdc767 3536 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3537 /* Delete a File or Directory */
mikekelly99 0:6db20bbdc767 3538 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3539
mikekelly99 0:6db20bbdc767 3540 FRESULT f_unlink (
mikekelly99 0:6db20bbdc767 3541 const TCHAR* path /* Pointer to the file or directory path */
mikekelly99 0:6db20bbdc767 3542 )
mikekelly99 0:6db20bbdc767 3543 {
mikekelly99 0:6db20bbdc767 3544 FRESULT res;
mikekelly99 0:6db20bbdc767 3545 FATFS_DIR dj, sdj;
mikekelly99 0:6db20bbdc767 3546 BYTE *dir;
mikekelly99 0:6db20bbdc767 3547 DWORD dclst = 0;
mikekelly99 0:6db20bbdc767 3548 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3549
mikekelly99 0:6db20bbdc767 3550
mikekelly99 0:6db20bbdc767 3551 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3552 res = find_volume(&dj.fs, &path, 1);
mikekelly99 0:6db20bbdc767 3553 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3554 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 3555 res = follow_path(&dj, path); /* Follow the file path */
mikekelly99 0:6db20bbdc767 3556 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
mikekelly99 0:6db20bbdc767 3557 res = FR_INVALID_NAME; /* Cannot remove dot entry */
mikekelly99 0:6db20bbdc767 3558 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 3559 if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */
mikekelly99 0:6db20bbdc767 3560 #endif
mikekelly99 0:6db20bbdc767 3561 if (res == FR_OK) { /* The object is accessible */
mikekelly99 0:6db20bbdc767 3562 dir = dj.dir;
mikekelly99 0:6db20bbdc767 3563 if (!dir) {
mikekelly99 0:6db20bbdc767 3564 res = FR_INVALID_NAME; /* Cannot remove the origin directory */
mikekelly99 0:6db20bbdc767 3565 } else {
mikekelly99 0:6db20bbdc767 3566 if (dir[DIR_Attr] & AM_RDO)
mikekelly99 0:6db20bbdc767 3567 res = FR_DENIED; /* Cannot remove R/O object */
mikekelly99 0:6db20bbdc767 3568 }
mikekelly99 0:6db20bbdc767 3569 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3570 dclst = ld_clust(dj.fs, dir);
mikekelly99 0:6db20bbdc767 3571 if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */
mikekelly99 0:6db20bbdc767 3572 #if _FS_RPATH
mikekelly99 0:6db20bbdc767 3573 if (dclst == dj.fs->cdir) { /* Is it the current directory? */
mikekelly99 0:6db20bbdc767 3574 res = FR_DENIED;
mikekelly99 0:6db20bbdc767 3575 } else
mikekelly99 0:6db20bbdc767 3576 #endif
mikekelly99 0:6db20bbdc767 3577 {
mikekelly99 0:6db20bbdc767 3578 mem_cpy(&sdj, &dj, sizeof (FATFS_DIR)); /* Open the sub-directory */
mikekelly99 0:6db20bbdc767 3579 sdj.sclust = dclst;
mikekelly99 0:6db20bbdc767 3580 res = dir_sdi(&sdj, 2);
mikekelly99 0:6db20bbdc767 3581 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3582 res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */
mikekelly99 0:6db20bbdc767 3583 if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */
mikekelly99 0:6db20bbdc767 3584 if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */
mikekelly99 0:6db20bbdc767 3585 }
mikekelly99 0:6db20bbdc767 3586 }
mikekelly99 0:6db20bbdc767 3587 }
mikekelly99 0:6db20bbdc767 3588 }
mikekelly99 0:6db20bbdc767 3589 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3590 res = dir_remove(&dj); /* Remove the directory entry */
mikekelly99 0:6db20bbdc767 3591 if (res == FR_OK && dclst) /* Remove the cluster chain if exist */
mikekelly99 0:6db20bbdc767 3592 res = remove_chain(dj.fs, dclst);
mikekelly99 0:6db20bbdc767 3593 if (res == FR_OK) res = sync_fs(dj.fs);
mikekelly99 0:6db20bbdc767 3594 }
mikekelly99 0:6db20bbdc767 3595 }
mikekelly99 0:6db20bbdc767 3596 FREE_BUF();
mikekelly99 0:6db20bbdc767 3597 }
mikekelly99 0:6db20bbdc767 3598
mikekelly99 0:6db20bbdc767 3599 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3600 }
mikekelly99 0:6db20bbdc767 3601
mikekelly99 0:6db20bbdc767 3602
mikekelly99 0:6db20bbdc767 3603
mikekelly99 0:6db20bbdc767 3604
mikekelly99 0:6db20bbdc767 3605 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3606 /* Create a Directory */
mikekelly99 0:6db20bbdc767 3607 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3608
mikekelly99 0:6db20bbdc767 3609 FRESULT f_mkdir (
mikekelly99 0:6db20bbdc767 3610 const TCHAR* path /* Pointer to the directory path */
mikekelly99 0:6db20bbdc767 3611 )
mikekelly99 0:6db20bbdc767 3612 {
mikekelly99 0:6db20bbdc767 3613 FRESULT res;
mikekelly99 0:6db20bbdc767 3614 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 3615 BYTE *dir, n;
mikekelly99 0:6db20bbdc767 3616 DWORD dsc, dcl, pcl, tm = GET_FATTIME();
mikekelly99 0:6db20bbdc767 3617 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3618
mikekelly99 0:6db20bbdc767 3619
mikekelly99 0:6db20bbdc767 3620 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3621 res = find_volume(&dj.fs, &path, 1);
mikekelly99 0:6db20bbdc767 3622 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3623 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 3624 res = follow_path(&dj, path); /* Follow the file path */
mikekelly99 0:6db20bbdc767 3625 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
mikekelly99 0:6db20bbdc767 3626 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT))
mikekelly99 0:6db20bbdc767 3627 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3628 if (res == FR_NO_FILE) { /* Can create a new directory */
mikekelly99 0:6db20bbdc767 3629 dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
mikekelly99 0:6db20bbdc767 3630 res = FR_OK;
mikekelly99 0:6db20bbdc767 3631 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
mikekelly99 0:6db20bbdc767 3632 if (dcl == 1) res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 3633 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 3634 if (res == FR_OK) /* Flush FAT */
mikekelly99 0:6db20bbdc767 3635 res = sync_window(dj.fs);
mikekelly99 0:6db20bbdc767 3636 if (res == FR_OK) { /* Initialize the new directory table */
mikekelly99 0:6db20bbdc767 3637 dsc = clust2sect(dj.fs, dcl);
mikekelly99 0:6db20bbdc767 3638 dir = dj.fs->win;
mikekelly99 0:6db20bbdc767 3639 mem_set(dir, 0, SS(dj.fs));
mikekelly99 0:6db20bbdc767 3640 mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
mikekelly99 0:6db20bbdc767 3641 dir[DIR_Name] = '.';
mikekelly99 0:6db20bbdc767 3642 dir[DIR_Attr] = AM_DIR;
mikekelly99 0:6db20bbdc767 3643 ST_DWORD(dir + DIR_WrtTime, tm);
mikekelly99 0:6db20bbdc767 3644 st_clust(dir, dcl);
mikekelly99 0:6db20bbdc767 3645 mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */
mikekelly99 0:6db20bbdc767 3646 dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust;
mikekelly99 0:6db20bbdc767 3647 if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
mikekelly99 0:6db20bbdc767 3648 pcl = 0;
mikekelly99 0:6db20bbdc767 3649 st_clust(dir + SZ_DIRE, pcl);
mikekelly99 0:6db20bbdc767 3650 for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
mikekelly99 0:6db20bbdc767 3651 dj.fs->winsect = dsc++;
mikekelly99 0:6db20bbdc767 3652 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3653 res = sync_window(dj.fs);
mikekelly99 0:6db20bbdc767 3654 if (res != FR_OK) break;
mikekelly99 0:6db20bbdc767 3655 mem_set(dir, 0, SS(dj.fs));
mikekelly99 0:6db20bbdc767 3656 }
mikekelly99 0:6db20bbdc767 3657 }
mikekelly99 0:6db20bbdc767 3658 if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
mikekelly99 0:6db20bbdc767 3659 if (res != FR_OK) {
mikekelly99 0:6db20bbdc767 3660 remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
mikekelly99 0:6db20bbdc767 3661 } else {
mikekelly99 0:6db20bbdc767 3662 dir = dj.dir;
mikekelly99 0:6db20bbdc767 3663 dir[DIR_Attr] = AM_DIR; /* Attribute */
mikekelly99 0:6db20bbdc767 3664 ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */
mikekelly99 0:6db20bbdc767 3665 st_clust(dir, dcl); /* Table start cluster */
mikekelly99 0:6db20bbdc767 3666 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3667 res = sync_fs(dj.fs);
mikekelly99 0:6db20bbdc767 3668 }
mikekelly99 0:6db20bbdc767 3669 }
mikekelly99 0:6db20bbdc767 3670 FREE_BUF();
mikekelly99 0:6db20bbdc767 3671 }
mikekelly99 0:6db20bbdc767 3672
mikekelly99 0:6db20bbdc767 3673 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3674 }
mikekelly99 0:6db20bbdc767 3675
mikekelly99 0:6db20bbdc767 3676
mikekelly99 0:6db20bbdc767 3677
mikekelly99 0:6db20bbdc767 3678
mikekelly99 0:6db20bbdc767 3679 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3680 /* Change Attribute */
mikekelly99 0:6db20bbdc767 3681 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3682
mikekelly99 0:6db20bbdc767 3683 FRESULT f_chmod (
mikekelly99 0:6db20bbdc767 3684 const TCHAR* path, /* Pointer to the file path */
mikekelly99 0:6db20bbdc767 3685 BYTE attr, /* Attribute bits */
mikekelly99 0:6db20bbdc767 3686 BYTE mask /* Attribute mask to change */
mikekelly99 0:6db20bbdc767 3687 )
mikekelly99 0:6db20bbdc767 3688 {
mikekelly99 0:6db20bbdc767 3689 FRESULT res;
mikekelly99 0:6db20bbdc767 3690 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 3691 BYTE *dir;
mikekelly99 0:6db20bbdc767 3692 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3693
mikekelly99 0:6db20bbdc767 3694
mikekelly99 0:6db20bbdc767 3695 res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3696 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3697 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 3698 res = follow_path(&dj, path); /* Follow the file path */
mikekelly99 0:6db20bbdc767 3699 FREE_BUF();
mikekelly99 0:6db20bbdc767 3700 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
mikekelly99 0:6db20bbdc767 3701 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3702 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3703 dir = dj.dir;
mikekelly99 0:6db20bbdc767 3704 if (!dir) { /* Is it a root directory? */
mikekelly99 0:6db20bbdc767 3705 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3706 } else { /* File or sub directory */
mikekelly99 0:6db20bbdc767 3707 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
mikekelly99 0:6db20bbdc767 3708 dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
mikekelly99 0:6db20bbdc767 3709 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3710 res = sync_fs(dj.fs);
mikekelly99 0:6db20bbdc767 3711 }
mikekelly99 0:6db20bbdc767 3712 }
mikekelly99 0:6db20bbdc767 3713 }
mikekelly99 0:6db20bbdc767 3714
mikekelly99 0:6db20bbdc767 3715 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3716 }
mikekelly99 0:6db20bbdc767 3717
mikekelly99 0:6db20bbdc767 3718
mikekelly99 0:6db20bbdc767 3719
mikekelly99 0:6db20bbdc767 3720
mikekelly99 0:6db20bbdc767 3721 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3722 /* Rename File/Directory */
mikekelly99 0:6db20bbdc767 3723 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3724
mikekelly99 0:6db20bbdc767 3725 FRESULT f_rename (
mikekelly99 0:6db20bbdc767 3726 const TCHAR* path_old, /* Pointer to the object to be renamed */
mikekelly99 0:6db20bbdc767 3727 const TCHAR* path_new /* Pointer to the new name */
mikekelly99 0:6db20bbdc767 3728 )
mikekelly99 0:6db20bbdc767 3729 {
mikekelly99 0:6db20bbdc767 3730 FRESULT res;
mikekelly99 0:6db20bbdc767 3731 FATFS_DIR djo, djn;
mikekelly99 0:6db20bbdc767 3732 BYTE buf[21], *dir;
mikekelly99 0:6db20bbdc767 3733 DWORD dw;
mikekelly99 0:6db20bbdc767 3734 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3735
mikekelly99 0:6db20bbdc767 3736
mikekelly99 0:6db20bbdc767 3737 /* Get logical drive number of the source object */
mikekelly99 0:6db20bbdc767 3738 res = find_volume(&djo.fs, &path_old, 1);
mikekelly99 0:6db20bbdc767 3739 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3740 djn.fs = djo.fs;
mikekelly99 0:6db20bbdc767 3741 INIT_BUF(djo);
mikekelly99 0:6db20bbdc767 3742 res = follow_path(&djo, path_old); /* Check old object */
mikekelly99 0:6db20bbdc767 3743 if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT))
mikekelly99 0:6db20bbdc767 3744 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3745 #if _FS_LOCK
mikekelly99 0:6db20bbdc767 3746 if (res == FR_OK) res = chk_lock(&djo, 2);
mikekelly99 0:6db20bbdc767 3747 #endif
mikekelly99 0:6db20bbdc767 3748 if (res == FR_OK) { /* Old object is found */
mikekelly99 0:6db20bbdc767 3749 if (!djo.dir) { /* Is root dir? */
mikekelly99 0:6db20bbdc767 3750 res = FR_NO_FILE;
mikekelly99 0:6db20bbdc767 3751 } else {
mikekelly99 0:6db20bbdc767 3752 mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */
mikekelly99 0:6db20bbdc767 3753 mem_cpy(&djn, &djo, sizeof (FATFS_DIR)); /* Duplicate the directory object */
mikekelly99 0:6db20bbdc767 3754 if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */
mikekelly99 0:6db20bbdc767 3755 res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */
mikekelly99 0:6db20bbdc767 3756 else
mikekelly99 0:6db20bbdc767 3757 res = FR_INVALID_DRIVE;
mikekelly99 0:6db20bbdc767 3758 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
mikekelly99 0:6db20bbdc767 3759 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
mikekelly99 0:6db20bbdc767 3760 res = dir_register(&djn); /* Register the new entry */
mikekelly99 0:6db20bbdc767 3761 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3762 /* Start of critical section where any interruption can cause a cross-link */
mikekelly99 0:6db20bbdc767 3763 dir = djn.dir; /* Copy information about object except name */
mikekelly99 0:6db20bbdc767 3764 mem_cpy(dir + 13, buf + 2, 19);
mikekelly99 0:6db20bbdc767 3765 dir[DIR_Attr] = buf[0] | AM_ARC;
mikekelly99 0:6db20bbdc767 3766 djo.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3767 if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */
mikekelly99 0:6db20bbdc767 3768 dw = clust2sect(djo.fs, ld_clust(djo.fs, dir));
mikekelly99 0:6db20bbdc767 3769 if (!dw) {
mikekelly99 0:6db20bbdc767 3770 res = FR_INT_ERR;
mikekelly99 0:6db20bbdc767 3771 } else {
mikekelly99 0:6db20bbdc767 3772 res = move_window(djo.fs, dw);
mikekelly99 0:6db20bbdc767 3773 dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */
mikekelly99 0:6db20bbdc767 3774 if (res == FR_OK && dir[1] == '.') {
mikekelly99 0:6db20bbdc767 3775 st_clust(dir, djn.sclust);
mikekelly99 0:6db20bbdc767 3776 djo.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3777 }
mikekelly99 0:6db20bbdc767 3778 }
mikekelly99 0:6db20bbdc767 3779 }
mikekelly99 0:6db20bbdc767 3780 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3781 res = dir_remove(&djo); /* Remove old entry */
mikekelly99 0:6db20bbdc767 3782 if (res == FR_OK)
mikekelly99 0:6db20bbdc767 3783 res = sync_fs(djo.fs);
mikekelly99 0:6db20bbdc767 3784 }
mikekelly99 0:6db20bbdc767 3785 /* End of critical section */
mikekelly99 0:6db20bbdc767 3786 }
mikekelly99 0:6db20bbdc767 3787 }
mikekelly99 0:6db20bbdc767 3788 }
mikekelly99 0:6db20bbdc767 3789 }
mikekelly99 0:6db20bbdc767 3790 FREE_BUF();
mikekelly99 0:6db20bbdc767 3791 }
mikekelly99 0:6db20bbdc767 3792
mikekelly99 0:6db20bbdc767 3793 LEAVE_FF(djo.fs, res);
mikekelly99 0:6db20bbdc767 3794 }
mikekelly99 0:6db20bbdc767 3795
mikekelly99 0:6db20bbdc767 3796
mikekelly99 0:6db20bbdc767 3797
mikekelly99 0:6db20bbdc767 3798
mikekelly99 0:6db20bbdc767 3799 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3800 /* Change Timestamp */
mikekelly99 0:6db20bbdc767 3801 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3802
mikekelly99 0:6db20bbdc767 3803 FRESULT f_utime (
mikekelly99 0:6db20bbdc767 3804 const TCHAR* path, /* Pointer to the file/directory name */
mikekelly99 0:6db20bbdc767 3805 const FILINFO* fno /* Pointer to the time stamp to be set */
mikekelly99 0:6db20bbdc767 3806 )
mikekelly99 0:6db20bbdc767 3807 {
mikekelly99 0:6db20bbdc767 3808 FRESULT res;
mikekelly99 0:6db20bbdc767 3809 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 3810 BYTE *dir;
mikekelly99 0:6db20bbdc767 3811 DEFINE_NAMEBUF;
mikekelly99 0:6db20bbdc767 3812
mikekelly99 0:6db20bbdc767 3813
mikekelly99 0:6db20bbdc767 3814 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3815 res = find_volume(&dj.fs, &path, 1);
mikekelly99 0:6db20bbdc767 3816 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3817 INIT_BUF(dj);
mikekelly99 0:6db20bbdc767 3818 res = follow_path(&dj, path); /* Follow the file path */
mikekelly99 0:6db20bbdc767 3819 FREE_BUF();
mikekelly99 0:6db20bbdc767 3820 if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
mikekelly99 0:6db20bbdc767 3821 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3822 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3823 dir = dj.dir;
mikekelly99 0:6db20bbdc767 3824 if (!dir) { /* Root directory */
mikekelly99 0:6db20bbdc767 3825 res = FR_INVALID_NAME;
mikekelly99 0:6db20bbdc767 3826 } else { /* File or sub-directory */
mikekelly99 0:6db20bbdc767 3827 ST_WORD(dir + DIR_WrtTime, fno->ftime);
mikekelly99 0:6db20bbdc767 3828 ST_WORD(dir + DIR_WrtDate, fno->fdate);
mikekelly99 0:6db20bbdc767 3829 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3830 res = sync_fs(dj.fs);
mikekelly99 0:6db20bbdc767 3831 }
mikekelly99 0:6db20bbdc767 3832 }
mikekelly99 0:6db20bbdc767 3833 }
mikekelly99 0:6db20bbdc767 3834
mikekelly99 0:6db20bbdc767 3835 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3836 }
mikekelly99 0:6db20bbdc767 3837
mikekelly99 0:6db20bbdc767 3838 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 3839 #endif /* _FS_MINIMIZE == 0 */
mikekelly99 0:6db20bbdc767 3840 #endif /* _FS_MINIMIZE <= 1 */
mikekelly99 0:6db20bbdc767 3841 #endif /* _FS_MINIMIZE <= 2 */
mikekelly99 0:6db20bbdc767 3842
mikekelly99 0:6db20bbdc767 3843
mikekelly99 0:6db20bbdc767 3844
mikekelly99 0:6db20bbdc767 3845
mikekelly99 0:6db20bbdc767 3846 #if _USE_LABEL
mikekelly99 0:6db20bbdc767 3847 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3848 /* Get volume label */
mikekelly99 0:6db20bbdc767 3849 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3850
mikekelly99 0:6db20bbdc767 3851 FRESULT f_getlabel (
mikekelly99 0:6db20bbdc767 3852 const TCHAR* path, /* Path name of the logical drive number */
mikekelly99 0:6db20bbdc767 3853 TCHAR* label, /* Pointer to a buffer to return the volume label */
mikekelly99 0:6db20bbdc767 3854 DWORD* vsn /* Pointer to a variable to return the volume serial number */
mikekelly99 0:6db20bbdc767 3855 )
mikekelly99 0:6db20bbdc767 3856 {
mikekelly99 0:6db20bbdc767 3857 FRESULT res;
mikekelly99 0:6db20bbdc767 3858 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 3859 UINT i, j;
mikekelly99 0:6db20bbdc767 3860 #if _USE_LFN && _LFN_UNICODE
mikekelly99 0:6db20bbdc767 3861 WCHAR w;
mikekelly99 0:6db20bbdc767 3862 #endif
mikekelly99 0:6db20bbdc767 3863
mikekelly99 0:6db20bbdc767 3864
mikekelly99 0:6db20bbdc767 3865 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3866 res = find_volume(&dj.fs, &path, 0);
mikekelly99 0:6db20bbdc767 3867
mikekelly99 0:6db20bbdc767 3868 /* Get volume label */
mikekelly99 0:6db20bbdc767 3869 if (res == FR_OK && label) {
mikekelly99 0:6db20bbdc767 3870 dj.sclust = 0; /* Open root directory */
mikekelly99 0:6db20bbdc767 3871 res = dir_sdi(&dj, 0);
mikekelly99 0:6db20bbdc767 3872 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3873 res = dir_read(&dj, 1); /* Get an entry with AM_VOL */
mikekelly99 0:6db20bbdc767 3874 if (res == FR_OK) { /* A volume label is exist */
mikekelly99 0:6db20bbdc767 3875 #if _USE_LFN && _LFN_UNICODE
mikekelly99 0:6db20bbdc767 3876 i = j = 0;
mikekelly99 0:6db20bbdc767 3877 do {
mikekelly99 0:6db20bbdc767 3878 w = (i < 11) ? dj.dir[i++] : ' ';
mikekelly99 0:6db20bbdc767 3879 if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i]))
mikekelly99 0:6db20bbdc767 3880 w = w << 8 | dj.dir[i++];
mikekelly99 0:6db20bbdc767 3881 label[j++] = ff_convert(w, 1); /* OEM -> Unicode */
mikekelly99 0:6db20bbdc767 3882 } while (j < 11);
mikekelly99 0:6db20bbdc767 3883 #else
mikekelly99 0:6db20bbdc767 3884 mem_cpy(label, dj.dir, 11);
mikekelly99 0:6db20bbdc767 3885 #endif
mikekelly99 0:6db20bbdc767 3886 j = 11;
mikekelly99 0:6db20bbdc767 3887 do {
mikekelly99 0:6db20bbdc767 3888 label[j] = 0;
mikekelly99 0:6db20bbdc767 3889 if (!j) break;
mikekelly99 0:6db20bbdc767 3890 } while (label[--j] == ' ');
mikekelly99 0:6db20bbdc767 3891 }
mikekelly99 0:6db20bbdc767 3892 if (res == FR_NO_FILE) { /* No label, return nul string */
mikekelly99 0:6db20bbdc767 3893 label[0] = 0;
mikekelly99 0:6db20bbdc767 3894 res = FR_OK;
mikekelly99 0:6db20bbdc767 3895 }
mikekelly99 0:6db20bbdc767 3896 }
mikekelly99 0:6db20bbdc767 3897 }
mikekelly99 0:6db20bbdc767 3898
mikekelly99 0:6db20bbdc767 3899 /* Get volume serial number */
mikekelly99 0:6db20bbdc767 3900 if (res == FR_OK && vsn) {
mikekelly99 0:6db20bbdc767 3901 res = move_window(dj.fs, dj.fs->volbase);
mikekelly99 0:6db20bbdc767 3902 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3903 i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID;
mikekelly99 0:6db20bbdc767 3904 *vsn = LD_DWORD(&dj.fs->win[i]);
mikekelly99 0:6db20bbdc767 3905 }
mikekelly99 0:6db20bbdc767 3906 }
mikekelly99 0:6db20bbdc767 3907
mikekelly99 0:6db20bbdc767 3908 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3909 }
mikekelly99 0:6db20bbdc767 3910
mikekelly99 0:6db20bbdc767 3911
mikekelly99 0:6db20bbdc767 3912
mikekelly99 0:6db20bbdc767 3913 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 3914 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3915 /* Set volume label */
mikekelly99 0:6db20bbdc767 3916 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 3917
mikekelly99 0:6db20bbdc767 3918 FRESULT f_setlabel (
mikekelly99 0:6db20bbdc767 3919 const TCHAR* label /* Pointer to the volume label to set */
mikekelly99 0:6db20bbdc767 3920 )
mikekelly99 0:6db20bbdc767 3921 {
mikekelly99 0:6db20bbdc767 3922 FRESULT res;
mikekelly99 0:6db20bbdc767 3923 FATFS_DIR dj;
mikekelly99 0:6db20bbdc767 3924 BYTE vn[11];
mikekelly99 0:6db20bbdc767 3925 UINT i, j, sl;
mikekelly99 0:6db20bbdc767 3926 WCHAR w;
mikekelly99 0:6db20bbdc767 3927 DWORD tm;
mikekelly99 0:6db20bbdc767 3928
mikekelly99 0:6db20bbdc767 3929
mikekelly99 0:6db20bbdc767 3930 /* Get logical drive number */
mikekelly99 0:6db20bbdc767 3931 res = find_volume(&dj.fs, &label, 1);
mikekelly99 0:6db20bbdc767 3932 if (res) LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 3933
mikekelly99 0:6db20bbdc767 3934 /* Create a volume label in directory form */
mikekelly99 0:6db20bbdc767 3935 vn[0] = 0;
mikekelly99 0:6db20bbdc767 3936 for (sl = 0; label[sl]; sl++) ; /* Get name length */
mikekelly99 0:6db20bbdc767 3937 for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */
mikekelly99 0:6db20bbdc767 3938 if (sl) { /* Create volume label in directory form */
mikekelly99 0:6db20bbdc767 3939 i = j = 0;
mikekelly99 0:6db20bbdc767 3940 do {
mikekelly99 0:6db20bbdc767 3941 #if _USE_LFN && _LFN_UNICODE
mikekelly99 0:6db20bbdc767 3942 w = ff_convert(ff_wtoupper(label[i++]), 0);
mikekelly99 0:6db20bbdc767 3943 #else
mikekelly99 0:6db20bbdc767 3944 w = (BYTE)label[i++];
mikekelly99 0:6db20bbdc767 3945 if (IsDBCS1(w))
mikekelly99 0:6db20bbdc767 3946 w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;
mikekelly99 0:6db20bbdc767 3947 #if _USE_LFN
mikekelly99 0:6db20bbdc767 3948 w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0);
mikekelly99 0:6db20bbdc767 3949 #else
mikekelly99 0:6db20bbdc767 3950 if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */
mikekelly99 0:6db20bbdc767 3951 #ifdef _EXCVT
mikekelly99 0:6db20bbdc767 3952 if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */
mikekelly99 0:6db20bbdc767 3953 #else
mikekelly99 0:6db20bbdc767 3954 if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */
mikekelly99 0:6db20bbdc767 3955 #endif
mikekelly99 0:6db20bbdc767 3956 #endif
mikekelly99 0:6db20bbdc767 3957 #endif
mikekelly99 0:6db20bbdc767 3958 if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */
mikekelly99 0:6db20bbdc767 3959 LEAVE_FF(dj.fs, FR_INVALID_NAME);
mikekelly99 0:6db20bbdc767 3960 if (w >= 0x100) vn[j++] = (BYTE)(w >> 8);
mikekelly99 0:6db20bbdc767 3961 vn[j++] = (BYTE)w;
mikekelly99 0:6db20bbdc767 3962 } while (i < sl);
mikekelly99 0:6db20bbdc767 3963 while (j < 11) vn[j++] = ' '; /* Fill remaining name field */
mikekelly99 0:6db20bbdc767 3964 if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */
mikekelly99 0:6db20bbdc767 3965 }
mikekelly99 0:6db20bbdc767 3966
mikekelly99 0:6db20bbdc767 3967 /* Set volume label */
mikekelly99 0:6db20bbdc767 3968 dj.sclust = 0; /* Open root directory */
mikekelly99 0:6db20bbdc767 3969 res = dir_sdi(&dj, 0);
mikekelly99 0:6db20bbdc767 3970 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3971 res = dir_read(&dj, 1); /* Get an entry with AM_VOL */
mikekelly99 0:6db20bbdc767 3972 if (res == FR_OK) { /* A volume label is found */
mikekelly99 0:6db20bbdc767 3973 if (vn[0]) {
mikekelly99 0:6db20bbdc767 3974 mem_cpy(dj.dir, vn, 11); /* Change the volume label name */
mikekelly99 0:6db20bbdc767 3975 tm = GET_FATTIME();
mikekelly99 0:6db20bbdc767 3976 ST_DWORD(dj.dir + DIR_WrtTime, tm);
mikekelly99 0:6db20bbdc767 3977 } else {
mikekelly99 0:6db20bbdc767 3978 dj.dir[0] = DDEM; /* Remove the volume label */
mikekelly99 0:6db20bbdc767 3979 }
mikekelly99 0:6db20bbdc767 3980 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3981 res = sync_fs(dj.fs);
mikekelly99 0:6db20bbdc767 3982 } else { /* No volume label is found or error */
mikekelly99 0:6db20bbdc767 3983 if (res == FR_NO_FILE) {
mikekelly99 0:6db20bbdc767 3984 res = FR_OK;
mikekelly99 0:6db20bbdc767 3985 if (vn[0]) { /* Create volume label as new */
mikekelly99 0:6db20bbdc767 3986 res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */
mikekelly99 0:6db20bbdc767 3987 if (res == FR_OK) {
mikekelly99 0:6db20bbdc767 3988 mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */
mikekelly99 0:6db20bbdc767 3989 mem_cpy(dj.dir, vn, 11);
mikekelly99 0:6db20bbdc767 3990 dj.dir[DIR_Attr] = AM_VOL;
mikekelly99 0:6db20bbdc767 3991 tm = GET_FATTIME();
mikekelly99 0:6db20bbdc767 3992 ST_DWORD(dj.dir + DIR_WrtTime, tm);
mikekelly99 0:6db20bbdc767 3993 dj.fs->wflag = 1;
mikekelly99 0:6db20bbdc767 3994 res = sync_fs(dj.fs);
mikekelly99 0:6db20bbdc767 3995 }
mikekelly99 0:6db20bbdc767 3996 }
mikekelly99 0:6db20bbdc767 3997 }
mikekelly99 0:6db20bbdc767 3998 }
mikekelly99 0:6db20bbdc767 3999 }
mikekelly99 0:6db20bbdc767 4000
mikekelly99 0:6db20bbdc767 4001 LEAVE_FF(dj.fs, res);
mikekelly99 0:6db20bbdc767 4002 }
mikekelly99 0:6db20bbdc767 4003
mikekelly99 0:6db20bbdc767 4004 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 4005 #endif /* _USE_LABEL */
mikekelly99 0:6db20bbdc767 4006
mikekelly99 0:6db20bbdc767 4007
mikekelly99 0:6db20bbdc767 4008
mikekelly99 0:6db20bbdc767 4009 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4010 /* Forward data to the stream directly (available on only tiny cfg) */
mikekelly99 0:6db20bbdc767 4011 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4012 #if _USE_FORWARD && _FS_TINY
mikekelly99 0:6db20bbdc767 4013
mikekelly99 0:6db20bbdc767 4014 FRESULT f_forward (
mikekelly99 0:6db20bbdc767 4015 FIL* fp, /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 4016 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
mikekelly99 0:6db20bbdc767 4017 UINT btf, /* Number of bytes to forward */
mikekelly99 0:6db20bbdc767 4018 UINT* bf /* Pointer to number of bytes forwarded */
mikekelly99 0:6db20bbdc767 4019 )
mikekelly99 0:6db20bbdc767 4020 {
mikekelly99 0:6db20bbdc767 4021 FRESULT res;
mikekelly99 0:6db20bbdc767 4022 DWORD remain, clst, sect;
mikekelly99 0:6db20bbdc767 4023 UINT rcnt;
mikekelly99 0:6db20bbdc767 4024 BYTE csect;
mikekelly99 0:6db20bbdc767 4025
mikekelly99 0:6db20bbdc767 4026
mikekelly99 0:6db20bbdc767 4027 *bf = 0; /* Clear transfer byte counter */
mikekelly99 0:6db20bbdc767 4028
mikekelly99 0:6db20bbdc767 4029 res = validate(fp); /* Check validity of the object */
mikekelly99 0:6db20bbdc767 4030 if (res != FR_OK) LEAVE_FF(fp->fs, res);
mikekelly99 0:6db20bbdc767 4031 if (fp->err) /* Check error */
mikekelly99 0:6db20bbdc767 4032 LEAVE_FF(fp->fs, (FRESULT)fp->err);
mikekelly99 0:6db20bbdc767 4033 if (!(fp->flag & FA_READ)) /* Check access mode */
mikekelly99 0:6db20bbdc767 4034 LEAVE_FF(fp->fs, FR_DENIED);
mikekelly99 0:6db20bbdc767 4035
mikekelly99 0:6db20bbdc767 4036 remain = fp->fsize - fp->fptr;
mikekelly99 0:6db20bbdc767 4037 if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */
mikekelly99 0:6db20bbdc767 4038
mikekelly99 0:6db20bbdc767 4039 for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
mikekelly99 0:6db20bbdc767 4040 fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {
mikekelly99 0:6db20bbdc767 4041 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
mikekelly99 0:6db20bbdc767 4042 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
mikekelly99 0:6db20bbdc767 4043 if (!csect) { /* On the cluster boundary? */
mikekelly99 0:6db20bbdc767 4044 clst = (fp->fptr == 0) ? /* On the top of the file? */
mikekelly99 0:6db20bbdc767 4045 fp->sclust : get_fat(fp->fs, fp->clust);
mikekelly99 0:6db20bbdc767 4046 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 4047 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 4048 fp->clust = clst; /* Update current cluster */
mikekelly99 0:6db20bbdc767 4049 }
mikekelly99 0:6db20bbdc767 4050 }
mikekelly99 0:6db20bbdc767 4051 sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */
mikekelly99 0:6db20bbdc767 4052 if (!sect) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 4053 sect += csect;
mikekelly99 0:6db20bbdc767 4054 if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */
mikekelly99 0:6db20bbdc767 4055 ABORT(fp->fs, FR_DISK_ERR);
mikekelly99 0:6db20bbdc767 4056 fp->dsect = sect;
mikekelly99 0:6db20bbdc767 4057 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
mikekelly99 0:6db20bbdc767 4058 if (rcnt > btf) rcnt = btf;
mikekelly99 0:6db20bbdc767 4059 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
mikekelly99 0:6db20bbdc767 4060 if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
mikekelly99 0:6db20bbdc767 4061 }
mikekelly99 0:6db20bbdc767 4062
mikekelly99 0:6db20bbdc767 4063 LEAVE_FF(fp->fs, FR_OK);
mikekelly99 0:6db20bbdc767 4064 }
mikekelly99 0:6db20bbdc767 4065 #endif /* _USE_FORWARD */
mikekelly99 0:6db20bbdc767 4066
mikekelly99 0:6db20bbdc767 4067
mikekelly99 0:6db20bbdc767 4068
mikekelly99 0:6db20bbdc767 4069 #if _USE_MKFS && !_FS_READONLY
mikekelly99 0:6db20bbdc767 4070 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4071 /* Create file system on the logical drive */
mikekelly99 0:6db20bbdc767 4072 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4073 #define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */
mikekelly99 0:6db20bbdc767 4074 #define N_FATS 1 /* Number of FATs (1 or 2) */
mikekelly99 0:6db20bbdc767 4075
mikekelly99 0:6db20bbdc767 4076
mikekelly99 0:6db20bbdc767 4077 FRESULT f_mkfs (
mikekelly99 0:6db20bbdc767 4078 const TCHAR* path, /* Logical drive number */
mikekelly99 0:6db20bbdc767 4079 BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
mikekelly99 0:6db20bbdc767 4080 UINT au /* Size of allocation unit in unit of byte or sector */
mikekelly99 0:6db20bbdc767 4081 )
mikekelly99 0:6db20bbdc767 4082 {
mikekelly99 0:6db20bbdc767 4083 static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
mikekelly99 0:6db20bbdc767 4084 static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
mikekelly99 0:6db20bbdc767 4085 int vol;
mikekelly99 0:6db20bbdc767 4086 BYTE fmt, md, sys, *tbl, pdrv, part;
mikekelly99 0:6db20bbdc767 4087 DWORD n_clst, vs, n, wsect;
mikekelly99 0:6db20bbdc767 4088 UINT i;
mikekelly99 0:6db20bbdc767 4089 DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
mikekelly99 0:6db20bbdc767 4090 DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
mikekelly99 0:6db20bbdc767 4091 FATFS *fs;
mikekelly99 0:6db20bbdc767 4092 DSTATUS stat;
mikekelly99 0:6db20bbdc767 4093 #if _USE_TRIM
mikekelly99 0:6db20bbdc767 4094 DWORD eb[2];
mikekelly99 0:6db20bbdc767 4095 #endif
mikekelly99 0:6db20bbdc767 4096
mikekelly99 0:6db20bbdc767 4097
mikekelly99 0:6db20bbdc767 4098 /* Check mounted drive and clear work area */
mikekelly99 0:6db20bbdc767 4099 if (sfd > 1) return FR_INVALID_PARAMETER;
mikekelly99 0:6db20bbdc767 4100 vol = get_ldnumber(&path);
mikekelly99 0:6db20bbdc767 4101 if (vol < 0) return FR_INVALID_DRIVE;
mikekelly99 0:6db20bbdc767 4102 fs = FatFs[vol];
mikekelly99 0:6db20bbdc767 4103 if (!fs) return FR_NOT_ENABLED;
mikekelly99 0:6db20bbdc767 4104 fs->fs_type = 0;
mikekelly99 0:6db20bbdc767 4105 pdrv = LD2PD(vol); /* Physical drive */
mikekelly99 0:6db20bbdc767 4106 part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/
mikekelly99 0:6db20bbdc767 4107
mikekelly99 0:6db20bbdc767 4108 /* Get disk statics */
mikekelly99 0:6db20bbdc767 4109 stat = disk_initialize(pdrv);
mikekelly99 0:6db20bbdc767 4110 if (stat & STA_NOINIT) return FR_NOT_READY;
mikekelly99 0:6db20bbdc767 4111 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
mikekelly99 0:6db20bbdc767 4112 #if _MAX_SS != _MIN_SS /* Get disk sector size */
mikekelly99 0:6db20bbdc767 4113 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS)
mikekelly99 0:6db20bbdc767 4114 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4115 #endif
mikekelly99 0:6db20bbdc767 4116 if (_MULTI_PARTITION && part) {
mikekelly99 0:6db20bbdc767 4117 /* Get partition information from partition table in the MBR */
mikekelly99 0:6db20bbdc767 4118 if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4119 if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
mikekelly99 0:6db20bbdc767 4120 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
mikekelly99 0:6db20bbdc767 4121 if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */
mikekelly99 0:6db20bbdc767 4122 b_vol = LD_DWORD(tbl + 8); /* Volume start sector */
mikekelly99 0:6db20bbdc767 4123 n_vol = LD_DWORD(tbl + 12); /* Volume size */
mikekelly99 0:6db20bbdc767 4124 } else {
mikekelly99 0:6db20bbdc767 4125 /* Create a partition in this function */
mikekelly99 0:6db20bbdc767 4126 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
mikekelly99 0:6db20bbdc767 4127 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4128 b_vol = (sfd) ? 0 : 63; /* Volume start sector */
mikekelly99 0:6db20bbdc767 4129 n_vol -= b_vol; /* Volume size */
mikekelly99 0:6db20bbdc767 4130 }
mikekelly99 0:6db20bbdc767 4131
mikekelly99 0:6db20bbdc767 4132 if (au & (au - 1)) au = 0;
mikekelly99 0:6db20bbdc767 4133 if (!au) { /* AU auto selection */
mikekelly99 0:6db20bbdc767 4134 vs = n_vol / (2000 / (SS(fs) / 512));
mikekelly99 0:6db20bbdc767 4135 for (i = 0; vs < vst[i]; i++) ;
mikekelly99 0:6db20bbdc767 4136 au = cst[i];
mikekelly99 0:6db20bbdc767 4137 }
mikekelly99 0:6db20bbdc767 4138 if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */
mikekelly99 0:6db20bbdc767 4139 if (!au) au = 1;
mikekelly99 0:6db20bbdc767 4140 if (au > 128) au = 128;
mikekelly99 0:6db20bbdc767 4141
mikekelly99 0:6db20bbdc767 4142 /* Pre-compute number of clusters and FAT sub-type */
mikekelly99 0:6db20bbdc767 4143 n_clst = n_vol / au;
mikekelly99 0:6db20bbdc767 4144 fmt = FS_FAT12;
mikekelly99 0:6db20bbdc767 4145 if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
mikekelly99 0:6db20bbdc767 4146 if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
mikekelly99 0:6db20bbdc767 4147
mikekelly99 0:6db20bbdc767 4148 /* Determine offset and size of FAT structure */
mikekelly99 0:6db20bbdc767 4149 if (fmt == FS_FAT32) {
mikekelly99 0:6db20bbdc767 4150 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
mikekelly99 0:6db20bbdc767 4151 n_rsv = 32;
mikekelly99 0:6db20bbdc767 4152 n_dir = 0;
mikekelly99 0:6db20bbdc767 4153 } else {
mikekelly99 0:6db20bbdc767 4154 n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
mikekelly99 0:6db20bbdc767 4155 n_fat = (n_fat + SS(fs) - 1) / SS(fs);
mikekelly99 0:6db20bbdc767 4156 n_rsv = 1;
mikekelly99 0:6db20bbdc767 4157 n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs);
mikekelly99 0:6db20bbdc767 4158 }
mikekelly99 0:6db20bbdc767 4159 b_fat = b_vol + n_rsv; /* FAT area start sector */
mikekelly99 0:6db20bbdc767 4160 b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
mikekelly99 0:6db20bbdc767 4161 b_data = b_dir + n_dir; /* Data area start sector */
mikekelly99 0:6db20bbdc767 4162 if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
mikekelly99 0:6db20bbdc767 4163
mikekelly99 0:6db20bbdc767 4164 /* Align data start sector to erase block boundary (for flash memory media) */
mikekelly99 0:6db20bbdc767 4165 if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
mikekelly99 0:6db20bbdc767 4166 n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
mikekelly99 0:6db20bbdc767 4167 n = (n - b_data) / N_FATS;
mikekelly99 0:6db20bbdc767 4168 if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
mikekelly99 0:6db20bbdc767 4169 n_rsv += n;
mikekelly99 0:6db20bbdc767 4170 b_fat += n;
mikekelly99 0:6db20bbdc767 4171 } else { /* FAT12/16: Expand FAT size */
mikekelly99 0:6db20bbdc767 4172 n_fat += n;
mikekelly99 0:6db20bbdc767 4173 }
mikekelly99 0:6db20bbdc767 4174
mikekelly99 0:6db20bbdc767 4175 /* Determine number of clusters and final check of validity of the FAT sub-type */
mikekelly99 0:6db20bbdc767 4176 n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
mikekelly99 0:6db20bbdc767 4177 if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
mikekelly99 0:6db20bbdc767 4178 || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
mikekelly99 0:6db20bbdc767 4179 return FR_MKFS_ABORTED;
mikekelly99 0:6db20bbdc767 4180
mikekelly99 0:6db20bbdc767 4181 /* Determine system ID in the partition table */
mikekelly99 0:6db20bbdc767 4182 if (fmt == FS_FAT32) {
mikekelly99 0:6db20bbdc767 4183 sys = 0x0C; /* FAT32X */
mikekelly99 0:6db20bbdc767 4184 } else {
mikekelly99 0:6db20bbdc767 4185 if (fmt == FS_FAT12 && n_vol < 0x10000) {
mikekelly99 0:6db20bbdc767 4186 sys = 0x01; /* FAT12(<65536) */
mikekelly99 0:6db20bbdc767 4187 } else {
mikekelly99 0:6db20bbdc767 4188 sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */
mikekelly99 0:6db20bbdc767 4189 }
mikekelly99 0:6db20bbdc767 4190 }
mikekelly99 0:6db20bbdc767 4191
mikekelly99 0:6db20bbdc767 4192 if (_MULTI_PARTITION && part) {
mikekelly99 0:6db20bbdc767 4193 /* Update system ID in the partition table */
mikekelly99 0:6db20bbdc767 4194 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
mikekelly99 0:6db20bbdc767 4195 tbl[4] = sys;
mikekelly99 0:6db20bbdc767 4196 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */
mikekelly99 0:6db20bbdc767 4197 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4198 md = 0xF8;
mikekelly99 0:6db20bbdc767 4199 } else {
mikekelly99 0:6db20bbdc767 4200 if (sfd) { /* No partition table (SFD) */
mikekelly99 0:6db20bbdc767 4201 md = 0xF0;
mikekelly99 0:6db20bbdc767 4202 } else { /* Create partition table (FDISK) */
mikekelly99 0:6db20bbdc767 4203 mem_set(fs->win, 0, SS(fs));
mikekelly99 0:6db20bbdc767 4204 tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */
mikekelly99 0:6db20bbdc767 4205 tbl[1] = 1; /* Partition start head */
mikekelly99 0:6db20bbdc767 4206 tbl[2] = 1; /* Partition start sector */
mikekelly99 0:6db20bbdc767 4207 tbl[3] = 0; /* Partition start cylinder */
mikekelly99 0:6db20bbdc767 4208 tbl[4] = sys; /* System type */
mikekelly99 0:6db20bbdc767 4209 tbl[5] = 254; /* Partition end head */
mikekelly99 0:6db20bbdc767 4210 n = (b_vol + n_vol) / 63 / 255;
mikekelly99 0:6db20bbdc767 4211 tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */
mikekelly99 0:6db20bbdc767 4212 tbl[7] = (BYTE)n; /* End cylinder */
mikekelly99 0:6db20bbdc767 4213 ST_DWORD(tbl + 8, 63); /* Partition start in LBA */
mikekelly99 0:6db20bbdc767 4214 ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */
mikekelly99 0:6db20bbdc767 4215 ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */
mikekelly99 0:6db20bbdc767 4216 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */
mikekelly99 0:6db20bbdc767 4217 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4218 md = 0xF8;
mikekelly99 0:6db20bbdc767 4219 }
mikekelly99 0:6db20bbdc767 4220 }
mikekelly99 0:6db20bbdc767 4221
mikekelly99 0:6db20bbdc767 4222 /* Create BPB in the VBR */
mikekelly99 0:6db20bbdc767 4223 tbl = fs->win; /* Clear sector */
mikekelly99 0:6db20bbdc767 4224 mem_set(tbl, 0, SS(fs));
mikekelly99 0:6db20bbdc767 4225 mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
mikekelly99 0:6db20bbdc767 4226 i = SS(fs); /* Sector size */
mikekelly99 0:6db20bbdc767 4227 ST_WORD(tbl + BPB_BytsPerSec, i);
mikekelly99 0:6db20bbdc767 4228 tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
mikekelly99 0:6db20bbdc767 4229 ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
mikekelly99 0:6db20bbdc767 4230 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
mikekelly99 0:6db20bbdc767 4231 i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */
mikekelly99 0:6db20bbdc767 4232 ST_WORD(tbl + BPB_RootEntCnt, i);
mikekelly99 0:6db20bbdc767 4233 if (n_vol < 0x10000) { /* Number of total sectors */
mikekelly99 0:6db20bbdc767 4234 ST_WORD(tbl + BPB_TotSec16, n_vol);
mikekelly99 0:6db20bbdc767 4235 } else {
mikekelly99 0:6db20bbdc767 4236 ST_DWORD(tbl + BPB_TotSec32, n_vol);
mikekelly99 0:6db20bbdc767 4237 }
mikekelly99 0:6db20bbdc767 4238 tbl[BPB_Media] = md; /* Media descriptor */
mikekelly99 0:6db20bbdc767 4239 ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */
mikekelly99 0:6db20bbdc767 4240 ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */
mikekelly99 0:6db20bbdc767 4241 ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */
mikekelly99 0:6db20bbdc767 4242 n = GET_FATTIME(); /* Use current time as VSN */
mikekelly99 0:6db20bbdc767 4243 if (fmt == FS_FAT32) {
mikekelly99 0:6db20bbdc767 4244 ST_DWORD(tbl + BS_VolID32, n); /* VSN */
mikekelly99 0:6db20bbdc767 4245 ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */
mikekelly99 0:6db20bbdc767 4246 ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */
mikekelly99 0:6db20bbdc767 4247 ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */
mikekelly99 0:6db20bbdc767 4248 ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */
mikekelly99 0:6db20bbdc767 4249 tbl[BS_DrvNum32] = 0x80; /* Drive number */
mikekelly99 0:6db20bbdc767 4250 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
mikekelly99 0:6db20bbdc767 4251 mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
mikekelly99 0:6db20bbdc767 4252 } else {
mikekelly99 0:6db20bbdc767 4253 ST_DWORD(tbl + BS_VolID, n); /* VSN */
mikekelly99 0:6db20bbdc767 4254 ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */
mikekelly99 0:6db20bbdc767 4255 tbl[BS_DrvNum] = 0x80; /* Drive number */
mikekelly99 0:6db20bbdc767 4256 tbl[BS_BootSig] = 0x29; /* Extended boot signature */
mikekelly99 0:6db20bbdc767 4257 mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
mikekelly99 0:6db20bbdc767 4258 }
mikekelly99 0:6db20bbdc767 4259 ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
mikekelly99 0:6db20bbdc767 4260 if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
mikekelly99 0:6db20bbdc767 4261 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4262 if (fmt == FS_FAT32) /* Write it to the backup VBR if needed (VBR + 6) */
mikekelly99 0:6db20bbdc767 4263 disk_write(pdrv, tbl, b_vol + 6, 1);
mikekelly99 0:6db20bbdc767 4264
mikekelly99 0:6db20bbdc767 4265 /* Initialize FAT area */
mikekelly99 0:6db20bbdc767 4266 wsect = b_fat;
mikekelly99 0:6db20bbdc767 4267 for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
mikekelly99 0:6db20bbdc767 4268 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
mikekelly99 0:6db20bbdc767 4269 n = md; /* Media descriptor byte */
mikekelly99 0:6db20bbdc767 4270 if (fmt != FS_FAT32) {
mikekelly99 0:6db20bbdc767 4271 n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
mikekelly99 0:6db20bbdc767 4272 ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */
mikekelly99 0:6db20bbdc767 4273 } else {
mikekelly99 0:6db20bbdc767 4274 n |= 0xFFFFFF00;
mikekelly99 0:6db20bbdc767 4275 ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */
mikekelly99 0:6db20bbdc767 4276 ST_DWORD(tbl + 4, 0xFFFFFFFF);
mikekelly99 0:6db20bbdc767 4277 ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */
mikekelly99 0:6db20bbdc767 4278 }
mikekelly99 0:6db20bbdc767 4279 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 4280 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4281 mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
mikekelly99 0:6db20bbdc767 4282 for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
mikekelly99 0:6db20bbdc767 4283 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 4284 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4285 }
mikekelly99 0:6db20bbdc767 4286 }
mikekelly99 0:6db20bbdc767 4287
mikekelly99 0:6db20bbdc767 4288 /* Initialize root directory */
mikekelly99 0:6db20bbdc767 4289 i = (fmt == FS_FAT32) ? au : (UINT)n_dir;
mikekelly99 0:6db20bbdc767 4290 do {
mikekelly99 0:6db20bbdc767 4291 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
mikekelly99 0:6db20bbdc767 4292 return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4293 } while (--i);
mikekelly99 0:6db20bbdc767 4294
mikekelly99 0:6db20bbdc767 4295 #if _USE_TRIM /* Erase data area if needed */
mikekelly99 0:6db20bbdc767 4296 {
mikekelly99 0:6db20bbdc767 4297 eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
mikekelly99 0:6db20bbdc767 4298 disk_ioctl(pdrv, CTRL_TRIM, eb);
mikekelly99 0:6db20bbdc767 4299 }
mikekelly99 0:6db20bbdc767 4300 #endif
mikekelly99 0:6db20bbdc767 4301
mikekelly99 0:6db20bbdc767 4302 /* Create FSINFO if needed */
mikekelly99 0:6db20bbdc767 4303 if (fmt == FS_FAT32) {
mikekelly99 0:6db20bbdc767 4304 ST_DWORD(tbl + FSI_LeadSig, 0x41615252);
mikekelly99 0:6db20bbdc767 4305 ST_DWORD(tbl + FSI_StrucSig, 0x61417272);
mikekelly99 0:6db20bbdc767 4306 ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */
mikekelly99 0:6db20bbdc767 4307 ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */
mikekelly99 0:6db20bbdc767 4308 ST_WORD(tbl + BS_55AA, 0xAA55);
mikekelly99 0:6db20bbdc767 4309 disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */
mikekelly99 0:6db20bbdc767 4310 disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */
mikekelly99 0:6db20bbdc767 4311 }
mikekelly99 0:6db20bbdc767 4312
mikekelly99 0:6db20bbdc767 4313 return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4314 }
mikekelly99 0:6db20bbdc767 4315
mikekelly99 0:6db20bbdc767 4316
mikekelly99 0:6db20bbdc767 4317
mikekelly99 0:6db20bbdc767 4318 #if _MULTI_PARTITION
mikekelly99 0:6db20bbdc767 4319 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4320 /* Create partition table on the physical drive */
mikekelly99 0:6db20bbdc767 4321 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4322
mikekelly99 0:6db20bbdc767 4323 FRESULT f_fdisk (
mikekelly99 0:6db20bbdc767 4324 BYTE pdrv, /* Physical drive number */
mikekelly99 0:6db20bbdc767 4325 const DWORD szt[], /* Pointer to the size table for each partitions */
mikekelly99 0:6db20bbdc767 4326 void* work /* Pointer to the working buffer */
mikekelly99 0:6db20bbdc767 4327 )
mikekelly99 0:6db20bbdc767 4328 {
mikekelly99 0:6db20bbdc767 4329 UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
mikekelly99 0:6db20bbdc767 4330 BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
mikekelly99 0:6db20bbdc767 4331 DSTATUS stat;
mikekelly99 0:6db20bbdc767 4332 DWORD sz_disk, sz_part, s_part;
mikekelly99 0:6db20bbdc767 4333
mikekelly99 0:6db20bbdc767 4334
mikekelly99 0:6db20bbdc767 4335 stat = disk_initialize(pdrv);
mikekelly99 0:6db20bbdc767 4336 if (stat & STA_NOINIT) return FR_NOT_READY;
mikekelly99 0:6db20bbdc767 4337 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
mikekelly99 0:6db20bbdc767 4338 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
mikekelly99 0:6db20bbdc767 4339
mikekelly99 0:6db20bbdc767 4340 /* Determine CHS in the table regardless of the drive geometry */
mikekelly99 0:6db20bbdc767 4341 for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
mikekelly99 0:6db20bbdc767 4342 if (n == 256) n--;
mikekelly99 0:6db20bbdc767 4343 e_hd = n - 1;
mikekelly99 0:6db20bbdc767 4344 sz_cyl = 63 * n;
mikekelly99 0:6db20bbdc767 4345 tot_cyl = sz_disk / sz_cyl;
mikekelly99 0:6db20bbdc767 4346
mikekelly99 0:6db20bbdc767 4347 /* Create partition table */
mikekelly99 0:6db20bbdc767 4348 mem_set(buf, 0, _MAX_SS);
mikekelly99 0:6db20bbdc767 4349 p = buf + MBR_Table; b_cyl = 0;
mikekelly99 0:6db20bbdc767 4350 for (i = 0; i < 4; i++, p += SZ_PTE) {
mikekelly99 0:6db20bbdc767 4351 p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
mikekelly99 0:6db20bbdc767 4352 if (!p_cyl) continue;
mikekelly99 0:6db20bbdc767 4353 s_part = (DWORD)sz_cyl * b_cyl;
mikekelly99 0:6db20bbdc767 4354 sz_part = (DWORD)sz_cyl * p_cyl;
mikekelly99 0:6db20bbdc767 4355 if (i == 0) { /* Exclude first track of cylinder 0 */
mikekelly99 0:6db20bbdc767 4356 s_hd = 1;
mikekelly99 0:6db20bbdc767 4357 s_part += 63; sz_part -= 63;
mikekelly99 0:6db20bbdc767 4358 } else {
mikekelly99 0:6db20bbdc767 4359 s_hd = 0;
mikekelly99 0:6db20bbdc767 4360 }
mikekelly99 0:6db20bbdc767 4361 e_cyl = b_cyl + p_cyl - 1;
mikekelly99 0:6db20bbdc767 4362 if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;
mikekelly99 0:6db20bbdc767 4363
mikekelly99 0:6db20bbdc767 4364 /* Set partition table */
mikekelly99 0:6db20bbdc767 4365 p[1] = s_hd; /* Start head */
mikekelly99 0:6db20bbdc767 4366 p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */
mikekelly99 0:6db20bbdc767 4367 p[3] = (BYTE)b_cyl; /* Start cylinder */
mikekelly99 0:6db20bbdc767 4368 p[4] = 0x06; /* System type (temporary setting) */
mikekelly99 0:6db20bbdc767 4369 p[5] = e_hd; /* End head */
mikekelly99 0:6db20bbdc767 4370 p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */
mikekelly99 0:6db20bbdc767 4371 p[7] = (BYTE)e_cyl; /* End cylinder */
mikekelly99 0:6db20bbdc767 4372 ST_DWORD(p + 8, s_part); /* Start sector in LBA */
mikekelly99 0:6db20bbdc767 4373 ST_DWORD(p + 12, sz_part); /* Partition size */
mikekelly99 0:6db20bbdc767 4374
mikekelly99 0:6db20bbdc767 4375 /* Next partition */
mikekelly99 0:6db20bbdc767 4376 b_cyl += p_cyl;
mikekelly99 0:6db20bbdc767 4377 }
mikekelly99 0:6db20bbdc767 4378 ST_WORD(p, 0xAA55);
mikekelly99 0:6db20bbdc767 4379
mikekelly99 0:6db20bbdc767 4380 /* Write it to the MBR */
mikekelly99 0:6db20bbdc767 4381 return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK;
mikekelly99 0:6db20bbdc767 4382 }
mikekelly99 0:6db20bbdc767 4383
mikekelly99 0:6db20bbdc767 4384
mikekelly99 0:6db20bbdc767 4385 #endif /* _MULTI_PARTITION */
mikekelly99 0:6db20bbdc767 4386 #endif /* _USE_MKFS && !_FS_READONLY */
mikekelly99 0:6db20bbdc767 4387
mikekelly99 0:6db20bbdc767 4388
mikekelly99 0:6db20bbdc767 4389
mikekelly99 0:6db20bbdc767 4390
mikekelly99 0:6db20bbdc767 4391 #if _USE_STRFUNC
mikekelly99 0:6db20bbdc767 4392 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4393 /* Get a string from the file */
mikekelly99 0:6db20bbdc767 4394 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4395
mikekelly99 0:6db20bbdc767 4396 TCHAR* f_gets (
mikekelly99 0:6db20bbdc767 4397 TCHAR* buff, /* Pointer to the string buffer to read */
mikekelly99 0:6db20bbdc767 4398 int len, /* Size of string buffer (characters) */
mikekelly99 0:6db20bbdc767 4399 FIL* fp /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 4400 )
mikekelly99 0:6db20bbdc767 4401 {
mikekelly99 0:6db20bbdc767 4402 int n = 0;
mikekelly99 0:6db20bbdc767 4403 TCHAR c, *p = buff;
mikekelly99 0:6db20bbdc767 4404 BYTE s[2];
mikekelly99 0:6db20bbdc767 4405 UINT rc;
mikekelly99 0:6db20bbdc767 4406
mikekelly99 0:6db20bbdc767 4407
mikekelly99 0:6db20bbdc767 4408 while (n < len - 1) { /* Read characters until buffer gets filled */
mikekelly99 0:6db20bbdc767 4409 #if _USE_LFN && _LFN_UNICODE
mikekelly99 0:6db20bbdc767 4410 #if _STRF_ENCODE == 3 /* Read a character in UTF-8 */
mikekelly99 0:6db20bbdc767 4411 f_read(fp, s, 1, &rc);
mikekelly99 0:6db20bbdc767 4412 if (rc != 1) break;
mikekelly99 0:6db20bbdc767 4413 c = s[0];
mikekelly99 0:6db20bbdc767 4414 if (c >= 0x80) {
mikekelly99 0:6db20bbdc767 4415 if (c < 0xC0) continue; /* Skip stray trailer */
mikekelly99 0:6db20bbdc767 4416 if (c < 0xE0) { /* Two-byte sequence */
mikekelly99 0:6db20bbdc767 4417 f_read(fp, s, 1, &rc);
mikekelly99 0:6db20bbdc767 4418 if (rc != 1) break;
mikekelly99 0:6db20bbdc767 4419 c = (c & 0x1F) << 6 | (s[0] & 0x3F);
mikekelly99 0:6db20bbdc767 4420 if (c < 0x80) c = '?';
mikekelly99 0:6db20bbdc767 4421 } else {
mikekelly99 0:6db20bbdc767 4422 if (c < 0xF0) { /* Three-byte sequence */
mikekelly99 0:6db20bbdc767 4423 f_read(fp, s, 2, &rc);
mikekelly99 0:6db20bbdc767 4424 if (rc != 2) break;
mikekelly99 0:6db20bbdc767 4425 c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F);
mikekelly99 0:6db20bbdc767 4426 if (c < 0x800) c = '?';
mikekelly99 0:6db20bbdc767 4427 } else { /* Reject four-byte sequence */
mikekelly99 0:6db20bbdc767 4428 c = '?';
mikekelly99 0:6db20bbdc767 4429 }
mikekelly99 0:6db20bbdc767 4430 }
mikekelly99 0:6db20bbdc767 4431 }
mikekelly99 0:6db20bbdc767 4432 #elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */
mikekelly99 0:6db20bbdc767 4433 f_read(fp, s, 2, &rc);
mikekelly99 0:6db20bbdc767 4434 if (rc != 2) break;
mikekelly99 0:6db20bbdc767 4435 c = s[1] + (s[0] << 8);
mikekelly99 0:6db20bbdc767 4436 #elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */
mikekelly99 0:6db20bbdc767 4437 f_read(fp, s, 2, &rc);
mikekelly99 0:6db20bbdc767 4438 if (rc != 2) break;
mikekelly99 0:6db20bbdc767 4439 c = s[0] + (s[1] << 8);
mikekelly99 0:6db20bbdc767 4440 #else /* Read a character in ANSI/OEM */
mikekelly99 0:6db20bbdc767 4441 f_read(fp, s, 1, &rc);
mikekelly99 0:6db20bbdc767 4442 if (rc != 1) break;
mikekelly99 0:6db20bbdc767 4443 c = s[0];
mikekelly99 0:6db20bbdc767 4444 if (IsDBCS1(c)) {
mikekelly99 0:6db20bbdc767 4445 f_read(fp, s, 1, &rc);
mikekelly99 0:6db20bbdc767 4446 if (rc != 1) break;
mikekelly99 0:6db20bbdc767 4447 c = (c << 8) + s[0];
mikekelly99 0:6db20bbdc767 4448 }
mikekelly99 0:6db20bbdc767 4449 c = ff_convert(c, 1); /* OEM -> Unicode */
mikekelly99 0:6db20bbdc767 4450 if (!c) c = '?';
mikekelly99 0:6db20bbdc767 4451 #endif
mikekelly99 0:6db20bbdc767 4452 #else /* Read a character without conversion */
mikekelly99 0:6db20bbdc767 4453 f_read(fp, s, 1, &rc);
mikekelly99 0:6db20bbdc767 4454 if (rc != 1) break;
mikekelly99 0:6db20bbdc767 4455 c = s[0];
mikekelly99 0:6db20bbdc767 4456 #endif
mikekelly99 0:6db20bbdc767 4457 if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */
mikekelly99 0:6db20bbdc767 4458 *p++ = c;
mikekelly99 0:6db20bbdc767 4459 n++;
mikekelly99 0:6db20bbdc767 4460 if (c == '\n') break; /* Break on EOL */
mikekelly99 0:6db20bbdc767 4461 }
mikekelly99 0:6db20bbdc767 4462 *p = 0;
mikekelly99 0:6db20bbdc767 4463 return n ? buff : 0; /* When no data read (eof or error), return with error. */
mikekelly99 0:6db20bbdc767 4464 }
mikekelly99 0:6db20bbdc767 4465
mikekelly99 0:6db20bbdc767 4466
mikekelly99 0:6db20bbdc767 4467
mikekelly99 0:6db20bbdc767 4468
mikekelly99 0:6db20bbdc767 4469 #if !_FS_READONLY
mikekelly99 0:6db20bbdc767 4470 #include <stdarg.h>
mikekelly99 0:6db20bbdc767 4471 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4472 /* Put a character to the file */
mikekelly99 0:6db20bbdc767 4473 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4474
mikekelly99 0:6db20bbdc767 4475 typedef struct {
mikekelly99 0:6db20bbdc767 4476 FIL* fp;
mikekelly99 0:6db20bbdc767 4477 int idx, nchr;
mikekelly99 0:6db20bbdc767 4478 BYTE buf[64];
mikekelly99 0:6db20bbdc767 4479 } putbuff;
mikekelly99 0:6db20bbdc767 4480
mikekelly99 0:6db20bbdc767 4481
mikekelly99 0:6db20bbdc767 4482 static
mikekelly99 0:6db20bbdc767 4483 void putc_bfd (
mikekelly99 0:6db20bbdc767 4484 putbuff* pb,
mikekelly99 0:6db20bbdc767 4485 TCHAR c
mikekelly99 0:6db20bbdc767 4486 )
mikekelly99 0:6db20bbdc767 4487 {
mikekelly99 0:6db20bbdc767 4488 UINT bw;
mikekelly99 0:6db20bbdc767 4489 int i;
mikekelly99 0:6db20bbdc767 4490
mikekelly99 0:6db20bbdc767 4491
mikekelly99 0:6db20bbdc767 4492 if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */
mikekelly99 0:6db20bbdc767 4493 putc_bfd(pb, '\r');
mikekelly99 0:6db20bbdc767 4494
mikekelly99 0:6db20bbdc767 4495 i = pb->idx; /* Buffer write index (-1:error) */
mikekelly99 0:6db20bbdc767 4496 if (i < 0) return;
mikekelly99 0:6db20bbdc767 4497
mikekelly99 0:6db20bbdc767 4498 #if _USE_LFN && _LFN_UNICODE
mikekelly99 0:6db20bbdc767 4499 #if _STRF_ENCODE == 3 /* Write a character in UTF-8 */
mikekelly99 0:6db20bbdc767 4500 if (c < 0x80) { /* 7-bit */
mikekelly99 0:6db20bbdc767 4501 pb->buf[i++] = (BYTE)c;
mikekelly99 0:6db20bbdc767 4502 } else {
mikekelly99 0:6db20bbdc767 4503 if (c < 0x800) { /* 11-bit */
mikekelly99 0:6db20bbdc767 4504 pb->buf[i++] = (BYTE)(0xC0 | c >> 6);
mikekelly99 0:6db20bbdc767 4505 } else { /* 16-bit */
mikekelly99 0:6db20bbdc767 4506 pb->buf[i++] = (BYTE)(0xE0 | c >> 12);
mikekelly99 0:6db20bbdc767 4507 pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F));
mikekelly99 0:6db20bbdc767 4508 }
mikekelly99 0:6db20bbdc767 4509 pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F));
mikekelly99 0:6db20bbdc767 4510 }
mikekelly99 0:6db20bbdc767 4511 #elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */
mikekelly99 0:6db20bbdc767 4512 pb->buf[i++] = (BYTE)(c >> 8);
mikekelly99 0:6db20bbdc767 4513 pb->buf[i++] = (BYTE)c;
mikekelly99 0:6db20bbdc767 4514 #elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */
mikekelly99 0:6db20bbdc767 4515 pb->buf[i++] = (BYTE)c;
mikekelly99 0:6db20bbdc767 4516 pb->buf[i++] = (BYTE)(c >> 8);
mikekelly99 0:6db20bbdc767 4517 #else /* Write a character in ANSI/OEM */
mikekelly99 0:6db20bbdc767 4518 c = ff_convert(c, 0); /* Unicode -> OEM */
mikekelly99 0:6db20bbdc767 4519 if (!c) c = '?';
mikekelly99 0:6db20bbdc767 4520 if (c >= 0x100)
mikekelly99 0:6db20bbdc767 4521 pb->buf[i++] = (BYTE)(c >> 8);
mikekelly99 0:6db20bbdc767 4522 pb->buf[i++] = (BYTE)c;
mikekelly99 0:6db20bbdc767 4523 #endif
mikekelly99 0:6db20bbdc767 4524 #else /* Write a character without conversion */
mikekelly99 0:6db20bbdc767 4525 pb->buf[i++] = (BYTE)c;
mikekelly99 0:6db20bbdc767 4526 #endif
mikekelly99 0:6db20bbdc767 4527
mikekelly99 0:6db20bbdc767 4528 if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */
mikekelly99 0:6db20bbdc767 4529 f_write(pb->fp, pb->buf, (UINT)i, &bw);
mikekelly99 0:6db20bbdc767 4530 i = (bw == (UINT)i) ? 0 : -1;
mikekelly99 0:6db20bbdc767 4531 }
mikekelly99 0:6db20bbdc767 4532 pb->idx = i;
mikekelly99 0:6db20bbdc767 4533 pb->nchr++;
mikekelly99 0:6db20bbdc767 4534 }
mikekelly99 0:6db20bbdc767 4535
mikekelly99 0:6db20bbdc767 4536
mikekelly99 0:6db20bbdc767 4537
mikekelly99 0:6db20bbdc767 4538 int f_putc (
mikekelly99 0:6db20bbdc767 4539 TCHAR c, /* A character to be output */
mikekelly99 0:6db20bbdc767 4540 FIL* fp /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 4541 )
mikekelly99 0:6db20bbdc767 4542 {
mikekelly99 0:6db20bbdc767 4543 putbuff pb;
mikekelly99 0:6db20bbdc767 4544 UINT nw;
mikekelly99 0:6db20bbdc767 4545
mikekelly99 0:6db20bbdc767 4546
mikekelly99 0:6db20bbdc767 4547 pb.fp = fp; /* Initialize output buffer */
mikekelly99 0:6db20bbdc767 4548 pb.nchr = pb.idx = 0;
mikekelly99 0:6db20bbdc767 4549
mikekelly99 0:6db20bbdc767 4550 putc_bfd(&pb, c); /* Put a character */
mikekelly99 0:6db20bbdc767 4551
mikekelly99 0:6db20bbdc767 4552 if ( pb.idx >= 0 /* Flush buffered characters to the file */
mikekelly99 0:6db20bbdc767 4553 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK
mikekelly99 0:6db20bbdc767 4554 && (UINT)pb.idx == nw) return pb.nchr;
mikekelly99 0:6db20bbdc767 4555 return EOF;
mikekelly99 0:6db20bbdc767 4556 }
mikekelly99 0:6db20bbdc767 4557
mikekelly99 0:6db20bbdc767 4558
mikekelly99 0:6db20bbdc767 4559
mikekelly99 0:6db20bbdc767 4560
mikekelly99 0:6db20bbdc767 4561 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4562 /* Put a string to the file */
mikekelly99 0:6db20bbdc767 4563 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4564
mikekelly99 0:6db20bbdc767 4565 int f_puts (
mikekelly99 0:6db20bbdc767 4566 const TCHAR* str, /* Pointer to the string to be output */
mikekelly99 0:6db20bbdc767 4567 FIL* fp /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 4568 )
mikekelly99 0:6db20bbdc767 4569 {
mikekelly99 0:6db20bbdc767 4570 putbuff pb;
mikekelly99 0:6db20bbdc767 4571 UINT nw;
mikekelly99 0:6db20bbdc767 4572
mikekelly99 0:6db20bbdc767 4573
mikekelly99 0:6db20bbdc767 4574 pb.fp = fp; /* Initialize output buffer */
mikekelly99 0:6db20bbdc767 4575 pb.nchr = pb.idx = 0;
mikekelly99 0:6db20bbdc767 4576
mikekelly99 0:6db20bbdc767 4577 while (*str) /* Put the string */
mikekelly99 0:6db20bbdc767 4578 putc_bfd(&pb, *str++);
mikekelly99 0:6db20bbdc767 4579
mikekelly99 0:6db20bbdc767 4580 if ( pb.idx >= 0 /* Flush buffered characters to the file */
mikekelly99 0:6db20bbdc767 4581 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK
mikekelly99 0:6db20bbdc767 4582 && (UINT)pb.idx == nw) return pb.nchr;
mikekelly99 0:6db20bbdc767 4583 return EOF;
mikekelly99 0:6db20bbdc767 4584 }
mikekelly99 0:6db20bbdc767 4585
mikekelly99 0:6db20bbdc767 4586
mikekelly99 0:6db20bbdc767 4587
mikekelly99 0:6db20bbdc767 4588
mikekelly99 0:6db20bbdc767 4589 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4590 /* Put a formatted string to the file */
mikekelly99 0:6db20bbdc767 4591 /*-----------------------------------------------------------------------*/
mikekelly99 0:6db20bbdc767 4592
mikekelly99 0:6db20bbdc767 4593 int f_printf (
mikekelly99 0:6db20bbdc767 4594 FIL* fp, /* Pointer to the file object */
mikekelly99 0:6db20bbdc767 4595 const TCHAR* fmt, /* Pointer to the format string */
mikekelly99 0:6db20bbdc767 4596 ... /* Optional arguments... */
mikekelly99 0:6db20bbdc767 4597 )
mikekelly99 0:6db20bbdc767 4598 {
mikekelly99 0:6db20bbdc767 4599 va_list arp;
mikekelly99 0:6db20bbdc767 4600 BYTE f, r;
mikekelly99 0:6db20bbdc767 4601 UINT nw, i, j, w;
mikekelly99 0:6db20bbdc767 4602 DWORD v;
mikekelly99 0:6db20bbdc767 4603 TCHAR c, d, s[16], *p;
mikekelly99 0:6db20bbdc767 4604 putbuff pb;
mikekelly99 0:6db20bbdc767 4605
mikekelly99 0:6db20bbdc767 4606
mikekelly99 0:6db20bbdc767 4607 pb.fp = fp; /* Initialize output buffer */
mikekelly99 0:6db20bbdc767 4608 pb.nchr = pb.idx = 0;
mikekelly99 0:6db20bbdc767 4609
mikekelly99 0:6db20bbdc767 4610 va_start(arp, fmt);
mikekelly99 0:6db20bbdc767 4611
mikekelly99 0:6db20bbdc767 4612 for (;;) {
mikekelly99 0:6db20bbdc767 4613 c = *fmt++;
mikekelly99 0:6db20bbdc767 4614 if (c == 0) break; /* End of string */
mikekelly99 0:6db20bbdc767 4615 if (c != '%') { /* Non escape character */
mikekelly99 0:6db20bbdc767 4616 putc_bfd(&pb, c);
mikekelly99 0:6db20bbdc767 4617 continue;
mikekelly99 0:6db20bbdc767 4618 }
mikekelly99 0:6db20bbdc767 4619 w = f = 0;
mikekelly99 0:6db20bbdc767 4620 c = *fmt++;
mikekelly99 0:6db20bbdc767 4621 if (c == '0') { /* Flag: '0' padding */
mikekelly99 0:6db20bbdc767 4622 f = 1; c = *fmt++;
mikekelly99 0:6db20bbdc767 4623 } else {
mikekelly99 0:6db20bbdc767 4624 if (c == '-') { /* Flag: left justified */
mikekelly99 0:6db20bbdc767 4625 f = 2; c = *fmt++;
mikekelly99 0:6db20bbdc767 4626 }
mikekelly99 0:6db20bbdc767 4627 }
mikekelly99 0:6db20bbdc767 4628 while (IsDigit(c)) { /* Precision */
mikekelly99 0:6db20bbdc767 4629 w = w * 10 + c - '0';
mikekelly99 0:6db20bbdc767 4630 c = *fmt++;
mikekelly99 0:6db20bbdc767 4631 }
mikekelly99 0:6db20bbdc767 4632 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
mikekelly99 0:6db20bbdc767 4633 f |= 4; c = *fmt++;
mikekelly99 0:6db20bbdc767 4634 }
mikekelly99 0:6db20bbdc767 4635 if (!c) break;
mikekelly99 0:6db20bbdc767 4636 d = c;
mikekelly99 0:6db20bbdc767 4637 if (IsLower(d)) d -= 0x20;
mikekelly99 0:6db20bbdc767 4638 switch (d) { /* Type is... */
mikekelly99 0:6db20bbdc767 4639 case 'S' : /* String */
mikekelly99 0:6db20bbdc767 4640 p = va_arg(arp, TCHAR*);
mikekelly99 0:6db20bbdc767 4641 for (j = 0; p[j]; j++) ;
mikekelly99 0:6db20bbdc767 4642 if (!(f & 2)) {
mikekelly99 0:6db20bbdc767 4643 while (j++ < w) putc_bfd(&pb, ' ');
mikekelly99 0:6db20bbdc767 4644 }
mikekelly99 0:6db20bbdc767 4645 while (*p) putc_bfd(&pb, *p++);
mikekelly99 0:6db20bbdc767 4646 while (j++ < w) putc_bfd(&pb, ' ');
mikekelly99 0:6db20bbdc767 4647 continue;
mikekelly99 0:6db20bbdc767 4648 case 'C' : /* Character */
mikekelly99 0:6db20bbdc767 4649 putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue;
mikekelly99 0:6db20bbdc767 4650 case 'B' : /* Binary */
mikekelly99 0:6db20bbdc767 4651 r = 2; break;
mikekelly99 0:6db20bbdc767 4652 case 'O' : /* Octal */
mikekelly99 0:6db20bbdc767 4653 r = 8; break;
mikekelly99 0:6db20bbdc767 4654 case 'D' : /* Signed decimal */
mikekelly99 0:6db20bbdc767 4655 case 'U' : /* Unsigned decimal */
mikekelly99 0:6db20bbdc767 4656 r = 10; break;
mikekelly99 0:6db20bbdc767 4657 case 'X' : /* Hexdecimal */
mikekelly99 0:6db20bbdc767 4658 r = 16; break;
mikekelly99 0:6db20bbdc767 4659 default: /* Unknown type (pass-through) */
mikekelly99 0:6db20bbdc767 4660 putc_bfd(&pb, c); continue;
mikekelly99 0:6db20bbdc767 4661 }
mikekelly99 0:6db20bbdc767 4662
mikekelly99 0:6db20bbdc767 4663 /* Get an argument and put it in numeral */
mikekelly99 0:6db20bbdc767 4664 v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int));
mikekelly99 0:6db20bbdc767 4665 if (d == 'D' && (v & 0x80000000)) {
mikekelly99 0:6db20bbdc767 4666 v = 0 - v;
mikekelly99 0:6db20bbdc767 4667 f |= 8;
mikekelly99 0:6db20bbdc767 4668 }
mikekelly99 0:6db20bbdc767 4669 i = 0;
mikekelly99 0:6db20bbdc767 4670 do {
mikekelly99 0:6db20bbdc767 4671 d = (TCHAR)(v % r); v /= r;
mikekelly99 0:6db20bbdc767 4672 if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
mikekelly99 0:6db20bbdc767 4673 s[i++] = d + '0';
mikekelly99 0:6db20bbdc767 4674 } while (v && i < sizeof s / sizeof s[0]);
mikekelly99 0:6db20bbdc767 4675 if (f & 8) s[i++] = '-';
mikekelly99 0:6db20bbdc767 4676 j = i; d = (f & 1) ? '0' : ' ';
mikekelly99 0:6db20bbdc767 4677 while (!(f & 2) && j++ < w) putc_bfd(&pb, d);
mikekelly99 0:6db20bbdc767 4678 do putc_bfd(&pb, s[--i]); while (i);
mikekelly99 0:6db20bbdc767 4679 while (j++ < w) putc_bfd(&pb, d);
mikekelly99 0:6db20bbdc767 4680 }
mikekelly99 0:6db20bbdc767 4681
mikekelly99 0:6db20bbdc767 4682 va_end(arp);
mikekelly99 0:6db20bbdc767 4683
mikekelly99 0:6db20bbdc767 4684 if ( pb.idx >= 0 /* Flush buffered characters to the file */
mikekelly99 0:6db20bbdc767 4685 && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK
mikekelly99 0:6db20bbdc767 4686 && (UINT)pb.idx == nw) return pb.nchr;
mikekelly99 0:6db20bbdc767 4687 return EOF;
mikekelly99 0:6db20bbdc767 4688 }
mikekelly99 0:6db20bbdc767 4689
mikekelly99 0:6db20bbdc767 4690 #endif /* !_FS_READONLY */
mikekelly99 0:6db20bbdc767 4691 #endif /* _USE_STRFUNC */