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