From 87c49071726570e97812128ef33669195203f4f5 Mon Sep 17 00:00:00 2001 From: savelij13 Date: Thu, 11 Sep 2025 10:44:45 +0300 Subject: [PATCH] fatfs v0.14b April 17, 2021: - Made FatFs uses standard library for copy, compare and search instead of built-in string functions. - Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP) - Made path name parser ignore the terminating separator to allow "dir/". - Improved the compatibility in Unix style path name feature. - Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a) - Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12) - Fixed code page 855 cannot be set by f_setcp(). - Fixed some compiler warnings. --- documents/00index_e.html | 18 +- documents/doc/appnote.html | 48 +- documents/doc/chdir.html | 2 +- documents/doc/chdrive.html | 4 +- documents/doc/config.html | 65 +- documents/doc/dioctl.html | 6 +- documents/doc/dread.html | 4 +- documents/doc/dwrite.html | 2 +- documents/doc/expand.html | 2 +- documents/doc/filename.html | 42 +- documents/doc/findfirst.html | 14 +- documents/doc/gets.html | 2 +- documents/doc/lseek.html | 12 +- documents/doc/mkfs.html | 12 +- documents/doc/mount.html | 2 +- documents/doc/open.html | 6 +- documents/doc/printf.html | 61 +- documents/doc/rc.html | 28 +- documents/doc/readdir.html | 4 +- documents/updates.txt | 13 +- source/00history.txt | 13 + source/00readme.txt | 2 +- source/ff.c | 1084 +++++++++++++++++++--------------- source/ff.h | 72 +-- source/ffconf.h | 49 +- 25 files changed, 866 insertions(+), 701 deletions(-) diff --git a/documents/00index_e.html b/documents/00index_e.html index e1df788..22779c0 100644 --- a/documents/00index_e.html +++ b/documents/00index_e.html @@ -5,8 +5,6 @@ - - FatFs - Generic FAT Filesystem Module @@ -27,12 +25,12 @@
  • Various configuration options to support for:
    • Long file name in ANSI/OEM or Unicode.
    • -
    • exFAT filesystem, 64-bit LBA and GPT for huge storeges.
    • +
    • exFAT filesystem, 64-bit LBA and GPT for huge storages.
    • Thread safe for RTOS.
    • -
    • Multiple volumes (physical drives and partitions).
    • +
    • Multiple volumes. (physical drives and partitions)
    • Variable sector size.
    • Multiple code pages including DBCS.
    • -
    • Read-only, optional API, I/O buffer and etc...
    • +
    • Read-only, optional APIs, I/O buffer and etc...
  • @@ -105,7 +103,7 @@

    Media Access Interface

    layer -

    Since FatFs module is the filesystem layer independent of platforms and storage media, it is completely separated from the physical devices, such as memory card, harddisk and any type of storage device. The storage device control module is not any part of FatFs module and it needs to be provided by implementer. FatFs controls the storage devices via a simple media access interface shown below. Also sample implementations for some platforms are available in the downloads. A function checker for storage device control module is available here.

    +

    Since FatFs module is the Filesystem Layer independent of platforms and storage media, it is completely separated from the physical devices, such as memory card, harddisk and any type of storage device. The storage device control module is not any part of FatFs module and it needs to be provided by implementer. FatFs controls the storage devices via a simple media access interface shown below. Also sample implementations for some platforms are available in the downloads. A function checker for storage device control module is available here.

    - diff --git a/documents/doc/appnote.html b/documents/doc/appnote.html index f8ccbbf..a455e37 100644 --- a/documents/doc/appnote.html +++ b/documents/doc/appnote.html @@ -67,16 +67,16 @@ The FatFs module is a middleware written in ANSI C (C89). There is no platform d

    functional diagram

    Required Functions

    -

    You need to provide only MAI functions required by FatFs module and nothing else. If any working device control module for the target system is available, you need to write only glue functions to attach it to the FatFs module. If not, you need to port another device control module or write it from scratch. Most of MAI functions are not that always required. For instance, any write function is not required in read-only configuration. Following table shows which function is required depends on the configuration options.

    +

    You need to provide only MAI functions required by FatFs module and nothing else. If a working device control module for the target system is available, you need to write only glue functions to attach it to the FatFs module. If not, you need to port another device control module or write it from scratch. Most of MAI functions are not that always required. For instance, the write function is not required in read-only configuration. Following table shows which function is required depends on the configuration options.

    - + - - - - - - + + + + + +
    FunctionRequired whenNote
    FunctionRequired when:Note
    disk_status
    disk_initialize
    disk_read
    AlwaysDisk I/O functions.
    Samples available in ffsample.zip.
    There are many implementations on the web.
    disk_write
    get_fattime
    disk_ioctl (CTRL_SYNC)
    FF_FS_READONLY == 0
    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.
    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.
    disk_write
    get_fattime
    disk_ioctl (CTRL_SYNC)
    FF_FS_READONLY == 0
    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.
    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.

    @@ -103,17 +103,17 @@ The FatFs module is a middleware written in ANSI C (C89). There is no platform d ARM7
    32bit
    ARM7
    Thumb
    CM3
    Thumb-2
    AVRH8/300HPIC24RL78V850ESSH-2ARX600IA-32 CompilerGCCGCCGCCGCCCH38C30CC78K0RCA850SHCRXCMSC -text (Full, R/W)10.6k6.8k6.4k12.4k10.1k11.4k13.1k8.9k9.1k6.5k9.0k -text (Min, R/W) 7.2k4.8k4.6k 8.5k 7.1k 8.0k 9.6k6.3k6.3k4.7k6.4k -text (Full, R/O) 5.0k3.2k2.9k 6.0k 4.8k 5.5k 6.6k4.4k4.1k3.2k4.3k -text (Min, R/O) 3.8k2.5k2.3k 4.4k 3.8k 4.2k 5.2k3.4k3.3k2.5k3.5k -bssV*4 + 2V*4 + 2V*4 + 2V*2 + 2V*4 + 2V*2 + 2V*2 + 2V*4 + 2V*4 + 2V*4 + 2V*4 + 2 +.text (Full, R/W)10.4k6.7k6.1k12.5k11.0k11.6k13.0k8.9k9.2k6.5k8.9k +.text (Min, R/W) 7.0k4.7k4.2k 8.5k 7.6k 8.1k 9.5k6.2k6.4k4.6k6.4k +.text (Full, R/O) 4.9k3.2k2.7k 6.1k 5.2k 5.5k 6.5k4.3k4.2k3.2k4.3k +.text (Min, R/O) 3.7k2.5k2.1k 4.4k 4.0k 4.3k 5.1k3.4k3.3k2.5k3.5k +.bssV*4 + 2V*4 + 2V*4 + 2V*2 + 2V*4 + 2V*2 + 2V*2 + 2V*4 + 2V*4 + 2V*4 + 2V*4 + 2 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 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.14a options:
    +FatFs R0.14b 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)
    @@ -123,9 +123,9 @@ And any other options are left unchanged from original setting.
     
     

    Reducing Module Size

    -

    Follwing table shows which API function is removed by configuration options for the module size reduction. To use any API function, the row of the function must be clear.

    +

    Follwing table shows which API function is removed by configuration options to reduce the module size. To use an API function, the row of the function must be clear.

    - + @@ -166,7 +166,7 @@ And any other options are left unchanged from original setting.

    Long File Name

    -

    FatFs module supports the long file name (LFN) extension of the FAT filesystem. The two different file names, short file name (SFN) and LFN, of a file is transparent on the API. The support for LFN feature 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 feature requiers a certain working buffer. The buffer size can be configured by FF_MAX_LFN according to the available memory. The length of an LFN can be up to 255 characters, so that the FF_MAX_LFN should be set to 255 for all existing 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 feature, 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 LFN working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.

    +

    FatFs module supports the long file name (LFN) extension of the FAT filesystem. The two different file names, short file name (SFN) and LFN, of a file is transparent on the API. The support for LFN feature 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 feature requiers a certain working buffer. The buffer size can be configured by FF_MAX_LFN according to the available memory. The length of LFN can be up to 255 characters, so that the FF_MAX_LFN should be set to 255 for any existing 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 feature in RTOS environment, 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 LFN working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.

    Impact upon Module Size

    FunctionFF_FS_
    MINIMIZE
    FF_FS_
    READONLY
    FF_USE_
    STRFUNC
    FF_FS_
    RPATH
    FF_USE_
    FIND
    FF_USE_
    CHMOD
    FF_USE_
    EXPAND
    FF_USE_
    LABEL
    FF_USE_
    MKFS
    FF_USE_
    FORWARD
    FF_MULTI_
    PARTITION
    FunctionFF_FS_
    MINIMIZE
    FF_FS_
    READONLY
    FF_USE_
    STRFUNC
    FF_FS_
    RPATH
    FF_USE_
    FIND
    FF_USE_
    CHMOD
    FF_USE_
    EXPAND
    FF_USE_
    LABEL
    FF_USE_
    MKFS
    FF_USE_
    FORWARD
    FF_MULTI_
    PARTITION
    0123010101201010101010101
    f_mount
    @@ -179,14 +179,14 @@ And any other options are left unchanged from original setting.
    With LFN at CM3 + gcc
    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 the increment of code size in some 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 enabled 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.

    +

    As the result, the FatFs with LFN enabled 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 API with any SBCS code page.

    There ware some restrictions on using LFN for open source project, because the LFN extension on the FAT filesystem was a patent of Microsoft Corporation. However the related patents all have expired and using the LFN feature is free for any projects.

    Unicode API

    By default, FatFs uses ANSI/OEM code set on the API even in 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.

    +

    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 to reduce the module size. However it still affects code conversion of string I/O functions when FF_STRF_ENCODE == 0, and also backward compatibility with legacy systems. In this case, the code page may need to be configured properly if it is considered a problem.

    @@ -198,8 +198,8 @@ And any other options are left unchanged from original setting.

    64-bit LBA

    -

    LBA (Logical Block Addressing) is an addressing method to specify the location of data block, called sector, on the storage media. It is a simple linear address beginning from 0 as the first block of data. The host system does not need to consider how the data block is located and managed in the storage device. FatFs supports only LBA for the media access. 32-bit LBA is a common size at the interface of the most storage devices. It can address up to 232 blocks, 2 TB in 512 bytes/sector. When a storage device larger than 2 TB is used, larger sector size or 64-bit LBA will be needed to address the entire block of the storage device.

    -

    By default, FatFs works in 32-bit LBA for media access interface. FatFs can also switch it to 64-bit LBA by a configuration option FF_LBA64. It also enables GPT (GUID Partition Table) for partiotion management on the storage device. For further information about GPT, refer to f_mkfs and f_fdisk function.

    +

    LBA (Logical Block Addressing) is an addressing method to specify the location of data block, called sector, on the storage media. It is a simple linear address beginning from 0 as the first sector, 1 as the second sector and so on. The host system does not need to consider how the data block is located and managed in the storage device. FatFs supports only LBA for the media access. 32-bit LBA is a common size in the most LBA scheme. It can address up to 232 sectors, 2 TB in 512 bytes/sector. When a storage device larger than 2 TB is used, larger sector size or 64-bit LBA will be needed to address the entire sectors of the storage device.

    +

    By default, FatFs works in 32-bit LBA for media access. FatFs can also switch it to 64-bit LBA by a configuration option FF_LBA64. It also enables GPT (GUID Partition Table) for partiotion management on the storage device. For further information about GPT, refer to f_mkfs and f_fdisk function.

    @@ -291,9 +291,9 @@ Figure 5. Minimized critical section

    Various Usable Functions for FatFs Projects

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

      -
    1. Open or Create File for Append (superseded by FA_APPEND flag added in R0.12)
    2. +
    3. Open or Create File for Append (superseded by FA_OPEN_APPEND flag added at R0.12)
    4. Delete Non-empty Sub-directory (for R0.12 and later)
    5. -
    6. Create Contiguous File (superseded by f_expand function added in R0.12)
    7. +
    8. Create Contiguous File (superseded by f_expand function added at R0.12)
    9. Test if the File is Contiguous or Not
    10. Compatibility Checker for Storage Device Control Module
    11. Performance Checker for Storage Device Control Module
    12. @@ -326,7 +326,7 @@ Figure 5. Minimized critical section
      / by use of this software. /----------------------------------------------------------------------------*/
    -

    Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, does not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses including GNU GPL. When you redistribute the FatFs source code with any changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that compatible with FatFs license.

    +

    Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, does not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses includs GNU GPL. When you redistribute the FatFs source code with any changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that compatible with FatFs license.

    Return Home

    diff --git a/documents/doc/chdir.html b/documents/doc/chdir.html index 6442c3b..338406e 100644 --- a/documents/doc/chdir.html +++ b/documents/doc/chdir.html @@ -50,7 +50,7 @@ FRESULT f_chdir (

    Description

    -

    The f_chdir function changes the current directory of the logical drive. Also the current drive will be changed when Unix style volume ID, FF_STR_VOLUME_ID == 2, is selected. The current directory of each logical drive is initialized to the root directory on mount.

    +

    The f_chdir function changes the current directory of the logical drive. Also the current drive will be changed when in Unix style drive prefix, FF_STR_VOLUME_ID == 2. The current directory of each logical drive is initialized to the root directory on mount.

    Note that the current directory is retained in the each file system object and the current drive is retained in a static variable, so that it also affects other tasks that use the file functions.

    diff --git a/documents/doc/chdrive.html b/documents/doc/chdrive.html index e54ae63..e8412b1 100644 --- a/documents/doc/chdrive.html +++ b/documents/doc/chdrive.html @@ -41,7 +41,7 @@ FRESULT f_chdrive (

    Description

    -

    The f_chdrive function changes only the current drive. The initial value of the current drive number is 0. Note that the current drive is retained in a static variable, so that it also affects other tasks that using the file functions.

    +

    The f_chdrive function changes only the current drive. The initial value of the current drive number is 0. In Unix style drive prefix configuration, this function will not be needed because f_chdir function changes also the current drive. Note that the current drive is retained in a static variable, so that it also affects other tasks that using the file functions.

    @@ -56,8 +56,6 @@ FRESULT f_chdrive ( f_chdrive("2:"); /* Set drive 2 as current drive */ f_chdrive(""); /* No effect (set current drive as current drive) */ - - f_chdrive("/flash"); /* Set drive "flash" as current drive (at Unix style volume ID) */
    diff --git a/documents/doc/config.html b/documents/doc/config.html index 502bd33..60f76e0 100644 --- a/documents/doc/config.html +++ b/documents/doc/config.html @@ -17,7 +17,6 @@
  • Namespace and Locale Configurations @@ -34,7 +37,6 @@
  • FF_MAX_LFN
  • FF_LFN_UNICODE
  • FF_LFN_BUF, FF_SFN_BUF
  • -
  • FF_STRF_ENCODE
  • FF_FS_RPATH
  • @@ -81,15 +83,6 @@ 3f_lseek function is removed in addition to 2. -

    FF_USE_STRFUNC

    -

    This option switches string functions, f_gets, f_putc, f_puts and f_printf.

    - - - - - -
    ValueDescription
    0Disable string functions.
    1Enable string functions without LF-CRLF conversion.
    2Enable string functions with LF-CRLF conversion.
    -

    FF_USE_FIND

    Disable (0) or Enable (1) filtered directory read functions, f_findfirst and f_findnext. Also FF_FS_MINIMIZE needs to be 0 or 1.

    @@ -111,6 +104,38 @@

    FF_USE_FORWARD

    Disable (0) or Enable (1) f_forward function.

    +

    FF_USE_STRFUNC

    +

    This option switches string functions, f_gets, f_putc, f_puts and f_printf. These functions are equivalents of regular string stream I/O functions in POSIX. If sprintf is available and code conversion is not needed, f_write with sprintf will be efficient in code size and performance rather than f_printf.

    + + + + + +
    ValueDescription
    0Disable string functions.
    1Enable string functions without LF-CRLF conversion.
    2Enable string functions with LF-CRLF conversion.
    + + +

    This option switches support for long long integer argument in f_printf.

    +

    Disable (0) or Enable (1). C standard needs to be C99 or later to enable this feature.

    + + +

    This option switches support for floating point argument in f_printf. C standard needs to be C99 or later to enable this feature.

    + + + + + +
    ValueDescription
    0Disable floating point argument.
    1Enable floating point argument in type 'f', 'e' and 'E'.
    2Enable with decimal separator ',' instead of '.'.
    + +

    FF_STRF_ENCODE

    +

    When character encoding on the API is Unicode (FF_LFN_UNICODE >= 1), string I/O functions enabled by FF_USE_STRFUNC 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 code conversion and this option has no effect.

    + + + + + + +
    ValueCharacter encoding on the file
    0ANSI/OEM in current code page
    1Unicode in UTF-16LE
    2Unicode in UTF-16BE
    3Unicode in UTF-8
    + @@ -118,7 +143,7 @@

    Namespace and Locale Configurations

    FF_CODE_PAGE

    -

    This option specifies the OEM code page 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 or character encoding is in Unicode, there is no difference between any code page settings. Set it 437 anyway.

    +

    This option specifies the OEM code page 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 or FF_LFN_UNICODE != 0, there is no difference between any code page settings. Set it 437 anyway.

    @@ -181,16 +206,6 @@
    ValueCode page
    0Includes all code pages below and set by f_setcp()

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

    - - - - - - -
    ValueCharacter encoding on the file
    0ANSI/OEM in current code page
    1Unicode in UTF-16LE
    2Unicode in UTF-16BE
    3Unicode in UTF-8
    -

    FF_FS_RPATH

    This option configures relative path function. For more information, read here.

    @@ -213,7 +228,7 @@

    This option switches the support for string volume ID. When arbitrary string for the volume ID is enabled for the drive prefix, also pre-defined strings by FF_VOLUME_STRS or user defined strings can be used as drive prefix in the path name. Numeric drive number is always valid regardless of this option, and also either format of drive prefix can be enabled by this option.

    - +
    ValueDescriptionExample
    0Only DOS/Windows style drive prefix in numeric ID can be used.0:/filename
    0Only DOS/Windows style drive prefix in numeric ID can be used.1:/filename
    1Also DOS/Windows style drive prefix in string ID can be used.flash:/filename
    2Also Unix style drive prefix in string ID can be used./flash/filename
    @@ -221,8 +236,8 @@

    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. 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"};
    +/* User defined volume ID strings for 0: to 3: */
    +const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb"};
     

    FF_MULTI_PARTITION

    diff --git a/documents/doc/dioctl.html b/documents/doc/dioctl.html index b5a2826..763f7f0 100644 --- a/documents/doc/dioctl.html +++ b/documents/doc/dioctl.html @@ -80,9 +80,9 @@ DRESULT disk_ioctl ( MMC_GET_CIDReads CID register and sets it into a 16-byte buffer pointed by buff. (MMC/SDC specific command) MMC_GET_OCRReads OCR register and sets it into a 4-byte buffer pointed by buff. (MMC/SDC specific command) MMC_GET_SDSTATReads SDSTATUS register and sets it into a 64-byte buffer pointed by buff. (SDC specific command) -ATA_GET_REVGets the revision string and sets it into a 16-byte buffer pointed by buff. (ATA/CFC specific command) -ATA_GET_MODELGets the model string and sets it into a 40-byte buffer pointed by buff. (ATA/CFC specific command) -ATA_GET_SNGets the serial number string and sets it into a 20-byte buffer pointed by buff. (ATA/CFC specific command) +ATA_GET_REVReads the revision string and sets it into a 16-byte buffer pointed by buff. (ATA/CFC specific command) +ATA_GET_MODELReads the model string and sets it into a 40-byte buffer pointed by buff. (ATA/CFC specific command) +ATA_GET_SNReads the serial number string and sets it into a 20-byte buffer pointed by buff. (ATA/CFC specific command) ISDIO_READReads a block of iSDIO registers specified by command structure pointed by buff. (FlashAir specific command) ISDIO_WRITEWrites a block of data to iSDIO registers specified by command structure pointed by buff. (FlashAir specific command) ISDIO_MRITEChanges bits in an iSDIO register specified by command structure pointed by buff. (FlashAir specific command) diff --git a/documents/doc/dread.html b/documents/doc/dread.html index 71821ae..c988fde 100644 --- a/documents/doc/dread.html +++ b/documents/doc/dread.html @@ -32,7 +32,7 @@ DRESULT disk_read (
    buff
    Pointer to the first item of the byte array to store read data. Size of read data will be the sector size * count bytes.
    sector
    -
    Start sector number in 32-bit or 64-bit LBA. The data type LBA_t is an alias of DWORD or QWORD depends on the configuration option.
    +
    Start sector number in LBA. The data type LBA_t is an alias of DWORD or QWORD depends on the configuration option.
    count
    Number of sectors to read.
    @@ -57,7 +57,7 @@ DRESULT disk_read (

    Description

    Read/write operation to the generic storage devices, such as memory card, hadddisk and optical disk, is done in unit of block of data bytes called sector. FatFs supports the sector size in range of 512 to 4096 bytes. When FatFs is configured for fixed sector size (FF_MIN_SS == FF_MAX_SS, this is the most case), the generic read/write function must work at the sector size only. When FatFs is configured for variable sector size (FF_MIN_SS < FF_MAX_SS), the sector size of medium is inquired with disk_ioctl function after disk_initialize function succeeded.

    -

    There are some considerations about the memory addres passed via buff. It is not that always aligned with the word boundary because the argument is defined as BYTE*. The unaligned transfer request can occure at direct transfer. If the bus architecture, especially DMA controller, does not allow unaligned memory access, it should be solved in this function. If it is the case, there are some workarounds described below to avoid this issue.

    +

    There are some considerations about the memory addres passed via buff. It is not that always aligned with the word boundary, because the argument is defined as BYTE*. The unaligned transfer request can occure at direct transfer. If the bus architecture, especially DMA controller, does not allow unaligned memory access, it should be solved in this function. If it is the case, there are some workarounds described below to avoid this issue.

    • Convert word transfer to byte transfer with some trick in this function. - Recommended.
    • On the f_read() calls, avoid long read request that includes a whole of sector. - Any direct transfer never occures.
    • diff --git a/documents/doc/dwrite.html b/documents/doc/dwrite.html index f94ff7b..e677da8 100644 --- a/documents/doc/dwrite.html +++ b/documents/doc/dwrite.html @@ -32,7 +32,7 @@ DRESULT disk_write (
      buff
      Pointer to the first item of the byte array to be written. The size of data to be written is sector size * count bytes.
      sector
      -
      Start sector number in 32-bit or 64-bit LBA. The data type LBA_t is an alias of DWORD or QWORD depends on the configuration option.
      +
      Start sector number in LBA. The data type LBA_t is an alias of DWORD or QWORD depends on the configuration option.
      count
      Number of sectors to write.
      diff --git a/documents/doc/expand.html b/documents/doc/expand.html index 6aec295..c753c2f 100644 --- a/documents/doc/expand.html +++ b/documents/doc/expand.html @@ -52,7 +52,7 @@ FRESULT f_expand (

      Description

      -

      The f_expand function prepares or allocates a contiguous data area to the file. When opt is 1, the data area is allocated to the file in this function. Unlike expansion of file size by f_lseek function, the file must be truncated prior to use this function and read/write pointer of the file stays at offset 0 after the function call. The file content allocated with this function is undefined because no data is written to the file in this process. The function can fail with FR_DENIED due to some reasons below.

      +

      The f_expand function prepares or allocates a contiguous data area to the file. When opt is 1, the data area is allocated to the file in this function. Unlike expansion of file size by f_lseek function, the file must be truncated prior to use this function and read/write pointer of the file stays at offset 0 after the function call. The file content allocated with this function is undefined, because no data is written to the file in this process. The function can fail with FR_DENIED due to some reasons below.

      • No free contiguous space was found.
      • Size of the file was not zero.
      • diff --git a/documents/doc/filename.html b/documents/doc/filename.html index 3a260a9..6c690cb 100644 --- a/documents/doc/filename.html +++ b/documents/doc/filename.html @@ -16,10 +16,10 @@

        Format of the Path Names

        The format of path name on the FatFs module is similer to the filename specs of DOS/Windos as follows:

        [drive#:][/]directory/file
        -

        The FatFs module supports long file name (LFN) and 8.3 format file name (SFN). The LFN can be used when FF_USE_LFN >= 1. The sub-directories are separated with a \ or / as the same way as DOS/Windows API. Duplicated separators are skipped and ignored. Only a difference is that the heading drive prefix to specify the logical drive number is in a numeral (0-9) + a colon, while it is an alphabet (A-Z) + a colon in DOS/Windows. The logical drive number is identifier to specify the FAT volume to be accessed. When drive prefix is omitted, the logical drive number is assumed as default drive.

        -

        Control characters (\0 to \x1F) are recognized as end of the path name. Leading/embedded white spaces in the path name are valid as a part of the name in LFN configuration but the white space is recognized as end of the path name in non-LFN configuration. Trailing white spaces and dots are ignored in both configurations.

        -

        In default configuration (FF_FS_RPATH == 0), it does not have a concept of current directory like OS oriented filesystem. Every object on the volume is always specified in full path name that followed from the root directory. Dot directory names (".", "..") are not allowed. Heading separator is ignored and it can be exist or omitted. The default drive is fixed to drive 0.

        -

        When relative path is enabled (FF_FS_RPATH >= 1), specified path is followed from the root directory if a heading separator is exist. If not, it is followed from the current directory of the drive set by f_chdir function. Dot names are also allowed for the path names. The default drive is the current drive set by f_chdrive function.

        +

        The FatFs module supports long file name (LFN) and 8.3 format file name (SFN). The LFN can be used when FF_USE_LFN >= 1. The sub-directories are separated with a \ or / as the same way as DOS/Windows API. Duplicated separator and terminating separator, such as "//animal///cat/", are ignored. Only a difference is that the heading drive prefix to specify the logical drive is in a digit (0-9) + a colon, while it is in an alphabet (A-Z) + a colon in DOS/Windows. The logical drive number is the identifier to specify the FAT volume to be accessed. When drive prefix is omitted, the logical drive number is assumed as default drive.

        +

        Control characters (\0 to \x1F) are recognized as end of the path name. Leading/embedded white spaces in the path name are valid as a part of the name in LFN configuration, but the white space is recognized as end of the path name in non-LFN configuration.

        +

        In default configuration (FF_FS_RPATH == 0), it does not have a concept of current directory like OS oriented filesystem. Every object on the volume is always specified in full path name followed from the root directory. Dot directory names (".", "..") are not allowed. Heading separator is ignored and it can be exist or omitted. The default drive is fixed to drive 0.

        +

        When relative path feature is enabled (FF_FS_RPATH >= 1), specified path is followed from the root directory if a heading separator is exist. If not, it is followed from the current directory of the default drive. Dot directory name is also allowed for the path name. The current directory is set by f_chdir function and the default drive is the current drive set by f_chdrive function.

        @@ -35,21 +35,21 @@
        Path nameFF_FS_RPATH == 0FF_FS_RPATH >= 1
        file.txtA file in the root directory of the drive 0A file in the current directory of the current drive
        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 "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.

        - +

        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:". If the srting does not match any volume ID, the function fails with FR_INVALID_DRIVE.

        +

        When FF_STR_VOLUME_ID == 2, Unix style drive prefix can be used. e.g. "/flash/file1.txt", "/ram/temp.dat" or "/sd". If a heading separator is exist, it is treated as start of drive prefix and in absolute path. Any form as "root directory in current drive" and "current directory in specified drive" cannot be used. Double dot entry cannot traverse the drives such as "/flash/../ram/foo.dat".

        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 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 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 (DOS/DBCS), extended characters ware 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 in only non-LFN with DBCS configuration (DOS/DBCS specs). But in LFN configuration, FatFs works with case-insensitive to the extended character (WindowsNT specs).

      +

      In the generic FAT filesystems, the legal characters for object name (file/directory name) are, 0-9 A-Z ! # $ % & ' ( ) - @ ^ _ ` { } ~ in ASCII and extended characters \x80 to \xFF. In the FAT filesystems with LFN extention, also + , ; = [ ], white space and extended characters U+000080 to U+10FFFF are legal for the object name. White spaces and dots can be placed anywhere in the path name except end of the name. Trailing white spaces and dots are ignored.

      +

      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 on the FAT filesystem. 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 extension is exist.

      +

      As for the MS-DOS and PC DOS for CJK (DOS/DBCS), extended characters ware recorded to the SFN entry without up-case conversion and compared in case-sensitive. This causes a problem on compatibility with Windows system when the 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 in only non-LFN with DBCS configuration (DOS/DBCS specs). But in 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 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 specify the string in proper type. 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 ✝☪✡☸☭ and any character not in BMP, 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 specify the string in proper type. 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) */
      @@ -61,27 +61,27 @@
       
       

      Volume Management

      -

      By default, each logical drive is associated with the physical drive in same drive number. An FAT volume on the physical drive is serched by the volume mount process. It reads boot sectors and checks it if it is an FAT boot sector in order of LBA 0 as SFD format, 1st partition, 2nd partition, 3rd partition, ..., as MBR or GPT format.

      -

      When multiple partition feature is enabled, FF_MULTI_PARTITION = 1, each individual logical drive is associated with arbitrary partition or drive specified by volume management table, VolToPart[]. The table needs to be defined by user to resolve the mappings of logical drives and partitions. Following code is an example of a volume management table.

      +

      By default, each logical drive is associated with the physical drive in same drive number. An FAT volume on the physical drive is serched in the volume mount process. It reads boot sectors and checks it if it is an FAT boot sector in order of LBA 0 as SFD format, 1st partition, 2nd partition, 3rd partition, ..., as MBR or GPT format.

      +

      When multiple partition feature is enabled, FF_MULTI_PARTITION = 1, each individual logical drive is associated with arbitrary partition or physical drive specified by volume management table, VolToPart[]. The table needs to be defined by user to resolve mappings of the logical drive numbers and the target partitions. Following code is an example of a volume management table.

       Example: "0:", "1:" and "2:" are associated with three partitions on the physical drive 0 (fixed drive)
                "3:" is associated with physical drive 1 (removable drive)
       
       PARTITION VolToPart[FF_VOLUMES] = {
      -    {0, 1},     /* "0:" ==> 1st partition on physical drive 0 */
      -    {0, 2},     /* "1:" ==> 2nd partition on physical drive 0 */
      -    {0, 3},     /* "2:" ==> 3rd partition on physical drive 0 */
      -    {1, 0}      /* "3:" ==> Physical drive 1 */
      +    {0, 1},     /* "0:" ==> 1st partition on the pd#0 */
      +    {0, 2},     /* "1:" ==> 2nd partition on the pd#0 */
      +    {0, 3},     /* "2:" ==> 3rd partition on the pd#0 */
      +    {1, 0}      /* "3:" ==> A valie FAT volume on the pd#1 (.pt = 0 specifies auto-search) */
       };
       
      relationship between logical drive and physical drive
      -

      There are some considerations on using multi-partition configuration.

      +

      There are some considerations when enable the multi-partition configuration.

        -
      • The physical drive that hosts two or more mounted partitions must be non-removable, or all volumes on the drive must be unmounted when remove the medium.
      • +
      • The physical drive that hosts two or more mounted partitions should be non-removable, or all volumes on the drive must be unmounted when remove the medium.
      • When make any change to the VolToPart[], corresponding volume should be unmounted prior to make change the item.
      • -
      • On the MBR format drive, up to four primary partitions (1-4) can be specified. The partition 1 specifies the first item in the partition table and the partition 2 specifies the second one, and so on. Logical patitions in the extended partition is not supported.
      • -
      • On the GPT format drive, there is no limitation. The partition 1 specifies the first Microsoft basic data partition found in the partition table and the partition 2 specifies the second one found, and so on.
      • -
      • Windows does not support multiple volumes on the storage with removable class. Only the first parition found on the drive will be mounted.
      • +
      • On the MBR format drive, up to four primary partitions (1-4) can be specified. The partition number 1 specifies the first item in the partition table and the partition number 2 specifies the second one, and so on. The logical patitions (5-) in the extended partition is not supported.
      • +
      • On the GPT format drive, the partition number 1 specifies the first Microsoft Basic Data Partition found in the partition table and the partition number 2 specifies the second one found, and so on.
      • +
      • Windows does not support multiple volumes on the physical drive with removable class. Only the first parition found on the drive will be mounted. Windows does not support SFD format on the physical drive with fixed disk class.
      • For further information, refer to f_fdisk and f_mkfsfunction.
      diff --git a/documents/doc/findfirst.html b/documents/doc/findfirst.html index fd90443..d57d59c 100644 --- a/documents/doc/findfirst.html +++ b/documents/doc/findfirst.html @@ -65,15 +65,15 @@ FRESULT f_findfirst (

      The matching pattern string can contain wildcard terms. For example:

      • ? - An any character.
      • -
      • ??? - Any string in length of three characters.
      • -
      • * - Any string in length of zero or longer.
      • -
      • ????* - Any string in length of four characters or longer.
      • +
      • ??? - An any string in length of three characters.
      • +
      • * - An any string in length of zero or longer.
      • +
      • ????* - An any string in length of four characters or longer.
      -

      Since the matching algorithm uses recursion, number of wildcard terms in the matching pattern is limited to four. Any pattern with too many wildcard terms does not match any name. In LFN configuration, only fname[] is tested when FF_USE_FIND == 1 and also altname[] is tested when FF_USE_FIND == 2. There are some differences listed below between FatFs and standard systems in matching condition.

      +

      Since the matching algorithm uses recursion, number of wildcard terms in the matching pattern is limited to four to limit the stack usage. Any pattern with too many wildcard terms does not match any name. In LFN configuration, only fname[] is tested when FF_USE_FIND == 1 and also altname[] is tested when FF_USE_FIND == 2. There are some differences listed below between FatFs and standard systems in matching condition.

      • "*.*" never matches any name without extension while it matches any name with or without extension in standard systems.
      • -
      • Any pattern terminated with a period never matches any name while it matches the name without extensiton in standard systems.
      • -
      • DBCS extended characters are compared in case-sensitive when LFN is enabled with ANSI/OEM API.
      • +
      • Any pattern terminated with a dot never matches any name while it matches the name without extensiton in standard systems.
      • +
      • DBCS extended characters are compared in case-sensitive when LFN is enabled with ANSI/OEM code API.
      @@ -95,7 +95,7 @@ void find_image_file (void) DIR dj; /* Directory object */ FILINFO fno; /* File information */ - fr = f_findfirst(&dj, &fno, "", "dsc*.jp*"); /* Start to search for photo files */ + fr = f_findfirst(&dj, &fno, "", "????????.JPG"); /* Start to search for photo files */ while (fr == FR_OK && fno.fname[0]) { /* Repeat while an item is found */ printf("%s\n", fno.fname); /* Print the object name */ diff --git a/documents/doc/gets.html b/documents/doc/gets.html index e82cfe0..6aee492 100644 --- a/documents/doc/gets.html +++ b/documents/doc/gets.html @@ -45,7 +45,7 @@ TCHAR* f_gets (

      Description

      The read operation continues until a '\n' is stored, reached end of the file or the buffer is filled with len - 1 characters. The read string is terminated with a '\0'. When no character to read or any error occured during read operation, it returns a null pointer. The status of EOF and error can be examined with f_eof and f_error function.

      -

      When FatFs is configured to Unicode API (FF_LFN_UNICODE >= 1), data types on the srting fuctions, f_putc, f_puts, f_printf and f_gets, is also switched to Unicode. The character encoding on the file to be read via this function is assumed as FF_STRF_ENCODE. If the character encoding on the file differs from that on the API, it is converted in this function. In this case, input characters with wrong encoding will be lost.

      +

      When FatFs is configured to Unicode API (FF_LFN_UNICODE >= 1), data types on the srting fuctions, f_putc, f_puts, f_printf and f_gets, is also switched to Unicode. The character encoding on the file to be read via this function is assumed as FF_STRF_ENCODE. If the character encoding on the file differs from that on the API, it is converted in this function. In this case, input characters with wrong encoding will be lost.

      diff --git a/documents/doc/lseek.html b/documents/doc/lseek.html index cb01d16..9573009 100644 --- a/documents/doc/lseek.html +++ b/documents/doc/lseek.html @@ -18,12 +18,12 @@
       FRESULT f_lseek (
         FIL*    fp,  /* [IN] File object */
      -  FSIZE_t ofs  /* [IN] File read/write pointer */
      +  FSIZE_t ofs  /* [IN] Offset of file read/write pointer to be set */
       );
       
       FRESULT f_rewind (
      -  FIL*    fp,  /* [IN] File object */
      +  FIL*    fp   /* [IN] File object */
       );
       
    @@ -57,9 +57,9 @@ FRESULT f_rewind (
     #define f_rewind(fp) f_lseek((fp), 0)
     
    -

    If an offset beyond the file size is specified in write mode, the file size is expanded to the specified offset. The file data in the expanded part is undefined because no data is written to the file in this process. This is suitable to pre-allocate a data area to the file quickly for fast write operation. When a contiguous data area needs to be allocated to the file, use f_expand function instead. After the f_lseek function succeeded, the current read/write pointer should be checked in order to make sure the read/write pointer has been moved correctry. In case of the read/write pointer is not the expected value, either of followings has been occured.

    +

    If an offset beyond the file size is specified in write mode, the file size is expanded to the specified offset. The file data in the expanded part is undefined, because no data is written to the file in this process. This is suitable to pre-allocate a data area to the file quickly for fast write operation. When a contiguous data area needs to be allocated to the file, use f_expand function instead. After the f_lseek function succeeded, the current read/write pointer should be checked in order to make sure the read/write pointer has been moved correctry. In case of the read/write pointer is not pointing expected offset, either of followings has been occured.

    The fast seek feature enables fast backward/long seek operations without FAT access by using an on-memory CLMT (cluster link map table). It is applied to f_read and f_write function as well, however, the file size cannot be expanded by f_write, f_lseek function while the file is at fast seek mode.

    @@ -101,11 +101,11 @@ FRESULT f_rewind ( res = f_lseek(fp, PRE_SIZE); /* Expand file size (cluster pre-allocation) */ if (res || f_tell(fp) != PRE_SIZE) ... /* Check if the file has been expanded successfly */ - res = f_lseek(fp, DATA_START); /* Record data stream WITHOUT cluster allocation delay */ + res = f_lseek(fp, OFS_DATA); /* Record data stream with free from cluster allocation delay */ ... /* Write operation should be aligned to sector boundary to optimize the write throughput */ res = f_truncate(fp); /* Truncate unused area */ - res = f_lseek(fp, 0); /* Set file header */ + res = f_lseek(fp, OFS_HEADER); /* Set file header */ ... res = f_close(fp); diff --git a/documents/doc/mkfs.html b/documents/doc/mkfs.html index 45fd3ac..170f37a 100644 --- a/documents/doc/mkfs.html +++ b/documents/doc/mkfs.html @@ -30,21 +30,21 @@ FRESULT f_mkfs (
    path
    Pointer to the null-terminated string specifies the logical drive to be formatted. If it does not have a drive number in it, it means to specify the default drive. The logical drive may or may not have been mounted for the format process.
    opt
    -
    Specifies the structure that is holding format options. If a null pointer is given, it gives the function all options in default value. The format option structure has five members described below:
    +
    Specifies the format option structure MKFS_PARM holding format options. If a null pointer is given, it gives the function all options in default value. The structure has five members described below:
    BYTE fmt
    Specifies combination of FAT type flags, FM_FAT, FM_FAT32, FM_EXFAT and bitwise-or of these three, FM_ANY. FM_EXFAT is ignored when exFAT is not enabled. These flags specify which FAT type to be created on the volume. If two or more types are specified, one out of them will be selected depends on the volume size and au_size. The flag FM_SFD specifies to create the volume on the drive in SFD format. The default value is FM_ANY.
    DWORD au_size
    -
    Specifies size of the allocation unit (cluter) in unit of byte. The valid value is power of 2 between sector size and 128 * sector size inclusive for FAT/FAT32 volume and up to 16 MB for exFAT volume. If a zero (the default value) or any invalid value is given, the default allocation unit size depends on the volume size is used.
    +
    Specifies size of the allocation unit (cluter) in unit of byte. The valid value is power of 2 between sector size and 128 * sector size inclusive for FAT/FAT32 volume, or up to 16 MB for exFAT volume. If a zero (default value) or any invalid value is given, the function uses default allocation unit size depends on the volume size.
    UINT n_align
    -
    Specifies alignment of the volume data area (file allocation pool, usually erase block boundary of flash media) in unit of sector. The valid value for this member is between 1 and 32768 inclusive in power of 2. If a zero (the default value) or any invalid value is given, the function obtains the block size from lower layer with disk_ioctl function.
    +
    Specifies alignment of the volume data area (file allocation pool, usually erase block boundary of flash memory media) in unit of sector. The valid value for this member is between 1 and 32768 inclusive in power of 2. If a zero (the default value) or any invalid value is given, the function obtains the block size from lower layer with disk_ioctl function.
    BYTE n_fat
    Specifies number of FAT copies on the FAT/FAT32 volume. Valid value for this member is 1 or 2. The default value (0) and any invaid value gives 1. If the FAT type is exFAT, this member has no effect.
    UINT n_root
    Specifies number of root directory entries on the FAT volume. Valid value for this member is up to 32768 and aligned to sector size / 32. The default value (0) and any invaid value gives 512. If the FAT type is FAT32 or exFAT, this member has no effect.
    work
    -
    Pointer to the working buffer used for the format process. When a null pointer is given with FF_USE_LFN == 3, the function obtains a memory block in this function for the working buffer.
    +
    Pointer to the working buffer used for the format process. If a null pointer is given with FF_USE_LFN == 3, the function obtains a memory block for the working buffer in this function.
    len
    Size of the working buffer in unit of byte. It needs to be FF_MAX_SS at least. Plenty of working buffer reduces number of write transactions to the drive and the format process will finish quickly.
    @@ -69,8 +69,8 @@ FRESULT f_mkfs (

    The FAT sub-type, FAT12/FAT16/FAT32, of FAT volume except exFAT is determined by only number of clusters on the volume and nothing else, according to the FAT specification issued by Microsoft. Thus the FAT sub-type of created volume depends on the volume size and the cluster size. In case of the combination of FAT type and cluter size specified by argument is not valid for the volume size, the function will fail with FR_MKFS_ABORTED.

    The allocation unit, also known as cluster, is a unit of disk space allocation for files. When the size of allocation unit is 32768 bytes, a file with 100 bytes in size occupies 32768 bytes of disk space. The space efficiency of disk usage gets worse as increasing size of allocation unit, but, on the other hand, the read/write performance increases. Therefore the size of allocation unit is a trade-off between space efficiency and performance. For the large volumes in GB order, 32768 bytes or larger, automatically selected by default, is recommended for most case unless extremely many small files are created in the volume.

    When the logical drive to be formatted is associated with a physical drive (FF_MULTI_PARTITION = 0) and FM_SFD flag is not specified, a partition occupies entire disk space is created and then the FAT volume is created in the partition. When FM_SFD flag is specified, the FAT volume is created without any disk partitioning.

    -

    When the logical drive to be formatted is associated with a specific partition by multiple partition feature (FF_MULTI_PARTITION = 1), the FAT volume is created in the partition of the drive specified by volume mapping table and FM_SFD flag is ignored. The corresponding physical drive needs to be partitioned with f_fdisk function or any partitioning tool prior to create the FAT volume with this function.

    -

    There are three standard disk partitioning formats, MBR, GPT and SFD. The MBR format, also known as FDISK format, is usually used for harddisk, memory card and U disk. It can divide a physical drive into one or more partitions with a partition table. The GPT (GUID Partition Table) is a newly defined patitioning format for large storage devices. FatFs suppors the GPT only when 64-bit LBA is enabled. SFD (Super-Floppy Disk) is non-partitioned disk format. The FAT volume occupies the entire physical drive without any disk partitioning. It is usually used for floppy disk, optical disk and most super-floppy media. Some combination of systems and media support only either partitioned format or non-partitioned format and the other is not supported.

    +

    When the logical drive to be formatted is associated with a specific partition by multiple partition feature (FF_MULTI_PARTITION = 1), the FAT volume is created in the partition of the drive specified by volume mapping table and FM_SFD flag is ignored. The hosting physical drive needs to be partitioned with f_fdisk function or any partitioning tool prior to create the FAT volume with this function.

    +

    There are three standard disk partitioning formats, MBR, GPT and SFD. The MBR format, also known as FDISK format, is usually used for harddisk, memory card and U disk. It can divide a physical drive into one or more partitions with a partition table. The GPT (GUID Partition Table) is a newly defined patitioning format for large storage devices. FatFs suppors the GPT only when 64-bit LBA is enabled. The SFD (Super-Floppy Disk) is non-partitioned disk format. The FAT volume starts at LBA 0 and occupies the entire physical drive without any disk partitioning. It is usually used for floppy disk, optical disk and most super-floppy media. Some combination of systems and media support only either partitioned format or non-partitioned format and the other is not supported.

    Some systems manage the partitions in the on-board storage in non-standard format. The partitions are mapped as physical drives identified by pdrv in disk_* functions. For such systems, SFD format is suitable to create the FAT volume in the partition.

    diff --git a/documents/doc/mount.html b/documents/doc/mount.html index 0dc8ce3..70caf65 100644 --- a/documents/doc/mount.html +++ b/documents/doc/mount.html @@ -23,7 +23,7 @@ FRESULT f_mount (
     FRESULT f_unmount (
    -  const TCHAR* path,  /* [IN] Logical drive number */
    +  const TCHAR* path   /* [IN] Logical drive number */
     );
     
    diff --git a/documents/doc/open.html b/documents/doc/open.html index f41496c..77695b2 100644 --- a/documents/doc/open.html +++ b/documents/doc/open.html @@ -34,9 +34,9 @@ FRESULT f_open (
    Mode flags that specifies the type of access and open method for the file. It is specified by a combination of following flags.
    - - - + + + diff --git a/documents/doc/printf.html b/documents/doc/printf.html index d559dd5..4e2ca71 100644 --- a/documents/doc/printf.html +++ b/documents/doc/printf.html @@ -39,7 +39,7 @@ int f_printf (

    Return Values

    -

    When the string was written successfuly, it returns number of character encoding units written to the file. When the function failed due to disk full or any error, a negative value will be returned.

    +

    When the string was written successfuly, it returns number of character encoding units written to the file. When the function failed due to disk full or an error, a negative value will be returned.

    @@ -47,13 +47,27 @@ int f_printf (

    Description

    The format control directive is a sub-set of standard library shown as follows:

    -    %[flag][width][prefix][type]
    +    %[flag][width][precision][size]type
     
    -
    flag
    Padding options. A '0' specifies zero padded. A '-' specifies left justified.
    -
    width
    Minimum width of the field, '1'-'99' or '*'. If the width of generated string is less than the specified value, rest field is padded with white spaces or zeros. An * specifies the value comes from an argument in int type. The default value is zero.
    -
    prefix
    Size prefix 'l' for long integer argument. If sizeof (long) == sizeof (int) (this is typical of 32-bit systems), the size prefix can be omitted.
    -
    type
    'c','s','d','u','o','x','b', specify type of the argument and output format, character, string, signed integer in decimal, unsigned integer in decimal, unsigned integer in octal, unsigned integer in hexdecimal and unsigned integer in binary respectively. These characters except 'x' are case insensitive. An 'X' generates a hexdecimal in up-case.
    +
    flag
    Padding options. A - specifies left-aligned. A 0 specifies zero padded. The default setting is in right-aligned and space padded.
    +
    width
    Minimum width of the field, 1-99 or *. If the width of generated string is less than the specified value, rest field is padded with spaces or zeros. An * specifies the value comes from an argument in int type.
    +
    precision
    Specifies number of fractional digits or maximum width of string, .0-.99 or .*. If number is omitted, it will be same as .0. Default setting is 6 for number and no limit for string.
    +
    size
    Specifies size of integer argument, l(long) and ll(long long). If sizeof (long) == sizeof (int) is true (this is typical of 32-bit systems), prefix l can be omitted for long integer argument. The default size is int for integer arrument and floating point argument is always assumed double.
    +
    type
    Specifies type of the output format and the argument as shown below. The length of generated string is in assumtion of int is 32-bit. +
    FlagsMeaning
    FA_READSpecifies read access to the object. Data can be read from the file.
    FA_WRITESpecifies write access to the object. Data can be written to the file. Combine with FA_READ for read-write access.
    FA_OPEN_EXISTINGOpens the file. The function fails if the file is not existing. (Default)
    FA_READSpecifies read access to the file. Data can be read from the file.
    FA_WRITESpecifies write access to the file. Data can be written to the file. Combine with FA_READ for read-write access.
    FA_OPEN_EXISTINGOpens a file. The function fails if the file is not existing. (Default)
    FA_CREATE_NEWCreates a new file. The function fails with FR_EXIST if the file is existing.
    FA_CREATE_ALWAYSCreates a new file. If the file is existing, it will be truncated and overwritten.
    FA_OPEN_ALWAYSOpens the file if it is existing. If not, a new file will be created.
    + + + + + + + + + + +
    TypeFormatArgumentLength
    cCharacterint,
    long,
    long long
    1 character.
    dSigned decimal1 to 11 (20 for ll) characters.
    uUnsigned decimal1 to 10 (20 for ll) characters.
    oUnsigned octal1 to 11 (22 for ll) characters.
    x XUnsigned hexdecimal1 to 8 (16 for ll) characters.
    bUnsigned binary1 to 32 characters. Limited to lower 32 digits when ll is specified.
    sStringTCHAR*As input string. Null pointer generates a null string.
    fFloating point
    (decimal)
    double1 to 31 characters. If the number of characters exceeds 31, it writes "±OV". Not a number and infinite write "NaN" and "±INF".
    e EFloating point
    (e notation)
    4 to 31 characters. If the number of characters exceeds 31 or exponent exceeds +99, it writes "±OV".
    +

    When FatFs is configured for Unicode API (FF_LFN_UNICODE >= 1), character encoding on the string fuctions, f_putc, f_puts, f_printf and f_gets function, is also switched to Unicode. The Unicode characters in multiple encoding unit, such as surrogate pair and multi-byte sequence, should not be divided into two function calls, or the character will be lost. The character encoding on the file to be written via this function is selected by FF_STRF_ENCODE. The characters with wrong encoding or invalid for the output encoding will be lost.

    @@ -68,23 +82,24 @@ int f_printf (

    Example

    -    f_printf(&fil, "%d", 1234);            /* "1234" */
    -    f_printf(&fil, "%6d,%3d%%", -200, 5);  /* "  -200,  5%" */
    -    f_printf(&fil, "%ld", 12345L);         /* "12345" */
    -    f_printf(&fil, "%06d", 25);            /* "000025" */
    -    f_printf(&fil, "%06d", -25);           /* "000-25" */
    -    f_printf(&fil, "%*d", 5, 100);         /* "  100" */
    -    f_printf(&fil, "%-6d", 25);            /* "25    " */
    -    f_printf(&fil, "%u", -1);              /* "65535" or "4294967295" */
    -    f_printf(&fil, "%04x", 0xAB3);         /* "0ab3" */
    -    f_printf(&fil, "%08lX", 0x123ABCL);    /* "00123ABC" */
    -    f_printf(&fil, "%04o", 255);           /* "0377" */
    -    f_printf(&fil, "%016b", 0x550F);       /* "0101010100001111" */
    -    f_printf(&fil, "%s", "String");        /* "String" */
    -    f_printf(&fil, "%8s", "abc");          /* "     abc" */
    -    f_printf(&fil, "%-8s", "abc");         /* "abc     " */
    -    f_printf(&fil, "%c", 'a');             /* "a" */
    -    f_printf(&fil, "%f", 10.0);            /* f_printf lacks floating point support */
    +    f_printf("%d", 1234);             /* "1234" */
    +    f_printf("%6d,%3d%%", -200, 5);   /* "  -200,  5%" */
    +    f_printf("%-6u", 100);            /* "100   " */
    +    f_printf("%ld", 12345678);        /* "12345678" */
    +    f_printf("%llu", 0x100000000);    /* "4294967296"   (FF_PRINT_LLI) */
    +    f_printf("%lld", -1LL);           /* "-1"           (FF_PRINT_LLI) */
    +    f_printf("%04x", 0xA3);           /* "00a3" */
    +    f_printf("%08lX", 0x123ABC);      /* "00123ABC" */
    +    f_printf("%016b", 0x550F);        /* "0101010100001111" */
    +    f_printf("%*d", 6, 100);          /* "   100" */
    +    f_printf("%s", "abcdefg");        /* "abcdefg" */
    +    f_printf("%5s", "abc");           /* "  abc" */
    +    f_printf("%-5s", "abc");          /* "abc  " */
    +    f_printf("%.5s", "abcdefg");      /* "abcde" */
    +    f_printf("%-5.2s", "abcdefg");    /* "ab   " */
    +    f_printf("%c", 'a');              /* "a" */
    +    f_printf("%12f", 10.0);           /* "   10.000000" (FF_PRINT_FLOAT) */
    +    f_printf("%.4E", 123.45678);      /* "1.2346E+02"   (FF_PRINT_FLOAT) */
     
    diff --git a/documents/doc/rc.html b/documents/doc/rc.html index 6fce2a6..0b3577e 100644 --- a/documents/doc/rc.html +++ b/documents/doc/rc.html @@ -22,14 +22,14 @@
    The lower layer, disk_read, disk_write or disk_ioctl function, reported that an unrecoverable hard error occured.
    Note that if once this error occured at any operation to an open file, the file object is aborted and any operations to the file except for close will be rejected.
    FR_INT_ERR
    -
    Assertion failed. An insanity is detected in the internal process. One of the following possibilities is suspected. +
    Assertion failed and an insanity is detected in the internal process. One of the following possibilities is suspected.
      -
    • Work area (file system object, file object or etc...) has been broken by stack overflow or any other tasks. This is the reason in most case.
    • +
    • Work area (file system object, file object or etc...) has been broken by stack overflow or something. This is the reason in most case.
    • There is an error of the FAT structure on the volume.
    • There is a bug in the FatFs module itself.
    • Wrong lower layer implementation.
    -Note that if once this error occured at any operation to an open file, the file object is aborted and all operations to the file except for close will be rejected. +Note that if once this error occured in the operation to an open file, the file object is aborted and any operation to the file except for close will be rejected.
    FR_NOT_READY
    @@ -54,20 +54,20 @@ Note that if once this error occured at any operation to an open file, the file
  • There is a character not allowed for the file name.
  • The file name is out of 8.3 format. (at non-LFN cfg.)
  • FF_MAX_LFN is insufficient for the file name. (at LFN cfg.)
  • -
  • There is any character encoding error in the string.
  • +
  • There is a character encoding error in the string.
  • FR_DENIED
    The required access was denied due to one of the following reasons:
      -
    • Write mode open against the read-only file.
    • -
    • Deleting the read-only file or directory.
    • -
    • Deleting the non-empty directory or current directory.
    • -
    • Reading the file opened without FA_READ flag.
    • -
    • Any modification to the file opened without FA_WRITE flag.
    • -
    • Could not create the object due to root directory full or disk full.
    • -
    • Could not allocate a contiguous area to the file.
    • +
    • Write mode open against the read-only file. (f_open)
    • +
    • Deleting the read-only file or directory. (f_unlink)
    • +
    • Deleting the non-empty directory or current directory. (f_unlink)
    • +
    • Reading the file opened without FA_READ flag. (f_read)
    • +
    • Any modification to the file opened without FA_WRITE flag. (f_write, f_truncate, f_expand)
    • +
    • Could not create the object due to root directory full or disk full. (f_open, f_mkfs)
    • +
    • Could not allocate a contiguous area to the file. (f_expand)
    @@ -93,7 +93,11 @@ Note that if once this error occured at any operation to an open file, the file
    Work area for the logical drive has not been registered by f_mount function.
    FR_NO_FILESYSTEM
    -
    There is no valid FAT volume on the drive or wrong lower layer implementation.
    +
    No valid FAT volume could not be found in the drive. One of the following possibilities is suspected. +
      +
    • Wrong lower layer implementation.
    • +
    • Wrong VolToPart[] settings. (FF_MULTI_PARTITION = 1)
    • +
    FR_MKFS_ABORTED
    The f_mkfs function aborted before start in format due to a reason as follows: diff --git a/documents/doc/readdir.html b/documents/doc/readdir.html index 77c8148..467773d 100644 --- a/documents/doc/readdir.html +++ b/documents/doc/readdir.html @@ -22,7 +22,7 @@ FRESULT f_readdir (
     FRESULT f_rewinddir (
    -  DIR* dp,      /* [IN] Directory object */
    +  DIR* dp       /* [IN] Directory object */
     );
     
    @@ -103,7 +103,7 @@ FRESULT scan_files ( printf("%s/%s\n", path, fno.fname); } } - f_closedir(&dir) + f_closedir(&dir); } return res; diff --git a/documents/updates.txt b/documents/updates.txt index b1a32b4..4112d3e 100644 --- a/documents/updates.txt +++ b/documents/updates.txt @@ -1,3 +1,14 @@ +R0.14b (April 17, 2021) + Made FatFs uses standard library for copy, compare and search instead of built-in string functions. + Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP) + Made path name parser ignore the terminating separator to allow "dir/". + Improved the compatibility in Unix style path name feature. + Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a) + Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12) + Fixed code page 855 cannot be set by f_setcp(). + Fixed some compiler warnings. + + R0.14a (December 05, 2020) Limited number of recursive calls in f_findnext(). Fixed old floppy disks formatted with MS-DOS 2.x and 3.x cannot be mounted. @@ -5,7 +16,7 @@ R0.14a (December 05, 2020) R0.14 (October 14, 2019) - Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1) + Added support for 64-bit LBA and GUID partition table (FF_LBA64) Changed some API functions, f_mkfs() and f_fdisk(). Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters. Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters. diff --git a/source/00history.txt b/source/00history.txt index f3032e4..8a0169b 100644 --- a/source/00history.txt +++ b/source/00history.txt @@ -344,3 +344,16 @@ R0.14a (December 5, 2020) Fixed old floppy disks formatted with MS-DOS 2.x and 3.x cannot be mounted. Fixed some compiler warnings. + + +R0.14b (April 17, 2021) + Made FatFs uses standard library for copy, compare and search instead of built-in string functions. + Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP) + Made path name parser ignore the terminating separator to allow "dir/". + Improved the compatibility in Unix style path name feature. + Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a) + Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12) + Fixed code page 855 cannot be set by f_setcp(). + Fixed some compiler warnings. + + diff --git a/source/00readme.txt b/source/00readme.txt index 1293b66..4960997 100644 --- a/source/00readme.txt +++ b/source/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.14a +FatFs Module Source Files R0.14b FILES diff --git a/source/ff.c b/source/ff.c index 9b980d7..d209605 100644 --- a/source/ff.c +++ b/source/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.14a / +/ FatFs - Generic FAT Filesystem Module R0.14b / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2020, ChaN, all right reserved. +/ Copyright (C) 2021, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -19,6 +19,7 @@ /----------------------------------------------------------------------------*/ +#include #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ @@ -29,7 +30,7 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 80196 /* Revision ID */ +#if FF_DEFINED != 86631 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -47,6 +48,8 @@ #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z') #define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsSeparator(c) ((c) == '/' || (c) == '\\') +#define IsTerminator(c) ((UINT)(c) < (FF_USE_LFN ? ' ' : '!')) #define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) #define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) @@ -61,7 +64,8 @@ /* 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 */ +#define AM_MASK 0x3F /* Mask of defined bits in FAT */ +#define AM_MASKX 0x37 /* Mask of defined bits in exFAT */ /* Name status flags in fn[11] */ @@ -233,7 +237,7 @@ /* Re-entrancy related */ #if FF_FS_REENTRANT #if FF_USE_LFN == 1 -#error Static LFN work area cannot be used at thread-safe configuration +#error Static LFN work area cannot be used in thread-safe configuration #endif #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } #else @@ -244,10 +248,10 @@ /* Definitions of logical drive - physical location conversion */ #if FF_MULTI_PARTITION #define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ -#define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition number (0:auto search, 1..:forced partition number) */ #else #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ -#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#define LD2PT(vol) 0 /* Auto partition search */ #endif @@ -556,7 +560,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ /* Code conversion tables */ /*--------------------------------*/ -#if FF_CODE_PAGE == 0 /* Run-time code page configuration */ +#if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #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 */ @@ -680,53 +684,6 @@ static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-en /* String functions */ /*-----------------------------------------------------------------------*/ -/* Copy memory to memory */ -static void mem_cpy (void* dst, const void* src, UINT cnt) -{ - BYTE *d = (BYTE*)dst; - const BYTE *s = (const BYTE*)src; - - if (cnt != 0) { - do { - *d++ = *s++; - } while (--cnt); - } -} - - -/* Fill memory block */ -static void mem_set (void* dst, int val, UINT cnt) -{ - BYTE *d = (BYTE*)dst; - - do { - *d++ = (BYTE)val; - } while (--cnt); -} - - -/* Compare memory block */ -static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ -{ - const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; - int r = 0; - - do { - r = *d++ - *s++; - } while (--cnt && r == 0); - - return r; -} - - -/* Check if chr is contained in the string */ -static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ -{ - while (*str && *str != chr) str++; - return *str; -} - - /* Test if the byte is DBC 1st byte */ static int dbc_1st (BYTE c) { @@ -795,18 +752,14 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on uc = (BYTE)*p++; /* Get an encoding unit */ if (uc & 0x80) { /* Multiple byte code? */ - if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ uc &= 0x1F; nf = 1; - } else { - if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ - uc &= 0x0F; nf = 2; - } else { - if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ - uc &= 0x07; nf = 3; - } else { /* Wrong sequence */ - return 0xFFFFFFFF; - } - } + } else if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + uc &= 0x0F; nf = 2; + } else if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + uc &= 0x07; nf = 3; + } else { /* Wrong sequence */ + return 0xFFFFFFFF; } do { /* Get trailing bytes */ b = (BYTE)*p++; @@ -844,8 +797,8 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on } -/* Output a TCHAR string in defined API encoding */ -static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ +/* Store a Unicode char in defined API encoding */ +static UINT put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */ TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ @@ -1011,7 +964,7 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 && Files[i].ofs == dp->dptr) break; } - if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ + if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; @@ -1038,13 +991,13 @@ static FRESULT dec_lock ( /* Decrement object open counter */ if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; - if (n == 0x100) n = 0; /* If write mode open, delete the entry */ - if (n > 0) n--; /* Decrement read mode open count */ + if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ res = FR_OK; } else { - res = FR_INT_ERR; /* Invalid index nunber */ + res = FR_INT_ERR; /* Invalid index nunber */ } return res; } @@ -1133,7 +1086,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, sizeof fs->win); + memset(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); /* Boot signature */ st_dword(fs->win + FSI_LeadSig, 0x41615252); /* Leading signature */ st_dword(fs->win + FSI_StrucSig, 0x61417272); /* Structure signature */ @@ -1172,7 +1125,7 @@ static LBA_t clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ /*-----------------------------------------------------------------------*/ -/* FAT access - Read value of a FAT entry */ +/* FAT access - Read value of an FAT entry */ /*-----------------------------------------------------------------------*/ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ @@ -1250,7 +1203,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFF #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* FAT access - Change value of a FAT entry */ +/* FAT access - Change value of an FAT entry */ /*-----------------------------------------------------------------------*/ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ @@ -1271,7 +1224,7 @@ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); - *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Update 1st byte */ + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Update 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; @@ -1684,12 +1637,12 @@ 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, sizeof fs->win); /* Clear window buffer */ + memset(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) ; if (szb > SS(fs)) { /* Buffer allocated? */ - mem_set(ibuf, 0, szb); + memset(ibuf, 0, szb); szb /= SS(fs); /* Bytes -> Sectors */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ ff_memfree(ibuf); @@ -1993,7 +1946,7 @@ static void put_lfn ( do { if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ st_word(dir + LfnOfs[s], wc); /* Put it */ - if (wc == 0) wc = 0xFFFF; /* Padding characters for following items */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for following items */ } while (++s < 13); if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ @@ -2011,7 +1964,7 @@ static void put_lfn ( static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ - const BYTE* src, /* Pointer to SFN */ + const BYTE* src, /* Pointer to SFN in directory form */ const WCHAR* lfn, /* Pointer to LFN */ UINT seq /* Sequence number */ ) @@ -2022,7 +1975,7 @@ static void gen_numname ( DWORD sreg; - mem_cpy(dst, src, 11); + memcpy(dst, src, 11); /* Prepare the SFN to be modified */ if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sreg = seq; @@ -2037,24 +1990,23 @@ static void gen_numname ( seq = (UINT)sreg; } - /* itoa (hexdecimal) */ + /* Make suffix (~ + hexdecimal) */ i = 7; do { - c = (BYTE)((seq % 16) + '0'); + c = (BYTE)((seq % 16) + '0'); seq /= 16; if (c > '9') c += 7; ns[i--] = c; - seq /= 16; - } while (seq); + } while (i && seq); ns[i] = '~'; - /* Append the number to the SFN body */ - for (j = 0; j < i && dst[j] != ' '; j++) { - if (dbc_1st(dst[j])) { + /* Append the suffix to the SFN body */ + for (j = 0; j < i && dst[j] != ' '; j++) { /* Find the offset to append */ + if (dbc_1st(dst[j])) { /* To avoid DBC break up */ if (j == i - 1) break; j++; } } - do { + do { /* Append the suffix */ dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } @@ -2139,47 +2091,6 @@ static DWORD xsum32 ( /* Returns 32-bit checksum */ #endif -#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 -/*------------------------------------------------------*/ -/* exFAT: Get object information from a directory block */ -/*------------------------------------------------------*/ - -static void get_xfileinfo ( - BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ - FILINFO* fno /* Buffer to store the extracted file information */ -) -{ - WCHAR wc, hs; - UINT di, si, nc; - - /* Get file name from the entry block */ - si = SZDIRE * 2; /* 1st C1 entry */ - nc = 0; hs = 0; di = 0; - while (nc < dirb[XDIR_NumName]) { - if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ - if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ - hs = wc; continue; /* Get low surrogate */ - } - wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ - di += wc; - hs = 0; - } - if (hs != 0) di = 0; /* Broken surrogate pair? */ - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ - fno->fname[di] = 0; /* Terminate the name */ - fno->altname[0] = 0; /* exFAT does not support SFN */ - - fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ - fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ - fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ - fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ -} - -#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ - /*-----------------------------------*/ /* exFAT: Get a directry entry block */ @@ -2191,28 +2102,28 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ { FRESULT res; UINT i, sz_ent; - BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ - /* Load file-directory entry */ + /* Load file directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ - mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); + memcpy(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 stream-extension 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] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ - mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); + memcpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; - /* Load file-name entries */ + /* Load file name entries */ i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); @@ -2221,7 +2132,7 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; 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); + if (i < MAXDIRB(FF_MAX_LFN)) memcpy(dirb + i, dp->dir, SZDIRE); } while ((i += SZDIRE) < sz_ent); /* Sanity check (do it for only accessible object) */ @@ -2289,7 +2200,7 @@ static FRESULT store_xdir ( { FRESULT res; UINT nent; - BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); @@ -2300,7 +2211,7 @@ static FRESULT store_xdir ( while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) break; - mem_cpy(dp->dir, dirb, SZDIRE); + memcpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; if (--nent == 0) break; dirb += SZDIRE; @@ -2326,7 +2237,7 @@ static void create_xdir ( /* Create file-directory and stream-extension entry */ - mem_set(dirb, 0, 2 * SZDIRE); + memset(dirb, 0, 2 * SZDIRE); dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; @@ -2337,7 +2248,7 @@ static void create_xdir ( 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 */ + st_word(dirb + i, wc); /* Store it */ i += 2; } while (i % SZDIRE != 0); nc1++; @@ -2402,17 +2313,17 @@ static FRESULT dir_read ( if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { - if (attr == AM_LFN) { /* An LFN entry is found */ - if (b & 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]; b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; - } else { /* An SFN entry is found */ + } 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. */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ } break; } @@ -2460,7 +2371,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ 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 */ + if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ @@ -2498,13 +2409,13 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ } } else { /* An SFN entry is found */ if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ - if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !memcmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } } #else /* Non LFN configuration */ dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; - if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ + if (!(dp->dir[DIR_Attr] & AM_VOL) && !memcmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ #endif res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); @@ -2552,10 +2463,10 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ if (res != FR_OK) return res; - dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ res = store_xdir(&dj); /* Store the object status */ if (res != FR_OK) return res; } @@ -2566,7 +2477,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too } #endif /* On the FAT/FAT32 volume */ - mem_cpy(sn, dp->fn, 12); + memcpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { @@ -2605,8 +2516,8 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too if (res == FR_OK) { res = move_window(fs, dp->sect); if (res == FR_OK) { - mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ - mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ + memset(dp->dir, 0, SZDIRE); /* Clean the entry */ + memcpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ #if FF_USE_LFN dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif @@ -2642,7 +2553,7 @@ static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ if (res != FR_OK) break; if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ - } else { /* On the FAT/FAT32 volume */ + } else { /* On the FAT/FAT32 volume */ dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ } fs->wflag = 1; @@ -2682,6 +2593,7 @@ static void get_fileinfo ( BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; + UINT nw; #else TCHAR c; #endif @@ -2692,22 +2604,47 @@ static void get_fileinfo ( #if FF_USE_LFN /* LFN configuration */ #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - get_xfileinfo(fs->dirbuf, fno); + if (fs->fs_type == FS_EXFAT) { /* exFAT volume */ + UINT nc = 0; + + si = SZDIRE * 2; di = 0; /* 1st C1 entry in the entry block */ + hs = 0; + while (nc < fs->dirbuf[XDIR_NumName]) { + if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ + } + nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ + if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + di += nw; + hs = 0; + } + if (hs != 0) di = 0; /* Broken surrogate pair? */ + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + fno->fname[di] = 0; /* Terminate the name */ + fno->altname[0] = 0; /* exFAT does not support SFN */ + + fno->fattrib = fs->dirbuf[XDIR_Attr] & AM_MASKX; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(fs->dirbuf + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(fs->dirbuf + XDIR_ModTime + 2); /* Date */ return; } else #endif - { /* On the FAT/FAT32 volume */ + { /* FAT/FAT32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ - si = di = hs = 0; + si = di = 0; + hs = 0; while (fs->lfnbuf[si] != 0) { wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } - wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ - if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ - di += wc; + nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ + if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + di += nw; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ @@ -2727,9 +2664,9 @@ static void get_fileinfo ( } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ - wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ - if (wc == 0) { di = 0; break; } /* Buffer overflow? */ - di += wc; + nw = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in API encoding */ + if (nw == 0) { di = 0; break; } /* Buffer overflow? */ + di += nw; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ #endif @@ -2760,10 +2697,10 @@ static void get_fileinfo ( if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ fno->fname[di++] = c; } - fno->fname[di] = 0; + fno->fname[di] = 0; /* Terminate the SFN */ #endif - fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fattrib = dp->dir[DIR_Attr] & AM_MASK; /* Attribute */ fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ @@ -2881,16 +2818,17 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ wc = (WCHAR)uc; - if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ - if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + if (wc < ' ' || IsSeparator(wc)) break; /* Break if end of the path or a separator is found */ + if (wc < 0x80 && strchr("*:<>|\"\?\x7F", (int)wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ - lfn[di++] = wc; /* Store the Unicode character */ + lfn[di++] = wc; /* Store the Unicode character */ } - if (wc < ' ') { /* End of path? */ - cf = NS_LAST; /* Set last segment flag */ - } else { - cf = 0; /* Next segment follows */ - while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ + if (wc < ' ') { /* Stopped at end of the path? */ + cf = NS_LAST; /* Last segment */ + } else { /* Stopped at a separator */ + while (IsSeparator(*p)) p++; /* Skip duplicated separators if exist */ + cf = 0; /* Next segment may follow */ + if (IsTerminator(*p)) cf = NS_LAST; /* Ignore terminating separator */ } *path = p; /* Return pointer to the next segment */ @@ -2898,14 +2836,14 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; - for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ + for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; } - dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif - while (di) { /* Snip off trailing spaces and dots if exist */ + while (di) { /* Snip off trailing spaces and dots if exist */ wc = lfn[di - 1]; if (wc != ' ' && wc != '.') break; di--; @@ -2918,7 +2856,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ - mem_set(dp->fn, ' ', 11); + memset(dp->fn, ' ', 11); i = b = 0; ni = 8; for (;;) { wc = lfn[si++]; /* Get an LFN character */ @@ -2939,20 +2877,20 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr continue; } - if (wc >= 0x80) { /* Is this a non-ASCII character? */ + if (wc >= 0x80) { /* Is this an extended character? */ cf |= NS_LFN; /* LFN entry needs to be created */ #if FF_CODE_PAGE == 0 - if (ExCvt) { /* At SBCS */ + if (ExCvt) { /* In SBCS cfg */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ - } else { /* At DBCS */ - wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ + } else { /* In DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Up-convert ==> ANSI/OEM code */ } -#elif FF_CODE_PAGE < 900 /* SBCS cfg */ +#elif FF_CODE_PAGE < 900 /* In SBCS cfg */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ -#else /* DBCS cfg */ - wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ +#else /* In DBCS cfg */ + wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Up-convert ==> ANSI/OEM code */ #endif } @@ -2963,7 +2901,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr } dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ } else { /* SBC */ - if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ + if (wc == 0 || strchr("+,;=[]", (int)wc)) { /* Replace illegal characters for SFN */ wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { if (IsUpper(wc)) { /* ASCII upper case? */ @@ -2998,7 +2936,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr /* Create file name in directory form */ p = *path; sfn = dp->fn; - mem_set(sfn, ' ', 11); + memset(sfn, ' ', 11); si = i = 0; ni = 8; #if FF_FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ @@ -3007,8 +2945,8 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr if (c != '.' || si >= 3) break; sfn[i++] = c; } - if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; - *path = p + si; /* Return pointer to the next segment */ + if (!IsSeparator(c) && c > ' ') return FR_INVALID_NAME; + *path = p + si; /* Return pointer to the next segment */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; } @@ -3016,8 +2954,8 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr for (;;) { c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ - if (c == '/' || c == '\\') { /* Break if a separator is found */ - while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + if (IsSeparator(c)) { /* Break if a separator is found */ + while (IsSeparator(p[si])) si++; /* Skip duplicated separator if exist */ break; } if (c == '.' || i >= ni) { /* End of body or field overflow? */ @@ -3040,16 +2978,16 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ - if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ + if (strchr("*+,:;<=>[]|\"\?\x7F", (int)c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ if (IsLower(c)) c -= 0x20; /* To upper */ sfn[i++] = c; } } - *path = p + si; /* Return pointer to the next segment */ + *path = &p[si]; /* Return pointer to the next segment */ if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ - sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + sfn[NSFLAG] = (c <= ' ' || p[si] <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; #endif /* FF_USE_LFN */ @@ -3073,13 +3011,13 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ #if FF_FS_RPATH != 0 - if (*path != '/' && *path != '\\') { /* Without heading separator */ - dp->obj.sclust = fs->cdir; /* Start from current directory */ + if (!IsSeparator(*path) && (FF_STR_VOLUME_ID != 2 || !IsTerminator(*path))) { /* Without heading separator */ + dp->obj.sclust = fs->cdir; /* Start at the current directory */ } else #endif { /* With heading separator */ - while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ - dp->obj.sclust = 0; /* Start from root directory */ + while (IsSeparator(*path)) path++; /* Strip separators */ + dp->obj.sclust = 0; /* Start from the root directory */ } #if FF_FS_EXFAT dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ @@ -3120,13 +3058,13 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ } break; } - if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ + if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ /* Get into the sub-directory */ - if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ dp->obj.c_scl = dp->obj.sclust; dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; @@ -3155,7 +3093,8 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb { const TCHAR *tp, *tt; TCHAR tc; - int i, vol = -1; + int i; + int vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ const char *sp; char c; @@ -3163,7 +3102,7 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ + do tc = *tt++; while (!IsTerminator(tc) && tc != ':'); /* Find a colon in the path */ if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; @@ -3190,21 +3129,22 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb return vol; } #if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ - if (*tp == '/') { + if (*tp == '/') { /* Is there a volume ID? */ + while (*(tp + 1) == '/') tp++; /* Skip duplicated separator */ i = 0; do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ + tt = tp; sp = VolumeStr[i]; /* Path name and this string volume ID */ do { /* Compare the volume ID with path name */ - c = *sp++; tc = *(++tp); + c = *sp++; tc = *(++tt); if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); - } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ + } while ((c || (tc != '/' && !IsTerminator(tc))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ - *path = tp; /* Snip the drive prefix off */ - return vol; + *path = tt; /* Snip the drive prefix off */ } + return vol; } #endif /* No drive prefix is found */ @@ -3253,7 +3193,7 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ DWORD bcc; - if (mem_cmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ + if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); } @@ -3295,7 +3235,7 @@ static DWORD make_rand ( /* Check what the sector is */ -static UINT check_fs ( /* 0:FAT VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 3:Not FAT and invalid BS, 4:Disk error */ +static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 3:Not FAT and invalid BS, 4:Disk error */ FATFS* fs, /* Filesystem object */ LBA_t sect /* Sector to load and check if it is an FAT-VBR or not */ ) @@ -3308,21 +3248,24 @@ static UINT check_fs ( /* 0:FAT VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 3:Not if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ sign = ld_word(fs->win + BS_55AA); #if FF_FS_EXFAT - if (sign == 0xAA55 && !mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ + if (sign == 0xAA55 && !memcmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ #endif b = fs->win[BS_JmpBoot]; if (b == 0xEB || b == 0xE9 || b == 0xE8) { /* Valid JumpBoot code? (short jump, near jump or near call) */ - if (sign == 0xAA55 && !mem_cmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) return 0; /* It is an FAT32 VBR */ - /* FAT volumes formatted with early MS-DOS lack boot signature and FAT string, so that we need to identify the FAT VBR without them. */ + if (sign == 0xAA55 && !memcmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) { + return 0; /* It is an FAT32 VBR */ + } + /* FAT volumes formatted with early MS-DOS lack BS_55AA and BS_FilSysType, so FAT VBR needs to be identified without them. */ w = ld_word(fs->win + BPB_BytsPerSec); - if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS) { /* Properness of sector size */ - b = fs->win[BPB_SecPerClus]; - if (b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size */ - && (fs->win[BPB_NumFATs] == 1 || fs->win[BPB_NumFATs] == 2) /* Properness of number of FATs */ - && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root entry count */ - && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size */ - return 0; /* Sector can be presumed an FAT VBR */ - } + b = fs->win[BPB_SecPerClus]; + if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS /* Properness of sector size (512-4096 and 2^n) */ + && b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size (2^n) */ + && ld_word(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of reserved sectors (MNBZ) */ + && (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of FATs (1 or 2) */ + && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir entries (MNBZ) */ + && (ld_word(fs->win + BPB_TotSec16) >= 128 || ld_dword(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume sectors (>=128) */ + && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */ + return 0; /* It can be presumed an FAT VBR */ } } return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (valid or invalid BS) */ @@ -3341,8 +3284,8 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ DWORD mbr_pt[4]; - fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD */ - if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is a FAT VBR as auto scan, not a BS or disk error */ + fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD format */ + if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is an FAT VBR as auto scan, not a BS or disk error */ /* Sector 0 is not an FAT VBR or forced partition number wants a partition */ @@ -3358,7 +3301,7 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ for (v_ent = i = 0; i < n_ent; i++) { /* Find FAT partition */ if (move_window(fs, pt_lba + i * SZ_GPTE / SS(fs)) != FR_OK) return 4; /* PT sector */ ofs = i * SZ_GPTE % SS(fs); /* Offset in the sector */ - if (!mem_cmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */ + if (!memcmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */ v_ent++; fmt = check_fs(fs, ld_qword(fs->win + ofs + GPTE_FstLba)); /* Load VBR and check status */ if (part == 0 && fmt <= 1) return fmt; /* Auto search (valid FAT volume found first) */ @@ -3426,7 +3369,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ } /* The filesystem object is not valid. */ - /* Following code attempts to mount the volume. (find a FAT volume, analyze the BPB and initialize the filesystem object) */ + /* Following code attempts to mount the volume. (find an FAT volume, analyze the BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ @@ -3446,7 +3389,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fmt = find_volume(fs, LD2PT(vol)); if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - bsect = fs->winsect; /* Volume location */ + bsect = fs->winsect; /* Volume offset */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ @@ -3464,8 +3407,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ return FR_NO_FILESYSTEM; } - maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ - if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA of the volume + 1 */ + if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be accessed in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ @@ -3473,7 +3416,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ - if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768 sectors) */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ @@ -3494,11 +3437,11 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (move_window(fs, clst2sect(fs, (DWORD)fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; so++; } - if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ i = (i + SZDIRE) % SS(fs); /* Next entry */ } - bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ - if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; + bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; /* (Wrong cluster#) */ 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; @@ -3660,9 +3603,9 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( - FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ + FATFS* fs, /* Pointer to the filesystem object to be registered (NULL:unmount)*/ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ - BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ + BYTE opt /* Mount option: 0=Do not mount (delayed mount), 1=Mount immediately */ ) { FATFS *cfs; @@ -3710,14 +3653,14 @@ FRESULT f_mount ( FRESULT f_open ( FIL* fp, /* Pointer to the blank file object */ const TCHAR* path, /* Pointer to the file name */ - BYTE mode /* Access mode and file open mode flags */ + BYTE mode /* Access mode and open mode flags */ ) { FRESULT res; DIR dj; FATFS *fs; #if !FF_FS_READONLY - DWORD cl, bcs, clst, tm; + DWORD cl, bcs, clst, tm; LBA_t sc; FSIZE_t ofs; #endif @@ -3770,8 +3713,8 @@ FRESULT f_open ( fp->obj.fs = fs; init_alloc_info(fs, &fp->obj); /* Set directory entry block initial state */ - mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ - mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ + memset(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ + memset(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ fs->dirbuf[XDIR_Attr] = AM_ARC; st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); fs->dirbuf[XDIR_GenFlags] = 1; @@ -3849,17 +3792,17 @@ FRESULT f_open ( fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } #if FF_USE_FASTSEEK - fp->cltbl = 0; /* Disable fast seek mode */ + fp->cltbl = 0; /* Disable fast seek mode */ #endif - fp->obj.fs = fs; /* Validate the file object */ + fp->obj.fs = fs; /* Validate the file object */ fp->obj.id = fs->id; - fp->flag = mode; /* Set file access mode */ - fp->err = 0; /* Clear error flag */ - fp->sect = 0; /* Invalidate current data sector */ - fp->fptr = 0; /* Set file pointer top of the file */ + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ #if !FF_FS_READONLY #if !FF_FS_TINY - mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ + memset(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 */ @@ -3882,6 +3825,9 @@ FRESULT f_open ( #endif } } +#if FF_FS_LOCK != 0 + if (res != FR_OK) dec_lock(fp->obj.lockid); /* Decrement file open counter if seek failed */ +#endif } #endif } @@ -3902,10 +3848,10 @@ FRESULT f_open ( /*-----------------------------------------------------------------------*/ FRESULT f_read ( - FIL* fp, /* Pointer to the file object */ - void* buff, /* Pointer to data buffer */ + FIL* fp, /* Open file to be read */ + void* buff, /* Data buffer to store the read data */ UINT btr, /* Number of bytes to read */ - UINT* br /* Pointer to number of bytes read */ + UINT* br /* Number of bytes read */ ) { FRESULT res; @@ -3924,8 +3870,7 @@ FRESULT f_read ( remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ - for ( ; btr; /* Repeat until btr bytes read */ - btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { + for ( ; btr > 0; btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { /* Repeat until btr bytes read */ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ @@ -3957,11 +3902,11 @@ FRESULT f_read ( #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { - mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + memcpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } #else if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { - mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + memcpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); } #endif #endif @@ -3985,9 +3930,9 @@ FRESULT f_read ( if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ - mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ + memcpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else - mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ + memcpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #endif } @@ -4003,10 +3948,10 @@ FRESULT f_read ( /*-----------------------------------------------------------------------*/ FRESULT f_write ( - FIL* fp, /* Pointer to the file object */ - const void* buff, /* Pointer to the data to be written */ + FIL* fp, /* Open file to be written */ + const void* buff, /* Data to be written */ UINT btw, /* Number of bytes to write */ - UINT* bw /* Pointer to number of bytes written */ + UINT* bw /* Number of bytes written */ ) { FRESULT res; @@ -4027,8 +3972,7 @@ FRESULT f_write ( btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } - for ( ; btw; /* Repeat until all data written */ - btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { + for ( ; btw > 0; btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { /* Repeat until all data written */ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ @@ -4073,12 +4017,12 @@ FRESULT f_write ( #if FF_FS_MINIMIZE <= 2 #if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + memcpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); fs->wflag = 0; } #else if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + memcpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); fp->flag &= (BYTE)~FA_DIRTY; } #endif @@ -4104,10 +4048,10 @@ FRESULT f_write ( if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ - mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + memcpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; #else - mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + memcpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fp->flag |= FA_DIRTY; #endif } @@ -4125,7 +4069,7 @@ FRESULT f_write ( /*-----------------------------------------------------------------------*/ FRESULT f_sync ( - FIL* fp /* Pointer to the file object */ + FIL* fp /* Open file to be synced */ ) { FRESULT res; @@ -4206,7 +4150,7 @@ FRESULT f_sync ( /*-----------------------------------------------------------------------*/ FRESULT f_close ( - FIL* fp /* Pointer to the file object to be closed */ + FIL* fp /* Open file to be closed */ ) { FRESULT res; @@ -4307,7 +4251,7 @@ FRESULT f_chdir ( } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; -#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ +#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed if in Unix style volume ID */ if (res == FR_OK) { for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ CurrVol = (BYTE)i; @@ -4431,7 +4375,8 @@ FRESULT f_lseek ( LBA_t nsect; FSIZE_t ifptr; #if FF_USE_FASTSEEK - DWORD cl, pcl, ncl, tcl, tlen, ulen, *tbl; + DWORD cl, pcl, ncl, tcl, tlen, ulen; + DWORD *tbl; LBA_t dsc; #endif @@ -4876,9 +4821,11 @@ FRESULT f_getfree ( } while (--clst); } } - *nclst = nfree; /* Return the free clusters */ - fs->free_clst = nfree; /* Now free_clst is valid */ - fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ + if (res == FR_OK) { /* Update parameters if succeeded */ + *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ + } } } @@ -4989,12 +4936,12 @@ FRESULT f_unlink ( } if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ #if FF_FS_RPATH != 0 - if (dclst == fs->cdir) { /* Is it the current directory? */ + if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { - sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.fs = fs; /* Open the sub-directory */ sdj.obj.sclust = dclst; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { @@ -5069,12 +5016,12 @@ FRESULT f_mkdir ( 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 */ + memset(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 */ + memcpy(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; @@ -5138,21 +5085,21 @@ FRESULT f_rename ( if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); - res = follow_path(&djo, path_old); /* Check old object */ + res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ #if FF_FS_LOCK != 0 if (res == FR_OK) { res = chk_lock(&djo, 2); } #endif - if (res == FR_OK) { /* Object to be renamed is found */ + if (res == FR_OK) { /* Object to be renamed is found */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ BYTE nf, nn; WORD nh; - mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ - mem_cpy(&djn, &djo, sizeof djo); + memcpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + memcpy(&djn, &djo, sizeof djo); res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; @@ -5162,7 +5109,7 @@ FRESULT f_rename ( if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); - mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ + memcpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ @@ -5173,8 +5120,8 @@ FRESULT f_rename ( } else #endif { /* At FAT/FAT32 volume */ - mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ - mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + memcpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ + memcpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; @@ -5183,7 +5130,7 @@ FRESULT f_rename ( res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { dir = djn.dir; /* Copy directory entry of the object except name */ - mem_cpy(dir + 13, buf + 13, SZDIRE - 13); + memcpy(dir + 13, buf + 13, SZDIRE - 13); dir[DIR_Attr] = buf[DIR_Attr]; if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; @@ -5349,15 +5296,16 @@ FRESULT f_getlabel ( #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { WCHAR hs; + UINT nw; for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ wc = ld_word(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue; } - wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); - if (wc == 0) { di = 0; break; } - di += wc; + nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4); /* Store it in API encoding */ + if (nw == 0) { di = 0; break; } /* Encode error? */ + di += nw; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ @@ -5370,10 +5318,9 @@ FRESULT f_getlabel ( wc = dj.dir[si++]; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ - wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ - if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ - if (wc == 0) { di = 0; break; } - di += wc; + wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ + if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */ + di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; #endif @@ -5431,7 +5378,7 @@ FRESULT f_setlabel ( BYTE dirvn[22]; UINT di; WCHAR wc; - static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ + static const char badchr[18] = "+.,;=[]" "/*:<>|\\\"\?\x7F"; /* [0..16] for FAT, [7..16] for exFAT */ #if FF_USE_LFN DWORD dc; #endif @@ -5442,7 +5389,7 @@ FRESULT f_setlabel ( #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ - mem_set(dirvn, 0, 22); + memset(dirvn, 0, 22); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ dc = tchar2uni(&label); /* Get a Unicode character */ @@ -5453,7 +5400,7 @@ FRESULT f_setlabel ( st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; } } - if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ + if (dc == 0 || strchr(&badchr[7], (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } st_word(dirvn + di * 2, (WCHAR)dc); di++; @@ -5461,7 +5408,7 @@ FRESULT f_setlabel ( } else #endif { /* On the FAT/FAT32 volume */ - mem_set(dirvn, ' ', 11); + memset(dirvn, ' ', 11); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ #if FF_USE_LFN @@ -5477,7 +5424,7 @@ FRESULT f_setlabel ( if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #endif #endif - if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + if (wc == 0 || strchr(&badchr[0], (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); @@ -5495,10 +5442,10 @@ FRESULT f_setlabel ( if (res == FR_OK) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ - mem_cpy(dj.dir + XDIR_Label, dirvn, 22); + memcpy(dj.dir + XDIR_Label, dirvn, 22); } else { if (di != 0) { - mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ + memcpy(dj.dir, dirvn, 11); /* Change the volume label */ } else { dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ } @@ -5511,14 +5458,14 @@ FRESULT f_setlabel ( if (di != 0) { /* Create a volume label entry */ res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { - mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ + memset(dj.dir, 0, SZDIRE); /* Clean the entry */ if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ dj.dir[XDIR_NumLabel] = (BYTE)di; - mem_cpy(dj.dir + XDIR_Label, dirvn, 22); + memcpy(dj.dir + XDIR_Label, dirvn, 22); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ - mem_cpy(dj.dir, dirvn, 11); + memcpy(dj.dir, dirvn, 11); } fs->wflag = 1; res = sync_fs(fs); @@ -5655,8 +5602,7 @@ FRESULT f_forward ( remain = fp->obj.objsize - fp->fptr; if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ - for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ - fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { + for ( ; btf > 0 && (*func)(0, 0); fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { /* Repeat until all data transferred or stream goes busy */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ if (csect == 0) { /* On the cluster boundary? */ @@ -5700,7 +5646,7 @@ FRESULT f_forward ( #if !FF_FS_READONLY && FF_USE_MKFS /*-----------------------------------------------------------------------*/ -/* Create FAT/exFAT volume */ +/* Create FAT/exFAT volume (with sub-functions) */ /*-----------------------------------------------------------------------*/ #define N_SEC_TRACK 63 /* Sectors per track for determination of drive CHS */ @@ -5719,18 +5665,19 @@ static FRESULT create_partition ( { UINT i, cy; LBA_t sz_drv; - DWORD sz_drv32, s_lba32, n_lba32; - BYTE *pte, hd, n_hd, sc, n_sc; + DWORD sz_drv32, nxt_alloc32, sz_part32; + BYTE *pte; + BYTE hd, n_hd, sc, n_sc; - /* Get drive size */ + /* Get physical drive size */ if (disk_ioctl(drv, GET_SECTOR_COUNT, &sz_drv) != RES_OK) return FR_DISK_ERR; #if FF_LBA64 - if (sz_drv >= FF_MIN_GPT) { /* Create partitions in GPT */ + if (sz_drv >= FF_MIN_GPT) { /* Create partitions in GPT format */ WORD ss; - UINT sz_pt, pi, si, ofs; + UINT sz_ptbl, pi, si, ofs; DWORD bcc, rnd, align; - QWORD s_lba64, n_lba64, sz_pool, s_bpt; + QWORD nxt_alloc, sz_part, sz_pool, top_bpt; static const BYTE gpt_mbr[16] = {0x00, 0x00, 0x02, 0x00, 0xEE, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; #if FF_MAX_SS != FF_MIN_SS @@ -5739,103 +5686,103 @@ static FRESULT create_partition ( #else ss = FF_MAX_SS; #endif - rnd = GET_FATTIME(); /* Random seed */ - align = GPT_ALIGN / ss; /* Partition alignment [sector] */ - sz_pt = GPT_ITEMS * SZ_GPTE / ss; /* Size of PT [sector] */ - s_bpt = sz_drv - sz_pt - 1; /* Backup PT start sector */ - s_lba64 = 2 + sz_pt; /* First allocatable sector */ - sz_pool = s_bpt - s_lba64; /* Size of allocatable area */ - bcc = 0xFFFFFFFF; n_lba64 = 1; + rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ + align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ + sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partiiton table start sector */ + nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ + sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ + bcc = 0xFFFFFFFF; sz_part = 1; pi = si = 0; /* partition table index, size table index */ do { - if (pi * SZ_GPTE % ss == 0) mem_set(buf, 0, ss); /* Clean the buffer if needed */ - if (n_lba64 != 0) { /* Is the size table not termintated? */ - s_lba64 = (s_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition start */ - n_lba64 = plst[si++]; /* Get a partition size */ - if (n_lba64 <= 100) { /* Is the size in percentage? */ - n_lba64 = sz_pool * n_lba64 / 100; - n_lba64 = (n_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ + if (pi * SZ_GPTE % ss == 0) memset(buf, 0, ss); /* Clean the buffer if needed */ + if (sz_part != 0) { /* Is the size table not termintated? */ + nxt_alloc = (nxt_alloc + align - 1) & ((QWORD)0 - align); /* Align partition start */ + sz_part = plst[si++]; /* Get a partition size */ + if (sz_part <= 100) { /* Is the size in percentage? */ + sz_part = sz_pool * sz_part / 100; + sz_part = (sz_part + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ } - if (s_lba64 + n_lba64 > s_bpt) { /* Clip at end of the pool */ - n_lba64 = (s_lba64 < s_bpt) ? s_bpt - s_lba64 : 0; + if (nxt_alloc + sz_part > top_bpt) { /* Clip the size at end of the pool */ + sz_part = (nxt_alloc < top_bpt) ? top_bpt - nxt_alloc : 0; } } - if (n_lba64 != 0) { /* Add a partition? */ + if (sz_part != 0) { /* Add a partition? */ ofs = pi * SZ_GPTE % ss; - mem_cpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Partition GUID (Microsoft Basic Data) */ - rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Unique partition GUID */ - st_qword(buf + ofs + GPTE_FstLba, s_lba64); /* Partition start LBA */ - st_qword(buf + ofs + GPTE_LstLba, s_lba64 + n_lba64 - 1); /* Partition end LBA */ - s_lba64 += n_lba64; /* Next partition LBA */ + memcpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Set partition GUID (Microsoft Basic Data) */ + rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Set unique partition GUID */ + st_qword(buf + ofs + GPTE_FstLba, nxt_alloc); /* Set partition start sector */ + st_qword(buf + ofs + GPTE_LstLba, nxt_alloc + sz_part - 1); /* Set partition end sector */ + nxt_alloc += sz_part; /* Next allocatable sector */ } if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ for (i = 0; i < ss; bcc = crc32(bcc, buf[i++])) ; /* Calculate table check sum */ - if (disk_write(drv, buf, 2 + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Primary table */ - if (disk_write(drv, buf, s_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Secondary table */ + if (disk_write(drv, buf, 2 + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Write to primary table */ + if (disk_write(drv, buf, top_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Write to secondary table */ } } while (++pi < GPT_ITEMS); /* Create primary GPT header */ - mem_set(buf, 0, ss); - mem_cpy(buf + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16); /* Signature, version (1.0) and size (92) */ - st_dword(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ - st_qword(buf + GPTH_CurLba, 1); /* LBA of this header */ - st_qword(buf + GPTH_BakLba, sz_drv - 1); /* LBA of another header */ - st_qword(buf + GPTH_FstLba, 2 + sz_pt); /* LBA of first allocatable sector */ - st_qword(buf + GPTH_LstLba, s_bpt - 1); /* LBA of last allocatable sector */ - st_dword(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ - st_dword(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ - st_dword(buf + GPTH_PtOfs, 2); /* LBA of this table */ + memset(buf, 0, ss); + memcpy(buf + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16); /* Signature, version (1.0) and size (92) */ + st_dword(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ + st_qword(buf + GPTH_CurLba, 1); /* LBA of this header */ + st_qword(buf + GPTH_BakLba, sz_drv - 1); /* LBA of secondary header */ + st_qword(buf + GPTH_FstLba, 2 + sz_ptbl); /* LBA of first allocatable sector */ + st_qword(buf + GPTH_LstLba, top_bpt - 1); /* LBA of last allocatable sector */ + st_dword(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ + st_dword(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ + st_dword(buf + GPTH_PtOfs, 2); /* LBA of this table */ rnd = make_rand(rnd, buf + GPTH_DskGuid, 16); /* Disk GUID */ for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ - st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ + st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ if (disk_write(drv, buf, 1, 1) != RES_OK) return FR_DISK_ERR; /* Create secondary GPT header */ - st_qword(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ - st_qword(buf + GPTH_BakLba, 1); /* LBA of another header */ - st_qword(buf + GPTH_PtOfs, s_bpt); /* LBA of this table */ + st_qword(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ + st_qword(buf + GPTH_BakLba, 1); /* LBA of primary header */ + st_qword(buf + GPTH_PtOfs, top_bpt); /* LBA of this table */ st_dword(buf + GPTH_Bcc, 0); for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ - st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ + st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ if (disk_write(drv, buf, sz_drv - 1, 1) != RES_OK) return FR_DISK_ERR; /* Create protective MBR */ - mem_set(buf, 0, ss); - mem_cpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ + memset(buf, 0, ss); + memcpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ st_word(buf + BS_55AA, 0xAA55); if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; } else #endif - { /* Create partitions in MBR */ + { /* Create partitions in MBR format */ sz_drv32 = (DWORD)sz_drv; - n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry */ + n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry */ for (n_hd = 8; n_hd != 0 && sz_drv32 / n_hd / n_sc > 1024; n_hd *= 2) ; - if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */ + if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */ - mem_set(buf, 0, FF_MAX_SS); /* Clear MBR */ + memset(buf, 0, FF_MAX_SS); /* Clear MBR */ pte = buf + MBR_Table; /* Partition table in the MBR */ - for (i = 0, s_lba32 = n_sc; i < 4 && s_lba32 != 0 && s_lba32 < sz_drv32; i++, s_lba32 += n_lba32) { - n_lba32 = (DWORD)plst[i]; /* Get partition size */ - if (n_lba32 <= 100) n_lba32 = (n_lba32 == 100) ? sz_drv32 : sz_drv32 / 100 * n_lba32; /* Size in percentage? */ - if (s_lba32 + n_lba32 > sz_drv32 || s_lba32 + n_lba32 < s_lba32) n_lba32 = sz_drv32 - s_lba32; /* Clip at drive size */ - if (n_lba32 == 0) break; /* End of table or no sector to allocate? */ + for (i = 0, nxt_alloc32 = n_sc; i < 4 && nxt_alloc32 != 0 && nxt_alloc32 < sz_drv32; i++, nxt_alloc32 += sz_part32) { + sz_part32 = (DWORD)plst[i]; /* Get partition size */ + if (sz_part32 <= 100) sz_part32 = (sz_part32 == 100) ? sz_drv32 : sz_drv32 / 100 * sz_part32; /* Size in percentage? */ + if (nxt_alloc32 + sz_part32 > sz_drv32 || nxt_alloc32 + sz_part32 < nxt_alloc32) sz_part32 = sz_drv32 - nxt_alloc32; /* Clip at drive size */ + if (sz_part32 == 0) break; /* End of table or no sector to allocate? */ - st_dword(pte + PTE_StLba, s_lba32); /* Start LBA */ - st_dword(pte + PTE_SizLba, n_lba32); /* Number of sectors */ + st_dword(pte + PTE_StLba, nxt_alloc32); /* Start LBA */ + st_dword(pte + PTE_SizLba, sz_part32); /* Number of sectors */ pte[PTE_System] = sys; /* System type */ - cy = (UINT)(s_lba32 / n_sc / n_hd); /* Start cylinder */ - hd = (BYTE)(s_lba32 / n_sc % n_hd); /* Start head */ - sc = (BYTE)(s_lba32 % n_sc + 1); /* Start sector */ + cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Start cylinder */ + hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Start head */ + sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Start sector */ pte[PTE_StHead] = hd; pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_StCyl] = (BYTE)cy; - cy = (UINT)((s_lba32 + n_lba32 - 1) / n_sc / n_hd); /* End cylinder */ - hd = (BYTE)((s_lba32 + n_lba32 - 1) / n_sc % n_hd); /* End head */ - sc = (BYTE)((s_lba32 + n_lba32 - 1) % n_sc + 1); /* End sector */ + cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* End cylinder */ + hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* End head */ + sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* End sector */ pte[PTE_EdHead] = hd; pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_EdCyl] = (BYTE)cy; @@ -5864,7 +5811,7 @@ FRESULT f_mkfs ( static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; WORD ss; /* Sector size */ - DWORD sz_buf, sz_blk, n_clst, pau, nsect, n; + DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ LBA_t sect, lba[2]; DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */ @@ -5930,7 +5877,7 @@ FRESULT f_mkfs ( ofs = i = 0; while (n_ent) { /* Find MS Basic partition with order of ipart */ if (ofs == 0 && disk_read(pdrv, buf, pt_lba++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Get PT sector */ - if (!mem_cmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */ + if (!memcmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */ b_vol = ld_qword(buf + ofs + GPTE_FstLba); sz_vol = ld_qword(buf + ofs + GPTE_LstLba) - b_vol + 1; break; @@ -5966,7 +5913,7 @@ FRESULT f_mkfs ( } if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ - /* Now start to create a FAT volume at b_vol and sz_vol */ + /* Now start to create an FAT volume at b_vol and sz_vol */ do { /* Pre-determine the FAT type */ if (FF_FS_EXFAT && (fsopt & FM_EXFAT)) { /* exFAT possible? */ @@ -5987,6 +5934,8 @@ FRESULT f_mkfs ( fsty = FS_FAT16; } while (0); + vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN generated from current time and partitiion size */ + #if FF_FS_EXFAT if (fsty == FS_EXFAT) { /* Create an exFAT volume */ DWORD szb_bit, szb_case, sum, nbit, clu, clen[3]; @@ -6041,7 +5990,7 @@ FRESULT f_mkfs ( ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } - sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; if (si == 0 || i == sz_buf * ss) { /* Write buffered data when buffer full or end of process */ @@ -6057,7 +6006,7 @@ FRESULT f_mkfs ( sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of bitmap sectors */ nbit = clen[0] + clen[1] + clen[2]; /* Number of clusters in-use by system (bitmap, up-case and root-dir) */ do { - mem_set(buf, 0, sz_buf * ss); /* Initialize bitmap buffer */ + memset(buf, 0, sz_buf * ss); /* Initialize bitmap buffer */ for (i = 0; nbit != 0 && i / 8 < sz_buf * ss; buf[i / 8] |= 1 << (i % 8), i++, nbit--) ; /* Mark used clusters */ n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); @@ -6068,7 +6017,7 @@ FRESULT f_mkfs ( sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ j = nbit = clu = 0; do { - mem_set(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write offset */ + memset(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write offset */ if (clu == 0) { /* Initialize FAT [0] and FAT[1] */ st_dword(buf + i, 0xFFFFFFF8); i += 4; clu++; st_dword(buf + i, 0xFFFFFFFF); i += 4; clu++; @@ -6086,20 +6035,20 @@ FRESULT f_mkfs ( } while (nsect); /* Initialize the root directory */ - mem_set(buf, 0, sz_buf * ss); - buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ - 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] = ET_UPCASE; /* Up-case table entry */ - st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ - st_dword(buf + SZDIRE * 2 + 20, 2 + clen[0]); /* cluster */ - st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ + memset(buf, 0, sz_buf * ss); + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ + 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] = ET_UPCASE; /* Up-case table entry */ + st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_dword(buf + SZDIRE * 2 + 20, 2 + clen[0]); /* cluster */ + st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + sz_au * (clen[0] + clen[1]); nsect = sz_au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - mem_set(buf, 0, ss); /* Rest of entries are filled with zero */ + memset(buf, 0, ss); /* Rest of entries are filled with zero */ sect += n; nsect -= n; } while (nsect); @@ -6107,8 +6056,8 @@ FRESULT f_mkfs ( sect = b_vol; for (n = 0; n < 2; n++) { /* Main record (+0) */ - mem_set(buf, 0, ss); - mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + memset(buf, 0, ss); + memcpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ st_qword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ st_qword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ st_dword(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ @@ -6116,7 +6065,7 @@ FRESULT f_mkfs ( st_dword(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root dir cluster # */ - st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ + st_dword(buf + BPB_VolIDEx, vsn); /* VSN */ st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ for (buf[BPB_SecPerClusEx] = 0, i = sz_au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ @@ -6129,14 +6078,14 @@ FRESULT f_mkfs ( } if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ - mem_set(buf, 0, ss); + memset(buf, 0, ss); st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* OEM/Reserved record (+9..+10) */ - mem_set(buf, 0, ss); + memset(buf, 0, ss); for ( ; j < 11; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); @@ -6204,7 +6153,7 @@ FRESULT f_mkfs ( if (fsty == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ if (sz_au == 0 && (pau * 2) <= 64) { - sz_au = pau * 2; continue; /* Adjust cluster size and retry */ + sz_au = pau * 2; continue; /* Adjust cluster size and retry */ } if ((fsopt & FM_FAT32)) { fsty = FS_FAT32; continue; /* Switch type to FAT32 and retry */ @@ -6228,8 +6177,8 @@ FRESULT f_mkfs ( disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Create FAT VBR */ - mem_set(buf, 0, ss); - mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + memset(buf, 0, ss); + memcpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11); /* Boot jump code (x86), OEM name */ st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ @@ -6245,20 +6194,20 @@ FRESULT f_mkfs ( st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ st_dword(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ if (fsty == FS_FAT32) { - st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BS_VolID32, vsn); /* VSN */ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + memcpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { - st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ + st_dword(buf + BS_VolID, vsn); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + memcpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ @@ -6266,7 +6215,7 @@ FRESULT f_mkfs ( /* Create FSINFO record if needed */ if (fsty == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ - mem_set(buf, 0, ss); + memset(buf, 0, ss); st_dword(buf + FSI_LeadSig, 0x41615252); st_dword(buf + FSI_StrucSig, 0x61417272); st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ @@ -6277,7 +6226,7 @@ FRESULT f_mkfs ( } /* Initialize FAT area */ - mem_set(buf, 0, sz_buf * ss); + memset(buf, 0, sz_buf * ss); sect = b_fat; /* FAT start sector */ for (i = 0; i < n_fat; i++) { /* Initialize FATs each */ if (fsty == FS_FAT32) { @@ -6291,7 +6240,7 @@ FRESULT f_mkfs ( do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - mem_set(buf, 0, ss); /* Rest of FAT all are cleared */ + memset(buf, 0, ss); /* Rest of FAT all are cleared */ sect += n; nsect -= n; } while (nsect); } @@ -6331,8 +6280,8 @@ FRESULT f_mkfs ( if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } } else { /* Volume as a new single partition */ - if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ - lba[0] = sz_vol, lba[1] = 0; + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ + lba[0] = sz_vol; lba[1] = 0; fr = create_partition(pdrv, lba, sys, buf); if (fr != FR_OK) LEAVE_MKFS(fr); } @@ -6415,12 +6364,12 @@ TCHAR* f_gets ( if (rc != 1) break; /* EOF? */ wc = s[0]; if (dbc_1st((BYTE)wc)) { /* DBC 1st byte? */ - f_read(fp, s, 1, &rc); /* Get DBC 2nd byte */ + f_read(fp, s, 1, &rc); /* Get 2nd byte */ if (rc != 1 || !dbc_2nd(s[0])) continue; /* Wrong code? */ wc = wc << 8 | s[0]; } - dc = ff_oem2uni(wc, CODEPAGE); /* OEM --> */ - if (dc == 0) continue; + dc = ff_oem2uni(wc, CODEPAGE); /* Convert ANSI/OEM into Unicode */ + if (dc == 0) continue; /* Conversion error? */ #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ f_read(fp, s, 2, &rc); /* Get a code unit */ if (rc != 2) break; /* EOF? */ @@ -6443,7 +6392,7 @@ TCHAR* f_gets ( if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ if (ct == 0) continue; - f_read(fp, s, ct, &rc); /* Get trailing bytes */ + f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; rc = 0; do { /* Merge the byte sequence */ @@ -6512,11 +6461,14 @@ TCHAR* f_gets ( #if !FF_FS_READONLY #include +#define SZ_PUTC_BUF 64 +#define SZ_NUM_BUF 32 + /*-----------------------------------------------------------------------*/ -/* Put a Character to the File (sub-functions) */ +/* Put a Character to the File (with sub-functions) */ /*-----------------------------------------------------------------------*/ -/* Putchar output buffer and work area */ +/* Output buffer and work area */ typedef struct { FIL *fp; /* Ptr to the writing file */ @@ -6527,11 +6479,11 @@ typedef struct { BYTE bs[4]; UINT wi, ct; #endif - BYTE buf[64]; /* Write buffer */ + BYTE buf[SZ_PUTC_BUF]; /* Write buffer */ } putbuff; -/* Buffered write with code conversion */ +/* Buffered file write with code conversion */ static void putc_bfd (putbuff* pb, TCHAR c) { @@ -6550,7 +6502,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) } i = pb->idx; /* Write index of pb->buf[] */ - if (i < 0) return; + if (i < 0) return; /* In write error? */ nc = pb->nchr; /* Write unit counter */ #if FF_USE_LFN && FF_LFN_UNICODE @@ -6649,7 +6601,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) pb->buf[i++] = (BYTE)wc; #endif -#else /* ANSI/OEM input (without re-encoding) */ +#else /* ANSI/OEM input (without re-encoding) */ pb->buf[i++] = (BYTE)c; #endif @@ -6679,7 +6631,7 @@ static int putc_flush (putbuff* pb) static void putc_init (putbuff* pb, FIL* fp) { - mem_set(pb, 0, sizeof (putbuff)); + memset(pb, 0, sizeof (putbuff)); pb->fp = fp; } @@ -6722,8 +6674,129 @@ int f_puts ( /*-----------------------------------------------------------------------*/ -/* Put a Formatted String to the File */ +/* Put a Formatted String to the File (with sub-functions) */ /*-----------------------------------------------------------------------*/ +#if FF_PRINT_FLOAT && FF_INTDEF == 2 +#include + +static int ilog10 (double n) /* Calculate log10(n) in integer output */ +{ + int rv = 0; + + while (n >= 10) { /* Decimate digit in right shift */ + if (n >= 100000) { + n /= 100000; rv += 5; + } else { + n /= 10; rv++; + } + } + while (n < 1) { /* Decimate digit in left shift */ + if (n < 0.00001) { + n *= 100000; rv -= 5; + } else { + n *= 10; rv--; + } + } + return rv; +} + + +static double i10x (int n) /* Calculate 10^n in integer input */ +{ + double rv = 1; + + while (n > 0) { /* Left shift */ + if (n >= 5) { + rv *= 100000; n -= 5; + } else { + rv *= 10; n--; + } + } + while (n < 0) { /* Right shift */ + if (n <= -5) { + rv /= 100000; n += 5; + } else { + rv /= 10; n++; + } + } + return rv; +} + + +static void ftoa ( + char* buf, /* Buffer to output the floating point string */ + double val, /* Value to output */ + int prec, /* Number of fractional digits */ + TCHAR fmt /* Notation */ +) +{ + int d; + int e = 0, m = 0; + char sign = 0; + double w; + const char *er = 0; + const char ds = FF_PRINT_FLOAT == 2 ? ',' : '.'; + + + if (isnan(val)) { /* Not a number? */ + er = "NaN"; + } else { + if (prec < 0) prec = 6; /* Default precision? (6 fractional digits) */ + if (val < 0) { /* Nagative? */ + val = 0 - val; sign = '-'; + } else { + sign = '+'; + } + if (isinf(val)) { /* Infinite? */ + er = "INF"; + } else { + if (fmt == 'f') { /* Decimal notation? */ + val += i10x(0 - prec) / 2; /* Round (nearest) */ + m = ilog10(val); + if (m < 0) m = 0; + if (m + prec + 3 >= SZ_NUM_BUF) er = "OV"; /* Buffer overflow? */ + } else { /* E notation */ + if (val != 0) { /* Not a true zero? */ + val += i10x(ilog10(val) - prec) / 2; /* Round (nearest) */ + e = ilog10(val); + if (e > 99 || prec + 7 >= SZ_NUM_BUF) { /* Buffer overflow or E > +99? */ + er = "OV"; + } else { + if (e < -99) e = -99; + val /= i10x(e); /* Normalize */ + } + } + } + } + if (!er) { /* Not error condition */ + if (sign == '-') *buf++ = sign; /* Add a - if negative value */ + do { /* Put decimal number */ + if (m == -1) *buf++ = ds; /* Insert a decimal separator when get into fractional part */ + w = i10x(m); /* Snip the highest digit d */ + d = (int)(val / w); val -= d * w; + *buf++ = (char)('0' + d); /* Put the digit */ + } while (--m >= -prec); /* Output all digits specified by prec */ + if (fmt != 'f') { /* Put exponent if needed */ + *buf++ = (char)fmt; + if (e < 0) { + e = 0 - e; *buf++ = '-'; + } else { + *buf++ = '+'; + } + *buf++ = (char)('0' + e / 10); + *buf++ = (char)('0' + e % 10); + } + } + } + if (er) { /* Error condition */ + if (sign) *buf++ = sign; /* Add sign if needed */ + do *buf++ = *er++; while (*er); /* Put error symbol */ + } + *buf = 0; /* Term */ +} +#endif /* FF_PRINT_FLOAT && FF_INTDEF == 2 */ + + int f_printf ( FIL* fp, /* Pointer to the file object */ @@ -6733,10 +6806,16 @@ int f_printf ( { va_list arp; putbuff pb; - BYTE f, r; - UINT i, j, w; + UINT i, j, w, f, r; + int prec; +#if FF_PRINT_LLI && FF_INTDEF == 2 + QWORD v; +#else DWORD v; - TCHAR c, d, str[32], *p; +#endif + TCHAR tc, pad, *tp; + TCHAR nul = 0; + char d, str[SZ_NUM_BUF]; putc_init(&pb, fp); @@ -6744,93 +6823,122 @@ int f_printf ( va_start(arp, fmt); for (;;) { - c = *fmt++; - if (c == 0) break; /* End of string */ - if (c != '%') { /* Non escape character */ - putc_bfd(&pb, c); + tc = *fmt++; + if (tc == 0) break; /* End of format string */ + if (tc != '%') { /* Not an escape character (pass-through) */ + putc_bfd(&pb, tc); continue; } - w = f = 0; - c = *fmt++; - if (c == '0') { /* Flag: '0' padding */ - f = 1; c = *fmt++; - } else { - if (c == '-') { /* Flag: left justified */ - f = 2; c = *fmt++; - } + f = w = 0; pad = ' '; prec = -1; /* Initialize parms */ + tc = *fmt++; + if (tc == '0') { /* Flag: '0' padded */ + pad = '0'; tc = *fmt++; + } else if (tc == '-') { /* Flag: Left aligned */ + f = 2; tc = *fmt++; } - if (c == '*') { /* Minimum width by argument */ + if (tc == '*') { /* Minimum width from an argument */ w = va_arg(arp, int); - c = *fmt++; + tc = *fmt++; } else { - while (IsDigit(c)) { /* Minimum width */ - w = w * 10 + c - '0'; - c = *fmt++; + while (IsDigit(tc)) { /* Minimum width */ + w = w * 10 + tc - '0'; + tc = *fmt++; } } - if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ - f |= 4; c = *fmt++; - } - if (c == 0) break; - d = c; - if (IsLower(d)) d -= 0x20; - switch (d) { /* Atgument type is... */ - case 'S': /* String */ - p = va_arg(arp, TCHAR*); - for (j = 0; p[j]; j++) ; - if (!(f & 2)) { /* Right padded */ - while (j++ < w) putc_bfd(&pb, ' ') ; + if (tc == '.') { /* Precision */ + tc = *fmt++; + if (tc == '*') { /* Precision from an argument */ + prec = va_arg(arp, int); + tc = *fmt++; + } else { + prec = 0; + while (IsDigit(tc)) { /* Precision */ + prec = prec * 10 + tc - '0'; + tc = *fmt++; + } } - while (*p) putc_bfd(&pb, *p++) ; /* String body */ - while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ - continue; - - case 'C': /* Character */ + } + if (tc == 'l') { /* Size: long int */ + f |= 4; tc = *fmt++; +#if FF_PRINT_LLI && FF_INTDEF == 2 + if (tc == 'l') { /* Size: long long int */ + f |= 8; tc = *fmt++; + } +#endif + } + if (tc == 0) break; /* End of format string */ + switch (tc) { /* Atgument type is... */ + case 'b': /* Unsigned binary */ + r = 2; break; + case 'o': /* Unsigned octal */ + r = 8; break; + case 'd': /* Signed decimal */ + case 'u': /* Unsigned decimal */ + r = 10; break; + case 'x': /* Unsigned hexdecimal (lower case) */ + case 'X': /* Unsigned hexdecimal (upper case) */ + r = 16; break; + case 'c': /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; - - case 'B': /* Unsigned binary */ - r = 2; - break; - - case 'O': /* Unsigned octal */ - r = 8; - break; - - case 'D': /* Signed decimal */ - case 'U': /* Unsigned decimal */ - r = 10; - break; - - case 'X': /* Unsigned hexdecimal */ - r = 16; - break; - + case 's': /* String */ + tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ + if (!tp) tp = &nul; /* Null ptr generates a null string */ + for (j = 0; tp[j]; j++) ; /* j = tcslen(tp) */ + if (prec >= 0 && j > (UINT)prec) j = prec; /* Limited length of string body */ + for ( ; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + while (*tp && prec--) putc_bfd(&pb, *tp++); /* Body */ + while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + continue; +#if FF_PRINT_FLOAT && FF_INTDEF == 2 + case 'f': /* Floating point (decimal) */ + case 'e': /* Floating point (e) */ + case 'E': /* Floating point (E) */ + ftoa(str, va_arg(arp, double), prec, tc); /* Make a flaoting point string */ + for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ + while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + continue; +#endif default: /* Unknown type (pass-through) */ - putc_bfd(&pb, c); continue; + putc_bfd(&pb, tc); continue; } - /* Get an argument and put it in numeral */ - v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); - if (d == 'D' && (v & 0x80000000)) { - v = 0 - v; - f |= 8; + /* Get an integer argument and put it in numeral */ +#if FF_PRINT_LLI && FF_INTDEF == 2 + if (f & 8) { /* long long argument? */ + v = (QWORD)va_arg(arp, LONGLONG); + } else { + if (f & 4) { /* long argument? */ + v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); + } } + if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ + v = 0 - v; f |= 1; + } +#else + if (f & 4) { /* long argument? */ + v = (DWORD)va_arg(arp, long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int); + } + if (tc == 'd' && (v & 0x80000000)) { /* Negative value? */ + v = 0 - v; f |= 1; + } +#endif i = 0; - do { - d = (TCHAR)(v % r); v /= r; - if (d > 9) d += (c == 'x') ? 0x27 : 0x07; + do { /* Make an integer number string */ + d = (char)(v % r); v /= r; + if (d > 9) d += (tc == 'x') ? 0x27 : 0x07; str[i++] = d + '0'; - } while (v && i < sizeof str / sizeof *str); - if (f & 8) str[i++] = '-'; - j = i; d = (f & 1) ? '0' : ' '; - if (!(f & 2)) { - while (j++ < w) putc_bfd(&pb, d); /* Right pad */ - } - do { - putc_bfd(&pb, str[--i]); /* Number body */ - } while (i); - while (j++ < w) putc_bfd(&pb, d); /* Left pad */ + } while (v && i < SZ_NUM_BUF); + if (f & 1) str[i++] = '-'; /* Sign */ + /* Write it */ + for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */ + while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ } va_end(arp); @@ -6852,8 +6960,8 @@ FRESULT f_setcp ( WORD cp /* Value to be set as active code page */ ) { - static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; - static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + static const WORD validcp[22] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; + static const BYTE* const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; diff --git a/source/ff.h b/source/ff.h index ec9c91e..4866576 100644 --- a/source/ff.h +++ b/source/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.14a / +/ FatFs - Generic FAT Filesystem module R0.14b / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2020, ChaN, all right reserved. +/ Copyright (C) 2021, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,7 +20,7 @@ #ifndef FF_DEFINED -#define FF_DEFINED 80196 /* Revision ID */ +#define FF_DEFINED 86631 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -35,10 +35,14 @@ extern "C" { /* Integer types used for FatFs API */ -#if defined(_WIN32) /* Main development platform */ +#if defined(_WIN32) /* Windows VC++ (for development only) */ #define FF_INTDEF 2 #include typedef unsigned __int64 QWORD; +#include +#define isnan(v) _isnan(v) +#define isinf(v) (!_finite(v)) + #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ #define FF_INTDEF 2 #include @@ -48,6 +52,7 @@ typedef uint16_t WORD; /* 16-bit unsigned integer */ typedef uint32_t DWORD; /* 32-bit unsigned integer */ typedef uint64_t QWORD; /* 64-bit unsigned integer */ typedef WORD WCHAR; /* UTF-16 character type */ + #else /* Earlier than C99 */ #define FF_INTDEF 1 typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ @@ -58,28 +63,29 @@ typedef WORD WCHAR; /* UTF-16 character type */ #endif -/* Definitions of volume management */ +/* Type of file size and LBA variables */ -#if FF_MULTI_PARTITION /* Multiple partition configuration */ -typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ -} PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ +#if FF_FS_EXFAT +#if FF_INTDEF != 2 +#error exFAT feature wants C99 or later #endif - -#if FF_STR_VOLUME_ID -#ifndef FF_VOLUME_STRS -extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +typedef QWORD FSIZE_t; +#if FF_LBA64 +typedef QWORD LBA_t; +#else +typedef DWORD LBA_t; #endif +#else +#if FF_LBA64 +#error exFAT needs to be enabled when enable 64-bit LBA +#endif +typedef DWORD FSIZE_t; +typedef DWORD LBA_t; #endif -/* Type of path name strings on FatFs API */ - -#ifndef _INC_TCHAR -#define _INC_TCHAR +/* Type of path name strings on FatFs API (TCHAR) */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ typedef WCHAR TCHAR; @@ -101,28 +107,22 @@ typedef char TCHAR; #define _TEXT(x) x #endif -#endif +/* Definitions of volume management */ -/* Type of file size and LBA variables */ +#if FF_MULTI_PARTITION /* Multiple partition configuration */ +typedef struct { + BYTE pd; /* Physical drive number */ + BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ +} PARTITION; +extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ +#endif -#if FF_FS_EXFAT -#if FF_INTDEF != 2 -#error exFAT feature wants C99 or later +#if FF_STR_VOLUME_ID +#ifndef FF_VOLUME_STRS +extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ #endif -typedef QWORD FSIZE_t; -#if FF_LBA64 -typedef QWORD LBA_t; -#else -typedef DWORD LBA_t; -#endif -#else -#if FF_LBA64 -#error exFAT needs to be enabled when enable 64-bit LBA -#endif -typedef DWORD FSIZE_t; -typedef DWORD LBA_t; #endif diff --git a/source/ffconf.h b/source/ffconf.h index e6beccb..ca17485 100644 --- a/source/ffconf.h +++ b/source/ffconf.h @@ -2,7 +2,7 @@ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 80196 /* Revision ID */ +#define FFCONF_DEF 86631 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -25,14 +25,6 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_STRFUNC 0 -/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). -/ -/ 0: Disable string functions. -/ 1: Enable without LF-CRLF conversion. -/ 2: Enable with LF-CRLF conversion. */ - - #define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ @@ -64,6 +56,30 @@ /* This option switches f_forward() function. (0:Disable or 1:Enable) */ +#define FF_USE_STRFUNC 0 +#define FF_PRINT_LLI 0 +#define FF_PRINT_FLOAT 0 +#define FF_STRF_ENCODE 0 +/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. +/ +/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 + makes f_printf() support floating point argument. These features want C99 or later. +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character +/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE +/ to be read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ @@ -137,19 +153,6 @@ / on character encoding. When LFN is not enabled, these options have no effect. */ -#define FF_STRF_ENCODE 3 -/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), -/ f_putc(), f_puts and f_printf() convert the character encoding in it. -/ This option selects assumption of character encoding ON THE FILE to be -/ read/written via those functions. -/ -/ 0: ANSI/OEM in current CP -/ 1: Unicode in UTF-16LE -/ 2: Unicode in UTF-16BE -/ 3: Unicode in UTF-8 -*/ - - #define FF_FS_RPATH 0 /* This option configures support for relative path. / @@ -194,7 +197,7 @@ #define FF_MAX_SS 512 /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and -/ harddisk. But a larger value may be required for on-board flash memory and some +/ harddisk, but a larger value may be required for on-board flash memory and some / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured / for variable sector size mode and disk_ioctl() function needs to implement / GET_SECTOR_SIZE command. */