From 8e92305484c92f3c0cc9d4cc7a81a830a39c2b56 Mon Sep 17 00:00:00 2001 From: savelij13 Date: Thu, 11 Sep 2025 09:06:19 +0300 Subject: [PATCH] fatfs v0.04a Apr 01, 2007: - Supported multiple partitions on a plysical drive. (FatFs) - Fixed an endian sensitive code in f_mkfs(). (FatFs) - Added a capability of extending the file size to f_lseek(). - Added minimization level 3. - Fixed a problem that can collapse a sector when recreate an - existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs) --- doc/00index_e.html | 59 +-- doc/00index_j.html | 48 +-- doc/css_e.css | 4 +- doc/css_j.css | 4 +- doc/en/appnote.html | 56 ++- doc/en/chmod.html | 10 +- doc/en/close.html | 2 +- doc/en/dioctl.html | 65 +++ doc/en/dread.html | 2 +- doc/en/dwrite.html | 2 +- doc/en/filename.html | 34 +- doc/en/getfree.html | 4 +- doc/en/lseek.html | 13 +- doc/en/mkdir.html | 6 +- doc/en/mkfs.html | 7 +- doc/en/mount.html | 2 +- doc/en/open.html | 9 +- doc/en/opendir.html | 4 +- doc/en/read.html | 2 +- doc/en/readdir.html | 8 +- doc/en/rename.html | 2 +- doc/en/sdir.html | 8 +- doc/en/sfatfs.html | 17 +- doc/en/sfile.html | 12 +- doc/en/stat.html | 4 +- doc/en/sync.html | 2 +- doc/en/unlink.html | 2 +- doc/en/write.html | 2 +- doc/img/f1.png | Bin 1080 -> 1145 bytes doc/img/f2.png | Bin 1351 -> 1458 bytes doc/img/f3.png | Bin 1017 -> 1039 bytes doc/img/f4.png | Bin 2451 -> 2474 bytes doc/img/f5.png | Bin 2593 -> 2433 bytes doc/ja/appnote.html | 57 ++- doc/ja/chmod.html | 4 +- doc/ja/close.html | 2 +- doc/ja/dioctl.html | 64 +++ doc/ja/dread.html | 2 +- doc/ja/dstat.html | 4 +- doc/ja/dwrite.html | 4 +- doc/ja/filename.html | 42 +- doc/ja/getfree.html | 8 +- doc/ja/lseek.html | 16 +- doc/ja/mkdir.html | 6 +- doc/ja/mkfs.html | 19 +- doc/ja/mount.html | 4 +- doc/ja/open.html | 15 +- doc/ja/opendir.html | 4 +- doc/ja/read.html | 6 +- doc/ja/readdir.html | 4 +- doc/ja/rename.html | 8 +- doc/ja/sdir.html | 8 +- doc/ja/sfatfs.html | 17 +- doc/ja/sfile.html | 12 +- doc/ja/stat.html | 4 +- doc/ja/sync.html | 2 +- doc/ja/unlink.html | 2 +- doc/ja/write.html | 6 +- doc/updates.txt | 35 ++ src/00readme.txt | 82 ++-- src/diskio.h | 45 ++- src/ff.c | 926 +++++++++++++++++++++++-------------------- src/ff.h | 177 +++++++-- src/integer.h | 16 +- src/tff.c | 683 +++++++++++++++++-------------- src/tff.h | 129 ++++-- 66 files changed, 1667 insertions(+), 1136 deletions(-) create mode 100644 doc/en/dioctl.html create mode 100644 doc/ja/dioctl.html create mode 100644 doc/updates.txt diff --git a/doc/00index_e.html b/doc/00index_e.html index e525a89..13cef08 100644 --- a/doc/00index_e.html +++ b/doc/00index_e.html @@ -3,11 +3,9 @@ - - -ELM - Generic FAT Files System Module +ELM - Generic FAT File System Module @@ -16,47 +14,22 @@
layer -

FatFs module is an experimental project to implement a FAT file system to small embdded systems. The FatFs module is written in compliance with ANSI C, therefore it is independent of hardware architecture. It can be incorporated into most small microcontrollers, such as 8051, PIC, AVR, H8, Z80 and etc..., without any change. I created two modules in different configurations in consideration of various use. To use the FatFs module, low level disk I/O functions for each media must be provided by user.

+

FatFs module is an experimental project to implement a FAT file system to small embdded systems. The FatFs module is written in compliance with ANSI C, therefore it is independent of hardware architecture. It can be incorporated into most 8-bit microcontrollers, such as 8051, PIC, AVR, H8, Z80 and etc..., without any change. I created two modules in different configurations in consideration of various use.

Features of FatFs Module

- +
    +
  1. Separated buffer for FAT structure and each file, suitable for fast multiple file accsess.
  2. +
  3. Supports multiple drives/partitions.
  4. +
  5. Supports FAT12, FAT16(+FAT64) and FAT32. (FAT64: FAT16 in 64KB/cluster)
  6. +
  7. Supports 8.3 format file name and NT lower case flag. (LFN is not supported)
  8. +
  9. Supports two partitioning rules: FDISK and Super-floppy.
  10. +
  11. Optimized for 8/16-bit microcontrollers.
  12. +

Features of Tiny-FatFs Module (different to FatFs)

- -
- - -
-

Memory Usage

-

There are some configuration options to eliminate unused functions to reduce module size. Following tables are the memory consumption in unit of byte on avr-gcc.

- -
- - - - - - - -
FatFs
SectionStd cfg.Min cfg.
Program (R/W cfg.)85746094
Program (R/O cfg.)42683494
Static Work Area2 + 2*<drives>
Dynamic Work Area550*<drives> + 544*<files>
-
- - - - - - - -
Tiny-FatFs
SectionStd cfg.Min cfg.
Program (R/W cfg.)71644890
Program (R/O cfg.)36602946
Static Work Area4
Dynamic Work Area542 + 28*<files>
+
@@ -86,12 +59,13 @@

Disk I/O Interface

-

Since the FatFs/Tiny-FatFs module is completely separated from disk I/O layer, it requires following functions to lower layer to read/write physical disk and to get current time. These functions must be provided by user.

+

Since the FatFs/Tiny-FatFs module is completely separated from disk I/O layer, it requires following functions to lower layer to read/write physical disk and to get current time. These functions must be provided by user. The low level disk I/O module that have this interace must be provided by user. The sample projects are also available.

@@ -108,8 +82,5 @@ - -
-

Return

diff --git a/doc/00index_j.html b/doc/00index_j.html index 0ebf67f..3d34f9f 100644 --- a/doc/00index_j.html +++ b/doc/00index_j.html @@ -3,8 +3,6 @@ - - ELM - 汎用FATファイルシステム・モジュール @@ -16,46 +14,21 @@
layer -

小規模な組み込みシステム向けの汎用FATファイルシステム・モジュールです。ANSI C準拠でハードウェア・アーキテクチャには依存しないので、必要なワーク・エリアが確保できれば、8051, AVR, H8, Z80などほとんどのマイコンでそのまま使用可能です。いろいろな使用形態を考慮して、高機能版(FatFs)と省メモリ版(Tiny-FatFs)の2通りを作成してみました。実際に使用するには、各記録メディア(CFC, MMC, SDC, ATA, USB, SCSI等)に対応したディスクI/Oモジュール(サンプルあり)を用意する必要があります。

+

小規模な組み込みシステム向けの汎用FATファイルシステム・モジュールです。ANSI C準拠でハードウェア・アーキテクチャには依存しないので、必要なワーク・エリアが確保できれば、8051, PIC, AVR, H8, Z80などほとんどの8ビット・マイコンでそのまま使用可能です。いろいろな使用形態を考慮して、高機能版(FatFs)と省メモリ版(Tiny-FatFs)の2通りを作成してみました。

FatFsの特徴

- +

Tiny-FatFsの特徴(FatFsとの相違)

- -
- - -
-

メモリ使用量

-

いくつかのコンフィギュレーション・オプションにより、不要な関数を削ってモジュール・サイズを削減できます。次に実際のメモリ使用量[バイト]を示します(avrgccの例)。

- -
- - - - - - - -
FatFs
セクション標準最小
プログラム(R/W構成)85746094
プログラム(R/O構成)42683494
静的ワークエリア2 + 2*<drives>
動的ワークエリア550*<drives> + 544*<files>
-
- - - - - - - -
Tiny-FatFs
セクション標準最小
プログラム(R/W構成)71644890
プログラム(R/O構成)36602946
静的ワークエリア4
動的ワークエリア542 + 28*<files>
+
@@ -85,12 +58,13 @@

下位レイヤI/F

-

FatFs/Tiny-FatFsモジュールは、物理ドライブへのアクセスや現在時刻を得るため、下位レイヤに次のインターフェースを要求します。

+

FatFs/Tiny-FatFsモジュールは、物理ドライブへのアクセスや現在時刻を得るため、下位レイヤに次のインターフェースを要求します。これらのインターフェースを持つそれぞれの記録メディアに対応したディスクI/Oモジュールは、ユーザにより用意する必要があります。(サンプルもあり)

@@ -108,7 +82,5 @@ -
-

戻る

diff --git a/doc/css_e.css b/doc/css_e.css index 30da503..881b3c1 100644 --- a/doc/css_e.css +++ b/doc/css_e.css @@ -7,7 +7,8 @@ a:active {color: darkmagenta; position: relative; top: 1px; left: 1px;} abbr {border-width: 1px;} p {margin: 0 0 0.3em 1em;} -em {} +em {font-style: normal; font-weight: bold; margin: 0 0.1em;} +pre em {font-style: italic; font-weight: normal;} strong {} pre {margin: 1em; line-height: 1.2em; background-color: white;} tt {margin: 0 0.2em;} @@ -48,6 +49,7 @@ table {margin: 4px; border-collapse: collapse; border-style: solid; border-width th {background-color: white; border-style: solid; border-width: 1px 1px 2px; border-color: black; padding: 0 3px; vertical-align: top; white-space: nowrap;} td {background-color: white; border-style: solid; border-width: 1px; border-color: black; padding: 0 3px; vertical-align: top; line-height: 1.3em;} table.lst td:first-child {font-family: monospace;} +table.lst2 td {font-family: monospace;} table caption {font-family: sans-serif; font-weight: bold;} p.foot {clear: both; text-indent: 0; margin: 1em 0.5em 1em;} diff --git a/doc/css_j.css b/doc/css_j.css index c3327f2..a5749b5 100644 --- a/doc/css_j.css +++ b/doc/css_j.css @@ -10,7 +10,8 @@ a:active {color: darkmagenta; position: relative; top: 1px; left: 1px;} abbr {border-width: 1px;} p {text-indent: 1em; margin: 0 0 0.3em 0.5em;} -em {} +em {font-style: normal; font-weight: bold; margin: 0 0.1em;} +pre em {font-style: italic; font-weight: normal;} strong {} pre {margin: 1em; line-height: 1.2em; letter-spacing: 0; background-color: white;} tt {margin: 0 0.2em; letter-spacing: 0;} @@ -51,6 +52,7 @@ table {margin: 4px; border-collapse: collapse; border-style: solid; border-width th {background-color: white; border-style: solid; border-width: 1px 1px 2px; border-color: black; padding: 0 3px; vertical-align: top;} td {background-color: white; border-style: solid; border-width: 1px; border-color: black; padding: 0 3px; vertical-align: top; line-height: 1.3em;} table.lst td:first-child {font-family: monospace; white-space: nowrap;} +table.lst2 td {font-family: monospace; white-space: nowrap;} table caption {font-family: sans-serif; font-weight: bold;} p.foot {clear: both; text-indent: 0; margin: 1em 0.5em 1em;} diff --git a/doc/en/appnote.html b/doc/en/appnote.html index 08bdad5..8fd30da 100644 --- a/doc/en/appnote.html +++ b/doc/en/appnote.html @@ -9,7 +9,7 @@ -

FatFs Module Application Note (for R0.04)

+

FatFs Module Application Note


@@ -17,17 +17,37 @@

The FatFs module is assuming following terms on portability.

+
+

Memory Usage (R0.04a)

+

These are the memory usage on some target systems. The memory sizes are in unit of byte, D means number of logical drives and F means number of open files. All samples are optimezed in code size.

+ + + + + + + + + + + + + + + + +
AVRH8/300HMSP430TLCS-870/CV850ESSH2
CompilergccCH38CL430CC870CCA850SHC
_MCU_ENDIAN122112
FatFs Code
(Full, R/W cfg.)
8672874663847390
FatFs Code
(Full, R/O cfg.)
4230410030123510
FatFs Code
(Mininum, R/W cfg.)
5706567840424882
FatFs Code
(Minimum, R/O cfg.)
3016311621982702
FatFs Work (Static)D*2 + 2D*4 + 2D*4 + 2D*4 + 2
FatFs Work (Dynamic)D*550 + F*544D*550 + F*550D*550 + F*550D*550 + F*550
Tiny-FatFs Code
(Full, R/W cfg.)
7188720665908799
Tiny-FatFs Code
(Full, R/O cfg.)
3592356031624353
Tiny-FatFs Code
(Minimum, R/W cfg.)
4670477243226073
Tiny-FatFs Code
(Minimum, R/O cfg.)
2576271423783324
Tiny-FatFs Wrok (Static)4644
Tiny-FatFs Work (Dynamic)542 + F*28542 + F*32542 + F*28542 + F*28
+

FatFs vs. Tiny-FatFs

-

For most applications, such as portable audio and data logger, Tiny-FatFs is the best choice. However because the Tiny-FatFs does not support FAT32 in default, there is a limitation that can handle only tiny storage upto 2GB(4GB in FAT64). The FAT32 support can be added by _USE_FAT32 option with an additional code size.

-

FatFs is suitable for accessing multiple files fast, and for multiple drive system.

+

For most applications, such as portable audio and data logger, Tiny-FatFs is the best choice. However because the Tiny-FatFs does not support FAT32 in default, there is a limitation that can handle only tiny storage upto 2GB(4GB in FAT64). The FAT32 support can be added by _USE_FAT32 option with an additional code size. The FatFs is suitable for fast multiple files access, and for multiple drive system.

@@ -36,7 +56,7 @@ This will not be a problem on most C compilers. When any conflict of integer def
Memory SizeFAT Type
>= 4GBFAT32
-

Rignt table shows the correspondence between memory size and FAT type for SD memroy card and they are shipped with this format. The data area is justified to the erase block and the memory card works the best performance. For that reason, the memory card should not be reformated with PC. When cluster size or FAT type is changed, the write performance can be worse.

+

Rignt table shows the correspondence between memory size and FAT type for SD memroy card and they are shipped with this format. The data area is justified to the erase block boundary and the memory card works with the best performance. For that reason, the memory card should not be reformated with PC. When cluster size or FAT type is changed, the write performance can be decreased.

@@ -52,10 +72,10 @@ This will not be a problem on most C compilers. When any conflict of integer def

Figure 3. Sector aligned read

-

The file I/O buffer means a sector buffer to read/write partial data on the sector. For FatFs, member buffer[] in the file object is used. For Tiny-FatFs, member win[] in the file system object is used.

+

The file I/O buffer means a sector buffer to read/write a partial data on the sector. On the FatFs, member buffer[] in the file object is used. On the Tiny-FatFs, member win[] in the file system object is used.

Tiny-FatFs processes all data transfer and access to the FAT/directory with only one sector buffer, so that FAT sector cached into the buffer is lost and it must reloaded at every cluster boundary. FatFs has a FAT/directory buffer separated from file I/O buffer, the frequency of FAT accesses is only 1/341, 1/256 or 1/128 (when cluster is contiguous) compared to Tiny-FatFs. Thus the Tiny-FatFs is sacrificing its performance in compensation for very small memory footprint.

-

Figure 1 shows that partial sector data is transferred via the file I/O buffer. At long data transfer shown in Figure 2, middle of transfer data that aligned to sector boundary is transferred into memory directly. Figure 3 shows that entier transfer data is aligned to the sector boundary. In this case, file I/O buffer is not used. At the direct transfer, maximum extent of sectors are read with disk_read function at a time but it never across cluster boundary even if it is contiguous.

-

Therefore taking effort to sector aligned read/write accesss reduces memcpy and read/write performance will be improved. Besides the effect, cached FAT sector on the Tiny-FatFs is not flushed during read/write access, so that it can achieve same performance as FatFs and its small memory footprint simultanesously.

+

Figure 1 shows that partial sector data is transferred via the file I/O buffer. At long data transfer shown in Figure 2, middle of transfer data that aligned to sector boundary is transferred into memory directly. Figure 3 shows that entier transfer data is aligned to the sector boundary. In this case, file I/O buffer is not used. At the unbuffered transfer, maximum extent of sectors are read with disk_read function at a time but it never across cluster boundary even if it is contiguous.

+

Therefore taking effort to sector aligned read/write accesss eliminates memcpy and the read/write performance will be improved. Besides the effect, cached FAT sector is not flushed during read/write access on the Tiny-FatFs, so that it can achieve same performance as FatFs and its small memory footprint simultanesously.

@@ -64,24 +84,22 @@ This will not be a problem on most C compilers. When any conflict of integer def

When write operation to the FAT file system is interrupted due to any accidental failure, such as sudden blackout, incorrect disk removal and unrecoverable data error, the FAT structure can be destroyed. Following images shows the critical section on the FatFs module.

Figure 4. Long critical section
-fig.4 +fig.4
Figure 5. Minimized critical section
-fig.5 +fig.5

-

An interruption in the red section can cause a cross link; as a result, the file/directory is lost. There is one or more possibility listed below when an interruption in the yellow section is occured.

+

An interruption in the red section can cause a cross link; as a result, the file/directory being changed will be lost. There is one or more possibility listed below when an interruption in the yellow section is occured.

-

Every case does not affect the files that not in write operation. To minimize risk of data loss, the critical section can be minimized like shown in Figure 5 by minimizing the time that file is opened in write mode and using f_sync function properly.

+

Each case does not affect the files that not in write operation. To minimize risk of data loss, the critical section can be minimized like shown in Figure 5 by minimizing the time that file is opened in write mode and using f_sync function properly.

@@ -89,7 +107,7 @@ Figure 5. Minimized critical section

Problems and Ideas


These are the problems and ideas on current revision of FatFs module. However the main target of FatFs module is 8 bit microcontrollers. These extensions requires much resource and the FatFs will unable to be ported to the 8 bit system. This may be the most serious problem on future plan.

diff --git a/doc/en/chmod.html b/doc/en/chmod.html index 502bdba..88758d4 100644 --- a/doc/en/chmod.html +++ b/doc/en/chmod.html @@ -31,10 +31,10 @@ FRESULT f_chmod (
Attribute flags to be set in one or more combination of the following flags. The specified flags are set and others are cleard.
- - - - + + + +
AttributeDescription
AR_RDORead only
AR_ARCArchive
AR_SYSSystem
AR_HIDHidden
AM_RDORead only
AM_ARCArchive
AM_SYSSystem
AM_HIDHidden
AttributeMask
@@ -61,7 +61,7 @@ FRESULT f_chmod (
FR_WRITE_PROTECTED
The medium is write protected.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
diff --git a/doc/en/close.html b/doc/en/close.html index b403ff5..683fbcb 100644 --- a/doc/en/close.html +++ b/doc/en/close.html @@ -35,7 +35,7 @@ FRESULT f_close (
FR_OK (0)
The file object has been closed successfuly.
FR_RW_ERROR
-
Any error has occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_INVALID_OBJECT
diff --git a/doc/en/dioctl.html b/doc/en/dioctl.html new file mode 100644 index 0000000..1ebfa05 --- /dev/null +++ b/doc/en/dioctl.html @@ -0,0 +1,65 @@ + + + + + + + +FatFs - disk_ioctl + + + + +
+

disk_ioctl

+

The disk_ioctl function cntrols device specified features and miscellaneous functions other than disk read/write.

+
+DRESULT disk_ioctl (
+  BYTE Drive,      /* Drive number */
+  BYTE Command,    /* Control command code */
+  void* Buffer     /* Data transfer buffer */
+);
+
+
+ +
+

Parameters

+
+
Drive
+
Specifies drive number (0-9).
+
Command
+
Specifies the command code.
+
Buffer
+
Pointer to the parameter buffer depends on the command code. When it is not used, specify a NULL pointer.
+
+
+ + +
+

Return Value

+
+
RES_OK (0)
+
The function succeeded.
+
RES_ERROR
+
Any error occured.
+
RES_PARERR
+
Invalid command code.
+
RES_NOTRDY
+
The disk dirve has not been initialized.
+
+
+ + +
+

Description

+

The FatFs module uses only device independent commands described below. Any device dependent function is not used. In read-only configuration, This function is not needed.

+ + + + +
CommandDescription
GET_SECTOR_COUNTReturns total sectors on the drive into the DWORD variable pointed by Buffer.
CTRL_SYNCMake sure that the drive has finished to write data. When the module has a write back cache, write back the dirty sector immediately.
+
+ +

Return

+ + diff --git a/doc/en/dread.html b/doc/en/dread.html index 6105b94..a9ab3db 100644 --- a/doc/en/dread.html +++ b/doc/en/dread.html @@ -41,7 +41,7 @@ DRESULT disk_read (

Return Value

-
RES_OK
+
RES_OK (0)
The function succeeded.
RES_ERROR
Any error occured during the read operation.
diff --git a/doc/en/dwrite.html b/doc/en/dwrite.html index 032de5f..857074b 100644 --- a/doc/en/dwrite.html +++ b/doc/en/dwrite.html @@ -41,7 +41,7 @@ DRESULT disk_write (

Return Values

-
RES_OK
+
RES_OK (0)
The function succeeded.
RES_ERROR
Any error occured during the write operation.
diff --git a/doc/en/filename.html b/doc/en/filename.html index bd52e5e..d094482 100644 --- a/doc/en/filename.html +++ b/doc/en/filename.html @@ -9,13 +9,13 @@ -

File and Path name on the FatFs module

-

The format of file and path name on the FatFs module is similer to MS-DOS. However does not have a concept of current directory, all objects on the drive are specified in full path from the roor directory.

+

File and Path name on the FatFs module

+

The format of file and path name on the FatFs module is similer to MS-DOS. However it does not have a concept of current directory, all objects on the drive are specified in full path from the roor directory.

 
- "Drive#:directory/file"
+ "[logical drive#:][/]directory/file"
 
  "file1.txt"           a file on drive 0
  "/file1.txt"          (same as above)
@@ -27,9 +27,31 @@
  "2:"                  the root directory on drive 2
 
 
-

The FatFs module supports only 8.3 format file name and long file name is currentry not supported. For directory separator, a '/' is used, not a '\'.

-

The FatFs module has work areas that called file system object for each logical drive. The logical drive number is specified in a numeral with a colon. When drive number is omitted, it means the default drive (0). The logical drive is bound to the physical drive that has same drive number.

-

As for the Tiny-FatFs, it has only one logical drive and always works as drive 0. Any drive number cannot be contained in the path name.

+

The FatFs module supports only 8.3 format file name and long file name is currentry not supported. For directory separator, a '/' is used, not a '\'. Heading '/' is ignored and can be omitted.

+

The logical drive number is specified in a numeral with a colon. When drive number is omitted, it means the default drive (0). As for the Tiny-FatFs, it has only one logical drive and always works as drive 0. Any drive number cannot be contained in the path name.

+
+ +


+
+

Correspondence between logical/physical drive

+

In default, the FatFs module has work areas that called file system object for each logical drive. The logical drive is bound simply to the physical drive that has same drive number, and first partition is mounted. When _MULTI_PARTITION is specified in configuration option, each individual logical drive can be bound to any physical drive/partition. In this case, a drive number resolution table must be defined as follows:

+
+Example: Logical drive 0-2 are assigned to three pri-partitions on the physical drive 0 (fixed disk)
+         Logical drive 3 is assigned to physical drive 0 (removable disk)
+
+const PARTITION Drives[] = {
+    {0, 0},     /* Logical drive 0 ==> Physical drive 0, 1st partition */
+    {0, 1},     /* Logical drive 1 ==> Physical drive 0, 2nd partition */
+    {0, 2},     /* Logical drive 2 ==> Physical drive 0, 3rd partition */
+    {1, 0}      /* Logical drive 3 ==> Physical drive 1 */
+};
+
+

There are some consideration when use _MULTI_PARTITION configuration.

+
    +
  • Only pri-partition (0-3) can be mounted.
  • +
  • When the drive have no partition table (super floppy format), partition number is ignored.
  • +
  • The drive that has two or more logical drive must be fixed drive.
  • +
diff --git a/doc/en/getfree.html b/doc/en/getfree.html index 87f5a6d..c978aae 100644 --- a/doc/en/getfree.html +++ b/doc/en/getfree.html @@ -45,7 +45,7 @@ FRESULT f_getfree (
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
@@ -74,7 +74,7 @@ FRESULT f_getfree ( // Get free space printf("%lu KB total disk space.\n" "%lu KB available on the disk.\n", - (fs->max_clust - 2) * fs->sects_clust / 2, + (DWORD)(fs->max_clust - 2) * fs->sects_clust / 2, clust * fs->sects_clust / 2);
diff --git a/doc/en/lseek.html b/doc/en/lseek.html index 2ae6aa8..42d58b7 100644 --- a/doc/en/lseek.html +++ b/doc/en/lseek.html @@ -38,7 +38,7 @@ FRESULT f_lseek (
FR_OK (0)
The function succeeded.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_INVALID_OBJECT
@@ -49,8 +49,13 @@ FRESULT f_lseek (

Description

-

The f_lseek function moves the file read/write pointer of an open file object. The offset can be specified in only origin from top of the file and cannot moved to above end of the file. When an offset above the file size was specified, the read/write pointer moves to end of the file.

-
+

The f_lseek function moves the file R/W pointer of an open file. The offset can be specified in only origin from top of the file. When an offset above the file size is specified in write mode, the file is extended to the offset and the data in the extended area is undefined. After the function succeeded, member fptr in the file object should be checked in order to make sure the R/W pointer has been moved correctry. In case of fptr is less than Offset, any of the followings has been occured.

+
    +
  • In read-only mode, the Offset was clipped in file size.
  • +
  • The drive gets full during the file extending process.
  • +
  • There is any error in the FAT structure.
  • +
+

This function is not supported in minimization level of >= 3.

@@ -62,7 +67,7 @@ FRESULT f_lseek ( // Forward 3000 bytes res = f_lseek(&file, file.fptr + 3000); - // Rewind 2000 bytes + // Rewind 2000 bytes (take care on overflow) res = f_lseek(&file, file.fptr - 2000); // Move to end of the file diff --git a/doc/en/mkdir.html b/doc/en/mkdir.html index 2a5e2e8..b0bd73d 100644 --- a/doc/en/mkdir.html +++ b/doc/en/mkdir.html @@ -41,13 +41,15 @@ FRESULT f_mkdir (
FR_INVALID_DRIVE
The drive number is invalid.
FR_DENIED
-
The function was denied due to any of following reasons: any file or directory that has same name is existing, cannot be created due to directory table or disk is full.
+
The directory cannot be created due to directory table or disk is full.
+
FR_EXIST
+
A file or directory that has same name is already existing.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_WRITE_PROTECTED
The medium is write protected.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
diff --git a/doc/en/mkfs.html b/doc/en/mkfs.html index a69462d..f687352 100644 --- a/doc/en/mkfs.html +++ b/doc/en/mkfs.html @@ -45,8 +45,10 @@ FRESULT f_mkfs (
The drive cannot work due to any reason.
FR_WRITE_PROTECTED
The drive is write protected.
+
FR_NOT_ENABLED
+
The logical drive has no work area.
FR_RW_ERROR
-
The function failed due to a write error in the low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_MKFS_ABORTED
The function aborted before start in format due to a reason as follows.
    @@ -60,7 +62,8 @@ FRESULT f_mkfs (

    Description

    -

    The f_mkfs function creates a FAT file system on the drive. There are two partitioning rules, FDISK and SFD, for removable media. It can be selected with a parameter and FDISK format is recommended for most case. The FAT type, FAT12/FAT16/FAT32, is determined by only how many clusters on the drive and nothing else, according to FAT specification. Thus which FAT type is selected, is depends on the drive size and specified cluster size.

    +

    The f_mkfs function creates a FAT file system on the drive. There are two partitioning rules, FDISK and SFD, for removable media. It can be selected with a parameter and FDISK format is recommended for most case. This function currently does not support multiple partition, so that existing partitions on the physical dirve will be deleted and re-created a partition occupies entire disk space.

    +

    The FAT type, FAT12/FAT16/FAT32, is determined by only how many clusters on the drive and nothing else, according to FAT specification. Thus which FAT type is selected, is depends on the drive size and specified cluster size. The cluster size affects performance of file system and large cluster increases the performance, so that 64 sectors per cluster is recommended except for small drive.

    This function is supported on only FatFs with _USE_MKFS option.

    diff --git a/doc/en/mount.html b/doc/en/mount.html index bd705b9..72ea811 100644 --- a/doc/en/mount.html +++ b/doc/en/mount.html @@ -45,7 +45,7 @@ FRESULT f_mount (

    Description

    The f_mount function registers/unregisters a work area to the FatFs module. The work area must be given to the logical drive with this function before using any file function. To unregister a work area, specify a NULL to the FileSystemObject, and then the work area can be discarded.

    -

    This function only initializes the work area and registers its address to the internal table, any access to the disk I/O layer does not occure. Actual mounting process is performed in any other file funcitons when it is needed.

    +

    This function only initializes the work area and registers its address to the internal table, any access to the disk I/O layer does not occure. Actual mounting process is performed in any other file funcitons with path name when it is needed.

    diff --git a/doc/en/open.html b/doc/en/open.html index 2221cea..d2c2c52 100644 --- a/doc/en/open.html +++ b/doc/en/open.html @@ -36,8 +36,9 @@ FRESULT f_open ( FA_READSpecifies read access to the object. Data can be read from the file.
    Combine with FA_WRITE for read-write access. 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. -FA_CREATE_ALWAYSCreates a new file. If the file is existing, it is truncated and overwritten. FA_OPEN_ALWAYSOpens the file, if it is existing. If not, the function creates the new file. +FA_CREATE_NEWCreates a new file. The function fails if the file is already existing. +FA_CREATE_ALWAYSCreates a new file. If the file is existing, it is truncated and overwritten.
@@ -57,6 +58,8 @@ FRESULT f_open (
The file name is invalid.
FR_INVALID_DRIVE
The drive number is invalid.
+
FR_EXIST
+
The file is already existing.
FR_DENIED
The required access was denied due to any of following reasons: write mode open of a file that has read-only attribute, file creation under existing a same name directory or read-only file, cannot be created due to the directory table or disk full.
FR_NOT_READY
@@ -64,7 +67,7 @@ FRESULT f_open (
FR_WRITE_PROTECTED
Write mode open or creation under the medium is write protected.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
@@ -77,7 +80,7 @@ FRESULT f_open (

Description

The created file object is used for subsequent calls to refer to the file. When close an open file object, use f_close function.

Before using any file function, work area (file system object) must be given to each logical drive with f_mount function. All file functions can work after this procedure.

-

Flags FA_WRITE, FA_CREATE_ALWAYS, FA_OPEN_ALWAYS are not supported in read-only configuration.

+

The mode flags, FA_WRITE, FA_CREATE_ALWAYS, FA_CREATE_NEW, FA_OPEN_ALWAYS, are not supported in read-only configuration.

diff --git a/doc/en/opendir.html b/doc/en/opendir.html index e36f2a1..2e2ff39 100644 --- a/doc/en/opendir.html +++ b/doc/en/opendir.html @@ -48,7 +48,7 @@ FRESULT f_opendir (
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
@@ -59,7 +59,7 @@ FRESULT f_opendir (

Description

-

The f_opendir function opens an exsisting directory and creates the directory object for subsequent calls. The directory object structure can be discarded at any time without any procedure. This function is not supported in minimization level 2.

+

The f_opendir function opens an exsisting directory and creates the directory object for subsequent calls. The directory object structure can be discarded at any time without any procedure. This function is not supported in minimization level of >=2.

diff --git a/doc/en/read.html b/doc/en/read.html index 36e4569..4e2254e 100644 --- a/doc/en/read.html +++ b/doc/en/read.html @@ -46,7 +46,7 @@ FRESULT f_read (
FR_DENIED
The function denied due to the file has been opened in write only mode.
FR_RW_ERROR
-
Any error has occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_INVALID_OBJECT
diff --git a/doc/en/readdir.html b/doc/en/readdir.html index 9ae8113..848de26 100644 --- a/doc/en/readdir.html +++ b/doc/en/readdir.html @@ -15,8 +15,8 @@

The f_readdir function reads directory entries.

 FRESULT f_readdir (
-  DIR* DirObject,    /* Pointer to the directory object strcture */
-  FILINFO* FileInfo  /* Pointer to the blank file information structure */
+  DIR* DirObject,    /* Pointer to the directory object structure */
+  FILINFO* FileInfo  /* Pointer to the file information structure */
 );
 
@@ -40,7 +40,7 @@ FRESULT f_readdir (
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_INVALID_OBJECT
The directory object is invalid.
@@ -49,7 +49,7 @@ FRESULT f_readdir (

Description

-

The f_readdir function reads directory entries in sequence. All items in the directory can be read by calling f_readdir function repeatedly. When all directory items have been read and no item to read, the function returns a null string into f_name[] member without any error. For details of the file informations, refer to the FILINFO. This function is not supported in minimization level of 2.

+

The f_readdir function reads directory entries in sequence. All items in the directory can be read by calling f_readdir function repeatedly. When all directory items have been read and no item to read, the function returns a null string into f_name[] member without any error. For details of the file informations, refer to the FILINFO. This function is not supported in minimization level of >=2.

diff --git a/doc/en/rename.html b/doc/en/rename.html index d305713..503b896 100644 --- a/doc/en/rename.html +++ b/doc/en/rename.html @@ -52,7 +52,7 @@ FRESULT f_rename (
FR_WRITE_PROTECTED
The medium is write protected.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
diff --git a/doc/en/sdir.html b/doc/en/sdir.html index ff9ae80..4853cce 100644 --- a/doc/en/sdir.html +++ b/doc/en/sdir.html @@ -16,23 +16,23 @@

FatFs

 typedef struct _DIR {
+    WORD    id;          /* Owner file system mount ID (inverted) */
+    WORD    index;       /* Current index */
     FATFS*  fs;          /* Pointer to the owner file system object */
     DWORD   sclust;      /* Start cluster */
     DWORD   clust;       /* Current cluster */
     DWORD   sect;        /* Current sector */
-    WORD    index;       /* Current index */
-    WORD    id;          /* Sum of owner file system mount ID */
 } DIR;
 

Tiny-FatFs

 typedef struct _DIR {
+    WORD    id;          /* Owner file system mount ID (inverted) */
+    WORD    index;       /* Current index */
     FATFS*  fs;          /* Pointer to the owner file system object */
     CLUST   sclust;      /* Start cluster */
     CLUST   clust;       /* Current cluster */
     DWORD   sect;        /* Current sector */
-    WORD    index;       /* Current index */
-    WORD    id;          /* Sum of owner file system mount ID */
 } DIR;
 
diff --git a/doc/en/sfatfs.html b/doc/en/sfatfs.html index dcc6f82..05a98be 100644 --- a/doc/en/sfatfs.html +++ b/doc/en/sfatfs.html @@ -16,10 +16,6 @@

FatFs

 typedef struct _FATFS {
-    BYTE    fs_type;        /* FAT type (0:Not mouted) */
-    BYTE    sects_clust;    /* Sectors per cluster */
-    BYTE    n_fats;         /* Number of FAT copies */
-    BYTE    drive;          /* Physical drive number */
     WORD    id;             /* File system mount ID */
     WORD    n_rootdir;      /* Number of root directory entries */
     DWORD   winsect;        /* Current sector appearing in the win[] */
@@ -29,7 +25,12 @@ typedef struct _FATFS {
     DWORD   dirbase;        /* Root directory start sector (cluster# for FAT32) */
     DWORD   database;       /* Data start sector */
     DWORD   last_clust;     /* Last allocated cluster */
+    BYTE    fs_type;        /* FAT type (0:Not mounted) */
+    BYTE    sects_clust;    /* Sectors per cluster */
+    BYTE    n_fats;         /* Number of FAT copies */
+    BYTE    drive;          /* Physical drive number */
     BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
+    BYTE    pad1;
     BYTE    win[512];       /* Disk access window for Directory/FAT */
 } FATFS;
 
@@ -37,10 +38,6 @@ typedef struct _FATFS {

Tiny-FatFs

 typedef struct _FATFS {
-    BYTE    fs_type;        /* FAT type (0:Not mouted) */
-    BYTE    sects_clust;    /* Sectors per cluster */
-    BYTE    n_fats;         /* Number of FAT copies */
-    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
     WORD    id;             /* File system mount ID */
     WORD    n_rootdir;      /* Number of root directory entries */
     DWORD   winsect;        /* Current sector appearing in the win[] */
@@ -50,6 +47,10 @@ typedef struct _FATFS {
     CLUST   sects_fat;      /* Sectors per fat */
     CLUST   max_clust;      /* Maximum cluster# + 1 */
     CLUST   last_clust;     /* Last allocated cluster */
+    BYTE    fs_type;        /* FAT type (0:Not mounted) */
+    BYTE    sects_clust;    /* Sectors per cluster */
+    BYTE    n_fats;         /* Number of FAT copies */
+    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
     BYTE    win[512];       /* Disk access window for Directory/FAT/File */
 } FATFS;
 
diff --git a/doc/en/sfile.html b/doc/en/sfile.html index 32e96bc..1b50210 100644 --- a/doc/en/sfile.html +++ b/doc/en/sfile.html @@ -17,6 +17,9 @@

FatFs

 typedef struct _FIL {
+    WORD    id;             /* Owner file system mount ID (inverted) */
+    BYTE    flag;           /* File status flags */
+    BYTE    sect_clust;     /* Left sectors in cluster */
     FATFS*  fs;             /* Pointer to the owner file system object */
     DWORD   fptr;           /* File R/W pointer */
     DWORD   fsize;          /* File size */
@@ -25,9 +28,6 @@ typedef struct _FIL {
     DWORD   curr_sect;      /* Current sector */
     DWORD   dir_sect;       /* Sector containing the directory entry */
     BYTE*   dir_ptr;        /* Ponter to the directory entry in the window */
-    WORD    id;             /* Sum of owner file system mount ID */
-    BYTE    flag;           /* File status flags */
-    BYTE    sect_clust;     /* Left sectors in cluster */
     BYTE    buffer[512];    /* File R/W buffer */
 } FIL;
 
@@ -35,6 +35,9 @@ typedef struct _FIL {

Tiny-FatFs

 typedef struct _FIL {
+    WORD    id;             /* Owner file system mount ID (inverted) */
+    BYTE    flag;           /* File status flags */
+    BYTE    sect_clust;     /* Left sectors in cluster */
     FATFS*  fs;             /* Pointer to owner file system */
     DWORD   fptr;           /* File R/W pointer */
     DWORD   fsize;          /* File size */
@@ -43,9 +46,6 @@ typedef struct _FIL {
     DWORD   curr_sect;      /* Current sector */
     DWORD   dir_sect;       /* Sector containing the directory entry */
     BYTE*   dir_ptr;        /* Ponter to the directory entry in the window */
-    WORD    id;             /* Sum of owner file system mount ID */
-    BYTE    flag;           /* File status flags */
-    BYTE    sect_clust;     /* Left sectors in cluster */
 } FIL;
 
diff --git a/doc/en/stat.html b/doc/en/stat.html index b4e899e..3b518b5 100644 --- a/doc/en/stat.html +++ b/doc/en/stat.html @@ -25,7 +25,7 @@ FRESULT f_stat (

Parameters

FileName
-
Pointer to the null-terminated string that specifies the file or directory to get its information. Do not specify root directory.
+
Pointer to the null-terminated string that specifies the file or directory to get its information.
FileInfo
Pointer to the blank FILINFO structure to store the information.
@@ -48,7 +48,7 @@ FRESULT f_stat (
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
diff --git a/doc/en/sync.html b/doc/en/sync.html index 0223e61..a2e98e6 100644 --- a/doc/en/sync.html +++ b/doc/en/sync.html @@ -35,7 +35,7 @@ FRESULT f_sync (
FR_OK (0)
The function succeeded.
FR_RW_ERROR
-
Any error has occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_INVALID_OBJECT
diff --git a/doc/en/unlink.html b/doc/en/unlink.html index 8225928..9346296 100644 --- a/doc/en/unlink.html +++ b/doc/en/unlink.html @@ -49,7 +49,7 @@ FRESULT f_unlink (
FR_WRITE_PROTECTED
The medium is write protected.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
The function failed due to a disk error or an internal error.
FR_NOT_ENABLED
The logical drive has no work area.
FR_NO_FILESYSTEM
diff --git a/doc/en/write.html b/doc/en/write.html index 4927d2f..e408150 100644 --- a/doc/en/write.html +++ b/doc/en/write.html @@ -46,7 +46,7 @@ FRESULT f_write (
FR_DENIED
The function denied due to the file has been opened in read only mode.
FR_RW_ERROR
-
Any error has occured in low level disk I/O layer.
+
The function failed due to a disk error or an internal error.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_INVALID_OBJECT
diff --git a/doc/img/f1.png b/doc/img/f1.png index 9723ea03c8ff9a88cbec27877d1ced8c909a2652..42cc2713f58cb71002ab49170e7b621f36d1c110 100644 GIT binary patch delta 1057 zcmV++1m63&2>A$*XMYaF000ie0hKEb8vpl*|B!(b@D*MEhp(p-}TO!^D=?6-Dt z8cqflZU})<=ht}P3w%;Eh?n|u@A%!n7woiFpqJWK+fp!2AVVG@>wMWm-O2Y25$b;k zImnRutX{76=h-Q;_^{|yM<-V~ zK>2_@yZz_;VX28d$7&Rzu}xMP$kv(Houe$WE^>#&7Yzn=<*sJ7o8YelYJ6A})NKnD zBML_OoZctHhmmuG8gK0lH-6aq=W3)a%ZX>DIMHgF#(k zPThe`dgh$q!7gPE_ny?4S6t3EWvS7csF2}-?bhlzLmnY8$u8x(WHtf6q~X7>Yk?Xio zhkxr=)U^_KaiUh|E~Qr3FMT(ZJZi68{)ADxH}Bb{_PzU9vrO%mYX$wrjXI%qt)$bkkUf!S;Lj|8_l}DebE{pm+e=b zV)0F`a;4M~N~vYys@qMdlv+YDrw+H9_jj+UUq#fC%{Avlmr`m8#hW@|N~x2hlo~oY bN+$JxO?ZTi-2~0>00000NkvXXu0mjf(;XUg delta 991 zcmV<510ekQ2)GE4XMX?y000000qSKIqyPW|u1Q2eRCt{2n$1$vP!z{clgdXaCg?^t zf-hhlw~m&DTShkS`vQ)2?E-iL*t&wf!`Pk6cJu*SpP--*z-?e?p@rl9NZK$GAUF4x zv^W1S(=>;B?*GTR=Oz>YO%&X>fqPL#ZH_W(eUktn45tFTEPq{8X4*Vpvlr~Uuif%E zoD3~o5do_yu8F{B_^4=-F!lNN;oHB@_-UiWE_IxaqhOv`hC(9F>0*ewTO3$HXz)Ja zBqQpRX0<+;<)_3E(~|q8=5B&O*h>OmL9I_=o1b-X1<~TCjcrB@tOqJ{Nb+T={0{qy zX(%L$W+7a>%zw9`Pw_pv-nrMFyGDI&F<)^U)YWhE{Okw2!Y_h-#HiWPE!1{N zF=l2ze{qnMn%eW6RvB6wbeDmAlY8CV&lBgYut$BdU|d)JZsz(0{xYP-y>dX^aY#vW zJ;Bp6H#v33t|L5V?|;Dp_v*5c$9=J2TvsS+&FIOfy^3}sjD{{cqw{+SZLf_5R0h;W>&zxVWp+6Rk>k84YHGfC<#cI7D>}I1{OYa@9 zLv}=m6b|NFC9x)Zh4Zjp5qGZI zhPSxm_kVRudWAP?4ZlO!A$$(i`6fdl5wPh~%4NlF13qWwavR)h57zoN zZatwt78aE9rcdBmL5GZLjg{3;kpsr*PM4rN8-H{NJH(pA8q^~PjM1Dn!FeI*5Wcqg znxyOYC~|;!A(HdSjvI%L?a0s+Q~zFw3{5XJv34V40X0bKwy8DcO(@N^PU#xTs3nw9 z%fwZWyQ7SyCJAPlTS53y7HX(1;41ot`* zj)J_}q>Wl&n?^nTwf;XV+#Hw9t4dm^Ls)yb(!9!~gF1Y_R+(3wjQvY)l36lpnYik4 zcT`3#p^RE4u6o=ZHKCstDx#JguDK?@Z! N002ovPDHLkV1hJT^|k;2 diff --git a/doc/img/f2.png b/doc/img/f2.png index f25726301467fb81734f1112755b22ce3c187d1a..8ef0ec241e602e362cb0f21f7ccc66c9ceb057b5 100644 GIT binary patch delta 1372 zcmV-i1*7`M3bG53XMYaF000ie0hKEb8vp0`%k{50G#j!0UFs zW=ZN}Wy_3L}AR_AKh<~V?Bck>u4#2o9@h2u; zi6zXATUw^<|_4zMY(C+kA)v@$i`YtOA z`W44o(W|4ONPBq7EDP9;Zr<8@=1$!bFz&bZ0glv(KU;}A+HYA@WkJ7U>S3JK{uVNu z?G7$c_pfkgChOhR??4Yj*!%3+=W;Nr{IK};)snGEp8D*DJbAW$4|bR1f1%vT#9CDr z^eY|LhkrW2KZ)~C-h82FE}1+Q|B1)-j%5#@XY+AZ_yc}vi=Tf}`C;Sv_NKAP)ic+- z-m4`zotN3{mUK(Gv$4~O$2C)x1^r5L_`1r2oP8~(tCSza-d7Rz2v+QuO6q>F=8>YfBAZzOOR+OMU6F(lyuiW!F)jV;yK8B5Df}wM{*CyBXD3 zYJcu5@c&Bxkt9gxJjYSeCalW~pWU6rWu zyd!F&cC;HkMvwhvO`*PMQFGUq+Bo~LI#ZisjbOKG)D0ciD0YcDJnwu{yRGKU-ubfo z_#>;5`S#&@@6f;gUPBzl%+*Zll7B1%XMcZ*+TKd3U7Uxq4kv1&t~Yh5=`5V@TtrRO zL`~H7pe}Lhir=OnYN94;q9$srr-fG3MPEnqK<#G5YQhGqdj%N&5_QSccH^S*)DDfR zOKq3VgBcpwe+26t(AU*2o-Qr}^6D282Of-lO4=R-{Bt)I=R1we5;2ZeG!6q;6J- zny87IsEN9|)Xm(XLDWP|)I?ni>SpegCTgNaQ#Nk|L+v}6UEHk{%9~BTsac5B-aGh3 z>OkID^i9o$FKV}^g^6-|E>P_9{C{4K0NzA41qID+K5+!l!{6f`(%lUEe~HQWL>#-h zI}j8#YOIZ8K8zghiP{uv1iL=6S$1myirwsO4R>5;wvpi2%}3nLE^-e~=+mu$xOS)1 zZtH-A`kJd4uWs~#A=vdMZ`ARwI48T_M6tGzq1|*`=m znH*7WCq%&e~Ua zo0%8To87dqx)Ptdz@S+zYy<3z6JHB~9qF4FQ5n&fPhI!3+IPmY*=Fqmb@dWEJw-3i zz63c9Ve9_N13no=ei%PGm{2z9ratTAC(jnfU~}643t=ZT)}k_^ulBs&lLP#Yo!>ot zC|53?Jb%W2`ty2S^9mmz1AbQc0w0R({U?zh7B|+Gl}#>Rxqep;Cg5~{XR~2$OW0Xl zFZuJDh{}k*f*ige@*pKoSZ9~=hHX9es2eb&M_n1J1X)3pae1^i`&^wFyLTxizDqfu zFYN>4qtTi#)TEtLm}!>S(mn23RBD*BCQ6DV$bSl*QXeU(o8(|0PRaO0kQF*(eNw)y zZjuY?g<6mmM3M8Fuen3&Cb^(q+X%9PD5rOp1s05`oA}gJw@1x(321U!U6)(xR&`rl znOkajbXBGIOT6gO(lveCiW^gw$2z6g5K?Ohsdeg2x9d^PQqvf{WS2T1*HLDv3?bNI`_8X#@h!3W1ThXcyWVyolbWasZ;C@sa>W9;vzNA-Xz!5%GHPDnOZg02I6Lo z+R=G!BrZ~?&z)`Rc)NMEJ6mz*ZfTX!tB<(Po&F6gTB7M#x!j~q_`@=Y?H8%_qa=EX z)3ofvks7JU{3y5_JbVRn*=+idIDo`ZY#PY*Typ9=S&C?L<>X z9dV*YRC`{hiW+mcc{#dXcRc~=pmuXdiquGr)G4Ia-7)#ioqV?tsgW9~ks7J9OMmU= z9U4fD)JTogxuACQPHCh@>U>kX`OPLLsong>Vs@$Hy<4buXe;i`e-rsCcj=6qHEKuy zn*{!s7;V2PrdEx$fw(rP!?zZgj4S=7cV35XBQY8`^u)%CYv&5@+zMzmZihPFJ|LjJ zrWa-JN)N<9Tx+sM?cWs_E3P%+SZQlW(XKPE&Biq)E7YMJZZxhj*`N-u*CykdlbtKP z=X%radK6M?2&r}IO}Fb&NUfoaQ^(uQtKD0QYlvF2x#cmjC8X9+wy7NxQoAFhc1K9< aj{X6zQWL5vc%^Xw0000s(I!B diff --git a/doc/img/f3.png b/doc/img/f3.png index f07201a401e2b917a106157ffae78676d3442650..9111bfc97609c492db457a23a6f93e62151c5241 100644 GIT binary patch delta 950 zcmV;n14;b(2agDlXMYaF000ie0hKEb8vpy{1soB+ZJN>4zytiqm|PHvDR(18QgoFHo2Y0~E7A^D>OQ#=#dlI7_A z)0sqmk>>rLZD*xsH#;lTlgD!}HZ6`ax~EC-=K6qPcN=+g_si}OPsFF%tDU8nQYBI5Y_YXs z;cV5Ev%5J7PWdUDGzNX%@aul(w(+&kThqqfc1o2*S)h3c%a^qg%mn_}yFk2w&p2%# z0)%0FEsQ!T)_)b856;;o;~mcAYaD!9)UI18RT5=E4G3fA?}LAgID^^+_P*8e(^-wP zFpScu5n^ote=cYN7+-l|+uuv6k|>ANm(?M{6IuQVO>B$qZ%b1cMrpK3F!qE~Ogi|d zud#dZA*D*9EWTesn6)cIfD3uxhbW4%4RNEKNuxFd1%JV0i;MHxk4AVfAQ=u|m{KKC z=4`$t4$gafFxZd2A^Lf>ucc9s|7wD}hH$D^8%1OLijj-1swu{QS1DDoN?CTRBfu9UTy`tRIDtc)!r`nMhEW=I`kRk_ zHB*cmuzwYsRCL)0K?7o%R#ZXM zkKU>2o;vJn#a7;;`Ri`Tg*rH|vrwDuaGnn}W~4Se=LbW}0&25EJn)#P3!*kU#KRC1 zHBpAz)XMX?y000000qSKIqyPW|Z%IT!RCt{2oK14mFcimMoG@uVh|*yL ztHKGwZ~)o`>y!=qoB+ZJN>4zytiqm|PHvDR(18QQoFHo2Y0~E7A^D>OQ#=#dlI`gI z)0sqmk>>rLo+Vjz3}~YuYX>qBQQIS;E~tRXzwN5%@x-K{xqnPb&B6KZAM`CB;e8sO z=@dM>Z6~E>H?0lo+2f@XnpVdN-P0s^bA80Hw}-s3|7CxKr{YuPRcr0UREd;1TU9qK zoNby?b~h!#89!sQ`f$MOZq4o7*1ryTb6&sOi>VSR3p58|{jxHFg}|RWW5gTyjPrIE zzz^eVVbn>nt$*NRc)>0i?{FqxQ}5HNa@~xn5-AI6K$tT35Zn{Q1ysh^|5n3K=M~QU zFiN9Fh^+*|REd;1 zTUN!vW&Z$%hru^QKX3N6H0tqRO>kEiPW3C3Ah%DS%D&?eGx$6_b6vIE4$Ny}G;4}6 zt$*%_^ST^{Q5v;kq@t^GjPc)9N?EK@*1hrs@Wlkzz0wKJpo??pF3NrwrBSE9>F8G@ z#<&A3(tiiVok5IsSE=J=H8s!H3)4zSUC?NO@40={A-RgOq6S3;myO^xAf{`O?uJyTz4JN=wb>5m=}==rYQuBBms&ZXHk;y}$3&eGwb2y!Lrl~} zZIasLiS0W~)I?3xM6H9`;2<6Zn5c=GsEL}WQ-7m2H+2R6rbL}=x3H+ximep9uZfzd ziTeN4#-^??yhKgZL`~F0ogTHRsVj^wQ4=*$>!&s}oZSbPs57M2o8l08w}YAoH;Uzs zT5pQ`*gS94-p^$8YIE?&#crVyYDk}2v6a6vTsL(7GFO6HAyE@GQ4{q}P}})md!i<4qRu0=`es&Ybpr^H*#{P1Hoad(`HJ@G!zeP1FXd?R-j%ozx~19P{$@Cp(|?Rm`WlC8f?ns@r^N z-&~qT)5JlkPHD)@ zHfe`4k%(+l$|cuBQba_$ zv=u>sJM|obL%oL~Rm0QR<=xl?m1&sp6pbpPu*(F(C0QuuKPr51zuXm=3 z`ngCMmF=B4IgSlUIcP8I0C4}2l4l3I#r4AwhszFrIy{+PEP)BQ+oeCjpd{Z-nQp0D zvor~8atTI_8@Tpt5(>v2sDB+h*-C1@?GMB0p)pIXt#dDJ_-c*O$1l3{v>#k_9hPq%J_ zek4E8&_EBhJCJe(FDgkRtJ$jW0w276A0ai?pmxvHxF$8k^&w07F+g!IJ#-JlVN7s# z%UM)rdB<*)RXyQdAn2HHPw1Xcw**E0fLT^-SnP{B4{a#0YME#G`FgIVjv06TaxohA z;llpU8BOO_Q|lssl!3o}9_&92kVl_F)qOM>+KSN4B5m*ovmD?q%;1%g=22w zHq|MmnMu2~Ae5j#1}9D`)Q)S6Ot-|7TtIFCep<*W^~G!CsunX^I6OpcVqb{lk}|O9 z?Ct#YQI4n?W~*2(%HcE{A%W2qjaGPnXlo@SRG-SXh`KcAUlgZ`tj2+ZVhrsTeM=T# zm!!1zH)xyVh~-N-$8TwaQ{}D452-z-_w)OQvMGb->tHhG7u$dbeEp7Sx;bWhN>mQ^ zTOi1Ea*pk@UEV9s9N+`4L=5#ht6I#iYl!!|Kfrr|H|j%8J^6<>e2QTUa8GI~%?LaZ zHtR;%tRy9xbU!_(MNe$O$J zQmxn~?ai#qs}z|!z(J&PCayhFfF54=4beQkD*7wqMVjhWiL!6i%iRD$$V_;eL>Wc0 z>UE~)@(iI#PDSZRl-lO7XLdcf7k|Mi{KO5J@n{N=kp?HeAdJv#Z+l=o&B*-Y0r>h1 ztqnzK%xS&8(#hNiP-NWUSqVH|#cmlB&4a}p#Ue_uJ>v*hK<&bVM!q*meBhJ~_~$$V z&~ag|kS4bO9&6C~NxntVR|LBYI;~Ncc>9gL{+dIU#qBrz0mswY@TgzECOQ$}kDkli zF()3T?tlQ^X;~44xEp_m`@9(Y^M<&C?66;U8JD=YX29e+H7NPT46$yMC%c{BH!<(U zvo-{q9y~A<@JYS11D31y(`5Id#sxZgPF6)F?g`_!PAAI!7}7G{`AF)PiTw&oGen{6 zr8--@L7nri@c*y^o<1qI37OXUPojlH zj-oxxd-{t0Ri;0Tq5XMi`V810!X^deG-_ym%htCzfkYvKKzQ&NMGp~)n^s9fTc2?` z@%l;KF;6NQVuE|k%zKO~I3BXl#Zr;PD~(wXhd1+y>~6gtn;=6u%T({!D^(Dhyk#dd zdY{?WVndoas)-tLB9-Y!816n7!7a(y8EteIw9(+d*o!SdXP#jd28X!m*HXU-dwx4| zD!{as=?SvwZkGo3sp{}dgfB3KXKV~Bl8QC{GkI*m(XYCarD#fKcHf~VY;lZ@QCT_r zxN?8`fxyRx`@O@97TtpYabF1rllIuP*5$c-8W)|(E*B|G1+Pu9m4~HGW)-ynUa0I= zk<_^iW5}LmNcCpm?-f1~nIY5!RGlI#+MqhS^dp*crR`7emDOT<>Wk5PNaPd~0#?~3 z{}AOBPUs>W(0cmC=RM@{Y6jzf#>A);DS2Huym5%tJE_XnOpQPe5MD*w&ekLE+Dt-o zHHkL(IfGQ2kI~(00{7?wxy2>h^?~t?wIVim2Sc7BZeROh)6Ov*-Y%gu<}+6gE8Ep! z9Fa`=m=(;Otvm|exPEETalYH;B)H5-#`^wX{ak)xf>Yzbt6V~$57j6RHE?&7OHB8M zXE28~NyPu6DCD}HY$(zE^WR_%T2vlNo2XWULz8K{5G|*s^YJ%1r0Ww+(1_s<0@D&$y%1O_2c)AM0EIlvT{3f&WHXd=A1Q$W0#a}-z MX9tXZm90PNA3>mBJ^%m! literal 2451 zcma)8c{J4P8|T+|Tsv7qWgCVNitNe0WF)dgGN~-p9s807x36qjuesLj+YA#iG=?d2 z#x_}VLvj%zTcT-nEn~T(^E>y~^3U%*?{l8>KIgpWyytm7%bRFtYr(@Q&dI{U!eeD= zYR|&LdX5>dfkVv7`h7T+nbhoTE}1d&|Fia4SoZgsd*1-*D!{zJ;ct04h=ql>;~-cw zm3SqXH4ZCNqf6oW9}5yQ%XIn8lvte?iZTUrf`smO9p2e0j&-~fRb26sWN{k~nQK zq4b$PG~MNTyc^fho9>?`6XZ3>;(0D3zAitE$TLkP1IzCXUh`VdI)+Oy|} zO8Y<^?XmX;rsy>Ds$I|=5j^!-?slW342hwG7#j(Y~)BCkI;e2VQJ_T7xm>*H|b;vljdul zEn%9iF6Zjf_?G!0YbG_<6-MExbw|%)E%fx8HgjW_%Q46Vi2)dWyo~J+T2>Bi~aL!bZom2T6$Lm98R{zXD;VS@o#`(R>bMuBT=bOgS{rguN zWaNDE4nIan_|~(DmT_;NJ}Dv&+Y=I{fA4Lz+r6C;C&KMhso zi7&{Z+3?E5HuK26+JUTB4wu`S*m*^vs6RAO!d$A`QZ0#N6LOG4CmW&@s@;mr{hT^i z^-ZtV7zv)9if{f5qAy55LQX6`a*4a~plkrPR5 z*WRbwjMC3#{XTS9;zn=f{w{R}^Isl(JCH317#jqx38A2KQOekxL7*yoRyW64-pDt2 z9f~N>I|meTkcIm>TBTg%VVi2^zj7@A9)=k=1~~R0@hxrN6U^A?4-sHr>0=!iqO3zIN^!AeW}X4$ zTQqXpfYnO3c(74!-6_K`E4BLY@Ln=ekXKL1XUDZ22BlAC^ybxcdV_lJ>ehf!>udnl zi*;{eQ}!vHHX>w=x$T^!l;~)9-Rg|8b_Q{V>sHgg&%@tX?j#*t2pgu3xkgxA*)^wl zYfHNjhKBx5>#X>xF)Hj%l9J_89reXF$D5X3rfKTG?P;FF3oc~pZiT_(!ICLXN!g&g zr$cRE==6a3)#9V4(vk3Cy@5w!Y_!B&iw22h&#qiW*rH!nu;vjz6Yg1+yJgb2J2K(2 z-oOa&Me~tOeAjO_?%>&uGjP~>&UqXEU{*Z8EShLV4L+6PW*e@$r|x4;(II`r&}air zt@6a8FbtYHPDEjQk0mo8)R~`p&(u38pm{a`=ADGrfM=o7A54eaRwh-|Sk)Phr)Y^S z4+^GU&O~i<-*WKRJ@b@z$w`wV&-a|{{KjKQk^EC(9OF|n!oDgUfoG#`oJ_m4n_lb~ zhFSGwS<0L)2q;YgeS_8M;Yw>Cu?~y#eI||JSRB`n68jZeA6x!|YDb#c_2mb}14SwFne2Jmchdek zd&ni31YoPqUrU>sE)+@@jo-fdACwyifH}JO`Kyrb?gac8Pae6=~ZV( zJTPl6a~9qj&E3BC7znzO+JY}@jZmkFNKuYLAtbh%c~8$I>P(Bzj6}%$Z;9*5zvG}P zWa?}GNkxzA*%|LbX*nXJUYNbLb7Yz!7wO)^crUN2wM8!!{kXU0xN#b+zgiyscLez@ z@^dJ<8XzTFVn%lp1Xtz-K)wdm&E;eAnmM;-wt*?t(b_fVsspoJm*~dr-z5oEAV0fu zwMxFtP+h}jlX5X`Vj`%#M#NO*%jmxq^YlfW&1At4lW(ls_gvljd!oBS0uu?(F5H(c zqhi7r*PoB|nXJqszbNYl<~-L?-QphiRgC1r%;<^PY4tQbJZY~O$X$#tcyrx5W)pj! zUIn+aFuLv8B+5m>G)rNha`e~_Y6Z+2q0VRtjE8yXa?i{P5WC(LSWu|+-r7}c$N|pF zz_j)W6(*@PXqn`|Z_&wvx~%Y3<5JgbxGfE|p83q=8va6{Zz-?j6O$YRv=p{!5!EEx z%U=xJ)VjO^`EF@~QH^2^LwvV+T}3oFC=XX{8fW5&0%2~YYqvw?Ug!y`tl4z<9=Il) h-HG>mCmP|};~TD`DQSOtIC=23vNE$Ztu;n~{{SBxY104z diff --git a/doc/img/f5.png b/doc/img/f5.png index 6fb3bc8f6e7e9455f432923fc503475926c29d29..855917afca8988249c3500bbaa09d819c6f39178 100644 GIT binary patch literal 2433 zcma)8c{tQv8=kIadKsm$WLhNaWL_d<-x`s@Sd)YpLP;1z!jPXPCY8o6WvOhHvAkn9 zc}KElC&XCBP9|d)V_xrfeb@E%y7%TJUM#*ml=My-cF}Wx1pE8%CsO=vQM@uoqnrr$^VkrYdcgLY((&FQ z7*W9u)jHXEGeW`^Mu1rU3ZN)z?)$qps;p+4?2y$sew3*DVHK5<-BDr63d(FpCSV?p7=!PN4K8y`nC-JH{`BKxrXWohu>8 zs?-p>W3Za2N0}ad#1YVGtNf3Ev}|+N zlxO)$@I73p(crBNa>dEc!41-DgNxO(AQhtcjXO1v<@N`ngQo>EyC+phkR zqTY{XtPH-Jp&mbHdRQkBo z0=50DMAk+yq zB7m#i-x)`dR0vT}Y?rSw$9X!Nwi|2@!m?&Q-(QK9oBKm}@M6^bVvJ`iXa^#qngPLAAdwo%AN zSpp)qtACN`mm!0ZXH>%G+ ze$d#y9i*Gfh9iS(uzyY!*cQGWdduTvy!x4jD>x7k$M3?f^C-fWl$%=Q09A33<7J3; zd1h3hex2T3my7GRbE%SyuSx5{&z>5I%W*Tqvd)oTkBm1s@NqUa7`wkBU&|2}gjxCy z*1YDY%P%Y<5Ne0B#w>MZ$GY9YEP2o@6=;pgqX!zn8A8HG1VV97f{*Rhl$um%BQ{w+ z0U!Utk25M^3zBQ@`3X2`2;A$wbQxcf)?j`v2Dw~$S^>qPp2wROa!pGa_|uyruuU`Q zx*h4{xO3CUBZNoNHcy2T``9_n9PYJYN-jA5af(8@YtyA*gQAijH`+$>UF59M7WpX_ zO4G5&54`bCgx(?osvs| z$vV!aVcphn&o&7K4_d>Sc`@EO15vXtrzvfzVM}mf9$vHHADbJD@gmWd(w>6oftOqA z$>!xP*=yppj7d#mN1B&eszV_sSCEMZ*YZE(DUBDyQ!-CQoDb??^ipGNC%<`iz9f8> znQc#!E?dp;`+S$*n$?T8y|O)6x2_r9tT1YH*1-DI?mXpI>0uW0Pd33I^2VCxTh-9~>06S2;#1z2^YmLC7-)G@h(^kba6CP4Y>*YaYF)Q7$ zL1D=HW{L`xaMA7V&ZlQ;+Gd@jZF9HIj-0N1a6V7!P=^U5yrnp^*0eh+zPZA-p(wu+ zT#6BzKBJvSWV6$(8nLQACnxBxT7Gr@tWUTZda-)jy8TB+16^Z~_ux0d^1G}xKMrUt zHe6nW_kSd-WscLn(LX-n@Z%WT#w0KsCi}+=GvrNOOhekisps5=aH;KDy+Ck4h3tgx z(}j5haxtJmb%gmRCIW2ayFZ;qnjr6tBf;;KE3|XV587Nv3nDSit|ecInJiKEmD?O@ zJ(~<(2)(PMN?8swymtLz7*6F^-fat;iU2+;d7WHz4azBaF`s={1P|vE&hS{Eh{k@1 zfiBNh=c+M9gI4J(|8U-aFPF7wi#=Ue>g(6W%epfkD(>j@Y{gzCr->o^xo)uKdTr9!Pl94m>s0oK6B_)khr=-!4@q$V z#8=0uR)Q~Ie5=J&Lmi6WXRx}vzU}0f^$(4)detCWNFLWn_;-gGqV@dGN^aQ!)_buo zlRL_4c4J&WyVbwMdGG$%tX7uk9#urZQ{-O8$9pGarpR5QioXNm;gnR2cpjrjn<4Sd zR=j2E0=yJ;LnEizn+p+HQX#oGgf(VV58zPA#v`#X37sP}&71vWtH8Yd5_TZn9z20^ z!Tmy$ z&j+_XXqrtu_FUXmAjZ{5|gOW8;5qwFRbQ?rRxZ{8QIYk+aM#^Ib$I=hL?x8QWVv0@yv0)P sp(a|=n7D63do5Cnkr3|ppC`Y&e_!Im*^%63zP~?GMh0g3WIZhK7t<+usQ>@~ literal 2593 zcma)8c{mhW8+U6a#xP+*h{7)PFfEFsyq7|V=qBYVo4ku4f=vkloJ zjZv1e6k%kG>}!}YvdlN#f4=VW$9JCd{@(MPR$Wnj@L%aH7q9B@kMX#q^&;i%mSD{n^`>pN85H_3T=cVY<`KN*vjh(eJ?_tP!u zq$ct!XYxn9Y*=?AA%YVisP2shVhaX^p?V! z$D5{xW&cUFDT&{DrAC>&1!M75h{E7EVV$)IMaisTUl=-d{Bz&A@{Z+jA*x$&KEo3m ztlnF#c8bL(My;{pKF0+ir^Ni@{x_m~I4N-vG!`f~(-lWcKIEz0pj2UsCzzB+@yeM~ z@lO8sFr8F8HaOvJ@$aKxsbn6*sxt<9yd(A>W^OF)xS8GfI1+H}t_C;@%l6S-BDt%m z_Ube6mXV(QrI6O<--(SB3OF_RJql!Ncu-nkXsVprQ7Sv32IsLbAC|TVasjySP9H*@ zV-?%0x$`Imlv7<`K=?$Y zE+^pT)NiC5{R1uZdh&d(rQe3!YYES3OF4FZEeIAA#4(icS{qB?;cb z=%H#r&vJ?9cztBpJ2Db{UbPTO>GPR4ayyLi<#FmdnF=g+Xb(<6lSG-xB{zLDUMh?J z2Mx@rgs#A58{RL|@`}NvrV*smB;Ss!d)vp6MVv)OhHmu;;k(>{?>aXrA z>|){`G9=6O> z+N!e6Wz|MP{@z&q@T6$0j1ovHB7eYFpYSTOLFQnseTw;KX#WOH_LOj=bpkQbry&m% z`~XxgvMdb62QN7bAD>G~p;Kw23I*0iDcu+1K=BixjX6fVqn-J&IYu^5_{MbOZqbH> zE?I0#S`MSgHpe{pH%))exF(P4qoA{tRd3PN)0jwh?&<;ScqB`DyGJ# z-f>*pz3s*!`4aGtXK8Am)t+Hwnjg*A#dp*yuyD$7qEcma)qCGmetN#ja$?%bR6~@( z*j}YJc)3#5+v8|reAwPjlGaC)KIW{(nfYC;l9GT2h_Vod_5WKcKC8DhJbYN<^~$xqrt@sB z^`VmqFKEQm$k^5&VGTOkLr;H^4X(KJ)T{F;jOhNbUmD1GO+DPD4U}y;uCG`8=Ui-^!}TKYb3{QWj$R_Vb@sm3#ge?3*?lvW=PKKS)r`4D zrFxd@w>cwuqTBLW@%|_b@pYE-9PzC~UIGca1-6|MN1D>x5+dyivdf>Tj|!rNXC zNKp|FV>NdAFsu3M{QWMXfXJ9C5^QCcme%H5xk{8zZzAa3BdHTjOv|aCfio48ozCG> zf?E=u@pOYh_SiH|hzeIrcA%T(U92toDQObw0vtNBlBusdmDoO28S+|;G5KRP>5>4j z#Y9EWp@owfyy|#}{zwuOSsu(qRn8ROi!d0HBV3%Fakf9$d4n06Fb}E|++yg3&2R4G zyWb8q@yXS{6etT@Ix0pDLdp)4swVYy0B1;^Q(plsC;Q7MOe*A=5}<{|FHdg2lt;T0 zcF4quH?|uyl8iNyt24ES~d6=+3AJ%S^k}xCt?cUxg4q`L#98_C*=8$Z9cMB>%cbb1yyL9t89Z1 zb@r?472Lp-8#xs5gxLLgSdmjGLtiVf|N3ZPW05eOW1Ns~=Egz9i)aZQe00xAZK>OL zTcdQkiALO*YlX0wC6=3S1Zmv!TX}oPHF$TQ5~+j=4|)Fh9S>wc-G6XQuy7&orlye4 tsJbe6+Xx*xT^WM3m)6qyTZYrX2iy#?I?pE8?7r_GJuJo;U9RUy{4WGoyXpV{ diff --git a/doc/ja/appnote.html b/doc/ja/appnote.html index ce38a02..f6e6df9 100644 --- a/doc/ja/appnote.html +++ b/doc/ja/appnote.html @@ -9,7 +9,7 @@ -

FatFsモジュール アプリケーション・ノート (for R0.04)

+

FatFsモジュール アプリケーション・ノート


@@ -19,14 +19,35 @@
  • 処理系はANSI C準拠であること。
    FatFsモジュールはANSI C準拠で記述されているので、ANSI C準拠のコンパイラなら特に処理系依存な点はありません。ただし、FATというシステム間でポータブルな構造体を操作するため、プロセッサのエンディアンの違いは意識する必要があります。これは ff.h(tff.h) で定義されているので、最初にこれを適切に設定します(忘れている場合はエラーを出す)。
  • char/short/long のサイズは、それぞれ 8/16/32ビットであること。
    -整数の型とサイズに関してはまっとうなコンパイラなら問題ないと思います。integer.h内の typedefと既存の定義が衝突した場合は矛盾がないように注意しなければなりません。
  • +integer.h内でtypedefされています。整数の型とサイズに関しては、まっとうな処理系なら問題ないはずですが、既存の定義と衝突した場合は矛盾がないように注意しなければなりません。
    +
    +

    メモリ使用量 (R0.04a)

    +

    各種環境でのモジュールのメモリ使用量の例を示します。数値の単位はバイトで、Dは論理ドライブ数、Fは同時オープン・ファイル数を示します。最適化オプションは、全てコード・サイズとしています。

    + + + + + + + + + + + + + + + + +
    AVRH8/300HMSP430TLCS-870/CV850ESSH2
    コンパイラgccCH38CL430CC870CCA850SHC
    _MCU_ENDIAN122112
    FatFs コード
    (標準, R/W構成)
    8672874663847390
    FatFs コード
    (標準, R/O構成)
    4232410030123510
    FatFs コード
    (最小, R/W構成)
    5706567840424882
    FatFs コード
    (最小, R/O構成)
    3018311621982702
    FatFs 静的ワークD*2 + 2D*4 + 2D*4 + 2D*4 + 2
    FatFs 動的ワークD*550 + F*544D*550 + F*550D*550 + F*550D*550 + F*550
    Tiny-FatFs コード
    (標準, R/W構成)
    7188720665908799
    Tiny-FatFs コード
    (標準, R/O構成)
    3592356031624353
    Tiny-FatFs コード
    (最小, R/W構成)
    4670477243226073
    Tiny-FatFs コード
    (最小, R/O構成)
    2576271423783324
    Tiny-FatFs 静的ワーク4644
    Tiny-FatFs 動的ワーク542 + F*28542 + F*32542 + F*28542 + F*28
    +
    +

    FatFs vs. Tiny-FatFs

    -

    ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsはデフォルトではFAT32に対応していないので、使用できるディスクは2GB(FAT64で4GB)までという制約があります。_USE_FAT32オプションでFAT32がサポートされますが、コード・サイズが膨らみます。

    -

    フル機能のFatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な場合に有効です。

    +

    ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsは標準構成ではFAT32に対応していないので、使用できるディスクは2GB(FAT64で4GB)までという制約があります。_USE_FAT32オプションでFAT32を追加できますが、その分コード・サイズが膨らみます。フル機能のFatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な場合に有効です。

    @@ -55,33 +76,31 @@ FatFs

    ここでファイルI/Oバッファとは、データ・セクタの一部を読み書きするための1セクタ長のバッファで、FatFsではそのファイル・オブジェクト内の、Tiny-FatFsではワークエリア内のバッファのことを指しています。

    Tiny-FatFsでは、全てのデータ転送とFATやディレクトリへのアクセスをただ一つのセクタ・バッファで行っているため、データ転送によりFATのキャッシュが失われ、クラスタ境界を通過するたびにFATセクタを読み直す必要があります。FatFsの場合は、データ用バッファはFAT用とは別なので、FATセクタを読む頻度はTiny-FatFsの 1/341, 1/256 または 1/128で済みます(クラスタが連続している場合)。つまり、Tiny-FatFsは性能低下の代償を払ってRAM使用量を削減しているわけです。

    -

    転送領域のうちセクタ全体を含む部分は(図2)のようにファイルI/Oバッファを介さず、ディスクとの間で直接転送されます。完全なセクタ・アライメント・アクセスの場合(図3)は、ファイルI/Oバッファは全く使用されません。直接転送では、可能ならdisk_read()に複数セクタを指定して最大限のマルチ・セクタ転送が行われます。ただし、クラスタ境界をまたぐときは、たとえセクタが連続していたとしても転送は分割されます。

    -

    このように、極力セクタ・アライメント・アクセスになるように配慮すれば、無駄なデータ転送が減って性能が向上します。さらに、Tiny-FatFsではFATのキャッシュが生きるようになり、FatFsと同じ性能と省メモリ特性が同時に得られます。

    +

    転送領域のうちセクタ全体を含む部分は(図2)のようにファイルI/Oバッファを介さず、ディスクとの間で直接転送されます。完全なセクタ・アライメント・アクセスの場合(図3)は、ファイルI/Oバッファは全く使用されません。直接転送では、可能ならdisk_read()に複数セクタを指定して最大限のマルチ・セクタ転送が行われます。ただし、クラスタ境界をまたぐときはクラスタが隣接していたとしても転送は分割されます。

    +

    このように、極力セクタ・アライメント・アクセスになるように配慮すれば、無駄なメモリ・コピーが減って性能が向上します。さらに、Tiny-FatFsではFATのキャッシュが生きるようになり、省メモリ特性とFatFsの性能とが同時に得られます。

    クリチカル・セクション

    -

    ディスク上のFAT構造を操作している途中で、停電、不正なメディアの取り外し、回復不能なデータエラー等の障害が発生すると、更新が中途半端な状態で中断され、その結果としてFAT構造が破壊される可能性があります。次にFatFsモジュールにおけるクリチカル・セクションと、その間の障害により起きうるエラーの状態を示します。

    +

    ディスク上のFAT構造を操作している途中で、停電、不正なメディアの取り外し、回復不能なデータ・エラー等の障害が発生すると、処理が中途半端な状態で中断され、その結果としてFAT構造が破壊される可能性があります。次にFatFsモジュールにおけるクリチカル・セクションと、その間の障害により起きうるエラーの状態を示します。

    図4. 長いクリチカル・セクション
    -fig.4 +fig.4
    図5. 短くしたクリチカル・セクション
    -fig.5 +fig.5

    -

    赤で示したセクションを実行中に障害が発生した場合、クロスリンクが発生して操作対象のファイル・ディレクトリが失われる可能性があります。黄色で示したセクションを実行中に障害が発生した場合、つぎのうちいずれかまたは複数の結果が生じる可能性が考えられます。

    +

    赤で示したセクションを実行中に障害が発生した場合、クロス・リンクが発生して操作対象のファイル・ディレクトリが失われる可能性があります。黄色で示したセクションを実行中に障害が発生した場合、つぎのうちいずれかまたは複数の結果が生じる可能性があります。

      -
    • 書き換え中のファイルのデータ構造が破壊される。
    • +
    • 書き換え中のファイルの内容が破壊される。
    • 追記中のファイルがオープン前の状態に戻る。
    • 新規に作成されたファイルが消える。
    • -
    • 新規に作成されたファイルの長さがゼロになって残る。
    • -
    • 上書きで作成されたファイルの長さがゼロになって残る。
    • -
    • 上書きで作成されたファイルが作成前の状態に戻る。
    • +
    • 新規または上書きで作成されたファイルの長さがゼロになって残る。
    • ロストチェーンの発生によりディスクの利用効率が悪化する。
    -

    いずれも書き込み中でないファイルには影響はありません。これらのクリチカル・セクションは、ファイルを書き込みモードで開いている時間を最小限にするか、f_sync()を適宜使用することで図5のように最小化することができます。

    +

    いずれも書き込み中や操作対象でないファイルには影響はありません。これらのクリチカル・セクションは、ファイルを書き込みモードで開いている時間を最小限にするか、f_sync()を適宜使用することで図5のようにリスクを最小化することができます。

    @@ -89,18 +108,18 @@ FatFs

    現リビジョンの問題点とその改善案

    • ファイル・オブジェクトの抽象化
      -現在はファイル・オブジェクトの実体をアプリケーション側で管理しているので、アプリケーション・モジュールでのスタック消費量が多くなります(Tiny-FatFsでは問題にはならない)。これをハンドルで管理するなどより抽象化すればアプリケーション・モジュールでのスタック消費量を減らせます。この場合、FatFs内でファイル・オブジェクトの領域を静的に確保しておくか、malloc()することになります。ただし、このようにするとファイル・オブジェクトを直接参照できなくなり、feofやftellなどムダな関数が新たに必要になります。
    • +現在はファイル・オブジェクトの実体をアプリケーション側で管理しているので、アプリケーション・モジュールでのスタック消費量が多くなります(Tiny-FatFsでは問題にならない)。これをハンドルで管理するなどより抽象化すればアプリケーション・モジュールでのスタック消費量を減らせるし、他のファイル・システムへの対応も容易になります。この場合、FatFs内でファイル・オブジェクトの領域を静的に確保しておくか、malloc()することになります。ただし、このようにするとファイル・オブジェクトを直接参照できなくなり、feofやftellなどムダな関数が新たに必要になります。
    • セクタ・バッファ管理の改善
      現在はセクタ・バッファを固定して使用しているため、無駄なディスクアクセスが多く効率が悪い。メモリの潤沢なシステムでは、複数のセクタ・バッファを使用してディスク・キャッシュを構成すれば性能を向上させることができます。
    • FSInfoへの対応
      FAT32ではその膨大なクラスタ数のため、ファイル新規作成や空きスペース取得時のクラスタ・サーチにかなりの時間を要します。このため、最終割り当てクラスタ番号や残りクラスタ数がFSInfoセクタに記録されていて、延々とクラスタ・サーチするのを避けられるようになっています。現在はFSInfoに未対応なので、空きスペース取得時や、ディスク使用量が多い状態でのファイル作成(作成後の最初の書き込み)処理時間は問題になるレベルです。
    • 長いファイル名への対応
      -FATの拡張仕様では従来の8.3形式ファイル名に加え、255文字までの長いファイル名を扱えるようになっていますが、現リビジョンでは未対応で8.3形式しか使用できません。これに対応するには、ファイル名だけでも500バイト以上のバッファが必要になったり、UCS-2とShift_JISの相互変換(巨大な変換テーブル)が必要となるなど、メモリの消費が爆発的に増えてしまいます。なお、長いファイル名の機能はMicrosoft社の特許になっているため、これを製品に使うにはライセンス契約が必要です。
    • +FATの拡張仕様ではMS-DOSの8.3形式ファイル名に加え、255文字までの長いファイル名(LFN)を扱えるようになっていますが、現リビジョンでは未対応で8.3形式しか使用できません。これに対応するには、ファイル名だけでも500バイト以上のバッファが必要になったり、UCS-2とShift_JISの相互変換(巨大な変換テーブルを使う)が必要となるなど、メモリの消費が爆発的に増えてしまいます。なお、LFNの機能はMicrosoft社の特許になっているため、これを製品に使うにはライセンス契約が必要です。
    • RTOSへの対応
      -FatFsモジュールを使用するタスクを一つに限るなら特に意識する必要はありませんが、複数のタスクから使用するには、何らかの排他制御が必要になってきます。FatFsモジュールのRTOSへの対応作業は、TOPPERSプロジェクトで行われています。
    • +FatFsモジュールを使用するタスクを一つに限るなら特に意識する必要はありませんが、同じ論理ドライブに複数のタスクから同時アクセスするには、何らかの排他制御が必要になってきます。FatFsモジュールのRTOSへの対応作業は、TOPPERSプロジェクトで行われています。

    -

    そして、これらの機能拡張を行うとそれだけ多くのリソースが要求されるようになり、このプロジェクトが対象としている8/16ビット・マイコンのシステムに載せられなくなってしまうという問題もあります(これが一番の問題かも知れません)。

    +

    そして、これらの機能拡張を行うとそれだけ多くのリソースが要求されるようになり、このプロジェクトの対象とする8/16ビット・マイコンのシステムに載せられなくなってしまうという問題もあります(これが一番の問題かも知れません)。

    戻る

    diff --git a/doc/ja/chmod.html b/doc/ja/chmod.html index 4705c9a..02b12a1 100644 --- a/doc/ja/chmod.html +++ b/doc/ja/chmod.html @@ -38,7 +38,7 @@ FRESULT f_chmod (
    メモリ容量FATタイプ
    AttributeMask
    -
    変更する属性のマスク。指定した属性が設定または解除され、指定されなかった属性は保持されます。Attributeと同じ値を使います。
    +
    変更する属性のマスク。指定した属性が設定または解除され、指定されなかった属性は状態が保持されます。Attributeと同じ値を使います。
    @@ -61,7 +61,7 @@ FRESULT f_chmod (
    FR_WRITE_PROTECTED
    メディアが書き込み禁止状態。
    FR_RW_ERROR
    -
    ディスクアクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    その論理ドライブにワーク・エリアが与えられていない。
    FR_NO_FILESYSTEM
    diff --git a/doc/ja/close.html b/doc/ja/close.html index 295e87f..825ba11 100644 --- a/doc/ja/close.html +++ b/doc/ja/close.html @@ -35,7 +35,7 @@ FRESULT f_close (
    FR_OK (0)
    正常終了。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_INVALID_OBJECT
    diff --git a/doc/ja/dioctl.html b/doc/ja/dioctl.html new file mode 100644 index 0000000..228c28d --- /dev/null +++ b/doc/ja/dioctl.html @@ -0,0 +1,64 @@ + + + + + + + +FatFs - disk_ioctl + + + + +
    +

    disk_ioctl

    +

    セクタの読み書き以外のディスク・ドライブ自体に対する様々な制御をします。

    +
    +DRESULT disk_ioctl (
    +  BYTE Drive,      /* 物理ドライブ番号 */
    +  BYTE Command,    /* 制御コマンド */
    +  void* Buffer     /* データ受け渡しバッファ */
    +);
    +
    +
    + +
    +

    引数

    +
    +
    Drive
    +
    物理ドライブ番号(0-9)を指定します。
    +
    Command
    +
    制御コマンド・コードを指定します。
    +
    Buffer
    +
    制御コマンドに依存したパラメータを授受するバッファを指すポインタを指定します。バッファを使用しないコマンドの場合は、NULLを指定します。
    +
    +
    + +
    +

    戻り値

    +
    +
    RES_OK (0)
    +
    正常終了。
    +
    RES_ERROR
    +
    何らかのエラーが発生した。
    +
    RES_PARERR
    +
    コマンドが不正。
    +
    RES_NOTRDY
    +
    ドライブが動作可能状態ではない、または初期化されていない。
    +
    +
    + +
    +

    解説

    +

    物理ドライブの種類によりサポートされるコマンドは異なりますが、FatFsモジュールでは、ドライブの種類に依存した制御は行いません。次のドライブ共通コマンドを使用します。リード・オンリー構成ではこの関数は必要とされません。

    + + + + +
    コマンド解説
    GET_SECTOR_COUNTBufferの指すDWORD変数にドライブ上の総セクタ数を返します。
    CTRL_SYNCディスクへのデータの書き込みが完了するのを待ちます。ライト・バック・キャッシュを持っている場合は、書き込まれていないデータを即時書き戻します。
    +
    + + +

    戻る

    + + diff --git a/doc/ja/dread.html b/doc/ja/dread.html index a8785d8..40f7406 100644 --- a/doc/ja/dread.html +++ b/doc/ja/dread.html @@ -41,7 +41,7 @@ DRESULT disk_read (

    戻り値

    -
    RES_OK
    +
    RES_OK (0)
    正常終了。
    RES_ERROR
    読み込み中にエラーが発生した。
    diff --git a/doc/ja/dstat.html b/doc/ja/dstat.html index 344aec1..29447bb 100644 --- a/doc/ja/dstat.html +++ b/doc/ja/dstat.html @@ -34,11 +34,11 @@ DSTATUS disk_status (

    物理ドライブの状態が次のフラグの組み合わせの値で返されます。

    STA_NOINIT
    -
    ドライブが初期化されていないことを示すフラグ。電源ONまたはメディアの取り外しでセットされ、disk_initialize() の正常終了でクリア、失敗でセットされます。
    +
    ドライブが初期化されていないことを示すフラグ。システム・リセットやメディアの取り外し等でセットされ、disk_initialize() の正常終了でクリア、失敗でセットされます。
    STA_NODISK
    メディアがセットされていないことを示すフラグ。メディアが取り外されている間はセットされ、メディアがセットされている間はクリアされます。固定ディスクでは常にクリアされています。
    STA_PROTECTED
    -
    メディアがライト・プロテクトされていることを示すフラグ。ライト・プロテクト・ノッチをサポートしないメディアでは常にクリアされています。
    +
    メディアがライト・プロテクトされていることを示すフラグ。ライト・プロテクト機能をサポートしないメディアでは常にクリアされています。
    diff --git a/doc/ja/dwrite.html b/doc/ja/dwrite.html index ce0e7a9..bdb10ca 100644 --- a/doc/ja/dwrite.html +++ b/doc/ja/dwrite.html @@ -27,7 +27,7 @@ DRESULT disk_write (

    引数

    Drive
    -
    書き込むドライブ番号を指定します。
    +
    物理ドライブ番号(0-9)を指定します。
    Buffer
    ディスクに書き込むデータを指定します。
    SectorNumber
    @@ -41,7 +41,7 @@ DRESULT disk_write (

    戻り値

    -
    RES_OK
    +
    RES_OK (0)
    正常終了。
    RES_ERROR
    書き込み中にエラーが発生した。
    diff --git a/doc/ja/filename.html b/doc/ja/filename.html index d92d391..dc6f606 100644 --- a/doc/ja/filename.html +++ b/doc/ja/filename.html @@ -9,27 +9,47 @@ -

    ファイル・ディレクトリの指定方法

    -
    +

    ファイル・ディレクトリの指定方法

    FatFsモジュールでのファイル、ディレクトリ、ドライブの指定方法はMS-DOSとほぼ同じです。ただし、MS-DOSのようなカレント・ディレクトリの概念は無いので、常にルート・ディレクトリから辿る絶対パスでの指定となります。パス名の指定方法と例は次の通りです。

     
      "[論理ドライブ番号:][/]ディレクトリ名/ファイル名"
     
    - "file1.txt"           ファイル(drive0)
    + "file1.txt"           ファイル(ドライブ0)
      "/file1.txt"          ↑と同じ
    - "dir1/dir2/file1.txt" ファイル(drive0)
    - "2:dir3/file2.txt"    ファイル(drive2)
    - "2:/dir5"             ディレクトリ(drive2)
    - ""                    ルート・ディレクトリ(drive2)
    + "dir1/dir2/file1.txt" ファイル(ドライブ0)
    + "2:dir3/file2.txt"    ファイル(ドライブ2)
    + "2:/dir5"             ディレクトリ(ドライブ2)
    + ""                    ルート・ディレクトリ(ドライブ0)
      "/"                   ↑と同じ
    - "2:"                  ルート・ディレクトリ(drive2)
    + "2:"                  ルート・ディレクトリ(ドライブ2)
     
     
    -

    FatFsモジュールは8.3形式ファイル名にのみ対応しています。長いファイル名には対応していないので、ファイル名やディレクトリ名は8.3形式の範囲内で指定します。ディレクトリ・セパレータには'/'を使用します。パス名先頭の'/'は、あってもなくても同じです。

    -

    論理ドライブ番号は、'0'〜'9'の一文字の数字とコロンで指定します。省略した場合は"0:"を指定したことになります。FatFsでは論理ドライブ毎にファイル・システム・オブジェクトというワーク・エリアを持っています。現在のところ、論理ドライブは同じ番号の物理ドライブに結びつけられています。

    -

    Tiny-FatFsでは一つのファイル・システム・オブジェクトしか持てず、常に論理ドライブ0として動作します。また、パス名中に論理ドライブ番号を使用できません。

    +

    FatFsモジュールは8.3形式ファイル名にのみ対応しています。長いファイル名には対応していないので、ファイル名やディレクトリ名は8.3形式の範囲内で指定します。ディレクトリ・セパレータには'/'を使用します。パス名先頭の'/'は、あってもなくても同じです。論理ドライブ番号は、'0'〜'9'の一文字の数字とコロンで指定します。省略した場合は"0:"を指定したことになります。Tiny-FatFsでは一つのファイル・システム・オブジェクトしか持てず、常に論理ドライブ0として動作します。また、パス名中に論理ドライブ番号を使用できません。

    +
    +


    +
    +

    論理ドライブと物理ドライブの対応

    +

    標準構成では、それぞれの論理ドライブは同じ番号の物理ドライブに1:1で結びつけられていて、先頭の区画がマウントされます。構成オプションで_MULTI_PARTITIONを指定すると、論理ドライブに対して個別に物理ドライブ番号・区画を指定できるようになります。この構成では、論理ドライブと区画の対応を解決するためのテーブルを次に示すように定義する必要があります。

    +
    +例:論理ドライブ0〜2を物理ドライブ0(固定ディスク)の3つの基本区画に割り当て、
    +   論理ドライブ3を物理ドライブ1(リムーバブル・ディスク)に割り当てる場合。
    +
    +const PARTITION Drives[] = {
    +    {0, 0},     /* Logical drive 0 ==> Physical drive 0, 1st partition */
    +    {0, 1},     /* Logical drive 1 ==> Physical drive 0, 2nd partition */
    +    {0, 2},     /* Logical drive 2 ==> Physical drive 0, 3rd partition */
    +    {1, 0}      /* Logical drive 3 ==> Physical drive 1 */
    +};
    +
    +

    複数区画指定を使用する場合、次の点に注意しなければなりません。 +

      +
    • 指定可能な区画は基本区画(0〜3)のみ。
    • +
    • 物理ドライブがSFD形式(区画テーブル無し)の場合、区画指定は無視される。
    • +
    • 複数の論理ドライブを持つ物理ドライブは、固定ディスクでなければならない。
    • + +
    diff --git a/doc/ja/getfree.html b/doc/ja/getfree.html index ff3fa2a..deb6940 100644 --- a/doc/ja/getfree.html +++ b/doc/ja/getfree.html @@ -28,7 +28,7 @@ FRESULT f_getfree (
    Path
    情報を得る論理ドライブのルートディレクトリのパス名が入った'\0'で終わる文字列へのポインタを指定します。
    Clusters
    -
    空きクラスタ数を格納するDWORD変数へのポインタを指定します。
    +
    空きクラスタ数を格納するDWORD変数へのポインタを指定します。
    FileSystemObject
    対象ドライブのファイル・システム・オブジェクトを指すポインタを格納するポインタへのポインタを指定します。
    @@ -39,13 +39,13 @@ FRESULT f_getfree (

    戻り値

    FR_OK (0)
    -
    正常終了。*Clustersに空きクラスタ数が返されます。
    +
    正常終了。*Clustersに空きクラスタ数が返されます。
    FR_INVALID_DRIVE
    ドライブ番号が不正。
    FR_NOT_READY
    メディアがセットされていないなど、ディスクドライブが動作不能状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    その論理ドライブにワーク・エリアが与えられていない。
    FR_NO_FILESYSTEM
    @@ -74,7 +74,7 @@ FRESULT f_getfree ( // Get free space printf("%lu KB total disk space.\n" "%lu KB available on the disk.\n", - (fs->max_clust - 2) * fs->sects_clust / 2, + (DWORD)(fs->max_clust - 2) * fs->sects_clust / 2, clust * fs->sects_clust / 2);
    diff --git a/doc/ja/lseek.html b/doc/ja/lseek.html index 8a5866e..ea36566 100644 --- a/doc/ja/lseek.html +++ b/doc/ja/lseek.html @@ -38,31 +38,37 @@ FRESULT f_lseek (
    FR_OK (0)
    正常終了。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_INVALID_OBJECT
    -
    無効なファイルオブジェクト。
    +
    無効なファイル・オブジェクト。

    解説

    -

    ファイルR/Wポインタを移動します。オフセットの指定はファイル先頭からのみです。ファイル末尾以降への移動はできません。ファイル・サイズ以上のオフセットを指定した場合、R/Wポインタはファイル・サイズと同じになります。

    +

    ファイルR/Wポインタ(ファイル・オブジェクト内のfptrメンバで、次に読み出し・書き込みされるバイトのオフセットを示す)を移動します。オフセットの原点はファイル先頭からです。書き込みモードでファイル・サイズより大きな値を指定すると、そこまでファイルが拡張され、拡張された部分のデータは未定義となります。大容量データを遅延無く高速に書き込みたいときは、予めこの関数で必要なサイズまでファイルを拡張しておくと良いです。f_lseek関数が正常終了したあとは、ファイルR/Wポインタが正しく移動したかfptrをチェックするべきです。ファイルR/Wポインタが指定より小さいときは、次の原因が考えられます。

    +
      +
    • 非書き込みモードのため、ファイル・サイズでクリップされた。
    • +
    • ファイル拡張中にディスクが満杯になった。
    • +
    • FAT構造にエラーがある。
    • +
    +

    _FS_MINIMIZE >= 3ではこの関数はサポートされません。

    使用例

    -    // ファイル先頭から5000バイト目へ移動
    +    // ファイル・オフセット5000へ移動
         res = f_lseek(&file, 5000);
     
         // 3000バイト進める
         res = f_lseek(&file, file.fptr + 3000);
     
    -    // 2000バイト戻す
    +    // 2000バイト戻す(オーバーフローに注意)
         res = f_lseek(&file, file.fptr - 2000);
     
         // ファイル追記の準備
    diff --git a/doc/ja/mkdir.html b/doc/ja/mkdir.html
    index 4a065d0..26d59e9 100644
    --- a/doc/ja/mkdir.html
    +++ b/doc/ja/mkdir.html
    @@ -41,13 +41,15 @@ FRESULT f_mkdir (
     
    FR_INVALID_DRIVE
    ドライブ番号が不正。
    FR_DENIED
    -
    同名のディレクトリやファイルの存在、ディスクやディレクトリ・エントリが満杯の場合など。
    +
    ディスクやディレクトリ・エントリが満杯の場合など。
    +
    FR_EXIST
    +
    同名のディレクトリやファイルが存在する。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_WRITE_PROTECTED
    メディアが書き込み禁止状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    その論理ドライブにワーク・エリアが与えられていない。
    FR_NO_FILESYSTEM
    diff --git a/doc/ja/mkfs.html b/doc/ja/mkfs.html index 35019cc..ba4755f 100644 --- a/doc/ja/mkfs.html +++ b/doc/ja/mkfs.html @@ -15,9 +15,9 @@

    ドライブ上にFATファイル・システムを作成(フォーマット)します。

     FRESULT f_mkfs (
    -  BYTE  Drive,            /* Logical drive number */
    -  BYTE  PartitioningRule, /* Partitioning rule */
    -  BYTE  AllocSize         /* Allocation unit size */
    +  BYTE  Drive,              /* Logical drive number */
    +  BYTE  PartitioningRule,   /* Partitioning rule */
    +  BYTE  AllocSize           /* Allocation unit size */
     );
     
    @@ -45,14 +45,16 @@ FRESULT f_mkfs (
    メディアがセットされていないなど、物理ドライブが動作不能状態。
    FR_WRITE_PROTECTED
    メディアが書き込み禁止状態。
    +
    FR_NOT_ENABLED
    +
    その論理ドライブにワーク・エリアが割り当てられていない。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_MKFS_ABORTED
    -
    次の理由で処理が中断された。 +
    次の理由で開始前に処理が中断された。
    • ディスク・サイズが小さすぎる。
    • 何らかの引数が無効。
    • -
    • そのクラスタ・サイズが使えない。クラスタ数が0xFF7と0xFFF7近辺になると発生する可能性がある。
    • +
    • そのクラスタ・サイズが使えない。クラスタ数が0xFF7と0xFFF7近辺になるとき発生する可能性がある。
    @@ -60,8 +62,9 @@ FRESULT f_mkfs (

    説明

    -

    f_mkfs関数はFATファイル・システムをドライブ上に作成します。リムーバブル・メディアのパーテーショニング・ルールとしては、FDISK形式とSFD形式がありますが、多くの場合はFDISK形式が推奨されます。FATタイプ(FAT12/FAT16/FAT32)は、ディスク上のクラスタ数によってのみ決定される決まりになっていて、それ以外の要因はありません。したがって、どのFATタイプになるかは、ディスク・サイズとクラスタ・サイズに依存します。

    -

    この関数は、FatFsで_USE_MKFSを選択したときにサポートされます。

    +

    f_mkfs関数はFATファイル・システムをドライブ上に作成します。リムーバブル・メディアのパーテーショニング・ルールとしては、FDISK形式とSFD形式がありますが、FDISK形式が一般的です。この関数は複数区画には対応していないので、その物理ドライブの既存の区画は全て削除され、全体が一つの区画になります。

    +

    FATタイプ(FAT12/FAT16/FAT32)は、ディスク上のクラスタ数によってのみ決定される[FAT仕様書より]決まりになっていて、それ以外の要因はありません。したがって、どのFATタイプになるかは、ディスク・サイズとクラスタ・サイズに依存します。クラスタ・サイズは大きいほど性能が上がるので、特に小容量のドライブでなければ64セクタを選択しておけばよいです。

    +

    この関数は、FatFsで構成オプション_USE_MKFSを選択したときにサポートされます。また、Tiny-FatFsではサポートされません。

    diff --git a/doc/ja/mount.html b/doc/ja/mount.html index 7d82b83..02e9b7e 100644 --- a/doc/ja/mount.html +++ b/doc/ja/mount.html @@ -44,8 +44,8 @@ FRESULT f_mount (

    解説

    -

    論理ドライブにそのワーク・エリアを登録したり抹消したりします。何らかのファイル関数を使用する前にこの関数でその論理ドライブのワーク・エリアを与えておかなければなりません。FileSystemObjectにNULLポインタを指定するとその論理ドライブのワーク・エリアの登録は抹消され、登録されていたワーク・エリアは破棄できます。

    -

    この関数内では物理ドライブへのアクセスは行われず、ワーク・エリアを初期化して内部配列にそのアドレスを登録するだけです。実際のマウント動作は他のファイル関数の中で必要に応じて行われます。

    +

    FatFsモジュールではそれぞれの論理ドライブにファイル・システム・オブジェクトというワーク・エリアが必要です。この関数は論理ドライブにそのワーク・エリアを登録したり抹消したりします。何らかのファイル関数を使用する前にこの関数でその論理ドライブのワーク・エリアを与えておかなければなりません。FileSystemObjectにヌル・ポインタを指定するとその論理ドライブのワーク・エリアの登録は抹消され、登録されていたワーク・エリアは破棄できます。

    +

    この関数内では物理ドライブへのアクセスは発生せず、ワーク・エリアを初期化して内部配列にそのアドレスを登録するだけです。実際のマウント動作は、他のファイル関数(パス名を指定するもの)の中で必要に応じて行われます。

    diff --git a/doc/ja/open.html b/doc/ja/open.html index d3e9331..638230e 100644 --- a/doc/ja/open.html +++ b/doc/ja/open.html @@ -33,11 +33,12 @@ FRESULT f_open (
    ファイルのアクセス方法やオープン方法を決めるフラグです。このパラメータには次の組み合わせを指定します。
    - - + + - + +
    意味
    FA_READ読み出しモードでオープンします。読み書きする場合はFA_WRITEと共に指定します。
    FA_WRITE書き込みモードでオープンします。読み書きする場合はFA_READと共に指定します。
    FA_READ読み出しモードで開きます。読み書きする場合はFA_WRITEと共に指定します。
    FA_WRITE書き込みモードで開きます。読み書きする場合はFA_READと共に指定します。
    FA_OPEN_EXISTING既存のファイルを開きます。ファイルが無いときはエラーになります。
    FA_CREATE_ALWAYSファイルを作成します。既存のファイルがある場合は、サイズを0にしてから開きます。
    FA_OPEN_ALWAYS既存のファイルを開きます。ファイルが無いときはファイルを作成します。
    FA_CREATE_NEWファイルを作成します。同名のファイルがある場合は、エラーになります。
    FA_CREATE_ALWAYSファイルを作成します。同名のファイルがある場合は、サイズを0にしてから開きます。
    @@ -48,7 +49,7 @@ FRESULT f_open (

    戻り値

    FR_OK (0)
    -
    正常終了。以降、FileObject構造体を使ってこのファイルを操作できます。
    +
    正常終了。以降、FileObject構造体を使ってこのファイルを操作できます。
    FR_NO_FILE
    ファイルが見つからない。
    FR_NO_PATH
    @@ -57,6 +58,8 @@ FRESULT f_open (
    ファイル名が不正。
    FR_INVALID_DRIVE
    ドライブ番号が不正。
    +
    FR_EXIST
    +
    同名のファイルが既にある。
    FR_DENIED
    アクセスが拒否された。リード・オンリー・ファイルの書き込みモード・オープン、同名のディレクトリまたはリード・オンリー・ファイルがある状態でのファイル作成、ディスクまたはディレクトリ・テーブルが満杯でファイルを作成できないなど。
    FR_NOT_READY
    @@ -64,7 +67,7 @@ FRESULT f_open (
    FR_WRITE_PROTECTED
    メディアが書き込み禁止状態で書き込み系オープンをした。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    その論理ドライブにワーク・エリアが割り当てられていない。
    FR_NO_FILESYSTEM
    @@ -77,7 +80,7 @@ FRESULT f_open (

    解説

    作成されたファイル・オブジェクトは、以降そのファイルに対するアクセスに使用します。ファイルを閉じるときは、f_close()を使用します。

    ファイル操作関数を使用する前にまず、f_mount()を使ってそれぞれの論理ドライブにワーク・エリア(ファイル・システム・オブジェクト)を与えなければなりません。この初期化の後、その論理ドライブに対して全てのファイル関数が使えるようになります。

    -

    リードオンリー構成では、FA_WRITE, FA_CREATE_ALWAYS, FA_OPEN_ALWAYSの各フラグはサポートされません。

    +

    リードオンリー構成では、FA_WRITE, FA_CREATE_ALWAYS, FA_CREATE_NEW, FA_OPEN_ALWAYSの各フラグはサポートされません。

    diff --git a/doc/ja/opendir.html b/doc/ja/opendir.html index d060555..b0dedeb 100644 --- a/doc/ja/opendir.html +++ b/doc/ja/opendir.html @@ -48,7 +48,7 @@ FRESULT f_opendir (
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    論理ドライブにワーク・エリアが与えられていない。
    FR_NO_FILESYSTEM
    @@ -59,7 +59,7 @@ FRESULT f_opendir (

    解説

    -

    ディレクトリをオープンします。正常終了したら、DirObject構造体を使ってこのディレクトリの項目を順次読み出せます。DirObject構造体は使用後は任意の時点で破棄できます。_FS_MINIMIZE == 2ではこの関数はサポートされません。

    +

    ディレクトリをオープンします。正常終了したら、DirObject構造体を使ってこのディレクトリの項目を順次読み出せます。DirObject構造体は使用後は任意の時点で破棄できます。_FS_MINIMIZE >= 2ではこの関数はサポートされません。

    diff --git a/doc/ja/read.html b/doc/ja/read.html index b89cbd0..9c86eb9 100644 --- a/doc/ja/read.html +++ b/doc/ja/read.html @@ -31,7 +31,7 @@ FRESULT f_read (
    Buffer
    読み出したデータを格納するバッファを指すポインタを指定します。
    ByteToRead
    -
    読み出すバイト数を指定します。
    +
    読み出すバイト数(0〜65535)を指定します。
    ByteRead
    実際に読み出されたバイト数を格納する変数を指すポインタを指定します。
    @@ -44,9 +44,9 @@ FRESULT f_read (
    FR_OK (0)
    正常終了。
    FR_DENIED
    -
    書き込み専用モードで開いたファイルから読み込もうとした。
    +
    非読み込みモードで開いたファイルから読み込もうとした。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_INVALID_OBJECT
    diff --git a/doc/ja/readdir.html b/doc/ja/readdir.html index 7686b3d..1138ad1 100644 --- a/doc/ja/readdir.html +++ b/doc/ja/readdir.html @@ -40,7 +40,7 @@ FRESULT f_readdir (
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_INVALID_OBJECT
    無効なディレクトリ・オブジェクト。
    @@ -49,7 +49,7 @@ FRESULT f_readdir (

    解説

    -

    ディレクトリ・エントリーを順次読み出します。この関数を繰り返し実行することによりディレクトリの全ての項目を読み出すことができます。全ての項目を読み出し、読み出す項目がもう無いときは、f_name[]メンバにヌル文字列が返されます。得られるファイル情報の詳細については FILINFO構造体を参照してください。_FS_MINIMIZE == 2ではこの関数はサポートされません。

    +

    ディレクトリ項目を順次読み出します。この関数を繰り返し実行することによりディレクトリの全ての項目を読み出すことができます。全ての項目を読み出し、読み出す項目がもう無いときは、f_name[]メンバにヌル文字列が返されます。得られるファイル情報の詳細については FILINFO構造体を参照してください。_FS_MINIMIZE >= 2ではこの関数はサポートされません。

    diff --git a/doc/ja/rename.html b/doc/ja/rename.html index 4154bb5..0fdb62b 100644 --- a/doc/ja/rename.html +++ b/doc/ja/rename.html @@ -27,7 +27,7 @@ FRESULT f_rename (
    OldName
    変更対象のファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。
    NewName
    -
    新しいファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。既に存在するものと同じ名前は使えません。また、ドライブ番号は指定できず、OldNameで指定されたドライブ上として扱われます。
    +
    新しいファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。既に存在するものと同じ名前は使えません。また、ドライブ番号は指定できず、OldNameで指定されたドライブ上のオブジェクトとして扱われます。
    @@ -46,13 +46,15 @@ FRESULT f_rename (
    FR_INVALID_DRIVE
    ドライブ番号が不正。
    FR_DENIED
    -
    新しい名前が作れない。
    +
    新しい名前のオブジェクトが作れない。
    +
    FR_EXIST
    +
    NewNameと同じ名前のオブジェクトが既にある。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_WRITE_PROTECTED
    メディアが書き込み禁止状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    論理ドライブにワークエリアが割り当てられていない。
    FR_NO_FILESYSTEM
    diff --git a/doc/ja/sdir.html b/doc/ja/sdir.html index 1dcb778..6990f48 100644 --- a/doc/ja/sdir.html +++ b/doc/ja/sdir.html @@ -16,23 +16,23 @@

    FatFs

     typedef struct _DIR {
    +    WORD    id;          /* Owner file system mount ID (inverted) */
    +    WORD    index;       /* Current index */
         FATFS*  fs;          /* Pointer to the owner file system object */
         DWORD   sclust;      /* Start cluster */
         DWORD   clust;       /* Current cluster */
         DWORD   sect;        /* Current sector */
    -    WORD    index;       /* Current index */
    -    WORD    id;          /* Sum of owner file system mount ID */
     } DIR;
     

    Tiny-FatFs

     typedef struct _DIR {
    +    WORD    id;          /* Owner file system mount ID (inverted) */
    +    WORD    index;       /* Current index */
         FATFS*  fs;          /* Pointer to the owner file system object */
         CLUST   sclust;      /* Start cluster */
         CLUST   clust;       /* Current cluster */
         DWORD   sect;        /* Current sector */
    -    WORD    index;       /* Current index */
    -    WORD    id;          /* Sum of owner file system mount ID */
     } DIR;
     
    diff --git a/doc/ja/sfatfs.html b/doc/ja/sfatfs.html index ef5560d..9ad1397 100644 --- a/doc/ja/sfatfs.html +++ b/doc/ja/sfatfs.html @@ -16,10 +16,6 @@

    FatFs

     typedef struct _FATFS {
    -    BYTE    fs_type;        /* FAT type (0:Not mouted) */
    -    BYTE    sects_clust;    /* Sectors per cluster */
    -    BYTE    n_fats;         /* Number of FAT copies */
    -    BYTE    drive;          /* Physical drive number */
         WORD    id;             /* File system mount ID */
         WORD    n_rootdir;      /* Number of root directory entries */
         DWORD   winsect;        /* Current sector appearing in the win[] */
    @@ -29,7 +25,12 @@ typedef struct _FATFS {
         DWORD   dirbase;        /* Root directory start sector (cluster# for FAT32) */
         DWORD   database;       /* Data start sector */
         DWORD   last_clust;     /* Last allocated cluster */
    +    BYTE    fs_type;        /* FAT type (0:Not mounted) */
    +    BYTE    sects_clust;    /* Sectors per cluster */
    +    BYTE    n_fats;         /* Number of FAT copies */
    +    BYTE    drive;          /* Physical drive number */
         BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
    +    BYTE    pad1;
         BYTE    win[512];       /* Disk access window for Directory/FAT */
     } FATFS;
     
    @@ -37,10 +38,6 @@ typedef struct _FATFS {

    Tiny-FatFs

     typedef struct _FATFS {
    -    BYTE    fs_type;        /* FAT type (0:Not mouted) */
    -    BYTE    sects_clust;    /* Sectors per cluster */
    -    BYTE    n_fats;         /* Number of FAT copies */
    -    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
         WORD    id;             /* File system mount ID */
         WORD    n_rootdir;      /* Number of root directory entries */
         DWORD   winsect;        /* Current sector appearing in the win[] */
    @@ -50,6 +47,10 @@ typedef struct _FATFS {
         CLUST   sects_fat;      /* Sectors per fat */
         CLUST   max_clust;      /* Maximum cluster# + 1 */
         CLUST   last_clust;     /* Last allocated cluster */
    +    BYTE    fs_type;        /* FAT type (0:Not mounted) */
    +    BYTE    sects_clust;    /* Sectors per cluster */
    +    BYTE    n_fats;         /* Number of FAT copies */
    +    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
         BYTE    win[512];       /* Disk access window for Directory/FAT/File */
     } FATFS;
     
    diff --git a/doc/ja/sfile.html b/doc/ja/sfile.html index 5c932b7..7ae1ce8 100644 --- a/doc/ja/sfile.html +++ b/doc/ja/sfile.html @@ -16,6 +16,9 @@

    FatFs

     typedef struct _FIL {
    +    WORD    id;             /* Owner file system mount ID (inverted) */
    +    BYTE    flag;           /* File status flags */
    +    BYTE    sect_clust;     /* Left sectors in cluster */
         FATFS*  fs;             /* Pointer to the owner file system object */
         DWORD   fptr;           /* File R/W pointer */
         DWORD   fsize;          /* File size */
    @@ -24,9 +27,6 @@ typedef struct _FIL {
         DWORD   curr_sect;      /* Current sector */
         DWORD   dir_sect;       /* Sector containing the directory entry */
         BYTE*   dir_ptr;        /* Ponter to the directory entry in the window */
    -    WORD    id;             /* Sum of owner file system mount ID */
    -    BYTE    flag;           /* File status flags */
    -    BYTE    sect_clust;     /* Left sectors in cluster */
         BYTE    buffer[512];    /* File R/W buffer */
     } FIL;
     
    @@ -34,6 +34,9 @@ typedef struct _FIL {

    Tiny-FatFs

     typedef struct _FIL {
    +    WORD    id;             /* Owner file system mount ID (inverted) */
    +    BYTE    flag;           /* File status flags */
    +    BYTE    sect_clust;     /* Left sectors in cluster */
         FATFS*  fs;             /* Pointer to owner file system */
         DWORD   fptr;           /* File R/W pointer */
         DWORD   fsize;          /* File size */
    @@ -42,9 +45,6 @@ typedef struct _FIL {
         DWORD   curr_sect;      /* Current sector */
         DWORD   dir_sect;       /* Sector containing the directory entry */
         BYTE*   dir_ptr;        /* Ponter to the directory entry in the window */
    -    WORD    id;             /* Sum of owner file system mount ID */
    -    BYTE    flag;           /* File status flags */
    -    BYTE    sect_clust;     /* Left sectors in cluster */
     } FIL;
     
    diff --git a/doc/ja/stat.html b/doc/ja/stat.html index 412f203..d301e03 100644 --- a/doc/ja/stat.html +++ b/doc/ja/stat.html @@ -25,7 +25,7 @@ FRESULT f_stat (

    引数

    FileName
    -
    情報を得るファイルまたはディレクトリ名の'\0'で終わる文字列を指すポインタを指定します。ルートディレクトリの指定は禁止です。
    +
    情報を得るファイルまたはディレクトリ名の'\0'で終わる文字列を指すポインタを指定します。
    FileInfo
    読み出したファイル情報を格納するファイル情報構造体へのポインタを指定します。
    @@ -48,7 +48,7 @@ FRESULT f_stat (
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    論理ドライブにワークエリアが割り当てられていない。
    FR_NO_FILESYSTEM
    diff --git a/doc/ja/sync.html b/doc/ja/sync.html index f2645cb..06aee5a 100644 --- a/doc/ja/sync.html +++ b/doc/ja/sync.html @@ -35,7 +35,7 @@ FRESULT f_sync (
    FR_OK (0)
    正常終了。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_INVALID_OBJECT
    diff --git a/doc/ja/unlink.html b/doc/ja/unlink.html index ab9b5e8..71133e6 100644 --- a/doc/ja/unlink.html +++ b/doc/ja/unlink.html @@ -49,7 +49,7 @@ FRESULT f_unlink (
    FR_WRITE_PROTECTED
    メディアが書き込み禁止状態。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_ENABLED
    論理ドライブにワーク・エリアが割り当てられていない。
    FR_NO_FILESYSTEM
    diff --git a/doc/ja/write.html b/doc/ja/write.html index d21a3d7..56079f3 100644 --- a/doc/ja/write.html +++ b/doc/ja/write.html @@ -31,7 +31,7 @@ FRESULT f_write (
    Buffer
    書き込むデータを格納したバッファを指すポインタを指定します。
    ByteToWrite
    -
    書き込むバイト数を指定します。
    +
    書き込むバイト数(0〜65535)を指定します。
    ByteWritten
    書き込まれたバイト数を格納する変数を指すポインタを指定します。
    @@ -44,9 +44,9 @@ FRESULT f_write (
    FR_OK (0)
    正常終了。
    FR_DENIED
    -
    読み込み専用モードで開いたファイルに書き込もうとした。
    +
    非書き込みモードで開いたファイルに書き込もうとした。
    FR_RW_ERROR
    -
    ディスク・アクセスでエラーが発生した。
    +
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    FR_INVALID_OBJECT
    diff --git a/doc/updates.txt b/doc/updates.txt new file mode 100644 index 0000000..44cb1b1 --- /dev/null +++ b/doc/updates.txt @@ -0,0 +1,35 @@ +R0.04a, Apr 01, 2007 + Supported multiple partitions on a plysical drive. (FatFs) + Fixed an endian sensitive code in f_mkfs(). (FatFs) + Added a capability of extending file size to f_lseek(). + Added minimization level 3. + Fixed a problem that can collapse a sector when recreate an existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs) + +R0.04, Feb 04, 2007 + Supported multiple drive system. (FatFs) + Changed some APIs for multiple drive system. + Added f_mkfs(). (FatFs) + Added _USE_FAT32 option. (Tiny-FatFs) + +R0.03a, Dec 11, 2006 + Improved cluster scan algolithm to write files fast. + Fixed f_mkdir() creates incorrect directory on FAT32. + +R0.02a, Jun 10, 2006 + Added a configuration option _FS_MINIMUM. + +R0.02, Jun 01, 2006 + Added FAT12. + Removed unbuffered mode. + Fixed a problem on small (<32M) patition. + +R0.03, Sep 22, 2006 + Added f_rename(). + Changed option _FS_MINIMUM to _FS_MINIMIZE. + +R0.01, Apr 29, 2006 + First release + +R0.00, Feb 26, 2006 + Prototype (not released) + diff --git a/src/00readme.txt b/src/00readme.txt index 762b4e4..1c6ab55 100644 --- a/src/00readme.txt +++ b/src/00readme.txt @@ -1,4 +1,4 @@ -FatFs/Tiny-FatFs Module Source Files R0.04 (C)ChaN, 2007 +FatFs/Tiny-FatFs Module Source Files R0.04a (C)ChaN, 2007 FILES @@ -26,28 +26,30 @@ CONFIGURATION OPTIONS _MCU_ENDIAN This is the most impotant option that depends on the processor architecture. - When target device corresponds to either or both of following terms, the + When the target device corresponds to either or both of following terms, the _MCU_ENDIAN must be set to 2 to force FatFs to access FAT structure in - byte-by-byte. If not the case, this can be set to 1 for good code efficiency. - The initial value is 0 (must be set to 1 or 2 properly). + byte-by-byte. - Muti-byte integers (short, long) are stored in Big-Endian. - Address miss-aligned memory access results in an incorrect behavior. + If not the case, this can be set to 1 for good code efficiency. The initial + value is 0. (must be set to 1 or 2 properly) + _FS_READONLY When application program does not require any write function, _FS_READONLY - can be set to 1 to eliminate writing code to reduce module size. This + can be set to 1 to eliminate writing code to reduce the module size. This setting should be reflected to configurations of low level disk I/O module - if available. The initial value is 0 (R/W). + if available. The initial value is 0. (Read and Write) _FS_MINIMIZE When application program requires only file read/write function, _FS_MINIMIZE can be defined to eliminate some functions to reduce the module size. The - initial value is 0 (full function). + initial value is 0. (full function) _DRIVES @@ -59,43 +61,43 @@ CONFIGURATION OPTIONS When _FAT32 is set to 1, the FAT32 support is added with an additional code size. This is for only Tiny-FatFs and not supported on FatFs. FatFs - always supports all FAT type. The initial value is 0 (disabled). + always supports all FAT type. The initial value is 0. (disabled) _USE_SJIS - When _USE_SJIS is defined, Shift-JIS code set can be used as a file name, - otherwire second byte of double-byte characters will be collapted. This is - initially defined. + When _USE_SJIS is set to 1, Shift-JIS code set can be used as a file name, + otherwire second byte of double-byte characters will be collapted. + The initial value is 1. _USE_MKFS - When _USE_MKFS is defined and _FS_READONLY is set to 0, f_mkfs function + When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is enabled. This is for only FatFs module and not supported on Tiny-FatFs. - This is initialy undefined (not available). + The initial value is 0. (f_mkfs is not available) Following table shows which function is removed by configuratin options. - _FS_MINIMIZE _FS_MINIMIZE _FS_READONLY _USE_MKFS - (1) (2) (1) (undef) - f_mount - f_open - f_close - f_read - f_lseek - f_write x - f_sync x - f_opendir x - f_readdir x - f_stat x x - f_getfree x x x - f_unlink x x x - f_mkdir x x x - f_chmod x x x - f_rename x x x - f_mkfs x x + _FS_MINIMIZE _FS_READONLY _USE_MKFS + (1) (2) (3) (1) (0) + f_mount + f_open + f_close + f_read + f_write x + f_sync x + f_lseek x + f_opendir x x + f_readdir x x + f_stat x x x + f_getfree x x x x + f_unlink x x x x + f_mkdir x x x x + f_chmod x x x x + f_rename x x x x + f_mkfs x x @@ -112,9 +114,10 @@ REVISION HISTORY Feb 26, 2006 R0.00 Prototype - Apr 29, 2006 R0.01 First stable version + Apr 29, 2006 R0.01 First release. - Jun 01, 2006 R0.02 Added FAT12. Removed unbuffered mode. + Jun 01, 2006 R0.02 Added FAT12. + Removed unbuffered mode. Fixed a problem on small (<32M) patition. Jun 10, 2006 R0.02a Added a configuration option _FS_MINIMUM. @@ -125,6 +128,15 @@ REVISION HISTORY Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast. Fixed f_mkdir() creates incorrect directory on FAT32. - Feb 04, 2007 R0.04 Supported multiple drive system. + Feb 04, 2007 R0.04 Supported multiple drive system. (FatFs) Changed some APIs for multiple drive system. - Added f_mkfs(). + Added f_mkfs(). (FatFs) + Added _USE_FAT32 option. (Tiny-FatFs) + + Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. (FatFs) + Fixed an endian sensitive code in f_mkfs(). (FatFs) + Added a capability of extending the file size to f_lseek(). + Added minimization level 3. + Fixed a problem that can collapse a sector when recreate an + existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs) + diff --git a/src/diskio.h b/src/diskio.h index d8c0153..d58c41e 100644 --- a/src/diskio.h +++ b/src/diskio.h @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -/ Low level disk interface modlue include file R0.04 (C)ChaN, 2007 +/ Low level disk interface modlue include file R0.04a (C)ChaN, 2007 /-----------------------------------------------------------------------*/ #ifndef _DISKIO @@ -8,8 +8,18 @@ #include "integer.h" -typedef unsigned char DSTATUS; -typedef unsigned char DRESULT; + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; /*---------------------------------------*/ @@ -25,13 +35,6 @@ DRESULT disk_ioctl (BYTE, BYTE, void*); void disk_timerproc (void); -/* Results of Disk Functions (DRESULT) */ - -#define RES_OK 0 /* Successful */ -#define RES_ERROR 1 /* R/W Error */ -#define RES_WRPRT 2 /* Write Protected */ -#define RES_NOTRDY 3 /* Not Ready */ -#define RES_PARERR 4 /* Invalid Parameter */ /* Disk Status Bits (DSTATUS) */ @@ -43,16 +46,18 @@ void disk_timerproc (void); /* Command code for disk_ioctrl() */ -#define GET_SECTORS 1 -#define CTRL_POWER 2 -#define CTRL_LOCK 3 -#define CTRL_EJECT 4 -#define MMC_GET_CSD 10 -#define MMC_GET_CID 11 -#define MMC_GET_OCR 12 -#define ATA_GET_REV 20 -#define ATA_GET_MODEL 21 -#define ATA_GET_SN 22 +#define GET_SECTOR_COUNT 1 +#define GET_SECTOR_SIZE 2 +#define CTRL_SYNC 3 +#define CTRL_POWER 4 +#define CTRL_LOCK 5 +#define CTRL_EJECT 6 +#define MMC_GET_CSD 10 +#define MMC_GET_CID 11 +#define MMC_GET_OCR 12 +#define ATA_GET_REV 20 +#define ATA_GET_MODEL 21 +#define ATA_GET_SN 22 #define _DISKIO diff --git a/src/ff.c b/src/ff.c index c73025d..7d11e8e 100644 --- a/src/ff.c +++ b/src/ff.c @@ -1,7 +1,7 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.04 (C)ChaN, 2007 +/ FatFs - FAT file system module R0.04a (C)ChaN, 2007 /---------------------------------------------------------------------------/ -/ FatFs module is an experimenal project to implement FAT file system to +/ The FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, / research and development under license policy of following trems. / @@ -25,14 +25,16 @@ / Feb 04, 2007 R0.04 Supported multiple drive system. / Changed some interfaces for multiple drive system. / Added f_mkfs(). +/ Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. +/ Fixed an endian sensitive code in f_mkfs(). +/ Added a capability of extending file size to f_lseek(). +/ Added minimization level 3. /---------------------------------------------------------------------------*/ #include #include "ff.h" /* FatFs declarations */ #include "diskio.h" /* Include file for user provided disk functions */ -#define ld2pd(drv) (drv) /* Logical drive# to Physical drive# conversion */ - /*-------------------------------------------------------------------------- @@ -48,7 +50,7 @@ WORD fsid; /* File system mount ID */ /*-----------------------------------------------------------------------*/ -/* Change Window Offset */ +/* Change window offset */ /*-----------------------------------------------------------------------*/ static @@ -71,8 +73,7 @@ BOOL move_window ( /* TRUE: successful, FALSE: failed */ if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */ for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to FAT copy */ wsect += fs->sects_fat; - if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK) - break; + disk_write(fs->drive, fs->win, wsect, 1); } } } @@ -90,11 +91,31 @@ BOOL move_window ( /* TRUE: successful, FALSE: failed */ /*-----------------------------------------------------------------------*/ -/* Get a Cluster Status */ +/* Clean-up cached data */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 +static +FRESULT sync ( /* FR_OK: successful, FR_RW_ERROR: failed */ + FATFS *fs /* File system object */ +) +{ + fs->winflag = 1; + if (!move_window(fs, 0)) return FR_RW_ERROR; + if (disk_ioctl(fs->drive, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR; + return FR_OK; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Get a cluster status */ /*-----------------------------------------------------------------------*/ static -DWORD get_cluster ( /* 0,2..: successful, 1: failed */ +DWORD get_cluster ( /* 0,>=2: successful, 1: failed */ FATFS *fs, /* File system object */ DWORD clust /* Cluster# to get the link information */ ) @@ -108,21 +129,22 @@ DWORD get_cluster ( /* 0,2..: successful, 1: failed */ switch (fs->fs_type) { case FS_FAT12 : bc = (WORD)clust * 3 / 2; - if (!move_window(fs, fatsect + bc / 512)) break; - wc = fs->win[bc % 512]; bc++; - if (!move_window(fs, fatsect + bc / 512)) break; - wc |= (WORD)fs->win[bc % 512] << 8; + if (!move_window(fs, fatsect + (bc / S_SIZ))) break; + wc = fs->win[bc & (S_SIZ - 1)]; bc++; + if (!move_window(fs, fatsect + (bc / S_SIZ))) break; + wc |= (WORD)fs->win[bc & (S_SIZ - 1)] << 8; return (clust & 1) ? (wc >> 4) : (wc & 0xFFF); case FS_FAT16 : - if (!move_window(fs, fatsect + clust / 256)) break; - return LD_WORD(&fs->win[((WORD)clust * 2) % 512]); + if (!move_window(fs, fatsect + (clust / (S_SIZ / 2)))) break; + return LD_WORD(&fs->win[((WORD)clust * 2) & (S_SIZ - 1)]); case FS_FAT32 : - if (!move_window(fs, fatsect + clust / 128)) break; - return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF; + if (!move_window(fs, fatsect + (clust / (S_SIZ / 4)))) break; + return LD_DWORD(&fs->win[((WORD)clust * 4) & (S_SIZ - 1)]) & 0x0FFFFFFF; } } + return 1; /* There is no cluster information, or an error occured */ } @@ -130,7 +152,7 @@ DWORD get_cluster ( /* 0,2..: successful, 1: failed */ /*-----------------------------------------------------------------------*/ -/* Change a Cluster Status */ +/* Change a cluster status */ /*-----------------------------------------------------------------------*/ #if _FS_READONLY == 0 @@ -150,24 +172,24 @@ BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ switch (fs->fs_type) { case FS_FAT12 : bc = (WORD)clust * 3 / 2; - if (!move_window(fs, fatsect + bc / 512)) return FALSE; - p = &fs->win[bc % 512]; + if (!move_window(fs, fatsect + (bc / S_SIZ))) return FALSE; + p = &fs->win[bc & (S_SIZ - 1)]; *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; bc++; fs->winflag = 1; - if (!move_window(fs, fatsect + bc / 512)) return FALSE; - p = &fs->win[bc % 512]; + if (!move_window(fs, fatsect + (bc / S_SIZ))) return FALSE; + p = &fs->win[bc & (S_SIZ - 1)]; *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); break; case FS_FAT16 : - if (!move_window(fs, fatsect + clust / 256)) return FALSE; - ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val); + if (!move_window(fs, fatsect + (clust / (S_SIZ / 2)))) return FALSE; + ST_WORD(&fs->win[((WORD)clust * 2) & (S_SIZ - 1)], (WORD)val); break; case FS_FAT32 : - if (!move_window(fs, fatsect + clust / 128)) return FALSE; - ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val); + if (!move_window(fs, fatsect + (clust / (S_SIZ / 4)))) return FALSE; + ST_DWORD(&fs->win[((WORD)clust * 4) & (S_SIZ - 1)], val); break; default : @@ -176,13 +198,13 @@ BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ fs->winflag = 1; return TRUE; } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ /*-----------------------------------------------------------------------*/ -/* Remove a Cluster Chain */ +/* Remove a cluster chain */ /*-----------------------------------------------------------------------*/ #if _FS_READONLY == 0 @@ -195,11 +217,11 @@ BOOL remove_chain ( /* TRUE: successful, FALSE: failed */ DWORD nxt; - if (clust) { - while ((nxt = get_cluster(fs, clust)) >= 2) { - if (!put_cluster(fs, clust, 0)) return FALSE; - clust = nxt; - } + while (clust >= 2 && clust < fs->max_clust) { + nxt = get_cluster(fs, clust); + if (nxt == 1) return FALSE; + if (!put_cluster(fs, clust, 0)) return FALSE; + clust = nxt; } return TRUE; } @@ -209,55 +231,56 @@ BOOL remove_chain ( /* TRUE: successful, FALSE: failed */ /*-----------------------------------------------------------------------*/ -/* Stretch or Create a Cluster Chain */ +/* Stretch or create a cluster chain */ /*-----------------------------------------------------------------------*/ #if _FS_READONLY == 0 static -DWORD create_chain ( /* !=0: new cluster number, 0: failed */ +DWORD create_chain ( /* 0: no free cluster, 1: error, >=2: new cluster number */ FATFS *fs, /* File system object */ DWORD clust /* Cluster# to stretch, 0 means create new */ ) { - DWORD cstat, ncl, scl, mcl; + DWORD cstat, ncl, scl, mcl = fs->max_clust; - mcl = fs->max_clust; if (clust == 0) { /* Create new chain */ - scl = fs->last_clust; /* Get last allocated cluster */ - if (scl < 2 || scl >= mcl) scl = 1; + scl = fs->last_clust; /* Get suggested start point */ + if (scl == 0 || scl >= mcl) scl = 1; } else { /* Stretch existing chain */ - cstat = get_cluster(fs, clust); /* Check the cluster status */ - if (cstat < 2) return 0; /* It is an invalid cluster */ - if (cstat < mcl) return cstat; /* It is already followed by next cluster */ + cstat = get_cluster(fs, clust); /* Check the cluster status */ + if (cstat < 2) return 1; /* It is an invalid cluster */ + if (cstat < mcl) return cstat; /* It is already followed by next cluster */ scl = clust; } + ncl = scl; /* Start cluster */ - do { + for (;;) { ncl++; /* Next cluster */ if (ncl >= mcl) { /* Wrap around */ ncl = 2; - if (scl == 1) return 0; /* No free custer was found */ + if (ncl > scl) return 0; /* No free custer */ } - if (ncl == scl) return 0; /* No free custer was found */ cstat = get_cluster(fs, ncl); /* Get the cluster status */ - if (cstat == 1) return 0; /* Any error occured */ - } while (cstat); /* Repeat until find a free cluster */ + if (cstat == 0) break; /* Found a free cluster */ + if (cstat == 1) return 1; /* Any error occured */ + if (ncl == scl) return 0; /* No free custer */ + } - if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 0; /* Mark the new cluster "in use" */ - if (clust && !put_cluster(fs, clust, ncl)) return 0; /* Link it to previous one if needed */ + if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ + if (clust && !put_cluster(fs, clust, ncl)) return 1; /* Link it to previous one if needed */ fs->last_clust = ncl; return ncl; /* Return new cluster number */ } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ /*-----------------------------------------------------------------------*/ -/* Get Sector# from Cluster# */ +/* Get sector# from cluster# */ /*-----------------------------------------------------------------------*/ static @@ -267,7 +290,7 @@ DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ ) { clust -= 2; - if (clust >= fs->max_clust) return 0; /* Invalid cluster# */ + if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */ return clust * fs->sects_clust + fs->database; } @@ -275,7 +298,7 @@ DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ /*-----------------------------------------------------------------------*/ -/* Move Directory Pointer to Next */ +/* Move directory pointer to next */ /*-----------------------------------------------------------------------*/ static @@ -289,14 +312,14 @@ BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ idx = dirobj->index + 1; - if ((idx & 15) == 0) { /* Table sector changed? */ + if ((idx & ((S_SIZ - 1) / 32)) == 0) { /* Table sector changed? */ dirobj->sect++; /* Next sector */ if (!dirobj->clust) { /* In static table */ if (idx >= fs->n_rootdir) return FALSE; /* Reached to end of table */ - } else { /* In dynamic table */ - if (((idx / 16) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */ + } else { /* In dynamic table */ + if (((idx / (S_SIZ / 32)) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */ clust = get_cluster(fs, dirobj->clust); /* Get next cluster */ - if (clust >= fs->max_clust || clust < 2) /* Reached to end of table */ + if (clust < 2 || clust >= fs->max_clust) /* Reached to end of table */ return FALSE; dirobj->clust = clust; /* Initialize for new cluster */ dirobj->sect = clust2sect(fs, clust); @@ -311,7 +334,7 @@ BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ /*-----------------------------------------------------------------------*/ -/* Get File Status from Directory Entry */ +/* Get file status from directory entry */ /*-----------------------------------------------------------------------*/ #if _FS_MINIMIZE <= 1 @@ -326,18 +349,18 @@ void get_fileinfo ( /* No return code */ p = &finfo->fname[0]; - a = *(dir+12); /* NT flag */ + a = dir[DIR_NTres]; /* NT flag */ for (n = 0; n < 8; n++) { /* Convert file name (body) */ - c = *(dir+n); + c = dir[n]; if (c == ' ') break; if (c == 0x05) c = 0xE5; if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; } - if (*(dir+8) != ' ') { /* Convert file name (extension) */ + if (dir[8] != ' ') { /* Convert file name (extension) */ *p++ = '.'; for (n = 8; n < 11; n++) { - c = *(dir+n); + c = dir[n]; if (c == ' ') break; if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; @@ -345,10 +368,10 @@ void get_fileinfo ( /* No return code */ } *p = '\0'; - finfo->fattrib = *(dir+11); /* Attribute */ - finfo->fsize = LD_DWORD(dir+28); /* Size */ - finfo->fdate = LD_WORD(dir+24); /* Date */ - finfo->ftime = LD_WORD(dir+22); /* Time */ + finfo->fattrib = dir[DIR_Attr]; /* Attribute */ + finfo->fsize = LD_DWORD(&dir[DIR_FileSize]); /* Size */ + finfo->fdate = LD_WORD(&dir[DIR_WrtDate]); /* Date */ + finfo->ftime = LD_WORD(&dir[DIR_WrtTime]); /* Time */ } #endif /* _FS_MINIMIZE <= 1 */ @@ -356,11 +379,11 @@ void get_fileinfo ( /* No return code */ /*-----------------------------------------------------------------------*/ -/* Pick a Paragraph and Create the Name in Format of Directory Entry */ +/* Pick a paragraph and create the name in format of directory entry */ /*-----------------------------------------------------------------------*/ static -char make_dirfile ( /* 1: error - detected an invalid format, '\0'|'/': next character */ +char make_dirfile ( /* 1: error - detected an invalid format, '\0'or'/': next character */ const char **path, /* Pointer to the file path pointer */ char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */ ) @@ -384,7 +407,7 @@ char make_dirfile ( /* 1: error - detected an invalid format, '\0'|'/': next c } break; } -#ifdef _USE_SJIS +#if _USE_SJIS != 0 if ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ (c >= 0xE0 && c <= 0xFC)) { if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ @@ -423,7 +446,7 @@ char make_dirfile ( /* 1: error - detected an invalid format, '\0'|'/': next c /*-----------------------------------------------------------------------*/ -/* Trace a File Path */ +/* Trace a file path */ /*-----------------------------------------------------------------------*/ static @@ -460,21 +483,21 @@ FRESULT trace_path ( /* FR_OK(0): successful, !=0: error code */ if (ds == 1) return FR_INVALID_NAME; for (;;) { if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR; - dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ - if (*dptr == 0) /* Has it reached to end of dir? */ + dptr = &fs->win[(dirobj->index & ((S_SIZ - 1) / 32)) * 32]; /* Pointer to the directory entry */ + if (dptr[DIR_Name] == 0) /* Has it reached to end of dir? */ return !ds ? FR_NO_FILE : FR_NO_PATH; - if ( (*dptr != 0xE5) /* Matched? */ - && !(*(dptr+11) & AM_VOL) - && !memcmp(dptr, fn, 8+3) ) break; + if (dptr[DIR_Name] != 0xE5 /* Matched? */ + && !(dptr[DIR_Attr] & AM_VOL) + && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break; if (!next_dir_entry(dirobj)) /* Next directory pointer */ return !ds ? FR_NO_FILE : FR_NO_PATH; } if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */ - if (!(*(dptr+11) & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */ - clust = ((DWORD)LD_WORD(dptr+20) << 16) | LD_WORD(dptr+26); /* Get cluster# of the directory */ + if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */ + clust = ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) | LD_WORD(&dptr[DIR_FstClusLO]); /* Get cluster# of the directory */ dirobj->clust = dirobj->sclust = clust; /* Restart scanning at the new directory */ dirobj->sect = clust2sect(fs, clust); - dirobj->index = 0; + dirobj->index = 2; } } @@ -482,13 +505,14 @@ FRESULT trace_path ( /* FR_OK(0): successful, !=0: error code */ /*-----------------------------------------------------------------------*/ -/* Reserve a Directory Entry */ +/* Reserve a directory entry */ /*-----------------------------------------------------------------------*/ #if _FS_READONLY == 0 static -BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ - DIR *dirobj /* Target directory to create new entry */ +FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */ + DIR *dirobj, /* Target directory to create new entry */ + BYTE **dir /* Pointer to pointer to created entry to retutn */ ) { DWORD clust, sector; @@ -507,27 +531,31 @@ BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ dirobj->index = 0; do { - if (!move_window(fs, dirobj->sect)) return NULL; - dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ - c = *dptr; - if (c == 0 || c == 0xE5) return dptr; /* Found an empty entry! */ - } while (next_dir_entry(dirobj)); /* Next directory pointer */ + if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR; + dptr = &fs->win[(dirobj->index & ((S_SIZ - 1) / 32)) * 32]; /* Pointer to the directory entry */ + c = dptr[DIR_Name]; + if (c == 0 || c == 0xE5) { /* Found an empty entry! */ + *dir = dptr; return FR_OK; + } + } while (next_dir_entry(dirobj)); /* Next directory pointer */ /* Reached to end of the directory table */ /* Abort when static table or could not stretch dynamic table */ - if (!clust || !(clust = create_chain(fs, dirobj->clust))) return NULL; - if (!move_window(fs, 0)) return 0; + if (!clust || !(clust = create_chain(fs, dirobj->clust))) return FR_DENIED; + if (clust == 1 || !move_window(fs, 0)) return FR_RW_ERROR; fs->winsect = sector = clust2sect(fs, clust); /* Cleanup the expanded table */ - memset(fs->win, 0, 512); + memset(fs->win, 0, S_SIZ); for (n = fs->sects_clust; n; n--) { - if (disk_write(fs->drive, fs->win, sector, 1) != RES_OK) return NULL; + if (disk_write(fs->drive, fs->win, sector, 1) != RES_OK) + return FR_RW_ERROR; sector++; } fs->winflag = 1; - return fs->win; + *dir = fs->win; + return FR_OK; } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ @@ -537,20 +565,20 @@ BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ /*-----------------------------------------------------------------------*/ static -BYTE check_fs ( /* 0:Not a boot record, 1:Valid boot record but not a FAT, 2:FAT boot record */ +BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */ FATFS *fs, /* File system object */ DWORD sect /* Sector# (lba) to check if it is a FAT boot record or not */ ) { if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK) /* Load boot record */ - return 0; - if (LD_WORD(&fs->win[510]) != 0xAA55) /* Check record signature */ - return 0; + return 2; + if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always offset 510) */ + return 2; - if (!memcmp(&fs->win[54], "FAT", 3)) /* Check FAT signature */ - return 2; - if (!memcmp(&fs->win[82], "FAT32", 5) && !(fs->win[40] & 0x80)) - return 2; + if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3)) /* Check FAT signature */ + return 0; + if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80)) + return 0; return 1; } @@ -559,7 +587,7 @@ BYTE check_fs ( /* 0:Not a boot record, 1:Valid boot record but not a FAT, 2:FA /*-----------------------------------------------------------------------*/ -/* Make Sure that the File System is Valid */ +/* Make sure that the file system is valid */ /*-----------------------------------------------------------------------*/ static @@ -569,7 +597,7 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ BYTE chk_wp /* !=0: Check media write protection for wrinting fuctions */ ) { - BYTE drv, fmt; + BYTE drv, fmt, *tbl; DSTATUS stat; DWORD basesect, fatsize, totalsect, maxclust; const char *p = *path; @@ -578,8 +606,8 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ /* Get drive number from the path name */ while (*p == ' ') p++; /* Strip leading spaces */ - drv = *p - '0'; /* Is there a drive number? */ - if (drv <= 9 && *(p+1) == ':') + drv = p[0] - '0'; /* Is there a drive number? */ + if (drv <= 9 && p[1] == ':') p += 2; /* Found a drive number, get and strip it */ else drv = 0; /* No drive number is given, select drive 0 in default */ @@ -591,7 +619,7 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ if (!(fs = FatFs[drv])) return FR_NOT_ENABLED; /* Is the file system object registered? */ *rfs = fs; /* Returen pointer to the corresponding file system object */ - /* Chekck if the logical drive has been mounted or not */ + /* Check if the logical drive has been mounted or not */ if (fs->fs_type) { stat = disk_status(fs->drive); if (!(stat & STA_NOINIT)) { /* If the physical drive is kept initialized */ @@ -606,52 +634,58 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ /* The logical drive has not been mounted, following code attempts to mount the logical drive */ memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */ - fs->drive = ld2pd(drv); /* Bind the logical drive and a physical drive */ + fs->drive = LD2PD(drv); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->drive); /* Initialize low level disk I/O layer */ if (stat & STA_NOINIT) /* Check if the drive is ready */ return FR_NOT_READY; +#if S_MAX_SIZ > 512 /* Check disk sector size */ + if (disk_ioctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK || S_SIZ > S_MAX_SIZ) + return FR_NO_FILESYSTEM; +#endif #if _FS_READONLY == 0 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ return FR_WRITE_PROTECTED; #endif - /* Search FAT partition on the drive */ fmt = check_fs(fs, basesect = 0); /* Check sector 0 as an SFD format */ if (fmt == 1) { /* Not a FAT boot record, it may be patitioned */ /* Check a partition listed in top of the partition table */ - if (fs->win[0x1C2]) { /* Is the 1st partition existing? */ - basesect = LD_DWORD(&fs->win[0x1C6]); /* Partition offset in LBA */ + tbl = &fs->win[MBR_Table + LD2PT(drv) * 16]; /* Partition table */ + if (tbl[4]) { /* Is the partition existing? */ + basesect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */ fmt = check_fs(fs, basesect); /* Check the partition */ } } - if (fmt != 2 || fs->win[12] != 2) /* No valid FAT patition is found */ + if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != S_SIZ) /* No valid FAT patition is found */ return FR_NO_FILESYSTEM; /* Initialize the file system object */ - fatsize = LD_WORD(&fs->win[22]); /* Number of sectors per FAT */ - if (!fatsize) fatsize = LD_DWORD(&fs->win[36]); + fatsize = LD_WORD(&fs->win[BPB_FATSz16]); /* Number of sectors per FAT */ + if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]); fs->sects_fat = fatsize; - fs->n_fats = fs->win[16]; /* Number of FAT copies */ - fatsize *= fs->n_fats; /* Number of sectors in FAT area */ - fs->fatbase = basesect += LD_WORD(&fs->win[14]); /* FAT start sector (lba) */ - basesect += fatsize; /* Next sector of FAT area (lba) */ - fs->sects_clust = fs->win[13]; /* Number of sectors per cluster */ - fs->n_rootdir = LD_WORD(&fs->win[17]); /* Nmuber of root directory entries */ - totalsect = LD_WORD(&fs->win[19]); /* Number of sectors on the file system */ - if (!totalsect) totalsect = LD_DWORD(&fs->win[32]); + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ + fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */ + fs->fatbase = basesect += LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */ + basesect += fatsize; /* (Next sector of FAT area (lba)) */ + fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */ + totalsect = LD_WORD(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */ + if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); fs->max_clust = maxclust = (totalsect /* Last cluster# + 1 */ - - LD_WORD(&fs->win[14]) - fatsize - fs->n_rootdir / 16 + - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (S_SIZ / 32) ) / fs->sects_clust + 2; - fmt = FS_FAT12; /* Determins the FAT type */ - if (maxclust >= 0xFF7) fmt = FS_FAT16; - if (maxclust >= 0xFFF7) fmt = FS_FAT32; + + fmt = FS_FAT12; /* Determine the FAT sub type */ + if (maxclust > 0xFF7) fmt = FS_FAT16; + if (maxclust > 0xFFF7) fmt = FS_FAT32; + fs->fs_type = fmt; + if (fmt == FS_FAT32) - fs->dirbase = LD_DWORD(&fs->win[44]); /* Root directory start cluster */ + fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]); /* Root directory start cluster */ else fs->dirbase = basesect; /* Root directory start sector (lba) */ - fs->database = basesect + fs->n_rootdir / 16; /* Data start sector (lba) */ + fs->database = basesect + fs->n_rootdir / (S_SIZ / 32); /* Data start sector (lba) */ - fs->fs_type = fmt; /* FAT type */ fs->id = ++fsid; /* File system mount ID */ return FR_OK; @@ -670,7 +704,7 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Not valid */ WORD id /* id member of the target object to be checked */ ) { - if (!fs || (WORD)~fs->id != id) + if (!fs || fs->id != id) return FR_INVALID_OBJECT; if (disk_status(fs->drive) & STA_NOINIT) return FR_NOT_READY; @@ -731,73 +765,77 @@ FRESULT f_open ( #if _FS_READONLY == 0 - res = auto_mount(&path, &fs, mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)); + mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW); + res = auto_mount(&path, &fs, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW))); #else + mode &= FA_READ; res = auto_mount(&path, &fs, 0); #endif if (res != FR_OK) return res; + dirobj.fs = fs; /* Trace the file path */ - dirobj.fs = fs; res = trace_path(&dirobj, fn, path, &dir); - #if _FS_READONLY == 0 - /* Create or Open a File */ - if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) { + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) { DWORD ps, rs; if (res != FR_OK) { /* No file, create new */ - mode |= FA_CREATE_ALWAYS; if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ - if (dir == NULL) return FR_DENIED; - memset(dir, 0, 32); /* Initialize the new entry */ - memcpy(dir, fn, 8+3); - *(dir+12) = fn[11]; - } else { /* Any object is already existing */ - if (dir == NULL || (*(dir+11) & (AM_RDO|AM_DIR))) /* Could not overwrite (R/O or DIR) */ + res = reserve_direntry(&dirobj, &dir); + if (res != FR_OK) return res; + memset(dir, 0, 32); /* Initialize the new entry with open name */ + memcpy(&dir[DIR_Name], fn, 8+3); + dir[DIR_NTres] = fn[11]; + mode |= FA_CREATE_ALWAYS; + } + else { /* Any object is already existing */ + if (mode & FA_CREATE_NEW) /* Cannot create new */ + return FR_EXIST; + if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR))) /* Cannot overwrite it (R/O or DIR) */ return FR_DENIED; - if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */ - rs = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); - ST_WORD(dir+20, 0); ST_WORD(dir+26, 0); /* cluster = 0 */ - ST_DWORD(dir+28, 0); /* size = 0 */ + if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero if needed */ + rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); /* Get start cluster */ + ST_WORD(&dir[DIR_FstClusHI], 0); /* cluster = 0 */ + ST_WORD(&dir[DIR_FstClusLO], 0); + ST_DWORD(&dir[DIR_FileSize], 0); /* size = 0 */ fs->winflag = 1; - ps = fs->winsect; /* Remove the cluster chain */ + ps = fs->winsect; /* Remove the cluster chain */ if (!remove_chain(fs, rs) || !move_window(fs, ps)) return FR_RW_ERROR; + fs->last_clust = rs - 1; /* Reuse the cluster hole */ } } if (mode & FA_CREATE_ALWAYS) { - *(dir+11) = AM_ARC; + dir[DIR_Attr] = AM_ARC; /* New attribute */ ps = get_fattime(); - ST_DWORD(dir+14, ps); /* Created time */ - ST_DWORD(dir+22, ps); /* Updated time */ + ST_DWORD(&dir[DIR_WrtTime], ps); /* Updated time */ + ST_DWORD(&dir[DIR_CrtTime], ps); /* Created time */ fs->winflag = 1; } } - /* Open a File */ + /* Open an existing file */ else { -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ if (res != FR_OK) return res; /* Trace failed */ - if (dir == NULL || (*(dir+11) & AM_DIR)) /* It is a directory */ + if (dir == NULL || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */ return FR_NO_FILE; #if _FS_READONLY == 0 - if ((mode & FA_WRITE) && (*(dir+11) & AM_RDO)) /* R/O violation */ + if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ return FR_DENIED; } -#endif -#if _FS_READONLY == 0 - fp->flag = mode & (FA_WRITE|FA_READ); fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; -#else - fp->flag = mode & FA_READ; #endif - fp->org_clust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); /* File start cluster */ - fp->fsize = LD_DWORD(dir+28); /* File size */ + fp->flag = mode; /* File access mode */ + fp->org_clust = /* File start cluster */ + ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); + fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */ fp->fptr = 0; /* File ptr */ fp->sect_clust = 1; /* Sector counter */ - fp->fs = fs; fp->id = ~fs->id; /* Owner file system object of the file */ + fp->fs = fs; fp->id = fs->id; /* Owner file system object of the file */ + return FR_OK; } @@ -815,7 +853,7 @@ FRESULT f_read ( WORD *br /* Pointer to number of bytes read */ ) { - DWORD clust, sect, ln; + DWORD clust, sect, remain; WORD rcnt; BYTE cc, *rbuff = buff; FRESULT res; @@ -823,17 +861,17 @@ FRESULT f_read ( *br = 0; - res = validate(fs, fp->id); + res = validate(fs, fp->id); /* Check validity of the object */ if (res) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */ - ln = fp->fsize - fp->fptr; - if (btr > ln) btr = (WORD)ln; /* Truncate read count by number of bytes left */ + remain = fp->fsize - fp->fptr; + if (btr > remain) btr = (WORD)remain; /* Truncate read count by number of bytes left */ for ( ; btr; /* Repeat until all data transferred */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % 512) == 0) { /* On the sector boundary */ - if (--(fp->sect_clust)) { /* Decrement left sector counter */ + if ((fp->fptr & (S_SIZ - 1)) == 0) { /* On the sector boundary */ + if (--fp->sect_clust) { /* Decrement left sector counter */ sect = fp->curr_sect + 1; /* Get current sector */ } else { /* On the cluster boundary, get next cluster */ clust = (fp->fptr == 0) ? @@ -852,21 +890,21 @@ FRESULT f_read ( } #endif fp->curr_sect = sect; /* Update current sector */ - cc = btr / 512; /* When left bytes >= 512, */ + cc = btr / S_SIZ; /* When left bytes >= S_SIZ, */ if (cc) { /* Read maximum contiguous sectors directly */ if (cc > fp->sect_clust) cc = fp->sect_clust; if (disk_read(fs->drive, rbuff, sect, cc) != RES_OK) goto fr_error; fp->sect_clust -= cc - 1; fp->curr_sect += cc - 1; - rcnt = cc * 512; continue; + rcnt = cc * S_SIZ; continue; } if (disk_read(fs->drive, fp->buffer, sect, 1) != RES_OK) /* Load the sector into file I/O buffer */ goto fr_error; } - rcnt = 512 - ((WORD)fp->fptr % 512); /* Copy fractional bytes from file I/O buffer */ + rcnt = S_SIZ - ((WORD)fp->fptr & (S_SIZ - 1)); /* Copy fractional bytes from file I/O buffer */ if (rcnt > btr) rcnt = btr; - memcpy(rbuff, &fp->buffer[fp->fptr % 512], rcnt); + memcpy(rbuff, &fp->buffer[fp->fptr & (S_SIZ - 1)], rcnt); } return FR_OK; @@ -879,11 +917,11 @@ fr_error: /* Abort this file due to an unrecoverable error */ +#if _FS_READONLY == 0 /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ -#if _FS_READONLY == 0 FRESULT f_write ( FIL *fp, /* Pointer to the file object */ const void *buff, /* Pointer to the data to be written */ @@ -900,16 +938,16 @@ FRESULT f_write ( *bw = 0; - res = validate(fs, fp->id); + res = validate(fs, fp->id); /* Check validity of the object */ if (res) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ if (!(fp->flag & FA_WRITE)) return FR_DENIED; /* Check access mode */ - if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */ + if (fp->fsize + btw < fp->fsize) return FR_OK; /* File size cannot reach 4GB */ for ( ; btw; /* Repeat until all data transferred */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % 512) == 0) { /* On the sector boundary */ - if (--(fp->sect_clust)) { /* Decrement left sector counter */ + if ((fp->fptr & (S_SIZ - 1)) == 0) { /* On the sector boundary */ + if (--fp->sect_clust) { /* Decrement left sector counter */ sect = fp->curr_sect + 1; /* Get current sector */ } else { /* On the cluster boundary, get next cluster */ if (fp->fptr == 0) { /* Is top of the file */ @@ -919,7 +957,8 @@ FRESULT f_write ( } else { /* Middle or end of file */ clust = create_chain(fs, fp->curr_clust); /* Trace or streach cluster chain */ } - if (clust < 2 || clust >= fs->max_clust) break; + if (clust == 0) break; /* Disk full */ + if (clust == 1 || clust >= fs->max_clust) goto fw_error; fp->curr_clust = clust; /* Current cluster */ sect = clust2sect(fs, clust); /* Get current sector */ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ @@ -930,22 +969,22 @@ FRESULT f_write ( fp->flag &= ~FA__DIRTY; } fp->curr_sect = sect; /* Update current sector */ - cc = btw / 512; /* When left bytes >= 512, */ + cc = btw / S_SIZ; /* When left bytes >= S_SIZ, */ if (cc) { /* Write maximum contiguous sectors directly */ if (cc > fp->sect_clust) cc = fp->sect_clust; if (disk_write(fs->drive, wbuff, sect, cc) != RES_OK) goto fw_error; fp->sect_clust -= cc - 1; fp->curr_sect += cc - 1; - wcnt = cc * 512; continue; + wcnt = cc * S_SIZ; continue; } if (fp->fptr < fp->fsize && /* Fill sector buffer with file data if needed */ disk_read(fs->drive, fp->buffer, sect, 1) != RES_OK) goto fw_error; } - wcnt = 512 - ((WORD)fp->fptr % 512); /* Copy fractional bytes to file I/O buffer */ + wcnt = S_SIZ - ((WORD)fp->fptr & (S_SIZ - 1)); /* Copy fractional bytes to file I/O buffer */ if (wcnt > btw) wcnt = btw; - memcpy(&fp->buffer[fp->fptr % 512], wbuff, wcnt); + memcpy(&fp->buffer[fp->fptr & (S_SIZ - 1)], wbuff, wcnt); fp->flag |= FA__DIRTY; } @@ -957,63 +996,6 @@ fw_error: /* Abort this file due to an unrecoverable error */ fp->flag |= FA__ERROR; return FR_RW_ERROR; } -#endif /* _FS_READONLY */ - - - - -/*-----------------------------------------------------------------------*/ -/* Seek File Pointer */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_lseek ( - FIL *fp, /* Pointer to the file object */ - DWORD ofs /* File pointer from top of file */ -) -{ - DWORD clust; - BYTE sc; - FRESULT res; - FATFS *fs = fp->fs; - - - res = validate(fs, fp->id); - if (res) return res; - if (fp->flag & FA__ERROR) return FR_RW_ERROR; -#if _FS_READONLY == 0 - if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */ - if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) goto fk_error; - fp->flag &= ~FA__DIRTY; - } -#endif - if (ofs > fp->fsize) ofs = fp->fsize; /* Clip offset by file size */ - fp->fptr = ofs; fp->sect_clust = 1; /* Re-initialize file pointer */ - - /* Seek file pinter if needed */ - if (ofs) { - ofs = (ofs - 1) / 512; /* Calcurate current sector */ - sc = fs->sects_clust; /* Number of sectors in a cluster */ - fp->sect_clust = sc - ((BYTE)ofs % sc); /* Calcurate sector counter */ - ofs /= sc; /* Number of clusters to skip */ - clust = fp->org_clust; /* Seek to current cluster */ - while (ofs--) - clust = get_cluster(fs, clust); - if (clust < 2 || clust >= fs->max_clust) - goto fk_error; - fp->curr_clust = clust; - fp->curr_sect = clust2sect(fs, clust) + sc - fp->sect_clust; /* Current sector */ - if (fp->fptr % 512) { /* Load currnet sector if needed */ - if (disk_read(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) - goto fk_error; - } - } - - return FR_OK; - -fk_error: /* Abort this file due to an unrecoverable error */ - fp->flag |= FA__ERROR; - return FR_RW_ERROR; -} @@ -1022,44 +1004,43 @@ fk_error: /* Abort this file due to an unrecoverable error */ /* Synchronize between File and Disk */ /*-----------------------------------------------------------------------*/ -#if _FS_READONLY == 0 FRESULT f_sync ( FIL *fp /* Pointer to the file object */ ) { - BYTE *ptr; + DWORD tim; + BYTE *dir; FRESULT res; FATFS *fs = fp->fs; - res = validate(fs, fp->id); - if (res) return res; - - /* Has the file been written? */ - if (fp->flag & FA__WRITTEN) { - /* Write back data buffer if needed */ - if (fp->flag & FA__DIRTY) { - if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + res = validate(fs, fp->id); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ + /* Write back data buffer if needed */ + if (fp->flag & FA__DIRTY) { + if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + return FR_RW_ERROR; + fp->flag &= ~FA__DIRTY; + } + /* Update the directory entry */ + if (!move_window(fs, fp->dir_sect)) return FR_RW_ERROR; - fp->flag &= ~FA__DIRTY; + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + ST_DWORD(&dir[DIR_FileSize], fp->fsize); /* Update file size */ + ST_WORD(&dir[DIR_FstClusLO], fp->org_clust); /* Update start cluster */ + ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16); + tim = get_fattime(); /* Updated time */ + ST_DWORD(&dir[DIR_WrtTime], tim); + fp->flag &= ~FA__WRITTEN; + res = sync(fs); } - /* Update the directory entry */ - if (!move_window(fs, fp->dir_sect)) - return FR_RW_ERROR; - ptr = fp->dir_ptr; - *(ptr+11) |= AM_ARC; /* Set archive bit */ - ST_DWORD(ptr+28, fp->fsize); /* Update file size */ - ST_WORD(ptr+26, fp->org_clust); /* Update start cluster */ - ST_WORD(ptr+20, fp->org_clust >> 16); - ST_DWORD(ptr+22, get_fattime()); /* Updated time */ - fs->winflag = 1; - fp->flag &= ~FA__WRITTEN; } - if (!move_window(fs, 0)) return FR_RW_ERROR; - - return FR_OK; + return res; } -#endif /* _FS_READONLY */ + +#endif /* _FS_READONLY == 0 */ @@ -1088,6 +1069,92 @@ FRESULT f_close ( +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File R/W Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL *fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + DWORD clust, csize; + BYTE csect; + FRESULT res; + FATFS *fs = fp->fs; + + + res = validate(fs, fp->id); /* Check validity of the object */ + if (res) return res; + if (fp->flag & FA__ERROR) return FR_RW_ERROR; +#if _FS_READONLY == 0 + if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */ + if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fk_error; + fp->flag &= ~FA__DIRTY; + } + if (ofs > fp->fsize && !(fp->flag & FA_WRITE)) +#else + if (ofs > fp->fsize) +#endif + ofs = fp->fsize; + fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */ + + /* Move file R/W pointer if needed */ + if (ofs) { + clust = fp->org_clust; /* Get start cluster */ +#if _FS_READONLY == 0 + if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */ + clust = create_chain(fs, 0); + if (clust == 1) goto fk_error; + fp->org_clust = fp->curr_clust = clust; + } +#endif + if (clust) { /* If the file has a cluster chain, it can be followed */ + csize = (DWORD)fs->sects_clust * S_SIZ; /* Cluster size in unit of byte */ + while (ofs > csize) { /* Skip leading clusters */ +#if _FS_READONLY == 0 + if (fp->flag & FA_WRITE) /* Check if in write mode or not */ + clust = create_chain(fs, clust); /* Force streached if in write mode */ + else +#endif + clust = get_cluster(fs, clust); /* Only follow cluster chain if not in write mode */ + if (clust == 0) { /* Stop if could not follow the cluster chain */ + ofs = csize; + break; + } + if (clust == 1 || clust >= fs->max_clust) goto fk_error; /* Abort when any error occured */ + fp->curr_clust = clust; /* Update current cluster and R/W pointer */ + fp->fptr += csize; + ofs -= csize; + } + csect = (BYTE)((ofs - 1) / S_SIZ); /* Sector offset in the cluster */ + fp->curr_sect = clust2sect(fs, clust) + csect; /* Get current cluster */ + if ((ofs & (S_SIZ - 1)) && /* Load current sector if needed */ + disk_read(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fk_error; + fp->sect_clust = fs->sects_clust - csect; /* Left sector counter in the cluster */ + fp->fptr += ofs; /* Update file R/W pointer */ + } + } +#if _FS_READONLY == 0 + if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */ + fp->fsize = fp->fptr; + fp->flag |= FA__WRITTEN; + } +#endif + + return FR_OK; + +fk_error: /* Abort this file due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} + + + + #if _FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a directroy object */ @@ -1104,22 +1171,22 @@ FRESULT f_opendir ( FATFS *fs; - if ((res = auto_mount(&path, &fs, 0)) != FR_OK) - return res; + res = auto_mount(&path, &fs, 0); + if (res != FR_OK) return res; dirobj->fs = fs; - res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */ + res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */ if (res == FR_OK) { /* Trace completed */ - if (dir != NULL) { /* It is not a root dir */ - if (*(dir+11) & AM_DIR) { /* The entry is a directory */ - dirobj->clust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); + if (dir != NULL) { /* It is not the root dir */ + if (dir[DIR_Attr] & AM_DIR) { /* The entry is a directory */ + dirobj->clust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); dirobj->sect = clust2sect(fs, dirobj->clust); - dirobj->index = 0; + dirobj->index = 2; } else { /* The entry is not a directory */ res = FR_NO_FILE; } } - dirobj->id = ~fs->id; + dirobj->id = fs->id; } return res; } @@ -1140,17 +1207,17 @@ FRESULT f_readdir ( FATFS *fs = dirobj->fs; - res = validate(fs, dirobj->id); + res = validate(fs, dirobj->id); /* Check validity of the object */ if (res) return res; finfo->fname[0] = 0; while (dirobj->sect) { if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR; - dir = &fs->win[(dirobj->index & 15) * 32]; /* pointer to the directory entry */ + dir = &fs->win[(dirobj->index & ((S_SIZ - 1) >> 5)) * 32]; /* pointer to the directory entry */ c = *dir; if (c == 0) break; /* Has it reached to end of dir? */ - if (c != 0xE5 && c != '.' && !(*(dir+11) & AM_VOL)) /* Is it a valid entry? */ + if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */ get_fileinfo(finfo, dir); if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */ if (finfo->fname[0]) break; /* Found valid entry */ @@ -1179,13 +1246,17 @@ FRESULT f_stat ( FATFS *fs; - if ((res = auto_mount(&path, &fs, 0)) != FR_OK) - return res; + res = auto_mount(&path, &fs, 0); + if (res != FR_OK) return res; dirobj.fs = fs; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ - if (res == FR_OK) /* Trace completed */ - get_fileinfo(finfo, dir); + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + if (res == FR_OK) { /* Trace completed */ + if (dir) /* Found an object */ + get_fileinfo(finfo, dir); + else /* It is root dir */ + res = FR_INVALID_NAME; + } return res; } @@ -1210,8 +1281,8 @@ FRESULT f_getfree ( /* Get drive number */ - if ((res = auto_mount(&drv, &fs, 0)) != FR_OK) - return res; + res = auto_mount(&drv, &fs, 0); + if (res != FR_OK) return res; *fatfs = fs; /* Count number of free clusters */ @@ -1264,37 +1335,36 @@ FRESULT f_unlink ( FATFS *fs; - if ((res = auto_mount(&path, &fs, 1)) != FR_OK) - return res; + res = auto_mount(&path, &fs, 1); + if (res != FR_OK) return res; dirobj.fs = fs; + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ - if (res != FR_OK) return res; /* Trace failed */ - if (dir == NULL) return FR_NO_FILE; /* It is a root directory */ - if (*(dir+11) & AM_RDO) return FR_DENIED; /* It is a R/O item */ + if (dir == NULL) return FR_INVALID_NAME; /* It is the root directory */ + if (dir[DIR_Attr] & AM_RDO) return FR_DENIED; /* It is a R/O object */ dsect = fs->winsect; - dclust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); + dclust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); - if (*(dir+11) & AM_DIR) { /* It is a sub-directory */ + if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */ dirobj.clust = dclust; /* Check if the sub-dir is empty or not */ dirobj.sect = clust2sect(fs, dclust); - dirobj.index = 0; + dirobj.index = 2; do { if (!move_window(fs, dirobj.sect)) return FR_RW_ERROR; - sdir = &fs->win[(dirobj.index & 15) * 32]; - if (*sdir == 0) break; - if (!((*sdir == 0xE5) || *sdir == '.') && !(*(sdir+11) & AM_VOL)) + sdir = &fs->win[(dirobj.index & ((S_SIZ - 1) >> 5)) * 32]; + if (sdir[DIR_Name] == 0) break; + if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL)) return FR_DENIED; /* The directory is not empty */ } while (next_dir_entry(&dirobj)); } if (!move_window(fs, dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */ - *dir = 0xE5; + dir[DIR_Name] = 0xE5; fs->winflag = 1; if (!remove_chain(fs, dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ - if (!move_window(fs, 0)) return FR_RW_ERROR; - return FR_OK; + return sync(fs); } @@ -1308,7 +1378,7 @@ FRESULT f_mkdir ( const char *path /* Pointer to the directory path */ ) { - BYTE *dir, *w, n; + BYTE *dir, *sec, n; char fn[8+3+1]; DWORD sect, dsect, dclust, pclust, tim; FRESULT res; @@ -1316,56 +1386,55 @@ FRESULT f_mkdir ( FATFS *fs; - if ((res = auto_mount(&path, &fs, 1)) != FR_OK) - return res; + res = auto_mount(&path, &fs, 1); + if (res != FR_OK) return res; dirobj.fs = fs; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ - if (res == FR_OK) return FR_DENIED; /* Any file or directory is already existing */ + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + if (res == FR_OK) return FR_EXIST; /* Any file or directory is already existing */ if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ - if (dir == NULL) return FR_DENIED; + res = reserve_direntry(&dirobj, &dir); /* Reserve a directory entry */ + if (res != FR_OK) return res; sect = fs->winsect; - dsect = clust2sect(fs, dclust = create_chain(fs, 0)); /* Get a new cluster for new directory */ + dclust = create_chain(fs, 0); /* Allocate a cluster for new directory table */ + if (dclust == 1) return FR_RW_ERROR; + dsect = clust2sect(fs, dclust); if (!dsect) return FR_DENIED; - if (!move_window(fs, 0)) return 0; + if (!move_window(fs, 0)) return FR_RW_ERROR; - w = fs->win; - memset(w, 0, 512); /* Initialize the directory table */ + sec = fs->win; + memset(sec, 0, S_SIZ); /* Initialize the directory table */ for (n = fs->sects_clust - 1; n; n--) { - if (disk_write(fs->drive, w, dsect+n, 1) != RES_OK) + if (disk_write(fs->drive, sec, dsect+n, 1) != RES_OK) return FR_RW_ERROR; } - fs->winsect = dsect; /* Create dot directories */ - memset(w, ' ', 8+3); - *w = '.'; - *(w+11) = AM_DIR; + fs->winsect = dsect; /* Create "." ".." directories */ + memset(&sec[DIR_Name], ' ', 8+3); /* "." entry */ + sec[DIR_Name] = '.'; + sec[DIR_Attr] = AM_DIR; tim = get_fattime(); - ST_DWORD(w+22, tim); - ST_WORD(w+26, dclust); - ST_WORD(w+20, dclust >> 16); - memcpy(w+32, w, 32); *(w+33) = '.'; + ST_DWORD(&sec[DIR_WrtTime], tim); + memcpy(&sec[32], &sec[0], 32); sec[33] = '.'; /* ".." entry */ + ST_WORD(&sec[DIR_FstClusLO], dclust); + ST_WORD(&sec[DIR_FstClusHI], dclust >> 16); pclust = dirobj.sclust; if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0; - ST_WORD(w+32+26, pclust); - ST_WORD(w+32+20, pclust >> 16); + ST_WORD(&sec[32+DIR_FstClusLO], pclust); + ST_WORD(&sec[32+DIR_FstClusHI], pclust >> 16); fs->winflag = 1; - if (!move_window(fs, sect)) return FR_RW_ERROR; - memcpy(dir, fn, 8+3); /* Initialize the new entry */ - *(dir+11) = AM_DIR; - *(dir+12) = fn[11]; - memset(dir+13, 0, 32-13); - ST_DWORD(dir+22, tim); /* Crated time */ - ST_WORD(dir+26, dclust); /* Table start cluster */ - ST_WORD(dir+20, dclust >> 16); - fs->winflag = 1; - if (!move_window(fs, 0)) return FR_RW_ERROR; + memset(&dir[0], 0, 32); /* Initialize the new entry */ + memcpy(&dir[DIR_Name], fn, 8+3); /* Name */ + dir[DIR_NTres] = fn[11]; + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(&dir[DIR_WrtTime], tim); /* Crated time */ + ST_WORD(&dir[DIR_FstClusLO], dclust); /* Table start cluster */ + ST_WORD(&dir[DIR_FstClusHI], dclust >> 16); - return FR_OK; + return sync(fs); } @@ -1388,19 +1457,18 @@ FRESULT f_chmod ( FATFS *fs; - if ((res = auto_mount(&path, &fs, 1)) != FR_OK) - return res; - dirobj.fs = fs; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ - - if (res == FR_OK) { /* Trace completed */ - if (dir == NULL) { - res = FR_NO_FILE; - } else { - mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ - *(dir+11) = (value & mask) | (*(dir+11) & ~mask); /* Apply attribute change */ - fs->winflag = 1; - if (!move_window(fs, 0)) res = FR_RW_ERROR; + res = auto_mount(&path, &fs, 1); + if (res == FR_OK) { + dirobj.fs = fs; + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + if (res == FR_OK) { /* Trace completed */ + if (dir == NULL) { + res = FR_INVALID_NAME; + } else { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = sync(fs); + } } } return res; @@ -1426,51 +1494,51 @@ FRESULT f_rename ( FATFS *fs; - if ((res = auto_mount(&path_old, &fs, 1)) != FR_OK) - return res; + res = auto_mount(&path_old, &fs, 1); + if (res != FR_OK) return res; dirobj.fs = fs; - res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ + res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ if (res != FR_OK) return res; /* The old object is not found */ if (!dir_old) return FR_NO_FILE; sect_old = fs->winsect; /* Save the object information */ - memcpy(direntry, dir_old+11, 32-11); + memcpy(direntry, &dir_old[DIR_Attr], 32-11); res = trace_path(&dirobj, fn, path_new, &dir_new); /* Check new object */ - if (res == FR_OK) return FR_DENIED; /* The new object name is already existing */ - if (res != FR_NO_FILE) return res; + if (res == FR_OK) return FR_EXIST; /* The new object name is already existing */ + if (res != FR_NO_FILE) return res; /* Is there no old name? */ + res = reserve_direntry(&dirobj, &dir_new); /* Reserve a directory entry */ + if (res != FR_OK) return res; - dir_new = reserve_direntry(&dirobj); /* Reserve a directory entry */ - if (dir_new == NULL) return FR_DENIED; - memcpy(dir_new+11, direntry, 32-11); /* Create new entry */ - memcpy(dir_new, fn, 8+3); - *(dir_new+12) = fn[11]; + memcpy(&dir_new[DIR_Attr], direntry, 32-11); /* Create new entry */ + memcpy(&dir_new[DIR_Name], fn, 8+3); + dir_new[DIR_NTres] = fn[11]; fs->winflag = 1; if (!move_window(fs, sect_old)) return FR_RW_ERROR; /* Remove old entry */ - *dir_old = 0xE5; - fs->winflag = 1; - if (!move_window(fs, 0)) return FR_RW_ERROR; + dir_old[DIR_Name] = 0xE5; - return FR_OK; + return sync(fs); } -#ifdef _USE_MKFS +#if _USE_MKFS != 0 /*-----------------------------------------------------------------------*/ /* Create File System on the Drive */ /*-----------------------------------------------------------------------*/ -#define ERASE_BLK 32 #define N_ROOTDIR 512 -#define N_FATS 2 +#define N_FATS 1 +#define MAX_SECTOR 64000000UL +#define MIN_SECTOR 1000UL +#define ERASE_BLK 32 FRESULT f_mkfs ( BYTE drv, /* Logical drive number */ BYTE partition, /* Partitioning rule 0:FDISK, 1:SFD */ - BYTE allocsize /* Allocation unit size */ + BYTE allocsize /* Allocation unit size [sectors] */ ) { BYTE fmt, m, *tbl; @@ -1484,22 +1552,30 @@ FRESULT f_mkfs ( /* Check mounted drive */ if (drv >= _DRIVES) return FR_INVALID_DRIVE; - if (!(fs = FatFs[drv])) return FR_NOT_ENABLED; + fs = FatFs[drv]; + if (!fs) return FR_NOT_ENABLED; memset(fs, 0, sizeof(FATFS)); - drv = ld2pd(drv); + drv = LD2PD(drv); /* Check validity of the parameters */ for (n = 0; allocsize != tbl_alloc[n] && tbl_alloc[n]; n++); if (!tbl_alloc[n] || partition >= 2) return FR_MKFS_ABORTED; - /* Get disk size */ + /* Get disk statics */ stat = disk_initialize(drv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; - if (disk_ioctl(drv, GET_SECTORS, &n_part) != RES_OK || n_part < 1000) + if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR) return FR_MKFS_ABORTED; + if (n_part > MAX_SECTOR) n_part = MAX_SECTOR; b_part = (!partition) ? 63 : 0; n_part -= b_part; +#if S_MAX_SIZ > 512 /* Check disk sector size */ + if (disk_ioctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK + || S_SIZ > S_MAX_SIZ + || (DWORD)S_SIZ * allocsize > 32768U) + return FR_MKFS_ABORTED; +#endif /* Pre-compute number of clusters and FAT type */ n_clust = n_part / allocsize; @@ -1508,23 +1584,23 @@ FRESULT f_mkfs ( if (n_clust >= 0xFFF7) fmt = FS_FAT32; switch (fmt) { case FS_FAT12: - n_fat = ((n_clust * 2 + 1) / 3 + 3 + 511) / 512; + n_fat = ((n_clust * 3 + 1) / 2 + 3 + S_SIZ - 1) / S_SIZ; n_rsv = 1 + partition; - n_dir = N_ROOTDIR * 32 / 512; + n_dir = N_ROOTDIR * 32 / S_SIZ; break; case FS_FAT16: - n_fat = ((n_clust * 2) + 4 + 511) / 512; + n_fat = ((n_clust * 2) + 4 + S_SIZ - 1) / S_SIZ; n_rsv = 1 + partition; - n_dir = N_ROOTDIR * 32 / 512; + n_dir = N_ROOTDIR * 32 / S_SIZ; break; default: - n_fat = ((n_clust * 4) + 8 + 511) / 512; + n_fat = ((n_clust * 4) + 8 + S_SIZ - 1) / S_SIZ; n_rsv = 33 - partition; n_dir = 0; } - b_fat = b_part + n_rsv; - b_dir = b_fat + n_fat * N_FATS; - b_data = b_dir + n_dir; + b_fat = b_part + n_rsv; /* FATs start sector */ + b_dir = b_fat + n_fat * N_FATS; /* Directory start sector */ + b_data = b_dir + n_dir; /* Data start sector */ #ifdef ERASE_BLK /* Round up data start sector to erase block boundary */ @@ -1542,62 +1618,59 @@ FRESULT f_mkfs ( if (!partition) { DWORD n_disk = b_part + n_part; - tbl = &fs->win[0x1BE]; - ST_DWORD(tbl+0, 0x00010180); /* Partition start in CHS */ + tbl = &fs->win[MBR_Table]; + ST_DWORD(&tbl[0], 0x00010180); /* Partition start in CHS */ if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */ n_disk = n_disk / 63 / 255; - *(tbl+7) = (BYTE)n_disk; - *(tbl+6) = (BYTE)((n_disk >> 2) | 63); + tbl[7] = (BYTE)n_disk; + tbl[6] = (BYTE)((n_disk >> 2) | 63); } else { - ST_WORD(tbl+6, 0xFFFF); + ST_WORD(&tbl[6], 0xFFFF); } - *(tbl+5) = 254; + tbl[5] = 254; if (fmt != FS_FAT32) /* System ID */ - *(tbl+4) = (n_part < 0x10000) ? 0x04 : 0x06; + tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06; else - *(tbl+4) = 0x0c; - ST_DWORD(tbl+8, 63); /* Partition start in LBA */ - ST_DWORD(tbl+12, n_part); /* Partition size in LBA */ - ST_WORD(tbl+64, 0xAA55); /* Signature */ + tbl[4] = 0x0c; + ST_DWORD(&tbl[8], 63); /* Partition start in LBA */ + ST_DWORD(&tbl[12], n_part); /* Partition size in LBA */ + ST_WORD(&tbl[64], 0xAA55); /* Signature */ if (disk_write(drv, fs->win, 0, 1) != RES_OK) return FR_RW_ERROR; } /* Create boot record */ - memset(tbl = fs->win, 0, 512); - ST_DWORD(tbl+0, 0x0090FEEB); /* Boot code (jmp $) */ - ST_WORD(tbl+11, 512); /* Sector size */ - *(tbl+13) = (BYTE)allocsize; /* Cluster size */ - ST_WORD(tbl+14, n_rsv); /* Reserved sectors */ - *(tbl+16) = N_FATS; /* Number of FATs */ - ST_WORD(tbl+17, n_dir * 16); /* Number of rootdir entries */ - if (n_part < 0x10000) { /* Number of total sectors */ - ST_WORD(tbl+19, n_part); + memset(tbl = fs->win, 0, S_SIZ); + ST_DWORD(&tbl[BS_jmpBoot], 0x90FEEB); /* Boot code (jmp $, nop) */ + ST_WORD(&tbl[BPB_BytsPerSec], S_SIZ); /* Sector size */ + tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */ + ST_WORD(&tbl[BPB_RsvdSecCnt], n_rsv); /* Reserved sectors */ + tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ + ST_WORD(&tbl[BPB_RootEntCnt], S_SIZ / 32 * n_dir); /* Number of rootdir entries */ + if (n_part < 0x10000) { /* Number of total sectors */ + ST_WORD(&tbl[BPB_TotSec16], n_part); } else { - ST_DWORD(tbl+32, n_part); + ST_DWORD(&tbl[BPB_TotSec32], n_part); } - *(tbl+21) = 0xF8; /* Media descripter */ - ST_WORD(tbl+24, 63); /* Number of sectors per track */ - ST_WORD(tbl+26, 255); /* Number of heads */ - ST_DWORD(tbl+28, b_part); /* Hidden sectors */ + tbl[BPB_Media] = 0xF8; /* Media descripter */ + ST_WORD(&tbl[BPB_SecPerTrk], 63); /* Number of sectors per track */ + ST_WORD(&tbl[BPB_NumHeads], 255); /* Number of heads */ + ST_DWORD(&tbl[BPB_HiddSec], b_part); /* Hidden sectors */ if (fmt != FS_FAT32) { - ST_WORD(tbl+22, n_fat); /* Number of secters per FAT */ - *(tbl+36) = 0x80; /* Drive number */ - *(tbl+38) = 0x29; /* Extended boot signature */ - memcpy(tbl+43, "NO NAME ", 11); /* Volume lavel */ - memcpy(tbl+54, (fmt == FS_FAT12) ? /* FAT signature */ - "FAT12 " : "FAT16 ", 8); + ST_WORD(&tbl[BPB_FATSz16], n_fat); /* Number of secters per FAT */ + tbl[BS_DrvNum] = 0x80; /* Drive number */ + tbl[BS_BootSig] = 0x29; /* Extended boot signature */ + memcpy(&tbl[BS_VolLab], "NO NAME FAT ", 19); /* Volume lavel, FAT signature */ } else { - ST_DWORD(tbl+36, n_fat); /* Number of secters per FAT */ - ST_DWORD(tbl+44, 2); /* Root directory cluster */ - ST_WORD(tbl+48, 1); /* FSInfo record */ - ST_WORD(tbl+50, 6); /* Backup boot record */ - *(tbl+64) = 0x80; /* Drive number */ - *(tbl+66) = 0x29; /* Extended boot signature */ - memcpy(tbl+71, "NO NAME ", 11); /* Volume lavel */ - memcpy(tbl+82, "FAT32 ", 8); /* FAT signature */ + ST_DWORD(&tbl[BPB_FATSz32], n_fat); /* Number of secters per FAT */ + ST_DWORD(&tbl[BPB_RootClus], 2); /* Root directory cluster (2) */ + ST_WORD(&tbl[BPB_FSInfo], 1); /* FSInfo record (bs+1) */ + ST_WORD(&tbl[BPB_BkBootSec], 6); /* Backup boot record (bs+6) */ + tbl[BS_DrvNum32] = 0x80; /* Drive number */ + tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ + memcpy(&tbl[BS_VolLab32], "NO NAME FAT32 ", 19); /* Volume lavel, FAT signature */ } - *(WORD*)(tbl+510) = 0xAA55; /* Signature */ + ST_WORD(&tbl[BS_55AA], 0xAA55); /* Signature */ if (disk_write(drv, tbl, b_part, 1) != RES_OK) return FR_RW_ERROR; if (fmt == FS_FAT32) @@ -1606,10 +1679,10 @@ FRESULT f_mkfs ( /* Create FSInfo record if needed */ if (fmt == FS_FAT32) { memset(tbl, 0, 510); - ST_DWORD(tbl, 0x41615252); - ST_DWORD(tbl+484, 0x61417272); - ST_DWORD(tbl+488, 0xFFFFFFFF); - ST_DWORD(tbl+492, 0xFFFFFFFF); + ST_DWORD(&tbl[0], 0x41615252); /* "RRaA" */ + ST_DWORD(&tbl[484], 0x61417272); /* "rrAa" */ + ST_DWORD(&tbl[488], 0xFFFFFFFF); /* Free count */ + ST_DWORD(&tbl[492], 0xFFFFFFFF); /* Last allocated */ if (disk_write(drv, tbl, b_part+1, 1) != RES_OK) return FR_RW_ERROR; disk_write(drv, tbl, b_part+7, 1); @@ -1617,18 +1690,18 @@ FRESULT f_mkfs ( /* Initialize FAT area */ for (m = 0; m < N_FATS; m++) { - memset(tbl, 0, 512); /* 1st sector of the FAT */ + memset(tbl, 0, S_SIZ); /* 1st sector of the FAT */ if (fmt != FS_FAT32) { - n = (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8; - ST_DWORD(tbl+0, n); + n = (fmt == FS_FAT12) ? 0x00FFFFF8 : 0xFFFFFFF8; + ST_DWORD(&tbl[0], n); /* Reserve cluster #0-1 (FAT12/16) */ } else { - ST_DWORD(tbl+0, 0xFFFFFFF8); - ST_DWORD(tbl+4, 0xFFFFFFFF); - ST_DWORD(tbl+8, 0x0FFFFFFF); + ST_DWORD(&tbl[0], 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */ + ST_DWORD(&tbl[4], 0xFFFFFFFF); + ST_DWORD(&tbl[8], 0x0FFFFFFF); /* Reserve cluster #2 for root dir */ } if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) return FR_RW_ERROR; - memset(tbl, 0, 512); /* Following sectors */ + memset(tbl, 0, S_SIZ); /* Following FAT entries are filled by zero */ for (n = 1; n < n_fat; n++) { if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) return FR_RW_ERROR; @@ -1641,11 +1714,12 @@ FRESULT f_mkfs ( return FR_RW_ERROR; } - return FR_OK; + return (disk_ioctl(drv, CTRL_SYNC, NULL) == RES_OK) ? FR_OK : FR_RW_ERROR; } -#endif /* _USE_MKFS */ +#endif /* _USE_MKFS != 0 */ #endif /* _FS_READONLY == 0 */ #endif /* _FS_MINIMIZE == 0 */ #endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ diff --git a/src/ff.h b/src/ff.h index f755b7e..9b11233 100644 --- a/src/ff.h +++ b/src/ff.h @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module include file R0.04 (C)ChaN, 2007 +/ FatFs - FAT file system module include file R0.04a (C)ChaN, 2007 /---------------------------------------------------------------------------/ / FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, @@ -33,33 +33,40 @@ /* The _FS_MINIMIZE option defines minimization level to remove some functions. / 0: Full function. / 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod and f_rename are removed. -/ 2: f_opendir and f_readdir are removed in addition to level 1. */ +/ 2: f_opendir and f_readdir are removed in addition to level 1. +/ 3: f_lseek is removed in addition to level 2. */ -#define _DRIVES 2 -/* Number of logical drives to be used */ +#define _DRIVES 1 +/* Number of logical drives to be used. This affects the size of internal table. */ -#define _USE_SJIS -/* When _USE_SJIS is defined, Shift-JIS code transparency is enabled, otherwise +#define _USE_SJIS 1 +/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise / only US-ASCII(7bit) code can be accepted as file/directory name. */ -/* #define _USE_MKFS */ -/* When _USE_MKFS is defined and _FS_READONLY is set to 0, f_mkfs function - is enabled. */ +#define _USE_MKFS 0 +/* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is +/ enabled. */ +#define _MULTI_PARTITION 0 +/* When _MULTI_PARTITION is set to 0, each logical drive is bound to same +/ physical drive number and can mount only 1st primaly partition. When it is +/ set to 1, each logical drive can mount a partition listed in Drives[]. */ #include "integer.h" -/* Result type for fatfs application interface */ -typedef unsigned char FRESULT; + +/* Definitions corresponds to multiple sector size (not tested) */ +#define S_MAX_SIZ 512 /* Do not change */ +#if S_MAX_SIZ > 512 +#define S_SIZ (fs->s_size) +#else +#define S_SIZ 512 +#endif /* File system object structure */ typedef struct _FATFS { - BYTE fs_type; /* FAT type */ - BYTE sects_clust; /* Sectors per cluster */ - BYTE n_fats; /* Number of FAT copies */ - BYTE drive; /* Physical drive number */ WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries */ DWORD winsect; /* Current sector appearing in the win[] */ @@ -69,24 +76,35 @@ typedef struct _FATFS { DWORD dirbase; /* Root directory start sector (cluster# for FAT32) */ DWORD database; /* Data start sector */ DWORD last_clust; /* Last allocated cluster */ +#if S_MAX_SIZ > 512 + WORD s_size; /* Sector size */ +#endif + BYTE fs_type; /* FAT sub type */ + BYTE sects_clust; /* Sectors per cluster */ + BYTE n_fats; /* Number of FAT copies */ + BYTE drive; /* Physical drive number */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ - BYTE win[512]; /* Disk access window for Directory/FAT */ + BYTE pad1; + BYTE win[S_MAX_SIZ]; /* Disk access window for Directory/FAT */ } FATFS; /* Directory object structure */ typedef struct _DIR { + WORD id; /* Owner file system mount ID */ + WORD index; /* Current index */ FATFS* fs; /* Pointer to the owner file system object */ DWORD sclust; /* Start cluster */ DWORD clust; /* Current cluster */ DWORD sect; /* Current sector */ - WORD index; /* Current index */ - WORD id; /* Sum of owner file system mount ID */ } DIR; /* File object structure */ typedef struct _FIL { + WORD id; /* Owner file system mount ID */ + BYTE flag; /* File status flags */ + BYTE sect_clust; /* Left sectors in cluster */ FATFS* fs; /* Pointer to the owner file system object */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ @@ -97,10 +115,7 @@ typedef struct _FIL { DWORD dir_sect; /* Sector containing the directory entry */ BYTE* dir_ptr; /* Ponter to the directory entry in the window */ #endif - WORD id; /* Sum of owner file system mount ID */ - BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ - BYTE buffer[512]; /* File R/W buffer */ + BYTE buffer[S_MAX_SIZ]; /* File R/W buffer */ } FIL; @@ -115,6 +130,48 @@ typedef struct _FILINFO { +/* Definitions corresponds to multi partition */ + +#if _MULTI_PARTITION != 0 /* Multiple partition cfg */ + +typedef struct _PARTITION { + BYTE pd; /* Physical drive # (0-255) */ + BYTE pt; /* Partition # (0-3) */ +} PARTITION; +extern +const PARTITION Drives[]; /* Logical drive# to physical location conversion table */ +#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */ +#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */ + +#else /* Single partition cfg */ + +#define LD2PD(drv) (drv) /* Physical drive# is equal to logical drive# */ +#define LD2PT(drv) 0 /* Always mounts the 1st partition */ + +#endif + + +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* 0 */ + FR_NOT_READY, /* 1 */ + FR_NO_FILE, /* 2 */ + FR_NO_PATH, /* 3 */ + FR_INVALID_NAME, /* 4 */ + FR_INVALID_DRIVE, /* 5 */ + FR_DENIED, /* 6 */ + FR_EXIST, /* 7 */ + FR_RW_ERROR, /* 8 */ + FR_WRITE_PROTECTED, /* 9 */ + FR_NOT_ENABLED, /* 10 */ + FR_NO_FILESYSTEM, /* 11 */ + FR_INVALID_OBJECT, /* 12 */ + FR_MKFS_ABORTED /* 13 */ +} FRESULT; + + + /*-----------------------------------------------------*/ /* FatFs module application interface */ @@ -143,30 +200,13 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20 -/* File function return code (FRESULT) */ - -#define FR_OK 0 -#define FR_NOT_READY 1 -#define FR_NO_FILE 2 -#define FR_NO_PATH 3 -#define FR_INVALID_NAME 4 -#define FR_INVALID_DRIVE 5 -#define FR_DENIED 6 -#define FR_DISK_FULL 7 -#define FR_RW_ERROR 8 -#define FR_WRITE_PROTECTED 9 -#define FR_NOT_ENABLED 10 -#define FR_NO_FILESYSTEM 11 -#define FR_INVALID_OBJECT 12 -#define FR_MKFS_ABORTED 13 - - /* File access control and file status flags (FIL.flag) */ #define FA_READ 0x01 #define FA_OPEN_EXISTING 0x00 #if _FS_READONLY == 0 #define FA_WRITE 0x02 +#define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA__WRITTEN 0x20 @@ -175,7 +215,7 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20 #define FA__ERROR 0x80 -/* FAT type signature (FATFS.fs_type) */ +/* FAT sub type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 @@ -194,6 +234,57 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20 +/* Offset of FAT structure members */ + +#define BS_jmpBoot 0 +#define BS_OEMName 3 +#define BPB_BytsPerSec 11 +#define BPB_SecPerClus 13 +#define BPB_RsvdSecCnt 14 +#define BPB_NumFATs 16 +#define BPB_RootEntCnt 17 +#define BPB_TotSec16 19 +#define BPB_Media 21 +#define BPB_FATSz16 22 +#define BPB_SecPerTrk 24 +#define BPB_NumHeads 26 +#define BPB_HiddSec 28 +#define BPB_TotSec32 32 +#define BS_55AA 510 + +#define BS_DrvNum 36 +#define BS_BootSig 38 +#define BS_VolID 39 +#define BS_VolLab 43 +#define BS_FilSysType 54 + +#define BPB_FATSz32 36 +#define BPB_ExtFlags 40 +#define BPB_FSVer 42 +#define BPB_RootClus 44 +#define BPB_FSInfo 48 +#define BPB_BkBootSec 50 +#define BS_DrvNum32 64 +#define BS_BootSig32 66 +#define BS_VolID32 67 +#define BS_VolLab32 71 +#define BS_FilSysType32 82 + +#define MBR_Table 446 + +#define DIR_Name 0 +#define DIR_Attr 11 +#define DIR_NTres 12 +#define DIR_CrtTime 14 +#define DIR_CrtDate 16 +#define DIR_FstClusHI 20 +#define DIR_WrtTime 22 +#define DIR_WrtDate 24 +#define DIR_FstClusLO 26 +#define DIR_FileSize 28 + + + /* Multi-byte word access macros */ #if _MCU_ENDIAN == 1 /* Use word access */ @@ -208,10 +299,10 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20 #define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8) #define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24) #else -#error Don't forget to set _MCU_ENDIAN properly! +#error Do not forget to set _MCU_ENDIAN properly! #endif #endif #define _FATFS -#endif +#endif /* _FATFS */ diff --git a/src/integer.h b/src/integer.h index 18ce992..8247065 100644 --- a/src/integer.h +++ b/src/integer.h @@ -1,23 +1,25 @@ #ifndef _INTEGER -typedef int INT; +typedef signed int INT; typedef unsigned int UINT; -typedef char CHAR; +/* These types are assumed as 8-bit integer */ +typedef signed char CHAR; typedef unsigned char UCHAR; typedef unsigned char BYTE; -typedef short SHORT; +/* These types are assumed as 16-bit integer */ +typedef signed short SHORT; typedef unsigned short USHORT; typedef unsigned short WORD; -typedef long LONG; +/* These types are assumed as 32-bit integer */ +typedef signed long LONG; typedef unsigned long ULONG; typedef unsigned long DWORD; -typedef unsigned char BOOL; -#define FALSE 0 -#define TRUE 1 +/* Boolean type */ +typedef enum { FALSE = 0, TRUE } BOOL; #define _INTEGER #endif diff --git a/src/tff.c b/src/tff.c index e214bef..4692f5b 100644 --- a/src/tff.c +++ b/src/tff.c @@ -1,7 +1,7 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.04 (C)ChaN, 2007 +/ FatFs - Tiny FAT file system module R0.04a (C)ChaN, 2007 /---------------------------------------------------------------------------/ -/ FatFs module is an experimenal project to implement FAT file system to +/ The FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, / research and development under license policy of following trems. / @@ -23,6 +23,10 @@ / Dec 09, 2006 R0.03a Improved cluster scan algolithm to write files fast. / Feb 04, 2007 R0.04 Added FAT32 supprt. / Changed some interfaces incidental to FatFs. +/ Apr 01, 2007 R0.04a Added a capability of extending file size to f_lseek(). +/ Added minimization level 3. +/ Fixed a problem that can collapse a sector when recreate +/ an existing file in any sub-directory at non FAT32 cfg. /---------------------------------------------------------------------------*/ #include @@ -47,7 +51,7 @@ WORD fsid; /* File system mount ID */ /*-----------------------------------------------------------------------*/ static -BOOL move_window ( +BOOL move_window ( /* TRUE: successful, FALSE: failed */ DWORD sector /* Sector number to make apperance in the FatFs->win */ ) /* Move to zero only writes back dirty window */ { @@ -83,12 +87,30 @@ BOOL move_window ( +/*-----------------------------------------------------------------------*/ +/* Clean-up cached data */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 +static +FRESULT sync (void) /* FR_OK: successful, FR_RW_ERROR: failed */ +{ + FatFs->winflag = 1; + if (!move_window(0)) return FR_RW_ERROR; + if (disk_ioctl(0, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR; + return FR_OK; +} +#endif + + + + /*-----------------------------------------------------------------------*/ /* Get a cluster status */ /*-----------------------------------------------------------------------*/ static -CLUST get_cluster ( +CLUST get_cluster ( /* 0,>=2: successful, 1: failed */ CLUST clust /* Cluster# to get the link information */ ) { @@ -118,6 +140,7 @@ CLUST get_cluster ( #endif } } + return 1; /* There is no cluster information, or an error occured */ } @@ -171,7 +194,7 @@ BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ fs->winflag = 1; return TRUE; } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ @@ -182,18 +205,18 @@ BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ #if _FS_READONLY == 0 static -BOOL remove_chain ( +BOOL remove_chain ( /* TRUE: successful, FALSE: failed */ CLUST clust /* Cluster# to remove chain from */ ) { CLUST nxt; - if (clust) { - while ((nxt = get_cluster(clust)) >= 2) { - if (!put_cluster(clust, 0)) return FALSE; - clust = nxt; - } + while (clust >= 2 && clust < FatFs->max_clust) { + nxt = get_cluster(clust); + if (nxt == 1) return FALSE; + if (!put_cluster(clust, 0)) return FALSE; + clust = nxt; } return TRUE; } @@ -208,8 +231,8 @@ BOOL remove_chain ( #if _FS_READONLY == 0 static -CLUST create_chain ( - CLUST clust /* Cluster# to stretch, 0 means create new */ +CLUST create_chain ( /* 0: no free cluster, 1: error, >=2: new cluster number */ + CLUST clust /* Cluster# to stretch, 0 means create new */ ) { CLUST cstat, ncl, scl, mcl; @@ -223,29 +246,31 @@ CLUST create_chain ( } else { /* Stretch existing chain */ cstat = get_cluster(clust); /* Check the cluster status */ - if (cstat < 2) return 0; /* It is an invalid cluster */ + if (cstat < 2) return 1; /* It is an invalid cluster */ if (cstat < mcl) return cstat; /* It is already followed by next cluster */ scl = clust; } - ncl = scl; /* Start cluster */ - do { - ncl++; /* Next cluster */ - if (ncl >= mcl) { /* Wrap around */ - ncl = 2; - if (scl == 1) return 0; /* No free custer was found */ - } - if (ncl == scl) return 0; /* No free custer was found */ - cstat = get_cluster(ncl); /* Get the cluster status */ - if (cstat == 1) return 0; /* Any error occured */ - } while (cstat); /* Repeat until find a free cluster */ - if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 0; /* Mark the new cluster "in use" */ - if (clust && !put_cluster(clust, ncl)) return 0; /* Link it to previous one if needed */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= mcl) { /* Wrap around */ + ncl = 2; + if (ncl > scl) return 0; /* No free custer */ + } + cstat = get_cluster(ncl); /* Get the cluster status */ + if (cstat == 0) break; /* Found a free cluster */ + if (cstat == 1) return 1; /* Any error occured */ + if (ncl == scl) return 0; /* No free custer */ + } + + if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ + if (clust && !put_cluster(clust, ncl)) return 1; /* Link it to previous one if needed */ fs->last_clust = ncl; return ncl; /* Return new cluster number */ } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ @@ -263,7 +288,7 @@ DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ clust -= 2; - if (clust >= fs->max_clust) return 0; /* Invalid cluster# */ + if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */ return (DWORD)clust * fs->sects_clust + fs->database; } @@ -275,7 +300,7 @@ DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ /*-----------------------------------------------------------------------*/ static -BOOL next_dir_entry ( +BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ DIR *dirobj /* Pointer to directory object */ ) { @@ -289,10 +314,10 @@ BOOL next_dir_entry ( dirobj->sect++; /* Next sector */ if (!dirobj->clust) { /* In static table */ if (idx >= fs->n_rootdir) return FALSE; /* Reached to end of table */ - } else { /* In dynamic table */ + } else { /* In dynamic table */ if (((idx / 16) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */ - clust = get_cluster(dirobj->clust); /* Get next cluster */ - if (clust >= fs->max_clust || clust < 2) /* Reached to end of table */ + clust = get_cluster(dirobj->clust); /* Get next cluster */ + if (clust < 2 || clust >= fs->max_clust) /* Reached to end of table */ return FALSE; dirobj->clust = clust; /* Initialize for new cluster */ dirobj->sect = clust2sect(clust); @@ -312,7 +337,7 @@ BOOL next_dir_entry ( #if _FS_MINIMIZE <= 1 static -void get_fileinfo ( +void get_fileinfo ( /* No return code */ FILINFO *finfo, /* Ptr to store the File Information */ const BYTE *dir /* Ptr to the directory entry */ ) @@ -322,18 +347,18 @@ void get_fileinfo ( p = &finfo->fname[0]; - a = *(dir+12); /* NT flag */ + a = dir[DIR_NTres]; /* NT flag */ for (n = 0; n < 8; n++) { /* Convert file name (body) */ - c = *(dir+n); + c = dir[n]; if (c == ' ') break; if (c == 0x05) c = 0xE5; if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; } - if (*(dir+8) != ' ') { /* Convert file name (extension) */ + if (dir[8] != ' ') { /* Convert file name (extension) */ *p++ = '.'; for (n = 8; n < 11; n++) { - c = *(dir+n); + c = dir[n]; if (c == ' ') break; if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; @@ -341,10 +366,10 @@ void get_fileinfo ( } *p = '\0'; - finfo->fattrib = *(dir+11); /* Attribute */ - finfo->fsize = LD_DWORD(dir+28); /* Size */ - finfo->fdate = LD_WORD(dir+24); /* Date */ - finfo->ftime = LD_WORD(dir+22); /* Time */ + finfo->fattrib = dir[DIR_Attr]; /* Attribute */ + finfo->fsize = LD_DWORD(&dir[DIR_FileSize]); /* Size */ + finfo->fdate = LD_WORD(&dir[DIR_WrtDate]); /* Date */ + finfo->ftime = LD_WORD(&dir[DIR_WrtTime]); /* Time */ } #endif /* _FS_MINIMIZE <= 1 */ @@ -356,7 +381,7 @@ void get_fileinfo ( /*-----------------------------------------------------------------------*/ static -char make_dirfile ( +char make_dirfile ( /* 1: error - detected an invalid format, '\0'or'/': next character */ const char **path, /* Pointer to the file path pointer */ char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */ ) @@ -380,7 +405,7 @@ char make_dirfile ( } break; } -#ifdef _USE_SJIS +#if _USE_SJIS != 0 if ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ (c >= 0xE0 && c <= 0xFC)) { if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ @@ -422,8 +447,8 @@ char make_dirfile ( /*-----------------------------------------------------------------------*/ static -FRESULT trace_path ( - DIR *dirobj, /* Pointer to directory object to return last directory */ +FRESULT trace_path ( /* FR_OK(0): successful, !=0: error code */ + DIR *dirobj, /* Pointer to directory object to return last directory */ char *fn, /* Pointer to last segment name to return */ const char *path, /* Full-path string to trace a file or directory */ BYTE **dir /* Directory pointer in Win[] to retutn */ @@ -436,10 +461,13 @@ FRESULT trace_path ( /* Initialize directory object */ clust = fs->dirbase; - if (_FAT32 != 0 && fs->fs_type == FS_FAT32) { +#if _FAT32 != 0 + if (fs->fs_type == FS_FAT32) { dirobj->clust = dirobj->sclust = clust; dirobj->sect = clust2sect(clust); - } else { + } else +#endif + { dirobj->clust = dirobj->sclust = 0; dirobj->sect = clust; } @@ -456,24 +484,24 @@ FRESULT trace_path ( for (;;) { if (!move_window(dirobj->sect)) return FR_RW_ERROR; dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ - if (*dptr == 0) /* Has it reached to end of dir? */ + if (dptr[DIR_Name] == 0) /* Has it reached to end of dir? */ return !ds ? FR_NO_FILE : FR_NO_PATH; - if ( (*dptr != 0xE5) /* Matched? */ - && !(*(dptr+11) & AM_VOL) - && !memcmp(dptr, fn, 8+3) ) break; + if (dptr[DIR_Name] != 0xE5 /* Matched? */ + && !(dptr[DIR_Attr] & AM_VOL) + && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break; if (!next_dir_entry(dirobj)) /* Next directory pointer */ return !ds ? FR_NO_FILE : FR_NO_PATH; } if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */ - if (!(*(dptr+11) & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */ + if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH;/* Cannot trace because it is a file */ #if _FAT32 != 0 - clust = ((DWORD)LD_WORD(dptr+20) << 16) | LD_WORD(dptr+26); /* Get cluster# of the directory */ + clust = ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) | LD_WORD(&dptr[DIR_FstClusLO]); /* Get cluster# of the directory */ #else - clust = LD_WORD(dptr+26); + clust = LD_WORD(&dptr[DIR_FstClusLO]); #endif dirobj->clust = dirobj->sclust = clust; /* Restart scannig with the new directory */ dirobj->sect = clust2sect(clust); - dirobj->index = 0; + dirobj->index = 2; } } @@ -485,8 +513,9 @@ FRESULT trace_path ( #if _FS_READONLY == 0 static -BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ - DIR *dirobj /* Target directory to create new entry */ +FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */ + DIR *dirobj, /* Target directory to create new entry */ + BYTE **dir /* Pointer to pointer to created entry to retutn */ ) { CLUST clust; @@ -506,27 +535,31 @@ BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ dirobj->index = 0; do { - if (!move_window(dirobj->sect)) return NULL; - dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ - c = *dptr; - if (c == 0 || c == 0xE5) return dptr; /* Found an empty entry! */ - } while (next_dir_entry(dirobj)); /* Next directory pointer */ + if (!move_window(dirobj->sect)) return FR_RW_ERROR; + dptr = &fs->win[(dirobj->index & 15) * 32]; /* Pointer to the directory entry */ + c = dptr[DIR_Name]; + if (c == 0 || c == 0xE5) { /* Found an empty entry! */ + *dir = dptr; return FR_OK; + } + } while (next_dir_entry(dirobj)); /* Next directory pointer */ /* Reached to end of the directory table */ /* Abort when static table or could not stretch dynamic table */ - if (!clust || !(clust = create_chain(dirobj->clust))) return NULL; - if (!move_window(0)) return 0; + if (!clust || !(clust = create_chain(dirobj->clust))) return FR_DENIED; + if (clust == 1 || !move_window(0)) return FR_RW_ERROR; fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */ memset(fs->win, 0, 512); for (n = fs->sects_clust; n; n--) { - if (disk_write(0, fs->win, sector, 1) != RES_OK) return NULL; + if (disk_write(0, fs->win, sector, 1) != RES_OK) + return FR_RW_ERROR; sector++; } fs->winflag = 1; - return fs->win; + *dir = fs->win; + return FR_OK; } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ @@ -536,22 +569,22 @@ BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ /*-----------------------------------------------------------------------*/ static -BYTE check_fs ( /* 0:Not a boot record, 1:Valid boot record but not a FAT, 2:FAT boot record */ +BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */ DWORD sect /* Sector# to check if it is a FAT boot record or not */ ) { FATFS *fs = FatFs; if (disk_read(0, fs->win, sect, 1) != RES_OK) /* Load boot record */ - return 0; - if (LD_WORD(&fs->win[510]) != 0xAA55) /* Check record signature */ - return 0; + return 2; + if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature */ + return 2; - if (!memcmp(&fs->win[54], "FAT", 3)) /* Check FAT signature */ - return 2; + if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3)) /* Check FAT signature */ + return 0; #if _FAT32 != 0 - if (!memcmp(&fs->win[82], "FAT32", 5) && !(fs->win[40] & 0x80)) - return 2; + if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80)) + return 0; #endif return 1; } @@ -611,43 +644,45 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ fmt = check_fs(basesect = 0); /* Check sector 0 as an SFD format */ if (fmt == 1) { /* Not a FAT boot record, it may be patitioned */ /* Check a partition listed in top of the partition table */ - if (fs->win[0x1C2]) { /* Is the 1st partition existing? */ - basesect = LD_DWORD(&fs->win[0x1C6]); /* Partition offset in LBA */ + if (fs->win[MBR_Table+4]) { /* Is the 1st partition existing? */ + basesect = LD_DWORD(&fs->win[MBR_Table+8]); /* Partition offset in LBA */ fmt = check_fs(basesect); /* Check the partition */ } } - if (fmt != 2 || fs->win[12] != 2) /* No valid FAT patition is found */ + if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512) /* No valid FAT patition is found */ return FR_NO_FILESYSTEM; /* Initialize the file system object */ - fatsize = LD_WORD(&fs->win[22]); /* Number of sectors per FAT */ - if (!fatsize) fatsize = LD_DWORD(&fs->win[36]); + fatsize = LD_WORD(&fs->win[BPB_FATSz16]); /* Number of sectors per FAT */ + if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]); fs->sects_fat = (CLUST)fatsize; - fs->n_fats = fs->win[16]; /* Number of FAT copies */ - fatsize *= fs->n_fats; /* Number of sectors in FAT area */ - fs->fatbase = basesect += LD_WORD(&fs->win[14]); /* FAT start sector (lba) */ - basesect += fatsize; /* Next sector of FAT area (lba) */ - fs->sects_clust = fs->win[13]; /* Number of sectors per cluster */ - fs->n_rootdir = LD_WORD(&fs->win[17]); /* Nmuber of root directory entries */ - totalsect = LD_WORD(&fs->win[19]); /* Number of sectors on the file system */ - if (!totalsect) totalsect = LD_DWORD(&fs->win[32]); + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ + fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */ + fs->fatbase = basesect += LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */ + basesect += fatsize; /* (Next sector of FAT area (lba)) */ + fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */ + totalsect = LD_WORD(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */ + if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); fs->max_clust = maxclust = (totalsect /* Last cluster# + 1 */ - - LD_WORD(&fs->win[14]) - fatsize - fs->n_rootdir / 16 + - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / 16 ) / fs->sects_clust + 2; - fmt = FS_FAT12; /* Determins the FAT type */ - if (maxclust >= 0xFF7) fmt = FS_FAT16; + + fmt = FS_FAT12; /* Determine the FAT sub type */ + if (maxclust > 0xFF7) fmt = FS_FAT16; + if (maxclust > 0xFFF7) #if _FAT32 == 0 - if (maxclust >= 0xFFF7) return FR_NO_FILESYSTEM; + return FR_NO_FILESYSTEM; #else - if (maxclust >= 0xFFF7) fmt = FS_FAT32; + fmt = FS_FAT32; if (fmt == FS_FAT32) - fs->dirbase = LD_DWORD(&fs->win[44]); /* Root directory start cluster */ + fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]); /* Root directory start cluster */ else #endif fs->dirbase = basesect; /* Root directory start sector (lba) */ fs->database = basesect + fs->n_rootdir / 16; /* Data start sector (lba) */ + fs->fs_type = fmt; - fs->fs_type = fmt; /* FAT type */ fs->id = ++fsid; /* File system mount ID */ return FR_OK; @@ -666,7 +701,7 @@ FRESULT validate ( /* FR_OK(0): The id is valid, !=0: Not valid */ WORD id /* id member of the target object to be checked */ ) { - if (!fs || (WORD)~fs->id != id) + if (!fs || fs->id != id) return FR_INVALID_OBJECT; if (disk_status(0) & STA_NOINIT) return FR_NOT_READY; @@ -726,8 +761,10 @@ FRESULT f_open ( #if _FS_READONLY == 0 - res = auto_mount(&path, mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)); + mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW); + res = auto_mount(&path, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW))); #else + mode &= FA_READ; res = auto_mount(&path, 0); #endif if (res != FR_OK) return res; @@ -737,67 +774,67 @@ FRESULT f_open ( #if _FS_READONLY == 0 /* Create or Open a File */ - if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) { - CLUST ps, rs; - DWORD tm; + if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) { + CLUST rs; + DWORD dw; if (res != FR_OK) { /* No file, create new */ - mode |= FA_CREATE_ALWAYS; if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ - if (dir == NULL) return FR_DENIED; + res = reserve_direntry(&dirobj, &dir); + if (res != FR_OK) return res; memset(dir, 0, 32); /* Initialize the new entry */ - memcpy(dir, fn, 8+3); - *(dir+12) = fn[11]; + memcpy(&dir[DIR_Name], fn, 8+3); + dir[DIR_NTres] = fn[11]; + mode |= FA_CREATE_ALWAYS; } else { /* Any object is already existing */ - if (dir == NULL || (*(dir+11) & (AM_RDO|AM_DIR))) /* Could not overwrite (R/O or DIR) */ + if (mode & FA_CREATE_NEW) /* Cannot create new */ + return FR_EXIST; + if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR))) /* Cannot overwrite (R/O or DIR) */ return FR_DENIED; - if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */ + if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */ #if _FAT32 != 0 - rs = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); - ST_WORD(dir+20, 0); + rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); + ST_WORD(&dir[DIR_FstClusHI], 0); #else - rs = LD_WORD(dir+26); + rs = LD_WORD(&dir[DIR_FstClusLO]); #endif - ST_WORD(dir+26, 0); /* cluster = 0 */ - ST_DWORD(dir+28, 0); /* size = 0 */ + ST_WORD(&dir[DIR_FstClusLO], 0); /* cluster = 0 */ + ST_DWORD(&dir[DIR_FileSize], 0); /* size = 0 */ fs->winflag = 1; - ps = fs->winsect; /* Remove the cluster chain */ - if (!remove_chain(rs) || !move_window(ps)) + dw = fs->winsect; /* Remove the cluster chain */ + if (!remove_chain(rs) || !move_window(dw)) return FR_RW_ERROR; + fs->last_clust = rs - 1; /* Reuse the cluster hole */ } } if (mode & FA_CREATE_ALWAYS) { - *(dir+11) = AM_ARC; - tm = get_fattime(); - ST_DWORD(dir+14, tm); /* Created time */ - ST_DWORD(dir+22, tm); /* Updated time */ + dir[DIR_Attr] = AM_ARC; /* New attribute */ + dw = get_fattime(); + ST_DWORD(&dir[DIR_WrtTime], dw); /* Updated time */ + ST_DWORD(&dir[DIR_CrtTime], dw); /* Created time */ fs->winflag = 1; } } /* Open a File */ else { -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ if (res != FR_OK) return res; /* Trace failed */ - if (dir == NULL || (*(dir+11) & AM_DIR)) /* It is a directory */ + if (dir == NULL || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */ return FR_NO_FILE; #if _FS_READONLY == 0 - if ((mode & FA_WRITE) && (*(dir+11) & AM_RDO)) /* R/O violation */ + if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ return FR_DENIED; } -#endif -#if _FS_READONLY == 0 - fp->flag = mode & (FA_WRITE|FA_READ); fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; -#else - fp->flag = mode & FA_READ; #endif - fp->org_clust = LD_WORD(dir+26); /* File start cluster */ - fp->fsize = LD_DWORD(dir+28); /* File size */ - fp->fptr = 0; /* File ptr */ - fp->sect_clust = 1; /* Sector counter */ - fp->fs = fs; fp->id = ~fs->id; /* Owner file system object of the file */ + fp->flag = mode; /* File access mode */ + fp->org_clust = LD_WORD(&dir[DIR_FstClusLO]); /* File start cluster */ + fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */ + fp->fptr = 0; /* File ptr */ + fp->sect_clust = 1; /* Sector counter */ + fp->fs = fs; fp->id = fs->id; /* Owner file system object of the file */ + return FR_OK; } @@ -824,7 +861,7 @@ FRESULT f_read ( *br = 0; - res = validate(fs, fp->id); + res = validate(fs, fp->id); /* Check validity of the object */ if (res) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */ @@ -834,10 +871,10 @@ FRESULT f_read ( for ( ; btr; /* Repeat until all data transferred */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { if ((fp->fptr % 512) == 0) { /* On the sector boundary */ - if (--(fp->sect_clust)) { /* Decrement left sector counter */ + if (--fp->sect_clust) { /* Decrement left sector counter */ sect = fp->curr_sect + 1; /* Get current sector */ } else { /* On the cluster boundary, get next cluster */ - clust = (fp->fptr == 0) ? + clust = (fp->fptr == 0) ? fp->org_clust : get_cluster(fp->curr_clust); if (clust < 2 || clust >= fs->max_clust) goto fr_error; @@ -859,7 +896,7 @@ FRESULT f_read ( if (!move_window(fp->curr_sect)) goto fr_error; /* Move sector window */ rcnt = 512 - (WORD)(fp->fptr % 512); /* Copy fractional bytes from sector window */ if (rcnt > btr) rcnt = btr; - memcpy(rbuff, &fs->win[fp->fptr % 512], rcnt); + memcpy(rbuff, &fs->win[(WORD)fp->fptr % 512], rcnt); } return FR_OK; @@ -872,11 +909,11 @@ fr_error: /* Abort this function due to an unrecoverable error */ +#if _FS_READONLY == 0 /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ -#if _FS_READONLY == 0 FRESULT f_write ( FIL *fp, /* Pointer to the file object */ const void *buff, /* Pointer to the data to be written */ @@ -894,11 +931,11 @@ FRESULT f_write ( *bw = 0; - res = validate(fs, fp->id); + res = validate(fs, fp->id); /* Check validity of the object */ if (res) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ if (!(fp->flag & FA_WRITE)) return FR_DENIED; /* Check access mode */ - if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */ + if (fp->fsize + btw < fp->fsize) return FR_OK; /* File size cannot reach 4GB */ for ( ; btw; /* Repeat until all data transferred */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { @@ -913,7 +950,8 @@ FRESULT f_write ( } else { /* Middle or end of file */ clust = create_chain(fp->curr_clust); /* Trace or streach cluster chain */ } - if (clust < 2 || clust >= fs->max_clust) break; + if (clust == 0) break; /* Disk full */ + if (clust == 1 || clust >= fs->max_clust) goto fw_error; fp->curr_clust = clust; /* Current cluster */ sect = clust2sect(clust); /* Get current sector */ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ @@ -937,7 +975,7 @@ FRESULT f_write ( goto fw_error; wcnt = 512 - (WORD)(fp->fptr % 512); /* Copy fractional bytes bytes to sector window */ if (wcnt > btw) wcnt = btw; - memcpy(&fs->win[fp->fptr % 512], wbuff, wcnt); + memcpy(&fs->win[(WORD)fp->fptr % 512], wbuff, wcnt); fs->winflag = 1; } @@ -949,53 +987,6 @@ fw_error: /* Abort this function due to an unrecoverable error */ fp->flag |= FA__ERROR; return FR_RW_ERROR; } -#endif /* _FS_READONLY */ - - - - -/*-----------------------------------------------------------------------*/ -/* Seek File Pointer */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_lseek ( - FIL *fp, /* Pointer to the file object */ - DWORD ofs /* File pointer from top of file */ -) -{ - CLUST clust; - BYTE sc; - FRESULT res; - FATFS *fs = fp->fs; - - - res = validate(fs, fp->id); - if (res) return res; - if (fp->flag & FA__ERROR) return FR_RW_ERROR; - if (ofs > fp->fsize) ofs = fp->fsize; /* Clip offset by file size */ - fp->fptr = ofs; fp->sect_clust = 1; /* Re-initialize file pointer */ - - /* Seek file pinter if needed */ - if (ofs) { - ofs = (ofs - 1) / 512; /* Calcurate current sector */ - sc = fs->sects_clust; /* Number of sectors in a cluster */ - fp->sect_clust = sc - ((BYTE)ofs % sc); /* Calcurate sector counter */ - ofs /= sc; /* Number of clusters to skip */ - clust = fp->org_clust; /* Seek to current cluster */ - while (ofs--) - clust = get_cluster(clust); - if (clust < 2 || clust >= fs->max_clust) - goto fk_error; - fp->curr_clust = clust; - fp->curr_sect = clust2sect(clust) + sc - fp->sect_clust; /* Current sector */ - } - - return FR_OK; - -fk_error: /* Abort this function due to an unrecoverable error */ - fp->flag |= FA__ERROR; - return FR_RW_ERROR; -} @@ -1004,40 +995,39 @@ fk_error: /* Abort this function due to an unrecoverable error */ /* Synchronize between File and Disk */ /*-----------------------------------------------------------------------*/ -#if _FS_READONLY == 0 FRESULT f_sync ( FIL *fp /* Pointer to the file object */ ) { - BYTE *ptr; + DWORD tim; + BYTE *dir; FRESULT res; FATFS *fs = fp->fs; - res = validate(fs, fp->id); - if (res) return res; - - /* Has the file been written? */ - if (fp->flag & FA__WRITTEN) { - /* Update the directory entry */ - if (!move_window(fp->dir_sect)) - return FR_RW_ERROR; - ptr = fp->dir_ptr; - *(ptr+11) |= AM_ARC; /* Set archive bit */ - ST_DWORD(ptr+28, fp->fsize); /* Update file size */ - ST_WORD(ptr+26, fp->org_clust); /* Update start cluster */ + res = validate(fs, fp->id); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ + /* Update the directory entry */ + if (!move_window(fp->dir_sect)) + return FR_RW_ERROR; + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + ST_DWORD(&dir[DIR_FileSize], fp->fsize); /* Update file size */ + ST_WORD(&dir[DIR_FstClusLO], fp->org_clust); /* Update start cluster */ #if _FAT32 != 0 - ST_WORD(ptr+20, fp->org_clust >> 16); + ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16); #endif - ST_DWORD(ptr+22, get_fattime()); /* Updated time */ - fs->winflag = 1; - fp->flag &= ~FA__WRITTEN; + tim = get_fattime(); /* Updated time */ + ST_DWORD(&dir[DIR_WrtTime], tim); + fp->flag &= ~FA__WRITTEN; + res = sync(); + } } - if (!move_window(0)) return FR_RW_ERROR; - - return FR_OK; + return res; } -#endif /* _FS_READONLY */ + +#endif /* _FS_READONLY == 0 */ @@ -1067,9 +1057,89 @@ FRESULT f_close ( +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL *fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + CLUST clust; + DWORD csize; + BYTE csect; + FRESULT res; + FATFS *fs = fp->fs; + + + res = validate(fs, fp->id); /* Check validity of the object */ + if (res) return res; + + if (fp->flag & FA__ERROR) return FR_RW_ERROR; +#if _FS_READONLY == 0 + if (ofs > fp->fsize && !(fp->flag & FA_WRITE)) +#else + if (ofs > fp->fsize) +#endif + ofs = fp->fsize; + fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */ + + /* Move file R/W pointer if needed */ + if (ofs) { + clust = fp->org_clust; /* Get start cluster */ +#if _FS_READONLY == 0 + if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */ + clust = create_chain(0); + if (clust == 1) goto fk_error; + fp->org_clust = fp->curr_clust = clust; + } +#endif + if (clust) { /* If the file has a cluster chain, it can be followed */ + csize = (DWORD)fs->sects_clust * 512; /* Cluster size in unit of byte */ + while (ofs > csize) { /* Skip leading clusters */ +#if _FS_READONLY == 0 + if (fp->flag & FA_WRITE) /* Check if in write mode or not */ + clust = create_chain(clust); /* Force streached if in write mode */ + else +#endif + clust = get_cluster(clust); /* Only follow cluster chain if not in write mode */ + if (clust == 0) { /* Stop if could not follow the cluster chain */ + ofs = csize; + break; + } + if (clust == 1 || clust >= fs->max_clust) goto fk_error; /* Abort when any error occured */ + fp->curr_clust = clust; /* Update current cluster and R/W pointer */ + fp->fptr += csize; + ofs -= csize; + } + csect = (BYTE)((ofs - 1) / 512); /* Sector offset in the cluster */ + fp->curr_sect = clust2sect(clust) + csect; /* Get current cluster */ + fp->sect_clust = fs->sects_clust - csect; /* Left sector counter in the cluster */ + fp->fptr += ofs; /* Update file R/W pointer */ + } + } +#if _FS_READONLY == 0 + if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */ + fp->fsize = fp->fptr; + fp->flag |= FA__WRITTEN; + } +#endif + + return FR_OK; + +fk_error: /* Abort this function due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} + + + + #if _FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ -/* Create a directroy object */ +/* Open a directroy */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( @@ -1083,25 +1153,25 @@ FRESULT f_opendir ( FATFS *fs = FatFs; - if ((res = auto_mount(&path, 0)) != FR_OK) - return res; - res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */ + res = auto_mount(&path, 0); + if (res != FR_OK) return res; - if (res == FR_OK) { /* Trace completed */ - if (dir != NULL) { /* It is not a root dir */ - if (*(dir+11) & AM_DIR) { /* The entry is a directory */ + res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */ + if (res == FR_OK) { /* Trace completed */ + if (dir != NULL) { /* It is not the root dir */ + if (dir[DIR_Attr] & AM_DIR) { /* The entry is a directory */ #if _FAT32 != 0 - dirobj->clust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); + dirobj->clust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); #else - dirobj->clust = LD_WORD(dir+26); + dirobj->clust = LD_WORD(&dir[DIR_FstClusLO]); #endif dirobj->sect = clust2sect(dirobj->clust); - dirobj->index = 0; + dirobj->index = 2; } else { /* The entry is not a directory */ res = FR_NO_FILE; } } - dirobj->id = ~fs->id; + dirobj->id = fs->id; } return res; } @@ -1123,7 +1193,7 @@ FRESULT f_readdir ( FATFS *fs = dirobj->fs; - res = validate(fs, dirobj->id); + res = validate(fs, dirobj->id); /* Check validity of the object */ if (res) return res; finfo->fname[0] = 0; @@ -1131,9 +1201,9 @@ FRESULT f_readdir ( if (!move_window(dirobj->sect)) return FR_RW_ERROR; dir = &fs->win[(dirobj->index & 15) * 32]; /* pointer to the directory entry */ - c = *dir; + c = dir[DIR_Name]; if (c == 0) break; /* Has it reached to end of dir? */ - if (c != 0xE5 && c != '.' && !(*(dir+11) & AM_VOL)) /* Is it a valid entry? */ + if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */ get_fileinfo(finfo, dir); if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */ if (finfo->fname[0]) break; /* Found valid entry */ @@ -1161,12 +1231,16 @@ FRESULT f_stat ( DIR dirobj; - if ((res = auto_mount(&path, 0)) != FR_OK) - return res; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + res = auto_mount(&path, 0); + if (res != FR_OK) return res; - if (res == FR_OK) /* Trace completed */ - get_fileinfo(finfo, dir); + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + if (res == FR_OK) { /* Trace completed */ + if (dir) /* Found an object */ + get_fileinfo(finfo, dir); + else /* It is root dir */ + res = FR_INVALID_NAME; + } return res; } @@ -1193,8 +1267,8 @@ FRESULT f_getfree ( /* Get drive number */ - if ((res = auto_mount(&drv, 0)) != FR_OK) - return res; + res = auto_mount(&drv, 0); + if (res != FR_OK) return res; *fatfs = fs = FatFs; /* Count number of free clusters */ @@ -1248,39 +1322,38 @@ FRESULT f_unlink ( FATFS *fs = FatFs; - if ((res = auto_mount(&path, 1)) != FR_OK) - return res; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + res = auto_mount(&path, 1); + if (res != FR_OK) return res; + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ if (res != FR_OK) return res; /* Trace failed */ - if (dir == NULL) return FR_NO_FILE; /* It is a root directory */ - if (*(dir+11) & AM_RDO) return FR_DENIED; /* It is a R/O item */ + if (dir == NULL) return FR_INVALID_NAME; /* It is the root directory */ + if (dir[DIR_Attr] & AM_RDO) return FR_DENIED; /* It is a R/O object */ dsect = fs->winsect; #if _FAT32 != 0 - dclust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); + dclust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); #else - dclust = LD_WORD(dir+26); + dclust = LD_WORD(&dir[DIR_FstClusLO]); #endif - if (*(dir+11) & AM_DIR) { /* It is a sub-directory */ + if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */ dirobj.clust = dclust; /* Check if the sub-dir is empty or not */ dirobj.sect = clust2sect(dclust); - dirobj.index = 0; + dirobj.index = 2; do { if (!move_window(dirobj.sect)) return FR_RW_ERROR; sdir = &fs->win[(dirobj.index & 15) * 32]; - if (*sdir == 0) break; - if (!(*sdir == 0xE5 || *sdir == '.') && !(*(sdir+11) & AM_VOL)) + if (sdir[DIR_Name] == 0) break; + if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL)) return FR_DENIED; /* The directory is not empty */ } while (next_dir_entry(&dirobj)); } if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */ - *dir = 0xE5; + dir[DIR_Name] = 0xE5; fs->winflag = 1; if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ - if (!move_window(0)) return FR_RW_ERROR; - return FR_OK; + return sync(); } @@ -1294,7 +1367,7 @@ FRESULT f_mkdir ( const char *path /* Pointer to the directory path */ ) { - BYTE *dir, *w, n; + BYTE *dir, *sec, n; char fn[8+3+1]; DWORD sect, dsect, tim; CLUST dclust, pclust; @@ -1303,57 +1376,58 @@ FRESULT f_mkdir ( FATFS *fs = FatFs; - if ((res = auto_mount(&path, 1)) != FR_OK) - return res; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + res = auto_mount(&path, 1); + if (res != FR_OK) return res; - if (res == FR_OK) return FR_DENIED; /* Any file or directory is already existing */ + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + if (res == FR_OK) return FR_EXIST; /* Any file or directory is already existing */ if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ - if (dir == NULL) return FR_DENIED; + res = reserve_direntry(&dirobj, &dir); /* Reserve a directory entry */ + if (res != FR_OK) return res; sect = fs->winsect; - dsect = clust2sect(dclust = create_chain(0)); /* Get a new cluster for new directory */ + dclust = create_chain(0); /* Allocate a cluster for new directory table */ + if (dclust == 1) return FR_RW_ERROR; + dsect = clust2sect(dclust); if (!dsect) return FR_DENIED; - if (!move_window(0)) return 0; + if (!move_window(0)) return FR_RW_ERROR; - w = fs->win; - memset(w, 0, 512); /* Initialize the directory table */ + sec = fs->win; + memset(sec, 0, 512); /* Initialize the directory table */ for (n = fs->sects_clust - 1; n; n--) { - if (disk_write(0, w, dsect+n, 1) != RES_OK) + if (disk_write(0, sec, dsect+n, 1) != RES_OK) return FR_RW_ERROR; } - fs->winsect = dsect; /* Create dot directories */ - memset(w, ' ', 8+3); - *w = '.'; *(w+11) = AM_DIR; - tim = get_fattime(); ST_DWORD(w+22, tim); - memcpy(w+32, w, 32); *(w+33) = '.'; + fs->winsect = dsect; /* Create "." ".." directories */ + memset(&sec[DIR_Name], ' ', 8+3); /* "." entry */ + sec[DIR_Name] = '.'; + sec[DIR_Attr] = AM_DIR; + tim = get_fattime(); + ST_DWORD(&sec[DIR_WrtTime], tim); + memcpy(&sec[32], &sec[0], 32); sec[33] = '.'; /* ".." entry */ pclust = dirobj.sclust; - ST_WORD(w+32+26, pclust); - ST_WORD(w +26, dclust); + ST_WORD(&sec[ DIR_FstClusLO], dclust); + ST_WORD(&sec[32+DIR_FstClusLO], pclust); #if _FAT32 != 0 + ST_WORD(&sec[ +DIR_FstClusHI], dclust >> 16); if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0; - ST_WORD(w+32+20, pclust >> 16); - ST_WORD(w +20, dclust >> 16); + ST_WORD(&sec[32+DIR_FstClusHI], pclust >> 16); #endif fs->winflag = 1; - if (!move_window(sect)) return FR_RW_ERROR; - memcpy(dir, fn, 8+3); /* Initialize the new entry */ - *(dir+11) = AM_DIR; - *(dir+12) = fn[11]; - memset(dir+13, 0, 32-13); - ST_DWORD(dir+22, tim); /* Crated time */ - ST_WORD(dir+26, dclust); /* Table start cluster */ + + memset(&dir[0], 0, 32); /* Initialize the new entry */ + memcpy(&dir[DIR_Name], fn, 8+3); /* Name */ + dir[DIR_NTres] = fn[11]; + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(&dir[DIR_WrtTime], tim); /* Crated time */ + ST_WORD(&dir[DIR_FstClusLO], dclust); /* Table start cluster */ #if _FAT32 != 0 - ST_WORD(dir+20, dclust >> 16); + ST_WORD(&dir[DIR_FstClusHI], dclust >> 16); #endif - fs->winflag = 1; - if (!move_window(0)) return FR_RW_ERROR; - - return FR_OK; + return sync(); } @@ -1373,21 +1447,19 @@ FRESULT f_chmod ( BYTE *dir; DIR dirobj; char fn[8+3+1]; - FATFS *fs = FatFs; - if ((res = auto_mount(&path, 1)) != FR_OK) - return res; - res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ - - if (res == FR_OK) { /* Trace completed */ - if (dir == NULL) { - res = FR_NO_FILE; - } else { - mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ - *(dir+11) = (value & mask) | (*(dir+11) & ~mask); /* Apply attribute change */ - fs->winflag = 1; - if (!move_window(0)) res = FR_RW_ERROR; + res = auto_mount(&path, 1); + if (res == FR_OK) { + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ + if (res == FR_OK) { /* Trace completed */ + if (dir == NULL) { + res = FR_INVALID_NAME; + } else { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = sync(); + } } } return res; @@ -1413,35 +1485,34 @@ FRESULT f_rename ( FATFS *fs = FatFs; - if ((res = auto_mount(&path_old, 1)) != FR_OK) - return res; - res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ + res = auto_mount(&path_old, 1); + if (res != FR_OK) return res; + res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ if (res != FR_OK) return res; /* The old object is not found */ if (!dir_old) return FR_NO_FILE; sect_old = fs->winsect; /* Save the object information */ - memcpy(direntry, dir_old+11, 32-11); + memcpy(direntry, &dir_old[11], 32-11); res = trace_path(&dirobj, fn, path_new, &dir_new); /* Check new object */ - if (res == FR_OK) return FR_DENIED; /* The new object name is already existing */ - if (res != FR_NO_FILE) return res; + if (res == FR_OK) return FR_EXIST; /* The new object name is already existing */ + if (res != FR_NO_FILE) return res; /* Is there no old name? */ + res = reserve_direntry(&dirobj, &dir_new); /* Reserve a directory entry */ + if (res != FR_OK) return res; - dir_new = reserve_direntry(&dirobj); /* Reserve a directory entry */ - if (dir_new == NULL) return FR_DENIED; - memcpy(dir_new+11, direntry, 32-11); /* Create new entry */ - memcpy(dir_new, fn, 8+3); - *(dir_new+12) = fn[11]; + memcpy(&dir_new[DIR_Attr], direntry, 32-11); /* Create new entry */ + memcpy(&dir_new[DIR_Name], fn, 8+3); + dir_new[DIR_NTres] = fn[11]; fs->winflag = 1; if (!move_window(sect_old)) return FR_RW_ERROR; /* Remove old entry */ *dir_old = 0xE5; - fs->winflag = 1; - if (!move_window(0)) return FR_RW_ERROR; - return FR_OK; + return sync(); } -#endif /* _FS_READONLY */ +#endif /* _FS_READONLY == 0 */ #endif /* _FS_MINIMIZE == 0 */ #endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ diff --git a/src/tff.h b/src/tff.h index c5ef8f3..dd1d222 100644 --- a/src/tff.h +++ b/src/tff.h @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------/ -/ Tiny-FatFs - FAT file system module include file R0.04 (C)ChaN, 2007 +/ Tiny-FatFs - FAT file system module include file R0.04a (C)ChaN, 2007 /---------------------------------------------------------------------------/ / FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, @@ -33,21 +33,21 @@ /* The _FS_MINIMIZE option defines minimization level to remove some functions. / 0: Full function. / 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod and f_rename are removed. -/ 2: f_opendir and f_readdir are removed in addition to level 1. */ +/ 2: f_opendir and f_readdir are removed in addition to level 1. +/ 3: f_lseek is removed in addition to level 2. */ -/* #define _FAT32 0 */ -/* When enable FAT32 support, set _FAT32 to 1. */ +#define _FAT32 0 +/* To add FAT32 support, set _FAT32 to 1. */ -#define _USE_SJIS -/* When _USE_SJIS is defined, Shift-JIS code transparency is enabled, otherwise +#define _USE_SJIS 1 +/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise / only US-ASCII(7bit) code can be accepted as file/directory name. */ #include "integer.h" -/* Result type for fatfs application interface */ -typedef unsigned char FRESULT; +/* Type definition for cluster number */ #if _FAT32 == 0 typedef WORD CLUST; #else @@ -57,10 +57,6 @@ typedef DWORD CLUST; /* File system object structure */ typedef struct _FATFS { - BYTE fs_type; /* FAT type */ - BYTE sects_clust; /* Sectors per cluster */ - BYTE n_fats; /* Number of FAT copies */ - BYTE winflag; /* win[] dirty flag (1:must be written back) */ WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries */ DWORD winsect; /* Current sector appearing in the win[] */ @@ -70,23 +66,30 @@ typedef struct _FATFS { CLUST sects_fat; /* Sectors per fat */ CLUST max_clust; /* Maximum cluster# + 1 */ CLUST last_clust; /* Last allocated cluster */ + BYTE fs_type; /* FAT sub type */ + BYTE sects_clust; /* Sectors per cluster */ + BYTE n_fats; /* Number of FAT copies */ + BYTE winflag; /* win[] dirty flag (1:must be written back) */ BYTE win[512]; /* Disk access window for Directory/FAT/File */ } FATFS; /* Directory object structure */ typedef struct _DIR { + WORD id; /* Owner file system mount ID */ + WORD index; /* Current index */ FATFS* fs; /* Pointer to the owner file system object */ CLUST sclust; /* Start cluster */ CLUST clust; /* Current cluster */ DWORD sect; /* Current sector */ - WORD index; /* Current index */ - WORD id; /* Sum of owner file system mount ID */ } DIR; /* File object structure */ typedef struct _FIL { + WORD id; /* Owner file system mount ID */ + BYTE flag; /* File status flags */ + BYTE sect_clust; /* Left sectors in cluster */ FATFS* fs; /* Pointer to owner file system */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ @@ -97,9 +100,6 @@ typedef struct _FIL { DWORD dir_sect; /* Sector containing the directory entry */ BYTE* dir_ptr; /* Ponter to the directory entry in the window */ #endif - WORD id; /* Sum of owner file system mount ID */ - BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ } FIL; @@ -113,6 +113,25 @@ typedef struct _FILINFO { } FILINFO; +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* 0 */ + FR_NOT_READY, /* 1 */ + FR_NO_FILE, /* 2 */ + FR_NO_PATH, /* 3 */ + FR_INVALID_NAME, /* 4 */ + FR_INVALID_DRIVE, /* 5 */ + FR_DENIED, /* 6 */ + FR_EXIST, /* 7 */ + FR_RW_ERROR, /* 8 */ + FR_WRITE_PROTECTED, /* 9 */ + FR_NOT_ENABLED, /* 10 */ + FR_NO_FILESYSTEM, /* 11 */ + FR_INVALID_OBJECT /* 12 */ +} FRESULT; + + /*-----------------------------------------------------*/ /* FatFs module application interface */ @@ -141,29 +160,13 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16 -/* File function return code (FRESULT) */ - -#define FR_OK 0 -#define FR_NOT_READY 1 -#define FR_NO_FILE 2 -#define FR_NO_PATH 3 -#define FR_INVALID_NAME 4 -#define FR_INVALID_DRIVE 5 -#define FR_DENIED 6 -#define FR_DISK_FULL 7 -#define FR_RW_ERROR 8 -#define FR_WRITE_PROTECTED 9 -#define FR_NOT_ENABLED 10 -#define FR_NO_FILESYSTEM 11 -#define FR_INVALID_OBJECT 12 - - /* File access control and file status flags (FIL.flag) */ #define FA_READ 0x01 #define FA_OPEN_EXISTING 0x00 #if _FS_READONLY == 0 #define FA_WRITE 0x02 +#define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA__WRITTEN 0x20 @@ -171,7 +174,7 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16 #define FA__ERROR 0x80 -/* FAT type signature (FATFS.fs_type) */ +/* FAT sub type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 @@ -190,6 +193,57 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16 +/* Offset of FAT structure members */ + +#define BS_jmpBoot 0 +#define BS_OEMName 3 +#define BPB_BytsPerSec 11 +#define BPB_SecPerClus 13 +#define BPB_RsvdSecCnt 14 +#define BPB_NumFATs 16 +#define BPB_RootEntCnt 17 +#define BPB_TotSec16 19 +#define BPB_Media 21 +#define BPB_FATSz16 22 +#define BPB_SecPerTrk 24 +#define BPB_NumHeads 26 +#define BPB_HiddSec 28 +#define BPB_TotSec32 32 +#define BS_55AA 510 + +#define BS_DrvNum 36 +#define BS_BootSig 38 +#define BS_VolID 39 +#define BS_VolLab 43 +#define BS_FilSysType 54 + +#define BPB_FATSz32 36 +#define BPB_ExtFlags 40 +#define BPB_FSVer 42 +#define BPB_RootClus 44 +#define BPB_FSInfo 48 +#define BPB_BkBootSec 50 +#define BS_DrvNum32 64 +#define BS_BootSig32 66 +#define BS_VolID32 67 +#define BS_VolLab32 71 +#define BS_FilSysType32 82 + +#define MBR_Table 446 + +#define DIR_Name 0 +#define DIR_Attr 11 +#define DIR_NTres 12 +#define DIR_CrtTime 14 +#define DIR_CrtDate 16 +#define DIR_FstClusHI 20 +#define DIR_WrtTime 22 +#define DIR_WrtDate 24 +#define DIR_FstClusLO 26 +#define DIR_FileSize 28 + + + /* Multi-byte word access macros */ #if _MCU_ENDIAN == 1 /* Use word access */ @@ -204,10 +258,11 @@ DWORD get_fattime (void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16 #define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8) #define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24) #else -#error Don't forget to set _MCU_ENDIAN properly! +#error Do not forget to set _MCU_ENDIAN properly! #endif #endif + #define _FATFS -#endif +#endif /* _FATFS */