fatfs v0.13c October 14, 2018:

- Supported stdint.h for C99 and later. (integer.h was included in ff.h)
- Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
- Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
- Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
This commit is contained in:
savelij13 2025-09-11 10:35:10 +03:00
parent 7b4dceffab
commit 7cb0c2d1e6
29 changed files with 369 additions and 263 deletions

View File

@ -32,22 +32,28 @@
<h3>How to Port</h3>
<h4>Basic Considerations</h4>
<p>The FatFs module is assuming following conditions on portability.</p>
<p>The FatFs module assumes following conditions on portability.</p>
<ul>
<li>ANSI C<br>
The FatFs module is a middleware written in ANSI C (C89). There is no platform dependence, so long as the compiler is in compliance with ANSI C.</li>
The FatFs module is a middleware written in ANSI C (C89). There is no platform dependence, so long as the compiler is in compliance with C89 or later. Only exFAT feature requires C99.</li>
<li>Size of integer types<br>
The FatFs module assumes that size of <tt>char</tt>/<tt>short</tt>/<tt>long</tt> are 8/16/32 bit and <tt>int</tt> is 16 or 32 bit. These correspondence are defined in <tt>integer.h</tt>. This will not be a problem on most compilers. When a conflict with existing definitions is occured, you must resolve it with care.</li>
<ul>
<li>When the C standard is in C89, size of <tt>char</tt>/<tt>short</tt>/<tt>long</tt> must be 8/16/32-bit respectively.</li>
<li>When it is in C99 or later, <tt>stdint.h</tt> is used to obtain the correct sizes.</li>
<li>Size of <tt>char</tt> must be 8-bit.</li>
<li>Size of <tt>int</tt>, as well as integer promotion, must be 16-bit or 32-bit.</li>
</ul>
Integer types used in FatFs are defined in <tt>fftypes.h</tt>. This will not be a problem on most platform. When a conflict with existing definitions occured, you must resolve it with care.</li>
</ul>
<h4>System Organizations</h4>
<p>The dependency diagram shown below is a typical but not specific configuration of the embedded system with FatFs module.</p>
<p>The dependency diagram shown below is a typical, but not specific, configuration of the embedded system with FatFs module.</p>
<p><img src="../res/modules.png" width="580" height="280" alt="dependency diagram"></p>
<p>(a) If a working disk module with FatFs disk interface is provided, nothing else will be needed. (b) To attach existing disk drivers with different interface, glue functions are needed to translate the interfaces between FatFs and the drivers.</p>
<p>(a) If a working disk module for FatFs is provided, nothing else will be needed. (b) To attach existing disk drivers with different interface, some glue functions are needed to translate the interfaces between FatFs and the driver.</p>
<p><img src="../res/funcs.png" width="750" height="420" alt="functional diagram"></p>
<h4>Required Functions</h4>
<p>You need to provide only low level disk I/O functions required by FatFs module and nothing else. If a working disk module for the target system is already provided, you need to write only glue functions to attach it to the FatFs module. If not, you need to port another disk I/O module or write it from scratch. Most of defined functions are not that always required. For example, any write function is not required at read-only configuration. Following table shows which function is required depends on the configuration options.</p>
<p>You need to provide only low level disk I/O functions required by FatFs module and nothing else. If a working disk I/O module for the target system is already provided, you need to write only glue functions to attach it to the FatFs module. If not, you need to port another disk I/O module or write it from scratch. Most of defined functions are not that always required. For instance, any write function is not required at read-only configuration. Following table shows which function is required depends on the configuration options.</p>
<table class="lst2">
<tr><th>Function</th><th>Required when</th><th>Note</th></tr>
<tr><td>disk_status<br>disk_initialize<br>disk_read</td><td>Always</td><td rowspan="5">Disk I/O functions.<br>Samples available in ffsample.zip.<br>There are many implementations on the web.</td></tr>
@ -55,10 +61,11 @@ The FatFs module assumes that size of <tt>char</tt>/<tt>short</tt>/<tt>long</tt>
<tr><td>disk_ioctl (GET_SECTOR_COUNT)<br>disk_ioctl (GET_BLOCK_SIZE)</td><td>FF_USE_MKFS == 1</td></tr>
<tr><td>disk_ioctl (GET_SECTOR_SIZE)</td><td>FF_MAX_SS != FF_MIN_SS</td></tr>
<tr><td>disk_ioctl (CTRL_TRIM)</td><td>FF_USE_TRIM == 1</td></tr>
<tr><td>ff_uni2oem<br>ff_oem2uni<br>ff_wtoupper</td><td>FF_USE_LFN != 0</td><td>Unicode support functions.<br>Just add ffunicode.c to the project.</td></tr>
<tr><td>ff_cre_syncobj<br>ff_del_syncobj<br>ff_req_grant<br>ff_rel_grant</td><td>FF_FS_REENTRANT == 1</td><td rowspan="2">O/S dependent functions.<br>Samples available in ffsystem.c.</td></tr>
<tr><td>ff_uni2oem<br>ff_oem2uni<br>ff_wtoupper</td><td>FF_USE_LFN != 0</td><td>Unicode support functions.<br>Add optional module ffunicode.c to the project.</td></tr>
<tr><td>ff_cre_syncobj<br>ff_del_syncobj<br>ff_req_grant<br>ff_rel_grant</td><td>FF_FS_REENTRANT == 1</td><td rowspan="2">O/S dependent functions.<br>Sample code is available in ffsystem.c.</td></tr>
<tr><td>ff_mem_alloc<br>ff_mem_free</td><td>FF_USE_LFN == 3</td></tr>
</table>
<p>FatFs cares about neither what kind of storage device is used nor how it is implemented. Only a requirement is that it is a block device read/written in fixed-size blocks that accessible via the disk I/O functions defined above.</p>
</div>
<div class="para doc" id="limits">
@ -89,13 +96,13 @@ The FatFs module assumes that size of <tt>char</tt>/<tt>short</tt>/<tt>long</tt>
<tr class="ral"><td class="cal">Work area<br><small>(FF_FS_TINY == 0)</small></td><td>V*564<br>+ F*552</td><td>V*564<br>+ F*552</td><td>V*564<br>+ F*552</td><td>V*560<br>+ F*546</td><td>V*560<br>+ F*546</td><td>V*560<br>+ F*546</td><td>V*560<br>+ F*546</td><td>V*564<br>+ F*552</td><td>V*564<br>+ F*552</td><td>V*564<br>+ F*552</td><td>V*564<br>+ F*552</td></tr>
<tr class="ral"><td class="cal">Work area<br><small>(FF_FS_TINY == 1)</small></td><td>V*564<br>+ F*40</td><td>V*564<br>+ F*40</td><td>V*564<br>+ F*40</td><td>V*560<br>+ F*34</td><td>V*560<br>+ F*34</td><td>V*560<br>+ F*34</td><td>V*560<br>+ F*34</td><td>V*564<br>+ F*40</td><td>V*564<br>+ F*40</td><td>V*564<br>+ F*40</td><td>V*564<br>+ F*40</td></tr>
</table>
<p>These are the memory usage on some target systems with following condition. The memory sizes are in unit of byte, <em>V</em> denotes number of mounted volumes and <em>F</em> denotes number of open files. All samples here are optimezed in code size.</p>
<p>These are the memory usage of FatFs module without lower layer on some target systems in following condition. <em>V</em> denotes number of mounted volumes and <em>F</em> denotes number of open files. Every samples here are optimezed in code size.</p>
<pre>
FatFs R0.13a options:
FF_FS_READONLY 0 (Read/Write) or 1 (Read only)
FF_FS_MINIMIZE 0 (Full, with all basic functions) or 3 (Min, with fully minimized)
FF_FS_TINY 0 (Default) or 1 (Tiny file object)
And other options are left unchanged from original setting.
And any other options are left unchanged from original setting.
</pre>
</div>
@ -146,8 +153,8 @@ And other options are left unchanged from original setting.
<h3>Long File Name</h3>
<p>FatFs module supports long file name (LFN). The two different file names, short file name (SFN) and LFN, of a file is transparent on the API except for <tt>f_readdir</tt> function. The support for LFN is disabled by default. To enable the LFN, set <tt><a href="config.html#use_lfn">FF_USE_LFN</a></tt> to 1, 2 or 3, and add <tt>ffunicode.c</tt> to the project. The LFN requiers a certain working buffer in addition. The buffer size can be configured by <tt><a href="config.html#max_lfn">FF_MAX_LFN</a></tt> according to the available memory. The length of an LFN will be up to 255 characters, so that the <tt>FF_MAX_LFN</tt> should be set to 255 for all file names. If the size of working buffer is insufficient for the input file name, the file function fails with <tt>FR_INVALID_NAME</tt>. When use any re-entry to the API with LFN is enabled, <tt>FF_USE_LFN</tt> must be set to 2 or 3. In this case, the file function allocates the working buffer on the stack or heap. The working buffer occupies <tt>(FF_MAX_LFN + 1) * 2</tt> bytes and additional <tt>(FF_MAX_LFN + 44) / 15 * 32</tt> bytes when exFAT is enabled.</p>
<table class="lst2 rset">
<caption>With LFN at CM3+gcc</caption>
<tr><th><tt>FF_CODE_PAGE</tt></th><th>Increment</th></tr>
<caption>With LFN at CM3 + gcc</caption>
<tr><th><tt>FF_CODE_PAGE</tt></th><th>Code size</th></tr>
<tr><td>437-869 (SBCS)</td><td>+3.3k</td></tr>
<tr><td>932 (Japanese)</td><td>+62k</td></tr>
<tr><td>936 (Simplified Chinese)</td><td>+177k</td></tr>
@ -155,22 +162,22 @@ And other options are left unchanged from original setting.
<tr><td>950 (Traditional Chinese)</td><td>+111k</td></tr>
<tr><td>0 (All code pages)</td><td>+486k</td></tr>
</table>
<p>When the LFN is enabled, the module size will be increased depends on the configured code page. Right table shows increment of code size by LFN function at different code pages. Especially, in the CJK region, tens of thousands of characters are being used. Unfortunately, it requires a huge OEM-Unicode bidirectional conversion table and the module size will be drastically increased as shown in the table. As the result, the FatFs with LFN enebled with those code pages will not able to be ported on the most 8-bit MCU systems.</p>
<p>If you can discard ANSI/OEM code API and backward compatibility with non-ASCII SFN, you will able to configure FatFs for Unicode API with any SBCS.</p>
<p>There ware some restrictions on using LFN for open source project because the support for LFN on the FAT volume was a patent of Microsoft Corporation. The related patents have expired and using the LFN function have got free for any projects.</p>
<p>When the LFN is enabled, the module size will be increased depends on the configured code page. Right table shows increment of code size by LFN function at different code pages. Especially, in the CJK region, tens of thousands of characters are being used. Unfortunately, it requires a huge OEM-Unicode bidirectional conversion table and the module size will be drastically increased as shown in the table.</p>
<p>As the result, the FatFs with LFN enebled with DBCS code pages will not able to be ported on the most 8-bit MCU systems. If the target system is in legacy-free, in only Unicode and any ANSI/OEM code is not used at all, the code page setting gets meaningless. You will able to reduce the code size by configureing FatFs for Unicode with any SBCS code page.</p>
<p>There ware some restrictions on using LFN for open source project because the support for LFN on the FAT volume was a patent of Microsoft Corporation. The related patents have expired and using the LFN function has got free for any projects.</p>
</div>
<div class="para doc" id="unicode">
<h3>Unicode API</h3>
<p>By default, FatFs uses ANSI/OEM code set on the API even at LFN configuration. FatFs can also switch the character encoding on the API to Unicode by configuration option <tt><a href="config.html#lfn_unicode">FF_LFN_UNICODE</a></tt>. This means that FatFs supports the full featured LFN specification. The data type <tt>TCHAR</tt> specifies path name strings on the API is an alias of either <tt>char</tt>(ANSI/OEM or UTF-8), <tt>WCHAR</tt>(UTF-16) or <tt>DWORD</tt>(UTF-32) depends on that option. For more information, refer to the description in the <a href="filename.html#uni">file name</a>.</p>
<p>Note that code page setting, <tt><a href="config.html#code_page">FF_CODE_PAGE</a></tt>, has actually no meaning for the path names at the Unicode API. However it still affects code conversion of string I/O functions at <tt><a href="config.html#strf_encode">FF_STRF_ENCODE</a> != 0</tt> and backward compatibility with legacy systems, so that code page needs to be configured properly when it is considered a problem.</p>
<p>By default, FatFs uses ANSI/OEM code set on the API even at LFN configuration. FatFs can also switch the character encoding on the API to Unicode by configuration option <tt><a href="config.html#lfn_unicode">FF_LFN_UNICODE</a></tt>. This means that FatFs is compliant with the full featured LFN specification. The data type <tt>TCHAR</tt> specifies path name strings on the API is an alias of either <tt>char</tt>(ANSI/OEM or UTF-8), <tt>WCHAR</tt>(UTF-16) or <tt>DWORD</tt>(UTF-32) depends on that option. For more information, refer to the description in the <a href="filename.html#uni">file name</a>.</p>
<p>Note that setting of code page, <tt><a href="config.html#code_page">FF_CODE_PAGE</a></tt>, has actually no meaning when FatFs is configured for the Unicode API. It should be set 437 anyway. However it still affects code conversion of string I/O functions at <tt><a href="config.html#strf_encode">FF_STRF_ENCODE</a> == 0</tt> and backward compatibility with legacy systems, so that code page may need to be configured properly if it is considered a problem.</p>
</div>
<div class="para doc" id="exfat">
<h3>exFAT Filesystem</h3>
<p>The exFAT (Microsoft's Extended File Allocation Table) filesystem is a succession of the FAT/FAT32 filesystem which has been widely used in embedded systems, consumer devices and portable storage media. It is adopted by SDA (SD Association) as a recommended filesystem for high capacity SD cards larger than 32 GB and they are being shipped with this format, so that the exFAT became one of the standard filesystems for removable media as well as FAT. The exFAT filesystem allows the file size beyond the 4 GB limit what FAT filesystem allows upto and some filesystem overhead, especially cluster allocation delay, are reduced as well. This feature improves the write throughput to the file.</p>
<p>Note that the exFAT is a patent of Microsoft Corporation. The exFAT function of FatFs is an implementation based on <cite>US. Pat. App. Pub. No. 2009/0164440 A1</cite>. FatFs module can switch the support for exFAT on/off by configuration option, <tt><a href="config.html#fs_exfat">FF_FS_EXFAT</a></tt>. When enable the exFAT on the commercial products, a license by Microsoft will be needed depends on the final destination of the products.</p>
<p><em>Remark: Enabling exFAT discards ANSI C (C89) compatibility because of need for 64-bit integer type.</em></p>
<p>The exFAT (Microsoft's Extended File Allocation Table) filesystem is a succession of the FAT/FAT32 filesystem which has been widely used in embedded systems, consumer devices and portable storage media. It is adopted by SDA (SD Association) as the regular filesystem for SDXC card, 64 GB and larger, and they are being shipped with this format. Therefore the exFAT is one of the standard filesystems for removable media as well as FAT. The exFAT filesystem allows the file size beyond the 4 GB limit what FAT filesystem allows upto and some filesystem overhead, especially cluster allocation delay, are reduced as well. These features allow to record the large media file without dividing into some files and improve the write throughput to the file.</p>
<p>Note that the exFAT is a patent of Microsoft Corporation. The support for exFAT of FatFs is an implementation based on <cite>US. Pat. App. Pub. No. 2009/0164440 A1</cite>. FatFs module can switch the exFAT on or off by configuration option, <tt><a href="config.html#fs_exfat">FF_FS_EXFAT</a></tt>. When enable the exFAT on the commercial products, a license by Microsoft will be needed depends on the final destination of the products.</p>
<p><em>Remark: Enabling exFAT discards C89 compatibility because of need for 64-bit integer type.</em></p>
</div>
<div class="para doc" id="reentrant">
@ -245,11 +252,12 @@ Figure 5. Minimized critical section<br>
<h3>Extended Use of FatFs API</h3>
<p>These are examples of extended use of FatFs APIs. New item will be added whenever a useful code is found.</p>
<ol>
<li><a href="http://elm-chan.org/fsw/ff/res/app1.c">Open or create a file for append</a> (for only R0.12 and earlier)</li>
<li><a href="http://elm-chan.org/fsw/ff/res/app2.c">Empty a directory</a></li>
<li><a href="http://elm-chan.org/fsw/ff/res/app3.c">Allocate contiguous area to the file</a> (for only R0.11a and earlier)</li>
<li><a href="http://elm-chan.org/fsw/ff/res/app1.c">Open or create a file for append</a> (for R0.12 and earlier)</li>
<li><a href="http://elm-chan.org/fsw/ff/res/app2.c">Delete a non-empty sub-directory</a> (for R0.12 and later)</li>
<li><a href="http://elm-chan.org/fsw/ff/res/app3.c">Allocate contiguous area to the file</a> (for R0.11a and earlier)</li>
<li><a href="http://elm-chan.org/fsw/ff/res/app4.c">Compatibility checker for low level disk I/O module</a></li>
<li><a href="http://elm-chan.org/fsw/ff/res/mkfatimg.zip">FAT volume image creator</a></li>
<li><a href="http://elm-chan.org/fsw/ff/res/app5.c">Test if the file is contiguous or not</a></li>
</ol>
</div>

View File

@ -116,10 +116,10 @@
<h3>Namespace and Locale Configurations</h3>
<h4 id="code_page">FF_CODE_PAGE</h4>
<p>This option specifies the OEM code page to be used on the target system. Incorrect setting of the code page can cause a file open failure. If any non-ASCII character is not used at all, there is no difference between any code page settings.</p>
<p>This option specifies the OEM code page to be used on the target system. Incorrect setting of the code page can cause a file open failure. If any non-ASCII character is not used for the path name, there is no difference between any code page settings. Set it 437 anyway.</p>
<table class="lst1">
<tr><th>Value</th><th>Code page</th></tr>
<tr><td>0</td><td>Include all code pages below and set by <tt>f_setcp()</tt></td></tr>
<tr><td>0</td><td>Includes all code pages below and set by <tt>f_setcp()</tt></td></tr>
<tr><td>437</td><td>U.S.</td></tr>
<tr><td>720</td><td>Arabic</td></tr>
<tr><td>737</td><td>Greek</td></tr>
@ -157,7 +157,7 @@
<p>LFN function requiers certain internal working buffer for the file name. This option defines size of the buffer and the value can be in range of 12 to 255 in UTF-16 encoding unit of the LFN. The buffer occupies <tt>(FF_MAX_LFN + 1) * 2</tt> bytes and additional <tt>(FF_MAX_LFN + 44) / 15 * 32</tt> bytes when exFAT is enabled. It is recommended to be set 255 to fully support the LFN specification. This option has no effect when LFN is not enabled.</p>
<h4 id="lfn_unicode">FF_LFN_UNICODE</h4>
<p>This option switches character encoding for the file name on the API. When Unicode is selected, <tt>FF_CODE_PAGE</tt> has actually no meaning except for compatibility with legacy systems. FatFs supports the code point upto U+10FFFF.</p>
<p>This option switches character encoding for the file name on the API. When Unicode is selected, <tt>FF_CODE_PAGE</tt> has actually no meaning except for compatibility with legacy systems, such as MS-DOS and any system without support for LFN. FatFs supports the code point upto U+10FFFF.</p>
<table class="lst2">
<tr><th>Value</th><th>Character Encoding</th><th><tt>TCHAR</tt></th></tr>
<tr><td>0</td><td>ANSI/OEM in current CP</td><td>char</td></tr>
@ -168,7 +168,7 @@
<p>This option also affects behavior of string I/O functions (see <tt>FF_STRF_ENCODE</tt>). When LFN is not enabled, this option has no effect and FatFs works at ANSI/OEM code on the API. For more information, read <a href="filename.html#uni">here</a>.</p>
<h4 id="lfn_buf">FF_LFN_BUF, FF_SFN_BUF</h4>
<p>This set of options defines size of file name members, <tt>fname[]</tt> and <tt>altname[]</tt>, in the <tt><a href="sfileinfo.html">FILINFO</a></tt> structure which is used to read out the directory items. These values should be suffcient for the file names to read. How long is the read file name length maximum depends on the character encoding on the API as follows:</p>
<p>This set of options defines size of file name members, <tt>fname[]</tt> and <tt>altname[]</tt>, in the <tt><a href="sfileinfo.html">FILINFO</a></tt> structure which is used to read out the directory items. These values should be suffcient for the file names to read. The maximum possible length of read file name depends on the character encoding on the API as follows:</p>
<table class="lst2">
<tr><th>Encoding</th><th>LFN length</th><th>SFN length</th></tr>
<tr><td>ANSI/OEM at SBCS</td><td>255 items</td><td>12 items</td></tr>
@ -179,7 +179,7 @@
<p>If the size of name member is insufficient for the LFN, the item is treated as without LFN. When LFN is not enabled, these options have no effect.</p>
<h4 id="strf_encode">FF_STRF_ENCODE</h4>
<p>When character encoding on the API is Unicode (<tt>FF_LFN_UNICODE &gt;= 1</tt>), string I/O functions, <tt>f_gets</tt>, <tt>f_putc</tt>, <tt>f_puts</tt> and <tt>f_printf</tt>, convert the character encodins in it. This option defines the assumption of character encoding <em>on the file</em> to be read/written via those functions. When LFN is not enabled or <tt>FF_LFN_UNICODE == 0</tt>, the string functions work without any encoding conversion and this option has no effect.</p>
<p>When character encoding on the API is Unicode (<tt>FF_LFN_UNICODE &gt;= 1</tt>), string I/O functions, <tt>f_gets</tt>, <tt>f_putc</tt>, <tt>f_puts</tt> and <tt>f_printf</tt>, convert the character encoding in it. This option defines the assumption of character encoding <em>on the file</em> to be read/written via those functions. When LFN is not enabled or <tt>FF_LFN_UNICODE == 0</tt>, the string functions work without any encoding conversion and this option has no effect.</p>
<table class="lst2">
<tr><th>Value</th><th>Character encoding on the file</th></tr>
<tr><td>0</td><td>ANSI/OEM in current code page</td></tr>
@ -216,7 +216,7 @@
</table>
<h4 id="volume_strs">FF_VOLUME_STRS</h4>
<p>This option defines the volume ID strings for each logical drives. Number of items must not be less than <tt>FF_VOLUMES</tt>. Valid characters for the volume ID string are A-Z, a-z and 0-9, however, they are compared in case-insensitive. If <tt>FF_STR_VOLUME_ID == 0</tt>, this option has no effect. If <tt>FF_STR_VOLUME_ID &gt;= 1</tt> and this option is not defined, a user defined volume string table needs to be defined as shown below.</p>
<p>This option defines the volume ID strings for each logical drives. Number of items must not be less than <tt>FF_VOLUMES</tt>. Valid characters for the volume ID string are A-Z, a-z and 0-9, however, they are compared in case-insensitive. If <tt>FF_STR_VOLUME_ID == 0</tt>, this option has no effect. If <tt>FF_STR_VOLUME_ID &gt;= 1</tt> and this option is not defined, a user defined volume string table needs to be defined as shown below. The table should not be modified on the fly.</p>
<pre>
<span class="c">/* User defined volume ID strings for 0: 1: 2: 3: ... */</span>
const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sdc","usb"};
@ -268,7 +268,7 @@ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sdc","usb"};
</table>
<h4 id="fs_reentrant">FF_FS_REENTRANT</h4>
<p>Disable (0) or Enable (1). This option switches the re-entrancy (thread safe) of the FatFs module itself. Note that file/directory access to the different volume is always re-entrant and it can work simultaneously regardless of this option but volume control functions. <tt>f_mount</tt>, <tt>f_mkfs</tt> and <tt>f_fdisk</tt>, are always not re-entrant. Only file/directory access to the same volume, in other words, exclusive use of each filesystem object, is under control of this function. To enable this feature, also user provided synchronization handlers, <tt>ff_req_grant</tt>, <tt>ff_rel_grant</tt>, <tt>ff_del_syncobj</tt> and <tt>ff_cre_syncobj</tt>, need to be added to the project. Sample code is available in <tt>ffsystem.c</tt>.</p>
<p>Disable (0) or Enable (1). This option switches the re-entrancy (thread safe) of the FatFs module itself. Note that file/directory access to the different volume is always re-entrant and it can work simultaneously regardless of this option, however, volume management functions, <tt>f_mount</tt>, <tt>f_mkfs</tt> and <tt>f_fdisk</tt>, are always not re-entrant. Only file/directory access to the same volume, in other words, exclusive use of each filesystem object, is under control of this function. To enable this feature, also user provided synchronization handlers, <tt>ff_req_grant</tt>, <tt>ff_rel_grant</tt>, <tt>ff_del_syncobj</tt> and <tt>ff_cre_syncobj</tt>, need to be added to the project. Sample code is available in <tt>ffsystem.c</tt>.</p>
<h4 id="fs_timeout">FF_FS_TIMEOUT</h4>
<p>Number of time ticks to abort the file function with <tt>FR_TIMEOUT</tt> when wait time is too long. This option has no effect when <tt>FF_FS_REENTRANT == 0</tt>.</p>

View File

@ -61,7 +61,7 @@ DRESULT disk_read (
<ul>
<li>Convert word transfer to byte transfer in this function if needed. - Recommended.</li>
<li>On the <tt>f_read()</tt> calls, avoid long read request that includes a whole of sector. - Any direct transfer never occures.</li>
<li>On the <tt>f_read(fp, dat, btw, bw)</tt> calls, make sure that <tt>(((UINT)dat &amp; 3) == (f_tell(fp) &amp; 3))</tt> is true. - Word alignment of <tt class="arg">buff</tt> is guaranteed no matter dat is not word aligned.</li>
<li>On the <tt>f_read(fp, dat, btw, bw)</tt> calls, make sure that <tt>(((UINT)dat &amp; 3) == (f_tell(fp) &amp; 3))</tt> is true. - Word alignment of <tt class="arg">buff</tt> is guaranteed.</li>
</ul>
<p>Generally, a multiple sector read request must not be split into single sector transactions to the storage device, or read throughput gets worse.</p>
</div>

View File

@ -61,7 +61,7 @@ FRESULT f_expand (
</ul>
<p>When <tt class="arg">opt</tt> is 0, the function finds a contiguous data area and set it as suggested point for next allocation instead of allocating it to the file. The next cluster allocation is started at top of the contiguous area found by this function. Thus the write file is guaranteed be contiguous and no allocation delay until the size reaches that size at least unless any other changes to the volume is performed.</p>
<p>The contiguous file would have an advantage at time-critical read/write operations. It eliminates some overheads in the filesystem and the storage media caused by random access due to fragmented file data. Especially FAT access for the contiguous file on the exFAT volume is completely eliminated and storage media will be accessed sequentially.</p>
<p>Also the contiguous file can be easily accessed directly via low-level disk functions. But this is not recommended in consideration for future compatibility.</p>
<p>Also the contiguous file can be easily accessed directly via low-level disk functions. But this is not recommended in consideration for future compatibility. Use <a href="../res/app5.c">this function</a> to examine if the file is contiguous or not.</p>
</div>
<div class="para comp">

View File

@ -35,21 +35,21 @@
<tr><td>dir1/..</td><td>Invalid name</td><td>The current directory</td></tr>
<tr><td>/..</td><td>Invalid name</td><td>The root directory (sticks the top level)</td></tr>
</table>
<p>Also the drive prefix can be in pre-defined arbitrary string. When the option <tt><a href="config.html#str_volume_id">FF_STR_VOLUME_ID</a> == 1</tt>, also arbitrary string volume ID can be used as drive prefix. e.g. <tt>"flash:file1.txt"</tt>, <tt>"ram:temp.dat"</tt> or <tt>"usb:"</tt>. When <tt>FF_STR_VOLUME_ID == 2</tt>, Unix style drive prefix can be used. e.g. <tt>"/flash/file1.txt"</tt>, <tt>"/ram/temp.dat"</tt> or <tt>"/usb"</tt>. However, it cannot traverse the drives such as <tt>"/flash/../ram/temp.dat"</tt>. The Unix style drive prefix may lead a confusion in identification between volume ID and file name. For instance, which does <tt>"/flash"</tt> mean, a file <tt>"flash"</tt> on the root directory without drive prefix or a drive prefix of <tt>"flash"</tt>? If the string following a heading slash matches with any volume ID, it is treated as a drive prefix and skipped over.</p>
<p>Also the drive prefix can be in pre-defined arbitrary string. When the option <tt><a href="config.html#str_volume_id">FF_STR_VOLUME_ID</a> == 1</tt>, also arbitrary string volume ID can be used as drive prefix. e.g. <tt>"flash:file1.txt"</tt>, <tt>"ram:temp.dat"</tt> or <tt>"sd:"</tt>. When <tt>FF_STR_VOLUME_ID == 2</tt>, Unix style drive prefix can be used. e.g. <tt>"/flash/file1.txt"</tt>, <tt>"/ram/temp.dat"</tt> or <tt>"/usb"</tt>. However, it cannot traverse the drives such as <tt>"/flash/../ram/temp.dat"</tt>. The Unix style drive prefix may lead a confusion in identification between volume ID and file name. For instance, which does <tt>"/flash"</tt> mean, a file <tt>"flash"</tt> on the root directory without drive prefix or a drive prefix of <tt>"flash"</tt>? If the string following a heading slash matches with any volume ID, it is treated as a drive prefix.</p>
<p><em>Remark: In this revision, double dot name <tt>".."</tt> cannot follow the parent directory on the exFAT volume. It will work as <tt>"."</tt> and stay there.</em></p>
</div>
<div class="para doc" id="case">
<h3>Legal Characters and Case Sensitivity</h3>
<p>On the FAT filesystem, legal characters for object name (file/directory name) are, <tt>0-9 A-Z ! # $ % &amp; ' ( ) - @ ^ _ ` { } ~</tt> and extended characters (<tt>\x80</tt>-<tt>\xFF</tt>). Under LFN supported system, also <tt>+ , ; = [ ]</tt> and white space are legal for the object name and the white spaces and dots can be placed anywhere in the path name except for end of the object name.</p>
<p>On the FAT filesystem, legal characters for object name (file/directory name) are, <tt>0-9 A-Z ! # $ % &amp; ' ( ) - @ ^ _ ` { } ~</tt> and any extended character. The valid character codes of extended characters are depends on the configured code page. Under LFN supported system, also <tt>+ , ; = [ ]</tt> and white space are legal for the object name and the white spaces and dots can be placed anywhere in the path name except for end of the name.</p>
<p>FAT filesystem is case-insensitive to the object names on the volume. Object name on the FAT volume is compared in case-insensitive. For instance, these three names, <tt>file.txt</tt>, <tt>File.Txt</tt> and <tt>FILE.TXT</tt>, are identical. This is applied to extended charactres as well. When an object is created on the FAT volume, up converted name is recorded to the SFN entry, and the raw name is recorded to the LFN entry when LFN function is enabled.</p>
<p>As for the MS-DOS and PC DOS for CJK, it was case-sensitive to the DBCS extended characters. To follow this specification, FatFs works with case-sensitive to the extended characters at only non-LFN with DBCS configuration (DOS/DBCS specs). But at LFN configuration, FatFs works with case-insensitive to the extended character (WindowsNT specs). This can cause a problem on compatibility with Windows system when an object with extended characters is created on the volume at non-LFN and DBCS configuration; therfore the object names with DBCS extended characters should not be used on the FAT volume shared by those systems.</p>
<p>As for the MS-DOS and PC DOS for CJK (DOS/DBCS), extended characters are recorded to the SFN entry without up-case conversion and compared in case-sensitive. This causes a problem on compatibility with Windows system when any object with extended characters is created on the volume by DOS/DBCS system; therfore the object names with DBCS extended characters should not be used on the FAT volume shared by those systems. FatFs works with case-sensitive to the extended characters at only non-LFN with DBCS configuration (DOS/DBCS specs). But at LFN configuration, FatFs works with case-insensitive to the extended character (WindowsNT specs).</p>
</div>
<div class="para doc" id="uni">
<h3>Unicode API</h3>
<p>The path names are input/output in either ANSI/OEM code or Unicode depends on the configuration options. The type of arguments which specifies the path names is defined as <tt>TCHAR</tt>. It is an alias of <tt>char</tt> by default and the code set used for the path name string is ANSI/OEM specifid by <tt><a href="config.html#code_page">FF_CODE_PAGE</a></tt>. When <tt><a href="config.html#lfn_unicode">FF_LFN_UNICODE</a></tt> is set to 1, the type of the <tt>TCHAR</tt> is switched to <tt>WCHAR</tt> to support UTF-16 encoded Unicode string. When UTF-16 or UTF-8 is specified by this option, the full-featured LFN specification is supported and the Unicode specific characters, such as ✝☪✡☸☭, can also be used for the path name. It also affects data types and encoding of the string I/O functions. To define literal strings, <tt>_T(s)</tt> and <tt>_TEXT(s)</tt> macro are available to select either ANSI/OEM or Unicode automatically. The code shown below is an example to define the literal strings.</p>
<p>The path names are input/output in either ANSI/OEM code or Unicode depends on the configuration options. The type of arguments which specifies the path names is defined as <tt>TCHAR</tt>. It is an alias of <tt>char</tt> by default and the code set used for the path name string is ANSI/OEM specifid by <tt><a href="config.html#code_page">FF_CODE_PAGE</a></tt>. When <tt><a href="config.html#lfn_unicode">FF_LFN_UNICODE</a></tt> is set to 1 or larger, the type of the <tt>TCHAR</tt> is switched to proper type to support the Unicode string. When Unicode API is specified by this option, the full-featured LFN specification is supported and the Unicode specific characters, such as ✝☪✡☸☭, can also be used for the path name. It also affects data types and encoding of the string I/O functions. To define literal strings, <tt>_T(s)</tt> and <tt>_TEXT(s)</tt> macro are available to select either ANSI/OEM or Unicode automatically. The code shown below is an example to define the literal strings.</p>
<pre>
f_open(fp, "filename.txt", FA_READ); <span class="c">/* ANSI/OEM string (char) */</span>
f_open(fp, L"filename.txt", FA_READ); <span class="c">/* UTF-16 string (WCHAR) */</span>

View File

@ -50,7 +50,7 @@ FRESULT f_getcwd (
<div class="para desc">
<h4>Description</h4>
<p>The <tt>f_getcwd</tt> function retrieves full path name of the current directory of the current drive. When <tt><a href="config.html#volumes">FF_VOLUMES</a> &gt;= 2</tt>, a heading drive prefix is added to the path name. The style of drive prefix is depends on <tt><a href="config.html#str_volume_id">FF_STR_VOLUME_ID</a></tt>.</p>
<p>The <tt>f_getcwd</tt> function retrieves full path name of the current directory of the current drive. When <tt><a href="config.html#volumes">FF_VOLUMES</a> &gt;= 2</tt>, a heading drive prefix is added to the path name. The style of drive prefix depends on <tt><a href="config.html#str_volume_id">FF_STR_VOLUME_ID</a></tt>.</p>
<p><em>Note: In this revision, this function cannot retrieve the current directory path on the exFAT volume. It always returns the root directory path.</em></p>
</div>

View File

@ -118,7 +118,7 @@ int main (void)
fr = <em>f_open</em>(&amp;fil, "message.txt", FA_READ);
if (fr) return (int)fr;
<span class="c">/* Read all lines and display it */</span>
<span class="c">/* Read every line and display it */</span>
while (f_gets(line, sizeof line, &amp;fil)) {
printf(line);
}
@ -134,7 +134,7 @@ int main (void)
int main (void)
{
FATFS fs[2]; <span class="c">/* Work area (filesystem object) for logical drives */</span>
FATFS fs0, fs1; <span class="c">/* Work area (filesystem object) for logical drives */</span>
FIL fsrc, fdst; <span class="c">/* File objects */</span>
BYTE buffer[4096]; <span class="c">/* File copy buffer */</span>
FRESULT fr; <span class="c">/* FatFs function common result code */</span>
@ -142,8 +142,8 @@ int main (void)
<span class="c">/* Register work area for each logical drive */</span>
f_mount(&amp;fs[0], "0:", 0);
f_mount(&amp;fs[1], "1:", 0);
f_mount(&amp;fs0, "0:", 0);
f_mount(&amp;fs1, "1:", 0);
<span class="c">/* Open source file on the drive 1 */</span>
fr = <em>f_open</em>(&amp;fsrc, "1:file.bin", FA_READ);
@ -166,8 +166,8 @@ int main (void)
f_close(&amp;fdst);
<span class="c">/* Unregister work area prior to discard it */</span>
f_mount(NULL, "0:", 0);
f_mount(NULL, "1:", 0);
f_mount(0, "0:", 0);
f_mount(0, "1:", 0);
return (int)fr;
}

View File

@ -38,15 +38,15 @@ Note that if once this error occured at any operation to an open file, the file
<li>No medium in the drive.</li>
<li>Wrong lower layer implementation.</li>
<li>Wrong hardware configuration.</li>
<li>The storage device has been broken.</li>
<li>The storage device has broken.</li>
</ul>
</dd>
<dt id="nf">FR_NO_FILE</dt>
<dd>Could not find the file.</dd>
<dd>Could not find the file in the directory.</dd>
<dt id="np">FR_NO_PATH</dt>
<dd>Could not find the path.</dd>
<dd>Could not find the path, some directory in the path name could not be found.</dd>
<dt id="in">FR_INVALID_NAME</dt>
<dd>The given string is invalid as the <a href="filename.html">path name</a>. One of the following possibilities is suspected.
@ -72,12 +72,12 @@ Note that if once this error occured at any operation to an open file, the file
</dd>
<dt id="ex">FR_EXIST</dt>
<dd>Name collision. An object with the same name is already existing.</dd>
<dd>Name collision, an object with the same name is already existing.</dd>
<dt id="io">FR_INVALID_OBJECT</dt>
<dd>The file/directory object is invalid or a null pointer is given. There are some reasons as follows:
<ul>
<li>It has been closed, or collapsed.</li>
<li>It has been closed, or the structure has been collapsed.</li>
<li>It has been invalidated. Open objects on the volume are invalidated by voulme mount process.</li>
<li>Physical drive is not ready to work due to a media removal.</li>
</ul>

View File

@ -48,13 +48,13 @@ FRESULT f_readdir (
<div class="para desc">
<h4>Description</h4>
<p>The <tt>f_readdir</tt> function reads a directory item, informations about the object. All items in the directory can be read in sequence by <tt>f_readdir</tt> function calls. Dot entries (<tt>"."</tt> and <tt>".."</tt>) in the sub-directory are filtered out and they will never appear in the read items. When all directory items have been read and no item to read, a nul string is stored into the <tt>fno-&gt;fname[]</tt> without any error. When a null pointer is given to the <tt class="arg">fno</tt>, the read index of the directory object is rewinded.</p>
<p>The <tt>f_readdir</tt> function reads a directory item, informations about the object. Every item in the directory can be read in sequence by <tt>f_readdir</tt> function calls. Dot entries (<tt>"."</tt> and <tt>".."</tt>) in the sub-directory are filtered out and they will never appear in the read items. When all directory items have been read and no item to read, a null string is stored into the <tt>fno-&gt;fname[]</tt> without any error. When a null pointer is given to the <tt class="arg">fno</tt>, the read index of the directory object is rewinded.</p>
<p>When support of long file name (LFN) is enabled, a member <tt>altname[]</tt> is defined in the file information structure to store the short file name of the object. If the long file name is not accessible due to some reason listed below, short file name is stored to the <tt>fname[]</tt> and <tt>altname[]</tt> has a null string.</p>
<ul>
<li>The item has no LFN. (Not the case at exFAT volume)</li>
<li>Setting of <a href="config.html#max_lfn"><tt>FF_MAX_LFN</tt></a> is insufficient to handle the LFN. (Not the case at <tt>FF_MAX_LFN == 255</tt>)</li>
<li>Setting of <a href="config.html#lfn_buf"><tt>FF_LFN_BUF</tt></a> is insufficient to store the LFN.</li>
<li>The LFN contains any character not defined in current code page. (Not the case at <tt>FF_LFN_UNICODE &gt;= 1</tt>)</li>
<li>The LFN contains some character not defined in current code page. (Not the case at <tt>FF_LFN_UNICODE &gt;= 1</tt>)</li>
</ul>
<p>There is a problem on reading a directory of exFAT volume. The exFAT does not support short file name. This means no name can be returned on the condition above. If it is the case, "?" is returned into the <tt>fname[]</tt> to indicate that the object is not accessible. To avoid this problem, configure FatFs <tt><a href="config.html#lfn_unicode">FF_LFN_UNICODE</a> &gt;= 1</tt> and <tt>FF_MAX_LFN == 255</tt> to support the full feature of LFN specification.</p>
</div>

View File

@ -53,9 +53,9 @@ FRESULT f_setlabel (
<ul>
<li>Up to 11 bytes long as conversion of OEM code page at FAT volume.</li>
<li>Up to 11 characters long at exFAT volume.</li>
<li>Allowable characters for FAT volume are: <tt>! # $ % &amp; ' ( ) - ^ _ ` ~ { } 0-9 A-Z a-z</tt> and extended characters. Low-case characters are up converted.</li>
<li>Allowable characters for exFAT volume are: characters allowed for FAT volume and <tt>" + , . ; = [ ]</tt>. Low-case characters are preserved.</li>
<li>Spaces can be contained anywhere in the volume label. Trailing spaces are truncated off at FAT volume.</li>
<li>Allowable characters for FAT volume are: characters allowed for SFN excludes dot. Low-case characters are up converted.</li>
<li>Allowable characters for exFAT volume are: characters allowed for LFN includes dot. Low-case characters are preserved.</li>
<li>Spaces can be embedded anywhere in the volume label. Trailing spaces are truncated off at FAT volume.</li>
</ul>
<p>Remark: The standard system (Windows) has a problem at the volume label with a heading <tt>\xE5</tt> on the FAT volume. To avoid this problem, this function rejects such volume label as invalid name.</p>
</div>

View File

@ -44,7 +44,30 @@ FRESULT f_sync (
<div class="para desc">
<h4>Description</h4>
<p>The <tt>f_sync</tt> function performs the same process as <tt>f_close</tt> function but the file is left opened and can continue read/write/seek operations to the file. This is suitable for the applications that open files for a long time in write mode, such as data logger. Performing <tt>f_sync</tt> function of periodic or immediataly after <tt>f_write</tt> function can minimize the risk of data loss due to a sudden blackout or an unintentional media removal. For more information, refer to <a href="appnote.html#critical">application note</a>.</p>
<p>The <tt>f_sync</tt> function performs the same process as <tt>f_close</tt> function but the file is left opened and can continue read/write/seek operations to the file. This is suitable for the applications that open files for a long time in write mode, such as data logger. Performing <tt>f_sync</tt> function in certain interval can minimize the risk of data loss due to a sudden blackout or an unintentional media removal. For more information, refer to <a href="appnote.html#critical">application note</a>.</p>
<pre>
Case 1. Normal write sequence
Time --&gt; ↓Power off after close
OwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwC
Case 2. Without using f_sync()
Time --&gt; ↓System crush
O<span class="e">wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww</span>
|&lt;--------------- All data written will be lost ------------------&gt;|
Case 3. Using f_sync()
Time --&gt; ↓System crush
OwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwS<span class="e">wwwww</span>
Data after last f_sync will be lost |&lt;-&gt;|
O - f_open()
C - f_close()
w - f_write()
S - f_sync()
</pre>
<p>However there is no sense in <tt>f_sync</tt> function immediataly before <tt>f_close</tt> function because it performs <tt>f_sync</tt> function in it. In other words, the differnce between those functions is that the file object is invalidated or not.</p>
</div>

View File

@ -13,7 +13,7 @@
<div class="para func">
<h2>f_unlink</h2>
<p>The f_unlink function removes a file or sub-directory.</p>
<p>The f_unlink function removes a file or sub-directory from the volume.</p>
<pre>
FRESULT f_unlink (
const TCHAR* <span class="arg">path</span> <span class="c">/* [IN] Object name */</span>

View File

@ -1,65 +1,78 @@
/*------------------------------------------------------------/
/ Remove all contents of a directory
/ This function works regardless of FF_FS_RPATH.
/------------------------------------------------------------*/
/ Delete a sub-directory even if it contains any file
/-------------------------------------------------------------/
/ The delete_node() function is for R0.12+.
/ It works regardless of FF_FS_RPATH.
*/
FILINFO fno;
FRESULT empty_directory (
char* path /* Working buffer filled with start directory */
FRESULT delete_node (
TCHAR* path, /* Path name buffer with the sub-directory to delete */
UINT sz_buff, /* Size of path name buffer (items) */
FILINFO* fno /* Name read buffer */
)
{
UINT i, j;
FRESULT fr;
DIR dir;
fr = f_opendir(&dir, path);
if (fr == FR_OK) {
for (i = 0; path[i]; i++) ;
path[i++] = '/';
for (;;) {
fr = f_readdir(&dir, &fno);
if (fr != FR_OK || !fno.fname[0]) break;
if (_FS_RPATH && fno.fname[0] == '.') continue;
j = 0;
do
path[i+j] = fno.fname[j];
while (fno.fname[j++]);
if (fno.fattrib & AM_DIR) {
fr = empty_directory(path);
if (fr != FR_OK) break;
fr = f_opendir(&dir, path); /* Open the sub-directory to make it empty */
if (fr != FR_OK) return fr;
for (i = 0; path[i]; i++) ; /* Get current path length */
path[i++] = _T('/');
for (;;) {
fr = f_readdir(&dir, fno); /* Get a directory item */
if (fr != FR_OK || !fno->fname[0]) break; /* End of directory? */
j = 0;
do { /* Make a path name */
if (i + j >= sz_buff) { /* Buffer over flow? */
fr = 100; break; /* Fails with 100 when buffer overflow */
}
path[i + j] = fno->fname[j];
} while (fno->fname[j++]);
if (fno->fattrib & AM_DIR) { /* Item is a sub-directory */
fr = delete_node(path, sz_buff, fno);
} else { /* Item is a file */
fr = f_unlink(path);
if (fr != FR_OK) break;
}
path[--i] = '\0';
closedir(&dir);
if (fr != FR_OK) break;
}
path[--i] = 0; /* Restore the path name */
f_closedir(&dir);
if (fr == FR_OK) fr = f_unlink(path); /* Delete the empty sub-directory */
return fr;
}
int main (void)
int main (void) /* How to use */
{
FRESULT fr;
FATFS fs;
char buff[256]; /* Working buffer */
TCHAR buff[256];
FILINFO fno;
f_mount(&fs, _T("5:"), 0);
f_mount(&fs, "", 0);
/* Directory to be deleted */
_tcscpy(buff, _T("5:dir"));
strcpy(buff, "/"); /* Directory to be emptied */
fr = empty_directory(buff);
/* Delete the directory */
fr = delete_node(buff, sizeof buff / sizeof buff[0], &fno);
/* Check the result */
if (fr) {
printf("Function failed. (%u)\n", fr);
_tprintf(_T("Failed to delete the directory. (%u)\n"), fr);
return fr;
} else {
printf("All contents in the %s are successfully removed.\n", buff);
_tprintf(_T("The directory and the contents have successfully been deleted.\n"), buff);
return 0;
}
}

38
documents/res/app5.c Normal file
View File

@ -0,0 +1,38 @@
/*----------------------------------------------------------------------/
/ Test if the file is contiguous /
/----------------------------------------------------------------------*/
FRESULT test_contiguous_file (
FIL* fp, /* [IN] Open file object to be checked */
int* cont /* [OUT] 1:Contiguous, 0:Fragmented or zero-length */
)
{
DWORD clst, clsz, step;
FSIZE_t fsz;
FRESULT fr;
*cont = 0;
fr = f_lseek(fp, 0); /* Validates and prepares the file */
if (fr != FR_OK) return fr;
#if FF_MAX_SS == FF_MIN_SS
clsz = (DWORD)fp->obj.fs->csize * FF_MAX_SS; /* Cluster size */
#else
clsz = (DWORD)fp->obj.fs->csize * fp->obj.fs->ssize;
#endif
fsz = fp->obj.objsize;
if (fsz > 0) {
clst = fp->obj.sclust - 1; /* A cluster leading the first cluster for first test */
while (fsz) {
step = (fsz >= clsz) ? clsz : (DWORD)fsz;
fr = f_lseek(fp, f_tell(fp) + step); /* Advances file pointer a cluster */
if (fr != FR_OK) return fr;
if (clst + 1 != fp->clust) break; /* Is not the cluster next to previous one? */
clst = fp->clust; fsz -= step; /* Get current cluster for next test */
}
if (fsz == 0) *cont = 1; /* All done without fail? */
}
return FR_OK;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,6 +1,12 @@
R0.13c (October 14, 2018)
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
R0.13b (April 07, 2018)
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
Added support for Unix style volume prefix. (FF_STR_VOLUME_ID = 2)
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)

View File

@ -322,3 +322,9 @@ R0.13b (April 07, 2018)
R0.13c (October 14, 2018)
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)

View File

@ -1,4 +1,4 @@
FatFs Module Source Files R0.13b
FatFs Module Source Files R0.13c
FILES
@ -10,7 +10,6 @@ FILES
ff.h Common include file for FatFs and application module.
diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs.
ffunicode.c Optional Unicode utility functions.
ffsystem.c An example of optional O/S related functions.

View File

@ -7,7 +7,8 @@
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
/* Definitions of physical drive number for each drive */
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
@ -143,6 +144,8 @@ DRESULT disk_read (
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
@ -185,6 +188,7 @@ DRESULT disk_write (
return RES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/

View File

@ -9,9 +9,6 @@
extern "C" {
#endif
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;

View File

@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module R0.13b /
/ FatFs - Generic FAT Filesystem Module R0.13c /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
@ -29,11 +29,20 @@
---------------------------------------------------------------------------*/
#if FF_DEFINED != 63463 /* Revision ID */
#if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h).
#endif
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
/* Character code support macros */
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
@ -43,18 +52,18 @@
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Additional file access control and file status flags for internal use */
#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
#define FA_MODIFIED 0x40 /* File has been modified */
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Name status flags in fn[11] */
#define NSFLAG 11 /* Index of the name status byte */
#define NS_LOSS 0x01 /* Out of 8.3 format */
@ -67,13 +76,13 @@
#define NS_NONAME 0x80 /* Not followed */
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
/* exFAT directory entry types */
#define ET_BITMAP 0x81 /* Allocation bitmap */
#define ET_UPCASE 0x82 /* Up-case table */
#define ET_VLABEL 0x83 /* Volume label */
#define ET_FILEDIR 0x85 /* File and directory */
#define ET_STREAM 0xC0 /* Stream extension */
#define ET_FILENAME 0xC1 /* Name extension */
/* FatFs refers the FAT structure as simple byte array instead of structure member
@ -521,6 +530,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
#define CODEPAGE CodePage
static WORD CodePage; /* Current code page */
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
static const BYTE Ct437[] = TBL_CT437;
static const BYTE Ct720[] = TBL_CT720;
static const BYTE Ct737[] = TBL_CT737;
@ -1093,7 +1103,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
if (res == FR_OK) {
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
/* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs));
mem_set(fs->win, 0, sizeof fs->win);
st_word(fs->win + BS_55AA, 0xAA55);
st_dword(fs->win + FSI_LeadSig, 0x41615252);
st_dword(fs->win + FSI_StrucSig, 0x61417272);
@ -1293,7 +1303,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D
if (clst >= fs->n_fatent - 2) clst = 0;
scl = val = clst; ctr = 0;
for (;;) {
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */
if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
i = val / 8 % SS(fs); bm = 1 << (val % 8);
do {
do {
@ -1331,9 +1341,9 @@ static FRESULT change_bitmap (
clst -= 2; /* The first bit corresponds to cluster #2 */
sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */
i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */
sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */
for (;;) {
if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
do {
@ -1406,7 +1416,7 @@ static FRESULT fill_last_frag (
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FFOBJID* obj, /* Corresponding object */
DWORD clst, /* Cluster to remove a chain from */
DWORD pclst /* Previous cluster of clst (0:entire chain) */
DWORD pclst /* Previous cluster of clst (0 if entire chain) */
)
{
FRESULT res = FR_OK;
@ -1644,7 +1654,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */
if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
sect = clst2sect(fs, clst); /* Top of the cluster */
fs->winsect = sect; /* Set window to top of the cluster */
mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */
mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
/* Allocate a temporary buffer */
for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
@ -1728,7 +1738,8 @@ static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DEN
ofs = dp->dptr + SZDIRE; /* Next entry */
if (dp->sect == 0 || ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */
if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */
if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */
if (ofs % SS(fs) == 0) { /* Sector changed? */
dp->sect++; /* Next sector */
@ -2153,33 +2164,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */
/* Load 85 entry */
/* Load file-directory entry */
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */
if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
/* Load C0 entry */
/* Load stream-extension entry */
res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */
if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
/* Load C1 entries */
i = 2 * SZDIRE; /* C1 offset to load */
/* Load file-name entries */
i = 2 * SZDIRE; /* Name offset to load */
do {
res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */
if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
} while ((i += SZDIRE) < sz_ent);
@ -2284,16 +2295,16 @@ static void create_xdir (
WCHAR wc;
/* Create 85,C0 entry */
/* Create file-directory and stream-extension entry */
mem_set(dirb, 0, 2 * SZDIRE);
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */
dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
/* Create C1 entries */
i = SZDIRE * 2; /* Top of C1 entries */
/* Create file-name entries */
i = SZDIRE * 2; /* Top of file_name entries */
nlen = nc1 = 0; wc = 1;
do {
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */
dirb[i++] = ET_FILENAME; dirb[i++] = 0;
do { /* Fill name field */
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
st_word(dirb + i, wc); /* Store it */
@ -2317,8 +2328,8 @@ static void create_xdir (
/* Read an object from the directory */
/*-----------------------------------------------------------------------*/
#define dir_read_file(dp) dir_read(dp, 0)
#define dir_read_label(dp) dir_read(dp, 1)
#define DIR_READ_FILE(dp) dir_read(dp, 0)
#define DIR_READ_LABEL(dp) dir_read(dp, 1)
static FRESULT dir_read (
DIR* dp, /* Pointer to the directory object */
@ -2327,7 +2338,7 @@ static FRESULT dir_read (
{
FRESULT res = FR_NO_FILE;
FATFS *fs = dp->obj.fs;
BYTE a, c;
BYTE attr, b;
#if FF_USE_LFN
BYTE ord = 0xFF, sum = 0xFF;
#endif
@ -2335,16 +2346,16 @@ static FRESULT dir_read (
while (dp->sect) {
res = move_window(fs, dp->sect);
if (res != FR_OK) break;
c = dp->dir[DIR_Name]; /* Test for the entry type */
if (c == 0) {
b = dp->dir[DIR_Name]; /* Test for the entry type */
if (b == 0) {
res = FR_NO_FILE; break; /* Reached to end of the directory */
}
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
if (FF_USE_LABEL && vol) {
if (c == 0x83) break; /* Volume label entry? */
if (b == ET_VLABEL) break; /* Volume label entry? */
} else {
if (c == 0x85) { /* Start of the file entry block? */
if (b == ET_FILEDIR) { /* Start of the file entry block? */
dp->blk_ofs = dp->dptr; /* Get location of the block */
res = load_xdir(dp); /* Load the entry block */
if (res == FR_OK) {
@ -2356,19 +2367,19 @@ static FRESULT dir_read (
} else
#endif
{ /* On the FAT/FAT32 volume */
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
#if FF_USE_LFN /* LFN configuration */
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
ord = 0xFF;
} else {
if (a == AM_LFN) { /* An LFN entry is found */
if (c & LLEF) { /* Is it start of an LFN sequence? */
if (attr == AM_LFN) { /* An LFN entry is found */
if (b & LLEF) { /* Is it start of an LFN sequence? */
sum = dp->dir[LDIR_Chksum];
c &= (BYTE)~LLEF; ord = c;
b &= (BYTE)~LLEF; ord = b;
dp->blk_ofs = dp->dptr;
}
/* Check LFN validity and capture it */
ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
} else { /* An SFN entry is found */
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
@ -2377,7 +2388,7 @@ static FRESULT dir_read (
}
}
#else /* Non LFN configuration */
if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
break;
}
#endif
@ -2417,7 +2428,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
UINT di, ni;
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */
while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */
#if FF_MAX_LFN < 255
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
#endif
@ -2496,17 +2507,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
res = dir_alloc(dp, nent); /* Allocate entries */
res = dir_alloc(dp, nent); /* Allocate directory entries */
if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
if (dp->obj.stat & 4) { /* Has the directory been stretched? */
if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */
dp->obj.stat &= ~4;
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
if (res != FR_OK) return res;
if (dp->obj.sclust != 0) { /* Is it a sub directory? */
if (dp->obj.sclust != 0) { /* Is it a sub-directory? */
DIR dj;
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
@ -3254,7 +3265,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
#endif
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
bsect = 0;
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
@ -3277,6 +3288,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_FS_EXFAT
if (fmt == 1) {
QWORD maxlba;
DWORD so, cv, bcl;
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
@ -3309,12 +3321,27 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
/* Check if bitmap location is in assumption (at the first cluster) */
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR;
for (i = 0; i < SS(fs); i += SZDIRE) {
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
/* Get bitmap location and check if it is contiguous (implementation assumption) */
so = i = 0;
for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */
if (i == 0) {
if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */
if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR;
so++;
}
if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
i = (i + SZDIRE) % SS(fs); /* Next entry */
}
if (i == SS(fs)) return FR_NO_FILESYSTEM;
bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM;
fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */
for (;;) { /* Check if bitmap is contiguous */
if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
if (cv == 0xFFFFFFFF) break; /* Last link? */
if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */
}
#if !FF_FS_READONLY
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
#endif
@ -3664,7 +3691,7 @@ FRESULT f_open (
fp->fptr = 0; /* Set file pointer top of the file */
#if !FF_FS_READONLY
#if !FF_FS_TINY
mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */
mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */
#endif
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
fp->fptr = fp->obj.objsize; /* Offset to seek */
@ -4144,6 +4171,7 @@ FRESULT f_getcwd (
/* Get logical drive */
buff[0] = 0; /* Set null string to get current volume */
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
if (res == FR_OK) {
dj.obj.fs = fs;
@ -4162,7 +4190,7 @@ FRESULT f_getcwd (
res = dir_sdi(&dj, 0);
if (res != FR_OK) break;
do { /* Find the entry links to the child directory */
res = dir_read_file(&dj);
res = DIR_READ_FILE(&dj);
if (res != FR_OK) break;
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
res = dir_next(&dj, 0);
@ -4494,7 +4522,7 @@ FRESULT f_readdir (
res = dir_sdi(dp, 0); /* Rewind the directory object */
} else {
INIT_NAMBUF(fs);
res = dir_read_file(dp); /* Read an item */
res = DIR_READ_FILE(dp); /* Read an item */
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
if (res == FR_OK) { /* A valid entry is found */
get_fileinfo(dp, fno); /* Get the object information */
@ -4639,7 +4667,7 @@ FRESULT f_getfree (
UINT b;
clst = fs->n_fatent - 2; /* Number of clusters */
sect = fs->database; /* Assuming bitmap starts at cluster 2 */
sect = fs->bitbase; /* Bitmap sector */
i = 0; /* Offset in the sector */
do { /* Counts numbuer of bits with zero in the bitmap */
if (i == 0) {
@ -4802,7 +4830,7 @@ FRESULT f_unlink (
#endif
res = dir_sdi(&sdj, 0);
if (res == FR_OK) {
res = dir_read_file(&sdj); /* Test if the directory is empty */
res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */
if (res == FR_OK) res = FR_DENIED; /* Not empty? */
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
}
@ -4840,73 +4868,69 @@ FRESULT f_mkdir (
{
FRESULT res;
DIR dj;
FFOBJID sobj;
FATFS *fs;
BYTE *dir;
DWORD dcl, pcl, tm;
DEF_NAMBUF
/* Get logical drive */
res = find_volume(&path, &fs, FA_WRITE);
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
if (res == FR_OK) {
dj.obj.fs = fs;
INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {
if (res == FR_OK) res = FR_EXIST; /* Name collision? */
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
res = FR_INVALID_NAME;
}
if (res == FR_NO_FILE) { /* Can create a new directory */
dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */
dj.obj.objsize = (DWORD)fs->csize * SS(fs);
if (res == FR_NO_FILE) { /* It is clear to create a new directory */
sobj.fs = fs; /* New object id to create a new chain */
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
res = FR_OK;
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
if (dcl == 1) res = FR_INT_ERR;
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
tm = GET_FATTIME();
if (res == FR_OK) { /* Initialize the new directory table */
res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */
dir = fs->win;
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
dir[DIR_Name] = '.';
dir[DIR_Attr] = AM_DIR;
st_dword(dir + DIR_ModTime, tm);
st_clust(fs, dir, dcl);
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, dir + SZDIRE, pcl);
fs->wflag = 1;
}
}
if (res == FR_OK) {
res = dir_register(&dj); /* Register the object to the directoy */
res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK) {
if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
fs->win[DIR_Name] = '.';
fs->win[DIR_Attr] = AM_DIR;
st_dword(fs->win + DIR_ModTime, tm);
st_clust(fs, fs->win, dcl);
mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, fs->win + SZDIRE, pcl);
fs->wflag = 1;
}
res = dir_register(&dj); /* Register the object to the parent directoy */
}
}
if (res == FR_OK) {
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */
st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */
st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */
st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */
st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize);
st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */
st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs));
fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */
fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */
res = store_xdir(&dj);
} else
#endif
{
dir = dj.dir;
st_dword(dir + DIR_ModTime, tm); /* Created time */
st_clust(fs, dir, dcl); /* Table start cluster */
dir[DIR_Attr] = AM_DIR; /* Attribute */
st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
st_clust(fs, dj.dir, dcl); /* Table start cluster */
dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
fs->wflag = 1;
}
if (res == FR_OK) {
res = sync_fs(fs);
}
} else {
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */
remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */
}
}
FREE_NAMBUF();
@ -5146,7 +5170,7 @@ FRESULT f_getlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0);
if (res == FR_OK) {
res = dir_read_label(&dj); /* Find a volume label entry */
res = DIR_READ_LABEL(&dj); /* Find a volume label entry */
if (res == FR_OK) {
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) {
@ -5291,7 +5315,7 @@ FRESULT f_setlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0);
if (res == FR_OK) {
res = dir_read_label(&dj); /* Get volume label entry */
res = DIR_READ_LABEL(&dj); /* Get volume label entry */
if (res == FR_OK) {
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
@ -5313,7 +5337,7 @@ FRESULT f_setlabel (
if (res == FR_OK) {
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */
dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */
dj.dir[XDIR_NumLabel] = (BYTE)di;
mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
} else {
@ -5699,11 +5723,11 @@ FRESULT f_mkfs (
/* Initialize the root directory */
mem_set(buf, 0, szb_buf);
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */
buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */
buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
@ -6191,8 +6215,7 @@ typedef struct { /* Putchar output buffer and work area */
} putbuff;
static
void putc_bfd ( /* Buffered write with code conversion */
static void putc_bfd ( /* Buffered write with code conversion */
putbuff* pb,
TCHAR c
)
@ -6303,7 +6326,7 @@ void putc_bfd ( /* Buffered write with code conversion */
#else /* Write it in ANSI/OEM */
if (hs != 0) return;
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
if (wc == 0) return;;
if (wc == 0) return;
if (wc >= 0x100) {
pb->buf[i++] = (BYTE)(wc >> 8); nc++;
}
@ -6323,8 +6346,7 @@ void putc_bfd ( /* Buffered write with code conversion */
}
static
int putc_flush ( /* Flush left characters in the buffer */
static int putc_flush ( /* Flush left characters in the buffer */
putbuff* pb
)
{
@ -6337,8 +6359,7 @@ int putc_flush ( /* Flush left characters in the buffer */
}
static
void putc_init ( /* Initialize write buffer */
static void putc_init ( /* Initialize write buffer */
putbuff* pb,
FIL* fp
)

View File

@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13b /
/ FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
@ -20,13 +20,12 @@
#ifndef FF_DEFINED
#define FF_DEFINED 63463 /* Revision ID */
#define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
@ -34,6 +33,30 @@ extern "C" {
#endif
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint16_t WCHAR; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef unsigned short WORD; /* 16-bit unsigned integer */
typedef unsigned short WCHAR; /* 16-bit unsigned integer */
typedef unsigned long DWORD; /* 32-bit unsigned integer */
#endif
/* Definitions of volume management */
@ -85,6 +108,9 @@ typedef char TCHAR;
/* Type of file size variables */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
@ -95,8 +121,8 @@ typedef DWORD FSIZE_t;
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:N/A) */
BYTE pdrv; /* Physical drive number */
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
@ -133,6 +159,9 @@ typedef struct {
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
@ -145,7 +174,7 @@ typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT

View File

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/
/ FatFs - Configuration file
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 63463 /* Revision ID */
#define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@ -232,7 +232,7 @@
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled.
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
@ -262,6 +262,7 @@
/ lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
@ -282,8 +283,6 @@
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/

View File

@ -1,20 +1,19 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C)ChaN, 2017 */
/* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/
#include "ff.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
@ -27,7 +26,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do for null) */
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
)
{
free(mblock); /* Free the memory block with POSIX API */
@ -47,7 +46,7 @@ void ff_memfree (
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
@ -74,7 +73,7 @@ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object
// return (int)(*sobj != NULL);
/* CMSIS-RTOS */
// *sobj = osMutexCreate(Mutex + vol);
// *sobj = osMutexCreate(&Mutex[vol]);
// return (int)(*sobj != NULL);
}

View File

@ -1,5 +1,5 @@
/*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13b */
/* Unicode handling functions for FatFs R0.13c */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
@ -25,9 +25,9 @@
#include "ff.h"
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */
#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
#if FF_DEFINED != 63463 /* Revision ID */
#if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h).
#endif

View File

@ -1,36 +0,0 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef FF_INTEGER
#define FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
typedef unsigned long long QWORD;
#endif
#endif