diff --git a/documents/doc/appnote.html b/documents/doc/appnote.html index 591a91f..2c96520 100644 --- a/documents/doc/appnote.html +++ b/documents/doc/appnote.html @@ -32,22 +32,28 @@

How to Port

Basic Considerations

-

The FatFs module is assuming following conditions on portability.

+

The FatFs module assumes following conditions on portability.

System Organizations

-

The dependency diagram shown below is a typical but not specific configuration of the embedded system with FatFs module.

+

The dependency diagram shown below is a typical, but not specific, configuration of the embedded system with FatFs module.

dependency diagram

-

(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.

+

(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.

functional diagram

Required Functions

-

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.

+

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.

@@ -55,10 +61,11 @@ The FatFs module assumes that size of char/short/long - - + +
FunctionRequired whenNote
disk_status
disk_initialize
disk_read
AlwaysDisk I/O functions.
Samples available in ffsample.zip.
There are many implementations on the web.
disk_ioctl (GET_SECTOR_COUNT)
disk_ioctl (GET_BLOCK_SIZE)
FF_USE_MKFS == 1
disk_ioctl (GET_SECTOR_SIZE)FF_MAX_SS != FF_MIN_SS
disk_ioctl (CTRL_TRIM)FF_USE_TRIM == 1
ff_uni2oem
ff_oem2uni
ff_wtoupper
FF_USE_LFN != 0Unicode support functions.
Just add ffunicode.c to the project.
ff_cre_syncobj
ff_del_syncobj
ff_req_grant
ff_rel_grant
FF_FS_REENTRANT == 1O/S dependent functions.
Samples available in ffsystem.c.
ff_uni2oem
ff_oem2uni
ff_wtoupper
FF_USE_LFN != 0Unicode support functions.
Add optional module ffunicode.c to the project.
ff_cre_syncobj
ff_del_syncobj
ff_req_grant
ff_rel_grant
FF_FS_REENTRANT == 1O/S dependent functions.
Sample code is available in ffsystem.c.
ff_mem_alloc
ff_mem_free
FF_USE_LFN == 3
+

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.

@@ -89,13 +96,13 @@ The FatFs module assumes that size of char/short/long Work area
(FF_FS_TINY == 0)V*564
+ F*552V*564
+ F*552V*564
+ F*552V*560
+ F*546V*560
+ F*546V*560
+ F*546V*560
+ F*546V*564
+ F*552V*564
+ F*552V*564
+ F*552V*564
+ F*552 Work area
(FF_FS_TINY == 1)V*564
+ F*40V*564
+ F*40V*564
+ F*40V*560
+ F*34V*560
+ F*34V*560
+ F*34V*560
+ F*34V*564
+ F*40V*564
+ F*40V*564
+ F*40V*564
+ F*40 -

These are the memory usage on some target systems with following condition. The memory sizes are in unit of byte, V denotes number of mounted volumes and F denotes number of open files. All samples here are optimezed in code size.

+

These are the memory usage of FatFs module without lower layer on some target systems in following condition. V denotes number of mounted volumes and F denotes number of open files. Every samples here are optimezed in code size.

 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.
 
@@ -146,8 +153,8 @@ And other options are left unchanged from original setting.

Long File Name

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 f_readdir function. The support for LFN is disabled by default. To enable the LFN, set FF_USE_LFN to 1, 2 or 3, and add ffunicode.c to the project. The LFN requiers a certain working buffer in addition. The buffer size can be configured by FF_MAX_LFN according to the available memory. The length of an LFN will be up to 255 characters, so that the FF_MAX_LFN 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 FR_INVALID_NAME. When use any re-entry to the API with LFN is enabled, FF_USE_LFN 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 (FF_MAX_LFN + 1) * 2 bytes and additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.

- - + + @@ -155,22 +162,22 @@ And other options are left unchanged from original setting.
With LFN at CM3+gcc
FF_CODE_PAGEIncrement
With LFN at CM3 + gcc
FF_CODE_PAGECode size
437-869 (SBCS)+3.3k
932 (Japanese)+62k
936 (Simplified Chinese)+177k
950 (Traditional Chinese)+111k
0 (All code pages)+486k
-

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.

-

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.

-

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.

+

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 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.

+

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.

Unicode API

-

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 FF_LFN_UNICODE. This means that FatFs supports the full featured LFN specification. The data type TCHAR specifies path name strings on the API is an alias of either char(ANSI/OEM or UTF-8), WCHAR(UTF-16) or DWORD(UTF-32) depends on that option. For more information, refer to the description in the file name.

-

Note that code page setting, FF_CODE_PAGE, has actually no meaning for the path names at the Unicode API. However it still affects code conversion of string I/O functions at FF_STRF_ENCODE != 0 and backward compatibility with legacy systems, so that code page needs to be configured properly when it is considered a problem.

+

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 FF_LFN_UNICODE. This means that FatFs is compliant with the full featured LFN specification. The data type TCHAR specifies path name strings on the API is an alias of either char(ANSI/OEM or UTF-8), WCHAR(UTF-16) or DWORD(UTF-32) depends on that option. For more information, refer to the description in the file name.

+

Note that setting of code page, FF_CODE_PAGE, 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 FF_STRF_ENCODE == 0 and backward compatibility with legacy systems, so that code page may need to be configured properly if it is considered a problem.

exFAT Filesystem

-

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.

-

Note that the exFAT is a patent of Microsoft Corporation. The exFAT function of FatFs is an implementation based on US. Pat. App. Pub. No. 2009/0164440 A1. FatFs module can switch the support for exFAT on/off by configuration option, FF_FS_EXFAT. When enable the exFAT on the commercial products, a license by Microsoft will be needed depends on the final destination of the products.

-

Remark: Enabling exFAT discards ANSI C (C89) compatibility because of need for 64-bit integer type.

+

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.

+

Note that the exFAT is a patent of Microsoft Corporation. The support for exFAT of FatFs is an implementation based on US. Pat. App. Pub. No. 2009/0164440 A1. FatFs module can switch the exFAT on or off by configuration option, FF_FS_EXFAT. When enable the exFAT on the commercial products, a license by Microsoft will be needed depends on the final destination of the products.

+

Remark: Enabling exFAT discards C89 compatibility because of need for 64-bit integer type.

@@ -245,11 +252,12 @@ Figure 5. Minimized critical section

Extended Use of FatFs API

These are examples of extended use of FatFs APIs. New item will be added whenever a useful code is found.

    -
  1. Open or create a file for append (for only R0.12 and earlier)
  2. -
  3. Empty a directory
  4. -
  5. Allocate contiguous area to the file (for only R0.11a and earlier)
  6. +
  7. Open or create a file for append (for R0.12 and earlier)
  8. +
  9. Delete a non-empty sub-directory (for R0.12 and later)
  10. +
  11. Allocate contiguous area to the file (for R0.11a and earlier)
  12. Compatibility checker for low level disk I/O module
  13. FAT volume image creator
  14. +
  15. Test if the file is contiguous or not
diff --git a/documents/doc/config.html b/documents/doc/config.html index d4a6da0..3d2a580 100644 --- a/documents/doc/config.html +++ b/documents/doc/config.html @@ -116,10 +116,10 @@

Namespace and Locale Configurations

FF_CODE_PAGE

-

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.

+

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.

- + @@ -157,7 +157,7 @@

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 (FF_MAX_LFN + 1) * 2 bytes and additional (FF_MAX_LFN + 44) / 15 * 32 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.

FF_LFN_UNICODE

-

This option switches character encoding for the file name on the API. When Unicode is selected, FF_CODE_PAGE has actually no meaning except for compatibility with legacy systems. FatFs supports the code point upto U+10FFFF.

+

This option switches character encoding for the file name on the API. When Unicode is selected, FF_CODE_PAGE 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.

ValueCode page
0Include all code pages below and set by f_setcp()
0Includes all code pages below and set by f_setcp()
437U.S.
720Arabic
737Greek
@@ -168,7 +168,7 @@

This option also affects behavior of string I/O functions (see FF_STRF_ENCODE). When LFN is not enabled, this option has no effect and FatFs works at ANSI/OEM code on the API. For more information, read here.

FF_LFN_BUF, FF_SFN_BUF

-

This set of options defines size of file name members, fname[] and altname[], in the FILINFO 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:

+

This set of options defines size of file name members, fname[] and altname[], in the FILINFO 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:

ValueCharacter EncodingTCHAR
0ANSI/OEM in current CPchar
@@ -179,7 +179,7 @@

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.

FF_STRF_ENCODE

-

When character encoding on the API is Unicode (FF_LFN_UNICODE >= 1), string I/O functions, f_gets, f_putc, f_puts and f_printf, convert the character encodins in it. This option defines the assumption of character encoding on the file to be read/written via those functions. When LFN is not enabled or FF_LFN_UNICODE == 0, the string functions work without any encoding conversion and this option has no effect.

+

When character encoding on the API is Unicode (FF_LFN_UNICODE >= 1), string I/O functions, f_gets, f_putc, f_puts and f_printf, convert the character encoding in it. This option defines the assumption of character encoding on the file to be read/written via those functions. When LFN is not enabled or FF_LFN_UNICODE == 0, the string functions work without any encoding conversion and this option has no effect.

EncodingLFN lengthSFN length
ANSI/OEM at SBCS255 items12 items
@@ -216,7 +216,7 @@
ValueCharacter encoding on the file
0ANSI/OEM in current code page

FF_VOLUME_STRS

-

This option defines the volume ID strings for each logical drives. Number of items must not be less than FF_VOLUMES. Valid characters for the volume ID string are A-Z, a-z and 0-9, however, they are compared in case-insensitive. If FF_STR_VOLUME_ID == 0, this option has no effect. If FF_STR_VOLUME_ID >= 1 and this option is not defined, a user defined volume string table needs to be defined as shown below.

+

This option defines the volume ID strings for each logical drives. Number of items must not be less than FF_VOLUMES. Valid characters for the volume ID string are A-Z, a-z and 0-9, however, they are compared in case-insensitive. If FF_STR_VOLUME_ID == 0, this option has no effect. If FF_STR_VOLUME_ID >= 1 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.

 /* User defined volume ID strings for 0:    1:      2:    3:   ... */
 const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sdc","usb"};
@@ -268,7 +268,7 @@ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sdc","usb"};
 
 
 

FF_FS_REENTRANT

-

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. f_mount, f_mkfs and f_fdisk, 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, ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj, need to be added to the project. Sample code is available in ffsystem.c.

+

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, f_mount, f_mkfs and f_fdisk, 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, ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj, need to be added to the project. Sample code is available in ffsystem.c.

FF_FS_TIMEOUT

Number of time ticks to abort the file function with FR_TIMEOUT when wait time is too long. This option has no effect when FF_FS_REENTRANT == 0.

diff --git a/documents/doc/dread.html b/documents/doc/dread.html index 890bcdc..52d60f1 100644 --- a/documents/doc/dread.html +++ b/documents/doc/dread.html @@ -61,7 +61,7 @@ DRESULT disk_read (

Generally, a multiple sector read request must not be split into single sector transactions to the storage device, or read throughput gets worse.

diff --git a/documents/doc/expand.html b/documents/doc/expand.html index 9517609..12e5559 100644 --- a/documents/doc/expand.html +++ b/documents/doc/expand.html @@ -61,7 +61,7 @@ FRESULT f_expand (

When opt 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.

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.

-

Also the contiguous file can be easily accessed directly via low-level disk functions. But this is not recommended in consideration for future compatibility.

+

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 this function to examine if the file is contiguous or not.

diff --git a/documents/doc/filename.html b/documents/doc/filename.html index 51a5848..31e9e3d 100644 --- a/documents/doc/filename.html +++ b/documents/doc/filename.html @@ -35,21 +35,21 @@ dir1/..Invalid nameThe current directory /..Invalid nameThe root directory (sticks the top level) -

Also the drive prefix can be in pre-defined arbitrary string. When the option FF_STR_VOLUME_ID == 1, also arbitrary string volume ID can be used as drive prefix. e.g. "flash:file1.txt", "ram:temp.dat" or "usb:". When FF_STR_VOLUME_ID == 2, Unix style drive prefix can be used. e.g. "/flash/file1.txt", "/ram/temp.dat" or "/usb". However, it cannot traverse the drives such as "/flash/../ram/temp.dat". The Unix style drive prefix may lead a confusion in identification between volume ID and file name. For instance, which does "/flash" mean, a file "flash" on the root directory without drive prefix or a drive prefix of "flash"? If the string following a heading slash matches with any volume ID, it is treated as a drive prefix and skipped over.

+

Also the drive prefix can be in pre-defined arbitrary string. When the option FF_STR_VOLUME_ID == 1, also arbitrary string volume ID can be used as drive prefix. e.g. "flash:file1.txt", "ram:temp.dat" or "sd:". When FF_STR_VOLUME_ID == 2, Unix style drive prefix can be used. e.g. "/flash/file1.txt", "/ram/temp.dat" or "/usb". However, it cannot traverse the drives such as "/flash/../ram/temp.dat". The Unix style drive prefix may lead a confusion in identification between volume ID and file name. For instance, which does "/flash" mean, a file "flash" on the root directory without drive prefix or a drive prefix of "flash"? If the string following a heading slash matches with any volume ID, it is treated as a drive prefix.

Remark: In this revision, double dot name ".." cannot follow the parent directory on the exFAT volume. It will work as "." and stay there.

Legal Characters and Case Sensitivity

-

On the FAT filesystem, legal characters for object name (file/directory name) are, 0-9 A-Z ! # $ % & ' ( ) - @ ^ _ ` { } ~ and extended characters (\x80-\xFF). Under LFN supported system, also + , ; = [ ] 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.

+

On the FAT filesystem, legal characters for object name (file/directory name) are, 0-9 A-Z ! # $ % & ' ( ) - @ ^ _ ` { } ~ and any extended character. The valid character codes of extended characters are depends on the configured code page. Under LFN supported system, also + , ; = [ ] 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.

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, file.txt, File.Txt and FILE.TXT, 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.

-

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.

+

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).

Unicode API

-

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 TCHAR. It is an alias of char by default and the code set used for the path name string is ANSI/OEM specifid by FF_CODE_PAGE. When FF_LFN_UNICODE is set to 1, the type of the TCHAR is switched to WCHAR 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, _T(s) and _TEXT(s) macro are available to select either ANSI/OEM or Unicode automatically. The code shown below is an example to define the literal strings.

+

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 TCHAR. It is an alias of char by default and the code set used for the path name string is ANSI/OEM specifid by FF_CODE_PAGE. When FF_LFN_UNICODE is set to 1 or larger, the type of the TCHAR 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, _T(s) and _TEXT(s) macro are available to select either ANSI/OEM or Unicode automatically. The code shown below is an example to define the literal strings.

  f_open(fp, "filename.txt", FA_READ);      /* ANSI/OEM string (char) */
  f_open(fp, L"filename.txt", FA_READ);     /* UTF-16 string (WCHAR) */
diff --git a/documents/doc/getcwd.html b/documents/doc/getcwd.html
index a2628fb..ac9a6d6 100644
--- a/documents/doc/getcwd.html
+++ b/documents/doc/getcwd.html
@@ -50,7 +50,7 @@ FRESULT f_getcwd (
 
 

Description

-

The f_getcwd function retrieves full path name of the current directory of the current drive. When FF_VOLUMES >= 2, a heading drive prefix is added to the path name. The style of drive prefix is depends on FF_STR_VOLUME_ID.

+

The f_getcwd function retrieves full path name of the current directory of the current drive. When FF_VOLUMES >= 2, a heading drive prefix is added to the path name. The style of drive prefix depends on FF_STR_VOLUME_ID.

Note: In this revision, this function cannot retrieve the current directory path on the exFAT volume. It always returns the root directory path.

diff --git a/documents/doc/open.html b/documents/doc/open.html index c5dd7c5..c039826 100644 --- a/documents/doc/open.html +++ b/documents/doc/open.html @@ -118,7 +118,7 @@ int main (void) fr = f_open(&fil, "message.txt", FA_READ); if (fr) return (int)fr; - /* Read all lines and display it */ + /* Read every line and display it */ while (f_gets(line, sizeof line, &fil)) { printf(line); } @@ -134,7 +134,7 @@ int main (void) int main (void) { - FATFS fs[2]; /* Work area (filesystem object) for logical drives */ + FATFS fs0, fs1; /* Work area (filesystem object) for logical drives */ FIL fsrc, fdst; /* File objects */ BYTE buffer[4096]; /* File copy buffer */ FRESULT fr; /* FatFs function common result code */ @@ -142,8 +142,8 @@ int main (void) /* Register work area for each logical drive */ - f_mount(&fs[0], "0:", 0); - f_mount(&fs[1], "1:", 0); + f_mount(&fs0, "0:", 0); + f_mount(&fs1, "1:", 0); /* Open source file on the drive 1 */ fr = f_open(&fsrc, "1:file.bin", FA_READ); @@ -166,8 +166,8 @@ int main (void) f_close(&fdst); /* Unregister work area prior to discard it */ - f_mount(NULL, "0:", 0); - f_mount(NULL, "1:", 0); + f_mount(0, "0:", 0); + f_mount(0, "1:", 0); return (int)fr; } diff --git a/documents/doc/rc.html b/documents/doc/rc.html index 4b2ce43..114317b 100644 --- a/documents/doc/rc.html +++ b/documents/doc/rc.html @@ -38,15 +38,15 @@ Note that if once this error occured at any operation to an open file, the file
  • No medium in the drive.
  • Wrong lower layer implementation.
  • Wrong hardware configuration.
  • -
  • The storage device has been broken.
  • +
  • The storage device has broken.
  • FR_NO_FILE
    -
    Could not find the file.
    +
    Could not find the file in the directory.
    FR_NO_PATH
    -
    Could not find the path.
    +
    Could not find the path, some directory in the path name could not be found.
    FR_INVALID_NAME
    The given string is invalid as the path name. 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
    FR_EXIST
    -
    Name collision. An object with the same name is already existing.
    +
    Name collision, an object with the same name is already existing.
    FR_INVALID_OBJECT
    The file/directory object is invalid or a null pointer is given. There are some reasons as follows:
      -
    • It has been closed, or collapsed.
    • +
    • It has been closed, or the structure has been collapsed.
    • It has been invalidated. Open objects on the volume are invalidated by voulme mount process.
    • Physical drive is not ready to work due to a media removal.
    diff --git a/documents/doc/readdir.html b/documents/doc/readdir.html index 495703b..2d0ad6e 100644 --- a/documents/doc/readdir.html +++ b/documents/doc/readdir.html @@ -48,13 +48,13 @@ FRESULT f_readdir (

    Description

    -

    The f_readdir function reads a directory item, informations about the object. All items in the directory can be read in sequence by f_readdir function calls. Dot entries ("." and "..") 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 fno->fname[] without any error. When a null pointer is given to the fno, the read index of the directory object is rewinded.

    +

    The f_readdir function reads a directory item, informations about the object. Every item in the directory can be read in sequence by f_readdir function calls. Dot entries ("." and "..") 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 fno->fname[] without any error. When a null pointer is given to the fno, the read index of the directory object is rewinded.

    When support of long file name (LFN) is enabled, a member altname[] 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 fname[] and altname[] has a null string.

    • The item has no LFN. (Not the case at exFAT volume)
    • Setting of FF_MAX_LFN is insufficient to handle the LFN. (Not the case at FF_MAX_LFN == 255)
    • Setting of FF_LFN_BUF is insufficient to store the LFN.
    • -
    • The LFN contains any character not defined in current code page. (Not the case at FF_LFN_UNICODE >= 1)
    • +
    • The LFN contains some character not defined in current code page. (Not the case at FF_LFN_UNICODE >= 1)

    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 fname[] to indicate that the object is not accessible. To avoid this problem, configure FatFs FF_LFN_UNICODE >= 1 and FF_MAX_LFN == 255 to support the full feature of LFN specification.

    diff --git a/documents/doc/setlabel.html b/documents/doc/setlabel.html index 2ec5d42..61592e3 100644 --- a/documents/doc/setlabel.html +++ b/documents/doc/setlabel.html @@ -53,9 +53,9 @@ FRESULT f_setlabel (
    • Up to 11 bytes long as conversion of OEM code page at FAT volume.
    • Up to 11 characters long at exFAT volume.
    • -
    • Allowable characters for FAT volume are: ! # $ % & ' ( ) - ^ _ ` ~ { } 0-9 A-Z a-z and extended characters. Low-case characters are up converted.
    • -
    • Allowable characters for exFAT volume are: characters allowed for FAT volume and " + , . ; = [ ]. Low-case characters are preserved.
    • -
    • Spaces can be contained anywhere in the volume label. Trailing spaces are truncated off at FAT volume.
    • +
    • Allowable characters for FAT volume are: characters allowed for SFN excludes dot. Low-case characters are up converted.
    • +
    • Allowable characters for exFAT volume are: characters allowed for LFN includes dot. Low-case characters are preserved.
    • +
    • Spaces can be embedded anywhere in the volume label. Trailing spaces are truncated off at FAT volume.

    Remark: The standard system (Windows) has a problem at the volume label with a heading \xE5 on the FAT volume. To avoid this problem, this function rejects such volume label as invalid name.

    diff --git a/documents/doc/sync.html b/documents/doc/sync.html index df35312..39cac91 100644 --- a/documents/doc/sync.html +++ b/documents/doc/sync.html @@ -44,7 +44,30 @@ FRESULT f_sync (

    Description

    -

    The f_sync function performs the same process as f_close 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 f_sync function of periodic or immediataly after f_write function can minimize the risk of data loss due to a sudden blackout or an unintentional media removal. For more information, refer to application note.

    +

    The f_sync function performs the same process as f_close 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 f_sync 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 application note.

    +
    +Case 1. Normal write sequence
    +
    +                                Time -->                                     ↓Power off after close
    +OwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwC
    +
    +
    +Case 2. Without using f_sync()
    +
    +                                Time -->                             ↓System crush
    +Owwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
    + |<--------------- All data written will be lost ------------------>|
    +
    +
    +Case 3. Using f_sync()
    +                                Time -->                             ↓System crush
    +OwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwww
    +                            Data after last f_sync will be lost |<->| 
    +O - f_open()
    +C - f_close()
    +w - f_write()
    +S - f_sync()
    +

    However there is no sense in f_sync function immediataly before f_close function because it performs f_sync function in it. In other words, the differnce between those functions is that the file object is invalidated or not.

    diff --git a/documents/doc/unlink.html b/documents/doc/unlink.html index edd6371..08e478e 100644 --- a/documents/doc/unlink.html +++ b/documents/doc/unlink.html @@ -13,7 +13,7 @@

    f_unlink

    -

    The f_unlink function removes a file or sub-directory.

    +

    The f_unlink function removes a file or sub-directory from the volume.

     FRESULT f_unlink (
       const TCHAR* path  /* [IN] Object name */
    diff --git a/documents/res/app2.c b/documents/res/app2.c
    index 49d322d..3d14709 100644
    --- a/documents/res/app2.c
    +++ b/documents/res/app2.c
    @@ -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;
         }
     }
    diff --git a/documents/res/app5.c b/documents/res/app5.c
    new file mode 100644
    index 0000000..6a0819d
    --- /dev/null
    +++ b/documents/res/app5.c
    @@ -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;
    +}
    diff --git a/documents/res/f4.png b/documents/res/f4.png
    index f9a6b46..2c00ddc 100644
    Binary files a/documents/res/f4.png and b/documents/res/f4.png differ
    diff --git a/documents/res/f5.png b/documents/res/f5.png
    index b110b29..bc0171a 100644
    Binary files a/documents/res/f5.png and b/documents/res/f5.png differ
    diff --git a/documents/res/mkfatimg.zip b/documents/res/mkfatimg.zip
    index 67d423b..63e6ad7 100644
    Binary files a/documents/res/mkfatimg.zip and b/documents/res/mkfatimg.zip differ
    diff --git a/documents/res/modules.png b/documents/res/modules.png
    index b1ab987..885a15a 100644
    Binary files a/documents/res/modules.png and b/documents/res/modules.png differ
    diff --git a/documents/updates.txt b/documents/updates.txt
    index 3b7d126..42405b9 100644
    --- a/documents/updates.txt
    +++ b/documents/updates.txt
    @@ -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)
     
    diff --git a/source/00history.txt b/source/00history.txt
    index 9b67d02..db12a9e 100644
    --- a/source/00history.txt
    +++ b/source/00history.txt
    @@ -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)
    +
    diff --git a/source/00readme.txt b/source/00readme.txt
    index 15426d2..dcccbdb 100644
    --- a/source/00readme.txt
    +++ b/source/00readme.txt
    @@ -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.
     
    diff --git a/source/diskio.c b/source/diskio.c
    index f611063..08ffcc8 100644
    --- a/source/diskio.c
    +++ b/source/diskio.c
    @@ -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
     
     
     /*-----------------------------------------------------------------------*/
    diff --git a/source/diskio.h b/source/diskio.h
    index 1fa4400..31776b8 100644
    --- a/source/diskio.h
    +++ b/source/diskio.h
    @@ -9,9 +9,6 @@
     extern "C" {
     #endif
     
    -#include "integer.h"
    -
    -
     /* Status of Disk Functions */
     typedef BYTE	DSTATUS;
     
    diff --git a/source/ff.c b/source/ff.c
    index 35c9755..290f577 100644
    --- a/source/ff.c
    +++ b/source/ff.c
    @@ -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
     )
    diff --git a/source/ff.h b/source/ff.h
    index cd90d6d..a0792b2 100644
    --- a/source/ff.h
    +++ b/source/ff.h
    @@ -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 
    +typedef unsigned __int64 QWORD;
    +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus)	/* C99 or later */
    +#define FF_INTDEF 2
    +#include 
    +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
    diff --git a/source/ffconf.h b/source/ffconf.h
    index fe5aacd..5bd2f21 100644
    --- a/source/ffconf.h
    +++ b/source/ffconf.h
    @@ -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 	// 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 	// O/S definitions  */
    -
     
     
     /*--- End of configuration options ---*/
    diff --git a/source/ffsystem.c b/source/ffsystem.c
    index 9df330f..b88ce15 100644
    --- a/source/ffsystem.c
    +++ b/source/ffsystem.c
    @@ -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);
     }
     
    diff --git a/source/ffunicode.c b/source/ffunicode.c
    index 9a5d37e..349901b 100644
    --- a/source/ffunicode.c
    +++ b/source/ffunicode.c
    @@ -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
     
    diff --git a/source/integer.h b/source/integer.h
    deleted file mode 100644
    index b3c70ca..0000000
    --- a/source/integer.h
    +++ /dev/null
    @@ -1,36 +0,0 @@
    -/*-------------------------------------------*/
    -/* Integer type definitions for FatFs module */
    -/*-------------------------------------------*/
    -
    -#ifndef FF_INTEGER
    -#define FF_INTEGER
    -
    -#ifdef _WIN32	/* FatFs development platform */
    -
    -#include 
    -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