diff options
author | Dean Camera <dean@fourwalledcubicle.com> | 2011-02-06 15:17:46 +0000 |
---|---|---|
committer | Dean Camera <dean@fourwalledcubicle.com> | 2011-02-06 15:17:46 +0000 |
commit | a95d2241851a4877189b11854f25ff65b6a2b411 (patch) | |
tree | 24a5dbe368c7d6f1db5205168183fb2e6cdf14ea /Projects/TempDataLogger/Lib/FATFs/ff.c | |
parent | b1d75686512a55c73b117fae766945f31f26d913 (diff) | |
download | lufa-a95d2241851a4877189b11854f25ff65b6a2b411.tar.gz lufa-a95d2241851a4877189b11854f25ff65b6a2b411.tar.bz2 lufa-a95d2241851a4877189b11854f25ff65b6a2b411.zip |
Update projects using FatFS and PetiteFatFS to the latest library versions.
Diffstat (limited to 'Projects/TempDataLogger/Lib/FATFs/ff.c')
-rw-r--r-- | Projects/TempDataLogger/Lib/FATFs/ff.c | 1338 |
1 files changed, 882 insertions, 456 deletions
diff --git a/Projects/TempDataLogger/Lib/FATFs/ff.c b/Projects/TempDataLogger/Lib/FATFs/ff.c index ab53ea598..4f76915b6 100644 --- a/Projects/TempDataLogger/Lib/FATFs/ff.c +++ b/Projects/TempDataLogger/Lib/FATFs/ff.c @@ -1,11 +1,11 @@ /*----------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.08 (C)ChaN, 2010 +/ FatFs - FAT file system module R0.08b (C)ChaN, 2011 /-----------------------------------------------------------------------------/ / FatFs module is a generic FAT file system module for small embedded systems. / This is a free software that opened for education, research and commercial / developments under license policy of following terms. / -/ Copyright (C) 2010, ChaN, all right reserved. +/ Copyright (C) 2011, ChaN, all right reserved. / / * The FatFs module is a free software and there is NO WARRANTY. / * No restriction on use. You can use, modify and redistribute it for @@ -45,24 +45,22 @@ / Fixed f_mkdir() on FAT32 creates incorrect directory. / Feb 03,'08 R0.05a Added f_truncate() and f_utime(). / Fixed off by one error at FAT sub-type determination. -/ Fixed btr in f_read() can be mis-truncated. -/ Fixed cached sector is not flushed when create and close -/ without write. +/ Fixed btr in f_read() can be mistruncated. +/ Fixed cached sector is not flushed when create and close without write. / / Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets(). -/ Improved performance of f_lseek() on moving to the same -/ or following cluster. +/ Improved performance of f_lseek() on moving to the same or following cluster. / -/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a buffer configuration option. -/ Added long file name support. -/ Added multiple code page support. +/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a configuration option. (_FS_TINY) +/ Added long file name feature. +/ Added multiple code page feature. / Added re-entrancy for multitask operation. / Added auto cluster size selection to f_mkfs(). / Added rewind option to f_readdir(). / Changed result code of critical errors. / Renamed string functions to avoid name collision. / Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg. -/ Added multiple sector size support. +/ Added multiple sector size feature. / Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error. / Fixed wrong cache control in f_lseek(). / Added relative path feature. @@ -72,15 +70,23 @@ / Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH. / Fixed name matching error on the 13 char boundary. / Added a configuration option, _LFN_UNICODE. -/ Changed f_readdir() to return the SFN with always upper -/ case on non-LFN cfg. +/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. / -/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN) +/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3) / Added file lock feature. (_FS_SHARE) / Added fast seek feature. (_USE_FASTSEEK) / Changed some types on the API, XCHAR->TCHAR. / Changed fname member in the FILINFO structure on Unicode cfg. / String functions support UTF-8 encoding files on Unicode cfg. +/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2) +/ Added sector erase feature. (_USE_ERASE) +/ Moved file lock semaphore table from fs object to the bss. +/ Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'. +/ Fixed f_mkfs() creates wrong FAT32 volume. +/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write(). +/ f_lseek() reports required table size on creating CLMP. +/ Extended format syntax of f_printf function. +/ Ignores duplicated directory separators in given path names. /---------------------------------------------------------------------------*/ #include "ff.h" /* FatFs configurations and declarations */ @@ -93,44 +99,253 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 8085 +#if _FATFS != 8237 #error Wrong include file (ff.h). #endif -/* FAT sub-type boundaries */ -/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */ -#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */ -#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */ - - -/* Definitions corresponds to multiple sector size */ -#if _MAX_SS == 512 /* Single sector size */ -#define SS(fs) 512U -#elif _MAX_SS == 1024 || _MAX_SS == 2048 || _MAX_SS == 4096 /* Multiple sector size */ -#define SS(fs) ((fs)->ssize) -#else +/* Definitions on sector size */ +#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096 #error Wrong sector size. #endif +#if _MAX_SS != 512 +#define SS(fs) ((fs)->ssize) /* Multiple sector size */ +#else +#define SS(fs) 512U /* Fixed sector size */ +#endif -/* Re-entrancy related */ +/* Reentrancy related */ #if _FS_REENTRANT #if _USE_LFN == 1 #error Static LFN work area must not be used in re-entrant configuration. #endif #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } - #else #define ENTER_FF(fs) #define LEAVE_FF(fs, res) return res - #endif #define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); } +/* File shareing feature */ +#if _FS_SHARE +#if _FS_READONLY +#error _FS_SHARE must be 0 on read-only cfg. +#endif +typedef struct { + FATFS *fs; /* File ID 1, volume (NULL:blank entry) */ + DWORD clu; /* File ID 2, directory */ + WORD idx; /* File ID 3, directory index */ + WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */ +} FILESEM; +#endif + + +/* Misc definitions */ +#define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO)) +#define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);} + + +/* DBCS code ranges and SBCS extend char conversion table */ + +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} + +#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1253 /* Greek (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ + 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} + +#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1256 /* Arabic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1257 /* Baltic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#if _USE_LFN +#error Cannot use LFN feature without valid code page. +#endif +#define _DF1S 0 + +#else +#error Unknown code page + +#endif + + /* Character code support macros */ #define IsUpper(c) (((c)>='A')&&((c)<='Z')) #define IsLower(c) (((c)>='a')&&((c)<='z')) @@ -159,7 +374,7 @@ /* Name status flags */ -#define NS 11 /* Offset of name status byte */ +#define NS 11 /* Index of name status byte in fn[] */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ @@ -168,23 +383,97 @@ #define NS_DOT 0x20 /* Dot entry */ +/* FAT sub-type boundaries */ +/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */ +#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */ +#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */ + + +/* FatFs refers the members in the FAT structures as byte array instead of +/ structure member because the structure is not binary compatible between +/ different platforms */ + +#define BS_jmpBoot 0 /* Jump instruction (3) */ +#define BS_OEMName 3 /* OEM name (8) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ +#define BPB_NumFATs 16 /* Number of FAT copies (1) */ +#define BPB_RootEntCnt 17 /* Number of root dir entries for FAT12/16 (2) */ +#define BPB_TotSec16 19 /* Volume size [sector] (2) */ +#define BPB_Media 21 /* Media descriptor (1) */ +#define BPB_FATSz16 22 /* FAT size [sector] (2) */ +#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ +#define BPB_NumHeads 26 /* Number of heads (2) */ +#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ +#define BPB_TotSec32 32 /* Volume size [sector] (4) */ +#define BS_DrvNum 36 /* Physical drive number (2) */ +#define BS_BootSig 38 /* Extended boot signature (1) */ +#define BS_VolID 39 /* Volume serial number (4) */ +#define BS_VolLab 43 /* Volume label (8) */ +#define BS_FilSysType 54 /* File system type (1) */ +#define BPB_FATSz32 36 /* FAT size [sector] (4) */ +#define BPB_ExtFlags 40 /* Extended flags (2) */ +#define BPB_FSVer 42 /* File system version (2) */ +#define BPB_RootClus 44 /* Root dir first cluster (4) */ +#define BPB_FSInfo 48 /* Offset of FSInfo sector (2) */ +#define BPB_BkBootSec 50 /* Offset of backup boot sectot (2) */ +#define BS_DrvNum32 64 /* Physical drive number (2) */ +#define BS_BootSig32 66 /* Extended boot signature (1) */ +#define BS_VolID32 67 /* Volume serial number (4) */ +#define BS_VolLab32 71 /* Volume label (8) */ +#define BS_FilSysType32 82 /* File system type (1) */ +#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ +#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ +#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ +#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ +#define MBR_Table 446 /* MBR: Partition table offset (2) */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define BS_55AA 510 /* Boot sector signature (2) */ + +#define DIR_Name 0 /* Short file name (11) */ +#define DIR_Attr 11 /* Attribute (1) */ +#define DIR_NTres 12 /* NT flag (1) */ +#define DIR_CrtTime 14 /* Created time (2) */ +#define DIR_CrtDate 16 /* Created date (2) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ +#define DIR_WrtTime 22 /* Modified time (2) */ +#define DIR_WrtDate 24 /* Modified date (2) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ +#define DIR_FileSize 28 /* File size (4) */ +#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ +#define LDIR_Attr 11 /* LFN attribute (1) */ +#define LDIR_Type 12 /* LFN type (1) */ +#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ +#define LDIR_FstClusLO 26 /* Filled by zero (0) */ +#define SZ_DIR 32 /* Size of a directory entry */ +#define LLE 0x40 /* Last long entry flag in LDIR_Ord */ +#define DDE 0xE5 /* Deleted directory enrty mark in DIR_Name[0] */ +#define NDDE 0x05 /* Replacement of a character collides with DDE */ + /*------------------------------------------------------------*/ /* Work area */ -#if !_DRIVES +#if _VOLUMES +static +FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ +#else #error Number of drives must not be 0. #endif + static WORD Fsid; /* File system mount ID */ -static -FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */ #if _FS_RPATH static -BYTE Drive; /* Current drive */ +BYTE CurrVol; /* Current drive */ #endif +#if _FS_SHARE +static +FILESEM Files[_FS_SHARE]; /* File lock semaphores */ +#endif #if _USE_LFN == 0 /* No LFN */ #define DEF_NAMEBUF BYTE sfn[12] @@ -192,13 +481,13 @@ BYTE Drive; /* Current drive */ #define FREE_BUF() #elif _USE_LFN == 1 /* LFN with static LFN working buffer */ -static WCHAR LfnBuf[_MAX_LFN + 1]; +static WCHAR LfnBuf[_MAX_LFN+1]; #define DEF_NAMEBUF BYTE sfn[12] #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } #define FREE_BUF() #elif _USE_LFN == 2 /* LFN with dynamic LFN working buffer on the stack */ -#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1] +#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1] #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } #define FREE_BUF() @@ -229,7 +518,7 @@ static WCHAR LfnBuf[_MAX_LFN + 1]; /* Copy memory to memory */ static -void mem_cpy (void* dst, const void* src, int cnt) { +void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; @@ -246,7 +535,7 @@ void mem_cpy (void* dst, const void* src, int cnt) { /* Fill memory */ static -void mem_set (void* dst, int val, int cnt) { +void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; while (cnt--) @@ -255,7 +544,7 @@ void mem_set (void* dst, int val, int cnt) { /* Compare memory to memory */ static -int mem_cmp (const void* dst, const void* src, int cnt) { +int mem_cmp (const void* dst, const void* src, UINT cnt) { const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; @@ -304,7 +593,7 @@ void unlock_fs ( /*-----------------------------------------------------------------------*/ -/* File sharing control functions */ +/* File shareing control functions */ /*-----------------------------------------------------------------------*/ #if _FS_SHARE @@ -318,18 +607,19 @@ FRESULT chk_lock ( /* Check if the file can be accessed */ /* Search file semaphore table */ for (i = be = 0; i < _FS_SHARE; i++) { - if (dj->fs->flsem[i].ctr) { /* Existing entry */ - if (dj->fs->flsem[i].clu == dj->sclust && /* The file is found (identified with its location) */ - dj->fs->flsem[i].idx == dj->index) break; - } else { /* Blank entry */ + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dj->fs && /* Check if the file matched with an open file */ + Files[i].clu == dj->sclust && + Files[i].idx == dj->index) break; + } else { /* Blank entry */ be++; } } - if (i == _FS_SHARE) /* The file has not been opened */ - return (be || acc != 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */ + if (i == _FS_SHARE) /* The file is not opened */ + return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */ /* The file has been opened. Reject any open against writing file and all write mode open */ - return (acc || dj->fs->flsem[i].ctr == 0x100) ? FR_LOCKED : FR_OK; + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } @@ -340,7 +630,7 @@ int enq_lock ( /* Check if an entry is available for a new file */ { UINT i; - for (i = 0; i < _FS_SHARE && fs->flsem[i].ctr; i++) ; + for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ; return (i == _FS_SHARE) ? 0 : 1; } @@ -355,21 +645,23 @@ UINT inc_lock ( /* Increment file open counter and returns its index (0:int erro for (i = 0; i < _FS_SHARE; i++) { /* Find the file */ - if (dj->fs->flsem[i].ctr && - dj->fs->flsem[i].clu == dj->sclust && - dj->fs->flsem[i].idx == dj->index) break; + if (Files[i].fs == dj->fs && + Files[i].clu == dj->sclust && + Files[i].idx == dj->index) break; } if (i == _FS_SHARE) { /* Not opened. Register it as new. */ - for (i = 0; i < _FS_SHARE && dj->fs->flsem[i].ctr; i++) ; + for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ; if (i == _FS_SHARE) return 0; /* No space to register (int err) */ - dj->fs->flsem[i].clu = dj->sclust; - dj->fs->flsem[i].idx = dj->index; + Files[i].fs = dj->fs; + Files[i].clu = dj->sclust; + Files[i].idx = dj->index; + Files[i].ctr = 0; } - if (acc && dj->fs->flsem[i].ctr) return 0; /* Access violation (int err) */ + if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ - dj->fs->flsem[i].ctr = acc ? 0x100 : dj->fs->flsem[i].ctr + 1; /* Set semaphore value */ + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ return i + 1; } @@ -377,7 +669,6 @@ UINT inc_lock ( /* Increment file open counter and returns its index (0:int erro static FRESULT dec_lock ( /* Decrement file open counter */ - FATFS* fs, /* File system object */ UINT i /* Semaphore index */ ) { @@ -386,10 +677,11 @@ FRESULT dec_lock ( /* Decrement file open counter */ if (--i < _FS_SHARE) { - n = fs->flsem[i].ctr; - if (n >= 0x100) n = 0; + n = Files[i].ctr; + if (n == 0x100) n = 0; if (n) n--; - fs->flsem[i].ctr = n; + Files[i].ctr = n; + if (!n) Files[i].fs = 0; res = FR_OK; } else { res = FR_INT_ERR; @@ -397,6 +689,18 @@ FRESULT dec_lock ( /* Decrement file open counter */ return res; } + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < _FS_SHARE; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} #endif @@ -460,12 +764,14 @@ FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */ /* Update FSInfo sector if needed */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { fs->winsect = 0; + /* Create FSInfo structure */ mem_set(fs->win, 0, 512); ST_WORD(fs->win+BS_55AA, 0xAA55); ST_DWORD(fs->win+FSI_LeadSig, 0x41615252); ST_DWORD(fs->win+FSI_StrucSig, 0x61417272); ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust); ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust); + /* Write it into the FSInfo sector */ disk_write(fs->drv, fs->win, fs->fsi_sector, 1); fs->fsi_flag = 0; } @@ -482,6 +788,24 @@ FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */ /*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ + + +DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ + FATFS *fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; + if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; +} + + + + +/*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ @@ -495,7 +819,7 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status BYTE *p; - if (clst < 2 || clst >= fs->n_fatent) /* Check range */ + if (clst < 2 || clst >= fs->n_fatent) /* Chack range */ return 1; switch (fs->fs_type) { @@ -599,7 +923,9 @@ FRESULT remove_chain ( { FRESULT res; DWORD nxt; - +#if _USE_ERASE + DWORD scl = clst, ecl = clst, resion[2]; +#endif if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ res = FR_INT_ERR; @@ -617,6 +943,16 @@ FRESULT remove_chain ( fs->free_clust++; fs->fsi_flag = 1; } +#if _USE_ERASE + if (ecl + 1 == nxt) { /* Next cluster is contiguous */ + ecl = nxt; + } else { /* End of contiguous clusters */ + resion[0] = clust2sect(fs, scl); /* Start sector */ + resion[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, resion); /* Erase the block */ + scl = ecl = nxt; + } +#endif clst = nxt; /* Next cluster */ } } @@ -639,6 +975,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err ) { DWORD cs, ncl, scl; + FRESULT res; if (clst == 0) { /* Create a new chain */ @@ -666,41 +1003,51 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err if (ncl == scl) return 0; /* No free cluster */ } - if (put_fat(fs, ncl, 0x0FFFFFFF)) /* Mark the new cluster "last link" */ - return 0xFFFFFFFF; - if (clst != 0) { /* Link it to the previous one if needed */ - if (put_fat(fs, clst, ncl)) - return 0xFFFFFFFF; + res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ } - - fs->last_clust = ncl; /* Update FSINFO */ - if (fs->free_clust != 0xFFFFFFFF) { - fs->free_clust--; - fs->fsi_flag = 1; + if (res == FR_OK) { + fs->last_clust = ncl; /* Update FSINFO */ + if (fs->free_clust != 0xFFFFFFFF) { + fs->free_clust--; + fs->fsi_flag = 1; + } + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; } - return ncl; /* Return new cluster number */ + return ncl; /* Return new cluster number or error code */ } #endif /* !_FS_READONLY */ - /*-----------------------------------------------------------------------*/ -/* Get sector# from cluster# */ +/* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ - -DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ - FATFS *fs, /* File system object */ - DWORD clst /* Cluster# to be converted */ +#if _USE_FASTSEEK +static +DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File offset to be converted to cluster# */ ) { - clst -= 2; - if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */ - return clst * fs->csize + fs->database; -} + DWORD cl, ncl, *tbl; + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (!ncl) return 0; /* End of table? (error) */ + if (cl < ncl) break; /* In this fragment? */ + cl -= ncl; tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ +} +#endif /* _USE_FASTSEEK */ @@ -725,14 +1072,14 @@ FRESULT dir_sdi ( if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ clst = dj->fs->dirbase; - if (clst == 0) { /* Static table */ + if (clst == 0) { /* Static table (root-dir in FAT12/16) */ dj->clust = clst; if (idx >= dj->fs->n_rootdir) /* Index is out of range */ return FR_INT_ERR; - dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32); /* Sector# */ + dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */ } - else { /* Dynamic table */ - ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */ + else { /* Dynamic table (sub-dirs or root-dir in FAT32) */ + ic = SS(dj->fs) / SZ_DIR * dj->fs->csize; /* Entries per cluster */ while (idx >= ic) { /* Follow cluster chain */ clst = get_fat(dj->fs, clst); /* Get next cluster */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ @@ -741,10 +1088,10 @@ FRESULT dir_sdi ( idx -= ic; } dj->clust = clst; - dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32); /* Sector# */ + dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */ } - dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */ + dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */ return FR_OK; /* Seek succeeded */ } @@ -770,7 +1117,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT an if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ return FR_NO_FILE; - if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */ + if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */ dj->sect++; /* Next sector */ if (dj->clust == 0) { /* Static table */ @@ -778,7 +1125,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT an return FR_NO_FILE; } else { /* Dynamic table */ - if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ + if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ clst = get_fat(dj->fs, dj->clust); /* Get next cluster */ if (clst <= 1) return FR_INT_ERR; if (clst == 0xFFFFFFFF) return FR_DISK_ERR; @@ -811,7 +1158,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT an } dj->index = i; - dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32; + dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; return FR_OK; } @@ -833,11 +1180,11 @@ int cmp_lfn ( /* 1:Matched, 0:Not matched */ BYTE *dir /* Pointer to the directory entry containing a part of LFN */ ) { - int i, s; + UINT i, s; WCHAR wc, uc; - i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */ + i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13; /* Get offset in the LFN buffer */ s = 0; wc = 1; do { uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */ @@ -850,7 +1197,7 @@ int cmp_lfn ( /* 1:Matched, 0:Not matched */ } } while (++s < 13); /* Repeat until all chars in the entry are checked */ - if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */ + if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i]) /* Last segment matched but different length */ return 0; return 1; /* The part of LFN matched */ @@ -864,7 +1211,7 @@ int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ BYTE *dir /* Pointer to the directory entry */ ) { - int i, s; + UINT i, s; WCHAR wc, uc; @@ -881,7 +1228,7 @@ int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ } } while (++s < 13); /* Read all character in the entry */ - if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */ + if (dir[LDIR_Ord] & LLE) { /* Put terminator if it is the last LFN part */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } @@ -899,7 +1246,7 @@ void fit_lfn ( BYTE sum /* SFN sum */ ) { - int i, s; + UINT i, s; WCHAR wc; @@ -915,7 +1262,7 @@ void fit_lfn ( ST_WORD(dir+LfnOfs[s], wc); /* Put it */ if (!wc) wc = 0xFFFF; /* Padding chars following last char */ } while (++s < 13); - if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40; /* Bottom LFN part is the start of LFN sequence */ + if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE; /* Bottom LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ } @@ -936,7 +1283,7 @@ void gen_numname ( ) { BYTE ns[8], c; - int i, j; + UINT i, j; mem_cpy(dst, src, 11); @@ -945,7 +1292,7 @@ void gen_numname ( do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn); } - /* itoa */ + /* itoa (hexdecimal) */ i = 7; do { c = (seq % 16) + '0'; @@ -981,7 +1328,7 @@ BYTE sum_sfn ( ) { BYTE sum = 0; - int n = 11; + UINT n = 11; do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); return sum; @@ -1020,14 +1367,14 @@ FRESULT dir_find ( if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ #if _USE_LFN /* LFN configuration */ a = dir[DIR_Attr] & AM_MASK; - if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; } else { if (a == AM_LFN) { /* An LFN entry is found */ if (dj->lfn) { - if (c & 0x40) { /* Is it start of LFN sequence? */ + if (c & LLE) { /* Is it start of LFN sequence? */ sum = dir[LDIR_Chksum]; - c &= 0xBF; ord = c; /* LFN start order */ + c &= ~LLE; ord = c; /* LFN start order */ dj->lfn_idx = dj->index; } /* Check validity of the LFN entry and compare it with given name */ @@ -1076,13 +1423,13 @@ FRESULT dir_read ( if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ #if _USE_LFN /* LFN configuration */ a = dir[DIR_Attr] & AM_MASK; - if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + if (c == DDE || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; } else { if (a == AM_LFN) { /* An LFN entry is found */ - if (c & 0x40) { /* Is it start of LFN sequence? */ + if (c & LLE) { /* Is it start of LFN sequence? */ sum = dir[LDIR_Chksum]; - c &= 0xBF; ord = c; + c &= ~LLE; ord = c; dj->lfn_idx = dj->index; } /* Check LFN validity and capture it */ @@ -1094,7 +1441,7 @@ FRESULT dir_read ( } } #else /* Non LFN configuration */ - if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */ + if (c != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */ break; #endif res = dir_next(dj, 0); /* Next entry */ @@ -1129,7 +1476,8 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many fn = dj->fn; lfn = dj->lfn; mem_cpy(sn, fn, 12); - if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME; /* Cannot create dot entry */ + if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */ + return FR_INVALID_NAME; if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ fn[NS] = 0; dj->lfn = 0; /* Find only SFN */ @@ -1158,7 +1506,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many res = move_window(dj->fs, dj->sect); if (res != FR_OK) break; c = *dj->dir; /* Check the entry status */ - if (c == 0xE5 || c == 0) { /* Is it a blank entry? */ + if (c == DDE || c == 0) { /* Is it a blank entry? */ if (n == 0) is = dj->index; /* First index of the contiguous entry */ if (++n == ne) break; /* A contiguous entry that required count is found */ } else { @@ -1189,7 +1537,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many res = move_window(dj->fs, dj->sect); if (res != FR_OK) break; c = *dj->dir; - if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */ + if (c == DDE || c == 0) break; /* Is it a blank entry? */ res = dir_next(dj, 1); /* Next entry with table stretch */ } while (res == FR_OK); } @@ -1199,7 +1547,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many res = move_window(dj->fs, dj->sect); if (res == FR_OK) { dir = dj->dir; - mem_set(dir, 0, 32); /* Clean the entry */ + mem_set(dir, 0, SZ_DIR); /* Clean the entry */ mem_cpy(dir, dj->fn, 11); /* Put SFN */ #if _USE_LFN dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */ @@ -1234,7 +1582,7 @@ FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ do { res = move_window(dj->fs, dj->sect); if (res != FR_OK) break; - *dj->dir = 0xE5; /* Mark the entry "deleted" */ + *dj->dir = DDE; /* Mark the entry "deleted" */ dj->fs->wflag = 1; if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ res = dir_next(dj, 0); /* Next entry */ @@ -1247,7 +1595,7 @@ FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ if (res == FR_OK) { res = move_window(dj->fs, dj->sect); if (res == FR_OK) { - *dj->dir = 0xE5; /* Mark the entry "deleted" */ + *dj->dir = DDE; /* Mark the entry "deleted" */ dj->fs->wflag = 1; } } @@ -1277,13 +1625,13 @@ FRESULT create_name ( #if _USE_LFN /* LFN configuration */ BYTE b, cf; WCHAR w, *lfn; - int i, ni, si, di; + UINT i, ni, si, di; const TCHAR *p; /* Create LFN in Unicode */ - si = di = 0; - p = *path; + for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ lfn = dj->lfn; + si = di = 0; for (;;) { w = p[si++]; /* Get a character */ if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ @@ -1291,13 +1639,13 @@ FRESULT create_name ( return FR_INVALID_NAME; #if !_LFN_UNICODE w &= 0xFF; - if (IsDBCS1(w)) { /* If it is a DBC 1st byte */ - b = p[si++]; /* Get 2nd byte */ - if (!IsDBCS2(b)) /* Reject invalid code for DBC */ - return FR_INVALID_NAME; - w = (w << 8) + b; + if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(b)) + return FR_INVALID_NAME; /* Reject invalid sequence */ + w = (w << 8) + b; /* Create a DBC */ } - w = ff_convert(w, 1); /* Convert OEM to Unicode */ + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ if (!w) return FR_INVALID_NAME; /* Reject invalid code */ #endif if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */ @@ -1307,8 +1655,8 @@ FRESULT create_name ( *path = &p[si]; /* Return pointer to the next segment */ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ #if _FS_RPATH - if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ - (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { + if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */ + (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) { lfn[di] = 0; for (i = 0; i < 11; i++) dj->fn[i] = (i < di) ? '.' : ' '; @@ -1317,11 +1665,11 @@ FRESULT create_name ( } #endif while (di) { /* Strip trailing spaces and dots */ - w = lfn[di - 1]; + w = lfn[di-1]; if (w != ' ' && w != '.') break; di--; } - if (!di) return FR_INVALID_NAME; /* Reject null string */ + if (!di) return FR_INVALID_NAME; /* Reject nul string */ lfn[di] = 0; /* LFN is created */ @@ -1359,14 +1707,14 @@ FRESULT create_name ( cf |= NS_LFN; /* Force create LFN entry */ } - if (_DF1S && w >= 0x100) { /* Double byte char */ + if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */ if (i >= ni - 1) { cf |= NS_LOSS | NS_LFN; i = ni; continue; } dj->fn[i++] = (BYTE)(w >> 8); } else { /* Single byte char */ - if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */ - w = '_'; cf |= NS_LOSS | NS_LFN; /* Lossy conversion */ + if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */ + w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { if (IsUpper(w)) { /* ASCII large capital */ b |= 2; @@ -1380,7 +1728,7 @@ FRESULT create_name ( dj->fn[i++] = (BYTE)w; } - if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05; /* If the first char collides with deleted mark, replace it with 0x05 */ + if (dj->fn[0] == DDE) dj->fn[0] = NDDE; /* If the first char collides with deleted mark, replace it with 0x05 */ if (ni == 8) b <<= 2; if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ @@ -1397,14 +1745,14 @@ FRESULT create_name ( #else /* Non-LFN configuration */ BYTE b, c, d, *sfn; - int ni, si, i; + UINT ni, si, i; const char *p; /* Create file name in directory form */ + for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ sfn = dj->fn; mem_set(sfn, ' ', 11); si = i = b = 0; ni = 8; - p = *path; #if _FS_RPATH if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { @@ -1426,24 +1774,24 @@ FRESULT create_name ( i = 8; ni = 11; b <<= 2; continue; } - if (c >= 0x80) { /* Extended char */ + if (c >= 0x80) { /* Extended char? */ + b |= 3; /* Eliminate NT flag */ #ifdef _EXCVT - c = excvt[c - 0x80]; /* Convert extend char (SBCS) */ + c = excvt[c-0x80]; /* Upper conversion (SBCS) */ #else - b |= 3; /* Eliminate NT flag if extended char is exist */ #if !_DF1S /* ASCII only cfg */ return FR_INVALID_NAME; #endif #endif } - if (IsDBCS1(c)) { /* DBC 1st byte? */ + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ d = (BYTE)p[si++]; /* Get 2nd byte */ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ return FR_INVALID_NAME; sfn[i++] = c; sfn[i++] = d; } else { /* Single byte code */ - if (chk_chr("\"*+,:<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ return FR_INVALID_NAME; if (IsUpper(c)) { /* ASCII large capital? */ b |= 2; @@ -1458,8 +1806,8 @@ FRESULT create_name ( *path = &p[si]; /* Return pointer to the next segment */ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ - if (!i) return FR_INVALID_NAME; /* Reject null string */ - if (sfn[0] == 0xE5) sfn[0] = 0x05; /* When first char collides with 0xE5, replace it with 0x05 */ + if (!i) return FR_INVALID_NAME; /* Reject nul string */ + if (sfn[0] == DDE) sfn[0] = NDDE; /* When first char collides with DDE, replace it with 0x05 */ if (ni == 8) b <<= 2; if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ @@ -1484,7 +1832,7 @@ void get_fileinfo ( /* No return code */ FILINFO *fno /* Pointer to the file information to be filled */ ) { - int i; + UINT i; BYTE nt, *dir; TCHAR *p, c; @@ -1496,10 +1844,10 @@ void get_fileinfo ( /* No return code */ for (i = 0; i < 8; i++) { /* Copy name body */ c = dir[i]; if (c == ' ') break; - if (c == 0x05) c = (TCHAR)0xE5; + if (c == NDDE) c = (TCHAR)DDE; if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20; #if _LFN_UNICODE - if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i + 1])) + if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1])) c = (c << 8) | dir[++i]; c = ff_convert(c, 1); if (!c) c = '?'; @@ -1513,7 +1861,7 @@ void get_fileinfo ( /* No return code */ if (c == ' ') break; if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20; #if _LFN_UNICODE - if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i + 1])) + if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1])) c = (c << 8) | dir[++i]; c = ff_convert(c, 1); if (!c) c = '?'; @@ -1526,10 +1874,10 @@ void get_fileinfo ( /* No return code */ fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */ fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */ } - *p = 0; + *p = 0; /* Terminate SFN str by a \0 */ #if _USE_LFN - if (fno->lfname) { + if (fno->lfname && fno->lfsize) { TCHAR *tp = fno->lfname; WCHAR w, *lfn; @@ -1540,14 +1888,14 @@ void get_fileinfo ( /* No return code */ #if !_LFN_UNICODE w = ff_convert(w, 0); /* Unicode -> OEM conversion */ if (!w) { i = 0; break; } /* Could not convert, no LFN */ - if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC */ + if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ tp[i++] = (TCHAR)(w >> 8); #endif - if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overrun, no LFN */ + if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */ tp[i++] = (TCHAR)w; } } - tp[i] = 0; /* Terminator */ + tp[i] = 0; /* Terminate the LFN str by a \0 */ } #endif } @@ -1582,7 +1930,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ dj->sclust = 0; /* Start from the root dir */ #endif - if ((UINT)*path < ' ') { /* Null path means the start directory itself */ + if ((UINT)*path < ' ') { /* Nul path means the start directory itself */ res = dir_sdi(dj, 0); dj->dir = 0; @@ -1593,7 +1941,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ res = dir_find(dj); /* Find it */ ns = *(dj->fn+NS); if (res != FR_OK) { /* Failed to find the object */ - if (res != FR_NO_FILE) break; /* Abort if any hard error occurred */ + if (res != FR_NO_FILE) break; /* Abort if any hard error occured */ /* Object not found */ if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */ dj->sclust = 0; dj->dir = 0; /* It is the root dir */ @@ -1609,7 +1957,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */ res = FR_NO_PATH; break; } - dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); + dj->sclust = LD_CLUST(dir); } } @@ -1646,7 +1994,7 @@ BYTE check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk e /*-----------------------------------------------------------------------*/ -/* Make sure that the file system is valid */ +/* Check if the file system object is valid or not */ /*-----------------------------------------------------------------------*/ static @@ -1665,56 +2013,57 @@ FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ FATFS *fs; /* Get logical drive number from the path name */ - vol = p[0] - '0'; /* Is there a drive number? */ - if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */ - p += 2; *path = p; /* Return pointer to the path name */ - } else { /* No drive number is given */ + vol = p[0] - '0'; /* Is there a drive number? */ + if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */ + p += 2; *path = p; /* Return pointer to the path name */ + } else { /* No drive number is given */ #if _FS_RPATH - vol = Drive; /* Use current drive */ + vol = CurrVol; /* Use current drive */ #else - vol = 0; /* Use drive 0 */ + vol = 0; /* Use drive 0 */ #endif } /* Check if the logical drive is valid or not */ - if (vol >= _DRIVES) /* Is the drive number valid? */ + if (vol >= _VOLUMES) /* Is the drive number valid? */ return FR_INVALID_DRIVE; - *rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */ - if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ + *rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */ + if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ - ENTER_FF(fs); /* Lock file system */ + ENTER_FF(fs); /* Lock file system */ - if (fs->fs_type) { /* If the logical drive has been mounted */ + if (fs->fs_type) { /* If the logical drive has been mounted */ stat = disk_status(fs->drv); - if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */ + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */ #if !_FS_READONLY if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ return FR_WRITE_PROTECTED; #endif - return FR_OK; /* The file system object is valid */ + return FR_OK; /* The file system object is valid */ } } - /* The logical drive must be mounted. Following code attempts to mount the volume (initialize the file system object) */ + /* The logical drive must be mounted. */ + /* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */ fs->fs_type = 0; /* Clear the file system object */ fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */ - if (stat & STA_NOINIT) /* Check if the drive is ready */ - return FR_NOT_READY; -#if _MAX_SS != 512 /* Get disk sector size if needed */ - if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS) - return FR_NO_FILESYSTEM; + if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no media or hard error */ +#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK) + return FR_DISK_ERR; #endif #if !_FS_READONLY if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; #endif - /* Search FAT partition on the drive (Supports only generic partitions, FDISK and SFD) */ + /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */ fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */ if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */ /* Check the partition listed in top of the partition table */ - tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */ + tbl = &fs->win[MBR_Table + LD2PT(vol) * SZ_PTE];/* Partition table */ if (tbl[4]) { /* Is the partition existing? */ bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */ fmt = check_fs(fs, bsect); /* Check the partition */ @@ -1737,10 +2086,10 @@ FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ fasize *= b; /* Number of sectors for FAT area */ fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ - if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be 1,2,4...128) */ + if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */ - if (fs->n_rootdir % (SS(fs) / 32)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */ + if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */ tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */ if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32); @@ -1749,7 +2098,7 @@ FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */ /* Determine the FAT sub type */ - sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / 32); /* RSV+FAT+DIR */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ @@ -1771,7 +2120,7 @@ FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } - if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (FAT size must not be less than FAT sectors */ + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than required) */ return FR_NO_FILESYSTEM; #if !_FS_READONLY @@ -1800,8 +2149,7 @@ FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ fs->cdir = 0; /* Current directory (root dir) */ #endif #if _FS_SHARE /* Clear file lock semaphores */ - for (vol = 0; vol < _FS_SHARE; vol++) - fs->flsem[vol].ctr = 0; + clear_lock(fs); #endif return FR_OK; @@ -1854,11 +2202,14 @@ FRESULT f_mount ( FATFS *rfs; - if (vol >= _DRIVES) /* Check if the drive number is valid */ + if (vol >= _VOLUMES) /* Check if the drive number is valid */ return FR_INVALID_DRIVE; rfs = FatFs[vol]; /* Get current fs object */ if (rfs) { +#if _FS_SHARE + clear_lock(rfs); +#endif #if _FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR; #endif @@ -1922,32 +2273,31 @@ FRESULT f_open ( if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { DWORD dw, cl; - if (res != FR_OK) { /* No file, create new */ - if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ #if _FS_SHARE res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif - mode |= FA_CREATE_ALWAYS; - dir = dj.dir; /* New entry */ + mode |= FA_CREATE_ALWAYS; /* File is created */ + dir = dj.dir; /* New entry */ } - else { /* Any object is already existing */ - if (mode & FA_CREATE_NEW) { /* Cannot create new */ - res = FR_EXIST; + else { /* Any object is already existing */ + if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; } else { - if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) /* Cannot overwrite it (R/O or DIR) */ - res = FR_DENIED; + if (mode & FA_CREATE_NEW) /* Cannot create as new file */ + res = FR_EXIST; } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ - dw = get_fattime(); /* Created time */ + dw = get_fattime(); /* Created time */ ST_DWORD(dir+DIR_CrtTime, dw); dir[DIR_Attr] = 0; /* Reset attribute */ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */ - cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); /* Get start cluster */ - ST_WORD(dir+DIR_FstClusHI, 0); /* cluster = 0 */ - ST_WORD(dir+DIR_FstClusLO, 0); + cl = LD_CLUST(dir); /* Get start cluster */ + ST_CLUST(dir, 0); /* cluster = 0 */ dj.fs->wflag = 1; if (cl) { /* Remove the cluster chain if exist */ dw = dj.fs->winsect; @@ -1970,8 +2320,8 @@ FRESULT f_open ( } } if (res == FR_OK) { - if (mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) - mode |= FA__WRITTEN; /* Set file changed flag */ + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ + mode |= FA__WRITTEN; fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; #if _FS_SHARE @@ -1994,13 +2344,12 @@ FRESULT f_open ( if (res == FR_OK) { fp->flag = mode; /* File access mode */ - fp->org_clust = /* File start cluster */ - ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); + fp->sclust = LD_CLUST(dir); /* File start cluster */ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ fp->fptr = 0; /* File pointer */ fp->dsect = 0; #if _USE_FASTSEEK - fp->cltbl = 0; /* No cluster link map table */ + fp->cltbl = 0; /* Normal seek mode */ #endif fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */ } @@ -2030,36 +2379,44 @@ FRESULT f_read ( *br = 0; /* Initialize byte counter */ - res = validate(fp->fs, fp->id); /* Check validity of the object */ + res = validate(fp->fs, fp->id); /* Check validity */ if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->flag & FA__ERROR) /* Check abort flag */ + if (fp->flag & FA__ERROR) /* Aborted file? */ LEAVE_FF(fp->fs, FR_INT_ERR); - if (!(fp->flag & FA_READ)) /* Check access mode */ + if (!(fp->flag & FA_READ)) /* Check access mode */ LEAVE_FF(fp->fs, FR_DENIED); remain = fp->fsize - fp->fptr; - if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ - for ( ; btr; /* Repeat until all data transferred */ + for ( ; btr; /* Repeat until all data read */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ - clst = (fp->fptr == 0) ? /* On the top of the file? */ - fp->org_clust : get_fat(fp->fs, fp->curr_clust); - if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ + } + if (clst < 2) ABORT(fp->fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->curr_clust = clst; /* Update current cluster */ + fp->clust = clst; /* Update current cluster */ } - sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */ + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ if (!sect) ABORT(fp->fs, FR_INT_ERR); sect += csect; - cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Read maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ cc = fp->fs->csize - csect; if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK) ABORT(fp->fs, FR_DISK_ERR); -#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if _FS_TINY if (fp->fs->wflag && fp->fs->winsect - sect < cc) mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); @@ -2068,19 +2425,19 @@ FRESULT f_read ( mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); #endif #endif - rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ continue; } #if !_FS_TINY + if (fp->dsect != sect) { /* Load data sector if not in cache */ #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write sector I/O buffer if needed */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } #endif - if (fp->dsect != sect) { /* Fill sector buffer with file data */ - if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) + if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ ABORT(fp->fs, FR_DISK_ERR); } #endif @@ -2089,7 +2446,7 @@ FRESULT f_read ( rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ if (rcnt > btr) rcnt = btr; #if _FS_TINY - if (move_window(fp->fs, fp->dsect)) /* Move sector window */ + if (move_window(fp->fs, fp->dsect)) /* Move sector window */ ABORT(fp->fs, FR_DISK_ERR); mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ #else @@ -2124,71 +2481,76 @@ FRESULT f_write ( *bw = 0; /* Initialize byte counter */ - res = validate(fp->fs, fp->id); /* Check validity of the object */ + res = validate(fp->fs, fp->id); /* Check validity */ if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->flag & FA__ERROR) /* Check abort flag */ + if (fp->flag & FA__ERROR) /* Aborted file? */ LEAVE_FF(fp->fs, FR_INT_ERR); - if (!(fp->flag & FA_WRITE)) /* Check access mode */ + if (!(fp->flag & FA_WRITE)) /* Check access mode */ LEAVE_FF(fp->fs, FR_DENIED); - if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */ + if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0; /* File size cannot reach 4GB */ - for ( ; btw; /* Repeat until all data transferred */ + for ( ; btw; /* Repeat until all data written */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ - if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->org_clust; /* Follow from the origin */ - if (clst == 0) /* When there is no cluster chain, */ - fp->org_clust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ - } else { /* Middle or end of the file */ - clst = create_chain(fp->fs, fp->curr_clust); /* Follow or stretch cluster chain */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + if (clst == 0) /* When no cluster is allocated, */ + fp->sclust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ } - if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ if (clst == 1) ABORT(fp->fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->curr_clust = clst; /* Update current cluster */ + fp->clust = clst; /* Update current cluster */ } #if _FS_TINY - if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write back data buffer prior to following direct transfer */ + if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write-back sector cache */ ABORT(fp->fs, FR_DISK_ERR); #else - if (fp->flag & FA__DIRTY) { /* Write back data buffer prior to following direct transfer */ + if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) ABORT(fp->fs, FR_DISK_ERR); fp->flag &= ~FA__DIRTY; } #endif - sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */ + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ if (!sect) ABORT(fp->fs, FR_INT_ERR); sect += csect; - cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Write maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ cc = fp->fs->csize - csect; if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK) ABORT(fp->fs, FR_DISK_ERR); #if _FS_TINY - if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */ + if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); fp->fs->wflag = 0; } #else - if (fp->dsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */ + if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); fp->flag &= ~FA__DIRTY; } #endif - wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ continue; } #if _FS_TINY - if (fp->fptr >= fp->fsize) { /* Avoid silly buffer filling at growing edge */ + if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR); fp->fs->winsect = sect; } #else - if (fp->dsect != sect) { /* Fill sector buffer with file data */ + if (fp->dsect != sect) { /* Fill sector cache with file data */ if (fp->fptr < fp->fsize && disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fp->fs, FR_DISK_ERR); @@ -2196,10 +2558,10 @@ FRESULT f_write ( #endif fp->dsect = sect; } - wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */ + wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ if (wcnt > btw) wcnt = btw; #if _FS_TINY - if (move_window(fp->fs, fp->dsect)) /* Move sector window */ + if (move_window(fp->fs, fp->dsect)) /* Move sector window */ ABORT(fp->fs, FR_DISK_ERR); mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ fp->fs->wflag = 1; @@ -2210,7 +2572,7 @@ FRESULT f_write ( } if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ - fp->flag |= FA__WRITTEN; /* Set file changed flag */ + fp->flag |= FA__WRITTEN; /* Set file change flag */ LEAVE_FF(fp->fs, FR_OK); } @@ -2247,8 +2609,7 @@ FRESULT f_sync ( dir = fp->dir_ptr; dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */ - ST_WORD(dir+DIR_FstClusLO, fp->org_clust); /* Update start cluster */ - ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16); + ST_CLUST(dir, fp->sclust); /* Update start cluster */ tim = get_fattime(); /* Update updated time */ ST_DWORD(dir+DIR_WrtTime, tim); fp->flag &= ~FA__WRITTEN; @@ -2289,11 +2650,11 @@ FRESULT f_close ( #if _FS_REENTRANT res = validate(fp->fs, fp->id); if (res == FR_OK) { - res = dec_lock(fp->fs, fp->lockid); + res = dec_lock(fp->lockid); unlock_fs(fp->fs, FR_OK); } #else - res = dec_lock(fp->fs, fp->lockid); + res = dec_lock(fp->lockid); #endif } #endif @@ -2306,32 +2667,30 @@ FRESULT f_close ( /*-----------------------------------------------------------------------*/ -/* Change Current Drive/Directory */ +/* Current Drive/Directory Handlings */ /*-----------------------------------------------------------------------*/ -#if _FS_RPATH +#if _FS_RPATH >= 1 FRESULT f_chdrive ( BYTE drv /* Drive number */ ) { - if (drv >= _DRIVES) return FR_INVALID_DRIVE; + if (drv >= _VOLUMES) return FR_INVALID_DRIVE; - Drive = drv; + CurrVol = drv; return FR_OK; } - FRESULT f_chdir ( const TCHAR *path /* Pointer to the directory path */ ) { FRESULT res; DIR dj; - BYTE *dir; DEF_NAMEBUF; @@ -2341,12 +2700,11 @@ FRESULT f_chdir ( res = follow_path(&dj, path); /* Follow the path */ FREE_BUF(); if (res == FR_OK) { /* Follow completed */ - dir = dj.dir; /* Pointer to the entry */ - if (!dir) { + if (!dj.dir) { dj.fs->cdir = dj.sclust; /* Start directory itself */ } else { - if (dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ - dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); + if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ + dj.fs->cdir = LD_CLUST(dj.dir); else res = FR_NO_PATH; /* Reached but a file */ } @@ -2357,7 +2715,78 @@ FRESULT f_chdir ( LEAVE_FF(dj.fs, res); } -#endif + +#if _FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR *path, /* Pointer to the directory path */ + UINT sz_path /* Size of path */ +) +{ + FRESULT res; + DIR dj; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEF_NAMEBUF; + + + *path = 0; + res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */ + if (res == FR_OK) { + INIT_BUF(dj); + i = sz_path; /* Bottom of buffer (dir stack base) */ + dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */ + while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */ + res = dir_sdi(&dj, 1); /* Get parent dir */ + if (res != FR_OK) break; + res = dir_read(&dj); + if (res != FR_OK) break; + dj.sclust = LD_CLUST(dj.dir); /* Goto parent dir */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child dir */ + res = dir_read(&dj); + if (res != FR_OK) break; + if (ccl == LD_CLUST(dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; +#if _USE_LFN + fno.lfname = path; + fno.lfsize = i; +#endif + get_fileinfo(&dj, &fno); /* Get the dir name and push it to the buffer */ + tp = fno.fname; + if (_USE_LFN && *path) tp = path; + for (n = 0; tp[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) path[--i] = tp[--n]; + path[--i] = '/'; + } + tp = path; + if (res == FR_OK) { + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; + if (i == sz_path) { /* Root-dir */ + *tp++ = '/'; + } else { /* Sub-dir */ + do /* Add stacked path str */ + *tp++ = path[i++]; + while (i < sz_path); + } + } + *tp = 0; + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} +#endif /* _FS_RPATH >= 2 */ +#endif /* _FS_RPATH >= 1 */ @@ -2381,58 +2810,52 @@ FRESULT f_lseek ( #if _USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ - DWORD cl, pcl, ncl, tcl, dsc, tlen, *tbl = fp->cltbl; - BYTE csc; + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; - tlen = *tbl++; - if (ofs == CREATE_LINKMAP) { /* Create link map table */ - cl = fp->org_clust; + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; ulen = 2; /* Given table size and required table size */ + cl = fp->sclust; /* Top of the chain */ if (cl) { do { - if (tlen < 4) { /* Not enough table items */ - res = FR_NOT_ENOUGH_CORE; break; - } - tcl = cl; ncl = 0; - do { /* Get a fragment and store the top and length */ + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { pcl = cl; ncl++; cl = get_fat(fp->fs, cl); if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); } while (cl == pcl + 1); - *tbl++ = ncl; *tbl++ = tcl; - tlen -= 2; - } while (cl < fp->fs->n_fatent); + if (ulen <= tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; *tbl++ = tcl; + } + } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ } - *tbl = 0; /* Terminate table */ + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) + *tbl = 0; /* Terminate table */ + else + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ } else { /* Fast seek */ if (ofs > fp->fsize) /* Clip offset at the file size */ ofs = fp->fsize; fp->fptr = ofs; /* Set file pointer */ if (ofs) { - dsc = (ofs - 1) / SS(fp->fs); - cl = dsc / fp->fs->csize; - for (;;) { - ncl = *tbl++; - if (!ncl) ABORT(fp->fs, FR_INT_ERR); - if (cl < ncl) break; - cl -= ncl; tbl++; - } - fp->curr_clust = cl + *tbl; - csc = (BYTE)(dsc & (fp->fs->csize - 1)); - dsc = clust2sect(fp->fs, fp->curr_clust); + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clust2sect(fp->fs, fp->clust); if (!dsc) ABORT(fp->fs, FR_INT_ERR); - dsc += csc; - if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { + dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); + if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */ + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) ABORT(fp->fs, FR_DISK_ERR); fp->flag &= ~FA__DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) + if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ ABORT(fp->fs, FR_DISK_ERR); #endif fp->dsect = dsc; @@ -2460,18 +2883,18 @@ FRESULT f_lseek ( (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; - clst = fp->curr_clust; + clst = fp->clust; } else { /* When seek to back cluster, */ - clst = fp->org_clust; /* start from the first cluster */ + clst = fp->sclust; /* start from the first cluster */ #if !_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(fp->fs, 0); if (clst == 1) ABORT(fp->fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->org_clust = clst; + fp->sclust = clst; } #endif - fp->curr_clust = clst; + fp->clust = clst; } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ @@ -2486,7 +2909,7 @@ FRESULT f_lseek ( clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); - fp->curr_clust = clst; + fp->clust = clst; fp->fptr += bcs; ofs -= bcs; } @@ -2498,22 +2921,22 @@ FRESULT f_lseek ( } } } - if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { + if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */ + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) ABORT(fp->fs, FR_DISK_ERR); fp->flag &= ~FA__DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) + if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ ABORT(fp->fs, FR_DISK_ERR); #endif fp->dsect = nsect; } #if !_FS_READONLY - if (fp->fptr > fp->fsize) { /* Set changed flag if the file size is extended */ + if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ fp->fsize = fp->fptr; fp->flag |= FA__WRITTEN; } @@ -2527,7 +2950,7 @@ FRESULT f_lseek ( #if _FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ -/* Create a Directory Object */ +/* Create a Directroy Object */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( @@ -2536,7 +2959,6 @@ FRESULT f_opendir ( ) { FRESULT res; - BYTE *dir; DEF_NAMEBUF; @@ -2546,10 +2968,9 @@ FRESULT f_opendir ( res = follow_path(dj, path); /* Follow the path to the directory */ FREE_BUF(); if (res == FR_OK) { /* Follow completed */ - dir = dj->dir; - if (dir) { /* It is not the current dir */ - if (dir[DIR_Attr] & AM_DIR) { /* The object is a directory */ - dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); + if (dj->dir) { /* It is not the root dir */ + if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */ + dj->sclust = LD_CLUST(dj->dir); } else { /* The object is not a directory */ res = FR_NO_PATH; } @@ -2569,7 +2990,7 @@ FRESULT f_opendir ( /*-----------------------------------------------------------------------*/ -/* Read Directory Entry in Sequence */ +/* Read Directory Entry in Sequense */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( @@ -2584,11 +3005,11 @@ FRESULT f_readdir ( res = validate(dj->fs, dj->id); /* Check validity of the object */ if (res == FR_OK) { if (!fno) { - res = dir_sdi(dj, 0); + res = dir_sdi(dj, 0); /* Rewind the directory object */ } else { INIT_BUF(*dj); - res = dir_read(dj); - if (res == FR_NO_FILE) { + res = dir_read(dj); /* Read an directory item */ + if (res == FR_NO_FILE) { /* Reached end of dir */ dj->sect = 0; res = FR_OK; } @@ -2734,15 +3155,15 @@ FRESULT f_truncate ( fp->fsize = fp->fptr; /* Set file size to current R/W point */ fp->flag |= FA__WRITTEN; if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ - res = remove_chain(fp->fs, fp->org_clust); - fp->org_clust = 0; + res = remove_chain(fp->fs, fp->sclust); + fp->sclust = 0; } else { /* When truncate a part of the file, remove remaining clusters */ - ncl = get_fat(fp->fs, fp->curr_clust); + ncl = get_fat(fp->fs, fp->clust); res = FR_OK; if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; if (ncl == 1) res = FR_INT_ERR; if (res == FR_OK && ncl < fp->fs->n_fatent) { - res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF); + res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); if (res == FR_OK) res = remove_chain(fp->fs, ncl); } } @@ -2788,7 +3209,7 @@ FRESULT f_unlink ( if (dir[DIR_Attr] & AM_RDO) res = FR_DENIED; /* Cannot remove R/O object */ } - dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); + dclst = LD_CLUST(dir); if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */ if (dclst < 2) { res = FR_INT_ERR; @@ -2862,14 +3283,12 @@ FRESULT f_mkdir ( dir[DIR_Name] = '.'; dir[DIR_Attr] = AM_DIR; ST_DWORD(dir+DIR_WrtTime, tim); - ST_WORD(dir+DIR_FstClusLO, dcl); - ST_WORD(dir+DIR_FstClusHI, dcl >> 16); - mem_cpy(dir+32, dir, 32); /* Create ".." entry */ + ST_CLUST(dir, dcl); + mem_cpy(dir+SZ_DIR, dir, SZ_DIR); /* Create ".." entry */ dir[33] = '.'; pcl = dj.sclust; if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) pcl = 0; - ST_WORD(dir+32+DIR_FstClusLO, pcl); - ST_WORD(dir+32+DIR_FstClusHI, pcl >> 16); + ST_CLUST(dir+SZ_DIR, pcl); for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ dj.fs->winsect = dsc++; dj.fs->wflag = 1; @@ -2878,15 +3297,14 @@ FRESULT f_mkdir ( mem_set(dir, 0, SS(dj.fs)); } } - if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directory */ + if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ if (res != FR_OK) { - remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ + remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ } else { dir = dj.dir; - dir[DIR_Attr] = AM_DIR; /* Attribute */ - ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */ - ST_WORD(dir+DIR_FstClusLO, dcl); /* Table start cluster */ - ST_WORD(dir+DIR_FstClusHI, dcl >> 16); + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */ + ST_CLUST(dir, dcl); /* Table start cluster */ dj.fs->wflag = 1; res = sync(dj.fs); } @@ -2943,7 +3361,7 @@ FRESULT f_chmod ( /*-----------------------------------------------------------------------*/ -/* Change Time-stamp */ +/* Change Timestamp */ /*-----------------------------------------------------------------------*/ FRESULT f_utime ( @@ -3016,8 +3434,8 @@ FRESULT f_rename ( mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */ mem_cpy(&djn, &djo, sizeof(DIR)); /* Check new object */ res = follow_path(&djn, path_new); - if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ - if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */ + if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ + if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */ /* Start critical section that any interruption or error can cause cross-link */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { @@ -3026,16 +3444,15 @@ FRESULT f_rename ( dir[DIR_Attr] = buf[0] | AM_ARC; djo.fs->wflag = 1; if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */ - dw = clust2sect(djn.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO)); + dw = clust2sect(djn.fs, LD_CLUST(dir)); if (!dw) { res = FR_INT_ERR; } else { res = move_window(djn.fs, dw); - dir = djn.fs->win+32; /* .. entry */ + dir = djn.fs->win+SZ_DIR; /* .. entry */ if (res == FR_OK && dir[1] == '.') { dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust; - ST_WORD(dir+DIR_FstClusLO, dw); - ST_WORD(dir+DIR_FstClusHI, dw >> 16); + ST_CLUST(dir, dw); djn.fs->wflag = 1; } } @@ -3098,13 +3515,13 @@ FRESULT f_forward ( if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ if (!csect) { /* On the cluster boundary? */ clst = (fp->fptr == 0) ? /* On the top of the file? */ - fp->org_clust : get_fat(fp->fs, fp->curr_clust); + fp->sclust : get_fat(fp->fs, fp->clust); if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->curr_clust = clst; /* Update current cluster */ + fp->clust = clst; /* Update current cluster */ } } - sect = clust2sect(fp->fs, fp->curr_clust); /* Get current data sector */ + sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ if (!sect) ABORT(fp->fs, FR_INT_ERR); sect += csect; if (move_window(fp->fs, sect)) /* Move sector window */ @@ -3126,8 +3543,8 @@ FRESULT f_forward ( /*-----------------------------------------------------------------------*/ /* Create File System on the Drive */ /*-----------------------------------------------------------------------*/ -#define N_ROOTDIR 512 /* Multiple of 32 */ -#define N_FATS 1 /* 1 or 2 */ +#define N_ROOTDIR 512 /* Number of root dir entries for FAT12/16 */ +#define N_FATS 1 /* Number of FAT copies (1 or 2) */ FRESULT f_mkfs ( @@ -3139,16 +3556,16 @@ FRESULT f_mkfs ( static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; BYTE fmt, md, *tbl; - DWORD n_clst, vs, n; - UINT as, i; - DWORD b_vol, b_fat, b_dir, b_data; /* Area offset (LBA) */ - DWORD n_vol, n_rsv, n_fat, n_dir; /* Area size */ + DWORD n_clst, vs, n, wsect; + UINT i; + DWORD b_vol, b_fat, b_dir, b_data; /* Offset (LBA) */ + DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ FATFS *fs; DSTATUS stat; /* Check mounted drive and clear work area */ - if (drv >= _DRIVES) return FR_INVALID_DRIVE; + if (drv >= _VOLUMES) return FR_INVALID_DRIVE; fs = FatFs[drv]; if (!fs) return FR_NOT_ENABLED; fs->fs_type = 0; @@ -3159,25 +3576,24 @@ FRESULT f_mkfs ( if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; #if _MAX_SS != 512 /* Get disk sector size */ - if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS) + if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; #endif if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) return FR_DISK_ERR; - b_vol = (sfd == 1) ? 0 : 63; /* Volume start sector */ + b_vol = (sfd) ? 0 : 63; /* Volume start sector */ n_vol -= b_vol; - if (au & (au - 1)) au = 0; /* Check validity of the allocation unit size */ - if (!au) { /* AU auto selection */ + if (au & (au - 1)) au = 0; /* Check validity of the AU size */ + if (!au) { /* AU auto selection */ vs = n_vol / (2000 / (SS(fs) / 512)); for (i = 0; vs < vst[i]; i++) ; au = cst[i]; } - if (_MAX_SS != 512 && au < SS(fs)) au = SS(fs); au /= SS(fs); /* Number of sectors per cluster */ if (au == 0) au = 1; if (au > 128) au = 128; - /* Pre-compute number of clusters and FAT sub-type */ + /* Pre-compute number of clusters and FAT syb-type */ n_clst = n_vol / au; fmt = FS_FAT12; if (n_clst >= MIN_FAT16) fmt = FS_FAT16; @@ -3192,7 +3608,7 @@ FRESULT f_mkfs ( n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; n_fat = (n_fat + SS(fs) - 1) / SS(fs); n_rsv = 1; - n_dir = N_ROOTDIR * 32UL / SS(fs); + n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs); } b_fat = b_vol + n_rsv; /* FAT area start sector */ b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ @@ -3200,134 +3616,142 @@ FRESULT f_mkfs ( if (n_vol < b_data + au) return FR_MKFS_ABORTED; /* Too small volume */ /* Align data start sector to erase block boundary (for flash memory media) */ - if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_DISK_ERR; - if (!n || n > 32768) return FR_MKFS_ABORTED; - n = (b_data + n - 1) & ~(n - 1); /* Next nearest boundary from current data start */ + if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; + n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ n = (n - b_data) / N_FATS; - if (fmt == FS_FAT32) { /* FAT32: Move FAT start */ + if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ n_rsv += n; b_fat += n; } else { /* FAT12/16: Expand FAT size */ n_fat += n; } - /* b_dir and b_data are no longer used below */ - /* Determine number of cluster and final check of validity of the FAT sub-type */ + /* Determine number of clusters and final check of validity of the FAT sub-type */ n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) return FR_MKFS_ABORTED; /* Create partition table if required */ - if (sfd == 1) { + if (sfd) { /* No patition table (SFD) */ md = 0xF0; - } else { + } else { /* With patition table (FDISK) */ DWORD n_disk = b_vol + n_vol; mem_set(fs->win, 0, SS(fs)); tbl = fs->win+MBR_Table; - ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */ + ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */ if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */ n_disk = n_disk / 63 / 255; tbl[7] = (BYTE)n_disk; tbl[6] = (BYTE)((n_disk >> 2) | 63); } else { - ST_WORD(&tbl[6], 0xFFFF); + ST_WORD(&tbl[6], 0xFFFF); /* CHS saturated */ } tbl[5] = 254; - if (fmt != FS_FAT32) /* System ID */ + if (fmt != FS_FAT32) /* System ID */ tbl[4] = (n_vol < 0x10000) ? 0x04 : 0x06; else tbl[4] = 0x0c; - ST_DWORD(tbl+8, 63); /* Partition start in LBA */ - ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */ - ST_WORD(tbl+64, 0xAA55); /* Signature */ - if (disk_write(drv, fs->win, 0, 1) != RES_OK) + ST_DWORD(tbl+8, 63); /* Partition start in LBA */ + ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */ + ST_WORD(fs->win+BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(drv, fs->win, 0, 1) != RES_OK) /* Put the MBR into first physical sector */ return FR_DISK_ERR; md = 0xF8; } - /* Create VBR */ - tbl = fs->win; /* Clear buffer */ + /* Create volume boot record */ + tbl = fs->win; /* Clear sector */ mem_set(tbl, 0, SS(fs)); - ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */ - as = SS(fs); /* Sector size */ - ST_WORD(tbl+BPB_BytsPerSec, as); - tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ - ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ - tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ - as = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */ - ST_WORD(tbl+BPB_RootEntCnt, as); - if (n_vol < 0x10000) { /* Number of total sectors */ + mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ + i = SS(fs); /* Sector size */ + ST_WORD(tbl+BPB_BytsPerSec, i); + tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ + ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ + tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ + i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */ + ST_WORD(tbl+BPB_RootEntCnt, i); + if (n_vol < 0x10000) { /* Number of total sectors */ ST_WORD(tbl+BPB_TotSec16, n_vol); } else { ST_DWORD(tbl+BPB_TotSec32, n_vol); } - tbl[BPB_Media] = md; /* Media descriptor */ - ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */ - ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */ - ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */ - n = get_fattime(); /* Use current time as VSN */ + tbl[BPB_Media] = md; /* Media descriptor */ + ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */ + ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */ + ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */ + n = get_fattime(); /* Use current time as VSN */ if (fmt == FS_FAT32) { - ST_DWORD(tbl+BS_VolID32, n); /* VSN */ - ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */ - ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */ - ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */ - ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */ - tbl[BS_DrvNum32] = 0x80; /* Drive number */ - tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(tbl+BS_VolLab32, "NO NAME FAT32 ", 19); /* Volume label, FAT signature */ + ST_DWORD(tbl+BS_VolID32, n); /* VSN */ + ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */ + ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */ + ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */ + ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */ + tbl[BS_DrvNum32] = 0x80; /* Drive number */ + tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { - ST_DWORD(tbl+BS_VolID, n); /* VSN */ - ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */ - tbl[BS_DrvNum] = 0x80; /* Drive number */ - tbl[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(tbl+BS_VolLab, "NO NAME FAT ", 19); /* Volume label, FAT signature */ - } - ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ - if (disk_write(drv, tbl, b_vol, 1) != RES_OK) /* Original (VBR) */ + ST_DWORD(tbl+BS_VolID, n); /* VSN */ + ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */ + tbl[BS_DrvNum] = 0x80; /* Drive number */ + tbl[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ + if (disk_write(drv, tbl, b_vol, 1) != RES_OK) /* Write VBR */ return FR_DISK_ERR; - if (fmt == FS_FAT32) /* Backup (VBR+6) */ + if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */ disk_write(drv, tbl, b_vol + 6, 1); /* Initialize FAT area */ - for (i = 0; i < N_FATS; i++) { + wsect = b_fat; + for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ n = md; /* Media descriptor byte */ if (fmt != FS_FAT32) { n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */ } else { - n |= 0x0FFFFF00; + n |= 0xFFFFFF00; ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */ - ST_DWORD(tbl+4, 0x0FFFFFFF); + ST_DWORD(tbl+4, 0xFFFFFFFF); ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */ } - if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) + if (disk_write(drv, tbl, wsect++, 1) != RES_OK) return FR_DISK_ERR; - mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ - for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector write */ - if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) + mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ + for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ + if (disk_write(drv, tbl, wsect++, 1) != RES_OK) return FR_DISK_ERR; } } /* Initialize root directory */ - n = (fmt == FS_FAT32) ? as : n_dir; - while (n--) { - if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) + i = (fmt == FS_FAT32) ? au : n_dir; + do { + if (disk_write(drv, tbl, wsect++, 1) != RES_OK) return FR_DISK_ERR; + } while (--i); + +#if _USE_ERASE /* Erase data area if needed */ + { + DWORD eb[2]; + + eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; + disk_ioctl(drv, CTRL_ERASE_SECTOR, eb); } +#endif - /* Create FSInfo record if needed */ + /* Create FSInfo if needed */ if (fmt == FS_FAT32) { - ST_WORD(tbl+BS_55AA, 0xAA55); ST_DWORD(tbl+FSI_LeadSig, 0x41615252); ST_DWORD(tbl+FSI_StrucSig, 0x61417272); - ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); - ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF); - disk_write(drv, tbl, b_vol + 1, 1); /* Original (VBR+1) */ - disk_write(drv, tbl, b_vol + 7, 1); /* Backup (VBR+7) */ + ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + ST_DWORD(tbl+FSI_Nxt_Free, 2); /* Last allocated cluster# */ + ST_WORD(tbl+BS_55AA, 0xAA55); + disk_write(drv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */ + disk_write(drv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */ } return (disk_ioctl(drv, CTRL_SYNC, (void*)0) == RES_OK) ? FR_OK : FR_DISK_ERR; @@ -3361,18 +3785,18 @@ TCHAR* f_gets ( #if _LFN_UNICODE /* Read a character in UTF-8 encoding */ if (c >= 0x80) { if (c < 0xC0) continue; /* Skip stray trailer */ - if (c < 0xE0) { /* Two-byte sequence */ + if (c < 0xE0) { /* Two-byte sequense */ f_read(fil, s, 1, &rc); if (rc != 1) break; c = ((c & 0x1F) << 6) | (s[0] & 0x3F); if (c < 0x80) c = '?'; } else { - if (c < 0xF0) { /* Three-byte sequence */ + if (c < 0xF0) { /* Three-byte sequense */ f_read(fil, s, 2, &rc); if (rc != 2) break; c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F); if (c < 0x800) c = '?'; - } else { /* Reject four-byte sequence */ + } else { /* Reject four-byte sequense */ c = '?'; } } @@ -3467,9 +3891,9 @@ int f_printf ( { va_list arp; BYTE f, r; - UINT i, w; - ULONG val; - TCHAR c, d, s[16]; + UINT i, j, w; + ULONG v; + TCHAR c, d, s[16], *p; int res, cc; @@ -3487,20 +3911,31 @@ int f_printf ( c = *str++; if (c == '0') { /* Flag: '0' padding */ f = 1; c = *str++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; c = *str++; + } } while (IsDigit(c)) { /* Precision */ w = w * 10 + c - '0'; c = *str++; } if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ - f |= 2; c = *str++; + f |= 4; c = *str++; } if (!c) break; d = c; if (IsLower(d)) d -= 0x20; switch (d) { /* Type is... */ case 'S' : /* String */ - cc = f_puts(va_arg(arp, TCHAR*), fil); continue; + p = va_arg(arp, TCHAR*); + for (j = 0; p[j]; j++) ; + res = 0; + while (!(f & 2) && j++ < w) res += (cc = f_putc(' ', fil)); + res += (cc = f_puts(p, fil)); + while (j++ < w) res += (cc = f_putc(' ', fil)); + if (cc != EOF) cc = res; + continue; case 'C' : /* Character */ cc = f_putc((TCHAR)va_arg(arp, int), fil); continue; case 'B' : /* Binary */ @@ -3510,39 +3945,31 @@ int f_printf ( case 'D' : /* Signed decimal */ case 'U' : /* Unsigned decimal */ r = 10; break; - case 'X' : /* Hexadecimal */ + case 'X' : /* Hexdecimal */ r = 16; break; - default: /* Unknown */ + default: /* Unknown type (passthrough) */ cc = f_putc(c, fil); continue; } - /* Get an argument */ - val = (f & 2) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int)); - if (d == 'D' && (val & 0x80000000)) { - val = 0 - val; - f |= 4; + /* Get an argument and put it in numeral */ + v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int)); + if (d == 'D' && (v & 0x80000000)) { + v = 0 - v; + f |= 8; } - /* Put it in numeral string */ i = 0; do { - d = (TCHAR)(val % r); val /= r; - if (d > 9) { - d += 7; - if (c == 'x') d += 0x20; - } + d = (TCHAR)(v % r); v /= r; + if (d > 9) d += (c == 'x') ? 0x27 : 0x07; s[i++] = d + '0'; - } while (val && i < sizeof(s) / sizeof(s[0])); - if (f & 4) s[i++] = '-'; - cc = 0; - while (i < w-- && cc != EOF) { - cc = f_putc((TCHAR)((f & 1) ? '0' : ' '), fil); - res++; - } - do { - cc = f_putc(s[--i], fil); - res++; - } while (i && cc != EOF); - if (cc != EOF) cc = 0; + } while (v && i < sizeof(s) / sizeof(s[0])); + if (f & 8) s[i++] = '-'; + j = i; d = (f & 1) ? '0' : ' '; + res = 0; + while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil)); + do res += (cc = f_putc(s[--i], fil)); while(i); + while (j++ < w) res += (cc = f_putc(' ', fil)); + if (cc != EOF) cc = res; } va_end(arp); @@ -3551,4 +3978,3 @@ int f_printf ( #endif /* !_FS_READONLY */ #endif /* _USE_STRFUNC */ - |