SD Card Interface class. Log raw data bytes to memory addresses of your choice, or format the card and use the FAT file system to write files.

Dependencies:   mbed

Committer:
Blaze513
Date:
Sat Aug 07 18:32:30 2010 +0000
Revision:
1:94c648931f84
Child:
3:210eb67b260c

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Blaze513 1:94c648931f84 1 /*----------------------------------------------------------------------------/
Blaze513 1:94c648931f84 2 / FatFs - FAT file system module R0.08 (C)ChaN, 2010
Blaze513 1:94c648931f84 3 /-----------------------------------------------------------------------------/
Blaze513 1:94c648931f84 4 / FatFs module is a generic FAT file system module for small embedded systems.
Blaze513 1:94c648931f84 5 / This is a free software that opened for education, research and commercial
Blaze513 1:94c648931f84 6 / developments under license policy of following terms.
Blaze513 1:94c648931f84 7 /
Blaze513 1:94c648931f84 8 / Copyright (C) 2010, ChaN, all right reserved.
Blaze513 1:94c648931f84 9 /
Blaze513 1:94c648931f84 10 / * The FatFs module is a free software and there is NO WARRANTY.
Blaze513 1:94c648931f84 11 / * No restriction on use. You can use, modify and redistribute it for
Blaze513 1:94c648931f84 12 / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
Blaze513 1:94c648931f84 13 / * Redistributions of source code must retain the above copyright notice.
Blaze513 1:94c648931f84 14 /
Blaze513 1:94c648931f84 15 /-----------------------------------------------------------------------------/
Blaze513 1:94c648931f84 16 / Feb 26,'06 R0.00 Prototype.
Blaze513 1:94c648931f84 17 /
Blaze513 1:94c648931f84 18 / Apr 29,'06 R0.01 First stable version.
Blaze513 1:94c648931f84 19 /
Blaze513 1:94c648931f84 20 / Jun 01,'06 R0.02 Added FAT12 support.
Blaze513 1:94c648931f84 21 / Removed unbuffered mode.
Blaze513 1:94c648931f84 22 / Fixed a problem on small (<32M) partition.
Blaze513 1:94c648931f84 23 / Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
Blaze513 1:94c648931f84 24 /
Blaze513 1:94c648931f84 25 / Sep 22,'06 R0.03 Added f_rename().
Blaze513 1:94c648931f84 26 / Changed option _FS_MINIMUM to _FS_MINIMIZE.
Blaze513 1:94c648931f84 27 / Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
Blaze513 1:94c648931f84 28 / Fixed f_mkdir() creates incorrect directory on FAT32.
Blaze513 1:94c648931f84 29 /
Blaze513 1:94c648931f84 30 / Feb 04,'07 R0.04 Supported multiple drive system.
Blaze513 1:94c648931f84 31 / Changed some interfaces for multiple drive system.
Blaze513 1:94c648931f84 32 / Changed f_mountdrv() to f_mount().
Blaze513 1:94c648931f84 33 / Added f_mkfs().
Blaze513 1:94c648931f84 34 / Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
Blaze513 1:94c648931f84 35 / Added a capability of extending file size to f_lseek().
Blaze513 1:94c648931f84 36 / Added minimization level 3.
Blaze513 1:94c648931f84 37 / Fixed an endian sensitive code in f_mkfs().
Blaze513 1:94c648931f84 38 / May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
Blaze513 1:94c648931f84 39 / Added FSInfo support.
Blaze513 1:94c648931f84 40 / Fixed DBCS name can result FR_INVALID_NAME.
Blaze513 1:94c648931f84 41 / Fixed short seek (<= csize) collapses the file object.
Blaze513 1:94c648931f84 42 /
Blaze513 1:94c648931f84 43 / Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
Blaze513 1:94c648931f84 44 / Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
Blaze513 1:94c648931f84 45 / Fixed f_mkdir() on FAT32 creates incorrect directory.
Blaze513 1:94c648931f84 46 / Feb 03,'08 R0.05a Added f_truncate() and f_utime().
Blaze513 1:94c648931f84 47 / Fixed off by one error at FAT sub-type determination.
Blaze513 1:94c648931f84 48 / Fixed btr in f_read() can be mistruncated.
Blaze513 1:94c648931f84 49 / Fixed cached sector is not flushed when create and close
Blaze513 1:94c648931f84 50 / without write.
Blaze513 1:94c648931f84 51 /
Blaze513 1:94c648931f84 52 / Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
Blaze513 1:94c648931f84 53 / Improved performance of f_lseek() on moving to the same
Blaze513 1:94c648931f84 54 / or following cluster.
Blaze513 1:94c648931f84 55 /
Blaze513 1:94c648931f84 56 / Apr 01,'09 R0.07 Merged Tiny-FatFs as a buffer configuration option.
Blaze513 1:94c648931f84 57 / Added long file name support.
Blaze513 1:94c648931f84 58 / Added multiple code page support.
Blaze513 1:94c648931f84 59 / Added re-entrancy for multitask operation.
Blaze513 1:94c648931f84 60 / Added auto cluster size selection to f_mkfs().
Blaze513 1:94c648931f84 61 / Added rewind option to f_readdir().
Blaze513 1:94c648931f84 62 / Changed result code of critical errors.
Blaze513 1:94c648931f84 63 / Renamed string functions to avoid name collision.
Blaze513 1:94c648931f84 64 / Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
Blaze513 1:94c648931f84 65 / Added multiple sector size support.
Blaze513 1:94c648931f84 66 / Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
Blaze513 1:94c648931f84 67 / Fixed wrong cache control in f_lseek().
Blaze513 1:94c648931f84 68 / Added relative path feature.
Blaze513 1:94c648931f84 69 / Added f_chdir() and f_chdrive().
Blaze513 1:94c648931f84 70 / Added proper case conversion to extended char.
Blaze513 1:94c648931f84 71 / Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
Blaze513 1:94c648931f84 72 / Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
Blaze513 1:94c648931f84 73 / Fixed name matching error on the 13 char boundary.
Blaze513 1:94c648931f84 74 / Added a configuration option, _LFN_UNICODE.
Blaze513 1:94c648931f84 75 / Changed f_readdir() to return the SFN with always upper
Blaze513 1:94c648931f84 76 / case on non-LFN cfg.
Blaze513 1:94c648931f84 77 /
Blaze513 1:94c648931f84 78 / May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN)
Blaze513 1:94c648931f84 79 / Added file lock feature. (_FS_SHARE)
Blaze513 1:94c648931f84 80 / Added fast seek feature. (_USE_FASTSEEK)
Blaze513 1:94c648931f84 81 / Changed some types on the API, XCHAR->TCHAR.
Blaze513 1:94c648931f84 82 / Changed fname member in the FILINFO structure on Unicode cfg.
Blaze513 1:94c648931f84 83 / String functions support UTF-8 encoding files on Unicode cfg.
Blaze513 1:94c648931f84 84 /---------------------------------------------------------------------------*/
Blaze513 1:94c648931f84 85
Blaze513 1:94c648931f84 86 #include "ff.h" /* FatFs configurations and declarations */
Blaze513 1:94c648931f84 87 #include "diskio.h" /* Declarations of low level disk I/O functions */
Blaze513 1:94c648931f84 88
Blaze513 1:94c648931f84 89
Blaze513 1:94c648931f84 90 /*--------------------------------------------------------------------------
Blaze513 1:94c648931f84 91
Blaze513 1:94c648931f84 92 Module Private Definitions
Blaze513 1:94c648931f84 93
Blaze513 1:94c648931f84 94 ---------------------------------------------------------------------------*/
Blaze513 1:94c648931f84 95
Blaze513 1:94c648931f84 96 #if _FATFS != 8085
Blaze513 1:94c648931f84 97 #error Wrong include file (ff.h).
Blaze513 1:94c648931f84 98 #endif
Blaze513 1:94c648931f84 99
Blaze513 1:94c648931f84 100
Blaze513 1:94c648931f84 101 /* FAT sub-type boundaries */
Blaze513 1:94c648931f84 102 /* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
Blaze513 1:94c648931f84 103 #define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
Blaze513 1:94c648931f84 104 #define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
Blaze513 1:94c648931f84 105
Blaze513 1:94c648931f84 106
Blaze513 1:94c648931f84 107 /* Definitions corresponds to multiple sector size */
Blaze513 1:94c648931f84 108 #if _MAX_SS == 512 /* Single sector size */
Blaze513 1:94c648931f84 109 #define SS(fs) 512U
Blaze513 1:94c648931f84 110 #elif _MAX_SS == 1024 || _MAX_SS == 2048 || _MAX_SS == 4096 /* Multiple sector size */
Blaze513 1:94c648931f84 111 #define SS(fs) ((fs)->ssize)
Blaze513 1:94c648931f84 112 #else
Blaze513 1:94c648931f84 113 #error Wrong sector size.
Blaze513 1:94c648931f84 114 #endif
Blaze513 1:94c648931f84 115
Blaze513 1:94c648931f84 116
Blaze513 1:94c648931f84 117 /* Reentrancy related */
Blaze513 1:94c648931f84 118 #if _FS_REENTRANT
Blaze513 1:94c648931f84 119 #if _USE_LFN == 1
Blaze513 1:94c648931f84 120 #error Static LFN work area must not be used in re-entrant configuration.
Blaze513 1:94c648931f84 121 #endif
Blaze513 1:94c648931f84 122 #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
Blaze513 1:94c648931f84 123 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
Blaze513 1:94c648931f84 124
Blaze513 1:94c648931f84 125 #else
Blaze513 1:94c648931f84 126 #define ENTER_FF(fs)
Blaze513 1:94c648931f84 127 #define LEAVE_FF(fs, res) return res
Blaze513 1:94c648931f84 128
Blaze513 1:94c648931f84 129 #endif
Blaze513 1:94c648931f84 130
Blaze513 1:94c648931f84 131 #define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
Blaze513 1:94c648931f84 132
Blaze513 1:94c648931f84 133
Blaze513 1:94c648931f84 134 /* Character code support macros */
Blaze513 1:94c648931f84 135 #define IsUpper(c) (((c)>='A')&&((c)<='Z'))
Blaze513 1:94c648931f84 136 #define IsLower(c) (((c)>='a')&&((c)<='z'))
Blaze513 1:94c648931f84 137 #define IsDigit(c) (((c)>='0')&&((c)<='9'))
Blaze513 1:94c648931f84 138
Blaze513 1:94c648931f84 139 #if _DF1S /* Code page is DBCS */
Blaze513 1:94c648931f84 140
Blaze513 1:94c648931f84 141 #ifdef _DF2S /* Two 1st byte areas */
Blaze513 1:94c648931f84 142 #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
Blaze513 1:94c648931f84 143 #else /* One 1st byte area */
Blaze513 1:94c648931f84 144 #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
Blaze513 1:94c648931f84 145 #endif
Blaze513 1:94c648931f84 146
Blaze513 1:94c648931f84 147 #ifdef _DS3S /* Three 2nd byte areas */
Blaze513 1:94c648931f84 148 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
Blaze513 1:94c648931f84 149 #else /* Two 2nd byte areas */
Blaze513 1:94c648931f84 150 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
Blaze513 1:94c648931f84 151 #endif
Blaze513 1:94c648931f84 152
Blaze513 1:94c648931f84 153 #else /* Code page is SBCS */
Blaze513 1:94c648931f84 154
Blaze513 1:94c648931f84 155 #define IsDBCS1(c) 0
Blaze513 1:94c648931f84 156 #define IsDBCS2(c) 0
Blaze513 1:94c648931f84 157
Blaze513 1:94c648931f84 158 #endif /* _DF1S */
Blaze513 1:94c648931f84 159
Blaze513 1:94c648931f84 160
Blaze513 1:94c648931f84 161 /* Name status flags */
Blaze513 1:94c648931f84 162 #define NS 11 /* Offset of name status byte */
Blaze513 1:94c648931f84 163 #define NS_LOSS 0x01 /* Out of 8.3 format */
Blaze513 1:94c648931f84 164 #define NS_LFN 0x02 /* Force to create LFN entry */
Blaze513 1:94c648931f84 165 #define NS_LAST 0x04 /* Last segment */
Blaze513 1:94c648931f84 166 #define NS_BODY 0x08 /* Lower case flag (body) */
Blaze513 1:94c648931f84 167 #define NS_EXT 0x10 /* Lower case flag (ext) */
Blaze513 1:94c648931f84 168 #define NS_DOT 0x20 /* Dot entry */
Blaze513 1:94c648931f84 169
Blaze513 1:94c648931f84 170
Blaze513 1:94c648931f84 171
Blaze513 1:94c648931f84 172 /*------------------------------------------------------------*/
Blaze513 1:94c648931f84 173 /* Work area */
Blaze513 1:94c648931f84 174
Blaze513 1:94c648931f84 175 #if !_DRIVES
Blaze513 1:94c648931f84 176 #error Number of drives must not be 0.
Blaze513 1:94c648931f84 177 #endif
Blaze513 1:94c648931f84 178 static
Blaze513 1:94c648931f84 179 WORD Fsid; /* File system mount ID */
Blaze513 1:94c648931f84 180 static
Blaze513 1:94c648931f84 181 FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */
Blaze513 1:94c648931f84 182
Blaze513 1:94c648931f84 183 #if _FS_RPATH
Blaze513 1:94c648931f84 184 static
Blaze513 1:94c648931f84 185 BYTE Drive; /* Current drive */
Blaze513 1:94c648931f84 186 #endif
Blaze513 1:94c648931f84 187
Blaze513 1:94c648931f84 188
Blaze513 1:94c648931f84 189 #if _USE_LFN == 0 /* No LFN */
Blaze513 1:94c648931f84 190 #define DEF_NAMEBUF BYTE sfn[12]
Blaze513 1:94c648931f84 191 #define INIT_BUF(dobj) (dobj).fn = sfn
Blaze513 1:94c648931f84 192 #define FREE_BUF()
Blaze513 1:94c648931f84 193
Blaze513 1:94c648931f84 194 #elif _USE_LFN == 1 /* LFN with static LFN working buffer */
Blaze513 1:94c648931f84 195 static WCHAR LfnBuf[_MAX_LFN + 1];
Blaze513 1:94c648931f84 196 #define DEF_NAMEBUF BYTE sfn[12]
Blaze513 1:94c648931f84 197 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
Blaze513 1:94c648931f84 198 #define FREE_BUF()
Blaze513 1:94c648931f84 199
Blaze513 1:94c648931f84 200 #elif _USE_LFN == 2 /* LFN with dynamic LFN working buffer on the stack */
Blaze513 1:94c648931f84 201 #define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1]
Blaze513 1:94c648931f84 202 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
Blaze513 1:94c648931f84 203 #define FREE_BUF()
Blaze513 1:94c648931f84 204
Blaze513 1:94c648931f84 205 #elif _USE_LFN == 3 /* LFN with dynamic LFN working buffer on the heap */
Blaze513 1:94c648931f84 206 #define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn
Blaze513 1:94c648931f84 207 #define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
Blaze513 1:94c648931f84 208 if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
Blaze513 1:94c648931f84 209 (dobj).lfn = lfn; (dobj).fn = sfn; }
Blaze513 1:94c648931f84 210 #define FREE_BUF() ff_memfree(lfn)
Blaze513 1:94c648931f84 211
Blaze513 1:94c648931f84 212 #else
Blaze513 1:94c648931f84 213 #error Wrong LFN configuration.
Blaze513 1:94c648931f84 214 #endif
Blaze513 1:94c648931f84 215
Blaze513 1:94c648931f84 216
Blaze513 1:94c648931f84 217
Blaze513 1:94c648931f84 218
Blaze513 1:94c648931f84 219 /*--------------------------------------------------------------------------
Blaze513 1:94c648931f84 220
Blaze513 1:94c648931f84 221 Module Private Functions
Blaze513 1:94c648931f84 222
Blaze513 1:94c648931f84 223 ---------------------------------------------------------------------------*/
Blaze513 1:94c648931f84 224
Blaze513 1:94c648931f84 225
Blaze513 1:94c648931f84 226 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 227 /* String functions */
Blaze513 1:94c648931f84 228 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 229
Blaze513 1:94c648931f84 230 /* Copy memory to memory */
Blaze513 1:94c648931f84 231 static
Blaze513 1:94c648931f84 232 void mem_cpy (void* dst, const void* src, int cnt) {
Blaze513 1:94c648931f84 233 BYTE *d = (BYTE*)dst;
Blaze513 1:94c648931f84 234 const BYTE *s = (const BYTE*)src;
Blaze513 1:94c648931f84 235
Blaze513 1:94c648931f84 236 #if _WORD_ACCESS == 1
Blaze513 1:94c648931f84 237 while (cnt >= sizeof(int)) {
Blaze513 1:94c648931f84 238 *(int*)d = *(int*)s;
Blaze513 1:94c648931f84 239 d += sizeof(int); s += sizeof(int);
Blaze513 1:94c648931f84 240 cnt -= sizeof(int);
Blaze513 1:94c648931f84 241 }
Blaze513 1:94c648931f84 242 #endif
Blaze513 1:94c648931f84 243 while (cnt--)
Blaze513 1:94c648931f84 244 *d++ = *s++;
Blaze513 1:94c648931f84 245 }
Blaze513 1:94c648931f84 246
Blaze513 1:94c648931f84 247 /* Fill memory */
Blaze513 1:94c648931f84 248 static
Blaze513 1:94c648931f84 249 void mem_set (void* dst, int val, int cnt) {
Blaze513 1:94c648931f84 250 BYTE *d = (BYTE*)dst;
Blaze513 1:94c648931f84 251
Blaze513 1:94c648931f84 252 while (cnt--)
Blaze513 1:94c648931f84 253 *d++ = (BYTE)val;
Blaze513 1:94c648931f84 254 }
Blaze513 1:94c648931f84 255
Blaze513 1:94c648931f84 256 /* Compare memory to memory */
Blaze513 1:94c648931f84 257 static
Blaze513 1:94c648931f84 258 int mem_cmp (const void* dst, const void* src, int cnt) {
Blaze513 1:94c648931f84 259 const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
Blaze513 1:94c648931f84 260 int r = 0;
Blaze513 1:94c648931f84 261
Blaze513 1:94c648931f84 262 while (cnt-- && (r = *d++ - *s++) == 0) ;
Blaze513 1:94c648931f84 263 return r;
Blaze513 1:94c648931f84 264 }
Blaze513 1:94c648931f84 265
Blaze513 1:94c648931f84 266 /* Check if chr is contained in the string */
Blaze513 1:94c648931f84 267 static
Blaze513 1:94c648931f84 268 int chk_chr (const char* str, int chr) {
Blaze513 1:94c648931f84 269 while (*str && *str != chr) str++;
Blaze513 1:94c648931f84 270 return *str;
Blaze513 1:94c648931f84 271 }
Blaze513 1:94c648931f84 272
Blaze513 1:94c648931f84 273
Blaze513 1:94c648931f84 274
Blaze513 1:94c648931f84 275 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 276 /* Request/Release grant to access the volume */
Blaze513 1:94c648931f84 277 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 278 #if _FS_REENTRANT
Blaze513 1:94c648931f84 279
Blaze513 1:94c648931f84 280 static
Blaze513 1:94c648931f84 281 int lock_fs (
Blaze513 1:94c648931f84 282 FATFS *fs /* File system object */
Blaze513 1:94c648931f84 283 )
Blaze513 1:94c648931f84 284 {
Blaze513 1:94c648931f84 285 return ff_req_grant(fs->sobj);
Blaze513 1:94c648931f84 286 }
Blaze513 1:94c648931f84 287
Blaze513 1:94c648931f84 288
Blaze513 1:94c648931f84 289 static
Blaze513 1:94c648931f84 290 void unlock_fs (
Blaze513 1:94c648931f84 291 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 292 FRESULT res /* Result code to be returned */
Blaze513 1:94c648931f84 293 )
Blaze513 1:94c648931f84 294 {
Blaze513 1:94c648931f84 295 if (res != FR_NOT_ENABLED &&
Blaze513 1:94c648931f84 296 res != FR_INVALID_DRIVE &&
Blaze513 1:94c648931f84 297 res != FR_INVALID_OBJECT &&
Blaze513 1:94c648931f84 298 res != FR_TIMEOUT) {
Blaze513 1:94c648931f84 299 ff_rel_grant(fs->sobj);
Blaze513 1:94c648931f84 300 }
Blaze513 1:94c648931f84 301 }
Blaze513 1:94c648931f84 302 #endif
Blaze513 1:94c648931f84 303
Blaze513 1:94c648931f84 304
Blaze513 1:94c648931f84 305
Blaze513 1:94c648931f84 306 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 307 /* File shareing control functions */
Blaze513 1:94c648931f84 308 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 309 #if _FS_SHARE
Blaze513 1:94c648931f84 310
Blaze513 1:94c648931f84 311 static
Blaze513 1:94c648931f84 312 FRESULT chk_lock ( /* Check if the file can be accessed */
Blaze513 1:94c648931f84 313 FAT_DIR* dj, /* Directory object pointing the file to be checked */
Blaze513 1:94c648931f84 314 int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
Blaze513 1:94c648931f84 315 )
Blaze513 1:94c648931f84 316 {
Blaze513 1:94c648931f84 317 UINT i, be;
Blaze513 1:94c648931f84 318
Blaze513 1:94c648931f84 319 /* Search file semaphore table */
Blaze513 1:94c648931f84 320 for (i = be = 0; i < _FS_SHARE; i++) {
Blaze513 1:94c648931f84 321 if (dj->fs->flsem[i].ctr) { /* Existing entry */
Blaze513 1:94c648931f84 322 if (dj->fs->flsem[i].clu == dj->sclust && /* The file is found (identified with its location) */
Blaze513 1:94c648931f84 323 dj->fs->flsem[i].idx == dj->index) break;
Blaze513 1:94c648931f84 324 } else { /* Blank entry */
Blaze513 1:94c648931f84 325 be++;
Blaze513 1:94c648931f84 326 }
Blaze513 1:94c648931f84 327 }
Blaze513 1:94c648931f84 328 if (i == _FS_SHARE) /* The file has not been opened */
Blaze513 1:94c648931f84 329 return (be || acc != 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */
Blaze513 1:94c648931f84 330
Blaze513 1:94c648931f84 331 /* The file has been opened. Reject any open against writing file and all write mode open */
Blaze513 1:94c648931f84 332 return (acc || dj->fs->flsem[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
Blaze513 1:94c648931f84 333 }
Blaze513 1:94c648931f84 334
Blaze513 1:94c648931f84 335
Blaze513 1:94c648931f84 336 static
Blaze513 1:94c648931f84 337 int enq_lock ( /* Check if an entry is available for a new file */
Blaze513 1:94c648931f84 338 FATFS* fs /* File system object */
Blaze513 1:94c648931f84 339 )
Blaze513 1:94c648931f84 340 {
Blaze513 1:94c648931f84 341 UINT i;
Blaze513 1:94c648931f84 342
Blaze513 1:94c648931f84 343 for (i = 0; i < _FS_SHARE && fs->flsem[i].ctr; i++) ;
Blaze513 1:94c648931f84 344 return (i == _FS_SHARE) ? 0 : 1;
Blaze513 1:94c648931f84 345 }
Blaze513 1:94c648931f84 346
Blaze513 1:94c648931f84 347
Blaze513 1:94c648931f84 348 static
Blaze513 1:94c648931f84 349 UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
Blaze513 1:94c648931f84 350 FAT_DIR* dj, /* Directory object pointing the file to register or increment */
Blaze513 1:94c648931f84 351 int acc /* Desired access mode (0:Read, !0:Write) */
Blaze513 1:94c648931f84 352 )
Blaze513 1:94c648931f84 353 {
Blaze513 1:94c648931f84 354 UINT i;
Blaze513 1:94c648931f84 355
Blaze513 1:94c648931f84 356
Blaze513 1:94c648931f84 357 for (i = 0; i < _FS_SHARE; i++) { /* Find the file */
Blaze513 1:94c648931f84 358 if (dj->fs->flsem[i].ctr &&
Blaze513 1:94c648931f84 359 dj->fs->flsem[i].clu == dj->sclust &&
Blaze513 1:94c648931f84 360 dj->fs->flsem[i].idx == dj->index) break;
Blaze513 1:94c648931f84 361 }
Blaze513 1:94c648931f84 362
Blaze513 1:94c648931f84 363 if (i == _FS_SHARE) { /* Not opened. Register it as new. */
Blaze513 1:94c648931f84 364 for (i = 0; i < _FS_SHARE && dj->fs->flsem[i].ctr; i++) ;
Blaze513 1:94c648931f84 365 if (i == _FS_SHARE) return 0; /* No space to register (int err) */
Blaze513 1:94c648931f84 366 dj->fs->flsem[i].clu = dj->sclust;
Blaze513 1:94c648931f84 367 dj->fs->flsem[i].idx = dj->index;
Blaze513 1:94c648931f84 368 }
Blaze513 1:94c648931f84 369
Blaze513 1:94c648931f84 370 if (acc && dj->fs->flsem[i].ctr) return 0; /* Access violation (int err) */
Blaze513 1:94c648931f84 371
Blaze513 1:94c648931f84 372 dj->fs->flsem[i].ctr = acc ? 0x100 : dj->fs->flsem[i].ctr + 1; /* Set semaphore value */
Blaze513 1:94c648931f84 373
Blaze513 1:94c648931f84 374 return i + 1;
Blaze513 1:94c648931f84 375 }
Blaze513 1:94c648931f84 376
Blaze513 1:94c648931f84 377
Blaze513 1:94c648931f84 378 static
Blaze513 1:94c648931f84 379 FRESULT dec_lock ( /* Decrement file open counter */
Blaze513 1:94c648931f84 380 FATFS* fs, /* File system object */
Blaze513 1:94c648931f84 381 UINT i /* Semaphore index */
Blaze513 1:94c648931f84 382 )
Blaze513 1:94c648931f84 383 {
Blaze513 1:94c648931f84 384 WORD n;
Blaze513 1:94c648931f84 385 FRESULT res;
Blaze513 1:94c648931f84 386
Blaze513 1:94c648931f84 387
Blaze513 1:94c648931f84 388 if (--i < _FS_SHARE) {
Blaze513 1:94c648931f84 389 n = fs->flsem[i].ctr;
Blaze513 1:94c648931f84 390 if (n >= 0x100) n = 0;
Blaze513 1:94c648931f84 391 if (n) n--;
Blaze513 1:94c648931f84 392 fs->flsem[i].ctr = n;
Blaze513 1:94c648931f84 393 res = FR_OK;
Blaze513 1:94c648931f84 394 } else {
Blaze513 1:94c648931f84 395 res = FR_INT_ERR;
Blaze513 1:94c648931f84 396 }
Blaze513 1:94c648931f84 397 return res;
Blaze513 1:94c648931f84 398 }
Blaze513 1:94c648931f84 399
Blaze513 1:94c648931f84 400 #endif
Blaze513 1:94c648931f84 401
Blaze513 1:94c648931f84 402
Blaze513 1:94c648931f84 403
Blaze513 1:94c648931f84 404 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 405 /* Change window offset */
Blaze513 1:94c648931f84 406 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 407
Blaze513 1:94c648931f84 408 static
Blaze513 1:94c648931f84 409 FRESULT move_window (
Blaze513 1:94c648931f84 410 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 411 DWORD sector /* Sector number to make appearance in the fs->win[] */
Blaze513 1:94c648931f84 412 ) /* Move to zero only writes back dirty window */
Blaze513 1:94c648931f84 413 {
Blaze513 1:94c648931f84 414 DWORD wsect;
Blaze513 1:94c648931f84 415
Blaze513 1:94c648931f84 416
Blaze513 1:94c648931f84 417 wsect = fs->winsect;
Blaze513 1:94c648931f84 418 if (wsect != sector) { /* Changed current window */
Blaze513 1:94c648931f84 419 #if !_FS_READONLY
Blaze513 1:94c648931f84 420 if (fs->wflag) { /* Write back dirty window if needed */
Blaze513 1:94c648931f84 421 if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
Blaze513 1:94c648931f84 422 return FR_DISK_ERR;
Blaze513 1:94c648931f84 423 fs->wflag = 0;
Blaze513 1:94c648931f84 424 if (wsect < (fs->fatbase + fs->fsize)) { /* In FAT area */
Blaze513 1:94c648931f84 425 BYTE nf;
Blaze513 1:94c648931f84 426 for (nf = fs->n_fats; nf > 1; nf--) { /* Reflect the change to all FAT copies */
Blaze513 1:94c648931f84 427 wsect += fs->fsize;
Blaze513 1:94c648931f84 428 disk_write(fs->drv, fs->win, wsect, 1);
Blaze513 1:94c648931f84 429 }
Blaze513 1:94c648931f84 430 }
Blaze513 1:94c648931f84 431 }
Blaze513 1:94c648931f84 432 #endif
Blaze513 1:94c648931f84 433 if (sector) {
Blaze513 1:94c648931f84 434 if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
Blaze513 1:94c648931f84 435 return FR_DISK_ERR;
Blaze513 1:94c648931f84 436 fs->winsect = sector;
Blaze513 1:94c648931f84 437 }
Blaze513 1:94c648931f84 438 }
Blaze513 1:94c648931f84 439
Blaze513 1:94c648931f84 440 return FR_OK;
Blaze513 1:94c648931f84 441 }
Blaze513 1:94c648931f84 442
Blaze513 1:94c648931f84 443
Blaze513 1:94c648931f84 444
Blaze513 1:94c648931f84 445
Blaze513 1:94c648931f84 446 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 447 /* Clean-up cached data */
Blaze513 1:94c648931f84 448 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 449 #if !_FS_READONLY
Blaze513 1:94c648931f84 450 static
Blaze513 1:94c648931f84 451 FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
Blaze513 1:94c648931f84 452 FATFS *fs /* File system object */
Blaze513 1:94c648931f84 453 )
Blaze513 1:94c648931f84 454 {
Blaze513 1:94c648931f84 455 FRESULT res;
Blaze513 1:94c648931f84 456
Blaze513 1:94c648931f84 457
Blaze513 1:94c648931f84 458 res = move_window(fs, 0);
Blaze513 1:94c648931f84 459 if (res == FR_OK) {
Blaze513 1:94c648931f84 460 /* Update FSInfo sector if needed */
Blaze513 1:94c648931f84 461 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
Blaze513 1:94c648931f84 462 fs->winsect = 0;
Blaze513 1:94c648931f84 463 mem_set(fs->win, 0, 512);
Blaze513 1:94c648931f84 464 ST_WORD(fs->win+BS_55AA, 0xAA55);
Blaze513 1:94c648931f84 465 ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
Blaze513 1:94c648931f84 466 ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
Blaze513 1:94c648931f84 467 ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
Blaze513 1:94c648931f84 468 ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
Blaze513 1:94c648931f84 469 disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
Blaze513 1:94c648931f84 470 fs->fsi_flag = 0;
Blaze513 1:94c648931f84 471 }
Blaze513 1:94c648931f84 472 /* Make sure that no pending write process in the physical drive */
Blaze513 1:94c648931f84 473 if (disk_ioctl(fs->drv, CTRL_SYNC, (void*)0) != RES_OK)
Blaze513 1:94c648931f84 474 res = FR_DISK_ERR;
Blaze513 1:94c648931f84 475 }
Blaze513 1:94c648931f84 476
Blaze513 1:94c648931f84 477 return res;
Blaze513 1:94c648931f84 478 }
Blaze513 1:94c648931f84 479 #endif
Blaze513 1:94c648931f84 480
Blaze513 1:94c648931f84 481
Blaze513 1:94c648931f84 482
Blaze513 1:94c648931f84 483
Blaze513 1:94c648931f84 484 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 485 /* FAT access - Read value of a FAT entry */
Blaze513 1:94c648931f84 486 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 487
Blaze513 1:94c648931f84 488
Blaze513 1:94c648931f84 489 DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
Blaze513 1:94c648931f84 490 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 491 DWORD clst /* Cluster# to get the link information */
Blaze513 1:94c648931f84 492 )
Blaze513 1:94c648931f84 493 {
Blaze513 1:94c648931f84 494 UINT wc, bc;
Blaze513 1:94c648931f84 495 BYTE *p;
Blaze513 1:94c648931f84 496
Blaze513 1:94c648931f84 497
Blaze513 1:94c648931f84 498 if (clst < 2 || clst >= fs->n_fatent) /* Chack range */
Blaze513 1:94c648931f84 499 return 1;
Blaze513 1:94c648931f84 500
Blaze513 1:94c648931f84 501 switch (fs->fs_type) {
Blaze513 1:94c648931f84 502 case FS_FAT12 :
Blaze513 1:94c648931f84 503 bc = (UINT)clst; bc += bc / 2;
Blaze513 1:94c648931f84 504 if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
Blaze513 1:94c648931f84 505 wc = fs->win[bc % SS(fs)]; bc++;
Blaze513 1:94c648931f84 506 if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
Blaze513 1:94c648931f84 507 wc |= fs->win[bc % SS(fs)] << 8;
Blaze513 1:94c648931f84 508 return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
Blaze513 1:94c648931f84 509
Blaze513 1:94c648931f84 510 case FS_FAT16 :
Blaze513 1:94c648931f84 511 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
Blaze513 1:94c648931f84 512 p = &fs->win[clst * 2 % SS(fs)];
Blaze513 1:94c648931f84 513 return LD_WORD(p);
Blaze513 1:94c648931f84 514
Blaze513 1:94c648931f84 515 case FS_FAT32 :
Blaze513 1:94c648931f84 516 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
Blaze513 1:94c648931f84 517 p = &fs->win[clst * 4 % SS(fs)];
Blaze513 1:94c648931f84 518 return LD_DWORD(p) & 0x0FFFFFFF;
Blaze513 1:94c648931f84 519 }
Blaze513 1:94c648931f84 520
Blaze513 1:94c648931f84 521 return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */
Blaze513 1:94c648931f84 522 }
Blaze513 1:94c648931f84 523
Blaze513 1:94c648931f84 524
Blaze513 1:94c648931f84 525
Blaze513 1:94c648931f84 526
Blaze513 1:94c648931f84 527 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 528 /* FAT access - Change value of a FAT entry */
Blaze513 1:94c648931f84 529 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 530 #if !_FS_READONLY
Blaze513 1:94c648931f84 531
Blaze513 1:94c648931f84 532 FRESULT put_fat (
Blaze513 1:94c648931f84 533 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 534 DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
Blaze513 1:94c648931f84 535 DWORD val /* New value to mark the cluster */
Blaze513 1:94c648931f84 536 )
Blaze513 1:94c648931f84 537 {
Blaze513 1:94c648931f84 538 UINT bc;
Blaze513 1:94c648931f84 539 BYTE *p;
Blaze513 1:94c648931f84 540 FRESULT res;
Blaze513 1:94c648931f84 541
Blaze513 1:94c648931f84 542
Blaze513 1:94c648931f84 543 if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
Blaze513 1:94c648931f84 544 res = FR_INT_ERR;
Blaze513 1:94c648931f84 545
Blaze513 1:94c648931f84 546 } else {
Blaze513 1:94c648931f84 547 switch (fs->fs_type) {
Blaze513 1:94c648931f84 548 case FS_FAT12 :
Blaze513 1:94c648931f84 549 bc = clst; bc += bc / 2;
Blaze513 1:94c648931f84 550 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
Blaze513 1:94c648931f84 551 if (res != FR_OK) break;
Blaze513 1:94c648931f84 552 p = &fs->win[bc % SS(fs)];
Blaze513 1:94c648931f84 553 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
Blaze513 1:94c648931f84 554 bc++;
Blaze513 1:94c648931f84 555 fs->wflag = 1;
Blaze513 1:94c648931f84 556 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
Blaze513 1:94c648931f84 557 if (res != FR_OK) break;
Blaze513 1:94c648931f84 558 p = &fs->win[bc % SS(fs)];
Blaze513 1:94c648931f84 559 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
Blaze513 1:94c648931f84 560 break;
Blaze513 1:94c648931f84 561
Blaze513 1:94c648931f84 562 case FS_FAT16 :
Blaze513 1:94c648931f84 563 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
Blaze513 1:94c648931f84 564 if (res != FR_OK) break;
Blaze513 1:94c648931f84 565 p = &fs->win[clst * 2 % SS(fs)];
Blaze513 1:94c648931f84 566 ST_WORD(p, (WORD)val);
Blaze513 1:94c648931f84 567 break;
Blaze513 1:94c648931f84 568
Blaze513 1:94c648931f84 569 case FS_FAT32 :
Blaze513 1:94c648931f84 570 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
Blaze513 1:94c648931f84 571 if (res != FR_OK) break;
Blaze513 1:94c648931f84 572 p = &fs->win[clst * 4 % SS(fs)];
Blaze513 1:94c648931f84 573 val |= LD_DWORD(p) & 0xF0000000;
Blaze513 1:94c648931f84 574 ST_DWORD(p, val);
Blaze513 1:94c648931f84 575 break;
Blaze513 1:94c648931f84 576
Blaze513 1:94c648931f84 577 default :
Blaze513 1:94c648931f84 578 res = FR_INT_ERR;
Blaze513 1:94c648931f84 579 }
Blaze513 1:94c648931f84 580 fs->wflag = 1;
Blaze513 1:94c648931f84 581 }
Blaze513 1:94c648931f84 582
Blaze513 1:94c648931f84 583 return res;
Blaze513 1:94c648931f84 584 }
Blaze513 1:94c648931f84 585 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 586
Blaze513 1:94c648931f84 587
Blaze513 1:94c648931f84 588
Blaze513 1:94c648931f84 589
Blaze513 1:94c648931f84 590 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 591 /* FAT handling - Remove a cluster chain */
Blaze513 1:94c648931f84 592 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 593 #if !_FS_READONLY
Blaze513 1:94c648931f84 594 static
Blaze513 1:94c648931f84 595 FRESULT remove_chain (
Blaze513 1:94c648931f84 596 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 597 DWORD clst /* Cluster# to remove a chain from */
Blaze513 1:94c648931f84 598 )
Blaze513 1:94c648931f84 599 {
Blaze513 1:94c648931f84 600 FRESULT res;
Blaze513 1:94c648931f84 601 DWORD nxt;
Blaze513 1:94c648931f84 602
Blaze513 1:94c648931f84 603
Blaze513 1:94c648931f84 604 if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
Blaze513 1:94c648931f84 605 res = FR_INT_ERR;
Blaze513 1:94c648931f84 606
Blaze513 1:94c648931f84 607 } else {
Blaze513 1:94c648931f84 608 res = FR_OK;
Blaze513 1:94c648931f84 609 while (clst < fs->n_fatent) { /* Not a last link? */
Blaze513 1:94c648931f84 610 nxt = get_fat(fs, clst); /* Get cluster status */
Blaze513 1:94c648931f84 611 if (nxt == 0) break; /* Empty cluster? */
Blaze513 1:94c648931f84 612 if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
Blaze513 1:94c648931f84 613 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
Blaze513 1:94c648931f84 614 res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
Blaze513 1:94c648931f84 615 if (res != FR_OK) break;
Blaze513 1:94c648931f84 616 if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
Blaze513 1:94c648931f84 617 fs->free_clust++;
Blaze513 1:94c648931f84 618 fs->fsi_flag = 1;
Blaze513 1:94c648931f84 619 }
Blaze513 1:94c648931f84 620 clst = nxt; /* Next cluster */
Blaze513 1:94c648931f84 621 }
Blaze513 1:94c648931f84 622 }
Blaze513 1:94c648931f84 623
Blaze513 1:94c648931f84 624 return res;
Blaze513 1:94c648931f84 625 }
Blaze513 1:94c648931f84 626 #endif
Blaze513 1:94c648931f84 627
Blaze513 1:94c648931f84 628
Blaze513 1:94c648931f84 629
Blaze513 1:94c648931f84 630
Blaze513 1:94c648931f84 631 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 632 /* FAT handling - Stretch or Create a cluster chain */
Blaze513 1:94c648931f84 633 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 634 #if !_FS_READONLY
Blaze513 1:94c648931f84 635 static
Blaze513 1:94c648931f84 636 DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
Blaze513 1:94c648931f84 637 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 638 DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
Blaze513 1:94c648931f84 639 )
Blaze513 1:94c648931f84 640 {
Blaze513 1:94c648931f84 641 DWORD cs, ncl, scl;
Blaze513 1:94c648931f84 642
Blaze513 1:94c648931f84 643
Blaze513 1:94c648931f84 644 if (clst == 0) { /* Create a new chain */
Blaze513 1:94c648931f84 645 scl = fs->last_clust; /* Get suggested start point */
Blaze513 1:94c648931f84 646 if (!scl || scl >= fs->n_fatent) scl = 1;
Blaze513 1:94c648931f84 647 }
Blaze513 1:94c648931f84 648 else { /* Stretch the current chain */
Blaze513 1:94c648931f84 649 cs = get_fat(fs, clst); /* Check the cluster status */
Blaze513 1:94c648931f84 650 if (cs < 2) return 1; /* It is an invalid cluster */
Blaze513 1:94c648931f84 651 if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
Blaze513 1:94c648931f84 652 scl = clst;
Blaze513 1:94c648931f84 653 }
Blaze513 1:94c648931f84 654
Blaze513 1:94c648931f84 655 ncl = scl; /* Start cluster */
Blaze513 1:94c648931f84 656 for (;;) {
Blaze513 1:94c648931f84 657 ncl++; /* Next cluster */
Blaze513 1:94c648931f84 658 if (ncl >= fs->n_fatent) { /* Wrap around */
Blaze513 1:94c648931f84 659 ncl = 2;
Blaze513 1:94c648931f84 660 if (ncl > scl) return 0; /* No free cluster */
Blaze513 1:94c648931f84 661 }
Blaze513 1:94c648931f84 662 cs = get_fat(fs, ncl); /* Get the cluster status */
Blaze513 1:94c648931f84 663 if (cs == 0) break; /* Found a free cluster */
Blaze513 1:94c648931f84 664 if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
Blaze513 1:94c648931f84 665 return cs;
Blaze513 1:94c648931f84 666 if (ncl == scl) return 0; /* No free cluster */
Blaze513 1:94c648931f84 667 }
Blaze513 1:94c648931f84 668
Blaze513 1:94c648931f84 669 if (put_fat(fs, ncl, 0x0FFFFFFF)) /* Mark the new cluster "last link" */
Blaze513 1:94c648931f84 670 return 0xFFFFFFFF;
Blaze513 1:94c648931f84 671 if (clst != 0) { /* Link it to the previous one if needed */
Blaze513 1:94c648931f84 672 if (put_fat(fs, clst, ncl))
Blaze513 1:94c648931f84 673 return 0xFFFFFFFF;
Blaze513 1:94c648931f84 674 }
Blaze513 1:94c648931f84 675
Blaze513 1:94c648931f84 676 fs->last_clust = ncl; /* Update FSINFO */
Blaze513 1:94c648931f84 677 if (fs->free_clust != 0xFFFFFFFF) {
Blaze513 1:94c648931f84 678 fs->free_clust--;
Blaze513 1:94c648931f84 679 fs->fsi_flag = 1;
Blaze513 1:94c648931f84 680 }
Blaze513 1:94c648931f84 681
Blaze513 1:94c648931f84 682 return ncl; /* Return new cluster number */
Blaze513 1:94c648931f84 683 }
Blaze513 1:94c648931f84 684 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 685
Blaze513 1:94c648931f84 686
Blaze513 1:94c648931f84 687
Blaze513 1:94c648931f84 688
Blaze513 1:94c648931f84 689 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 690 /* Get sector# from cluster# */
Blaze513 1:94c648931f84 691 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 692
Blaze513 1:94c648931f84 693
Blaze513 1:94c648931f84 694 DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
Blaze513 1:94c648931f84 695 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 696 DWORD clst /* Cluster# to be converted */
Blaze513 1:94c648931f84 697 )
Blaze513 1:94c648931f84 698 {
Blaze513 1:94c648931f84 699 clst -= 2;
Blaze513 1:94c648931f84 700 if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */
Blaze513 1:94c648931f84 701 return clst * fs->csize + fs->database;
Blaze513 1:94c648931f84 702 }
Blaze513 1:94c648931f84 703
Blaze513 1:94c648931f84 704
Blaze513 1:94c648931f84 705
Blaze513 1:94c648931f84 706
Blaze513 1:94c648931f84 707 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 708 /* Directory handling - Set directory index */
Blaze513 1:94c648931f84 709 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 710
Blaze513 1:94c648931f84 711 static
Blaze513 1:94c648931f84 712 FRESULT dir_sdi (
Blaze513 1:94c648931f84 713 FAT_DIR *dj, /* Pointer to directory object */
Blaze513 1:94c648931f84 714 WORD idx /* Directory index number */
Blaze513 1:94c648931f84 715 )
Blaze513 1:94c648931f84 716 {
Blaze513 1:94c648931f84 717 DWORD clst;
Blaze513 1:94c648931f84 718 WORD ic;
Blaze513 1:94c648931f84 719
Blaze513 1:94c648931f84 720
Blaze513 1:94c648931f84 721 dj->index = idx;
Blaze513 1:94c648931f84 722 clst = dj->sclust;
Blaze513 1:94c648931f84 723 if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */
Blaze513 1:94c648931f84 724 return FR_INT_ERR;
Blaze513 1:94c648931f84 725 if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
Blaze513 1:94c648931f84 726 clst = dj->fs->dirbase;
Blaze513 1:94c648931f84 727
Blaze513 1:94c648931f84 728 if (clst == 0) { /* Static table */
Blaze513 1:94c648931f84 729 dj->clust = clst;
Blaze513 1:94c648931f84 730 if (idx >= dj->fs->n_rootdir) /* Index is out of range */
Blaze513 1:94c648931f84 731 return FR_INT_ERR;
Blaze513 1:94c648931f84 732 dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32); /* Sector# */
Blaze513 1:94c648931f84 733 }
Blaze513 1:94c648931f84 734 else { /* Dynamic table */
Blaze513 1:94c648931f84 735 ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */
Blaze513 1:94c648931f84 736 while (idx >= ic) { /* Follow cluster chain */
Blaze513 1:94c648931f84 737 clst = get_fat(dj->fs, clst); /* Get next cluster */
Blaze513 1:94c648931f84 738 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
Blaze513 1:94c648931f84 739 if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */
Blaze513 1:94c648931f84 740 return FR_INT_ERR;
Blaze513 1:94c648931f84 741 idx -= ic;
Blaze513 1:94c648931f84 742 }
Blaze513 1:94c648931f84 743 dj->clust = clst;
Blaze513 1:94c648931f84 744 dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32); /* Sector# */
Blaze513 1:94c648931f84 745 }
Blaze513 1:94c648931f84 746
Blaze513 1:94c648931f84 747 dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */
Blaze513 1:94c648931f84 748
Blaze513 1:94c648931f84 749 return FR_OK; /* Seek succeeded */
Blaze513 1:94c648931f84 750 }
Blaze513 1:94c648931f84 751
Blaze513 1:94c648931f84 752
Blaze513 1:94c648931f84 753
Blaze513 1:94c648931f84 754
Blaze513 1:94c648931f84 755 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 756 /* Directory handling - Move directory index next */
Blaze513 1:94c648931f84 757 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 758
Blaze513 1:94c648931f84 759 static
Blaze513 1:94c648931f84 760 FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */
Blaze513 1:94c648931f84 761 FAT_DIR *dj, /* Pointer to directory object */
Blaze513 1:94c648931f84 762 int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
Blaze513 1:94c648931f84 763 )
Blaze513 1:94c648931f84 764 {
Blaze513 1:94c648931f84 765 DWORD clst;
Blaze513 1:94c648931f84 766 WORD i;
Blaze513 1:94c648931f84 767
Blaze513 1:94c648931f84 768
Blaze513 1:94c648931f84 769 i = dj->index + 1;
Blaze513 1:94c648931f84 770 if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
Blaze513 1:94c648931f84 771 return FR_NO_FILE;
Blaze513 1:94c648931f84 772
Blaze513 1:94c648931f84 773 if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */
Blaze513 1:94c648931f84 774 dj->sect++; /* Next sector */
Blaze513 1:94c648931f84 775
Blaze513 1:94c648931f84 776 if (dj->clust == 0) { /* Static table */
Blaze513 1:94c648931f84 777 if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
Blaze513 1:94c648931f84 778 return FR_NO_FILE;
Blaze513 1:94c648931f84 779 }
Blaze513 1:94c648931f84 780 else { /* Dynamic table */
Blaze513 1:94c648931f84 781 if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
Blaze513 1:94c648931f84 782 clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
Blaze513 1:94c648931f84 783 if (clst <= 1) return FR_INT_ERR;
Blaze513 1:94c648931f84 784 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
Blaze513 1:94c648931f84 785 if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */
Blaze513 1:94c648931f84 786 #if !_FS_READONLY
Blaze513 1:94c648931f84 787 BYTE c;
Blaze513 1:94c648931f84 788 if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */
Blaze513 1:94c648931f84 789 clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */
Blaze513 1:94c648931f84 790 if (clst == 0) return FR_DENIED; /* No free cluster */
Blaze513 1:94c648931f84 791 if (clst == 1) return FR_INT_ERR;
Blaze513 1:94c648931f84 792 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
Blaze513 1:94c648931f84 793 /* Clean-up stretched table */
Blaze513 1:94c648931f84 794 if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
Blaze513 1:94c648931f84 795 mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
Blaze513 1:94c648931f84 796 dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
Blaze513 1:94c648931f84 797 for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
Blaze513 1:94c648931f84 798 dj->fs->wflag = 1;
Blaze513 1:94c648931f84 799 if (move_window(dj->fs, 0)) return FR_DISK_ERR;
Blaze513 1:94c648931f84 800 dj->fs->winsect++;
Blaze513 1:94c648931f84 801 }
Blaze513 1:94c648931f84 802 dj->fs->winsect -= c; /* Rewind window address */
Blaze513 1:94c648931f84 803 #else
Blaze513 1:94c648931f84 804 return FR_NO_FILE; /* Report EOT */
Blaze513 1:94c648931f84 805 #endif
Blaze513 1:94c648931f84 806 }
Blaze513 1:94c648931f84 807 dj->clust = clst; /* Initialize data for new cluster */
Blaze513 1:94c648931f84 808 dj->sect = clust2sect(dj->fs, clst);
Blaze513 1:94c648931f84 809 }
Blaze513 1:94c648931f84 810 }
Blaze513 1:94c648931f84 811 }
Blaze513 1:94c648931f84 812
Blaze513 1:94c648931f84 813 dj->index = i;
Blaze513 1:94c648931f84 814 dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
Blaze513 1:94c648931f84 815
Blaze513 1:94c648931f84 816 return FR_OK;
Blaze513 1:94c648931f84 817 }
Blaze513 1:94c648931f84 818
Blaze513 1:94c648931f84 819
Blaze513 1:94c648931f84 820
Blaze513 1:94c648931f84 821
Blaze513 1:94c648931f84 822 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 823 /* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
Blaze513 1:94c648931f84 824 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 825 #if _USE_LFN
Blaze513 1:94c648931f84 826 static
Blaze513 1:94c648931f84 827 const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
Blaze513 1:94c648931f84 828
Blaze513 1:94c648931f84 829
Blaze513 1:94c648931f84 830 static
Blaze513 1:94c648931f84 831 int cmp_lfn ( /* 1:Matched, 0:Not matched */
Blaze513 1:94c648931f84 832 WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
Blaze513 1:94c648931f84 833 BYTE *dir /* Pointer to the directory entry containing a part of LFN */
Blaze513 1:94c648931f84 834 )
Blaze513 1:94c648931f84 835 {
Blaze513 1:94c648931f84 836 int i, s;
Blaze513 1:94c648931f84 837 WCHAR wc, uc;
Blaze513 1:94c648931f84 838
Blaze513 1:94c648931f84 839
Blaze513 1:94c648931f84 840 i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */
Blaze513 1:94c648931f84 841 s = 0; wc = 1;
Blaze513 1:94c648931f84 842 do {
Blaze513 1:94c648931f84 843 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
Blaze513 1:94c648931f84 844 if (wc) { /* Last char has not been processed */
Blaze513 1:94c648931f84 845 wc = ff_wtoupper(uc); /* Convert it to upper case */
Blaze513 1:94c648931f84 846 if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
Blaze513 1:94c648931f84 847 return 0; /* Not matched */
Blaze513 1:94c648931f84 848 } else {
Blaze513 1:94c648931f84 849 if (uc != 0xFFFF) return 0; /* Check filler */
Blaze513 1:94c648931f84 850 }
Blaze513 1:94c648931f84 851 } while (++s < 13); /* Repeat until all chars in the entry are checked */
Blaze513 1:94c648931f84 852
Blaze513 1:94c648931f84 853 if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */
Blaze513 1:94c648931f84 854 return 0;
Blaze513 1:94c648931f84 855
Blaze513 1:94c648931f84 856 return 1; /* The part of LFN matched */
Blaze513 1:94c648931f84 857 }
Blaze513 1:94c648931f84 858
Blaze513 1:94c648931f84 859
Blaze513 1:94c648931f84 860
Blaze513 1:94c648931f84 861 static
Blaze513 1:94c648931f84 862 int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
Blaze513 1:94c648931f84 863 WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
Blaze513 1:94c648931f84 864 BYTE *dir /* Pointer to the directory entry */
Blaze513 1:94c648931f84 865 )
Blaze513 1:94c648931f84 866 {
Blaze513 1:94c648931f84 867 int i, s;
Blaze513 1:94c648931f84 868 WCHAR wc, uc;
Blaze513 1:94c648931f84 869
Blaze513 1:94c648931f84 870
Blaze513 1:94c648931f84 871 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
Blaze513 1:94c648931f84 872
Blaze513 1:94c648931f84 873 s = 0; wc = 1;
Blaze513 1:94c648931f84 874 do {
Blaze513 1:94c648931f84 875 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
Blaze513 1:94c648931f84 876 if (wc) { /* Last char has not been processed */
Blaze513 1:94c648931f84 877 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
Blaze513 1:94c648931f84 878 lfnbuf[i++] = wc = uc; /* Store it */
Blaze513 1:94c648931f84 879 } else {
Blaze513 1:94c648931f84 880 if (uc != 0xFFFF) return 0; /* Check filler */
Blaze513 1:94c648931f84 881 }
Blaze513 1:94c648931f84 882 } while (++s < 13); /* Read all character in the entry */
Blaze513 1:94c648931f84 883
Blaze513 1:94c648931f84 884 if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */
Blaze513 1:94c648931f84 885 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
Blaze513 1:94c648931f84 886 lfnbuf[i] = 0;
Blaze513 1:94c648931f84 887 }
Blaze513 1:94c648931f84 888
Blaze513 1:94c648931f84 889 return 1;
Blaze513 1:94c648931f84 890 }
Blaze513 1:94c648931f84 891
Blaze513 1:94c648931f84 892
Blaze513 1:94c648931f84 893 #if !_FS_READONLY
Blaze513 1:94c648931f84 894 static
Blaze513 1:94c648931f84 895 void fit_lfn (
Blaze513 1:94c648931f84 896 const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
Blaze513 1:94c648931f84 897 BYTE *dir, /* Pointer to the directory entry */
Blaze513 1:94c648931f84 898 BYTE ord, /* LFN order (1-20) */
Blaze513 1:94c648931f84 899 BYTE sum /* SFN sum */
Blaze513 1:94c648931f84 900 )
Blaze513 1:94c648931f84 901 {
Blaze513 1:94c648931f84 902 int i, s;
Blaze513 1:94c648931f84 903 WCHAR wc;
Blaze513 1:94c648931f84 904
Blaze513 1:94c648931f84 905
Blaze513 1:94c648931f84 906 dir[LDIR_Chksum] = sum; /* Set check sum */
Blaze513 1:94c648931f84 907 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
Blaze513 1:94c648931f84 908 dir[LDIR_Type] = 0;
Blaze513 1:94c648931f84 909 ST_WORD(dir+LDIR_FstClusLO, 0);
Blaze513 1:94c648931f84 910
Blaze513 1:94c648931f84 911 i = (ord - 1) * 13; /* Get offset in the LFN buffer */
Blaze513 1:94c648931f84 912 s = wc = 0;
Blaze513 1:94c648931f84 913 do {
Blaze513 1:94c648931f84 914 if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
Blaze513 1:94c648931f84 915 ST_WORD(dir+LfnOfs[s], wc); /* Put it */
Blaze513 1:94c648931f84 916 if (!wc) wc = 0xFFFF; /* Padding chars following last char */
Blaze513 1:94c648931f84 917 } while (++s < 13);
Blaze513 1:94c648931f84 918 if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40; /* Bottom LFN part is the start of LFN sequence */
Blaze513 1:94c648931f84 919 dir[LDIR_Ord] = ord; /* Set the LFN order */
Blaze513 1:94c648931f84 920 }
Blaze513 1:94c648931f84 921
Blaze513 1:94c648931f84 922 #endif
Blaze513 1:94c648931f84 923 #endif
Blaze513 1:94c648931f84 924
Blaze513 1:94c648931f84 925
Blaze513 1:94c648931f84 926
Blaze513 1:94c648931f84 927 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 928 /* Create numbered name */
Blaze513 1:94c648931f84 929 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 930 #if _USE_LFN
Blaze513 1:94c648931f84 931 void gen_numname (
Blaze513 1:94c648931f84 932 BYTE *dst, /* Pointer to generated SFN */
Blaze513 1:94c648931f84 933 const BYTE *src, /* Pointer to source SFN to be modified */
Blaze513 1:94c648931f84 934 const WCHAR *lfn, /* Pointer to LFN */
Blaze513 1:94c648931f84 935 WORD seq /* Sequence number */
Blaze513 1:94c648931f84 936 )
Blaze513 1:94c648931f84 937 {
Blaze513 1:94c648931f84 938 BYTE ns[8], c;
Blaze513 1:94c648931f84 939 int i, j;
Blaze513 1:94c648931f84 940
Blaze513 1:94c648931f84 941
Blaze513 1:94c648931f84 942 mem_cpy(dst, src, 11);
Blaze513 1:94c648931f84 943
Blaze513 1:94c648931f84 944 if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
Blaze513 1:94c648931f84 945 do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
Blaze513 1:94c648931f84 946 }
Blaze513 1:94c648931f84 947
Blaze513 1:94c648931f84 948 /* itoa */
Blaze513 1:94c648931f84 949 i = 7;
Blaze513 1:94c648931f84 950 do {
Blaze513 1:94c648931f84 951 c = (seq % 16) + '0';
Blaze513 1:94c648931f84 952 if (c > '9') c += 7;
Blaze513 1:94c648931f84 953 ns[i--] = c;
Blaze513 1:94c648931f84 954 seq /= 16;
Blaze513 1:94c648931f84 955 } while (seq);
Blaze513 1:94c648931f84 956 ns[i] = '~';
Blaze513 1:94c648931f84 957
Blaze513 1:94c648931f84 958 /* Append the number */
Blaze513 1:94c648931f84 959 for (j = 0; j < i && dst[j] != ' '; j++) {
Blaze513 1:94c648931f84 960 if (IsDBCS1(dst[j])) {
Blaze513 1:94c648931f84 961 if (j == i - 1) break;
Blaze513 1:94c648931f84 962 j++;
Blaze513 1:94c648931f84 963 }
Blaze513 1:94c648931f84 964 }
Blaze513 1:94c648931f84 965 do {
Blaze513 1:94c648931f84 966 dst[j++] = (i < 8) ? ns[i++] : ' ';
Blaze513 1:94c648931f84 967 } while (j < 8);
Blaze513 1:94c648931f84 968 }
Blaze513 1:94c648931f84 969 #endif
Blaze513 1:94c648931f84 970
Blaze513 1:94c648931f84 971
Blaze513 1:94c648931f84 972
Blaze513 1:94c648931f84 973
Blaze513 1:94c648931f84 974 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 975 /* Calculate sum of an SFN */
Blaze513 1:94c648931f84 976 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 977 #if _USE_LFN
Blaze513 1:94c648931f84 978 static
Blaze513 1:94c648931f84 979 BYTE sum_sfn (
Blaze513 1:94c648931f84 980 const BYTE *dir /* Ptr to directory entry */
Blaze513 1:94c648931f84 981 )
Blaze513 1:94c648931f84 982 {
Blaze513 1:94c648931f84 983 BYTE sum = 0;
Blaze513 1:94c648931f84 984 int n = 11;
Blaze513 1:94c648931f84 985
Blaze513 1:94c648931f84 986 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
Blaze513 1:94c648931f84 987 return sum;
Blaze513 1:94c648931f84 988 }
Blaze513 1:94c648931f84 989 #endif
Blaze513 1:94c648931f84 990
Blaze513 1:94c648931f84 991
Blaze513 1:94c648931f84 992
Blaze513 1:94c648931f84 993
Blaze513 1:94c648931f84 994 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 995 /* Directory handling - Find an object in the directory */
Blaze513 1:94c648931f84 996 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 997
Blaze513 1:94c648931f84 998 static
Blaze513 1:94c648931f84 999 FRESULT dir_find (
Blaze513 1:94c648931f84 1000 FAT_DIR *dj /* Pointer to the directory object linked to the file name */
Blaze513 1:94c648931f84 1001 )
Blaze513 1:94c648931f84 1002 {
Blaze513 1:94c648931f84 1003 FRESULT res;
Blaze513 1:94c648931f84 1004 BYTE c, *dir;
Blaze513 1:94c648931f84 1005 #if _USE_LFN
Blaze513 1:94c648931f84 1006 BYTE a, ord, sum;
Blaze513 1:94c648931f84 1007 #endif
Blaze513 1:94c648931f84 1008
Blaze513 1:94c648931f84 1009 res = dir_sdi(dj, 0); /* Rewind directory object */
Blaze513 1:94c648931f84 1010 if (res != FR_OK) return res;
Blaze513 1:94c648931f84 1011
Blaze513 1:94c648931f84 1012 #if _USE_LFN
Blaze513 1:94c648931f84 1013 ord = sum = 0xFF;
Blaze513 1:94c648931f84 1014 #endif
Blaze513 1:94c648931f84 1015 do {
Blaze513 1:94c648931f84 1016 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1017 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1018 dir = dj->dir; /* Ptr to the directory entry of current index */
Blaze513 1:94c648931f84 1019 c = dir[DIR_Name];
Blaze513 1:94c648931f84 1020 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
Blaze513 1:94c648931f84 1021 #if _USE_LFN /* LFN configuration */
Blaze513 1:94c648931f84 1022 a = dir[DIR_Attr] & AM_MASK;
Blaze513 1:94c648931f84 1023 if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
Blaze513 1:94c648931f84 1024 ord = 0xFF;
Blaze513 1:94c648931f84 1025 } else {
Blaze513 1:94c648931f84 1026 if (a == AM_LFN) { /* An LFN entry is found */
Blaze513 1:94c648931f84 1027 if (dj->lfn) {
Blaze513 1:94c648931f84 1028 if (c & 0x40) { /* Is it start of LFN sequence? */
Blaze513 1:94c648931f84 1029 sum = dir[LDIR_Chksum];
Blaze513 1:94c648931f84 1030 c &= 0xBF; ord = c; /* LFN start order */
Blaze513 1:94c648931f84 1031 dj->lfn_idx = dj->index;
Blaze513 1:94c648931f84 1032 }
Blaze513 1:94c648931f84 1033 /* Check validity of the LFN entry and compare it with given name */
Blaze513 1:94c648931f84 1034 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
Blaze513 1:94c648931f84 1035 }
Blaze513 1:94c648931f84 1036 } else { /* An SFN entry is found */
Blaze513 1:94c648931f84 1037 if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
Blaze513 1:94c648931f84 1038 ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
Blaze513 1:94c648931f84 1039 if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
Blaze513 1:94c648931f84 1040 }
Blaze513 1:94c648931f84 1041 }
Blaze513 1:94c648931f84 1042 #else /* Non LFN configuration */
Blaze513 1:94c648931f84 1043 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
Blaze513 1:94c648931f84 1044 break;
Blaze513 1:94c648931f84 1045 #endif
Blaze513 1:94c648931f84 1046 res = dir_next(dj, 0); /* Next entry */
Blaze513 1:94c648931f84 1047 } while (res == FR_OK);
Blaze513 1:94c648931f84 1048
Blaze513 1:94c648931f84 1049 return res;
Blaze513 1:94c648931f84 1050 }
Blaze513 1:94c648931f84 1051
Blaze513 1:94c648931f84 1052
Blaze513 1:94c648931f84 1053
Blaze513 1:94c648931f84 1054
Blaze513 1:94c648931f84 1055 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1056 /* Read an object from the directory */
Blaze513 1:94c648931f84 1057 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1058 #if _FS_MINIMIZE <= 1
Blaze513 1:94c648931f84 1059 static
Blaze513 1:94c648931f84 1060 FRESULT dir_read (
Blaze513 1:94c648931f84 1061 FAT_DIR *dj /* Pointer to the directory object that pointing the entry to be read */
Blaze513 1:94c648931f84 1062 )
Blaze513 1:94c648931f84 1063 {
Blaze513 1:94c648931f84 1064 FRESULT res;
Blaze513 1:94c648931f84 1065 BYTE c, *dir;
Blaze513 1:94c648931f84 1066 #if _USE_LFN
Blaze513 1:94c648931f84 1067 BYTE a, ord = 0xFF, sum = 0xFF;
Blaze513 1:94c648931f84 1068 #endif
Blaze513 1:94c648931f84 1069
Blaze513 1:94c648931f84 1070 res = FR_NO_FILE;
Blaze513 1:94c648931f84 1071 while (dj->sect) {
Blaze513 1:94c648931f84 1072 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1073 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1074 dir = dj->dir; /* Ptr to the directory entry of current index */
Blaze513 1:94c648931f84 1075 c = dir[DIR_Name];
Blaze513 1:94c648931f84 1076 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
Blaze513 1:94c648931f84 1077 #if _USE_LFN /* LFN configuration */
Blaze513 1:94c648931f84 1078 a = dir[DIR_Attr] & AM_MASK;
Blaze513 1:94c648931f84 1079 if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
Blaze513 1:94c648931f84 1080 ord = 0xFF;
Blaze513 1:94c648931f84 1081 } else {
Blaze513 1:94c648931f84 1082 if (a == AM_LFN) { /* An LFN entry is found */
Blaze513 1:94c648931f84 1083 if (c & 0x40) { /* Is it start of LFN sequence? */
Blaze513 1:94c648931f84 1084 sum = dir[LDIR_Chksum];
Blaze513 1:94c648931f84 1085 c &= 0xBF; ord = c;
Blaze513 1:94c648931f84 1086 dj->lfn_idx = dj->index;
Blaze513 1:94c648931f84 1087 }
Blaze513 1:94c648931f84 1088 /* Check LFN validity and capture it */
Blaze513 1:94c648931f84 1089 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
Blaze513 1:94c648931f84 1090 } else { /* An SFN entry is found */
Blaze513 1:94c648931f84 1091 if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
Blaze513 1:94c648931f84 1092 dj->lfn_idx = 0xFFFF; /* It has no LFN. */
Blaze513 1:94c648931f84 1093 break;
Blaze513 1:94c648931f84 1094 }
Blaze513 1:94c648931f84 1095 }
Blaze513 1:94c648931f84 1096 #else /* Non LFN configuration */
Blaze513 1:94c648931f84 1097 if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
Blaze513 1:94c648931f84 1098 break;
Blaze513 1:94c648931f84 1099 #endif
Blaze513 1:94c648931f84 1100 res = dir_next(dj, 0); /* Next entry */
Blaze513 1:94c648931f84 1101 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1102 }
Blaze513 1:94c648931f84 1103
Blaze513 1:94c648931f84 1104 if (res != FR_OK) dj->sect = 0;
Blaze513 1:94c648931f84 1105
Blaze513 1:94c648931f84 1106 return res;
Blaze513 1:94c648931f84 1107 }
Blaze513 1:94c648931f84 1108 #endif
Blaze513 1:94c648931f84 1109
Blaze513 1:94c648931f84 1110
Blaze513 1:94c648931f84 1111
Blaze513 1:94c648931f84 1112 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1113 /* Register an object to the directory */
Blaze513 1:94c648931f84 1114 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1115 #if !_FS_READONLY
Blaze513 1:94c648931f84 1116 static
Blaze513 1:94c648931f84 1117 FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
Blaze513 1:94c648931f84 1118 FAT_DIR *dj /* Target directory with object name to be created */
Blaze513 1:94c648931f84 1119 )
Blaze513 1:94c648931f84 1120 {
Blaze513 1:94c648931f84 1121 FRESULT res;
Blaze513 1:94c648931f84 1122 BYTE c, *dir;
Blaze513 1:94c648931f84 1123 #if _USE_LFN /* LFN configuration */
Blaze513 1:94c648931f84 1124 WORD n, ne, is;
Blaze513 1:94c648931f84 1125 BYTE sn[12], *fn, sum;
Blaze513 1:94c648931f84 1126 WCHAR *lfn;
Blaze513 1:94c648931f84 1127
Blaze513 1:94c648931f84 1128
Blaze513 1:94c648931f84 1129 fn = dj->fn; lfn = dj->lfn;
Blaze513 1:94c648931f84 1130 mem_cpy(sn, fn, 12);
Blaze513 1:94c648931f84 1131
Blaze513 1:94c648931f84 1132 if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME; /* Cannot create dot entry */
Blaze513 1:94c648931f84 1133
Blaze513 1:94c648931f84 1134 if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
Blaze513 1:94c648931f84 1135 fn[NS] = 0; dj->lfn = 0; /* Find only SFN */
Blaze513 1:94c648931f84 1136 for (n = 1; n < 100; n++) {
Blaze513 1:94c648931f84 1137 gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
Blaze513 1:94c648931f84 1138 res = dir_find(dj); /* Check if the name collides with existing SFN */
Blaze513 1:94c648931f84 1139 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1140 }
Blaze513 1:94c648931f84 1141 if (n == 100) return FR_DENIED; /* Abort if too many collisions */
Blaze513 1:94c648931f84 1142 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
Blaze513 1:94c648931f84 1143 fn[NS] = sn[NS]; dj->lfn = lfn;
Blaze513 1:94c648931f84 1144 }
Blaze513 1:94c648931f84 1145
Blaze513 1:94c648931f84 1146 if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve an SFN + LFN entries. */
Blaze513 1:94c648931f84 1147 for (ne = 0; lfn[ne]; ne++) ;
Blaze513 1:94c648931f84 1148 ne = (ne + 25) / 13;
Blaze513 1:94c648931f84 1149 } else { /* Otherwise reserve only an SFN entry. */
Blaze513 1:94c648931f84 1150 ne = 1;
Blaze513 1:94c648931f84 1151 }
Blaze513 1:94c648931f84 1152
Blaze513 1:94c648931f84 1153 /* Reserve contiguous entries */
Blaze513 1:94c648931f84 1154 res = dir_sdi(dj, 0);
Blaze513 1:94c648931f84 1155 if (res != FR_OK) return res;
Blaze513 1:94c648931f84 1156 n = is = 0;
Blaze513 1:94c648931f84 1157 do {
Blaze513 1:94c648931f84 1158 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1159 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1160 c = *dj->dir; /* Check the entry status */
Blaze513 1:94c648931f84 1161 if (c == 0xE5 || c == 0) { /* Is it a blank entry? */
Blaze513 1:94c648931f84 1162 if (n == 0) is = dj->index; /* First index of the contiguous entry */
Blaze513 1:94c648931f84 1163 if (++n == ne) break; /* A contiguous entry that required count is found */
Blaze513 1:94c648931f84 1164 } else {
Blaze513 1:94c648931f84 1165 n = 0; /* Not a blank entry. Restart to search */
Blaze513 1:94c648931f84 1166 }
Blaze513 1:94c648931f84 1167 res = dir_next(dj, 1); /* Next entry with table stretch */
Blaze513 1:94c648931f84 1168 } while (res == FR_OK);
Blaze513 1:94c648931f84 1169
Blaze513 1:94c648931f84 1170 if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
Blaze513 1:94c648931f84 1171 res = dir_sdi(dj, is);
Blaze513 1:94c648931f84 1172 if (res == FR_OK) {
Blaze513 1:94c648931f84 1173 sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
Blaze513 1:94c648931f84 1174 ne--;
Blaze513 1:94c648931f84 1175 do { /* Store LFN entries in bottom first */
Blaze513 1:94c648931f84 1176 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1177 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1178 fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
Blaze513 1:94c648931f84 1179 dj->fs->wflag = 1;
Blaze513 1:94c648931f84 1180 res = dir_next(dj, 0); /* Next entry */
Blaze513 1:94c648931f84 1181 } while (res == FR_OK && --ne);
Blaze513 1:94c648931f84 1182 }
Blaze513 1:94c648931f84 1183 }
Blaze513 1:94c648931f84 1184
Blaze513 1:94c648931f84 1185 #else /* Non LFN configuration */
Blaze513 1:94c648931f84 1186 res = dir_sdi(dj, 0);
Blaze513 1:94c648931f84 1187 if (res == FR_OK) {
Blaze513 1:94c648931f84 1188 do { /* Find a blank entry for the SFN */
Blaze513 1:94c648931f84 1189 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1190 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1191 c = *dj->dir;
Blaze513 1:94c648931f84 1192 if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */
Blaze513 1:94c648931f84 1193 res = dir_next(dj, 1); /* Next entry with table stretch */
Blaze513 1:94c648931f84 1194 } while (res == FR_OK);
Blaze513 1:94c648931f84 1195 }
Blaze513 1:94c648931f84 1196 #endif
Blaze513 1:94c648931f84 1197
Blaze513 1:94c648931f84 1198 if (res == FR_OK) { /* Initialize the SFN entry */
Blaze513 1:94c648931f84 1199 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1200 if (res == FR_OK) {
Blaze513 1:94c648931f84 1201 dir = dj->dir;
Blaze513 1:94c648931f84 1202 mem_set(dir, 0, 32); /* Clean the entry */
Blaze513 1:94c648931f84 1203 mem_cpy(dir, dj->fn, 11); /* Put SFN */
Blaze513 1:94c648931f84 1204 #if _USE_LFN
Blaze513 1:94c648931f84 1205 dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
Blaze513 1:94c648931f84 1206 #endif
Blaze513 1:94c648931f84 1207 dj->fs->wflag = 1;
Blaze513 1:94c648931f84 1208 }
Blaze513 1:94c648931f84 1209 }
Blaze513 1:94c648931f84 1210
Blaze513 1:94c648931f84 1211 return res;
Blaze513 1:94c648931f84 1212 }
Blaze513 1:94c648931f84 1213 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 1214
Blaze513 1:94c648931f84 1215
Blaze513 1:94c648931f84 1216
Blaze513 1:94c648931f84 1217
Blaze513 1:94c648931f84 1218 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1219 /* Remove an object from the directory */
Blaze513 1:94c648931f84 1220 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1221 #if !_FS_READONLY && !_FS_MINIMIZE
Blaze513 1:94c648931f84 1222 static
Blaze513 1:94c648931f84 1223 FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
Blaze513 1:94c648931f84 1224 FAT_DIR *dj /* Directory object pointing the entry to be removed */
Blaze513 1:94c648931f84 1225 )
Blaze513 1:94c648931f84 1226 {
Blaze513 1:94c648931f84 1227 FRESULT res;
Blaze513 1:94c648931f84 1228 #if _USE_LFN /* LFN configuration */
Blaze513 1:94c648931f84 1229 WORD i;
Blaze513 1:94c648931f84 1230
Blaze513 1:94c648931f84 1231 i = dj->index; /* SFN index */
Blaze513 1:94c648931f84 1232 res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
Blaze513 1:94c648931f84 1233 if (res == FR_OK) {
Blaze513 1:94c648931f84 1234 do {
Blaze513 1:94c648931f84 1235 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1236 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1237 *dj->dir = 0xE5; /* Mark the entry "deleted" */
Blaze513 1:94c648931f84 1238 dj->fs->wflag = 1;
Blaze513 1:94c648931f84 1239 if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
Blaze513 1:94c648931f84 1240 res = dir_next(dj, 0); /* Next entry */
Blaze513 1:94c648931f84 1241 } while (res == FR_OK);
Blaze513 1:94c648931f84 1242 if (res == FR_NO_FILE) res = FR_INT_ERR;
Blaze513 1:94c648931f84 1243 }
Blaze513 1:94c648931f84 1244
Blaze513 1:94c648931f84 1245 #else /* Non LFN configuration */
Blaze513 1:94c648931f84 1246 res = dir_sdi(dj, dj->index);
Blaze513 1:94c648931f84 1247 if (res == FR_OK) {
Blaze513 1:94c648931f84 1248 res = move_window(dj->fs, dj->sect);
Blaze513 1:94c648931f84 1249 if (res == FR_OK) {
Blaze513 1:94c648931f84 1250 *dj->dir = 0xE5; /* Mark the entry "deleted" */
Blaze513 1:94c648931f84 1251 dj->fs->wflag = 1;
Blaze513 1:94c648931f84 1252 }
Blaze513 1:94c648931f84 1253 }
Blaze513 1:94c648931f84 1254 #endif
Blaze513 1:94c648931f84 1255
Blaze513 1:94c648931f84 1256 return res;
Blaze513 1:94c648931f84 1257 }
Blaze513 1:94c648931f84 1258 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 1259
Blaze513 1:94c648931f84 1260
Blaze513 1:94c648931f84 1261
Blaze513 1:94c648931f84 1262
Blaze513 1:94c648931f84 1263 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1264 /* Pick a segment and create the object name in directory form */
Blaze513 1:94c648931f84 1265 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1266
Blaze513 1:94c648931f84 1267 static
Blaze513 1:94c648931f84 1268 FRESULT create_name (
Blaze513 1:94c648931f84 1269 FAT_DIR *dj, /* Pointer to the directory object */
Blaze513 1:94c648931f84 1270 const TCHAR **path /* Pointer to pointer to the segment in the path string */
Blaze513 1:94c648931f84 1271 )
Blaze513 1:94c648931f84 1272 {
Blaze513 1:94c648931f84 1273 #ifdef _EXCVT
Blaze513 1:94c648931f84 1274 static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
Blaze513 1:94c648931f84 1275 #endif
Blaze513 1:94c648931f84 1276
Blaze513 1:94c648931f84 1277 #if _USE_LFN /* LFN configuration */
Blaze513 1:94c648931f84 1278 BYTE b, cf;
Blaze513 1:94c648931f84 1279 WCHAR w, *lfn;
Blaze513 1:94c648931f84 1280 int i, ni, si, di;
Blaze513 1:94c648931f84 1281 const TCHAR *p;
Blaze513 1:94c648931f84 1282
Blaze513 1:94c648931f84 1283 /* Create LFN in Unicode */
Blaze513 1:94c648931f84 1284 si = di = 0;
Blaze513 1:94c648931f84 1285 p = *path;
Blaze513 1:94c648931f84 1286 lfn = dj->lfn;
Blaze513 1:94c648931f84 1287 for (;;) {
Blaze513 1:94c648931f84 1288 w = p[si++]; /* Get a character */
Blaze513 1:94c648931f84 1289 if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
Blaze513 1:94c648931f84 1290 if (di >= _MAX_LFN) /* Reject too long name */
Blaze513 1:94c648931f84 1291 return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1292 #if !_LFN_UNICODE
Blaze513 1:94c648931f84 1293 w &= 0xFF;
Blaze513 1:94c648931f84 1294 if (IsDBCS1(w)) { /* If it is a DBC 1st byte */
Blaze513 1:94c648931f84 1295 b = p[si++]; /* Get 2nd byte */
Blaze513 1:94c648931f84 1296 if (!IsDBCS2(b)) /* Reject invalid code for DBC */
Blaze513 1:94c648931f84 1297 return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1298 w = (w << 8) + b;
Blaze513 1:94c648931f84 1299 }
Blaze513 1:94c648931f84 1300 w = ff_convert(w, 1); /* Convert OEM to Unicode */
Blaze513 1:94c648931f84 1301 if (!w) return FR_INVALID_NAME; /* Reject invalid code */
Blaze513 1:94c648931f84 1302 #endif
Blaze513 1:94c648931f84 1303 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
Blaze513 1:94c648931f84 1304 return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1305 lfn[di++] = w; /* Store the Unicode char */
Blaze513 1:94c648931f84 1306 }
Blaze513 1:94c648931f84 1307 *path = &p[si]; /* Return pointer to the next segment */
Blaze513 1:94c648931f84 1308 cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
Blaze513 1:94c648931f84 1309 #if _FS_RPATH
Blaze513 1:94c648931f84 1310 if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
Blaze513 1:94c648931f84 1311 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
Blaze513 1:94c648931f84 1312 lfn[di] = 0;
Blaze513 1:94c648931f84 1313 for (i = 0; i < 11; i++)
Blaze513 1:94c648931f84 1314 dj->fn[i] = (i < di) ? '.' : ' ';
Blaze513 1:94c648931f84 1315 dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
Blaze513 1:94c648931f84 1316 return FR_OK;
Blaze513 1:94c648931f84 1317 }
Blaze513 1:94c648931f84 1318 #endif
Blaze513 1:94c648931f84 1319 while (di) { /* Strip trailing spaces and dots */
Blaze513 1:94c648931f84 1320 w = lfn[di - 1];
Blaze513 1:94c648931f84 1321 if (w != ' ' && w != '.') break;
Blaze513 1:94c648931f84 1322 di--;
Blaze513 1:94c648931f84 1323 }
Blaze513 1:94c648931f84 1324 if (!di) return FR_INVALID_NAME; /* Reject nul string */
Blaze513 1:94c648931f84 1325
Blaze513 1:94c648931f84 1326 lfn[di] = 0; /* LFN is created */
Blaze513 1:94c648931f84 1327
Blaze513 1:94c648931f84 1328 /* Create SFN in directory form */
Blaze513 1:94c648931f84 1329 mem_set(dj->fn, ' ', 11);
Blaze513 1:94c648931f84 1330 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
Blaze513 1:94c648931f84 1331 if (si) cf |= NS_LOSS | NS_LFN;
Blaze513 1:94c648931f84 1332 while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
Blaze513 1:94c648931f84 1333
Blaze513 1:94c648931f84 1334 b = i = 0; ni = 8;
Blaze513 1:94c648931f84 1335 for (;;) {
Blaze513 1:94c648931f84 1336 w = lfn[si++]; /* Get an LFN char */
Blaze513 1:94c648931f84 1337 if (!w) break; /* Break on end of the LFN */
Blaze513 1:94c648931f84 1338 if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
Blaze513 1:94c648931f84 1339 cf |= NS_LOSS | NS_LFN; continue;
Blaze513 1:94c648931f84 1340 }
Blaze513 1:94c648931f84 1341
Blaze513 1:94c648931f84 1342 if (i >= ni || si == di) { /* Extension or end of SFN */
Blaze513 1:94c648931f84 1343 if (ni == 11) { /* Long extension */
Blaze513 1:94c648931f84 1344 cf |= NS_LOSS | NS_LFN; break;
Blaze513 1:94c648931f84 1345 }
Blaze513 1:94c648931f84 1346 if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
Blaze513 1:94c648931f84 1347 if (si > di) break; /* No extension */
Blaze513 1:94c648931f84 1348 si = di; i = 8; ni = 11; /* Enter extension section */
Blaze513 1:94c648931f84 1349 b <<= 2; continue;
Blaze513 1:94c648931f84 1350 }
Blaze513 1:94c648931f84 1351
Blaze513 1:94c648931f84 1352 if (w >= 0x80) { /* Non ASCII char */
Blaze513 1:94c648931f84 1353 #ifdef _EXCVT
Blaze513 1:94c648931f84 1354 w = ff_convert(w, 0); /* Unicode -> OEM code */
Blaze513 1:94c648931f84 1355 if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
Blaze513 1:94c648931f84 1356 #else
Blaze513 1:94c648931f84 1357 w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
Blaze513 1:94c648931f84 1358 #endif
Blaze513 1:94c648931f84 1359 cf |= NS_LFN; /* Force create LFN entry */
Blaze513 1:94c648931f84 1360 }
Blaze513 1:94c648931f84 1361
Blaze513 1:94c648931f84 1362 if (_DF1S && w >= 0x100) { /* Double byte char */
Blaze513 1:94c648931f84 1363 if (i >= ni - 1) {
Blaze513 1:94c648931f84 1364 cf |= NS_LOSS | NS_LFN; i = ni; continue;
Blaze513 1:94c648931f84 1365 }
Blaze513 1:94c648931f84 1366 dj->fn[i++] = (BYTE)(w >> 8);
Blaze513 1:94c648931f84 1367 } else { /* Single byte char */
Blaze513 1:94c648931f84 1368 if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */
Blaze513 1:94c648931f84 1369 w = '_'; cf |= NS_LOSS | NS_LFN; /* Lossy conversion */
Blaze513 1:94c648931f84 1370 } else {
Blaze513 1:94c648931f84 1371 if (IsUpper(w)) { /* ASCII large capital */
Blaze513 1:94c648931f84 1372 b |= 2;
Blaze513 1:94c648931f84 1373 } else {
Blaze513 1:94c648931f84 1374 if (IsLower(w)) { /* ASCII small capital */
Blaze513 1:94c648931f84 1375 b |= 1; w -= 0x20;
Blaze513 1:94c648931f84 1376 }
Blaze513 1:94c648931f84 1377 }
Blaze513 1:94c648931f84 1378 }
Blaze513 1:94c648931f84 1379 }
Blaze513 1:94c648931f84 1380 dj->fn[i++] = (BYTE)w;
Blaze513 1:94c648931f84 1381 }
Blaze513 1:94c648931f84 1382
Blaze513 1:94c648931f84 1383 if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05; /* If the first char collides with deleted mark, replace it with 0x05 */
Blaze513 1:94c648931f84 1384
Blaze513 1:94c648931f84 1385 if (ni == 8) b <<= 2;
Blaze513 1:94c648931f84 1386 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
Blaze513 1:94c648931f84 1387 cf |= NS_LFN;
Blaze513 1:94c648931f84 1388 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
Blaze513 1:94c648931f84 1389 if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
Blaze513 1:94c648931f84 1390 if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
Blaze513 1:94c648931f84 1391 }
Blaze513 1:94c648931f84 1392
Blaze513 1:94c648931f84 1393 dj->fn[NS] = cf; /* SFN is created */
Blaze513 1:94c648931f84 1394
Blaze513 1:94c648931f84 1395 return FR_OK;
Blaze513 1:94c648931f84 1396
Blaze513 1:94c648931f84 1397
Blaze513 1:94c648931f84 1398 #else /* Non-LFN configuration */
Blaze513 1:94c648931f84 1399 BYTE b, c, d, *sfn;
Blaze513 1:94c648931f84 1400 int ni, si, i;
Blaze513 1:94c648931f84 1401 const char *p;
Blaze513 1:94c648931f84 1402
Blaze513 1:94c648931f84 1403 /* Create file name in directory form */
Blaze513 1:94c648931f84 1404 sfn = dj->fn;
Blaze513 1:94c648931f84 1405 mem_set(sfn, ' ', 11);
Blaze513 1:94c648931f84 1406 si = i = b = 0; ni = 8;
Blaze513 1:94c648931f84 1407 p = *path;
Blaze513 1:94c648931f84 1408 #if _FS_RPATH
Blaze513 1:94c648931f84 1409 if (p[si] == '.') { /* Is this a dot entry? */
Blaze513 1:94c648931f84 1410 for (;;) {
Blaze513 1:94c648931f84 1411 c = (BYTE)p[si++];
Blaze513 1:94c648931f84 1412 if (c != '.' || si >= 3) break;
Blaze513 1:94c648931f84 1413 sfn[i++] = c;
Blaze513 1:94c648931f84 1414 }
Blaze513 1:94c648931f84 1415 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1416 *path = &p[si]; /* Return pointer to the next segment */
Blaze513 1:94c648931f84 1417 sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
Blaze513 1:94c648931f84 1418 return FR_OK;
Blaze513 1:94c648931f84 1419 }
Blaze513 1:94c648931f84 1420 #endif
Blaze513 1:94c648931f84 1421 for (;;) {
Blaze513 1:94c648931f84 1422 c = (BYTE)p[si++];
Blaze513 1:94c648931f84 1423 if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
Blaze513 1:94c648931f84 1424 if (c == '.' || i >= ni) {
Blaze513 1:94c648931f84 1425 if (ni != 8 || c != '.') return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1426 i = 8; ni = 11;
Blaze513 1:94c648931f84 1427 b <<= 2; continue;
Blaze513 1:94c648931f84 1428 }
Blaze513 1:94c648931f84 1429 if (c >= 0x80) { /* Extended char */
Blaze513 1:94c648931f84 1430 #ifdef _EXCVT
Blaze513 1:94c648931f84 1431 c = excvt[c - 0x80]; /* Convert extend char (SBCS) */
Blaze513 1:94c648931f84 1432 #else
Blaze513 1:94c648931f84 1433 b |= 3; /* Eliminate NT flag if extended char is exist */
Blaze513 1:94c648931f84 1434 #if !_DF1S /* ASCII only cfg */
Blaze513 1:94c648931f84 1435 return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1436 #endif
Blaze513 1:94c648931f84 1437 #endif
Blaze513 1:94c648931f84 1438 }
Blaze513 1:94c648931f84 1439 if (IsDBCS1(c)) { /* DBC 1st byte? */
Blaze513 1:94c648931f84 1440 d = (BYTE)p[si++]; /* Get 2nd byte */
Blaze513 1:94c648931f84 1441 if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
Blaze513 1:94c648931f84 1442 return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1443 sfn[i++] = c;
Blaze513 1:94c648931f84 1444 sfn[i++] = d;
Blaze513 1:94c648931f84 1445 } else { /* Single byte code */
Blaze513 1:94c648931f84 1446 if (chk_chr("\"*+,:<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
Blaze513 1:94c648931f84 1447 return FR_INVALID_NAME;
Blaze513 1:94c648931f84 1448 if (IsUpper(c)) { /* ASCII large capital? */
Blaze513 1:94c648931f84 1449 b |= 2;
Blaze513 1:94c648931f84 1450 } else {
Blaze513 1:94c648931f84 1451 if (IsLower(c)) { /* ASCII small capital? */
Blaze513 1:94c648931f84 1452 b |= 1; c -= 0x20;
Blaze513 1:94c648931f84 1453 }
Blaze513 1:94c648931f84 1454 }
Blaze513 1:94c648931f84 1455 sfn[i++] = c;
Blaze513 1:94c648931f84 1456 }
Blaze513 1:94c648931f84 1457 }
Blaze513 1:94c648931f84 1458 *path = &p[si]; /* Return pointer to the next segment */
Blaze513 1:94c648931f84 1459 c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
Blaze513 1:94c648931f84 1460
Blaze513 1:94c648931f84 1461 if (!i) return FR_INVALID_NAME; /* Reject nul string */
Blaze513 1:94c648931f84 1462 if (sfn[0] == 0xE5) sfn[0] = 0x05; /* When first char collides with 0xE5, replace it with 0x05 */
Blaze513 1:94c648931f84 1463
Blaze513 1:94c648931f84 1464 if (ni == 8) b <<= 2;
Blaze513 1:94c648931f84 1465 if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
Blaze513 1:94c648931f84 1466 if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
Blaze513 1:94c648931f84 1467
Blaze513 1:94c648931f84 1468 sfn[NS] = c; /* Store NT flag, File name is created */
Blaze513 1:94c648931f84 1469
Blaze513 1:94c648931f84 1470 return FR_OK;
Blaze513 1:94c648931f84 1471 #endif
Blaze513 1:94c648931f84 1472 }
Blaze513 1:94c648931f84 1473
Blaze513 1:94c648931f84 1474
Blaze513 1:94c648931f84 1475
Blaze513 1:94c648931f84 1476
Blaze513 1:94c648931f84 1477 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1478 /* Get file information from directory entry */
Blaze513 1:94c648931f84 1479 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1480 #if _FS_MINIMIZE <= 1
Blaze513 1:94c648931f84 1481 static
Blaze513 1:94c648931f84 1482 void get_fileinfo ( /* No return code */
Blaze513 1:94c648931f84 1483 FAT_DIR *dj, /* Pointer to the directory object */
Blaze513 1:94c648931f84 1484 FILINFO *fno /* Pointer to the file information to be filled */
Blaze513 1:94c648931f84 1485 )
Blaze513 1:94c648931f84 1486 {
Blaze513 1:94c648931f84 1487 int i;
Blaze513 1:94c648931f84 1488 BYTE nt, *dir;
Blaze513 1:94c648931f84 1489 TCHAR *p, c;
Blaze513 1:94c648931f84 1490
Blaze513 1:94c648931f84 1491
Blaze513 1:94c648931f84 1492 p = fno->fname;
Blaze513 1:94c648931f84 1493 if (dj->sect) {
Blaze513 1:94c648931f84 1494 dir = dj->dir;
Blaze513 1:94c648931f84 1495 nt = dir[DIR_NTres]; /* NT flag */
Blaze513 1:94c648931f84 1496 for (i = 0; i < 8; i++) { /* Copy name body */
Blaze513 1:94c648931f84 1497 c = dir[i];
Blaze513 1:94c648931f84 1498 if (c == ' ') break;
Blaze513 1:94c648931f84 1499 if (c == 0x05) c = (TCHAR)0xE5;
Blaze513 1:94c648931f84 1500 if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
Blaze513 1:94c648931f84 1501 #if _LFN_UNICODE
Blaze513 1:94c648931f84 1502 if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i + 1]))
Blaze513 1:94c648931f84 1503 c = (c << 8) | dir[++i];
Blaze513 1:94c648931f84 1504 c = ff_convert(c, 1);
Blaze513 1:94c648931f84 1505 if (!c) c = '?';
Blaze513 1:94c648931f84 1506 #endif
Blaze513 1:94c648931f84 1507 *p++ = c;
Blaze513 1:94c648931f84 1508 }
Blaze513 1:94c648931f84 1509 if (dir[8] != ' ') { /* Copy name extension */
Blaze513 1:94c648931f84 1510 *p++ = '.';
Blaze513 1:94c648931f84 1511 for (i = 8; i < 11; i++) {
Blaze513 1:94c648931f84 1512 c = dir[i];
Blaze513 1:94c648931f84 1513 if (c == ' ') break;
Blaze513 1:94c648931f84 1514 if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
Blaze513 1:94c648931f84 1515 #if _LFN_UNICODE
Blaze513 1:94c648931f84 1516 if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i + 1]))
Blaze513 1:94c648931f84 1517 c = (c << 8) | dir[++i];
Blaze513 1:94c648931f84 1518 c = ff_convert(c, 1);
Blaze513 1:94c648931f84 1519 if (!c) c = '?';
Blaze513 1:94c648931f84 1520 #endif
Blaze513 1:94c648931f84 1521 *p++ = c;
Blaze513 1:94c648931f84 1522 }
Blaze513 1:94c648931f84 1523 }
Blaze513 1:94c648931f84 1524 fno->fattrib = dir[DIR_Attr]; /* Attribute */
Blaze513 1:94c648931f84 1525 fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
Blaze513 1:94c648931f84 1526 fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
Blaze513 1:94c648931f84 1527 fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
Blaze513 1:94c648931f84 1528 }
Blaze513 1:94c648931f84 1529 *p = 0;
Blaze513 1:94c648931f84 1530
Blaze513 1:94c648931f84 1531 #if _USE_LFN
Blaze513 1:94c648931f84 1532 if (fno->lfname) {
Blaze513 1:94c648931f84 1533 TCHAR *tp = fno->lfname;
Blaze513 1:94c648931f84 1534 WCHAR w, *lfn;
Blaze513 1:94c648931f84 1535
Blaze513 1:94c648931f84 1536 i = 0;
Blaze513 1:94c648931f84 1537 if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
Blaze513 1:94c648931f84 1538 lfn = dj->lfn;
Blaze513 1:94c648931f84 1539 while ((w = *lfn++) != 0) { /* Get an LFN char */
Blaze513 1:94c648931f84 1540 #if !_LFN_UNICODE
Blaze513 1:94c648931f84 1541 w = ff_convert(w, 0); /* Unicode -> OEM conversion */
Blaze513 1:94c648931f84 1542 if (!w) { i = 0; break; } /* Could not convert, no LFN */
Blaze513 1:94c648931f84 1543 if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC */
Blaze513 1:94c648931f84 1544 tp[i++] = (TCHAR)(w >> 8);
Blaze513 1:94c648931f84 1545 #endif
Blaze513 1:94c648931f84 1546 if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overrun, no LFN */
Blaze513 1:94c648931f84 1547 tp[i++] = (TCHAR)w;
Blaze513 1:94c648931f84 1548 }
Blaze513 1:94c648931f84 1549 }
Blaze513 1:94c648931f84 1550 tp[i] = 0; /* Terminator */
Blaze513 1:94c648931f84 1551 }
Blaze513 1:94c648931f84 1552 #endif
Blaze513 1:94c648931f84 1553 }
Blaze513 1:94c648931f84 1554 #endif /* _FS_MINIMIZE <= 1 */
Blaze513 1:94c648931f84 1555
Blaze513 1:94c648931f84 1556
Blaze513 1:94c648931f84 1557
Blaze513 1:94c648931f84 1558
Blaze513 1:94c648931f84 1559 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1560 /* Follow a file path */
Blaze513 1:94c648931f84 1561 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1562
Blaze513 1:94c648931f84 1563 static
Blaze513 1:94c648931f84 1564 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
Blaze513 1:94c648931f84 1565 FAT_DIR *dj, /* Directory object to return last directory and found object */
Blaze513 1:94c648931f84 1566 const TCHAR *path /* Full-path string to find a file or directory */
Blaze513 1:94c648931f84 1567 )
Blaze513 1:94c648931f84 1568 {
Blaze513 1:94c648931f84 1569 FRESULT res;
Blaze513 1:94c648931f84 1570 BYTE *dir, ns;
Blaze513 1:94c648931f84 1571
Blaze513 1:94c648931f84 1572
Blaze513 1:94c648931f84 1573 #if _FS_RPATH
Blaze513 1:94c648931f84 1574 if (*path == '/' || *path == '\\') { /* There is a heading separator */
Blaze513 1:94c648931f84 1575 path++; dj->sclust = 0; /* Strip it and start from the root dir */
Blaze513 1:94c648931f84 1576 } else { /* No heading separator */
Blaze513 1:94c648931f84 1577 dj->sclust = dj->fs->cdir; /* Start from the current dir */
Blaze513 1:94c648931f84 1578 }
Blaze513 1:94c648931f84 1579 #else
Blaze513 1:94c648931f84 1580 if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
Blaze513 1:94c648931f84 1581 path++;
Blaze513 1:94c648931f84 1582 dj->sclust = 0; /* Start from the root dir */
Blaze513 1:94c648931f84 1583 #endif
Blaze513 1:94c648931f84 1584
Blaze513 1:94c648931f84 1585 if ((UINT)*path < ' ') { /* Nul path means the start directory itself */
Blaze513 1:94c648931f84 1586 res = dir_sdi(dj, 0);
Blaze513 1:94c648931f84 1587 dj->dir = 0;
Blaze513 1:94c648931f84 1588
Blaze513 1:94c648931f84 1589 } else { /* Follow path */
Blaze513 1:94c648931f84 1590 for (;;) {
Blaze513 1:94c648931f84 1591 res = create_name(dj, &path); /* Get a segment */
Blaze513 1:94c648931f84 1592 if (res != FR_OK) break;
Blaze513 1:94c648931f84 1593 res = dir_find(dj); /* Find it */
Blaze513 1:94c648931f84 1594 ns = *(dj->fn+NS);
Blaze513 1:94c648931f84 1595 if (res != FR_OK) { /* Failed to find the object */
Blaze513 1:94c648931f84 1596 if (res != FR_NO_FILE) break; /* Abort if any hard error occured */
Blaze513 1:94c648931f84 1597 /* Object not found */
Blaze513 1:94c648931f84 1598 if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */
Blaze513 1:94c648931f84 1599 dj->sclust = 0; dj->dir = 0; /* It is the root dir */
Blaze513 1:94c648931f84 1600 res = FR_OK;
Blaze513 1:94c648931f84 1601 if (!(ns & NS_LAST)) continue;
Blaze513 1:94c648931f84 1602 } else { /* Could not find the object */
Blaze513 1:94c648931f84 1603 if (!(ns & NS_LAST)) res = FR_NO_PATH;
Blaze513 1:94c648931f84 1604 }
Blaze513 1:94c648931f84 1605 break;
Blaze513 1:94c648931f84 1606 }
Blaze513 1:94c648931f84 1607 if (ns & NS_LAST) break; /* Last segment match. Function completed. */
Blaze513 1:94c648931f84 1608 dir = dj->dir; /* There is next segment. Follow the sub directory */
Blaze513 1:94c648931f84 1609 if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
Blaze513 1:94c648931f84 1610 res = FR_NO_PATH; break;
Blaze513 1:94c648931f84 1611 }
Blaze513 1:94c648931f84 1612 dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
Blaze513 1:94c648931f84 1613 }
Blaze513 1:94c648931f84 1614 }
Blaze513 1:94c648931f84 1615
Blaze513 1:94c648931f84 1616 return res;
Blaze513 1:94c648931f84 1617 }
Blaze513 1:94c648931f84 1618
Blaze513 1:94c648931f84 1619
Blaze513 1:94c648931f84 1620
Blaze513 1:94c648931f84 1621
Blaze513 1:94c648931f84 1622 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1623 /* Load boot record and check if it is an FAT boot record */
Blaze513 1:94c648931f84 1624 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1625
Blaze513 1:94c648931f84 1626 static
Blaze513 1:94c648931f84 1627 BYTE check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
Blaze513 1:94c648931f84 1628 FATFS *fs, /* File system object */
Blaze513 1:94c648931f84 1629 DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
Blaze513 1:94c648931f84 1630 )
Blaze513 1:94c648931f84 1631 {
Blaze513 1:94c648931f84 1632 if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
Blaze513 1:94c648931f84 1633 return 3;
Blaze513 1:94c648931f84 1634 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
Blaze513 1:94c648931f84 1635 return 2;
Blaze513 1:94c648931f84 1636
Blaze513 1:94c648931f84 1637 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
Blaze513 1:94c648931f84 1638 return 0;
Blaze513 1:94c648931f84 1639 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
Blaze513 1:94c648931f84 1640 return 0;
Blaze513 1:94c648931f84 1641
Blaze513 1:94c648931f84 1642 return 1;
Blaze513 1:94c648931f84 1643 }
Blaze513 1:94c648931f84 1644
Blaze513 1:94c648931f84 1645
Blaze513 1:94c648931f84 1646
Blaze513 1:94c648931f84 1647
Blaze513 1:94c648931f84 1648 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1649 /* Make sure that the file system is valid */
Blaze513 1:94c648931f84 1650 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1651
Blaze513 1:94c648931f84 1652 static
Blaze513 1:94c648931f84 1653 FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
Blaze513 1:94c648931f84 1654 const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
Blaze513 1:94c648931f84 1655 FATFS **rfs, /* Pointer to pointer to the found file system object */
Blaze513 1:94c648931f84 1656 BYTE chk_wp /* !=0: Check media write protection for write access */
Blaze513 1:94c648931f84 1657 )
Blaze513 1:94c648931f84 1658 {
Blaze513 1:94c648931f84 1659 BYTE fmt, b, *tbl;
Blaze513 1:94c648931f84 1660 UINT vol;
Blaze513 1:94c648931f84 1661 DSTATUS stat;
Blaze513 1:94c648931f84 1662 DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
Blaze513 1:94c648931f84 1663 WORD nrsv;
Blaze513 1:94c648931f84 1664 const TCHAR *p = *path;
Blaze513 1:94c648931f84 1665 FATFS *fs;
Blaze513 1:94c648931f84 1666
Blaze513 1:94c648931f84 1667 /* Get logical drive number from the path name */
Blaze513 1:94c648931f84 1668 vol = p[0] - '0'; /* Is there a drive number? */
Blaze513 1:94c648931f84 1669 if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
Blaze513 1:94c648931f84 1670 p += 2; *path = p; /* Return pointer to the path name */
Blaze513 1:94c648931f84 1671 } else { /* No drive number is given */
Blaze513 1:94c648931f84 1672 #if _FS_RPATH
Blaze513 1:94c648931f84 1673 vol = Drive; /* Use current drive */
Blaze513 1:94c648931f84 1674 #else
Blaze513 1:94c648931f84 1675 vol = 0; /* Use drive 0 */
Blaze513 1:94c648931f84 1676 #endif
Blaze513 1:94c648931f84 1677 }
Blaze513 1:94c648931f84 1678
Blaze513 1:94c648931f84 1679 /* Check if the logical drive is valid or not */
Blaze513 1:94c648931f84 1680 if (vol >= _DRIVES) /* Is the drive number valid? */
Blaze513 1:94c648931f84 1681 return FR_INVALID_DRIVE;
Blaze513 1:94c648931f84 1682 *rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */
Blaze513 1:94c648931f84 1683 if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
Blaze513 1:94c648931f84 1684
Blaze513 1:94c648931f84 1685 ENTER_FF(fs); /* Lock file system */
Blaze513 1:94c648931f84 1686
Blaze513 1:94c648931f84 1687 if (fs->fs_type) { /* If the logical drive has been mounted */
Blaze513 1:94c648931f84 1688 stat = disk_status(fs->drv);
Blaze513 1:94c648931f84 1689 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
Blaze513 1:94c648931f84 1690 #if !_FS_READONLY
Blaze513 1:94c648931f84 1691 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
Blaze513 1:94c648931f84 1692 return FR_WRITE_PROTECTED;
Blaze513 1:94c648931f84 1693 #endif
Blaze513 1:94c648931f84 1694 return FR_OK; /* The file system object is valid */
Blaze513 1:94c648931f84 1695 }
Blaze513 1:94c648931f84 1696 }
Blaze513 1:94c648931f84 1697
Blaze513 1:94c648931f84 1698 /* The logical drive must be mounted. Following code attempts to mount the volume (initialize the file system object) */
Blaze513 1:94c648931f84 1699
Blaze513 1:94c648931f84 1700 fs->fs_type = 0; /* Clear the file system object */
Blaze513 1:94c648931f84 1701 fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
Blaze513 1:94c648931f84 1702 stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */
Blaze513 1:94c648931f84 1703 if (stat & STA_NOINIT) /* Check if the drive is ready */
Blaze513 1:94c648931f84 1704 return FR_NOT_READY;
Blaze513 1:94c648931f84 1705 #if _MAX_SS != 512 /* Get disk sector size if needed */
Blaze513 1:94c648931f84 1706 if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
Blaze513 1:94c648931f84 1707 return FR_NO_FILESYSTEM;
Blaze513 1:94c648931f84 1708 #endif
Blaze513 1:94c648931f84 1709 #if !_FS_READONLY
Blaze513 1:94c648931f84 1710 if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
Blaze513 1:94c648931f84 1711 return FR_WRITE_PROTECTED;
Blaze513 1:94c648931f84 1712 #endif
Blaze513 1:94c648931f84 1713 /* Search FAT partition on the drive (Supports only generic partitionings, FDISK and SFD) */
Blaze513 1:94c648931f84 1714 fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
Blaze513 1:94c648931f84 1715 if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */
Blaze513 1:94c648931f84 1716 /* Check the partition listed in top of the partition table */
Blaze513 1:94c648931f84 1717 tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */
Blaze513 1:94c648931f84 1718 if (tbl[4]) { /* Is the partition existing? */
Blaze513 1:94c648931f84 1719 bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
Blaze513 1:94c648931f84 1720 fmt = check_fs(fs, bsect); /* Check the partition */
Blaze513 1:94c648931f84 1721 }
Blaze513 1:94c648931f84 1722 }
Blaze513 1:94c648931f84 1723 if (fmt == 3) return FR_DISK_ERR;
Blaze513 1:94c648931f84 1724 if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
Blaze513 1:94c648931f84 1725
Blaze513 1:94c648931f84 1726 /* Following code initializes the file system object */
Blaze513 1:94c648931f84 1727
Blaze513 1:94c648931f84 1728 if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
Blaze513 1:94c648931f84 1729 return FR_NO_FILESYSTEM;
Blaze513 1:94c648931f84 1730
Blaze513 1:94c648931f84 1731 fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
Blaze513 1:94c648931f84 1732 if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
Blaze513 1:94c648931f84 1733 fs->fsize = fasize;
Blaze513 1:94c648931f84 1734
Blaze513 1:94c648931f84 1735 fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
Blaze513 1:94c648931f84 1736 if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
Blaze513 1:94c648931f84 1737 fasize *= b; /* Number of sectors for FAT area */
Blaze513 1:94c648931f84 1738
Blaze513 1:94c648931f84 1739 fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
Blaze513 1:94c648931f84 1740 if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be 1,2,4...128) */
Blaze513 1:94c648931f84 1741
Blaze513 1:94c648931f84 1742 fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
Blaze513 1:94c648931f84 1743 if (fs->n_rootdir % (SS(fs) / 32)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
Blaze513 1:94c648931f84 1744
Blaze513 1:94c648931f84 1745 tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
Blaze513 1:94c648931f84 1746 if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
Blaze513 1:94c648931f84 1747
Blaze513 1:94c648931f84 1748 nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
Blaze513 1:94c648931f84 1749 if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
Blaze513 1:94c648931f84 1750
Blaze513 1:94c648931f84 1751 /* Determine the FAT sub type */
Blaze513 1:94c648931f84 1752 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / 32); /* RSV+FAT+DIR */
Blaze513 1:94c648931f84 1753 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
Blaze513 1:94c648931f84 1754 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
Blaze513 1:94c648931f84 1755 if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
Blaze513 1:94c648931f84 1756 fmt = FS_FAT12;
Blaze513 1:94c648931f84 1757 if (nclst >= MIN_FAT16) fmt = FS_FAT16;
Blaze513 1:94c648931f84 1758 if (nclst >= MIN_FAT32) fmt = FS_FAT32;
Blaze513 1:94c648931f84 1759
Blaze513 1:94c648931f84 1760 /* Boundaries and Limits */
Blaze513 1:94c648931f84 1761 fs->n_fatent = nclst + 2; /* Number of FAT entries */
Blaze513 1:94c648931f84 1762 fs->database = bsect + sysect; /* Data start sector */
Blaze513 1:94c648931f84 1763 fs->fatbase = bsect + nrsv; /* FAT start sector */
Blaze513 1:94c648931f84 1764 if (fmt == FS_FAT32) {
Blaze513 1:94c648931f84 1765 if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
Blaze513 1:94c648931f84 1766 fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
Blaze513 1:94c648931f84 1767 szbfat = fs->n_fatent * 4; /* (Required FAT size) */
Blaze513 1:94c648931f84 1768 } else {
Blaze513 1:94c648931f84 1769 if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
Blaze513 1:94c648931f84 1770 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
Blaze513 1:94c648931f84 1771 szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
Blaze513 1:94c648931f84 1772 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
Blaze513 1:94c648931f84 1773 }
Blaze513 1:94c648931f84 1774 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (FAT size must not be less than FAT sectors */
Blaze513 1:94c648931f84 1775 return FR_NO_FILESYSTEM;
Blaze513 1:94c648931f84 1776
Blaze513 1:94c648931f84 1777 #if !_FS_READONLY
Blaze513 1:94c648931f84 1778 /* Initialize cluster allocation information */
Blaze513 1:94c648931f84 1779 fs->free_clust = 0xFFFFFFFF;
Blaze513 1:94c648931f84 1780 fs->last_clust = 0;
Blaze513 1:94c648931f84 1781
Blaze513 1:94c648931f84 1782 /* Get fsinfo if available */
Blaze513 1:94c648931f84 1783 if (fmt == FS_FAT32) {
Blaze513 1:94c648931f84 1784 fs->fsi_flag = 0;
Blaze513 1:94c648931f84 1785 fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
Blaze513 1:94c648931f84 1786 if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
Blaze513 1:94c648931f84 1787 LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
Blaze513 1:94c648931f84 1788 LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
Blaze513 1:94c648931f84 1789 LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
Blaze513 1:94c648931f84 1790 fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
Blaze513 1:94c648931f84 1791 fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
Blaze513 1:94c648931f84 1792 }
Blaze513 1:94c648931f84 1793 }
Blaze513 1:94c648931f84 1794 #endif
Blaze513 1:94c648931f84 1795 fs->fs_type = fmt; /* FAT sub-type */
Blaze513 1:94c648931f84 1796 fs->id = ++Fsid; /* File system mount ID */
Blaze513 1:94c648931f84 1797 fs->winsect = 0; /* Invalidate sector cache */
Blaze513 1:94c648931f84 1798 fs->wflag = 0;
Blaze513 1:94c648931f84 1799 #if _FS_RPATH
Blaze513 1:94c648931f84 1800 fs->cdir = 0; /* Current directory (root dir) */
Blaze513 1:94c648931f84 1801 #endif
Blaze513 1:94c648931f84 1802 #if _FS_SHARE /* Clear file lock semaphores */
Blaze513 1:94c648931f84 1803 for (vol = 0; vol < _FS_SHARE; vol++)
Blaze513 1:94c648931f84 1804 fs->flsem[vol].ctr = 0;
Blaze513 1:94c648931f84 1805 #endif
Blaze513 1:94c648931f84 1806
Blaze513 1:94c648931f84 1807 return FR_OK;
Blaze513 1:94c648931f84 1808 }
Blaze513 1:94c648931f84 1809
Blaze513 1:94c648931f84 1810
Blaze513 1:94c648931f84 1811
Blaze513 1:94c648931f84 1812
Blaze513 1:94c648931f84 1813 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1814 /* Check if the file/dir object is valid or not */
Blaze513 1:94c648931f84 1815 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1816
Blaze513 1:94c648931f84 1817 static
Blaze513 1:94c648931f84 1818 FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
Blaze513 1:94c648931f84 1819 FATFS *fs, /* Pointer to the file system object */
Blaze513 1:94c648931f84 1820 WORD id /* Member id of the target object to be checked */
Blaze513 1:94c648931f84 1821 )
Blaze513 1:94c648931f84 1822 {
Blaze513 1:94c648931f84 1823 if (!fs || !fs->fs_type || fs->id != id)
Blaze513 1:94c648931f84 1824 return FR_INVALID_OBJECT;
Blaze513 1:94c648931f84 1825
Blaze513 1:94c648931f84 1826 ENTER_FF(fs); /* Lock file system */
Blaze513 1:94c648931f84 1827
Blaze513 1:94c648931f84 1828 if (disk_status(fs->drv) & STA_NOINIT)
Blaze513 1:94c648931f84 1829 return FR_NOT_READY;
Blaze513 1:94c648931f84 1830
Blaze513 1:94c648931f84 1831 return FR_OK;
Blaze513 1:94c648931f84 1832 }
Blaze513 1:94c648931f84 1833
Blaze513 1:94c648931f84 1834
Blaze513 1:94c648931f84 1835
Blaze513 1:94c648931f84 1836
Blaze513 1:94c648931f84 1837 /*--------------------------------------------------------------------------
Blaze513 1:94c648931f84 1838
Blaze513 1:94c648931f84 1839 Public Functions
Blaze513 1:94c648931f84 1840
Blaze513 1:94c648931f84 1841 --------------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1842
Blaze513 1:94c648931f84 1843
Blaze513 1:94c648931f84 1844
Blaze513 1:94c648931f84 1845 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1846 /* Mount/Unmount a Logical Drive */
Blaze513 1:94c648931f84 1847 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1848
Blaze513 1:94c648931f84 1849 FRESULT f_mount (
Blaze513 1:94c648931f84 1850 BYTE vol, /* Logical drive number to be mounted/unmounted */
Blaze513 1:94c648931f84 1851 FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
Blaze513 1:94c648931f84 1852 )
Blaze513 1:94c648931f84 1853 {
Blaze513 1:94c648931f84 1854 FATFS *rfs;
Blaze513 1:94c648931f84 1855
Blaze513 1:94c648931f84 1856
Blaze513 1:94c648931f84 1857 if (vol >= _DRIVES) /* Check if the drive number is valid */
Blaze513 1:94c648931f84 1858 return FR_INVALID_DRIVE;
Blaze513 1:94c648931f84 1859 rfs = FatFs[vol]; /* Get current fs object */
Blaze513 1:94c648931f84 1860
Blaze513 1:94c648931f84 1861 if (rfs) {
Blaze513 1:94c648931f84 1862 #if _FS_REENTRANT /* Discard sync object of the current volume */
Blaze513 1:94c648931f84 1863 if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
Blaze513 1:94c648931f84 1864 #endif
Blaze513 1:94c648931f84 1865 rfs->fs_type = 0; /* Clear old fs object */
Blaze513 1:94c648931f84 1866 }
Blaze513 1:94c648931f84 1867
Blaze513 1:94c648931f84 1868 if (fs) {
Blaze513 1:94c648931f84 1869 fs->fs_type = 0; /* Clear new fs object */
Blaze513 1:94c648931f84 1870 #if _FS_REENTRANT /* Create sync object for the new volume */
Blaze513 1:94c648931f84 1871 if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
Blaze513 1:94c648931f84 1872 #endif
Blaze513 1:94c648931f84 1873 }
Blaze513 1:94c648931f84 1874 FatFs[vol] = fs; /* Register new fs object */
Blaze513 1:94c648931f84 1875
Blaze513 1:94c648931f84 1876 return FR_OK;
Blaze513 1:94c648931f84 1877 }
Blaze513 1:94c648931f84 1878
Blaze513 1:94c648931f84 1879
Blaze513 1:94c648931f84 1880
Blaze513 1:94c648931f84 1881
Blaze513 1:94c648931f84 1882 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1883 /* Open or Create a File */
Blaze513 1:94c648931f84 1884 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 1885
Blaze513 1:94c648931f84 1886 FRESULT f_open (
Blaze513 1:94c648931f84 1887 FAT_FIL *fp, /* Pointer to the blank file object */
Blaze513 1:94c648931f84 1888 const TCHAR *path, /* Pointer to the file name */
Blaze513 1:94c648931f84 1889 BYTE mode /* Access mode and file open mode flags */
Blaze513 1:94c648931f84 1890 )
Blaze513 1:94c648931f84 1891 {
Blaze513 1:94c648931f84 1892 FRESULT res;
Blaze513 1:94c648931f84 1893 FAT_DIR dj;
Blaze513 1:94c648931f84 1894 BYTE *dir;
Blaze513 1:94c648931f84 1895 DEF_NAMEBUF;
Blaze513 1:94c648931f84 1896
Blaze513 1:94c648931f84 1897
Blaze513 1:94c648931f84 1898 fp->fs = 0; /* Clear file object */
Blaze513 1:94c648931f84 1899
Blaze513 1:94c648931f84 1900 #if !_FS_READONLY
Blaze513 1:94c648931f84 1901 mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
Blaze513 1:94c648931f84 1902 res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
Blaze513 1:94c648931f84 1903 #else
Blaze513 1:94c648931f84 1904 mode &= FA_READ;
Blaze513 1:94c648931f84 1905 res = chk_mounted(&path, &dj.fs, 0);
Blaze513 1:94c648931f84 1906 #endif
Blaze513 1:94c648931f84 1907 INIT_BUF(dj);
Blaze513 1:94c648931f84 1908 if (res == FR_OK)
Blaze513 1:94c648931f84 1909 res = follow_path(&dj, path); /* Follow the file path */
Blaze513 1:94c648931f84 1910 dir = dj.dir;
Blaze513 1:94c648931f84 1911
Blaze513 1:94c648931f84 1912 #if !_FS_READONLY /* R/W configuration */
Blaze513 1:94c648931f84 1913 if (res == FR_OK) {
Blaze513 1:94c648931f84 1914 if (!dir) /* Current dir itself */
Blaze513 1:94c648931f84 1915 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 1916 #if _FS_SHARE
Blaze513 1:94c648931f84 1917 else
Blaze513 1:94c648931f84 1918 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
Blaze513 1:94c648931f84 1919 #endif
Blaze513 1:94c648931f84 1920 }
Blaze513 1:94c648931f84 1921 /* Create or Open a file */
Blaze513 1:94c648931f84 1922 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
Blaze513 1:94c648931f84 1923 DWORD dw, cl;
Blaze513 1:94c648931f84 1924
Blaze513 1:94c648931f84 1925 if (res != FR_OK) { /* No file, create new */
Blaze513 1:94c648931f84 1926 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
Blaze513 1:94c648931f84 1927 #if _FS_SHARE
Blaze513 1:94c648931f84 1928 res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
Blaze513 1:94c648931f84 1929 #else
Blaze513 1:94c648931f84 1930 res = dir_register(&dj);
Blaze513 1:94c648931f84 1931 #endif
Blaze513 1:94c648931f84 1932 mode |= FA_CREATE_ALWAYS;
Blaze513 1:94c648931f84 1933 dir = dj.dir; /* New entry */
Blaze513 1:94c648931f84 1934 }
Blaze513 1:94c648931f84 1935 else { /* Any object is already existing */
Blaze513 1:94c648931f84 1936 if (mode & FA_CREATE_NEW) { /* Cannot create new */
Blaze513 1:94c648931f84 1937 res = FR_EXIST;
Blaze513 1:94c648931f84 1938 } else {
Blaze513 1:94c648931f84 1939 if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) /* Cannot overwrite it (R/O or DIR) */
Blaze513 1:94c648931f84 1940 res = FR_DENIED;
Blaze513 1:94c648931f84 1941 }
Blaze513 1:94c648931f84 1942 }
Blaze513 1:94c648931f84 1943 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
Blaze513 1:94c648931f84 1944 dw = get_fattime(); /* Created time */
Blaze513 1:94c648931f84 1945 ST_DWORD(dir+DIR_CrtTime, dw);
Blaze513 1:94c648931f84 1946 dir[DIR_Attr] = 0; /* Reset attribute */
Blaze513 1:94c648931f84 1947 ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
Blaze513 1:94c648931f84 1948 cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); /* Get start cluster */
Blaze513 1:94c648931f84 1949 ST_WORD(dir+DIR_FstClusHI, 0); /* cluster = 0 */
Blaze513 1:94c648931f84 1950 ST_WORD(dir+DIR_FstClusLO, 0);
Blaze513 1:94c648931f84 1951 dj.fs->wflag = 1;
Blaze513 1:94c648931f84 1952 if (cl) { /* Remove the cluster chain if exist */
Blaze513 1:94c648931f84 1953 dw = dj.fs->winsect;
Blaze513 1:94c648931f84 1954 res = remove_chain(dj.fs, cl);
Blaze513 1:94c648931f84 1955 if (res == FR_OK) {
Blaze513 1:94c648931f84 1956 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
Blaze513 1:94c648931f84 1957 res = move_window(dj.fs, dw);
Blaze513 1:94c648931f84 1958 }
Blaze513 1:94c648931f84 1959 }
Blaze513 1:94c648931f84 1960 }
Blaze513 1:94c648931f84 1961 }
Blaze513 1:94c648931f84 1962 else { /* Open an existing file */
Blaze513 1:94c648931f84 1963 if (res == FR_OK) { /* Follow succeeded */
Blaze513 1:94c648931f84 1964 if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
Blaze513 1:94c648931f84 1965 res = FR_NO_FILE;
Blaze513 1:94c648931f84 1966 } else {
Blaze513 1:94c648931f84 1967 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
Blaze513 1:94c648931f84 1968 res = FR_DENIED;
Blaze513 1:94c648931f84 1969 }
Blaze513 1:94c648931f84 1970 }
Blaze513 1:94c648931f84 1971 }
Blaze513 1:94c648931f84 1972 if (res == FR_OK) {
Blaze513 1:94c648931f84 1973 if (mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW))
Blaze513 1:94c648931f84 1974 mode |= FA__WRITTEN; /* Set file changed flag */
Blaze513 1:94c648931f84 1975 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
Blaze513 1:94c648931f84 1976 fp->dir_ptr = dir;
Blaze513 1:94c648931f84 1977 #if _FS_SHARE
Blaze513 1:94c648931f84 1978 fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
Blaze513 1:94c648931f84 1979 if (!fp->lockid) res = FR_INT_ERR;
Blaze513 1:94c648931f84 1980 #endif
Blaze513 1:94c648931f84 1981 }
Blaze513 1:94c648931f84 1982
Blaze513 1:94c648931f84 1983 #else /* R/O configuration */
Blaze513 1:94c648931f84 1984 if (res == FR_OK) { /* Follow succeeded */
Blaze513 1:94c648931f84 1985 if (!dir) { /* Current dir itself */
Blaze513 1:94c648931f84 1986 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 1987 } else {
Blaze513 1:94c648931f84 1988 if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
Blaze513 1:94c648931f84 1989 res = FR_NO_FILE;
Blaze513 1:94c648931f84 1990 }
Blaze513 1:94c648931f84 1991 }
Blaze513 1:94c648931f84 1992 #endif
Blaze513 1:94c648931f84 1993 FREE_BUF();
Blaze513 1:94c648931f84 1994
Blaze513 1:94c648931f84 1995 if (res == FR_OK) {
Blaze513 1:94c648931f84 1996 fp->flag = mode; /* File access mode */
Blaze513 1:94c648931f84 1997 fp->org_clust = /* File start cluster */
Blaze513 1:94c648931f84 1998 ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
Blaze513 1:94c648931f84 1999 fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
Blaze513 1:94c648931f84 2000 fp->fptr = 0; /* File pointer */
Blaze513 1:94c648931f84 2001 fp->dsect = 0;
Blaze513 1:94c648931f84 2002 #if _USE_FASTSEEK
Blaze513 1:94c648931f84 2003 fp->cltbl = 0; /* No cluster link map table */
Blaze513 1:94c648931f84 2004 #endif
Blaze513 1:94c648931f84 2005 fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
Blaze513 1:94c648931f84 2006 }
Blaze513 1:94c648931f84 2007
Blaze513 1:94c648931f84 2008 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2009 }
Blaze513 1:94c648931f84 2010
Blaze513 1:94c648931f84 2011
Blaze513 1:94c648931f84 2012
Blaze513 1:94c648931f84 2013
Blaze513 1:94c648931f84 2014 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2015 /* Read File */
Blaze513 1:94c648931f84 2016 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2017
Blaze513 1:94c648931f84 2018 FRESULT f_read (
Blaze513 1:94c648931f84 2019 FAT_FIL *fp, /* Pointer to the file object */
Blaze513 1:94c648931f84 2020 void *buff, /* Pointer to data buffer */
Blaze513 1:94c648931f84 2021 UINT btr, /* Number of bytes to read */
Blaze513 1:94c648931f84 2022 UINT *br /* Pointer to number of bytes read */
Blaze513 1:94c648931f84 2023 )
Blaze513 1:94c648931f84 2024 {
Blaze513 1:94c648931f84 2025 FRESULT res;
Blaze513 1:94c648931f84 2026 DWORD clst, sect, remain;
Blaze513 1:94c648931f84 2027 UINT rcnt, cc;
Blaze513 1:94c648931f84 2028 BYTE csect, *rbuff = (BYTE*)buff;
Blaze513 1:94c648931f84 2029
Blaze513 1:94c648931f84 2030
Blaze513 1:94c648931f84 2031 *br = 0; /* Initialize byte counter */
Blaze513 1:94c648931f84 2032
Blaze513 1:94c648931f84 2033 res = validate(fp->fs, fp->id); /* Check validity of the object */
Blaze513 1:94c648931f84 2034 if (res != FR_OK) LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 2035 if (fp->flag & FA__ERROR) /* Check abort flag */
Blaze513 1:94c648931f84 2036 LEAVE_FF(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2037 if (!(fp->flag & FA_READ)) /* Check access mode */
Blaze513 1:94c648931f84 2038 LEAVE_FF(fp->fs, FR_DENIED);
Blaze513 1:94c648931f84 2039 remain = fp->fsize - fp->fptr;
Blaze513 1:94c648931f84 2040 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
Blaze513 1:94c648931f84 2041
Blaze513 1:94c648931f84 2042 for ( ; btr; /* Repeat until all data transferred */
Blaze513 1:94c648931f84 2043 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
Blaze513 1:94c648931f84 2044 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
Blaze513 1:94c648931f84 2045 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
Blaze513 1:94c648931f84 2046 if (!csect) { /* On the cluster boundary? */
Blaze513 1:94c648931f84 2047 clst = (fp->fptr == 0) ? /* On the top of the file? */
Blaze513 1:94c648931f84 2048 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
Blaze513 1:94c648931f84 2049 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2050 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2051 fp->curr_clust = clst; /* Update current cluster */
Blaze513 1:94c648931f84 2052 }
Blaze513 1:94c648931f84 2053 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
Blaze513 1:94c648931f84 2054 if (!sect) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2055 sect += csect;
Blaze513 1:94c648931f84 2056 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
Blaze513 1:94c648931f84 2057 if (cc) { /* Read maximum contiguous sectors directly */
Blaze513 1:94c648931f84 2058 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
Blaze513 1:94c648931f84 2059 cc = fp->fs->csize - csect;
Blaze513 1:94c648931f84 2060 if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
Blaze513 1:94c648931f84 2061 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2062 #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
Blaze513 1:94c648931f84 2063 #if _FS_TINY
Blaze513 1:94c648931f84 2064 if (fp->fs->wflag && fp->fs->winsect - sect < cc)
Blaze513 1:94c648931f84 2065 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
Blaze513 1:94c648931f84 2066 #else
Blaze513 1:94c648931f84 2067 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
Blaze513 1:94c648931f84 2068 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
Blaze513 1:94c648931f84 2069 #endif
Blaze513 1:94c648931f84 2070 #endif
Blaze513 1:94c648931f84 2071 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
Blaze513 1:94c648931f84 2072 continue;
Blaze513 1:94c648931f84 2073 }
Blaze513 1:94c648931f84 2074 #if !_FS_TINY
Blaze513 1:94c648931f84 2075 #if !_FS_READONLY
Blaze513 1:94c648931f84 2076 if (fp->flag & FA__DIRTY) { /* Write sector I/O buffer if needed */
Blaze513 1:94c648931f84 2077 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
Blaze513 1:94c648931f84 2078 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2079 fp->flag &= ~FA__DIRTY;
Blaze513 1:94c648931f84 2080 }
Blaze513 1:94c648931f84 2081 #endif
Blaze513 1:94c648931f84 2082 if (fp->dsect != sect) { /* Fill sector buffer with file data */
Blaze513 1:94c648931f84 2083 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
Blaze513 1:94c648931f84 2084 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2085 }
Blaze513 1:94c648931f84 2086 #endif
Blaze513 1:94c648931f84 2087 fp->dsect = sect;
Blaze513 1:94c648931f84 2088 }
Blaze513 1:94c648931f84 2089 rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
Blaze513 1:94c648931f84 2090 if (rcnt > btr) rcnt = btr;
Blaze513 1:94c648931f84 2091 #if _FS_TINY
Blaze513 1:94c648931f84 2092 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
Blaze513 1:94c648931f84 2093 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2094 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
Blaze513 1:94c648931f84 2095 #else
Blaze513 1:94c648931f84 2096 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
Blaze513 1:94c648931f84 2097 #endif
Blaze513 1:94c648931f84 2098 }
Blaze513 1:94c648931f84 2099
Blaze513 1:94c648931f84 2100 LEAVE_FF(fp->fs, FR_OK);
Blaze513 1:94c648931f84 2101 }
Blaze513 1:94c648931f84 2102
Blaze513 1:94c648931f84 2103
Blaze513 1:94c648931f84 2104
Blaze513 1:94c648931f84 2105
Blaze513 1:94c648931f84 2106 #if !_FS_READONLY
Blaze513 1:94c648931f84 2107 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2108 /* Write File */
Blaze513 1:94c648931f84 2109 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2110
Blaze513 1:94c648931f84 2111 FRESULT f_write (
Blaze513 1:94c648931f84 2112 FAT_FIL *fp, /* Pointer to the file object */
Blaze513 1:94c648931f84 2113 const void *buff, /* Pointer to the data to be written */
Blaze513 1:94c648931f84 2114 UINT btw, /* Number of bytes to write */
Blaze513 1:94c648931f84 2115 UINT *bw /* Pointer to number of bytes written */
Blaze513 1:94c648931f84 2116 )
Blaze513 1:94c648931f84 2117 {
Blaze513 1:94c648931f84 2118 FRESULT res;
Blaze513 1:94c648931f84 2119 DWORD clst, sect;
Blaze513 1:94c648931f84 2120 UINT wcnt, cc;
Blaze513 1:94c648931f84 2121 const BYTE *wbuff = (const BYTE*)buff;
Blaze513 1:94c648931f84 2122 BYTE csect;
Blaze513 1:94c648931f84 2123
Blaze513 1:94c648931f84 2124
Blaze513 1:94c648931f84 2125 *bw = 0; /* Initialize byte counter */
Blaze513 1:94c648931f84 2126
Blaze513 1:94c648931f84 2127 res = validate(fp->fs, fp->id); /* Check validity of the object */
Blaze513 1:94c648931f84 2128 if (res != FR_OK) LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 2129 if (fp->flag & FA__ERROR) /* Check abort flag */
Blaze513 1:94c648931f84 2130 LEAVE_FF(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2131 if (!(fp->flag & FA_WRITE)) /* Check access mode */
Blaze513 1:94c648931f84 2132 LEAVE_FF(fp->fs, FR_DENIED);
Blaze513 1:94c648931f84 2133 if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */
Blaze513 1:94c648931f84 2134
Blaze513 1:94c648931f84 2135 for ( ; btw; /* Repeat until all data transferred */
Blaze513 1:94c648931f84 2136 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
Blaze513 1:94c648931f84 2137 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
Blaze513 1:94c648931f84 2138 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
Blaze513 1:94c648931f84 2139 if (!csect) { /* On the cluster boundary? */
Blaze513 1:94c648931f84 2140 if (fp->fptr == 0) { /* On the top of the file? */
Blaze513 1:94c648931f84 2141 clst = fp->org_clust; /* Follow from the origin */
Blaze513 1:94c648931f84 2142 if (clst == 0) /* When there is no cluster chain, */
Blaze513 1:94c648931f84 2143 fp->org_clust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
Blaze513 1:94c648931f84 2144 } else { /* Middle or end of the file */
Blaze513 1:94c648931f84 2145 clst = create_chain(fp->fs, fp->curr_clust); /* Follow or stretch cluster chain */
Blaze513 1:94c648931f84 2146 }
Blaze513 1:94c648931f84 2147 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
Blaze513 1:94c648931f84 2148 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2149 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2150 fp->curr_clust = clst; /* Update current cluster */
Blaze513 1:94c648931f84 2151 }
Blaze513 1:94c648931f84 2152 #if _FS_TINY
Blaze513 1:94c648931f84 2153 if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write back data buffer prior to following direct transfer */
Blaze513 1:94c648931f84 2154 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2155 #else
Blaze513 1:94c648931f84 2156 if (fp->flag & FA__DIRTY) { /* Write back data buffer prior to following direct transfer */
Blaze513 1:94c648931f84 2157 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
Blaze513 1:94c648931f84 2158 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2159 fp->flag &= ~FA__DIRTY;
Blaze513 1:94c648931f84 2160 }
Blaze513 1:94c648931f84 2161 #endif
Blaze513 1:94c648931f84 2162 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
Blaze513 1:94c648931f84 2163 if (!sect) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2164 sect += csect;
Blaze513 1:94c648931f84 2165 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
Blaze513 1:94c648931f84 2166 if (cc) { /* Write maximum contiguous sectors directly */
Blaze513 1:94c648931f84 2167 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
Blaze513 1:94c648931f84 2168 cc = fp->fs->csize - csect;
Blaze513 1:94c648931f84 2169 if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
Blaze513 1:94c648931f84 2170 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2171 #if _FS_TINY
Blaze513 1:94c648931f84 2172 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
Blaze513 1:94c648931f84 2173 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
Blaze513 1:94c648931f84 2174 fp->fs->wflag = 0;
Blaze513 1:94c648931f84 2175 }
Blaze513 1:94c648931f84 2176 #else
Blaze513 1:94c648931f84 2177 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
Blaze513 1:94c648931f84 2178 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
Blaze513 1:94c648931f84 2179 fp->flag &= ~FA__DIRTY;
Blaze513 1:94c648931f84 2180 }
Blaze513 1:94c648931f84 2181 #endif
Blaze513 1:94c648931f84 2182 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
Blaze513 1:94c648931f84 2183 continue;
Blaze513 1:94c648931f84 2184 }
Blaze513 1:94c648931f84 2185 #if _FS_TINY
Blaze513 1:94c648931f84 2186 if (fp->fptr >= fp->fsize) { /* Avoid silly buffer filling at growing edge */
Blaze513 1:94c648931f84 2187 if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2188 fp->fs->winsect = sect;
Blaze513 1:94c648931f84 2189 }
Blaze513 1:94c648931f84 2190 #else
Blaze513 1:94c648931f84 2191 if (fp->dsect != sect) { /* Fill sector buffer with file data */
Blaze513 1:94c648931f84 2192 if (fp->fptr < fp->fsize &&
Blaze513 1:94c648931f84 2193 disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
Blaze513 1:94c648931f84 2194 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2195 }
Blaze513 1:94c648931f84 2196 #endif
Blaze513 1:94c648931f84 2197 fp->dsect = sect;
Blaze513 1:94c648931f84 2198 }
Blaze513 1:94c648931f84 2199 wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */
Blaze513 1:94c648931f84 2200 if (wcnt > btw) wcnt = btw;
Blaze513 1:94c648931f84 2201 #if _FS_TINY
Blaze513 1:94c648931f84 2202 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
Blaze513 1:94c648931f84 2203 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2204 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
Blaze513 1:94c648931f84 2205 fp->fs->wflag = 1;
Blaze513 1:94c648931f84 2206 #else
Blaze513 1:94c648931f84 2207 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
Blaze513 1:94c648931f84 2208 fp->flag |= FA__DIRTY;
Blaze513 1:94c648931f84 2209 #endif
Blaze513 1:94c648931f84 2210 }
Blaze513 1:94c648931f84 2211
Blaze513 1:94c648931f84 2212 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
Blaze513 1:94c648931f84 2213 fp->flag |= FA__WRITTEN; /* Set file changed flag */
Blaze513 1:94c648931f84 2214
Blaze513 1:94c648931f84 2215 LEAVE_FF(fp->fs, FR_OK);
Blaze513 1:94c648931f84 2216 }
Blaze513 1:94c648931f84 2217
Blaze513 1:94c648931f84 2218
Blaze513 1:94c648931f84 2219
Blaze513 1:94c648931f84 2220
Blaze513 1:94c648931f84 2221 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2222 /* Synchronize the File Object */
Blaze513 1:94c648931f84 2223 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2224
Blaze513 1:94c648931f84 2225 FRESULT f_sync (
Blaze513 1:94c648931f84 2226 FAT_FIL *fp /* Pointer to the file object */
Blaze513 1:94c648931f84 2227 )
Blaze513 1:94c648931f84 2228 {
Blaze513 1:94c648931f84 2229 FRESULT res;
Blaze513 1:94c648931f84 2230 DWORD tim;
Blaze513 1:94c648931f84 2231 BYTE *dir;
Blaze513 1:94c648931f84 2232
Blaze513 1:94c648931f84 2233
Blaze513 1:94c648931f84 2234 res = validate(fp->fs, fp->id); /* Check validity of the object */
Blaze513 1:94c648931f84 2235 if (res == FR_OK) {
Blaze513 1:94c648931f84 2236 if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
Blaze513 1:94c648931f84 2237 #if !_FS_TINY /* Write-back dirty buffer */
Blaze513 1:94c648931f84 2238 if (fp->flag & FA__DIRTY) {
Blaze513 1:94c648931f84 2239 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
Blaze513 1:94c648931f84 2240 LEAVE_FF(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2241 fp->flag &= ~FA__DIRTY;
Blaze513 1:94c648931f84 2242 }
Blaze513 1:94c648931f84 2243 #endif
Blaze513 1:94c648931f84 2244 /* Update the directory entry */
Blaze513 1:94c648931f84 2245 res = move_window(fp->fs, fp->dir_sect);
Blaze513 1:94c648931f84 2246 if (res == FR_OK) {
Blaze513 1:94c648931f84 2247 dir = fp->dir_ptr;
Blaze513 1:94c648931f84 2248 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
Blaze513 1:94c648931f84 2249 ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
Blaze513 1:94c648931f84 2250 ST_WORD(dir+DIR_FstClusLO, fp->org_clust); /* Update start cluster */
Blaze513 1:94c648931f84 2251 ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16);
Blaze513 1:94c648931f84 2252 tim = get_fattime(); /* Update updated time */
Blaze513 1:94c648931f84 2253 ST_DWORD(dir+DIR_WrtTime, tim);
Blaze513 1:94c648931f84 2254 fp->flag &= ~FA__WRITTEN;
Blaze513 1:94c648931f84 2255 fp->fs->wflag = 1;
Blaze513 1:94c648931f84 2256 res = sync(fp->fs);
Blaze513 1:94c648931f84 2257 }
Blaze513 1:94c648931f84 2258 }
Blaze513 1:94c648931f84 2259 }
Blaze513 1:94c648931f84 2260
Blaze513 1:94c648931f84 2261 LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 2262 }
Blaze513 1:94c648931f84 2263
Blaze513 1:94c648931f84 2264 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 2265
Blaze513 1:94c648931f84 2266
Blaze513 1:94c648931f84 2267
Blaze513 1:94c648931f84 2268
Blaze513 1:94c648931f84 2269 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2270 /* Close File */
Blaze513 1:94c648931f84 2271 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2272
Blaze513 1:94c648931f84 2273 FRESULT f_close (
Blaze513 1:94c648931f84 2274 FAT_FIL *fp /* Pointer to the file object to be closed */
Blaze513 1:94c648931f84 2275 )
Blaze513 1:94c648931f84 2276 {
Blaze513 1:94c648931f84 2277 FRESULT res;
Blaze513 1:94c648931f84 2278
Blaze513 1:94c648931f84 2279 #if _FS_READONLY
Blaze513 1:94c648931f84 2280 FATFS *fs = fp->fs;
Blaze513 1:94c648931f84 2281 res = validate(fs, fp->id);
Blaze513 1:94c648931f84 2282 if (res == FR_OK) fp->fs = 0; /* Discard file object */
Blaze513 1:94c648931f84 2283 LEAVE_FF(fs, res);
Blaze513 1:94c648931f84 2284
Blaze513 1:94c648931f84 2285 #else
Blaze513 1:94c648931f84 2286 res = f_sync(fp); /* Flush cached data */
Blaze513 1:94c648931f84 2287 #if _FS_SHARE
Blaze513 1:94c648931f84 2288 if (res == FR_OK) { /* Decrement open counter */
Blaze513 1:94c648931f84 2289 #if _FS_REENTRANT
Blaze513 1:94c648931f84 2290 res = validate(fp->fs, fp->id);
Blaze513 1:94c648931f84 2291 if (res == FR_OK) {
Blaze513 1:94c648931f84 2292 res = dec_lock(fp->fs, fp->lockid);
Blaze513 1:94c648931f84 2293 unlock_fs(fp->fs, FR_OK);
Blaze513 1:94c648931f84 2294 }
Blaze513 1:94c648931f84 2295 #else
Blaze513 1:94c648931f84 2296 res = dec_lock(fp->fs, fp->lockid);
Blaze513 1:94c648931f84 2297 #endif
Blaze513 1:94c648931f84 2298 }
Blaze513 1:94c648931f84 2299 #endif
Blaze513 1:94c648931f84 2300 if (res == FR_OK) fp->fs = 0; /* Discard file object */
Blaze513 1:94c648931f84 2301 return res;
Blaze513 1:94c648931f84 2302 #endif
Blaze513 1:94c648931f84 2303 }
Blaze513 1:94c648931f84 2304
Blaze513 1:94c648931f84 2305
Blaze513 1:94c648931f84 2306
Blaze513 1:94c648931f84 2307
Blaze513 1:94c648931f84 2308 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2309 /* Change Current Drive/Directory */
Blaze513 1:94c648931f84 2310 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2311
Blaze513 1:94c648931f84 2312 #if _FS_RPATH
Blaze513 1:94c648931f84 2313
Blaze513 1:94c648931f84 2314 FRESULT f_chdrive (
Blaze513 1:94c648931f84 2315 BYTE drv /* Drive number */
Blaze513 1:94c648931f84 2316 )
Blaze513 1:94c648931f84 2317 {
Blaze513 1:94c648931f84 2318 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
Blaze513 1:94c648931f84 2319
Blaze513 1:94c648931f84 2320 Drive = drv;
Blaze513 1:94c648931f84 2321
Blaze513 1:94c648931f84 2322 return FR_OK;
Blaze513 1:94c648931f84 2323 }
Blaze513 1:94c648931f84 2324
Blaze513 1:94c648931f84 2325
Blaze513 1:94c648931f84 2326
Blaze513 1:94c648931f84 2327
Blaze513 1:94c648931f84 2328 FRESULT f_chdir (
Blaze513 1:94c648931f84 2329 const TCHAR *path /* Pointer to the directory path */
Blaze513 1:94c648931f84 2330 )
Blaze513 1:94c648931f84 2331 {
Blaze513 1:94c648931f84 2332 FRESULT res;
Blaze513 1:94c648931f84 2333 FAT_DIR dj;
Blaze513 1:94c648931f84 2334 BYTE *dir;
Blaze513 1:94c648931f84 2335 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2336
Blaze513 1:94c648931f84 2337
Blaze513 1:94c648931f84 2338 res = chk_mounted(&path, &dj.fs, 0);
Blaze513 1:94c648931f84 2339 if (res == FR_OK) {
Blaze513 1:94c648931f84 2340 INIT_BUF(dj);
Blaze513 1:94c648931f84 2341 res = follow_path(&dj, path); /* Follow the path */
Blaze513 1:94c648931f84 2342 FREE_BUF();
Blaze513 1:94c648931f84 2343 if (res == FR_OK) { /* Follow completed */
Blaze513 1:94c648931f84 2344 dir = dj.dir; /* Pointer to the entry */
Blaze513 1:94c648931f84 2345 if (!dir) {
Blaze513 1:94c648931f84 2346 dj.fs->cdir = dj.sclust; /* Start directory itself */
Blaze513 1:94c648931f84 2347 } else {
Blaze513 1:94c648931f84 2348 if (dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
Blaze513 1:94c648931f84 2349 dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
Blaze513 1:94c648931f84 2350 else
Blaze513 1:94c648931f84 2351 res = FR_NO_PATH; /* Reached but a file */
Blaze513 1:94c648931f84 2352 }
Blaze513 1:94c648931f84 2353 }
Blaze513 1:94c648931f84 2354 if (res == FR_NO_FILE) res = FR_NO_PATH;
Blaze513 1:94c648931f84 2355 }
Blaze513 1:94c648931f84 2356
Blaze513 1:94c648931f84 2357 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2358 }
Blaze513 1:94c648931f84 2359
Blaze513 1:94c648931f84 2360 #endif
Blaze513 1:94c648931f84 2361
Blaze513 1:94c648931f84 2362
Blaze513 1:94c648931f84 2363
Blaze513 1:94c648931f84 2364 #if _FS_MINIMIZE <= 2
Blaze513 1:94c648931f84 2365 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2366 /* Seek File R/W Pointer */
Blaze513 1:94c648931f84 2367 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2368
Blaze513 1:94c648931f84 2369 FRESULT f_lseek (
Blaze513 1:94c648931f84 2370 FAT_FIL *fp, /* Pointer to the file object */
Blaze513 1:94c648931f84 2371 DWORD ofs /* File pointer from top of file */
Blaze513 1:94c648931f84 2372 )
Blaze513 1:94c648931f84 2373 {
Blaze513 1:94c648931f84 2374 FRESULT res;
Blaze513 1:94c648931f84 2375
Blaze513 1:94c648931f84 2376
Blaze513 1:94c648931f84 2377 res = validate(fp->fs, fp->id); /* Check validity of the object */
Blaze513 1:94c648931f84 2378 if (res != FR_OK) LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 2379 if (fp->flag & FA__ERROR) /* Check abort flag */
Blaze513 1:94c648931f84 2380 LEAVE_FF(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2381
Blaze513 1:94c648931f84 2382 #if _USE_FASTSEEK
Blaze513 1:94c648931f84 2383 if (fp->cltbl) { /* Fast seek */
Blaze513 1:94c648931f84 2384 DWORD cl, pcl, ncl, tcl, dsc, tlen, *tbl = fp->cltbl;
Blaze513 1:94c648931f84 2385 BYTE csc;
Blaze513 1:94c648931f84 2386
Blaze513 1:94c648931f84 2387 tlen = *tbl++;
Blaze513 1:94c648931f84 2388 if (ofs == CREATE_LINKMAP) { /* Create link map table */
Blaze513 1:94c648931f84 2389 cl = fp->org_clust;
Blaze513 1:94c648931f84 2390 if (cl) {
Blaze513 1:94c648931f84 2391 do {
Blaze513 1:94c648931f84 2392 if (tlen < 4) { /* Not enough table items */
Blaze513 1:94c648931f84 2393 res = FR_NOT_ENOUGH_CORE; break;
Blaze513 1:94c648931f84 2394 }
Blaze513 1:94c648931f84 2395 tcl = cl; ncl = 0;
Blaze513 1:94c648931f84 2396 do { /* Get a fragment and store the top and length */
Blaze513 1:94c648931f84 2397 pcl = cl; ncl++;
Blaze513 1:94c648931f84 2398 cl = get_fat(fp->fs, cl);
Blaze513 1:94c648931f84 2399 if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2400 if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2401 } while (cl == pcl + 1);
Blaze513 1:94c648931f84 2402 *tbl++ = ncl; *tbl++ = tcl;
Blaze513 1:94c648931f84 2403 tlen -= 2;
Blaze513 1:94c648931f84 2404 } while (cl < fp->fs->n_fatent);
Blaze513 1:94c648931f84 2405 }
Blaze513 1:94c648931f84 2406 *tbl = 0; /* Terminate table */
Blaze513 1:94c648931f84 2407
Blaze513 1:94c648931f84 2408 } else { /* Fast seek */
Blaze513 1:94c648931f84 2409 if (ofs > fp->fsize) /* Clip offset at the file size */
Blaze513 1:94c648931f84 2410 ofs = fp->fsize;
Blaze513 1:94c648931f84 2411 fp->fptr = ofs; /* Set file pointer */
Blaze513 1:94c648931f84 2412 if (ofs) {
Blaze513 1:94c648931f84 2413 dsc = (ofs - 1) / SS(fp->fs);
Blaze513 1:94c648931f84 2414 cl = dsc / fp->fs->csize;
Blaze513 1:94c648931f84 2415 for (;;) {
Blaze513 1:94c648931f84 2416 ncl = *tbl++;
Blaze513 1:94c648931f84 2417 if (!ncl) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2418 if (cl < ncl) break;
Blaze513 1:94c648931f84 2419 cl -= ncl; tbl++;
Blaze513 1:94c648931f84 2420 }
Blaze513 1:94c648931f84 2421 fp->curr_clust = cl + *tbl;
Blaze513 1:94c648931f84 2422 csc = (BYTE)(dsc & (fp->fs->csize - 1));
Blaze513 1:94c648931f84 2423 dsc = clust2sect(fp->fs, fp->curr_clust);
Blaze513 1:94c648931f84 2424 if (!dsc) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2425 dsc += csc;
Blaze513 1:94c648931f84 2426 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) {
Blaze513 1:94c648931f84 2427 #if !_FS_TINY
Blaze513 1:94c648931f84 2428 #if !_FS_READONLY
Blaze513 1:94c648931f84 2429 if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */
Blaze513 1:94c648931f84 2430 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
Blaze513 1:94c648931f84 2431 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2432 fp->flag &= ~FA__DIRTY;
Blaze513 1:94c648931f84 2433 }
Blaze513 1:94c648931f84 2434 #endif
Blaze513 1:94c648931f84 2435 if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK)
Blaze513 1:94c648931f84 2436 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2437 #endif
Blaze513 1:94c648931f84 2438 fp->dsect = dsc;
Blaze513 1:94c648931f84 2439 }
Blaze513 1:94c648931f84 2440 }
Blaze513 1:94c648931f84 2441 }
Blaze513 1:94c648931f84 2442 } else
Blaze513 1:94c648931f84 2443 #endif
Blaze513 1:94c648931f84 2444
Blaze513 1:94c648931f84 2445 /* Normal Seek */
Blaze513 1:94c648931f84 2446 {
Blaze513 1:94c648931f84 2447 DWORD clst, bcs, nsect, ifptr;
Blaze513 1:94c648931f84 2448
Blaze513 1:94c648931f84 2449 if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
Blaze513 1:94c648931f84 2450 #if !_FS_READONLY
Blaze513 1:94c648931f84 2451 && !(fp->flag & FA_WRITE)
Blaze513 1:94c648931f84 2452 #endif
Blaze513 1:94c648931f84 2453 ) ofs = fp->fsize;
Blaze513 1:94c648931f84 2454
Blaze513 1:94c648931f84 2455 ifptr = fp->fptr;
Blaze513 1:94c648931f84 2456 fp->fptr = nsect = 0;
Blaze513 1:94c648931f84 2457 if (ofs) {
Blaze513 1:94c648931f84 2458 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
Blaze513 1:94c648931f84 2459 if (ifptr > 0 &&
Blaze513 1:94c648931f84 2460 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
Blaze513 1:94c648931f84 2461 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
Blaze513 1:94c648931f84 2462 ofs -= fp->fptr;
Blaze513 1:94c648931f84 2463 clst = fp->curr_clust;
Blaze513 1:94c648931f84 2464 } else { /* When seek to back cluster, */
Blaze513 1:94c648931f84 2465 clst = fp->org_clust; /* start from the first cluster */
Blaze513 1:94c648931f84 2466 #if !_FS_READONLY
Blaze513 1:94c648931f84 2467 if (clst == 0) { /* If no cluster chain, create a new chain */
Blaze513 1:94c648931f84 2468 clst = create_chain(fp->fs, 0);
Blaze513 1:94c648931f84 2469 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2470 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2471 fp->org_clust = clst;
Blaze513 1:94c648931f84 2472 }
Blaze513 1:94c648931f84 2473 #endif
Blaze513 1:94c648931f84 2474 fp->curr_clust = clst;
Blaze513 1:94c648931f84 2475 }
Blaze513 1:94c648931f84 2476 if (clst != 0) {
Blaze513 1:94c648931f84 2477 while (ofs > bcs) { /* Cluster following loop */
Blaze513 1:94c648931f84 2478 #if !_FS_READONLY
Blaze513 1:94c648931f84 2479 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
Blaze513 1:94c648931f84 2480 clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
Blaze513 1:94c648931f84 2481 if (clst == 0) { /* When disk gets full, clip file size */
Blaze513 1:94c648931f84 2482 ofs = bcs; break;
Blaze513 1:94c648931f84 2483 }
Blaze513 1:94c648931f84 2484 } else
Blaze513 1:94c648931f84 2485 #endif
Blaze513 1:94c648931f84 2486 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
Blaze513 1:94c648931f84 2487 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2488 if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2489 fp->curr_clust = clst;
Blaze513 1:94c648931f84 2490 fp->fptr += bcs;
Blaze513 1:94c648931f84 2491 ofs -= bcs;
Blaze513 1:94c648931f84 2492 }
Blaze513 1:94c648931f84 2493 fp->fptr += ofs;
Blaze513 1:94c648931f84 2494 if (ofs % SS(fp->fs)) {
Blaze513 1:94c648931f84 2495 nsect = clust2sect(fp->fs, clst); /* Current sector */
Blaze513 1:94c648931f84 2496 if (!nsect) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 2497 nsect += ofs / SS(fp->fs);
Blaze513 1:94c648931f84 2498 }
Blaze513 1:94c648931f84 2499 }
Blaze513 1:94c648931f84 2500 }
Blaze513 1:94c648931f84 2501 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
Blaze513 1:94c648931f84 2502 #if !_FS_TINY
Blaze513 1:94c648931f84 2503 #if !_FS_READONLY
Blaze513 1:94c648931f84 2504 if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */
Blaze513 1:94c648931f84 2505 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
Blaze513 1:94c648931f84 2506 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2507 fp->flag &= ~FA__DIRTY;
Blaze513 1:94c648931f84 2508 }
Blaze513 1:94c648931f84 2509 #endif
Blaze513 1:94c648931f84 2510 if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)
Blaze513 1:94c648931f84 2511 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 2512 #endif
Blaze513 1:94c648931f84 2513 fp->dsect = nsect;
Blaze513 1:94c648931f84 2514 }
Blaze513 1:94c648931f84 2515 #if !_FS_READONLY
Blaze513 1:94c648931f84 2516 if (fp->fptr > fp->fsize) { /* Set changed flag if the file size is extended */
Blaze513 1:94c648931f84 2517 fp->fsize = fp->fptr;
Blaze513 1:94c648931f84 2518 fp->flag |= FA__WRITTEN;
Blaze513 1:94c648931f84 2519 }
Blaze513 1:94c648931f84 2520 #endif
Blaze513 1:94c648931f84 2521 }
Blaze513 1:94c648931f84 2522
Blaze513 1:94c648931f84 2523 LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 2524 }
Blaze513 1:94c648931f84 2525
Blaze513 1:94c648931f84 2526
Blaze513 1:94c648931f84 2527
Blaze513 1:94c648931f84 2528 #if _FS_MINIMIZE <= 1
Blaze513 1:94c648931f84 2529 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2530 /* Create a Directroy Object */
Blaze513 1:94c648931f84 2531 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2532
Blaze513 1:94c648931f84 2533 FRESULT f_opendir (
Blaze513 1:94c648931f84 2534 FAT_DIR *dj, /* Pointer to directory object to create */
Blaze513 1:94c648931f84 2535 const TCHAR *path /* Pointer to the directory path */
Blaze513 1:94c648931f84 2536 )
Blaze513 1:94c648931f84 2537 {
Blaze513 1:94c648931f84 2538 FRESULT res;
Blaze513 1:94c648931f84 2539 BYTE *dir;
Blaze513 1:94c648931f84 2540 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2541
Blaze513 1:94c648931f84 2542
Blaze513 1:94c648931f84 2543 res = chk_mounted(&path, &dj->fs, 0);
Blaze513 1:94c648931f84 2544 if (res == FR_OK) {
Blaze513 1:94c648931f84 2545 INIT_BUF(*dj);
Blaze513 1:94c648931f84 2546 res = follow_path(dj, path); /* Follow the path to the directory */
Blaze513 1:94c648931f84 2547 FREE_BUF();
Blaze513 1:94c648931f84 2548 if (res == FR_OK) { /* Follow completed */
Blaze513 1:94c648931f84 2549 dir = dj->dir;
Blaze513 1:94c648931f84 2550 if (dir) { /* It is not the current dir */
Blaze513 1:94c648931f84 2551 if (dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
Blaze513 1:94c648931f84 2552 dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
Blaze513 1:94c648931f84 2553 } else { /* The object is not a directory */
Blaze513 1:94c648931f84 2554 res = FR_NO_PATH;
Blaze513 1:94c648931f84 2555 }
Blaze513 1:94c648931f84 2556 }
Blaze513 1:94c648931f84 2557 if (res == FR_OK) {
Blaze513 1:94c648931f84 2558 dj->id = dj->fs->id;
Blaze513 1:94c648931f84 2559 res = dir_sdi(dj, 0); /* Rewind dir */
Blaze513 1:94c648931f84 2560 }
Blaze513 1:94c648931f84 2561 }
Blaze513 1:94c648931f84 2562 if (res == FR_NO_FILE) res = FR_NO_PATH;
Blaze513 1:94c648931f84 2563 }
Blaze513 1:94c648931f84 2564
Blaze513 1:94c648931f84 2565 LEAVE_FF(dj->fs, res);
Blaze513 1:94c648931f84 2566 }
Blaze513 1:94c648931f84 2567
Blaze513 1:94c648931f84 2568
Blaze513 1:94c648931f84 2569
Blaze513 1:94c648931f84 2570
Blaze513 1:94c648931f84 2571 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2572 /* Read Directory Entry in Sequense */
Blaze513 1:94c648931f84 2573 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2574
Blaze513 1:94c648931f84 2575 FRESULT f_readdir (
Blaze513 1:94c648931f84 2576 FAT_DIR *dj, /* Pointer to the open directory object */
Blaze513 1:94c648931f84 2577 FILINFO *fno /* Pointer to file information to return */
Blaze513 1:94c648931f84 2578 )
Blaze513 1:94c648931f84 2579 {
Blaze513 1:94c648931f84 2580 FRESULT res;
Blaze513 1:94c648931f84 2581 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2582
Blaze513 1:94c648931f84 2583
Blaze513 1:94c648931f84 2584 res = validate(dj->fs, dj->id); /* Check validity of the object */
Blaze513 1:94c648931f84 2585 if (res == FR_OK) {
Blaze513 1:94c648931f84 2586 if (!fno) {
Blaze513 1:94c648931f84 2587 res = dir_sdi(dj, 0);
Blaze513 1:94c648931f84 2588 } else {
Blaze513 1:94c648931f84 2589 INIT_BUF(*dj);
Blaze513 1:94c648931f84 2590 res = dir_read(dj);
Blaze513 1:94c648931f84 2591 if (res == FR_NO_FILE) {
Blaze513 1:94c648931f84 2592 dj->sect = 0;
Blaze513 1:94c648931f84 2593 res = FR_OK;
Blaze513 1:94c648931f84 2594 }
Blaze513 1:94c648931f84 2595 if (res == FR_OK) { /* A valid entry is found */
Blaze513 1:94c648931f84 2596 get_fileinfo(dj, fno); /* Get the object information */
Blaze513 1:94c648931f84 2597 res = dir_next(dj, 0); /* Increment index for next */
Blaze513 1:94c648931f84 2598 if (res == FR_NO_FILE) {
Blaze513 1:94c648931f84 2599 dj->sect = 0;
Blaze513 1:94c648931f84 2600 res = FR_OK;
Blaze513 1:94c648931f84 2601 }
Blaze513 1:94c648931f84 2602 }
Blaze513 1:94c648931f84 2603 FREE_BUF();
Blaze513 1:94c648931f84 2604 }
Blaze513 1:94c648931f84 2605 }
Blaze513 1:94c648931f84 2606
Blaze513 1:94c648931f84 2607 LEAVE_FF(dj->fs, res);
Blaze513 1:94c648931f84 2608 }
Blaze513 1:94c648931f84 2609
Blaze513 1:94c648931f84 2610
Blaze513 1:94c648931f84 2611
Blaze513 1:94c648931f84 2612 #if _FS_MINIMIZE == 0
Blaze513 1:94c648931f84 2613 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2614 /* Get File Status */
Blaze513 1:94c648931f84 2615 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2616
Blaze513 1:94c648931f84 2617 FRESULT f_stat (
Blaze513 1:94c648931f84 2618 const TCHAR *path, /* Pointer to the file path */
Blaze513 1:94c648931f84 2619 FILINFO *fno /* Pointer to file information to return */
Blaze513 1:94c648931f84 2620 )
Blaze513 1:94c648931f84 2621 {
Blaze513 1:94c648931f84 2622 FRESULT res;
Blaze513 1:94c648931f84 2623 FAT_DIR dj;
Blaze513 1:94c648931f84 2624 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2625
Blaze513 1:94c648931f84 2626
Blaze513 1:94c648931f84 2627 res = chk_mounted(&path, &dj.fs, 0);
Blaze513 1:94c648931f84 2628 if (res == FR_OK) {
Blaze513 1:94c648931f84 2629 INIT_BUF(dj);
Blaze513 1:94c648931f84 2630 res = follow_path(&dj, path); /* Follow the file path */
Blaze513 1:94c648931f84 2631 if (res == FR_OK) { /* Follow completed */
Blaze513 1:94c648931f84 2632 if (dj.dir) /* Found an object */
Blaze513 1:94c648931f84 2633 get_fileinfo(&dj, fno);
Blaze513 1:94c648931f84 2634 else /* It is root dir */
Blaze513 1:94c648931f84 2635 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 2636 }
Blaze513 1:94c648931f84 2637 FREE_BUF();
Blaze513 1:94c648931f84 2638 }
Blaze513 1:94c648931f84 2639
Blaze513 1:94c648931f84 2640 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2641 }
Blaze513 1:94c648931f84 2642
Blaze513 1:94c648931f84 2643
Blaze513 1:94c648931f84 2644
Blaze513 1:94c648931f84 2645 #if !_FS_READONLY
Blaze513 1:94c648931f84 2646 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2647 /* Get Number of Free Clusters */
Blaze513 1:94c648931f84 2648 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2649
Blaze513 1:94c648931f84 2650 FRESULT f_getfree (
Blaze513 1:94c648931f84 2651 const TCHAR *path, /* Pointer to the logical drive number (root dir) */
Blaze513 1:94c648931f84 2652 DWORD *nclst, /* Pointer to the variable to return number of free clusters */
Blaze513 1:94c648931f84 2653 FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
Blaze513 1:94c648931f84 2654 )
Blaze513 1:94c648931f84 2655 {
Blaze513 1:94c648931f84 2656 FRESULT res;
Blaze513 1:94c648931f84 2657 DWORD n, clst, sect, stat;
Blaze513 1:94c648931f84 2658 UINT i;
Blaze513 1:94c648931f84 2659 BYTE fat, *p;
Blaze513 1:94c648931f84 2660
Blaze513 1:94c648931f84 2661
Blaze513 1:94c648931f84 2662 /* Get drive number */
Blaze513 1:94c648931f84 2663 res = chk_mounted(&path, fatfs, 0);
Blaze513 1:94c648931f84 2664 if (res == FR_OK) {
Blaze513 1:94c648931f84 2665 /* If free_clust is valid, return it without full cluster scan */
Blaze513 1:94c648931f84 2666 if ((*fatfs)->free_clust <= (*fatfs)->n_fatent - 2) {
Blaze513 1:94c648931f84 2667 *nclst = (*fatfs)->free_clust;
Blaze513 1:94c648931f84 2668 } else {
Blaze513 1:94c648931f84 2669 /* Get number of free clusters */
Blaze513 1:94c648931f84 2670 fat = (*fatfs)->fs_type;
Blaze513 1:94c648931f84 2671 n = 0;
Blaze513 1:94c648931f84 2672 if (fat == FS_FAT12) {
Blaze513 1:94c648931f84 2673 clst = 2;
Blaze513 1:94c648931f84 2674 do {
Blaze513 1:94c648931f84 2675 stat = get_fat(*fatfs, clst);
Blaze513 1:94c648931f84 2676 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
Blaze513 1:94c648931f84 2677 if (stat == 1) { res = FR_INT_ERR; break; }
Blaze513 1:94c648931f84 2678 if (stat == 0) n++;
Blaze513 1:94c648931f84 2679 } while (++clst < (*fatfs)->n_fatent);
Blaze513 1:94c648931f84 2680 } else {
Blaze513 1:94c648931f84 2681 clst = (*fatfs)->n_fatent;
Blaze513 1:94c648931f84 2682 sect = (*fatfs)->fatbase;
Blaze513 1:94c648931f84 2683 i = 0; p = 0;
Blaze513 1:94c648931f84 2684 do {
Blaze513 1:94c648931f84 2685 if (!i) {
Blaze513 1:94c648931f84 2686 res = move_window(*fatfs, sect++);
Blaze513 1:94c648931f84 2687 if (res != FR_OK) break;
Blaze513 1:94c648931f84 2688 p = (*fatfs)->win;
Blaze513 1:94c648931f84 2689 i = SS(*fatfs);
Blaze513 1:94c648931f84 2690 }
Blaze513 1:94c648931f84 2691 if (fat == FS_FAT16) {
Blaze513 1:94c648931f84 2692 if (LD_WORD(p) == 0) n++;
Blaze513 1:94c648931f84 2693 p += 2; i -= 2;
Blaze513 1:94c648931f84 2694 } else {
Blaze513 1:94c648931f84 2695 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
Blaze513 1:94c648931f84 2696 p += 4; i -= 4;
Blaze513 1:94c648931f84 2697 }
Blaze513 1:94c648931f84 2698 } while (--clst);
Blaze513 1:94c648931f84 2699 }
Blaze513 1:94c648931f84 2700 (*fatfs)->free_clust = n;
Blaze513 1:94c648931f84 2701 if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
Blaze513 1:94c648931f84 2702 *nclst = n;
Blaze513 1:94c648931f84 2703 }
Blaze513 1:94c648931f84 2704 }
Blaze513 1:94c648931f84 2705 LEAVE_FF(*fatfs, res);
Blaze513 1:94c648931f84 2706 }
Blaze513 1:94c648931f84 2707
Blaze513 1:94c648931f84 2708
Blaze513 1:94c648931f84 2709
Blaze513 1:94c648931f84 2710
Blaze513 1:94c648931f84 2711 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2712 /* Truncate File */
Blaze513 1:94c648931f84 2713 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2714
Blaze513 1:94c648931f84 2715 FRESULT f_truncate (
Blaze513 1:94c648931f84 2716 FAT_FIL *fp /* Pointer to the file object */
Blaze513 1:94c648931f84 2717 )
Blaze513 1:94c648931f84 2718 {
Blaze513 1:94c648931f84 2719 FRESULT res;
Blaze513 1:94c648931f84 2720 DWORD ncl;
Blaze513 1:94c648931f84 2721
Blaze513 1:94c648931f84 2722
Blaze513 1:94c648931f84 2723 res = validate(fp->fs, fp->id); /* Check validity of the object */
Blaze513 1:94c648931f84 2724 if (res == FR_OK) {
Blaze513 1:94c648931f84 2725 if (fp->flag & FA__ERROR) { /* Check abort flag */
Blaze513 1:94c648931f84 2726 res = FR_INT_ERR;
Blaze513 1:94c648931f84 2727 } else {
Blaze513 1:94c648931f84 2728 if (!(fp->flag & FA_WRITE)) /* Check access mode */
Blaze513 1:94c648931f84 2729 res = FR_DENIED;
Blaze513 1:94c648931f84 2730 }
Blaze513 1:94c648931f84 2731 }
Blaze513 1:94c648931f84 2732 if (res == FR_OK) {
Blaze513 1:94c648931f84 2733 if (fp->fsize > fp->fptr) {
Blaze513 1:94c648931f84 2734 fp->fsize = fp->fptr; /* Set file size to current R/W point */
Blaze513 1:94c648931f84 2735 fp->flag |= FA__WRITTEN;
Blaze513 1:94c648931f84 2736 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
Blaze513 1:94c648931f84 2737 res = remove_chain(fp->fs, fp->org_clust);
Blaze513 1:94c648931f84 2738 fp->org_clust = 0;
Blaze513 1:94c648931f84 2739 } else { /* When truncate a part of the file, remove remaining clusters */
Blaze513 1:94c648931f84 2740 ncl = get_fat(fp->fs, fp->curr_clust);
Blaze513 1:94c648931f84 2741 res = FR_OK;
Blaze513 1:94c648931f84 2742 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
Blaze513 1:94c648931f84 2743 if (ncl == 1) res = FR_INT_ERR;
Blaze513 1:94c648931f84 2744 if (res == FR_OK && ncl < fp->fs->n_fatent) {
Blaze513 1:94c648931f84 2745 res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
Blaze513 1:94c648931f84 2746 if (res == FR_OK) res = remove_chain(fp->fs, ncl);
Blaze513 1:94c648931f84 2747 }
Blaze513 1:94c648931f84 2748 }
Blaze513 1:94c648931f84 2749 }
Blaze513 1:94c648931f84 2750 if (res != FR_OK) fp->flag |= FA__ERROR;
Blaze513 1:94c648931f84 2751 }
Blaze513 1:94c648931f84 2752
Blaze513 1:94c648931f84 2753 LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 2754 }
Blaze513 1:94c648931f84 2755
Blaze513 1:94c648931f84 2756
Blaze513 1:94c648931f84 2757
Blaze513 1:94c648931f84 2758
Blaze513 1:94c648931f84 2759 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2760 /* Delete a File or Directory */
Blaze513 1:94c648931f84 2761 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2762
Blaze513 1:94c648931f84 2763 FRESULT f_unlink (
Blaze513 1:94c648931f84 2764 const TCHAR *path /* Pointer to the file or directory path */
Blaze513 1:94c648931f84 2765 )
Blaze513 1:94c648931f84 2766 {
Blaze513 1:94c648931f84 2767 FRESULT res;
Blaze513 1:94c648931f84 2768 FAT_DIR dj, sdj;
Blaze513 1:94c648931f84 2769 BYTE *dir;
Blaze513 1:94c648931f84 2770 DWORD dclst;
Blaze513 1:94c648931f84 2771 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2772
Blaze513 1:94c648931f84 2773
Blaze513 1:94c648931f84 2774 res = chk_mounted(&path, &dj.fs, 1);
Blaze513 1:94c648931f84 2775 if (res == FR_OK) {
Blaze513 1:94c648931f84 2776 INIT_BUF(dj);
Blaze513 1:94c648931f84 2777 res = follow_path(&dj, path); /* Follow the file path */
Blaze513 1:94c648931f84 2778 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
Blaze513 1:94c648931f84 2779 res = FR_INVALID_NAME; /* Cannot remove dot entry */
Blaze513 1:94c648931f84 2780 #if _FS_SHARE
Blaze513 1:94c648931f84 2781 if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */
Blaze513 1:94c648931f84 2782 #endif
Blaze513 1:94c648931f84 2783 if (res == FR_OK) { /* The object is accessible */
Blaze513 1:94c648931f84 2784 dir = dj.dir;
Blaze513 1:94c648931f84 2785 if (!dir) {
Blaze513 1:94c648931f84 2786 res = FR_INVALID_NAME; /* Cannot remove the start directory */
Blaze513 1:94c648931f84 2787 } else {
Blaze513 1:94c648931f84 2788 if (dir[DIR_Attr] & AM_RDO)
Blaze513 1:94c648931f84 2789 res = FR_DENIED; /* Cannot remove R/O object */
Blaze513 1:94c648931f84 2790 }
Blaze513 1:94c648931f84 2791 dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
Blaze513 1:94c648931f84 2792 if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */
Blaze513 1:94c648931f84 2793 if (dclst < 2) {
Blaze513 1:94c648931f84 2794 res = FR_INT_ERR;
Blaze513 1:94c648931f84 2795 } else {
Blaze513 1:94c648931f84 2796 mem_cpy(&sdj, &dj, sizeof(FAT_DIR)); /* Check if the sub-dir is empty or not */
Blaze513 1:94c648931f84 2797 sdj.sclust = dclst;
Blaze513 1:94c648931f84 2798 res = dir_sdi(&sdj, 2); /* Exclude dot entries */
Blaze513 1:94c648931f84 2799 if (res == FR_OK) {
Blaze513 1:94c648931f84 2800 res = dir_read(&sdj);
Blaze513 1:94c648931f84 2801 if (res == FR_OK /* Not empty dir */
Blaze513 1:94c648931f84 2802 #if _FS_RPATH
Blaze513 1:94c648931f84 2803 || dclst == sdj.fs->cdir /* Current dir */
Blaze513 1:94c648931f84 2804 #endif
Blaze513 1:94c648931f84 2805 ) res = FR_DENIED;
Blaze513 1:94c648931f84 2806 if (res == FR_NO_FILE) res = FR_OK; /* Empty */
Blaze513 1:94c648931f84 2807 }
Blaze513 1:94c648931f84 2808 }
Blaze513 1:94c648931f84 2809 }
Blaze513 1:94c648931f84 2810 if (res == FR_OK) {
Blaze513 1:94c648931f84 2811 res = dir_remove(&dj); /* Remove the directory entry */
Blaze513 1:94c648931f84 2812 if (res == FR_OK) {
Blaze513 1:94c648931f84 2813 if (dclst) /* Remove the cluster chain if exist */
Blaze513 1:94c648931f84 2814 res = remove_chain(dj.fs, dclst);
Blaze513 1:94c648931f84 2815 if (res == FR_OK) res = sync(dj.fs);
Blaze513 1:94c648931f84 2816 }
Blaze513 1:94c648931f84 2817 }
Blaze513 1:94c648931f84 2818 }
Blaze513 1:94c648931f84 2819 FREE_BUF();
Blaze513 1:94c648931f84 2820 }
Blaze513 1:94c648931f84 2821 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2822 }
Blaze513 1:94c648931f84 2823
Blaze513 1:94c648931f84 2824
Blaze513 1:94c648931f84 2825
Blaze513 1:94c648931f84 2826
Blaze513 1:94c648931f84 2827 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2828 /* Create a Directory */
Blaze513 1:94c648931f84 2829 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2830
Blaze513 1:94c648931f84 2831 FRESULT f_mkdir (
Blaze513 1:94c648931f84 2832 const TCHAR *path /* Pointer to the directory path */
Blaze513 1:94c648931f84 2833 )
Blaze513 1:94c648931f84 2834 {
Blaze513 1:94c648931f84 2835 FRESULT res;
Blaze513 1:94c648931f84 2836 FAT_DIR dj;
Blaze513 1:94c648931f84 2837 BYTE *dir, n;
Blaze513 1:94c648931f84 2838 DWORD dsc, dcl, pcl, tim = get_fattime();
Blaze513 1:94c648931f84 2839 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2840
Blaze513 1:94c648931f84 2841
Blaze513 1:94c648931f84 2842 res = chk_mounted(&path, &dj.fs, 1);
Blaze513 1:94c648931f84 2843 if (res == FR_OK) {
Blaze513 1:94c648931f84 2844 INIT_BUF(dj);
Blaze513 1:94c648931f84 2845 res = follow_path(&dj, path); /* Follow the file path */
Blaze513 1:94c648931f84 2846 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
Blaze513 1:94c648931f84 2847 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
Blaze513 1:94c648931f84 2848 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 2849 if (res == FR_NO_FILE) { /* Can create a new directory */
Blaze513 1:94c648931f84 2850 dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
Blaze513 1:94c648931f84 2851 res = FR_OK;
Blaze513 1:94c648931f84 2852 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
Blaze513 1:94c648931f84 2853 if (dcl == 1) res = FR_INT_ERR;
Blaze513 1:94c648931f84 2854 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
Blaze513 1:94c648931f84 2855 if (res == FR_OK) /* Flush FAT */
Blaze513 1:94c648931f84 2856 res = move_window(dj.fs, 0);
Blaze513 1:94c648931f84 2857 if (res == FR_OK) { /* Initialize the new directory table */
Blaze513 1:94c648931f84 2858 dsc = clust2sect(dj.fs, dcl);
Blaze513 1:94c648931f84 2859 dir = dj.fs->win;
Blaze513 1:94c648931f84 2860 mem_set(dir, 0, SS(dj.fs));
Blaze513 1:94c648931f84 2861 mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
Blaze513 1:94c648931f84 2862 dir[DIR_Name] = '.';
Blaze513 1:94c648931f84 2863 dir[DIR_Attr] = AM_DIR;
Blaze513 1:94c648931f84 2864 ST_DWORD(dir+DIR_WrtTime, tim);
Blaze513 1:94c648931f84 2865 ST_WORD(dir+DIR_FstClusLO, dcl);
Blaze513 1:94c648931f84 2866 ST_WORD(dir+DIR_FstClusHI, dcl >> 16);
Blaze513 1:94c648931f84 2867 mem_cpy(dir+32, dir, 32); /* Create ".." entry */
Blaze513 1:94c648931f84 2868 dir[33] = '.'; pcl = dj.sclust;
Blaze513 1:94c648931f84 2869 if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
Blaze513 1:94c648931f84 2870 pcl = 0;
Blaze513 1:94c648931f84 2871 ST_WORD(dir+32+DIR_FstClusLO, pcl);
Blaze513 1:94c648931f84 2872 ST_WORD(dir+32+DIR_FstClusHI, pcl >> 16);
Blaze513 1:94c648931f84 2873 for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
Blaze513 1:94c648931f84 2874 dj.fs->winsect = dsc++;
Blaze513 1:94c648931f84 2875 dj.fs->wflag = 1;
Blaze513 1:94c648931f84 2876 res = move_window(dj.fs, 0);
Blaze513 1:94c648931f84 2877 if (res != FR_OK) break;
Blaze513 1:94c648931f84 2878 mem_set(dir, 0, SS(dj.fs));
Blaze513 1:94c648931f84 2879 }
Blaze513 1:94c648931f84 2880 }
Blaze513 1:94c648931f84 2881 if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
Blaze513 1:94c648931f84 2882 if (res != FR_OK) {
Blaze513 1:94c648931f84 2883 remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
Blaze513 1:94c648931f84 2884 } else {
Blaze513 1:94c648931f84 2885 dir = dj.dir;
Blaze513 1:94c648931f84 2886 dir[DIR_Attr] = AM_DIR; /* Attribute */
Blaze513 1:94c648931f84 2887 ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */
Blaze513 1:94c648931f84 2888 ST_WORD(dir+DIR_FstClusLO, dcl); /* Table start cluster */
Blaze513 1:94c648931f84 2889 ST_WORD(dir+DIR_FstClusHI, dcl >> 16);
Blaze513 1:94c648931f84 2890 dj.fs->wflag = 1;
Blaze513 1:94c648931f84 2891 res = sync(dj.fs);
Blaze513 1:94c648931f84 2892 }
Blaze513 1:94c648931f84 2893 }
Blaze513 1:94c648931f84 2894 FREE_BUF();
Blaze513 1:94c648931f84 2895 }
Blaze513 1:94c648931f84 2896
Blaze513 1:94c648931f84 2897 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2898 }
Blaze513 1:94c648931f84 2899
Blaze513 1:94c648931f84 2900
Blaze513 1:94c648931f84 2901
Blaze513 1:94c648931f84 2902
Blaze513 1:94c648931f84 2903 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2904 /* Change Attribute */
Blaze513 1:94c648931f84 2905 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2906
Blaze513 1:94c648931f84 2907 FRESULT f_chmod (
Blaze513 1:94c648931f84 2908 const TCHAR *path, /* Pointer to the file path */
Blaze513 1:94c648931f84 2909 BYTE value, /* Attribute bits */
Blaze513 1:94c648931f84 2910 BYTE mask /* Attribute mask to change */
Blaze513 1:94c648931f84 2911 )
Blaze513 1:94c648931f84 2912 {
Blaze513 1:94c648931f84 2913 FRESULT res;
Blaze513 1:94c648931f84 2914 FAT_DIR dj;
Blaze513 1:94c648931f84 2915 BYTE *dir;
Blaze513 1:94c648931f84 2916 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2917
Blaze513 1:94c648931f84 2918
Blaze513 1:94c648931f84 2919 res = chk_mounted(&path, &dj.fs, 1);
Blaze513 1:94c648931f84 2920 if (res == FR_OK) {
Blaze513 1:94c648931f84 2921 INIT_BUF(dj);
Blaze513 1:94c648931f84 2922 res = follow_path(&dj, path); /* Follow the file path */
Blaze513 1:94c648931f84 2923 FREE_BUF();
Blaze513 1:94c648931f84 2924 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
Blaze513 1:94c648931f84 2925 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 2926 if (res == FR_OK) {
Blaze513 1:94c648931f84 2927 dir = dj.dir;
Blaze513 1:94c648931f84 2928 if (!dir) { /* Is it a root directory? */
Blaze513 1:94c648931f84 2929 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 2930 } else { /* File or sub directory */
Blaze513 1:94c648931f84 2931 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
Blaze513 1:94c648931f84 2932 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
Blaze513 1:94c648931f84 2933 dj.fs->wflag = 1;
Blaze513 1:94c648931f84 2934 res = sync(dj.fs);
Blaze513 1:94c648931f84 2935 }
Blaze513 1:94c648931f84 2936 }
Blaze513 1:94c648931f84 2937 }
Blaze513 1:94c648931f84 2938
Blaze513 1:94c648931f84 2939 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2940 }
Blaze513 1:94c648931f84 2941
Blaze513 1:94c648931f84 2942
Blaze513 1:94c648931f84 2943
Blaze513 1:94c648931f84 2944
Blaze513 1:94c648931f84 2945 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2946 /* Change Timestamp */
Blaze513 1:94c648931f84 2947 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2948
Blaze513 1:94c648931f84 2949 FRESULT f_utime (
Blaze513 1:94c648931f84 2950 const TCHAR *path, /* Pointer to the file/directory name */
Blaze513 1:94c648931f84 2951 const FILINFO *fno /* Pointer to the time stamp to be set */
Blaze513 1:94c648931f84 2952 )
Blaze513 1:94c648931f84 2953 {
Blaze513 1:94c648931f84 2954 FRESULT res;
Blaze513 1:94c648931f84 2955 FAT_DIR dj;
Blaze513 1:94c648931f84 2956 BYTE *dir;
Blaze513 1:94c648931f84 2957 DEF_NAMEBUF;
Blaze513 1:94c648931f84 2958
Blaze513 1:94c648931f84 2959
Blaze513 1:94c648931f84 2960 res = chk_mounted(&path, &dj.fs, 1);
Blaze513 1:94c648931f84 2961 if (res == FR_OK) {
Blaze513 1:94c648931f84 2962 INIT_BUF(dj);
Blaze513 1:94c648931f84 2963 res = follow_path(&dj, path); /* Follow the file path */
Blaze513 1:94c648931f84 2964 FREE_BUF();
Blaze513 1:94c648931f84 2965 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
Blaze513 1:94c648931f84 2966 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 2967 if (res == FR_OK) {
Blaze513 1:94c648931f84 2968 dir = dj.dir;
Blaze513 1:94c648931f84 2969 if (!dir) { /* Root directory */
Blaze513 1:94c648931f84 2970 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 2971 } else { /* File or sub-directory */
Blaze513 1:94c648931f84 2972 ST_WORD(dir+DIR_WrtTime, fno->ftime);
Blaze513 1:94c648931f84 2973 ST_WORD(dir+DIR_WrtDate, fno->fdate);
Blaze513 1:94c648931f84 2974 dj.fs->wflag = 1;
Blaze513 1:94c648931f84 2975 res = sync(dj.fs);
Blaze513 1:94c648931f84 2976 }
Blaze513 1:94c648931f84 2977 }
Blaze513 1:94c648931f84 2978 }
Blaze513 1:94c648931f84 2979
Blaze513 1:94c648931f84 2980 LEAVE_FF(dj.fs, res);
Blaze513 1:94c648931f84 2981 }
Blaze513 1:94c648931f84 2982
Blaze513 1:94c648931f84 2983
Blaze513 1:94c648931f84 2984
Blaze513 1:94c648931f84 2985
Blaze513 1:94c648931f84 2986 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2987 /* Rename File/Directory */
Blaze513 1:94c648931f84 2988 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 2989
Blaze513 1:94c648931f84 2990 FRESULT f_rename (
Blaze513 1:94c648931f84 2991 const TCHAR *path_old, /* Pointer to the old name */
Blaze513 1:94c648931f84 2992 const TCHAR *path_new /* Pointer to the new name */
Blaze513 1:94c648931f84 2993 )
Blaze513 1:94c648931f84 2994 {
Blaze513 1:94c648931f84 2995 FRESULT res;
Blaze513 1:94c648931f84 2996 FAT_DIR djo, djn;
Blaze513 1:94c648931f84 2997 BYTE buf[21], *dir;
Blaze513 1:94c648931f84 2998 DWORD dw;
Blaze513 1:94c648931f84 2999 DEF_NAMEBUF;
Blaze513 1:94c648931f84 3000
Blaze513 1:94c648931f84 3001
Blaze513 1:94c648931f84 3002 res = chk_mounted(&path_old, &djo.fs, 1);
Blaze513 1:94c648931f84 3003 if (res == FR_OK) {
Blaze513 1:94c648931f84 3004 djn.fs = djo.fs;
Blaze513 1:94c648931f84 3005 INIT_BUF(djo);
Blaze513 1:94c648931f84 3006 res = follow_path(&djo, path_old); /* Check old object */
Blaze513 1:94c648931f84 3007 if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
Blaze513 1:94c648931f84 3008 res = FR_INVALID_NAME;
Blaze513 1:94c648931f84 3009 #if _FS_SHARE
Blaze513 1:94c648931f84 3010 if (res == FR_OK) res = chk_lock(&djo, 2);
Blaze513 1:94c648931f84 3011 #endif
Blaze513 1:94c648931f84 3012 if (res == FR_OK) { /* Old object is found */
Blaze513 1:94c648931f84 3013 if (!djo.dir) { /* Is root dir? */
Blaze513 1:94c648931f84 3014 res = FR_NO_FILE;
Blaze513 1:94c648931f84 3015 } else {
Blaze513 1:94c648931f84 3016 mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */
Blaze513 1:94c648931f84 3017 mem_cpy(&djn, &djo, sizeof(FAT_DIR)); /* Check new object */
Blaze513 1:94c648931f84 3018 res = follow_path(&djn, path_new);
Blaze513 1:94c648931f84 3019 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
Blaze513 1:94c648931f84 3020 if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
Blaze513 1:94c648931f84 3021 /* Start critical section that any interruption or error can cause cross-link */
Blaze513 1:94c648931f84 3022 res = dir_register(&djn); /* Register the new entry */
Blaze513 1:94c648931f84 3023 if (res == FR_OK) {
Blaze513 1:94c648931f84 3024 dir = djn.dir; /* Copy object information except for name */
Blaze513 1:94c648931f84 3025 mem_cpy(dir+13, buf+2, 19);
Blaze513 1:94c648931f84 3026 dir[DIR_Attr] = buf[0] | AM_ARC;
Blaze513 1:94c648931f84 3027 djo.fs->wflag = 1;
Blaze513 1:94c648931f84 3028 if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */
Blaze513 1:94c648931f84 3029 dw = clust2sect(djn.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO));
Blaze513 1:94c648931f84 3030 if (!dw) {
Blaze513 1:94c648931f84 3031 res = FR_INT_ERR;
Blaze513 1:94c648931f84 3032 } else {
Blaze513 1:94c648931f84 3033 res = move_window(djn.fs, dw);
Blaze513 1:94c648931f84 3034 dir = djn.fs->win+32; /* .. entry */
Blaze513 1:94c648931f84 3035 if (res == FR_OK && dir[1] == '.') {
Blaze513 1:94c648931f84 3036 dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust;
Blaze513 1:94c648931f84 3037 ST_WORD(dir+DIR_FstClusLO, dw);
Blaze513 1:94c648931f84 3038 ST_WORD(dir+DIR_FstClusHI, dw >> 16);
Blaze513 1:94c648931f84 3039 djn.fs->wflag = 1;
Blaze513 1:94c648931f84 3040 }
Blaze513 1:94c648931f84 3041 }
Blaze513 1:94c648931f84 3042 }
Blaze513 1:94c648931f84 3043 if (res == FR_OK) {
Blaze513 1:94c648931f84 3044 res = dir_remove(&djo); /* Remove old entry */
Blaze513 1:94c648931f84 3045 if (res == FR_OK)
Blaze513 1:94c648931f84 3046 res = sync(djo.fs);
Blaze513 1:94c648931f84 3047 }
Blaze513 1:94c648931f84 3048 }
Blaze513 1:94c648931f84 3049 /* End critical section */
Blaze513 1:94c648931f84 3050 }
Blaze513 1:94c648931f84 3051 }
Blaze513 1:94c648931f84 3052 }
Blaze513 1:94c648931f84 3053 FREE_BUF();
Blaze513 1:94c648931f84 3054 }
Blaze513 1:94c648931f84 3055 LEAVE_FF(djo.fs, res);
Blaze513 1:94c648931f84 3056 }
Blaze513 1:94c648931f84 3057
Blaze513 1:94c648931f84 3058 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 3059 #endif /* _FS_MINIMIZE == 0 */
Blaze513 1:94c648931f84 3060 #endif /* _FS_MINIMIZE <= 1 */
Blaze513 1:94c648931f84 3061 #endif /* _FS_MINIMIZE <= 2 */
Blaze513 1:94c648931f84 3062
Blaze513 1:94c648931f84 3063
Blaze513 1:94c648931f84 3064
Blaze513 1:94c648931f84 3065 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3066 /* Forward data to the stream directly (available on only tiny cfg) */
Blaze513 1:94c648931f84 3067 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3068 #if _USE_FORWARD && _FS_TINY
Blaze513 1:94c648931f84 3069
Blaze513 1:94c648931f84 3070 FRESULT f_forward (
Blaze513 1:94c648931f84 3071 FAT_FIL *fp, /* Pointer to the file object */
Blaze513 1:94c648931f84 3072 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
Blaze513 1:94c648931f84 3073 UINT btr, /* Number of bytes to forward */
Blaze513 1:94c648931f84 3074 UINT *bf /* Pointer to number of bytes forwarded */
Blaze513 1:94c648931f84 3075 )
Blaze513 1:94c648931f84 3076 {
Blaze513 1:94c648931f84 3077 FRESULT res;
Blaze513 1:94c648931f84 3078 DWORD remain, clst, sect;
Blaze513 1:94c648931f84 3079 UINT rcnt;
Blaze513 1:94c648931f84 3080 BYTE csect;
Blaze513 1:94c648931f84 3081
Blaze513 1:94c648931f84 3082
Blaze513 1:94c648931f84 3083 *bf = 0; /* Initialize byte counter */
Blaze513 1:94c648931f84 3084
Blaze513 1:94c648931f84 3085 res = validate(fp->fs, fp->id); /* Check validity of the object */
Blaze513 1:94c648931f84 3086 if (res != FR_OK) LEAVE_FF(fp->fs, res);
Blaze513 1:94c648931f84 3087 if (fp->flag & FA__ERROR) /* Check error flag */
Blaze513 1:94c648931f84 3088 LEAVE_FF(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 3089 if (!(fp->flag & FA_READ)) /* Check access mode */
Blaze513 1:94c648931f84 3090 LEAVE_FF(fp->fs, FR_DENIED);
Blaze513 1:94c648931f84 3091
Blaze513 1:94c648931f84 3092 remain = fp->fsize - fp->fptr;
Blaze513 1:94c648931f84 3093 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
Blaze513 1:94c648931f84 3094
Blaze513 1:94c648931f84 3095 for ( ; btr && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
Blaze513 1:94c648931f84 3096 fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
Blaze513 1:94c648931f84 3097 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
Blaze513 1:94c648931f84 3098 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
Blaze513 1:94c648931f84 3099 if (!csect) { /* On the cluster boundary? */
Blaze513 1:94c648931f84 3100 clst = (fp->fptr == 0) ? /* On the top of the file? */
Blaze513 1:94c648931f84 3101 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
Blaze513 1:94c648931f84 3102 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 3103 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 3104 fp->curr_clust = clst; /* Update current cluster */
Blaze513 1:94c648931f84 3105 }
Blaze513 1:94c648931f84 3106 }
Blaze513 1:94c648931f84 3107 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current data sector */
Blaze513 1:94c648931f84 3108 if (!sect) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 3109 sect += csect;
Blaze513 1:94c648931f84 3110 if (move_window(fp->fs, sect)) /* Move sector window */
Blaze513 1:94c648931f84 3111 ABORT(fp->fs, FR_DISK_ERR);
Blaze513 1:94c648931f84 3112 fp->dsect = sect;
Blaze513 1:94c648931f84 3113 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
Blaze513 1:94c648931f84 3114 if (rcnt > btr) rcnt = btr;
Blaze513 1:94c648931f84 3115 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
Blaze513 1:94c648931f84 3116 if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
Blaze513 1:94c648931f84 3117 }
Blaze513 1:94c648931f84 3118
Blaze513 1:94c648931f84 3119 LEAVE_FF(fp->fs, FR_OK);
Blaze513 1:94c648931f84 3120 }
Blaze513 1:94c648931f84 3121 #endif /* _USE_FORWARD */
Blaze513 1:94c648931f84 3122
Blaze513 1:94c648931f84 3123
Blaze513 1:94c648931f84 3124
Blaze513 1:94c648931f84 3125 #if _USE_MKFS && !_FS_READONLY
Blaze513 1:94c648931f84 3126 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3127 /* Create File System on the Drive */
Blaze513 1:94c648931f84 3128 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3129 #define N_ROOTDIR 512 /* Multiple of 32 */
Blaze513 1:94c648931f84 3130 #define N_FATS 1 /* 1 or 2 */
Blaze513 1:94c648931f84 3131
Blaze513 1:94c648931f84 3132
Blaze513 1:94c648931f84 3133 FRESULT f_mkfs (
Blaze513 1:94c648931f84 3134 BYTE drv, /* Logical drive number */
Blaze513 1:94c648931f84 3135 BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
Blaze513 1:94c648931f84 3136 UINT au /* Allocation unit size [bytes] */
Blaze513 1:94c648931f84 3137 )
Blaze513 1:94c648931f84 3138 {
Blaze513 1:94c648931f84 3139 static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
Blaze513 1:94c648931f84 3140 static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
Blaze513 1:94c648931f84 3141 BYTE fmt, md, *tbl;
Blaze513 1:94c648931f84 3142 DWORD n_clst, vs, n;
Blaze513 1:94c648931f84 3143 UINT as, i;
Blaze513 1:94c648931f84 3144 DWORD b_vol, b_fat, b_dir, b_data; /* Area offset (LBA) */
Blaze513 1:94c648931f84 3145 DWORD n_vol, n_rsv, n_fat, n_dir; /* Area size */
Blaze513 1:94c648931f84 3146 FATFS *fs;
Blaze513 1:94c648931f84 3147 DSTATUS stat;
Blaze513 1:94c648931f84 3148
Blaze513 1:94c648931f84 3149
Blaze513 1:94c648931f84 3150 /* Check mounted drive and clear work area */
Blaze513 1:94c648931f84 3151 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
Blaze513 1:94c648931f84 3152 fs = FatFs[drv];
Blaze513 1:94c648931f84 3153 if (!fs) return FR_NOT_ENABLED;
Blaze513 1:94c648931f84 3154 fs->fs_type = 0;
Blaze513 1:94c648931f84 3155 drv = LD2PD(drv);
Blaze513 1:94c648931f84 3156
Blaze513 1:94c648931f84 3157 /* Get disk statics */
Blaze513 1:94c648931f84 3158 stat = disk_initialize(drv);
Blaze513 1:94c648931f84 3159 if (stat & STA_NOINIT) return FR_NOT_READY;
Blaze513 1:94c648931f84 3160 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
Blaze513 1:94c648931f84 3161 #if _MAX_SS != 512 /* Get disk sector size */
Blaze513 1:94c648931f84 3162 if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
Blaze513 1:94c648931f84 3163 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3164 #endif
Blaze513 1:94c648931f84 3165 if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
Blaze513 1:94c648931f84 3166 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3167 b_vol = (sfd == 1) ? 0 : 63; /* Volume start sector */
Blaze513 1:94c648931f84 3168 n_vol -= b_vol;
Blaze513 1:94c648931f84 3169 if (au & (au - 1)) au = 0; /* Check validity of the allocation unit size */
Blaze513 1:94c648931f84 3170 if (!au) { /* AU auto selection */
Blaze513 1:94c648931f84 3171 vs = n_vol / (2000 / (SS(fs) / 512));
Blaze513 1:94c648931f84 3172 for (i = 0; vs < vst[i]; i++) ;
Blaze513 1:94c648931f84 3173 au = cst[i];
Blaze513 1:94c648931f84 3174 }
Blaze513 1:94c648931f84 3175 if (_MAX_SS != 512 && au < SS(fs)) au = SS(fs);
Blaze513 1:94c648931f84 3176 au /= SS(fs); /* Number of sectors per cluster */
Blaze513 1:94c648931f84 3177 if (au == 0) au = 1;
Blaze513 1:94c648931f84 3178 if (au > 128) au = 128;
Blaze513 1:94c648931f84 3179
Blaze513 1:94c648931f84 3180 /* Pre-compute number of clusters and FAT syb-type */
Blaze513 1:94c648931f84 3181 n_clst = n_vol / au;
Blaze513 1:94c648931f84 3182 fmt = FS_FAT12;
Blaze513 1:94c648931f84 3183 if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
Blaze513 1:94c648931f84 3184 if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
Blaze513 1:94c648931f84 3185
Blaze513 1:94c648931f84 3186 /* Determine offset and size of FAT structure */
Blaze513 1:94c648931f84 3187 if (fmt == FS_FAT32) {
Blaze513 1:94c648931f84 3188 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
Blaze513 1:94c648931f84 3189 n_rsv = 32;
Blaze513 1:94c648931f84 3190 n_dir = 0;
Blaze513 1:94c648931f84 3191 } else {
Blaze513 1:94c648931f84 3192 n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
Blaze513 1:94c648931f84 3193 n_fat = (n_fat + SS(fs) - 1) / SS(fs);
Blaze513 1:94c648931f84 3194 n_rsv = 1;
Blaze513 1:94c648931f84 3195 n_dir = N_ROOTDIR * 32UL / SS(fs);
Blaze513 1:94c648931f84 3196 }
Blaze513 1:94c648931f84 3197 b_fat = b_vol + n_rsv; /* FAT area start sector */
Blaze513 1:94c648931f84 3198 b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
Blaze513 1:94c648931f84 3199 b_data = b_dir + n_dir; /* Data area start sector */
Blaze513 1:94c648931f84 3200 if (n_vol < b_data + au) return FR_MKFS_ABORTED; /* Too small volume */
Blaze513 1:94c648931f84 3201
Blaze513 1:94c648931f84 3202 /* Align data start sector to erase block boundary (for flash memory media) */
Blaze513 1:94c648931f84 3203 if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_DISK_ERR;
Blaze513 1:94c648931f84 3204 if (!n || n > 32768) return FR_MKFS_ABORTED;
Blaze513 1:94c648931f84 3205 n = (b_data + n - 1) & ~(n - 1); /* Next nearest boundary from current data start */
Blaze513 1:94c648931f84 3206 n = (n - b_data) / N_FATS;
Blaze513 1:94c648931f84 3207 if (fmt == FS_FAT32) { /* FAT32: Move FAT start */
Blaze513 1:94c648931f84 3208 n_rsv += n;
Blaze513 1:94c648931f84 3209 b_fat += n;
Blaze513 1:94c648931f84 3210 } else { /* FAT12/16: Expand FAT size */
Blaze513 1:94c648931f84 3211 n_fat += n;
Blaze513 1:94c648931f84 3212 }
Blaze513 1:94c648931f84 3213 /* b_dir and b_data are no longer used below */
Blaze513 1:94c648931f84 3214
Blaze513 1:94c648931f84 3215 /* Determine number of cluster and final check of validity of the FAT sub-type */
Blaze513 1:94c648931f84 3216 n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
Blaze513 1:94c648931f84 3217 if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
Blaze513 1:94c648931f84 3218 || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
Blaze513 1:94c648931f84 3219 return FR_MKFS_ABORTED;
Blaze513 1:94c648931f84 3220
Blaze513 1:94c648931f84 3221 /* Create partition table if required */
Blaze513 1:94c648931f84 3222 if (sfd == 1) {
Blaze513 1:94c648931f84 3223 md = 0xF0;
Blaze513 1:94c648931f84 3224 } else {
Blaze513 1:94c648931f84 3225 DWORD n_disk = b_vol + n_vol;
Blaze513 1:94c648931f84 3226
Blaze513 1:94c648931f84 3227 mem_set(fs->win, 0, SS(fs));
Blaze513 1:94c648931f84 3228 tbl = fs->win+MBR_Table;
Blaze513 1:94c648931f84 3229 ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */
Blaze513 1:94c648931f84 3230 if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */
Blaze513 1:94c648931f84 3231 n_disk = n_disk / 63 / 255;
Blaze513 1:94c648931f84 3232 tbl[7] = (BYTE)n_disk;
Blaze513 1:94c648931f84 3233 tbl[6] = (BYTE)((n_disk >> 2) | 63);
Blaze513 1:94c648931f84 3234 } else {
Blaze513 1:94c648931f84 3235 ST_WORD(&tbl[6], 0xFFFF);
Blaze513 1:94c648931f84 3236 }
Blaze513 1:94c648931f84 3237 tbl[5] = 254;
Blaze513 1:94c648931f84 3238 if (fmt != FS_FAT32) /* System ID */
Blaze513 1:94c648931f84 3239 tbl[4] = (n_vol < 0x10000) ? 0x04 : 0x06;
Blaze513 1:94c648931f84 3240 else
Blaze513 1:94c648931f84 3241 tbl[4] = 0x0c;
Blaze513 1:94c648931f84 3242 ST_DWORD(tbl+8, 63); /* Partition start in LBA */
Blaze513 1:94c648931f84 3243 ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */
Blaze513 1:94c648931f84 3244 ST_WORD(tbl+64, 0xAA55); /* Signature */
Blaze513 1:94c648931f84 3245 if (disk_write(drv, fs->win, 0, 1) != RES_OK)
Blaze513 1:94c648931f84 3246 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3247 md = 0xF8;
Blaze513 1:94c648931f84 3248 }
Blaze513 1:94c648931f84 3249
Blaze513 1:94c648931f84 3250 /* Create VBR */
Blaze513 1:94c648931f84 3251 tbl = fs->win; /* Clear buffer */
Blaze513 1:94c648931f84 3252 mem_set(tbl, 0, SS(fs));
Blaze513 1:94c648931f84 3253 ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */
Blaze513 1:94c648931f84 3254 as = SS(fs); /* Sector size */
Blaze513 1:94c648931f84 3255 ST_WORD(tbl+BPB_BytsPerSec, as);
Blaze513 1:94c648931f84 3256 tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
Blaze513 1:94c648931f84 3257 ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
Blaze513 1:94c648931f84 3258 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
Blaze513 1:94c648931f84 3259 as = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */
Blaze513 1:94c648931f84 3260 ST_WORD(tbl+BPB_RootEntCnt, as);
Blaze513 1:94c648931f84 3261 if (n_vol < 0x10000) { /* Number of total sectors */
Blaze513 1:94c648931f84 3262 ST_WORD(tbl+BPB_TotSec16, n_vol);
Blaze513 1:94c648931f84 3263 } else {
Blaze513 1:94c648931f84 3264 ST_DWORD(tbl+BPB_TotSec32, n_vol);
Blaze513 1:94c648931f84 3265 }
Blaze513 1:94c648931f84 3266 tbl[BPB_Media] = md; /* Media descriptor */
Blaze513 1:94c648931f84 3267 ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
Blaze513 1:94c648931f84 3268 ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
Blaze513 1:94c648931f84 3269 ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */
Blaze513 1:94c648931f84 3270 n = get_fattime(); /* Use current time as VSN */
Blaze513 1:94c648931f84 3271 if (fmt == FS_FAT32) {
Blaze513 1:94c648931f84 3272 ST_DWORD(tbl+BS_VolID32, n); /* VSN */
Blaze513 1:94c648931f84 3273 ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */
Blaze513 1:94c648931f84 3274 ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */
Blaze513 1:94c648931f84 3275 ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */
Blaze513 1:94c648931f84 3276 ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */
Blaze513 1:94c648931f84 3277 tbl[BS_DrvNum32] = 0x80; /* Drive number */
Blaze513 1:94c648931f84 3278 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
Blaze513 1:94c648931f84 3279 mem_cpy(tbl+BS_VolLab32, "NO NAME FAT32 ", 19); /* Volume label, FAT signature */
Blaze513 1:94c648931f84 3280 } else {
Blaze513 1:94c648931f84 3281 ST_DWORD(tbl+BS_VolID, n); /* VSN */
Blaze513 1:94c648931f84 3282 ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */
Blaze513 1:94c648931f84 3283 tbl[BS_DrvNum] = 0x80; /* Drive number */
Blaze513 1:94c648931f84 3284 tbl[BS_BootSig] = 0x29; /* Extended boot signature */
Blaze513 1:94c648931f84 3285 mem_cpy(tbl+BS_VolLab, "NO NAME FAT ", 19); /* Volume label, FAT signature */
Blaze513 1:94c648931f84 3286 }
Blaze513 1:94c648931f84 3287 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
Blaze513 1:94c648931f84 3288 if (disk_write(drv, tbl, b_vol, 1) != RES_OK) /* Original (VBR) */
Blaze513 1:94c648931f84 3289 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3290 if (fmt == FS_FAT32) /* Backup (VBR+6) */
Blaze513 1:94c648931f84 3291 disk_write(drv, tbl, b_vol + 6, 1);
Blaze513 1:94c648931f84 3292
Blaze513 1:94c648931f84 3293 /* Initialize FAT area */
Blaze513 1:94c648931f84 3294 for (i = 0; i < N_FATS; i++) {
Blaze513 1:94c648931f84 3295 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
Blaze513 1:94c648931f84 3296 n = md; /* Media descriptor byte */
Blaze513 1:94c648931f84 3297 if (fmt != FS_FAT32) {
Blaze513 1:94c648931f84 3298 n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
Blaze513 1:94c648931f84 3299 ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */
Blaze513 1:94c648931f84 3300 } else {
Blaze513 1:94c648931f84 3301 n |= 0x0FFFFF00;
Blaze513 1:94c648931f84 3302 ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */
Blaze513 1:94c648931f84 3303 ST_DWORD(tbl+4, 0x0FFFFFFF);
Blaze513 1:94c648931f84 3304 ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
Blaze513 1:94c648931f84 3305 }
Blaze513 1:94c648931f84 3306 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
Blaze513 1:94c648931f84 3307 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3308 mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
Blaze513 1:94c648931f84 3309 for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector write */
Blaze513 1:94c648931f84 3310 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
Blaze513 1:94c648931f84 3311 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3312 }
Blaze513 1:94c648931f84 3313 }
Blaze513 1:94c648931f84 3314
Blaze513 1:94c648931f84 3315 /* Initialize root directory */
Blaze513 1:94c648931f84 3316 n = (fmt == FS_FAT32) ? as : n_dir;
Blaze513 1:94c648931f84 3317 while (n--) {
Blaze513 1:94c648931f84 3318 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
Blaze513 1:94c648931f84 3319 return FR_DISK_ERR;
Blaze513 1:94c648931f84 3320 }
Blaze513 1:94c648931f84 3321
Blaze513 1:94c648931f84 3322 /* Create FSInfo record if needed */
Blaze513 1:94c648931f84 3323 if (fmt == FS_FAT32) {
Blaze513 1:94c648931f84 3324 ST_WORD(tbl+BS_55AA, 0xAA55);
Blaze513 1:94c648931f84 3325 ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
Blaze513 1:94c648931f84 3326 ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
Blaze513 1:94c648931f84 3327 ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
Blaze513 1:94c648931f84 3328 ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
Blaze513 1:94c648931f84 3329 disk_write(drv, tbl, b_vol + 1, 1); /* Original (VBR+1) */
Blaze513 1:94c648931f84 3330 disk_write(drv, tbl, b_vol + 7, 1); /* Backup (VBR+7) */
Blaze513 1:94c648931f84 3331 }
Blaze513 1:94c648931f84 3332
Blaze513 1:94c648931f84 3333 return (disk_ioctl(drv, CTRL_SYNC, (void*)0) == RES_OK) ? FR_OK : FR_DISK_ERR;
Blaze513 1:94c648931f84 3334 }
Blaze513 1:94c648931f84 3335
Blaze513 1:94c648931f84 3336 #endif /* _USE_MKFS && !_FS_READONLY */
Blaze513 1:94c648931f84 3337
Blaze513 1:94c648931f84 3338
Blaze513 1:94c648931f84 3339
Blaze513 1:94c648931f84 3340
Blaze513 1:94c648931f84 3341 #if _USE_STRFUNC
Blaze513 1:94c648931f84 3342 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3343 /* Get a string from the file */
Blaze513 1:94c648931f84 3344 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3345 TCHAR* f_gets (
Blaze513 1:94c648931f84 3346 TCHAR* buff, /* Pointer to the string buffer to read */
Blaze513 1:94c648931f84 3347 int len, /* Size of string buffer (characters) */
Blaze513 1:94c648931f84 3348 FAT_FIL* fil /* Pointer to the file object */
Blaze513 1:94c648931f84 3349 )
Blaze513 1:94c648931f84 3350 {
Blaze513 1:94c648931f84 3351 int n = 0;
Blaze513 1:94c648931f84 3352 TCHAR c, *p = buff;
Blaze513 1:94c648931f84 3353 BYTE s[2];
Blaze513 1:94c648931f84 3354 UINT rc;
Blaze513 1:94c648931f84 3355
Blaze513 1:94c648931f84 3356
Blaze513 1:94c648931f84 3357 while (n < len - 1) { /* Read bytes until buffer gets filled */
Blaze513 1:94c648931f84 3358 f_read(fil, s, 1, &rc);
Blaze513 1:94c648931f84 3359 if (rc != 1) break; /* Break on EOF or error */
Blaze513 1:94c648931f84 3360 c = s[0];
Blaze513 1:94c648931f84 3361 #if _LFN_UNICODE /* Read a character in UTF-8 encoding */
Blaze513 1:94c648931f84 3362 if (c >= 0x80) {
Blaze513 1:94c648931f84 3363 if (c < 0xC0) continue; /* Skip stray trailer */
Blaze513 1:94c648931f84 3364 if (c < 0xE0) { /* Two-byte sequense */
Blaze513 1:94c648931f84 3365 f_read(fil, s, 1, &rc);
Blaze513 1:94c648931f84 3366 if (rc != 1) break;
Blaze513 1:94c648931f84 3367 c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
Blaze513 1:94c648931f84 3368 if (c < 0x80) c = '?';
Blaze513 1:94c648931f84 3369 } else {
Blaze513 1:94c648931f84 3370 if (c < 0xF0) { /* Three-byte sequense */
Blaze513 1:94c648931f84 3371 f_read(fil, s, 2, &rc);
Blaze513 1:94c648931f84 3372 if (rc != 2) break;
Blaze513 1:94c648931f84 3373 c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
Blaze513 1:94c648931f84 3374 if (c < 0x800) c = '?';
Blaze513 1:94c648931f84 3375 } else { /* Reject four-byte sequense */
Blaze513 1:94c648931f84 3376 c = '?';
Blaze513 1:94c648931f84 3377 }
Blaze513 1:94c648931f84 3378 }
Blaze513 1:94c648931f84 3379 }
Blaze513 1:94c648931f84 3380 #endif
Blaze513 1:94c648931f84 3381 #if _USE_STRFUNC >= 2
Blaze513 1:94c648931f84 3382 if (c == '\r') continue; /* Strip '\r' */
Blaze513 1:94c648931f84 3383 #endif
Blaze513 1:94c648931f84 3384 *p++ = c;
Blaze513 1:94c648931f84 3385 n++;
Blaze513 1:94c648931f84 3386 if (c == '\n') break; /* Break on EOL */
Blaze513 1:94c648931f84 3387 }
Blaze513 1:94c648931f84 3388 *p = 0;
Blaze513 1:94c648931f84 3389 return n ? buff : 0; /* When no data read (eof or error), return with error. */
Blaze513 1:94c648931f84 3390 }
Blaze513 1:94c648931f84 3391
Blaze513 1:94c648931f84 3392
Blaze513 1:94c648931f84 3393
Blaze513 1:94c648931f84 3394 #if !_FS_READONLY
Blaze513 1:94c648931f84 3395 #include <stdarg.h>
Blaze513 1:94c648931f84 3396 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3397 /* Put a character to the file */
Blaze513 1:94c648931f84 3398 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3399 int f_putc (
Blaze513 1:94c648931f84 3400 TCHAR c, /* A character to be output */
Blaze513 1:94c648931f84 3401 FAT_FIL* fil /* Pointer to the file object */
Blaze513 1:94c648931f84 3402 )
Blaze513 1:94c648931f84 3403 {
Blaze513 1:94c648931f84 3404 UINT bw, btw;
Blaze513 1:94c648931f84 3405 BYTE s[3];
Blaze513 1:94c648931f84 3406
Blaze513 1:94c648931f84 3407
Blaze513 1:94c648931f84 3408 #if _USE_STRFUNC >= 2
Blaze513 1:94c648931f84 3409 if (c == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
Blaze513 1:94c648931f84 3410 #endif
Blaze513 1:94c648931f84 3411
Blaze513 1:94c648931f84 3412 #if _LFN_UNICODE /* Write the character in UTF-8 encoding */
Blaze513 1:94c648931f84 3413 if (c < 0x80) { /* 7-bit */
Blaze513 1:94c648931f84 3414 s[0] = (BYTE)c;
Blaze513 1:94c648931f84 3415 btw = 1;
Blaze513 1:94c648931f84 3416 } else {
Blaze513 1:94c648931f84 3417 if (c < 0x800) { /* 11-bit */
Blaze513 1:94c648931f84 3418 s[0] = (BYTE)(0xC0 | (c >> 6));
Blaze513 1:94c648931f84 3419 s[1] = (BYTE)(0x80 | (c & 0x3F));
Blaze513 1:94c648931f84 3420 btw = 2;
Blaze513 1:94c648931f84 3421 } else { /* 16-bit */
Blaze513 1:94c648931f84 3422 s[0] = (BYTE)(0xE0 | (c >> 12));
Blaze513 1:94c648931f84 3423 s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
Blaze513 1:94c648931f84 3424 s[2] = (BYTE)(0x80 | (c & 0x3F));
Blaze513 1:94c648931f84 3425 btw = 3;
Blaze513 1:94c648931f84 3426 }
Blaze513 1:94c648931f84 3427 }
Blaze513 1:94c648931f84 3428 #else /* Write the character without conversion */
Blaze513 1:94c648931f84 3429 s[0] = (BYTE)c;
Blaze513 1:94c648931f84 3430 btw = 1;
Blaze513 1:94c648931f84 3431 #endif
Blaze513 1:94c648931f84 3432 f_write(fil, s, btw, &bw); /* Write the char to the file */
Blaze513 1:94c648931f84 3433 return (bw == btw) ? 1 : EOF; /* Return the result */
Blaze513 1:94c648931f84 3434 }
Blaze513 1:94c648931f84 3435
Blaze513 1:94c648931f84 3436
Blaze513 1:94c648931f84 3437
Blaze513 1:94c648931f84 3438
Blaze513 1:94c648931f84 3439 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3440 /* Put a string to the file */
Blaze513 1:94c648931f84 3441 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3442 int f_puts (
Blaze513 1:94c648931f84 3443 const TCHAR* str, /* Pointer to the string to be output */
Blaze513 1:94c648931f84 3444 FAT_FIL* fil /* Pointer to the file object */
Blaze513 1:94c648931f84 3445 )
Blaze513 1:94c648931f84 3446 {
Blaze513 1:94c648931f84 3447 int n;
Blaze513 1:94c648931f84 3448
Blaze513 1:94c648931f84 3449
Blaze513 1:94c648931f84 3450 for (n = 0; *str; str++, n++) {
Blaze513 1:94c648931f84 3451 if (f_putc(*str, fil) == EOF) return EOF;
Blaze513 1:94c648931f84 3452 }
Blaze513 1:94c648931f84 3453 return n;
Blaze513 1:94c648931f84 3454 }
Blaze513 1:94c648931f84 3455
Blaze513 1:94c648931f84 3456
Blaze513 1:94c648931f84 3457
Blaze513 1:94c648931f84 3458
Blaze513 1:94c648931f84 3459 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3460 /* Put a formatted string to the file */
Blaze513 1:94c648931f84 3461 /*-----------------------------------------------------------------------*/
Blaze513 1:94c648931f84 3462 int f_printf (
Blaze513 1:94c648931f84 3463 FAT_FIL* fil, /* Pointer to the file object */
Blaze513 1:94c648931f84 3464 const TCHAR* str, /* Pointer to the format string */
Blaze513 1:94c648931f84 3465 ... /* Optional arguments... */
Blaze513 1:94c648931f84 3466 )
Blaze513 1:94c648931f84 3467 {
Blaze513 1:94c648931f84 3468 va_list arp;
Blaze513 1:94c648931f84 3469 BYTE f, r;
Blaze513 1:94c648931f84 3470 UINT i, w;
Blaze513 1:94c648931f84 3471 ULONG val;
Blaze513 1:94c648931f84 3472 TCHAR c, d, s[16];
Blaze513 1:94c648931f84 3473 int res, cc;
Blaze513 1:94c648931f84 3474
Blaze513 1:94c648931f84 3475
Blaze513 1:94c648931f84 3476 va_start(arp, str);
Blaze513 1:94c648931f84 3477
Blaze513 1:94c648931f84 3478 for (cc = res = 0; cc != EOF; res += cc) {
Blaze513 1:94c648931f84 3479 c = *str++;
Blaze513 1:94c648931f84 3480 if (c == 0) break; /* End of string */
Blaze513 1:94c648931f84 3481 if (c != '%') { /* Non escape character */
Blaze513 1:94c648931f84 3482 cc = f_putc(c, fil);
Blaze513 1:94c648931f84 3483 if (cc != EOF) cc = 1;
Blaze513 1:94c648931f84 3484 continue;
Blaze513 1:94c648931f84 3485 }
Blaze513 1:94c648931f84 3486 w = f = 0;
Blaze513 1:94c648931f84 3487 c = *str++;
Blaze513 1:94c648931f84 3488 if (c == '0') { /* Flag: '0' padding */
Blaze513 1:94c648931f84 3489 f = 1; c = *str++;
Blaze513 1:94c648931f84 3490 }
Blaze513 1:94c648931f84 3491 while (IsDigit(c)) { /* Precision */
Blaze513 1:94c648931f84 3492 w = w * 10 + c - '0';
Blaze513 1:94c648931f84 3493 c = *str++;
Blaze513 1:94c648931f84 3494 }
Blaze513 1:94c648931f84 3495 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
Blaze513 1:94c648931f84 3496 f |= 2; c = *str++;
Blaze513 1:94c648931f84 3497 }
Blaze513 1:94c648931f84 3498 if (!c) break;
Blaze513 1:94c648931f84 3499 d = c;
Blaze513 1:94c648931f84 3500 if (IsLower(d)) d -= 0x20;
Blaze513 1:94c648931f84 3501 switch (d) { /* Type is... */
Blaze513 1:94c648931f84 3502 case 'S' : /* String */
Blaze513 1:94c648931f84 3503 cc = f_puts(va_arg(arp, TCHAR*), fil); continue;
Blaze513 1:94c648931f84 3504 case 'C' : /* Character */
Blaze513 1:94c648931f84 3505 cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
Blaze513 1:94c648931f84 3506 case 'B' : /* Binary */
Blaze513 1:94c648931f84 3507 r = 2; break;
Blaze513 1:94c648931f84 3508 case 'O' : /* Octal */
Blaze513 1:94c648931f84 3509 r = 8; break;
Blaze513 1:94c648931f84 3510 case 'D' : /* Signed decimal */
Blaze513 1:94c648931f84 3511 case 'U' : /* Unsigned decimal */
Blaze513 1:94c648931f84 3512 r = 10; break;
Blaze513 1:94c648931f84 3513 case 'X' : /* Hexdecimal */
Blaze513 1:94c648931f84 3514 r = 16; break;
Blaze513 1:94c648931f84 3515 default: /* Unknown */
Blaze513 1:94c648931f84 3516 cc = f_putc(c, fil); continue;
Blaze513 1:94c648931f84 3517 }
Blaze513 1:94c648931f84 3518
Blaze513 1:94c648931f84 3519 /* Get an argument */
Blaze513 1:94c648931f84 3520 val = (f & 2) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int));
Blaze513 1:94c648931f84 3521 if (d == 'D' && (val & 0x80000000)) {
Blaze513 1:94c648931f84 3522 val = 0 - val;
Blaze513 1:94c648931f84 3523 f |= 4;
Blaze513 1:94c648931f84 3524 }
Blaze513 1:94c648931f84 3525 /* Put it in numeral string */
Blaze513 1:94c648931f84 3526 i = 0;
Blaze513 1:94c648931f84 3527 do {
Blaze513 1:94c648931f84 3528 d = (TCHAR)(val % r); val /= r;
Blaze513 1:94c648931f84 3529 if (d > 9) {
Blaze513 1:94c648931f84 3530 d += 7;
Blaze513 1:94c648931f84 3531 if (c == 'x') d += 0x20;
Blaze513 1:94c648931f84 3532 }
Blaze513 1:94c648931f84 3533 s[i++] = d + '0';
Blaze513 1:94c648931f84 3534 } while (val && i < sizeof(s) / sizeof(s[0]));
Blaze513 1:94c648931f84 3535 if (f & 4) s[i++] = '-';
Blaze513 1:94c648931f84 3536 cc = 0;
Blaze513 1:94c648931f84 3537 while (i < w-- && cc != EOF) {
Blaze513 1:94c648931f84 3538 cc = f_putc((TCHAR)((f & 1) ? '0' : ' '), fil);
Blaze513 1:94c648931f84 3539 res++;
Blaze513 1:94c648931f84 3540 }
Blaze513 1:94c648931f84 3541 do {
Blaze513 1:94c648931f84 3542 cc = f_putc(s[--i], fil);
Blaze513 1:94c648931f84 3543 res++;
Blaze513 1:94c648931f84 3544 } while (i && cc != EOF);
Blaze513 1:94c648931f84 3545 if (cc != EOF) cc = 0;
Blaze513 1:94c648931f84 3546 }
Blaze513 1:94c648931f84 3547
Blaze513 1:94c648931f84 3548 va_end(arp);
Blaze513 1:94c648931f84 3549 return (cc == EOF) ? cc : res;
Blaze513 1:94c648931f84 3550 }
Blaze513 1:94c648931f84 3551
Blaze513 1:94c648931f84 3552 #endif /* !_FS_READONLY */
Blaze513 1:94c648931f84 3553 #endif /* _USE_STRFUNC */