diff --git a/doc/00index_e.html b/doc/00index_e.html index bc585c1..e525a89 100644 --- a/doc/00index_e.html +++ b/doc/00index_e.html @@ -3,6 +3,8 @@ + + ELM - Generic FAT Files System Module @@ -13,26 +15,22 @@
- -

FatFs module is an experimental project to implement 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.

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

Features of FatFs Module

-

Features of Tiny-FatFs Module

- +

Features of Tiny-FatFs Module (different to FatFs)

+
@@ -45,19 +43,19 @@ - - - - + + + +
FatFs
SectionStd cfg.Min cfg.
Program (R/W cfg.)85266042
Program (R/O cfg.)41723402
Static Work Area2
Dynamic Work Area548 + 540 * <files>
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.)71384862
Program (R/O cfg.)35422778
Static Work Area2
Dynamic Work Area540 + 24 * <files>
Program (R/W cfg.)71644890
Program (R/O cfg.)36602946
Static Work Area4
Dynamic Work Area542 + 28*<files>
@@ -66,6 +64,7 @@

Application Interface

FatFs/Tiny-FatFs module provides following functions.

@@ -101,13 +100,16 @@

Resources

The FatFs/Tiny-FatFs module is a free software and is opened for education, research and development. You can use, modify and/or republish it for personal, non-profit or profit use without any restriction under your responsibility.

-
+ +
+

Return

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

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

-

FatFsモジュールの特徴

+layer +

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

+

FatFsの特徴

-

Tiny-FatFsモジュールの特徴

- +

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

+
-

メモリ使用

-

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

+

メモリ使用量

+

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

- - - - + + + +
FatFs
セクション標準最小
プログラム(R/W構成)85266042
プログラム(R/O構成)41723402
静的ワークエリア2
動的ワークエリア548 + 540 * <files>
プログラム(R/W構成)85746094
プログラム(R/O構成)42683494
静的ワークエリア2 + 2*<drives>
動的ワークエリア550*<drives> + 544*<files>
- - - - + + + +
Tiny-FatFs
セクション標準最小
プログラム(R/W構成)71384862
プログラム(R/O構成)35422778
静的ワークエリア2
動的ワークエリア540 + 24 * <files>
プログラム(R/W構成)71644890
プログラム(R/O構成)36602946
静的ワークエリア4
動的ワークエリア542 + 28*<files>
@@ -65,6 +63,7 @@

上位レイヤI/F

FatFs/Tiny-FatFsモジュールは、次のファイル操作関数を提供しています。

@@ -99,14 +98,17 @@

資料

-

FatFs/Tiny-FatFsモジュールはフリーソフトウェアとして教育・研究・開発用に公開しています。どのような利用目的(個人・非商用・商用)でも使用・改変・配布について一切の制限はありませんが、全て利用者の責任の下での利用とします。

-
+

FatFs/Tiny-FatFsモジュールはフリー・ソフトウェアとして教育・研究・開発用に公開しています。どのような利用目的(個人・非商用・商用)でも使用・改変・配布について一切の制限はありませんが、全て利用者の責任の下での利用とします。

+ +
+

戻る

diff --git a/doc/css_e.css b/doc/css_e.css index bcd398f..30da503 100644 --- a/doc/css_e.css +++ b/doc/css_e.css @@ -24,7 +24,7 @@ div.para {clear: both; font-family: serif;} .equ {text-indent: 0; margin: 1em 2em 1em;} .indent {margin-left: 2em;} .rset {float: right; margin: 0 0 0.5em 0.5em;} -.lset {float: left; margin: 0 0.5em 0.5em 0;} +.lset {float: left; margin: 0 0.5em 0.5em 0.5em;} ul.flat li {list-style-type: none; margin: 0;} a.imglnk img {border: 1px solid;} .iequ {white-space: nowrap; font-weight: bold;} diff --git a/doc/css_j.css b/doc/css_j.css index 7068916..c3327f2 100644 --- a/doc/css_j.css +++ b/doc/css_j.css @@ -27,7 +27,7 @@ div.para {clear: both; font-family: " .equ {text-indent: 0; margin: 1em 2em 1em;} .indent {margin-left: 2em;} .rset {float: right; margin: 0 0 0.5em 0.5em;} -.lset {float: left; margin: 0 0.5em 0.5em 0;} +.lset {float: left; margin: 0 0.5em 0.5em 0.5em;} ul.flat li {list-style-type: none; margin: 0;} a.imglnk img {border: 1px solid;} .iequ {white-space: nowrap; font-weight: bold;} diff --git a/doc/en/appnote.html b/doc/en/appnote.html new file mode 100644 index 0000000..08bdad5 --- /dev/null +++ b/doc/en/appnote.html @@ -0,0 +1,108 @@ + + + + + + + +FatFs Module Application Note + + + +

FatFs Module Application Note (for R0.04)

+
+ +
+

Considerations on porting to various platform

+

The FatFs module is assuming following terms on portability.

+ +
+ + +
+

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.

+
+ + + + + +
Memory SizeFAT Type
<= 64MBFAT12
128MB - 2GBFAT16
>= 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.

+
+ + +
+

Performance effective file access

+

For good performance on reading/writing files on the small embedded system, application program should consider what process is done in the FatFs module. The file data on the disk is transferred by f_read function in following process.

+

Figure 1. Sector miss-aligned read (short)
+ +

+

Figure 2. Sector miss-aligned read (long)
+ +

+

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.

+

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.

+
+ + +
+

Critical section

+

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 +
+
+Figure 5. Minimized critical section
+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.

+ +

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.

+
+ + +
+

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.

+
+ +

Return

+ + diff --git a/doc/en/chmod.html b/doc/en/chmod.html index d571fb9..502bdba 100644 --- a/doc/en/chmod.html +++ b/doc/en/chmod.html @@ -12,12 +12,12 @@

f_chmod

-

The f_chmod changes the attribute of a file or directory.

+

The f_chmod function changes the attribute of a file or directory.

 FRESULT f_chmod (
-  const char* FileName, // Pointer to the file or directory
-  BYTE Attribute,       // Attribute flags
-  BYTE AttributeMask    // Attribute masks
+  const char* FileName, /* Pointer to the file or directory */
+  BYTE Attribute,       /* Attribute flags */
+  BYTE AttributeMask    /* Attribute masks */
 );
 
@@ -26,7 +26,7 @@ FRESULT f_chmod (

Parameter

FileName
-
Pointer to the null-terminated string that specifies a file or directory to be changed
+
Pointer to the null-terminated string that specifies a file or directory to be changed
Attribute
Attribute flags to be set in one or more combination of the following flags. The specified flags are set and others are cleard.
@@ -54,16 +54,16 @@ FRESULT f_chmod (
Could not find the path.
FR_INVALID_NAME
The file name is invalid.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
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.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -72,14 +72,14 @@ FRESULT f_chmod (

Description

-

The f_chmod changes the attribute of a file or directory. This function is not supported in read-only configuration and minimization level of >=1.

+

The f_chmod function changes the attribute of a file or directory. This function is not supported in read-only configuration and minimization level of >=1.

Example

-    // Set read-only flag, clear archive flag and others are left unchanged.
+    // Set read-only flag, clear archive flag and others are retained.
     f_chmod("file.txt", AR_RDO, AR_RDO | AR_ARC);
 
diff --git a/doc/en/close.html b/doc/en/close.html index a79bb8f..b403ff5 100644 --- a/doc/en/close.html +++ b/doc/en/close.html @@ -12,10 +12,10 @@

f_close

-

Function f_close closes a file.

+

The f_close function closes an open file.

 FRESULT f_close (
-  FIL* FileObject     // Pointer to the file object structure
+  FIL* FileObject     /* Pointer to the file object structure */
 );
 
@@ -24,7 +24,7 @@ FRESULT f_close (

Parameter

FileObject
-
Pointer to the file object structure to be closed.
+
Pointer to the open file object structure to be closed.
@@ -33,20 +33,20 @@ FRESULT f_close (

Return Values

FR_OK (0)
-
The file has been closed successfuly.
+
The file object has been closed successfuly.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change occured.
-
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
Any error has occured in low level disk I/O.
+
FR_NOT_READY
+
The disk drive cannot work due to no medium in the drive or any other reason.
+
FR_INVALID_OBJECT
+
The file object is invalid.

Description

-

Function f_close closes a file. If any data has been written, the cached information of the file is written back to the disk. When the function succeeded, the file object is no longer valid and structure can be discarded.

+

The f_close function closes an open file object. If any data has been written to the file, the cached information of the file is written back to the disk. After the function succeeded, the file object is no longer valid and it can be discarded.

diff --git a/doc/en/dinit.html b/doc/en/dinit.html index cb8a231..939e505 100644 --- a/doc/en/dinit.html +++ b/doc/en/dinit.html @@ -12,20 +12,31 @@

disk_initialize

-

The disk_initialize initializes the disk drive.

+

The disk_initialize function initializes the disk drive.

-DSTATUS disk_initialize ();
+DSTATUS disk_initialize (
+  BYTE Drive           /* Physical drive number */
+);
 
+
+

Parameters

+
+
Drive
+
Specifies the physical drive number to initialize.
+
+
+ +

Return Values

-

This function returns a disk status. For details of the disk status, refer to the disk_status().

+

This function returns a disk status as the result. For details of the disk status, refer to the disk_status function.

Description

-

The disk_initialize initializes the disk drive. When the function succeeded, STA_NOINIT flag in the return value will be cleard.

+

The disk_initialize function initializes a physical drive. When the function succeeded, STA_NOINIT flag in the return value is cleard.

Return

diff --git a/doc/en/dread.html b/doc/en/dread.html index d842843..6105b94 100644 --- a/doc/en/dread.html +++ b/doc/en/dread.html @@ -12,12 +12,13 @@

disk_read

-

The disk_read reads sector(s) from the disk drive.

+

The disk_read function reads sector(s) from the disk drive.

 DRESULT disk_read (
-  BYTE* Buffer,        // Pointer to the read buffer.
-  DWORD SectorNumber,  // Sector number to read from.
-  BYTE SectorCount     // Number of sectros to read.
+  BYTE Drive,          /* Physical drive number */
+  BYTE* Buffer,        /* Pointer to the read buffer */
+  DWORD SectorNumber,  /* Sector number to read from */
+  BYTE SectorCount     /* Number of sectros to read */
 );
 
@@ -25,6 +26,8 @@ DRESULT disk_read (

Parameters

+
Drive
+
Specifies the physical drive number to read.
Buffer
Pointer to the read buffer to store the read data. SectorCount * 512 bytes is required for the size of the read buffer.
SectorNumber
diff --git a/doc/en/dstat.html b/doc/en/dstat.html index f84ea3a..b224956 100644 --- a/doc/en/dstat.html +++ b/doc/en/dstat.html @@ -12,22 +12,33 @@

disk_status

-

The disk_status gets the disk status.

+

The disk_status function gets the disk status.

-DSTATUS disk_status ();
+DSTATUS disk_status (
+  BYTE Drive     /* Physical drive number */
+);
 
+
+

Parameters

+
+
Drive
+
Specifies the physical drive number to be tested.
+
+
+ +

Return Values

The disk status is returned in combinatin of following flags.

STA_NOINIT
-
Indicates that the disk drive has not been initialiezed. This flag is set when power-on, occurrence of disk removal or disk_initialize() failed and cleared when disk_initialize() succeeded.
+
Indicates that the disk drive has not been initialiezed. This flag is set on: power-on, disk removal and disk_initialize function failed, and cleared on: disk_initialize function succeeded.
STA_NODISK
-
Indicates that no disk in the drive. It is always cleared on non-removable drive.
+
Indicates that no medium in the drive. It is always cleared on fixed disk drive.
STA_PROTECTED
-
Indicates that the disk is write protected. It is always cleared on the disk that has not write protect notch.
+
Indicates that the medium is write protected. It is always cleared on the drive that does not support write protect notch.
diff --git a/doc/en/dwrite.html b/doc/en/dwrite.html index 554a4b0..032de5f 100644 --- a/doc/en/dwrite.html +++ b/doc/en/dwrite.html @@ -15,9 +15,10 @@

The disk_write writes sector(s) to the disk.

 DRESULT disk_write (
-  const BYTE* Buffer,  // Pointer to the data to be written.
-  DWORD SectorNumber,  // Sector number to write.
-  BYTE SectorCount     // Number of sectors to write.
+  BYTE Drive,          /* Physical drive number */
+  const BYTE* Buffer,  /* Pointer to the read buffer */
+  DWORD SectorNumber,  /* Sector number to write */
+  BYTE SectorCount     /* Number of sectors to write */
 );
 
@@ -25,6 +26,8 @@ DRESULT disk_write (

Parameters

+
Drive
+
Specifies the physical drive number to write.
Buffer
Pointer to the data to be written.
SectorNumber diff --git a/doc/en/fattime.html b/doc/en/fattime.html index 6b02400..39081ab 100644 --- a/doc/en/fattime.html +++ b/doc/en/fattime.html @@ -12,9 +12,9 @@

get_fattime

-

The get_fattime gets current time.

+

The get_fattime function gets current time.

-DWORD get_fattime ();
+DWORD get_fattime (void);
 
@@ -41,7 +41,7 @@ DWORD get_fattime ();

Description

-

The function must return any valid time even if the system does not support a real time clock. The get_fattime is not required in read only configuration.

+

The get_fattime function must return any valid time even if the system does not support a real time clock. This fucntion is not required in read only configuration.

diff --git a/doc/en/filename.html b/doc/en/filename.html new file mode 100644 index 0000000..bd52e5e --- /dev/null +++ b/doc/en/filename.html @@ -0,0 +1,36 @@ + + + + + + + +FatFs - File and Path name on the FatFs module + + + +

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.

+
+
+ "Drive#:directory/file"
+
+ "file1.txt"           a file on drive 0
+ "/file1.txt"          (same as above)
+ "dir1/dir2/file1.txt" a file on drive 0
+ "2:dir3/file2.txt"    a file on drive 2
+ "2:/dir5"             a directory on drive 2
+ ""                    the root directory on drive 0
+ "/"                   (same as above)
+ "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.

+
+ + + diff --git a/doc/en/getfree.html b/doc/en/getfree.html index 86a516b..87f5a6d 100644 --- a/doc/en/getfree.html +++ b/doc/en/getfree.html @@ -12,10 +12,12 @@

f_getfree

-

The f_getfree gets number of the free clusters.

+

The f_getfree function gets number of the free clusters.

 FRESULT f_getfree (
-  DWORD* Clusters     // Pointer to the variable to store number of free clusters.
+  const char* Path,         /* Root directory of the drive */
+  DWORD* Clusters,          /* Pointer to the variable to store number of free clusters */
+  FATFS** FileSystemObject  /* Pointer to pointer to file system object */
 );
 
@@ -23,8 +25,12 @@ FRESULT f_getfree (

Parameters

+
Path
+
Pinter to the null-terminated string that specifies the root directory of the logical drive. Always specify a null-string for Tiny-FatFs.
Clusters
Pointer to the DWORD variable to store number of free clusters.
+
FileSystemObject
+
Pointer to the pointer that to be stored the pointer to corresponding file system object.
@@ -33,15 +39,15 @@ FRESULT f_getfree (

Return Values

FR_OK (0)
-
The function succeeded. The *Clusters havs number of free clusters.
+
The function succeeded. The *Clusters havs number of free clusters and *FileSystemObject points the file system object.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
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.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -50,21 +56,26 @@ FRESULT f_getfree (

Descriptions

-

The f_getfree gets number of free clusters on the drive. The FatFs.sects_clust is indicating number of sectors per cluster, so that the free space in unit of byte can be calcurated with this. This function is not supported in read-only configuration and minimization level of >= 1.

+

The f_getfree function gets number of free clusters on the drive. The sects_clust member in the file system object refreting number of sectors per cluster, so that the free space in unit of sector can be calcurated with this. This function is not supported in read-only configuration and minimization level of >= 1.

Samples Code

+    FATFS *fs;
     DWORD clust;
 
+
     // Get free clusters
-    res = f_getfree(&clust);
+    res = f_getfree("", &clust, &fs);
     if (res) die(res);
 
-    // Get free bytes
-    printf("%lu bytes available on the disk.\n", clust * FatFs->sects_clust * 512);
+    // 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,
+           clust * fs->sects_clust / 2);
 
diff --git a/doc/en/lseek.html b/doc/en/lseek.html index 034dded..2ae6aa8 100644 --- a/doc/en/lseek.html +++ b/doc/en/lseek.html @@ -12,11 +12,11 @@

f_lseek

-

The f_lseek moves the file read/write pointer.

+

The f_lseek functione moves the file read/write pointer of an open file object.

 FRESULT f_lseek (
-  FIL* FileObject,   // Pointer to the file object structure
-  DWORD Offset       // File offset in unit of byte
+  FIL* FileObject,   /* Pointer to the file object structure *
+  DWORD Offset       /* File offset in unit of byte *
 );
 
@@ -25,7 +25,7 @@ FRESULT f_lseek (

Parameters

FileObject
-
Pointer to the file object structure.
+
Pointer to the open file object.
Offset
Number of bytes where from start of file
@@ -39,17 +39,17 @@ FRESULT f_lseek (
The function succeeded.
FR_RW_ERROR
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal, such as a medium change during any file is opend, has been occured.
-
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
FR_NOT_READY
+
The disk drive cannot work due to no medium in the drive or any other reason.
+
FR_INVALID_OBJECT
+
The file object is invalid.

Description

-

The f_lseek moves the file read/write pointer. 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 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.

@@ -66,7 +66,7 @@ FRESULT f_lseek ( res = f_lseek(&file, file.fptr - 2000); // Move to end of the file - res = f_lseek(&file, 0xFFFFFFFF); + res = f_lseek(&file, file.fsize); diff --git a/doc/en/mkdir.html b/doc/en/mkdir.html index 0af7ed3..2a5e2e8 100644 --- a/doc/en/mkdir.html +++ b/doc/en/mkdir.html @@ -12,10 +12,10 @@

f_mkdir

-

The f_mkdir creates a directory.

+

The f_mkdir function creates a new directory.

 FRESULT f_mkdir (
-  const char* DirName // Pointer to the directory name
+  const char* DirName /* Pointer to the directory name */
 );
 
@@ -24,7 +24,7 @@ FRESULT f_mkdir (

Parameter

DirName
-
Pointer to the null-terminated string that specifies the full-path directory name to create. The directory separator is '/'. Because the FatFs module does not have a concept of current directory, a full-path name that followed from the root directory must be used. Leading space charactors are skipped if exist and heading '/' can be exist or omitted.
+
Pointer to the null-terminated string that specifies the directory name to create.
@@ -38,6 +38,8 @@ FRESULT f_mkdir (
Could not find the path.
FR_INVALID_NAME
The path name is invalid.
+
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.
FR_NOT_READY
@@ -46,10 +48,8 @@ FRESULT f_mkdir (
The medium is write protected.
FR_RW_ERROR
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -58,7 +58,7 @@ FRESULT f_mkdir (

Description

-

The f_mkdir creates an empty directory. This function is not supported in read-only configuration and minimization level of >= 1.

+

The f_mkdir function creates a new directory. This function is not supported in read-only configuration and minimization level of >= 1.

diff --git a/doc/en/mkfs.html b/doc/en/mkfs.html new file mode 100644 index 0000000..a69462d --- /dev/null +++ b/doc/en/mkfs.html @@ -0,0 +1,70 @@ + + + + + + + +FatFs - f_mkfs + + + + +
+

f_mkfs

+

The f_mkfs fucntion creates a file system on the drive.

+
+FRESULT f_mkfs (
+  BYTE  Drive,            /* Logical drive number */
+  BYTE  PartitioningRule, /* Partitioning rule */
+  BYTE  AllocSize         /* Allocation unit size */
+);
+
+
+ +
+

Parameters

+
+
Drive
+
Logical drive number (0-9) to be formatted.
+
PartitioningRule
+
When 0 is given, a partition table is created into first sector on the drive and then the file system is created on the partition. This is called FDISK format. When 1 is given, the file system starts from the first sector without partition table. This is often called super floppy (SFD) format.
+
AllocSize
+
Specifies allocation unit size (number of sectors per cluster). The value must be power of 2 in range of from 1 to 64.
+
+
+ +
+

Return Values

+
+
FR_OK (0)
+
The function succeeded.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
+
FR_NOT_READY
+
The drive cannot work due to any reason.
+
FR_WRITE_PROTECTED
+
The drive is write protected.
+
FR_RW_ERROR
+
The function failed due to a write error in the low level disk I/O.
+
FR_MKFS_ABORTED
+
The function aborted before start in format due to a reason as follows. +
    +
  • The disk size is too small.
  • +
  • Invalid parameter was given to any parameter.
  • +
  • Not allowable cluster size for this drive. This can occure when number of clusters becomes around 0xFF7 and 0xFFF7.
  • +
+
+
+
+ +
+

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.

+

This function is supported on only FatFs with _USE_MKFS option.

+

+ + +

Return

+ + diff --git a/doc/en/mount.html b/doc/en/mount.html new file mode 100644 index 0000000..bd705b9 --- /dev/null +++ b/doc/en/mount.html @@ -0,0 +1,59 @@ + + + + + + + +FatFs - f_mount + + + + +
+

f_mount

+

The f_mount fucntion registers/unregisters a work area to the FatFs module.

+
+FRESULT f_mount (
+  BYTE  Drive,              /* Logical drive number */
+  FATFS*  FileSystemObject  /* Pointer to the work area */
+);
+
+
+ +
+

Parameters

+
+
Drive
+
Logical drive number (0-9) to register/unregister the work area. Always 0 for Tiny-FatFs.
+
FileSystemObject
+
Pointer to the work area (file system object) to be registered.
+
+
+ +
+

Return Values

+
+
FR_OK (0)
+
The function succeeded.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
+
+
+ + +
+

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.

+

+ + +
+

References

+

FATFS

+
+ +

Return

+ + diff --git a/doc/en/open.html b/doc/en/open.html index aeeab39..2221cea 100644 --- a/doc/en/open.html +++ b/doc/en/open.html @@ -12,12 +12,12 @@

f_open

-

The f_open function creates or opens the file and initialize a file object structure to be used to access the file.

+

The f_open function creates a file object to be used to access the file.

 FRESULT f_open (
-  FIL* FileObject,      // Pointer to the file object structure
-  const char* FileName, // Pointer to the file neme
-  BYTE ModeFlags        // Mode flags
+  FIL* FileObject,      /* Pointer to the blank file object structure */
+  const char* FileName, /* Pointer to the file neme */
+  BYTE ModeFlags        /* Mode flags */
 );
 
@@ -26,9 +26,9 @@ FRESULT f_open (

Parameters

FileObject
-
Pointer to the blank file object structure to be initialized. After the f_open() succeeded, the file can be accessed with the file object structure until it is closed.
+
Pointer to the file object structure to be created. After the f_open funciton succeeded, the file can be accessed with the file object structure until it is closed.
FileName
-
Pointer to a null-terminated string specifies the full-path file name to create or open. The directory separator is '/'. Because the FatFs module does not have a concept of current directory, a full-path name that followed from the root directory must be used. Leading space charactors are skipped if exist, and heading '/' can be exist or omitted.
+
Pointer to a null-terminated string that specifies the file name to create or open.
ModeFlags
Specifies the type of access and open method for the file. It is specified by a combination of following flags.
@@ -48,13 +48,15 @@ FRESULT f_open (

Return Values

FR_OK (0)
-
The function succeeded. The FileObject structure is used for subsequent calls to refer to the file. When close the file, use function f_close().
+
The function succeeded and the file object is valid.
FR_NO_FILE
Could not find the file.
FR_NO_PATH
Could not find the path.
FR_INVALID_NAME
The file name is invalid.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
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
@@ -63,10 +65,8 @@ FRESULT f_open (
Write mode open or creation under the medium is write protected.
FR_RW_ERROR
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -75,7 +75,8 @@ FRESULT f_open (

Description

-

To start FatFs module, prepare a work area (FATFS structure), fill it with zero and set its address to the global variable FatFs to give the work area to the FatFs module. All file functions can work after the initialization. f_mountdrv() can also be used instead of the zero filling, however, the physical drive must be ready at that time. To terminate use of the FatFs module, close all files, clear FatFs and then the work area can be discarded.

+

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.

@@ -85,16 +86,15 @@ FRESULT f_open (
 void main ()
 {
-    FATFS fs;            // FatFs work area
-    FIL fsrc, fdst;      // file structures
+    FATFS fs;            // Work area (file system object) for logical drive
+    FIL fsrc, fdst;      // file objects
     BYTE buffer[4096];   // file copy buffer
     FRESULT res;         // FatFs function common result code
     WORD br, bw;         // File R/W count
 
 
-    // Give a work area to FatFs module (activate FatFs module)
-    FatFs = &fs;
-    memset(&fs, 0, sizeof(FATFS));  // Clear work area. f_mountdrv() can also be used instead.
+    // Register a work area to logical drive 0
+    f_mount(0, &fs);
 
     // Open source file
     res = f_open(&fsrc, "srcfile.dat", FA_OPEN_EXISTING | FA_READ);
@@ -107,7 +107,7 @@ void main ()
     // Copy source to destination
     for (;;) {
         res = f_read(&fsrc, buffer, sizeof(buffer), &br);
-        if (res || br == 0) break;   // error or eof
+        if (res || br == 0) break;      // error or eof
         res = f_write(&fdst, buffer, br, &bw);
         if (res || bw < br) break;   // error or disk full
     }
@@ -116,8 +116,8 @@ void main ()
     f_close(&fsrc);
     f_close(&fdst);
 
-    // Deactivate FatFs module
-    FatFs = NULL;
+    // Unregister a work area before discard it
+    f_mount(0, NULL);
 }
 
diff --git a/doc/en/opendir.html b/doc/en/opendir.html index c0e74dd..e36f2a1 100644 --- a/doc/en/opendir.html +++ b/doc/en/opendir.html @@ -12,11 +12,11 @@

f_opendir

-

The f_opendir opens a directory.

+

The f_opendir function opens a directory.

 FRESULT f_opendir (
-  DIR* DirObject,      // Pointer to blank directory object structure
-  const char* DirName  // Pointer to the directory name
+  DIR* DirObject,      /* Pointer to the blank directory object structure */
+  const char* DirName  /* Pointer to the directory name */
 );
 
@@ -25,9 +25,9 @@ FRESULT f_opendir (

Parameter

DirObject
-
Pointer to the blank directory object to be initialized
+
Pointer to the blank directory object to be created.
DirName
-
Pinter to the null-terminated string that specifies the full-path directory name to be opened. The directory separator is '/'. Because the FatFs module does not have a concept of current directory, a full-path name that followed from the root directory must be used. Leading space charactors are skipped if exist and heading '/' can be exist or omitted. The target directory name cannot be followed by a '/'. When open the root directory, specify "" or "/".
+
Pinter to the null-terminated string that specifies the directory name to be opened.
@@ -36,21 +36,21 @@ FRESULT f_opendir (

Return Values

FR_OK (0)
-
The function succeeded. The DirObject structure is used for subsequent calls to read the directory entries.
+
The function succeeded and the directory object is created. It is used for subsequent calls to read the directory entries.
FR_NO_FILE
Could not find the directory.
FR_NO_PATH
Could not find the path.
FR_INVALID_NAME
The path name is invalid.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
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.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -59,7 +59,7 @@ FRESULT f_opendir (

Description

-

The f_opendir opens a directory and initializes the DirObject structure for subsequent calls. The directory object structure can be discarded at any time. 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 2.

diff --git a/doc/en/read.html b/doc/en/read.html index b9ee0ab..36e4569 100644 --- a/doc/en/read.html +++ b/doc/en/read.html @@ -12,13 +12,13 @@

f_read

-

The f_read reads data from a file.

+

The f_read function reads data from a file.

 FRESULT f_read (
-  FIL* FileObject,    // Pointer to the file object structure
-  void* Buffer,       // Pointer to the buffer to store read data
-  WORD ByteToRead,    // Number of bytes to read
-  WORD* ByteRead      // Pointer to the variable to return number of bytes read
+  FIL* FileObject,    /* Pointer to the file object structure */
+  void* Buffer,       /* Pointer to the buffer to store read data */
+  WORD ByteToRead,    /* Number of bytes to read */
+  WORD* ByteRead      /* Pointer to the variable to return number of bytes read */
 );
 
@@ -27,7 +27,7 @@ FRESULT f_read (

Parameters

FileObject
-
Pointer to the valid file object structure.
+
Pointer to the open file object.
Buffer
Pointer to the buffer to store read data
ByteToRead
@@ -46,18 +46,18 @@ FRESULT f_read (
FR_DENIED
The function denied due to the file has been opened in write only mode.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
Any error has occured in low level disk I/O.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
-
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
FR_INVALID_OBJECT
+
The file object is invalid.

Description

-

The read/write pointer increases in number of bytes read. The ByteRead will be less than ByteToRead when the read pointer reached to end of the file or any error occured during the read operation.

+

The file pointer in the file object increases in number of bytes read. The ByteRead will become less than ByteToRead when the read pointer reached to end of the file or any error occured during the read operation.

diff --git a/doc/en/readdir.html b/doc/en/readdir.html index ee717d6..9ae8113 100644 --- a/doc/en/readdir.html +++ b/doc/en/readdir.html @@ -12,11 +12,11 @@

f_readdir

-

The f_readdir reads directory items.

+

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 strcture */
+  FILINFO* FileInfo  /* Pointer to the blank file information structure */
 );
 
@@ -25,7 +25,7 @@ FRESULT f_readdir (

Parameters

DirObject
-
Pointer to the valid directory object strcture.
+
Pointer to the open directory strcture.
FileInfo
Pointer to the file information structure to store the read item.
@@ -41,15 +41,15 @@ FRESULT f_readdir (
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.
-
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
FR_INVALID_OBJECT
+
The directory object is invalid.

Description

-

The f_readdir reads directory items in sequence. All items in the directory can be read by calling f_readdir repeatedly. When all items have been read and no item to read, the member f_name[] in the file information structure gets a null string. 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 86a67d5..d305713 100644 --- a/doc/en/rename.html +++ b/doc/en/rename.html @@ -15,8 +15,8 @@

Rename file or directory.

 FRESULT f_rename (
-  const char* OldName, // Pointer to old object name
-  const char* NewName  // Pointer to new object name
+  const char* OldName, /* Pointer to old file/directory name */
+  const char* NewName  /* Pointer to new file/directory name */
 );
 
@@ -25,9 +25,9 @@ FRESULT f_rename (

Parameter

OldName
-
Pointer to a null-terminated string specifies the old object name to be renamed.
+
Pointer to a null-terminated string specifies the old file/directory name to be renamed.
NewName
-
Pointer to a null-terminated string specifies the new object name. Existing name cannot be used.
+
Pointer to a null-terminated string specifies the new file/directory name without drive number. Existing object nannot be specified.
@@ -38,11 +38,13 @@ FRESULT f_rename (
FR_OK (0)
The function succeeded.
FR_NO_FILE
-
Could not find the file or directory.
+
Could not find the file nor directory.
FR_NO_PATH
Could not find the path.
FR_INVALID_NAME
The file name is invalid.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
FR_DENIED
@@ -51,10 +53,8 @@ FRESULT f_rename (
The medium is write protected.
FR_RW_ERROR
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -63,8 +63,8 @@ FRESULT f_rename (

Description

-

Rename a file or directory and can move it to other directory. This function is not supported in read-only configuration or minimization level of >= 1.

-

Note: In this revision, moving any directory to other directory collapses the file system.

+

Rename a file or directory and can move it to other directory. Logical drive number is determined by old name, new name must not contain logical drive number. This function is not supported in read-only configuration or minimization level of >= 1.

+

Note: In this revision, moving any directory to other directory collapses the FAT structure on the disk.

diff --git a/doc/en/sdir.html b/doc/en/sdir.html index 537930e..ff9ae80 100644 --- a/doc/en/sdir.html +++ b/doc/en/sdir.html @@ -12,23 +12,27 @@

DIR

-

The DIR structure is used for the work area to read a directory.

+

The DIR structure is used for the work area to read a directory by f_oepndir and f_readdir functions.

FatFs

 typedef struct _DIR {
-    DWORD   sclust;       // Directory start cluster
-    DWORD   clust;        // Current reading cluster
-    DWORD   sect;         // Current reading sector
-    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    sclust;       // Directory start cluster
-    WORD    clust;        // Current reading cluster
-    DWORD   sect;         // Current reading sector
-    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 5240d35..dcc6f82 100644 --- a/doc/en/sfatfs.html +++ b/doc/en/sfatfs.html @@ -12,17 +12,16 @@

FATFS

-

The FATFS structure holds dynamic work area of the FatFs modlue and it is allocated by an application program. There is no members that can be changed from the application program.

+

The FATFS structure holds dynamic work area of individual logical drives. It is given by application program and registerd/unregisterd to the FatFs module with f_mount function. There is no member that can be changed from the application program.

FatFs

 typedef struct _FATFS {
-    BYTE    fs_type;        /* FAT type */
-    BYTE    files;          /* Number of files currently opend */
+    BYTE    fs_type;        /* FAT type (0:Not mouted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
-    WORD    n_rootdir;      /* Number of root directory entry */
-    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
-    BYTE    pad1;
+    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[] */
     DWORD   sects_fat;      /* Sectors per fat */
     DWORD   max_clust;      /* Maximum cluster# + 1 */
@@ -30,6 +29,7 @@ typedef struct _FATFS {
     DWORD   dirbase;        /* Root directory start sector (cluster# for FAT32) */
     DWORD   database;       /* Data start sector */
     DWORD   last_clust;     /* Last allocated cluster */
+    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
     BYTE    win[512];       /* Disk access window for Directory/FAT */
 } FATFS;
 
@@ -37,20 +37,19 @@ typedef struct _FATFS {

Tiny-FatFs

 typedef struct _FATFS {
-    BYTE    fs_type;        /* FAT type */
-    BYTE    files;          /* Number of files currently opend */
+    BYTE    fs_type;        /* FAT type (0:Not mouted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
-    WORD    n_rootdir;      /* Number of root directory entry */
     BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
-    BYTE    pad1;
+    WORD    id;             /* File system mount ID */
+    WORD    n_rootdir;      /* Number of root directory entries */
     DWORD   winsect;        /* Current sector appearing in the win[] */
-    WORD    sects_fat;      /* Sectors per fat */
-    WORD    max_clust;      /* Maximum cluster# + 1 */
     DWORD   fatbase;        /* FAT start sector */
     DWORD   dirbase;        /* Root directory start sector */
     DWORD   database;       /* Data start sector */
-    WORD    last_clust;     /* Last allocated cluster */
+    CLUST   sects_fat;      /* Sectors per fat */
+    CLUST   max_clust;      /* Maximum cluster# + 1 */
+    CLUST   last_clust;     /* Last allocated cluster */
     BYTE    win[512];       /* Disk access window for Directory/FAT/File */
 } FATFS;
 
diff --git a/doc/en/sfile.html b/doc/en/sfile.html index 121d4f9..32e96bc 100644 --- a/doc/en/sfile.html +++ b/doc/en/sfile.html @@ -12,36 +12,40 @@

FIL

-

The FIL structure holds state of a file and it is allocated by an application program. There is no member that can be changed by the application program.

+

The FIL structure (file object) holds state of a file. It is created by f_open function and discarded by f_close function. There is no member that can be changed by the application program.

FatFs

 typedef struct _FIL {
-    DWORD   fptr;           // File R/W pointer
-    DWORD   fsize;          // File size
-    DWORD   org_clust;      // File start cluster
-    DWORD   curr_clust;     // Current cluster
-    DWORD   curr_sect;      // Current sector
-    DWORD   dir_sect;       // Sector# containing the directory entry
-    BYTE*   dir_ptr;        // Ponter to the directory entry in the window
-    BYTE    flag;           // File status flags
-    BYTE    sect_clust;     // Left sectors in current cluster
-    BYTE    buffer[512];    // File R/W buffer
+    FATFS*  fs;             /* Pointer to the owner file system object */
+    DWORD   fptr;           /* File R/W pointer */
+    DWORD   fsize;          /* File size */
+    DWORD   org_clust;      /* File start cluster */
+    DWORD   curr_clust;     /* Current cluster */
+    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;
 

Tiny-FatFs

 typedef struct _FIL {
-    DWORD   fptr;           // File R/W pointer
-    DWORD   fsize;          // File size
-    WORD    org_clust;      // File start cluster
-    WORD    curr_clust;     // Current cluster
-    DWORD   curr_sect;      // Current sector
-    DWORD   dir_sect;       // Sector# containing the directory entry
-    BYTE*   dir_ptr;        // Ponter to the directory entry in the window
-    BYTE    flag;           // File status flags
-    BYTE    sect_clust;     // Left sectors in current cluster
+    FATFS*  fs;             /* Pointer to owner file system */
+    DWORD   fptr;           /* File R/W pointer */
+    DWORD   fsize;          /* File size */
+    CLUST   org_clust;      /* File start cluster */
+    CLUST   curr_clust;     /* Current cluster */
+    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 1e54aa1..b4e899e 100644 --- a/doc/en/stat.html +++ b/doc/en/stat.html @@ -15,8 +15,8 @@

The f_stat gets the file status.

 FRESULT f_stat (
-  const char* FileName,  // Pointer to the file or directory name
-  FILINFO* FileInfo      // Pointer to the FILINFO structure
+  const char* FileName,   /* Pointer to the file or directory name */
+  FILINFO* FileInfo       /* Pointer to the FILINFO structure */
 );
 
@@ -25,9 +25,9 @@ FRESULT f_stat (

Parameters

FileName
-
Pointer to the null-terminated string that specifies the file or directory name to get the information. Do not specify root directory.
+
Pointer to the null-terminated string that specifies the file or directory to get its information. Do not specify root directory.
FileInfo
-
Pointer to the FILINFO structure to store the information.
+
Pointer to the blank FILINFO structure to store the information.
@@ -43,14 +43,14 @@ FRESULT f_stat (
Could not find the path.
FR_INVALID_NAME
The file name is invalid.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
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.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
diff --git a/doc/en/sync.html b/doc/en/sync.html index 8151e7d..0223e61 100644 --- a/doc/en/sync.html +++ b/doc/en/sync.html @@ -12,10 +12,10 @@

f_sync

-

The f_sync flushes the cached information of the wriiting file.

+

The f_sync function flushes the cached information of a wriiting file.

 FRESULT f_sync (
-  FIL* FileObject     // Pointer to the file object structure
+  FIL* FileObject     /* Pointer to the file object */
 );
 
@@ -24,7 +24,7 @@ FRESULT f_sync (

Parameters

FileObject
-
Pointer to the file object to be flushed.
+
Pointer to the open file object to be flushed.
@@ -35,18 +35,18 @@ FRESULT f_sync (
FR_OK (0)
The function succeeded.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has been occured.
-
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
Any error has occured in low level disk I/O.
+
FR_NOT_READY
+
The disk drive cannot work due to no medium in the drive or any other reason.
+
FR_INVALID_OBJECT
+
The file object is invalid.

Description

-

The function f_sync() performs the same process as f_close() but the file is left opened and can continue file read/write operations to the file. This is suitable for applications that open files for a long time in writing mode, such as data logger. Performing f_sync() of periodic or immediataly after f_write() can minimize risk of data loss due to sudden blackout or unintentional disk removal. This function is not supported in read-only configuration.

+

The f_sync function performs the same process as f_close function but the file is left opened and can continue read/write/seek operations to the file. This is suitable for applications that open files for a long time in writing mode, such as data logger. Performing f_sync of periodic or immediataly after f_write can minimize risk of data loss due to sudden blackout or unintentional disk removal. This function is not supported in read-only configuration.

diff --git a/doc/en/unlink.html b/doc/en/unlink.html index fa9a3f2..8225928 100644 --- a/doc/en/unlink.html +++ b/doc/en/unlink.html @@ -15,7 +15,7 @@

The f_unlink removes file or directory.

 FRESULT f_unlink (
-  const char* FileName  // Pointer to the file or directory name
+  const char* FileName  /* Pointer to the file or directory name */
 );
 
@@ -24,7 +24,7 @@ FRESULT f_unlink (

Parameters

FileName
-
Pointer to the null-terminated string that specifies the full path name of a file or directory to be removed. In read-only and minimum configuration, this function is not supported.
+
Pointer to the null-terminated string that specifies a file or directory to be removed.
@@ -40,6 +40,8 @@ FRESULT f_unlink (
Could not find the path.
FR_INVALID_NAME
The path name is invalid.
+
FR_INVALID_DRIVE
+
The drive number is invalid.
FR_DENIED
The function was denied due to either of following reasons: the file or directory has read-only attribute, the directory is not empty.
FR_NOT_READY
@@ -48,10 +50,8 @@ FRESULT f_unlink (
The medium is write protected.
FR_RW_ERROR
Any error occured in low level disk I/O.
-
FR_INCORRECT_DISK_CHANGE
-
Incorrect disk removal/change has occured.
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
The logical drive has no work area.
FR_NO_FILESYSTEM
There is no valid FAT partition on the disk.
@@ -60,7 +60,7 @@ FRESULT f_unlink (

Description

-

The f_unlink removes file or directory. This function is not supported in minimization level of >= 1.

+

The f_unlink function removes a file or directory. In read-only configuration or minimization level is >= 1, this function is not supported.

diff --git a/doc/en/write.html b/doc/en/write.html index a213b9a..4927d2f 100644 --- a/doc/en/write.html +++ b/doc/en/write.html @@ -15,10 +15,10 @@

The f_write writes data to a file.

 FRESULT f_write (
-  FIL* FileObject,     // Pointer to the file object structure
-  const void* Buffer,  // Pointer to the data to be written
-  WORD ByteToWrite,    // Number of bytes to write
-  WORD* ByteWritten    // Pointer to the variable to return number of bytes written
+  FIL* FileObject,     /* Pointer to the file object structure */
+  const void* Buffer,  /* Pointer to the data to be written */
+  WORD ByteToWrite,    /* Number of bytes to write */
+  WORD* ByteWritten    /* Pointer to the variable to return number of bytes written */
 );
 
@@ -27,7 +27,7 @@ FRESULT f_write (

Parameter

FileObject
-
Pointer to the valid file object structure.
+
Pointer to the open file object structure.
Buffer
Pointer to the data to be written.
ByteToWrite
@@ -46,18 +46,18 @@ FRESULT f_write (
FR_DENIED
The function denied due to the file has been opened in read only mode.
FR_RW_ERROR
-
Any error occured in low level disk I/O.
+
Any error has occured in low level disk I/O layer.
FR_NOT_READY
The disk drive cannot work due to no medium in the drive or any other reason.
-
FR_NOT_ENABLED
-
FatFs module is not enabled.
+
FR_INVALID_OBJECT
+
The file object is invalid.

Description

-

The read/write pointer increases in number of bytes written. The ByteWritten will be less than ByteToWrite when disk gets full during write function. This function is not supported in read-only configuration.

+

The read/write pointer in the file object is increased in number of bytes written. The ByteWritten will become less than ByteToWrite when disk gets full during write function. This function is not supported in read-only configuration.

diff --git a/doc/img/f1.png b/doc/img/f1.png new file mode 100644 index 0000000..9723ea0 Binary files /dev/null and b/doc/img/f1.png differ diff --git a/doc/img/f2.png b/doc/img/f2.png new file mode 100644 index 0000000..f257263 Binary files /dev/null and b/doc/img/f2.png differ diff --git a/doc/img/f3.png b/doc/img/f3.png new file mode 100644 index 0000000..f07201a Binary files /dev/null and b/doc/img/f3.png differ diff --git a/doc/img/f4.png b/doc/img/f4.png new file mode 100644 index 0000000..520fffd Binary files /dev/null and b/doc/img/f4.png differ diff --git a/doc/img/f5.png b/doc/img/f5.png new file mode 100644 index 0000000..6fb3bc8 Binary files /dev/null and b/doc/img/f5.png differ diff --git a/doc/img/layers.png b/doc/img/layers.png new file mode 100644 index 0000000..69773ee Binary files /dev/null and b/doc/img/layers.png differ diff --git a/doc/rw_ata.jpeg b/doc/img/rw_ata.jpeg similarity index 100% rename from doc/rw_ata.jpeg rename to doc/img/rw_ata.jpeg diff --git a/doc/rw_cfc.jpeg b/doc/img/rw_cfc.jpeg similarity index 100% rename from doc/rw_cfc.jpeg rename to doc/img/rw_cfc.jpeg diff --git a/doc/rw_mmc.jpeg b/doc/img/rw_mmc.jpeg similarity index 100% rename from doc/rw_mmc.jpeg rename to doc/img/rw_mmc.jpeg diff --git a/doc/rwtest.png b/doc/img/rwtest.png similarity index 100% rename from doc/rwtest.png rename to doc/img/rwtest.png diff --git a/doc/ja/appnote.html b/doc/ja/appnote.html new file mode 100644 index 0000000..ce38a02 --- /dev/null +++ b/doc/ja/appnote.html @@ -0,0 +1,108 @@ + + + + + + + +FatFsモジュール アプリケーション・ノート + + + +

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

+
+ +
+

移植の際に配慮すべきこと

+

FatFsモジュールは移植性に関して次の点を前提としています。

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

FatFs vs. Tiny-FatFs

+

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

+

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

+
+
+ + + + +
メモリ容量FATタイプ
<= 64MBFAT12
128MB〜2GBFAT16
>= 4GBFAT32
+ +

右の表にメモリ・カードの容量と規定のFATタイプ(SDメモリの場合)を示します。出荷時はこれらのFATタイプでフォーマットされていて、最大のパフォーマンスが出るようにデータ領域の境界が調整されています。したがって、PCでフォーマットするなどして規定と違うフォーマットになると書き込み性能が大幅に低下する場合があるので注意が必要です。

+ + +
+

効率の良いファイル・アクセスの方法

+

資源の限られた組み込みシステムで効率よくアクセスするためには、ファイル・アクセスの仕組みをある程度意識した使用が求められます。FatFsモジュールでは、ディスク上のファイル・データは f_read()内で次のような手順で読み出されます。

+
図1. セクタ・ミスアライメント・リード
+fig.1 +
+
+
図2. セクタ・ミスアライメント・リード
+fig.2 +
+
+
図3. セクタ・アライメント・リード
+fig.3 +
+
+

ここでファイル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と同じ性能と省メモリ特性が同時に得られます。

+
+ +
+

クリチカル・セクション

+

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

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

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

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

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

+
+ + +
+

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

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

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

+
+ +

戻る

+ + diff --git a/doc/ja/chmod.html b/doc/ja/chmod.html index d9554cb..4705c9a 100644 --- a/doc/ja/chmod.html +++ b/doc/ja/chmod.html @@ -15,23 +15,23 @@

ファイルまたはディレクトリの属性を変更します。

 FRESULT f_chmod (
-  const char* FileName, // ファイルまたはディレクトリの文字列へのポインタ
-  BYTE Attribute,       // 設定値
-  BYTE AttributeMask    // 変更マスク
+  const char* FileName, /* ファイルまたはディレクトリ名へのポインタ */
+  BYTE Attribute,       /* 設定値 */
+  BYTE AttributeMask    /* 変更マスク */
 );
 
-

パラメータ

+

引数

FileName
-
属性変更対象のファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列を指定します。
+
属性変更対象のファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列を指定します。
Attribute
設定する属性。指定可能な属性は次の通りで、これらの組み合わせで指定します。指定されなかった属性は解除されます。
- + @@ -54,16 +54,16 @@ FRESULT f_chmod (
パスが見つからない。
FR_INVALID_NAME
パス名が不正。
+
FR_INVALID_NAME
+
ドライブ番号が不正。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_WRITE_PROTECTED
メディアが書き込み禁止状態。
FR_RW_ERROR
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
その論理ドライブにワーク・エリアが与えられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -72,7 +72,7 @@ FRESULT f_chmod (

解説

-

ファイルまたはディレクトリの属性を変更します。リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

+

ファイルまたはディレクトリの属性を変更します。リード・オンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

diff --git a/doc/ja/close.html b/doc/ja/close.html index f27877e..295e87f 100644 --- a/doc/ja/close.html +++ b/doc/ja/close.html @@ -15,16 +15,16 @@

ファイルを閉じます。

 FRESULT f_close (
-  FIL* FileObject     // ファイルオブジェクト構造体へのポインタ
+  FIL* FileObject     /* ファイル・オブジェクトへのポインタ */
 );
 
-

パラメータ

+

引数

FileObject
-
閉じようとするファイルのファイルオブジェクト構造体へのポインタを指定します。
+
閉じようとするファイルのファイル・オブジェクト構造体へのポインタを指定します。
@@ -35,18 +35,18 @@ FRESULT f_close (
FR_OK (0)
正常終了。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
-
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
ディスク・アクセスでエラーが発生した。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
+
FR_INVALID_OBJECT
+
無効なファイル・オブジェクト。

解説

-

ファイルを閉じます。書き込みの行われたファイルの場合、キャッシュされた状態(R/Wバッファ上のデータ、変更されたFATやディレクトリ項目)はディスクに書き戻されます。関数が正常終了すると、そのファイルオブジェクト構造体は無効になり、そのメモリも解放できます。

+

ファイルを閉じます。書き込みの行われたファイルの場合、キャッシュされた状態(R/Wバッファ上のデータ、変更されたFATやディレクトリ項目)はディスクに書き戻されます。関数が正常終了すると、そのファイル・オブジェクトは無効になり、そのメモリも解放できます。

diff --git a/doc/ja/dinit.html b/doc/ja/dinit.html index 6bf5abc..7e83176 100644 --- a/doc/ja/dinit.html +++ b/doc/ja/dinit.html @@ -12,20 +12,31 @@

disk_initialize

-

ディスクドライブを初期化します。

+

ディスク・ドライブを初期化します。

-DSTATUS disk_initialize ();
+DSTATUS disk_initialize (
+  BYTE Drive      /* 物理ドライブ番号 */
+);
 
+
+

引数

+
+
Drive
+
初期化する物理ドライブ番号(0-9)を指定します。
+
+
+ +

戻り値

-

この関数は戻り値としてディスクステータスを返します。ディスクステータスの詳細に関してはdisk_status()を参照してください。

+

この関数は戻り値としてディスク・ステータスを返します。ディスク・ステータスの詳細に関してはdisk_status()を参照してください。

解説

-

ディスクドライブを初期化します。関数が成功すると、戻り値のSTA_NOINITフラグがクリアされます。

+

ディスク・ドライブを初期化します。関数が成功すると、戻り値のSTA_NOINITフラグがクリアされます。

戻る

diff --git a/doc/ja/dread.html b/doc/ja/dread.html index 07cb187..a8785d8 100644 --- a/doc/ja/dread.html +++ b/doc/ja/dread.html @@ -15,18 +15,21 @@

ディスクからセクタを読み出します。

 DRESULT disk_read (
-  BYTE* Buffer,        // 読み出しバッファへのポインタ
-  DWORD SectorNumber,  // 読み出し開始セクタ番号
-  BYTE SectorCount     // 読み出しセクタ数
+  BYTE Drive,          /* 物理ドライブ番号 */
+  BYTE* Buffer,        /* 読み出しバッファへのポインタ */
+  DWORD SectorNumber,  /* 読み出し開始セクタ番号 */
+  BYTE SectorCount     /* 読み出しセクタ数 */
 );
 
-

パラメータ

+

引数

+
Drive
+
物理ドライブ番号(0-9)を指定します。
Buffer
-
ディスクから読み出したセクタデータを格納するバッファ。SectorCount * 512バイトのサイズが必要です。
+
ディスクから読み出したデータを格納するバッファ。SectorCount * 512バイトのサイズが必要です。
SectorNumber
読み出しを開始するセクタ番号。LBAで指定します。
SectorCount
diff --git a/doc/ja/dstat.html b/doc/ja/dstat.html index f8c9cf1..344aec1 100644 --- a/doc/ja/dstat.html +++ b/doc/ja/dstat.html @@ -12,22 +12,33 @@

disk_status

-

ディスクの状態を取得します。

+

ディスク・ドライブの状態を取得します。

-DSTATUS disk_status ();
+DSTATUS disk_status (
+  BYTE Drive           /* 物理ドライブ番号 */
+);
 
+
+

引数

+
+
Drive
+
ステータスを取得する物理ドライブ番号を指定します。
+
+
+ +

戻り値

-

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

+

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

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

disk_write

-

ディスクにセクタデータを書き込みます。

+

ディスクにデータを書き込みます。

 DRESULT disk_write (
-  const BYTE* Buffer,  // 書き込むデータへのポインタ
-  DWORD SectorNumber,  // 書き込み開始セクタ番号
-  BYTE SectorCount     // 書き込みセクタ数
+  BYTE Drive,          /* 物理ドライブ番号 */
+  const BYTE* Buffer,  /* 書き込むデータへのポインタ */
+  DWORD SectorNumber,  /* 書き込み開始セクタ番号 */
+  BYTE SectorCount     /* 書き込みセクタ数 */
 );
 
-

パラメータ

+

引数

+
Drive
+
書き込むドライブ番号を指定します。
Buffer
-
ディスクに書き込むセクタデータを指定します。
+
ディスクに書き込むデータを指定します。
SectorNumber
書き込みを開始するセクタ番号。LBAで指定します。
SectorCount
@@ -54,7 +57,7 @@ DRESULT disk_write (

解説

-

リードオンリー構成ではこの関数は必要とされません。

+

リード・オンリー構成ではこの関数は必要とされません。

diff --git a/doc/ja/fattime.html b/doc/ja/fattime.html index 14da2fb..1dce3d5 100644 --- a/doc/ja/fattime.html +++ b/doc/ja/fattime.html @@ -14,14 +14,14 @@

get_fattime

現在時刻を取得します。

-DWORD get_fattime ();
+DWORD get_fattime (void);
 

戻り値

-

現在のローカルタイムがDWORD値にパックされて返されます。ビットフィールドは次に示すようになります。

+

現在のローカル・タイムがDWORD値にパックされて返されます。ビット・フィールドは次に示すようになります。

bit31:25
1980年を起点とした年が 0..127 で入ります。
@@ -41,7 +41,7 @@ DWORD get_fattime ();

解説

-

RTCをサポートしないシステムでも、何らかの有効な値を返さなければなりません。リードオンリー構成ではこの関数は必要とされません。

+

RTCをサポートしないシステムでも、何らかの日付として有効な値を返さなければなりません。リード・オンリー構成ではこの関数は必要とされません。

diff --git a/doc/ja/filename.html b/doc/ja/filename.html new file mode 100644 index 0000000..d92d391 --- /dev/null +++ b/doc/ja/filename.html @@ -0,0 +1,36 @@ + + + + + + + +FatFs - ファイル・ディレクトリの指定方法 + + + +

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

+ +
+

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

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

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

+

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

+

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

+
+ + + diff --git a/doc/ja/getfree.html b/doc/ja/getfree.html index f7a99f4..ff3fa2a 100644 --- a/doc/ja/getfree.html +++ b/doc/ja/getfree.html @@ -12,19 +12,25 @@

f_getfree

-

ディスクの未使用領域を得ます。

+

ディスクの未使用クラスタ数を得ます。

 FRESULT f_getfree (
-  DWORD* Clusters     // 空きクラスタ数を格納する変数へのポインタ
+  const char* Path,        /* 対象ドライブのルート・ディレクトリ */
+  DWORD* Clusters,         /* 空きクラスタ数を格納する変数へのポインタ */
+  FATFS** FileSystemObject /* ファイル・システム・オブジェクトを指すポインタへのポインタ */
 );
 
-

パラメータ

+

引数

+
Path
+
情報を得る論理ドライブのルートディレクトリのパス名が入った'\0'で終わる文字列へのポインタを指定します。
Clusters
空きクラスタ数を格納するDWORD変数へのポインタを指定します。
+
FileSystemObject
+
対象ドライブのファイル・システム・オブジェクトを指すポインタを格納するポインタへのポインタを指定します。
@@ -34,14 +40,14 @@ FRESULT f_getfree (
FR_OK (0)
正常終了。*Clustersに空きクラスタ数が返されます。
+
FR_INVALID_DRIVE
+
ドライブ番号が不正。
FR_NOT_READY
メディアがセットされていないなど、ディスクドライブが動作不能状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
その論理ドライブにワーク・エリアが与えられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -50,21 +56,26 @@ FRESULT f_getfree (

解説

-

ファイルシステム上の空きクラスタ数を取得します。FatFs.sects_clust がクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

+

論理ドライブ上の空きクラスタ数を取得します。返されたファイル・システム・オブジェクトのsects_clustメンバがクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

使用例

+    FATFS *fs;
     DWORD clust;
 
+
     // Get free clusters
-    res = f_getfree(&clust);
+    res = f_getfree("", &clust, &fs);
     if (res) die(res);
 
-    // Get free bytes
-    printf("%lu bytes available on the disk.\n", clust * FatFs->sects_clust * 512);
+    // 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,
+           clust * fs->sects_clust / 2);
 
diff --git a/doc/ja/lseek.html b/doc/ja/lseek.html index 6617633..8a5866e 100644 --- a/doc/ja/lseek.html +++ b/doc/ja/lseek.html @@ -15,17 +15,17 @@

ファイルのR/Wポインタを移動します。

 FRESULT f_lseek (
-  FIL* FileObject,   // ファイルオブジェクト構造体へのポインタ
-  DWORD Offset       // 移動先オフセット
+  FIL* FileObject,   /* ファイル・オブジェクト構造体へのポインタ */
+  DWORD Offset       /* 移動先オフセット */
 );
 
-

パラメータ

+

引数

FileObject
-
対象となるファイルオブジェクト構造体へのポインタを指定します。
+
対象となるファイル・オブジェクト構造体へのポインタを指定します。
Offset
移動先のオフセット(R/Wポインタ)値。ファイル先頭からのオフセットをバイト単位で指定します。
@@ -38,18 +38,18 @@ FRESULT f_lseek (
FR_OK (0)
正常終了。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
-
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
ディスク・アクセスでエラーが発生した。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
+
FR_INVALID_OBJECT
+
無効なファイルオブジェクト。

解説

-

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

+

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

@@ -66,7 +66,7 @@ FRESULT f_lseek ( res = f_lseek(&file, file.fptr - 2000); // ファイル追記の準備 - res = f_lseek(&file, 0xFFFFFFFF); + res = f_lseek(&file, file.fsize); diff --git a/doc/ja/mkdir.html b/doc/ja/mkdir.html index f45358c..4a065d0 100644 --- a/doc/ja/mkdir.html +++ b/doc/ja/mkdir.html @@ -15,16 +15,16 @@

ディレクトリを作成します。

 FRESULT f_mkdir (
-  const char* DirName // 作成するディレクトリ名へのポインタ
+  const char* DirName /* 作成するディレクトリ名へのポインタ */
 );
 
-

パラメータ

+

引数

DirName
-
作成するディレクトリのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。ディレクトリセパレータには'/'を使用します。FatFsモジュールにはカレントディレクトリの概念がないので、パスはルートディレクトリから辿る絶対パスとなります。文字列先頭のスペースはスキップされます。パス先頭の'/'はあってもなくてもかまいません。
+
作成するディレクトリのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。
@@ -38,18 +38,18 @@ FRESULT f_mkdir (
パスが見つからない。
FR_INVALID_NAME
パス名が不正。
+
FR_INVALID_DRIVE
+
ドライブ番号が不正。
FR_DENIED
-
同名のディレクトリやファイルの存在、ディスクやディレクトリエントリが満杯の場合など。
+
同名のディレクトリやファイルの存在、ディスクやディレクトリ・エントリが満杯の場合など。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_WRITE_PROTECTED
メディアが書き込み禁止状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
その論理ドライブにワーク・エリアが与えられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -58,7 +58,7 @@ FRESULT f_mkdir (

解説

-

空のディレクトリを作成します。リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

+

空のディレクトリを作成します。リード・オンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

diff --git a/doc/ja/mkfs.html b/doc/ja/mkfs.html new file mode 100644 index 0000000..35019cc --- /dev/null +++ b/doc/ja/mkfs.html @@ -0,0 +1,70 @@ + + + + + + + +FatFs - f_mkfs + + + + +
+

f_mkfs

+

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

+
+FRESULT f_mkfs (
+  BYTE  Drive,            /* Logical drive number */
+  BYTE  PartitioningRule, /* Partitioning rule */
+  BYTE  AllocSize         /* Allocation unit size */
+);
+
+
+ +
+

引数

+
+
Drive
+
フォーマットする論理ドライブ(0-9)。
+
PartitioningRule
+
0を指定すると、区画テーブルを作成したあとその区画にファイル・システムを作成します(FDISKフォーマット)。1を指定すると、先頭セクタから直接ファイル・システムを構築します(super floppy (SFD) フォーマット)。
+
AllocSize
+
アロケーション・ユニット・サイズ(クラスタ・サイズ)をセクタ単位で指定します。2の累乗でかつ1から64までの範囲でなければなりません。
+
+
+ +
+

戻り値

+
+
FR_OK (0)
+
正常終了。
+
FR_INVALID_DRIVE
+
ドライブ番号が無効。
+
FR_NOT_READY
+
メディアがセットされていないなど、物理ドライブが動作不能状態。
+
FR_WRITE_PROTECTED
+
メディアが書き込み禁止状態。
+
FR_RW_ERROR
+
ディスク・アクセスでエラーが発生した。
+
FR_MKFS_ABORTED
+
次の理由で処理が中断された。 +
    +
  • ディスク・サイズが小さすぎる。
  • +
  • 何らかの引数が無効。
  • +
  • そのクラスタ・サイズが使えない。クラスタ数が0xFF7と0xFFF7近辺になると発生する可能性がある。
  • +
+
+
+
+ +
+

説明

+

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

+

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

+

+ + +

Return

+ + diff --git a/doc/ja/mount.html b/doc/ja/mount.html new file mode 100644 index 0000000..7d82b83 --- /dev/null +++ b/doc/ja/mount.html @@ -0,0 +1,59 @@ + + + + + + + +FatFs - f_mount + + + + +
+

f_mount

+

論理ドライブのワーク・エリアを登録・抹消します。

+
+FRESULT f_mount (
+  BYTE  Drive,               /* 論理ドライブ番号 */
+  FATFS*  FileSystemObject   /* ワーク・エリアへのポインタ */
+);
+
+
+ +
+

引数

+
+
Drive
+
論理ドライブ番号(0-9)。Tiny-FatFsでは常に0。
+
FileSystemObject
+
登録するワーク・エリア(ファイル・システム・オブジェクト)へのポインタ。
+
+
+ +
+

戻り値

+
+
FR_OK (0)
+
正常終了。
+
FR_INVALID_DRIVE
+
ドライブ番号が無効。
+
+
+ + +
+

解説

+

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

+

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

+
+ + +
+

参照

+

FATFS

+
+ +

戻る

+ + diff --git a/doc/ja/open.html b/doc/ja/open.html index 734a01c..d3e9331 100644 --- a/doc/ja/open.html +++ b/doc/ja/open.html @@ -15,20 +15,20 @@

ファイルをオープンまたは作成します。

 FRESULT f_open (
-  FIL* FileObject,      // 空のファイルオブジェクト構造体へのポインタ
-  const char* FileName, // ファイルのフルパス名へのポインタ
-  BYTE ModeFlags        // モードフラグ
+  FIL* FileObject,      /* 空のファイル・オブジェクト構造体へのポインタ */
+  const char* FileName, /* ファイルのフルパス名へのポインタ */
+  BYTE ModeFlags        /* モードフラグ */
 );
 
-

パラメータ

+

引数

FileObject
-
新しく作成するファイルオブジェクト構造体へのポインタを指定します。以降、そのファイルを閉じるまでこのファイルオブジェクトを使用してファイル操作をします。
+
新しく作成するファイル・オブジェクト構造体へのポインタを指定します。以降、そのファイルを閉じるまでこのファイル・オブジェクトを使用してファイル操作をします。
FileName
-
作成する (またはオープンする) ファイルのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。ディレクトリセパレータには'/'を使用します。FatFsモジュールにはカレントディレクトリの概念がないので、パスはルートディレクトリから辿る絶対パスとなります。文字列先頭のスペースはスキップされます。パス先頭の'/'はあってもなくてもかまいません。
+
開く(または作成する)ファイルの ファイル名が入った'\0'で終わる文字列へのポインタを指定します。
ModeFlags
ファイルのアクセス方法やオープン方法を決めるフラグです。このパラメータには次の組み合わせを指定します。
意味
AM_RDOリードオンリー
AM_RDOリード・オンリー
AM_ARCアーカイブ
AM_SYSシステム
AM_HIDヒドゥン
@@ -48,25 +48,25 @@ FRESULT f_open (

戻り値

FR_OK (0)
-
正常終了。以降、FileObject構造体を使ってこのファイルを操作できます。ファイルを閉じるときは、f_close()を使用します。
+
正常終了。以降、FileObject構造体を使ってこのファイルを操作できます。
FR_NO_FILE
ファイルが見つからない。
FR_NO_PATH
パスが見つからない。
FR_INVALID_NAME
ファイル名が不正。
+
FR_INVALID_DRIVE
+
ドライブ番号が不正。
FR_DENIED
-
アクセスが拒否された。リードオンリーファイルの書き込みモードオープン、同名のディレクトリまたはリードオンリファイルがある状態でのファイル作成、ディスクまたはディレクトリテーブルが満杯でファイルを作成できないなど。
+
アクセスが拒否された。リード・オンリー・ファイルの書き込みモード・オープン、同名のディレクトリまたはリード・オンリー・ファイルがある状態でのファイル作成、ディスクまたはディレクトリ・テーブルが満杯でファイルを作成できないなど。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_WRITE_PROTECTED
-
メディアが書き込み禁止状態で書き込みオープンまたはファイル作成をした。
+
メディアが書き込み禁止状態で書き込み系オープンをした。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
その論理ドライブにワーク・エリアが割り当てられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -75,26 +75,25 @@ FRESULT f_open (

解説

-

FatFsモジュールの使用を開始するにはまず、FatFsモジュールのグローバル変数FatFsにゼロクリアしたワークエリア(FATFS構造体)のアドレスを代入します。このようにしてFatFsモジュールにワークエリアを割り当てるとモジュールは動作可能状態になり、ファイル関数が使えるようになります。ゼロクリアの代わりにf_mountdrv()でもOKですが、少なくともその時点で物理ドライブが動作可能になっていなければなりません。FatFsモジュールの使用を終了するには、全てのファイルを閉じたあとFatFsをクリアします。その後、ワークエリアは破棄できます。

+

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

+

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

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

-

使用例(ファイルコピー)

+

使用例(ファイル・コピー)

 void main ()
 {
-    FATFS fs;            // FatFsワークエリア
-    FIL fsrc, fdst;      // ファイルオブジェクト
+    FATFS fs;            // 論理ドライブのワーク・エリア(ファイル・システム・オブジェクト)
+    FIL fsrc, fdst;      // ファイル・オブジェクト
     BYTE buffer[4096];   // file copy buffer
     FRESULT res;         // FatFs function common result code
     WORD br, bw;         // File R/W count
 
-
-    // FatFsのワークエリアを確保する
-    FatFs = &fs;
-    memset(&fs, 0, sizeof(FATFS));      // ワークエリアの初期化。代わりに f_mountdrv() でもよい
+    // ドライブ0にワーク・エリアを与える
+    f_mount(0, &fs);
 
     // ソース・ファイルを開く
     res = f_open(&fsrc, "srcfile.dat", FA_OPEN_EXISTING | FA_READ);
@@ -116,8 +115,8 @@ void main ()
     f_close(&fsrc);
     f_close(&fdst);
 
-    // FatFsのワークエリアを開放する
-    FatFs = NULL;
+    // ワーク・エリアを開放する
+    f_mount(0, NULL);
 }
 
diff --git a/doc/ja/opendir.html b/doc/ja/opendir.html index c462d69..d060555 100644 --- a/doc/ja/opendir.html +++ b/doc/ja/opendir.html @@ -15,19 +15,19 @@

ディレクトリをオープンします。

 FRESULT f_opendir (
-  DIR* DirObject,      // ディレクトリブジェクト構造体へのポインタ
-  const char* DirName  // ディレクトリ名へのポインタ
+  DIR* DirObject,      /* ディレクトリ・ブジェクト構造体へのポインタ */
+  const char* DirName  /* ディレクトリ名へのポインタ */
 );
 
-

パラメータ

+

引数

DirObject
-
初期化するディレクトリオブジェクト構造体へのポインタを指定します。
+
初期化するディレクトリ・オブジェクト構造体へのポインタを指定します。
DirName
-
オープンするディレクトリのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。ディレクトリセパレータには'/'を使用します。FatFsモジュールにはカレントディレクトリの概念がないので、パスはルートディレクトリから辿る絶対パスとなります。先頭のスペースはスキップされます。パス先頭の'/'はあってもなくてもかまいませんが、最後のディレクトリ名の後ろに'/'を付けることはできません。ルートディレクトリを開くときは、""または"/"を指定します。
+
オープンするディレクトリのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。
@@ -43,14 +43,14 @@ FRESULT f_opendir (
パスが見つからない。
FR_INVALID_NAME
パス名が不正。
+
FR_INVALID_DRIVE
+
ドライブ番号が不正。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
論理ドライブにワーク・エリアが与えられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -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 0db8e3f..b89cbd0 100644 --- a/doc/ja/read.html +++ b/doc/ja/read.html @@ -15,7 +15,7 @@

ファイルからデータを読み出します。

 FRESULT f_read (
-  FIL* FileObject,    // ファイルオブジェクト構造体
+  FIL* FileObject,    // ファイル・オブジェクト構造体
   void* Buffer,       // 読み出したデータを格納するバッファ
   WORD ByteToRead,    // 読み出すバイト数
   WORD* ByteRead      // 読み出されたバイト数
@@ -24,10 +24,10 @@ FRESULT f_read (
 
 
 
-

パラメータ

+

引数

FileObject
-
ファイルオブジェクト構造体へのポインタを指定します。
+
ファイル・オブジェクト構造体へのポインタを指定します。
Buffer
読み出したデータを格納するバッファを指すポインタを指定します。
ByteToRead
@@ -46,11 +46,11 @@ FRESULT f_read (
FR_DENIED
書き込み専用モードで開いたファイルから読み込もうとした。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
-
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
+
FR_INVALID_OBJECT
+
無効なファイル・オブジェクト。
diff --git a/doc/ja/readdir.html b/doc/ja/readdir.html index 0022bab..7686b3d 100644 --- a/doc/ja/readdir.html +++ b/doc/ja/readdir.html @@ -15,17 +15,17 @@

ディレクトリ項目を読み出します

 FRESULT f_readdir (
-  DIR* DirObject,    // ディレクトリブジェクト構造体へのポインタ
-  FILINFO* FileInfo  // ファイル情報構造体へのポインタ
+  DIR* DirObject,    /* ディレクトリ・ブジェクト構造体へのポインタ */
+  FILINFO* FileInfo  /* ファイル情報構造体へのポインタ */
 );
 
-

パラメータ

+

引数

DirObject
-
初期化済みのディレクトリオブジェクト構造体へのポインタを指定します。
+
ディレクトリ・オブジェクト構造体へのポインタを指定します。
FileInfo
読み出したディレクトリ項目を格納するファイル情報構造体へのポインタを指定します。
@@ -38,18 +38,18 @@ FRESULT f_readdir (
FR_OK (0)
正常終了。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
ディスク・アクセスでエラーが発生した。
+
FR_INVALID_OBJECT
+
無効なディレクトリ・オブジェクト。

解説

-

ディレクトリ項目を順次読み出します。この関数を繰り返し実行することによりディレクトリの全ての項目を読み出すことができます。全ての項目を読み出し、読み出す項目がもう無いときは、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 eb883ce..4154bb5 100644 --- a/doc/ja/rename.html +++ b/doc/ja/rename.html @@ -15,19 +15,19 @@

ファイルまたはディレクトリの名前の変更または移動。

 FRESULT f_rename (
-  const char* OldName, // 古いファイルまたはディレクトリの文字列へのポインタ
-  const char* NewName  // 新しいファイルまたはディレクトリの文字列へのポインタ
+  const char* OldName, /* 古いファイルまたはディレクトリ名 */
+  const char* NewName  /* 新しいファイルまたはディレクトリ名 */
 );
 
-

パラメータ

+

引数

OldName
-
変更対象のファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。
+
変更対象のファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。
NewName
-
新しいファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。既に存在するものと同じ名前は使えません。
+
新しいファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列へのポインタを指定します。既に存在するものと同じ名前は使えません。また、ドライブ番号は指定できず、OldNameで指定されたドライブ上として扱われます。
@@ -43,18 +43,18 @@ FRESULT f_rename (
パスが見つからない。
FR_INVALID_NAME
パス名が不正。
+
FR_INVALID_DRIVE
+
ドライブ番号が不正。
FR_DENIED
新しい名前が作れない。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_WRITE_PROTECTED
メディアが書き込み禁止状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
論理ドライブにワークエリアが割り当てられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -63,8 +63,8 @@ FRESULT f_rename (

解説

-

ファイルまたはディレクトリの名前を変更します。別のディレクトリへの移動も可能です。リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

-

※現リビジョンでは、ディレクトリを別のディレクトリに移動するとファイルシステムが壊れます。

+

ファイルまたはディレクトリの名前を変更します。別のディレクトリへの移動(同じドライブ内のみ)も可能です。リード・オンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

+

※現リビジョンでは、ディレクトリを別のディレクトリに移動するとファイル・システムが壊れます。

diff --git a/doc/ja/sdir.html b/doc/ja/sdir.html index e2168dd..1dcb778 100644 --- a/doc/ja/sdir.html +++ b/doc/ja/sdir.html @@ -12,23 +12,27 @@

DIR

-

DIR構造体は、ディレクトリ情報読み出しのワークエリアとして使用されます。

+

DIR構造体は、f_opendir(), f_readdir()のワーク・エリアとして使用されます。

FatFs

 typedef struct _DIR {
-    DWORD   sclust;       // Directory start cluster
-    DWORD   clust;        // Current reading cluster
-    DWORD   sect;         // Current reading sector
-    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    sclust;       // Directory start cluster
-    WORD    clust;        // Current reading cluster
-    DWORD   sect;         // Current reading sector
-    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 487d8b9..ef5560d 100644 --- a/doc/ja/sfatfs.html +++ b/doc/ja/sfatfs.html @@ -12,17 +12,16 @@

FATFS

-

FATFS構造体は、FatFsモジュールのダイナミックワークエリアを保持し、アプリケーション側で確保・管理されます。アプリケーションから変更可能なメンバはありません。

+

FATFS構造体は、個々の論理ドライブのダイナミック・ワーク・エリアを保持し、f_mount()でFatFsモジュールに登録されます。アプリケーションから書き換え可能なメンバはありません。

FatFs

 typedef struct _FATFS {
-    BYTE    fs_type;        /* FAT type */
-    BYTE    files;          /* Number of files currently opend */
+    BYTE    fs_type;        /* FAT type (0:Not mouted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
-    WORD    n_rootdir;      /* Number of root directory entry */
-    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
-    BYTE    pad1;
+    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[] */
     DWORD   sects_fat;      /* Sectors per fat */
     DWORD   max_clust;      /* Maximum cluster# + 1 */
@@ -30,6 +29,7 @@ typedef struct _FATFS {
     DWORD   dirbase;        /* Root directory start sector (cluster# for FAT32) */
     DWORD   database;       /* Data start sector */
     DWORD   last_clust;     /* Last allocated cluster */
+    BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
     BYTE    win[512];       /* Disk access window for Directory/FAT */
 } FATFS;
 
@@ -37,20 +37,19 @@ typedef struct _FATFS {

Tiny-FatFs

 typedef struct _FATFS {
-    BYTE    fs_type;        /* FAT type */
-    BYTE    files;          /* Number of files currently opend */
+    BYTE    fs_type;        /* FAT type (0:Not mouted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
-    WORD    n_rootdir;      /* Number of root directory entry */
     BYTE    winflag;        /* win[] dirty flag (1:must be written back) */
-    BYTE    pad1;
+    WORD    id;             /* File system mount ID */
+    WORD    n_rootdir;      /* Number of root directory entries */
     DWORD   winsect;        /* Current sector appearing in the win[] */
-    WORD    sects_fat;      /* Sectors per fat */
-    WORD    max_clust;      /* Maximum cluster# + 1 */
     DWORD   fatbase;        /* FAT start sector */
     DWORD   dirbase;        /* Root directory start sector */
     DWORD   database;       /* Data start sector */
-    WORD    last_clust;     /* Last allocated cluster */
+    CLUST   sects_fat;      /* Sectors per fat */
+    CLUST   max_clust;      /* Maximum cluster# + 1 */
+    CLUST   last_clust;     /* Last allocated cluster */
     BYTE    win[512];       /* Disk access window for Directory/FAT/File */
 } FATFS;
 
diff --git a/doc/ja/sfile.html b/doc/ja/sfile.html index 478c18f..5c932b7 100644 --- a/doc/ja/sfile.html +++ b/doc/ja/sfile.html @@ -12,35 +12,39 @@

FIL

-

FIL構造体は、個々のファイルの状態を保持し、アプリケーション側で確保・管理されます。アプリケーションから変更可能なメンバはありません。

+

FIL構造体は、f_open()で作成され、そのファイルの状態を保持します。アプリケーションから書き換え可能なメンバはありません。

FatFs

 typedef struct _FIL {
-    DWORD   fptr;           // File R/W pointer
-    DWORD   fsize;          // File size
-    DWORD   org_clust;      // File start cluster
-    DWORD   curr_clust;     // Current cluster
-    DWORD   curr_sect;      // Current sector
-    DWORD   dir_sect;       // Sector# containing the directory entry
-    BYTE*   dir_ptr;        // Ponter to the directory entry in the window
-    BYTE    flag;           // File status flags
-    BYTE    sect_clust;     // Left sectors in current cluster
-    BYTE    buffer[512];    // File R/W buffer
+    FATFS*  fs;             /* Pointer to the owner file system object */
+    DWORD   fptr;           /* File R/W pointer */
+    DWORD   fsize;          /* File size */
+    DWORD   org_clust;      /* File start cluster */
+    DWORD   curr_clust;     /* Current cluster */
+    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;
 

Tiny-FatFs

 typedef struct _FIL {
-    DWORD   fptr;           // File R/W pointer
-    DWORD   fsize;          // File size
-    WORD    org_clust;      // File start cluster
-    WORD    curr_clust;     // Current cluster
-    DWORD   curr_sect;      // Current sector
-    DWORD   dir_sect;       // Sector# containing the directory entry
-    BYTE*   dir_ptr;        // Ponter to the directory entry in the window
-    BYTE    flag;           // File status flags
-    BYTE    sect_clust;     // Left sectors in current cluster
+    FATFS*  fs;             /* Pointer to owner file system */
+    DWORD   fptr;           /* File R/W pointer */
+    DWORD   fsize;          /* File size */
+    CLUST   org_clust;      /* File start cluster */
+    CLUST   curr_clust;     /* Current cluster */
+    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/sfileinfo.html b/doc/ja/sfileinfo.html index 91fd104..a510ed6 100644 --- a/doc/ja/sfileinfo.html +++ b/doc/ja/sfileinfo.html @@ -15,11 +15,11 @@

FILINFO構造体は、f_stat(), f_readdir()で返されるファイル情報を保持します。

 typedef struct _FILINFO {
-    DWORD fsize;            // Size
-    WORD fdate;             // Date
-    WORD ftime;             // Time
-    BYTE fattrib;           // Attribute
-    char fname[8+1+3+1];    // Name
+    DWORD fsize;            /* Size */
+    WORD fdate;             /* Date */
+    WORD ftime;             /* Time */
+    BYTE fattrib;           /* Attribute */
+    char fname[8+1+3+1];    /* Name */
 } FILINFO;
 
diff --git a/doc/ja/stat.html b/doc/ja/stat.html index 82e16f9..412f203 100644 --- a/doc/ja/stat.html +++ b/doc/ja/stat.html @@ -15,19 +15,19 @@

 FRESULT f_stat (
-  const char* FileName, // ファイルまたはディレクトリ名へのポインタ
-  FILINFO* FileInfo     // ファイル情報構造体へのポインタ
+  const char* FileName,  /* ファイルまたはディレクトリ名へのポインタ */
+  FILINFO* FileInfo      /* ファイル情報構造体へのポインタ *
 );
 
-

パラメータ

+

引数

FileName
情報を得るファイルまたはディレクトリ名の'\0'で終わる文字列を指すポインタを指定します。ルートディレクトリの指定は禁止です。
FileInfo
-
読み出し結果を格納するファイル情報構造体へのポインタを指定します。
+
読み出したファイル情報を格納するファイル情報構造体へのポインタを指定します。
@@ -43,14 +43,14 @@ FRESULT f_stat (
パスが見つからない。
FR_INVALID_NAME
パス名が不正。
+
FR_INVALID_NAME
+
ドライブ番号が不正。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
論理ドライブにワークエリアが割り当てられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
diff --git a/doc/ja/sync.html b/doc/ja/sync.html index f0209bf..f2645cb 100644 --- a/doc/ja/sync.html +++ b/doc/ja/sync.html @@ -15,16 +15,16 @@

書き込み中のファイルのキャッシュされた情報をフラッシュします。

 FRESULT f_sync (
-  FIL* FileObject     // ファイルオブジェクト構造体へのポインタ
+  FIL* FileObject     /* ファイル・オブジェクト構造体へのポインタ */
 );
 
-

パラメータ

+

引数

FileObject
-
syncするファイルオブジェクト構造体へのポインタを指定します。
+
syncするファイルのファイル・オブジェクト構造体へのポインタを指定します。
@@ -35,19 +35,19 @@ FRESULT f_sync (
FR_OK (0)
正常終了。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
-
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
ディスク・アクセスでエラーが発生した。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
+
FR_INVALID_OBJECT
+
ファイル・オブジェクトが無効。

解説

-

この関数はf_close()と同じ処理を実行しますが、ファイルは引き続き開かれたままになり、読み書きを続行できます。ロギングなど、書き込みモードで長時間ファイルが開かれているアプリケーションにおいて、定期的または区切りの良いところでsyncすることにより、不意の電源断やメディアの取り外しにより失われるデータを最小限にすることができます。

-

リードオンリー構成ではこの関数はサポートされません。

+

この関数はf_close()と同じ処理を実行しますが、ファイルは引き続き開かれたままになり、読み書きを続行できます。ロギングなど、書き込みモードで長時間ファイルが開かれているアプリケーションにおいて、定期的または区切りの良いところでsyncすることにより、不意の電源断やメディアの取り外しにより失われるデータを最小にすることができます。

+

リード・オンリー構成ではこの関数はサポートされません。

diff --git a/doc/ja/unlink.html b/doc/ja/unlink.html index 3148622..ab9b5e8 100644 --- a/doc/ja/unlink.html +++ b/doc/ja/unlink.html @@ -15,16 +15,16 @@

ファイルまたはディレクトリを削除します。

 FRESULT f_unlink (
-  const char* FileName  // ファイルまたはディレクトリ名へのポインタ
+  const char* FileName  /* ファイルまたはディレクトリ名へのポインタ */
 );
 
-

パラメータ

+

引数

FileName
-
削除対象のファイルまたはディレクトリ名の入った'\0'で終わる文字列へのポインタを指定します。リードオンリー構成および _FS_MINIMIZE >= 1 ではこの関数はサポートされません。
+
削除対象のファイルまたはディレクトリ名の入った'\0'で終わる文字列へのポインタを指定します。
@@ -40,18 +40,18 @@ FRESULT f_unlink (
パスが見つからない。
FR_INVALID_NAME
パス名が不正。
+
FR_INVALID_DRIVE
+
ドライブ番号が不正。
FR_DENIED
-
対象ファイル・ディレクトリがリードオンリー状態、対象ディレクトリが空でない場合など。
+
対象ファイル・ディレクトリがリード・オンリー状態、対象ディレクトリが空でない場合など。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
メディアがセットされていないなど、物理ドライブが動作不能状態。
FR_WRITE_PROTECTED
メディアが書き込み禁止状態。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
-
FR_INCORRECT_DISK_CHANGE
-
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
論理ドライブにワーク・エリアが割り当てられていない。
FR_NO_FILESYSTEM
ディスク上に有効なFATパーテーションが見つからない。
@@ -60,7 +60,7 @@ FRESULT f_unlink (

解説

-

ファイルまたはディレクトリを削除します。_FS_MINIMIZE >= 1ではこの関数はサポートされません。

+

ファイルまたはディレクトリを削除します。リード・オンリー構成や_FS_MINIMIZE >= 1ではこの関数はサポートされません。

戻る

diff --git a/doc/ja/write.html b/doc/ja/write.html index 45068a3..d21a3d7 100644 --- a/doc/ja/write.html +++ b/doc/ja/write.html @@ -15,19 +15,19 @@

ファイルにデータを書き込みます。

 FRESULT f_write (
-  FIL* FileObject,     // ファイルオブジェクト構造体
-  const void* Buffer,  // 書き込みデータ
-  WORD ByteToWrite,    // 書き込むバイト数
-  WORD* ByteWritten    // 書き込まれたバイト数
+  FIL* FileObject,     /* ファイル・オブジェクト */
+  const void* Buffer,  /* 書き込みデータ */
+  WORD ByteToWrite,    /* 書き込むバイト数 */
+  WORD* ByteWritten    /* 書き込まれたバイト数 */
 );
 
-

パラメータ

+

引数

FileObject
-
ファイルオブジェクト構造体へのポインタを指定します。
+
ファイル・オブジェクト構造体へのポインタを指定します。
Buffer
書き込むデータを格納したバッファを指すポインタを指定します。
ByteToWrite
@@ -46,18 +46,18 @@ FRESULT f_write (
FR_DENIED
読み込み専用モードで開いたファイルに書き込もうとした。
FR_RW_ERROR
-
ディスクアクセスでエラーが発生した。
+
ディスク・アクセスでエラーが発生した。
FR_NOT_READY
-
メディアがセットされていないなど、ディスクドライブが動作不能状態。
-
FR_NOT_ENABLED
-
FatFsモジュールが停止状態。
+
メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
+
FR_INVALID_OBJECT
+
無効なファイルオブジェクト。

解説

-

書き込み開始位置は、ファイルR/Wポインタの現在位置からになります。ファイルR/Wポインタは実際に書き込まれたバイト数だけ進みます。書き込み中にディスクが一杯になったときは、*ByteWrittenByteToWriteよりも小さくなります。リードオンリー構成ではこの関数はサポートされません。

+

書き込み開始位置は、ファイルR/Wポインタの現在位置からになります。ファイルR/Wポインタは実際に書き込まれたバイト数だけ進みます。書き込み中にディスクが一杯になったときは、*ByteWrittenByteToWriteよりも小さくなります。リード・オンリー構成ではこの関数はサポートされません。

diff --git a/doc/layers.png b/doc/layers.png deleted file mode 100644 index 739fadf..0000000 Binary files a/doc/layers.png and /dev/null differ diff --git a/src/00readme.txt b/src/00readme.txt index ecd2b65..762b4e4 100644 --- a/src/00readme.txt +++ b/src/00readme.txt @@ -1,4 +1,4 @@ -FatFs/Tiny-FatFs Module Source Files R0.03a (C)ChaN, 2006 +FatFs/Tiny-FatFs Module Source Files R0.04 (C)ChaN, 2007 FILES @@ -23,45 +23,64 @@ CONFIGURATION OPTIONS requirement. The configuration options are defined in header files, ff.h and tff.h. - _BYTE_ACC + _MCU_ENDIAN This is the most impotant option that depends on the processor architecture. - When your microcontroller corresponds to either or both of following terms, - the _BYTE_ACC must be defined to force FatFs to access FAT structure in - byte-by-byte. If not, this can be undefined to improve code size. This is - UNDEFINED in default. + When 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). - Muti-byte integers (short, long) are stored in Big-Endian. - - Address miss-aligned memory access causes an address error or any - incorrect behavior. + - Address miss-aligned memory access results in an incorrect behavior. _FS_READONLY When application program does not require any write function, _FS_READONLY - can be defined to eliminate writing code to reduce module size. This is - UNDEFINED in default. This setting should be reflected to configurations for - low level disk function if available. + can be set to 1 to eliminate writing code to reduce 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). _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 - default value is 0 (full function). + can be defined to eliminate some functions to reduce the module size. The + initial value is 0 (full function). + + + _DRIVES + + Number of drives to be used. This option is not supported on Tiny-FatFs. + The initial value is 2. + + _FAT32 + + 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). _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 - DEFINED in default. + initially defined. + + + _USE_MKFS + + When _USE_MKFS is defined 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). Following table shows which function is removed by configuratin options. - _FS_MINIMIZE _FS_MINIMIZE _FS_READONLY - (1) (2) + _FS_MINIMIZE _FS_MINIMIZE _FS_READONLY _USE_MKFS + (1) (2) (1) (undef) + f_mount f_open f_close f_read @@ -76,7 +95,7 @@ CONFIGURATION OPTIONS f_mkdir x x x f_chmod x x x f_rename x x x - f_mountdrv + f_mkfs x x @@ -92,11 +111,20 @@ AGREEMENTS REVISION HISTORY Feb 26, 2006 R0.00 Prototype + Apr 29, 2006 R0.01 First stable version + 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. + Sep 22, 2006 R0.03 Added f_rename(). Changed option _FS_MINIMUM to _FS_MINIMIZE. + 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. + Changed some APIs for multiple drive system. + Added f_mkfs(). diff --git a/src/diskio.h b/src/diskio.h index 583fd48..d8c0153 100644 --- a/src/diskio.h +++ b/src/diskio.h @@ -1,10 +1,10 @@ /*----------------------------------------------------------------------- -/ Low level disk interface modlue include file R0.02 (C)ChaN, 2006 +/ Low level disk interface modlue include file R0.04 (C)ChaN, 2007 /-----------------------------------------------------------------------*/ -#ifndef _DISKIF +#ifndef _DISKIO -//#define _READONLY /* Define this for read-only use */ +#define _READONLY 0 /* 1: Read-only mode */ #include "integer.h" @@ -15,15 +15,14 @@ typedef unsigned char DRESULT; /*---------------------------------------*/ /* Prototypes for disk control functions */ -DSTATUS disk_initialize (); -DSTATUS disk_shutdown (); -DSTATUS disk_status (); -DRESULT disk_read (BYTE*, DWORD, BYTE); -#ifndef _READONLY -DRESULT disk_write (const BYTE*, DWORD, BYTE); +DSTATUS disk_initialize (BYTE); +DSTATUS disk_status (BYTE); +DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); +#if _READONLY == 0 +DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); #endif -DRESULT disk_ioctl (BYTE, void*); -void disk_timerproc (); +DRESULT disk_ioctl (BYTE, BYTE, void*); +void disk_timerproc (void); /* Results of Disk Functions (DRESULT) */ @@ -45,7 +44,9 @@ void disk_timerproc (); /* Command code for disk_ioctrl() */ #define GET_SECTORS 1 -#define PUT_IDLE_STATE 2 +#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 @@ -54,5 +55,5 @@ void disk_timerproc (); #define ATA_GET_SN 22 -#define _DISKIF +#define _DISKIO #endif diff --git a/src/ff.c b/src/ff.c index eb276be..c73025d 100644 --- a/src/ff.c +++ b/src/ff.c @@ -1,11 +1,11 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.03a (C)ChaN, 2006 +/ FatFs - FAT file system module R0.04 (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, / research and development under license policy of following trems. / -/ Copyright (C) 2006, ChaN, all right reserved. +/ Copyright (C) 2007, ChaN, all right reserved. / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or @@ -22,49 +22,64 @@ / Changed option _FS_MINIMUM to _FS_MINIMIZE. / 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. +/ Changed some interfaces for multiple drive system. +/ Added f_mkfs(). /---------------------------------------------------------------------------*/ #include #include "ff.h" /* FatFs declarations */ #include "diskio.h" /* Include file for user provided disk functions */ - -FATFS *FatFs; /* Pointer to the file system object */ +#define ld2pd(drv) (drv) /* Logical drive# to Physical drive# conversion */ -/*------------------------------------------------------------------------- - Module Private Functions --------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------- -/*----------------------*/ -/* Change Window Offset */ + Module Private Functions + +---------------------------------------------------------------------------*/ static -BOOL move_window ( - DWORD sector /* Sector number to make apperance in the FatFs->win */ +FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */ +static +WORD fsid; /* File system mount ID */ + + + +/*-----------------------------------------------------------------------*/ +/* Change Window Offset */ +/*-----------------------------------------------------------------------*/ + +static +BOOL move_window ( /* TRUE: successful, FALSE: failed */ + FATFS *fs, /* File system object */ + DWORD sector /* Sector number to make apperance in the fs->win[] */ ) /* Move to zero only writes back dirty window */ { DWORD wsect; - FATFS *fs = FatFs; wsect = fs->winsect; if (wsect != sector) { /* Changed current window */ -#ifndef _FS_READONLY +#if _FS_READONLY == 0 BYTE n; if (fs->winflag) { /* Write back dirty window if needed */ - if (disk_write(fs->win, wsect, 1) != RES_OK) return FALSE; + if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK) + return FALSE; fs->winflag = 0; if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */ - for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to all FAT copies */ + for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to FAT copy */ wsect += fs->sects_fat; - if (disk_write(fs->win, wsect, 1) != RES_OK) break; + if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK) + break; } } } #endif if (sector) { - if (disk_read(fs->win, sector, 1) != RES_OK) return FALSE; + if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK) + return FALSE; fs->winsect = sector; } } @@ -73,37 +88,39 @@ BOOL move_window ( -/*----------------------*/ -/* Get a Cluster Status */ + +/*-----------------------------------------------------------------------*/ +/* Get a Cluster Status */ +/*-----------------------------------------------------------------------*/ static -DWORD get_cluster ( +DWORD get_cluster ( /* 0,2..: successful, 1: failed */ + FATFS *fs, /* File system object */ DWORD clust /* Cluster# to get the link information */ ) { WORD wc, bc; DWORD fatsect; - FATFS *fs = FatFs; - if ((clust >= 2) && (clust < fs->max_clust)) { /* Valid cluster# */ + if (clust >= 2 && clust < fs->max_clust) { /* Valid cluster# */ fatsect = fs->fatbase; switch (fs->fs_type) { case FS_FAT12 : bc = (WORD)clust * 3 / 2; - if (!move_window(fatsect + bc / 512)) break; + if (!move_window(fs, fatsect + bc / 512)) break; wc = fs->win[bc % 512]; bc++; - if (!move_window(fatsect + bc / 512)) break; + if (!move_window(fs, fatsect + bc / 512)) break; wc |= (WORD)fs->win[bc % 512] << 8; return (clust & 1) ? (wc >> 4) : (wc & 0xFFF); case FS_FAT16 : - if (!move_window(fatsect + clust / 256)) break; - return LD_WORD(&(fs->win[((WORD)clust * 2) % 512])); + if (!move_window(fs, fatsect + clust / 256)) break; + return LD_WORD(&fs->win[((WORD)clust * 2) % 512]); case FS_FAT32 : - if (!move_window(fatsect + clust / 128)) break; - return LD_DWORD(&(fs->win[((WORD)clust * 4) % 512])) & 0x0FFFFFFF; + if (!move_window(fs, fatsect + clust / 128)) break; + return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF; } } return 1; /* There is no cluster information, or an error occured */ @@ -111,12 +128,15 @@ DWORD get_cluster ( -/*--------------------------*/ -/* Change a Cluster Status */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Change a Cluster Status */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static -BOOL put_cluster ( +BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ + FATFS *fs, /* File system object */ DWORD clust, /* Cluster# to change */ DWORD val /* New value to mark the cluster */ ) @@ -124,31 +144,30 @@ BOOL put_cluster ( WORD bc; BYTE *p; DWORD fatsect; - FATFS *fs = FatFs; fatsect = fs->fatbase; switch (fs->fs_type) { case FS_FAT12 : bc = (WORD)clust * 3 / 2; - if (!move_window(fatsect + bc / 512)) return FALSE; + if (!move_window(fs, fatsect + bc / 512)) return FALSE; p = &fs->win[bc % 512]; *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; bc++; fs->winflag = 1; - if (!move_window(fatsect + bc / 512)) return FALSE; + if (!move_window(fs, fatsect + bc / 512)) return FALSE; p = &fs->win[bc % 512]; *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); break; case FS_FAT16 : - if (!move_window(fatsect + clust / 256)) return FALSE; - ST_WORD(&(fs->win[((WORD)clust * 2) % 512]), (WORD)val); + if (!move_window(fs, fatsect + clust / 256)) return FALSE; + ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val); break; case FS_FAT32 : - if (!move_window(fatsect + clust / 128)) return FALSE; - ST_DWORD(&(fs->win[((WORD)clust * 4) % 512]), val); + if (!move_window(fs, fatsect + clust / 128)) return FALSE; + ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val); break; default : @@ -161,12 +180,15 @@ BOOL put_cluster ( -/*------------------------*/ -/* Remove a Cluster Chain */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Remove a Cluster Chain */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static -BOOL remove_chain ( +BOOL remove_chain ( /* TRUE: successful, FALSE: failed */ + FATFS *fs, /* File system object */ DWORD clust /* Cluster# to remove chain from */ ) { @@ -174,8 +196,8 @@ BOOL remove_chain ( if (clust) { - while ((nxt = get_cluster(clust)) >= 2) { - if (!put_cluster(clust, 0)) return FALSE; + while ((nxt = get_cluster(fs, clust)) >= 2) { + if (!put_cluster(fs, clust, 0)) return FALSE; clust = nxt; } } @@ -185,17 +207,19 @@ BOOL remove_chain ( -/*-----------------------------------*/ -/* Stretch or Create a Cluster Chain */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Stretch or Create a Cluster Chain */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static -DWORD create_chain ( - DWORD clust /* Cluster# to stretch, 0 means create new */ +DWORD create_chain ( /* !=0: new cluster number, 0: failed */ + FATFS *fs, /* File system object */ + DWORD clust /* Cluster# to stretch, 0 means create new */ ) { DWORD cstat, ncl, scl, mcl; - FATFS *fs = FatFs; mcl = fs->max_clust; @@ -204,25 +228,25 @@ DWORD create_chain ( if (scl < 2 || scl >= mcl) scl = 1; } else { /* Stretch existing chain */ - cstat = get_cluster(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 0; /* It is an invalid cluster */ + if (cstat < mcl) return cstat; /* It is already followed by next cluster */ scl = clust; } - ncl = scl; /* Scan start cluster */ + ncl = scl; /* Start cluster */ do { - ncl++; /* Next cluster */ - if (ncl >= mcl) { /* Wrap around */ + ncl++; /* Next cluster */ + if (ncl >= mcl) { /* Wrap around */ ncl = 2; - if (scl == 1) return 0; /* No free custer was found */ + 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 (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 (!put_cluster(ncl, 0x0FFFFFFF)) return 0; /* Mark the new cluster "in use" */ - if (clust && !put_cluster(clust, ncl)) return 0; /* Link it to previous one if needed */ + 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 */ fs->last_clust = ncl; return ncl; /* Return new cluster number */ @@ -231,17 +255,17 @@ DWORD create_chain ( -/*----------------------------*/ -/* Get Sector# from Cluster# */ + +/*-----------------------------------------------------------------------*/ +/* Get Sector# from Cluster# */ +/*-----------------------------------------------------------------------*/ static -DWORD clust2sect ( +DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ + FATFS *fs, /* File system object */ DWORD clust /* Cluster# to be converted */ ) { - FATFS *fs = FatFs; - - clust -= 2; if (clust >= fs->max_clust) return 0; /* Invalid cluster# */ return clust * fs->sects_clust + fs->database; @@ -249,75 +273,50 @@ DWORD clust2sect ( -/*------------------------*/ -/* Check File System Type */ + +/*-----------------------------------------------------------------------*/ +/* Move Directory Pointer to Next */ +/*-----------------------------------------------------------------------*/ static -BYTE check_fs ( - DWORD sect /* Sector# to check if it is a FAT boot record or not */ -) -{ - static const char fatsign[] = "FAT12FAT16FAT32"; - FATFS *fs = FatFs; - - /* Determines FAT type by signature string but this is not correct. - For further information, refer to fatgen103.doc from Microsoft. */ - memset(fs->win, 0, 512); - if (disk_read(fs->win, sect, 1) == RES_OK) { /* Load boot record */ - if (LD_WORD(&(fs->win[510])) == 0xAA55) { /* Is it valid? */ - if (!memcmp(&(fs->win[0x36]), &fatsign[0], 5)) - return FS_FAT12; - if (!memcmp(&(fs->win[0x36]), &fatsign[5], 5)) - return FS_FAT16; - if (!memcmp(&(fs->win[0x52]), &fatsign[10], 5) && (fs->win[0x28] == 0)) - return FS_FAT32; - } - } - return 0; -} - - - -/*--------------------------------*/ -/* Move Directory Pointer to Next */ - -static -BOOL next_dir_entry ( - DIR *scan /* Pointer to directory object */ +BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ + DIR *dirobj /* Pointer to directory object */ ) { DWORD clust; WORD idx; - FATFS *fs = FatFs; + FATFS *fs = dirobj->fs; - idx = scan->index + 1; + idx = dirobj->index + 1; if ((idx & 15) == 0) { /* Table sector changed? */ - scan->sect++; /* Next sector */ - if (!scan->clust) { /* In static table */ + 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? */ - clust = get_cluster(scan->clust); /* Get next cluster */ - if ((clust >= fs->max_clust) || (clust < 2)) /* Reached to end of table */ + clust = get_cluster(fs, dirobj->clust); /* Get next cluster */ + if (clust >= fs->max_clust || clust < 2) /* Reached to end of table */ return FALSE; - scan->clust = clust; /* Initialize for new cluster */ - scan->sect = clust2sect(clust); + dirobj->clust = clust; /* Initialize for new cluster */ + dirobj->sect = clust2sect(fs, clust); } } } - scan->index = idx; /* Lower 4 bit of scan->index indicates offset in scan->sect */ + dirobj->index = idx; /* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */ return TRUE; } -/*--------------------------------------*/ -/* Get File Status from Directory Entry */ + +/*-----------------------------------------------------------------------*/ +/* Get File Status from Directory 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 */ ) @@ -326,13 +325,13 @@ void get_fileinfo ( char *p; - p = &(finfo->fname[0]); + p = &finfo->fname[0]; a = *(dir+12); /* NT flag */ for (n = 0; n < 8; n++) { /* Convert file name (body) */ c = *(dir+n); if (c == ' ') break; if (c == 0x05) c = 0xE5; - if ((a & 0x08) && (c >= 'A') && (c <= 'Z')) c += 0x20; + if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; } if (*(dir+8) != ' ') { /* Convert file name (extension) */ @@ -340,7 +339,7 @@ void get_fileinfo ( for (n = 8; n < 11; n++) { c = *(dir+n); if (c == ' ') break; - if ((a & 0x10) && (c >= 'A') && (c <= 'Z')) c += 0x20; + if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; } } @@ -355,11 +354,13 @@ void get_fileinfo ( -/*-------------------------------------------------------------------*/ -/* 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 ( +char make_dirfile ( /* 1: error - detected an invalid format, '\0'|'/': 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)} */ ) @@ -372,25 +373,25 @@ char make_dirfile ( n = 0; t = 8; for (;;) { c = *(*path)++; - if (c <= ' ') c = 0; - if ((c == 0) || (c == '/')) { /* Reached to end of str or directory separator */ + if (c == '\0' || c == '/') { /* Reached to end of str or directory separator */ if (n == 0) break; dirname[11] = a & b; return c; } + if (c <= ' ') break; /* Reject invisible chars */ if (c == '.') { - if(!(a & 1) && (n >= 1) && (n <= 8)) { /* Enter extension part */ + if(!(a & 1) && n >= 1 && n <= 8) { /* Enter extension part */ n = 8; t = 11; continue; } break; } #ifdef _USE_SJIS - if (((c >= 0x81) && (c <= 0x9F)) || /* Accept S-JIS code */ - ((c >= 0xE0) && (c <= 0xFC))) { - if ((n == 0) && (c == 0xE5)) /* Change heading \xE5 to \x05 */ + if ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ + (c >= 0xE0 && c <= 0xFC)) { + if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ c = 0x05; a ^= 1; goto md_l2; } - if ((c >= 0x7F) && (c <= 0x80)) break; /* Reject \x7F \x80 */ + if (c >= 0x7F && c <= 0x80) break; /* Reject \x7F \x80 */ #else if (c >= 0x7F) goto md_l1; /* Accept \x7F-0xFF */ #endif @@ -401,10 +402,10 @@ char make_dirfile ( if (c <= '?') break; /* Reject : ; < = > ? */ if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */ if (c == '|') break; /* Reject | */ - if ((c >= '[') && (c <= ']')) break;/* Reject [ \ ] */ - if ((c >= 'A') && (c <= 'Z')) + if (c >= '[' && c <= ']') break;/* Reject [ \ ] */ + if (c >= 'A' && c <= 'Z') (t == 8) ? (b &= ~0x08) : (b &= ~0x10); - if ((c >= 'a') && (c <= 'z')) { /* Convert to upper case */ + if (c >= 'a' && c <= 'z') { /* Convert to upper case */ c -= 0x20; (t == 8) ? (a |= 0x08) : (a |= 0x10); } @@ -420,13 +421,15 @@ char make_dirfile ( -/*-------------------*/ -/* Trace a File Path */ + +/*-----------------------------------------------------------------------*/ +/* Trace a File Path */ +/*-----------------------------------------------------------------------*/ static -FRESULT trace_path ( - DIR *scan, /* Pointer to directory object to return last directory */ - char *fn, /* Pointer to last segment name to return */ +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 {file(8),ext(3),attr(1)} */ const char *path, /* Full-path string to trace a file or directory */ BYTE **dir /* Directory pointer in Win[] to retutn */ ) @@ -434,21 +437,21 @@ FRESULT trace_path ( DWORD clust; char ds; BYTE *dptr = NULL; - FATFS *fs = FatFs; + FATFS *fs = dirobj->fs; /* Get logical drive from the given DIR structure */ + /* Initialize directory object */ clust = fs->dirbase; if (fs->fs_type == FS_FAT32) { - scan->clust = scan->sclust = clust; - scan->sect = clust2sect(clust); + dirobj->clust = dirobj->sclust = clust; + dirobj->sect = clust2sect(fs, clust); } else { - scan->clust = scan->sclust = 0; - scan->sect = clust; + dirobj->clust = dirobj->sclust = 0; + dirobj->sect = clust; } - scan->index = 0; + dirobj->index = 0; - while ((*path == ' ') || (*path == '/')) path++; /* Skip leading spaces */ - if ((BYTE)*path < ' ') { /* Null path means the root directory */ + if (*path == '\0') { /* Null path means the root directory */ *dir = NULL; return FR_OK; } @@ -456,67 +459,69 @@ FRESULT trace_path ( ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */ if (ds == 1) return FR_INVALID_NAME; for (;;) { - if (!move_window(scan->sect)) return FR_RW_ERROR; - dptr = &(fs->win[(scan->index & 15) * 32]); /* Pointer to the directory entry */ - if (*dptr == 0) /* Has it reached to end of dir? */ + 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? */ return !ds ? FR_NO_FILE : FR_NO_PATH; - if ( (*dptr != 0xE5) /* Matched? */ + if ( (*dptr != 0xE5) /* Matched? */ && !(*(dptr+11) & AM_VOL) && !memcmp(dptr, fn, 8+3) ) break; - if (!next_dir_entry(scan)) /* Next directory pointer */ + 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 (!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 */ - scan->clust = scan->sclust = clust; /* Restart scan with the new directory */ - scan->sect = clust2sect(clust); - scan->index = 0; + dirobj->clust = dirobj->sclust = clust; /* Restart scanning at the new directory */ + dirobj->sect = clust2sect(fs, clust); + dirobj->index = 0; } } -/*---------------------------*/ -/* Reserve a Directory Entry */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Reserve a Directory Entry */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static -BYTE* reserve_direntry ( - DIR *scan /* Target directory to create new entry */ +BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ + DIR *dirobj /* Target directory to create new entry */ ) { DWORD clust, sector; BYTE c, n, *dptr; - FATFS *fs = FatFs; + FATFS *fs = dirobj->fs; /* Re-initialize directory object */ - clust = scan->sclust; + clust = dirobj->sclust; if (clust) { /* Dyanmic directory table */ - scan->clust = clust; - scan->sect = clust2sect(clust); + dirobj->clust = clust; + dirobj->sect = clust2sect(fs, clust); } else { /* Static directory table */ - scan->sect = fs->dirbase; + dirobj->sect = fs->dirbase; } - scan->index = 0; + dirobj->index = 0; do { - if (!move_window(scan->sect)) return NULL; - dptr = &(fs->win[(scan->index & 15) * 32]); /* Pointer to the directory entry */ + 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(scan)); /* Next directory pointer */ + if (c == 0 || c == 0xE5) return dptr; /* Found an empty entry! */ + } 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(scan->clust))) return NULL; - if (!move_window(0)) return 0; + if (!clust || !(clust = create_chain(fs, dirobj->clust))) return NULL; + if (!move_window(fs, 0)) return 0; - fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */ + fs->winsect = sector = clust2sect(fs, clust); /* Cleanup the expanded table */ memset(fs->win, 0, 512); for (n = fs->sects_clust; n; n--) { - if (disk_write(fs->win, sector, 1) != RES_OK) return NULL; + if (disk_write(fs->drive, fs->win, sector, 1) != RES_OK) return NULL; sector++; } fs->winflag = 1; @@ -526,146 +531,246 @@ BYTE* reserve_direntry ( -/*-----------------------------------------*/ -/* Make Sure that the File System is Valid */ + +/*-----------------------------------------------------------------------*/ +/* Load boot record and check if it is a FAT boot record */ +/*-----------------------------------------------------------------------*/ static -FRESULT check_mounted () +BYTE check_fs ( /* 0:Not a boot record, 1:Valid boot record but not a FAT, 2:FAT boot record */ + FATFS *fs, /* File system object */ + DWORD sect /* Sector# (lba) to check if it is a FAT boot record or not */ +) { - FATFS *fs = FatFs; + 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; + 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 (!fs) return FR_NOT_ENABLED; /* Has the FatFs been enabled? */ - - if (disk_status() & STA_NOINIT) { /* The drive has not been initialized */ - if (fs->files) /* Drive was uninitialized with any file left opend */ - return FR_INCORRECT_DISK_CHANGE; - else - return f_mountdrv(); /* Initialize file system and return resulut */ - } else { /* The drive has been initialized */ - if (!fs->fs_type) /* But the file system has not been initialized */ - return f_mountdrv(); /* Initialize file system and return resulut */ - } - return FR_OK; /* File system is valid */ + return 1; } +/*-----------------------------------------------------------------------*/ +/* Make Sure that the File System is Valid */ +/*-----------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/* Public Funciotns */ -/*--------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------*/ -/* Load File System Information and Initialize FatFs Module */ - -FRESULT f_mountdrv (void) +static +FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ + const char **path, /* Pointer to pointer to the path name (drive number) */ + FATFS **rfs, /* Pointer to pointer to the found file system object */ + BYTE chk_wp /* !=0: Check media write protection for wrinting fuctions */ +) { - BYTE fat; - DWORD sect, fatend, maxsect; - FATFS *fs = FatFs; + BYTE drv, fmt; + DSTATUS stat; + DWORD basesect, fatsize, totalsect, maxclust; + const char *p = *path; + FATFS *fs; - if (!fs) return FR_NOT_ENABLED; + /* 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) == ':') + p += 2; /* Found a drive number, get and strip it */ + else + drv = 0; /* No drive number is given, select drive 0 in default */ + if (*p == '/') p++; /* Strip heading slash */ + *path = p; /* Return pointer to the path name */ - /* Initialize file system object */ - memset(fs, 0, sizeof(FATFS)); + /* Check if the drive number is valid or not */ + if (drv >= _DRIVES) return FR_INVALID_DRIVE; /* Is the drive number valid? */ + if (!(fs = FatFs[drv])) return FR_NOT_ENABLED; /* Is the file system object registered? */ + *rfs = fs; /* Returen pointer to the corresponding file system object */ - /* Initialize disk drive */ - if (disk_initialize() & STA_NOINIT) return FR_NOT_READY; - - /* Search FAT partition */ - fat = check_fs(sect = 0); /* Check sector 0 as an SFD format */ - if (!fat) { /* Not a FAT boot record, it will be an FDISK format */ - /* Check a partition listed in top of the partition table */ - if (fs->win[0x1C2]) { /* Is the partition existing? */ - sect = LD_DWORD(&(fs->win[0x1C6])); /* Partition offset in LBA */ - fat = check_fs(sect); /* Check the partition */ + /* Chekck 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 */ +#if _FS_READONLY == 0 + if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; +#endif + return FR_OK; /* The file system object is valid */ } } - if (!fat) return FR_NO_FILESYSTEM; /* No FAT patition */ - /* Initialize file system object */ - fs->fs_type = fat; /* FAT type */ - fs->sects_fat = /* Sectors per FAT */ - (fat == FS_FAT32) ? LD_DWORD(&(fs->win[0x24])) : LD_WORD(&(fs->win[0x16])); - fs->sects_clust = fs->win[0x0D]; /* Sectors per cluster */ - fs->n_fats = fs->win[0x10]; /* Number of FAT copies */ - fs->fatbase = sect + LD_WORD(&(fs->win[0x0E])); /* FAT start sector (physical) */ - fs->n_rootdir = LD_WORD(&(fs->win[0x11])); /* Nmuber of root directory entries */ + /* The logical drive has not been mounted, following code attempts to mount the logical drive */ - fatend = fs->sects_fat * fs->n_fats + fs->fatbase; - if (fat == FS_FAT32) { - fs->dirbase = LD_DWORD(&(fs->win[0x2C])); /* FAT32: Directory start cluster */ - fs->database = fatend; /* FAT32: Data start sector (physical) */ - } else { - fs->dirbase = fatend; /* Directory start sector (physical) */ - fs->database = fs->n_rootdir / 16 + fatend; /* Data start sector (physical) */ + memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */ + 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 _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 */ + fmt = check_fs(fs, basesect); /* Check the partition */ + } } - maxsect = LD_DWORD(&(fs->win[0x20])); /* Calculate maximum cluster number */ - if (!maxsect) maxsect = LD_WORD(&(fs->win[0x13])); - fs->max_clust = (maxsect - fs->database + sect) / fs->sects_clust + 2; + if (fmt != 2 || fs->win[12] != 2) /* 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]); + 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->max_clust = maxclust = (totalsect /* Last cluster# + 1 */ + - LD_WORD(&fs->win[14]) - fatsize - fs->n_rootdir / 16 + ) / fs->sects_clust + 2; + fmt = FS_FAT12; /* Determins the FAT type */ + if (maxclust >= 0xFF7) fmt = FS_FAT16; + if (maxclust >= 0xFFF7) fmt = FS_FAT32; + if (fmt == FS_FAT32) + fs->dirbase = LD_DWORD(&fs->win[44]); /* 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->fs_type = fmt; /* FAT type */ + fs->id = ++fsid; /* File system mount ID */ return FR_OK; } -/*-----------------------*/ -/* Open or Create a File */ + +/*-----------------------------------------------------------------------*/ +/* Check if the file/dir object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Not valid */ + const FATFS *fs, /* Pointer to the file system object */ + WORD id /* id member of the target object to be checked */ +) +{ + if (!fs || (WORD)~fs->id != id) + return FR_INVALID_OBJECT; + if (disk_status(fs->drive) & STA_NOINIT) + return FR_NOT_READY; + + return FR_OK; +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +--------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Locical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + BYTE drv, /* Logical drive number to be mounted/unmounted */ + FATFS *fs /* Pointer to new file system object (NULL for unmount)*/ +) +{ + FATFS *fsobj; + + + if (drv >= _DRIVES) return FR_INVALID_DRIVE; + fsobj = FatFs[drv]; + FatFs[drv] = fs; + if (fsobj) memset(fsobj, 0, sizeof(FATFS)); + if (fs) memset(fs, 0, sizeof(FATFS)); + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ FRESULT f_open ( - FIL *fp, /* Pointer to the buffer of new file object to create */ + FIL *fp, /* Pointer to the blank file object */ const char *path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ ) { FRESULT res; BYTE *dir; - DIR dirscan; + DIR dirobj; char fn[8+3+1]; - FATFS *fs = FatFs; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; -#ifndef _FS_READONLY - if ((mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) && (disk_status() & STA_PROTECT)) - return FR_WRITE_PROTECTED; +#if _FS_READONLY == 0 + res = auto_mount(&path, &fs, mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)); +#else + res = auto_mount(&path, &fs, 0); #endif + if (res != FR_OK) return res; - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + /* Trace the file path */ + dirobj.fs = fs; + res = trace_path(&dirobj, fn, path, &dir); -#ifndef _FS_READONLY +#if _FS_READONLY == 0 /* Create or Open a File */ if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) { - DWORD dw; + 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(&dirscan); /* Reserve a directory entry */ + dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ if (dir == NULL) return FR_DENIED; - memcpy(dir, fn, 8+3); /* Initialize the new entry */ + memset(dir, 0, 32); /* Initialize the new entry */ + memcpy(dir, fn, 8+3); *(dir+12) = fn[11]; - memset(dir+13, 0, 32-13); } else { /* Any object is already existing */ - if ((dir == NULL) || (*(dir+11) & (AM_RDO|AM_DIR))) /* Could not overwrite (R/O or DIR) */ + if (dir == NULL || (*(dir+11) & (AM_RDO|AM_DIR))) /* Could not overwrite (R/O or DIR) */ return FR_DENIED; if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */ - dw = fs->winsect; /* Remove the cluster chain */ - if (!remove_chain(((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26)) - || !move_window(dw) ) - return FR_RW_ERROR; + 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 */ + fs->winflag = 1; + ps = fs->winsect; /* Remove the cluster chain */ + if (!remove_chain(fs, rs) || !move_window(fs, ps)) + return FR_RW_ERROR; } } if (mode & FA_CREATE_ALWAYS) { *(dir+11) = AM_ARC; - dw = get_fattime(); - ST_DWORD(dir+14, dw); /* Created time */ - ST_DWORD(dir+22, dw); /* Updated time */ + ps = get_fattime(); + ST_DWORD(dir+14, ps); /* Created time */ + ST_DWORD(dir+22, ps); /* Updated time */ fs->winflag = 1; } } @@ -673,33 +778,35 @@ FRESULT f_open ( else { #endif /* _FS_READONLY */ if (res != FR_OK) return res; /* Trace failed */ - if ((dir == NULL) || (*(dir+11) & AM_DIR)) /* It is a directory */ + if (dir == NULL || (*(dir+11) & AM_DIR)) /* It is a directory */ return FR_NO_FILE; -#ifndef _FS_READONLY +#if _FS_READONLY == 0 if ((mode & FA_WRITE) && (*(dir+11) & AM_RDO)) /* R/O violation */ return FR_DENIED; } #endif -#ifdef _FS_READONLY - fp->flag = mode & FA_READ; -#else +#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->fptr = 0; /* File ptr */ fp->sect_clust = 1; /* Sector counter */ - fs->files++; + fp->fs = fs; fp->id = ~fs->id; /* Owner file system object of the file */ return FR_OK; } -/*-----------*/ -/* Read File */ + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ FRESULT f_read ( FIL *fp, /* Pointer to the file object */ @@ -711,12 +818,13 @@ FRESULT f_read ( DWORD clust, sect, ln; WORD rcnt; BYTE cc, *rbuff = buff; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = fp->fs; *br = 0; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; /* Check disk ready */ + res = validate(fs, fp->id); + 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; @@ -728,15 +836,18 @@ FRESULT f_read ( 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) ? fp->org_clust : get_cluster(fp->curr_clust); - if ((clust < 2) || (clust >= fs->max_clust)) goto fr_error; + clust = (fp->fptr == 0) ? + fp->org_clust : get_cluster(fs, fp->curr_clust); + if (clust < 2 || clust >= fs->max_clust) + goto fr_error; fp->curr_clust = clust; /* Current cluster */ - sect = clust2sect(clust); /* Get current sector */ + sect = clust2sect(fs, clust); /* Get current sector */ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ } -#ifndef _FS_READONLY +#if _FS_READONLY == 0 if (fp->flag & FA__DIRTY) { /* Flush file I/O buffer if needed */ - if (disk_write(fp->buffer, fp->curr_sect, 1) != RES_OK) goto fr_error; + if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fr_error; fp->flag &= ~FA__DIRTY; } #endif @@ -744,12 +855,13 @@ FRESULT f_read ( cc = btr / 512; /* When left bytes >= 512, */ if (cc) { /* Read maximum contiguous sectors directly */ if (cc > fp->sect_clust) cc = fp->sect_clust; - if (disk_read(rbuff, sect, cc) != RES_OK) goto fr_error; + 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; } - if (disk_read(fp->buffer, sect, 1) != RES_OK) /* Load the sector into file I/O buffer */ + 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 */ @@ -766,10 +878,12 @@ fr_error: /* Abort this file due to an unrecoverable error */ -/*------------*/ -/* Write File */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* 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 */ @@ -780,13 +894,14 @@ FRESULT f_write ( DWORD clust, sect; WORD wcnt; BYTE cc; + FRESULT res; const BYTE *wbuff = buff; - FATFS *fs = FatFs; + FATFS *fs = fp->fs; *bw = 0; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + res = validate(fs, fp->id); + 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 */ @@ -800,30 +915,32 @@ FRESULT f_write ( if (fp->fptr == 0) { /* Is top of the file */ clust = fp->org_clust; if (clust == 0) /* No cluster is created yet */ - fp->org_clust = clust = create_chain(0); /* Create a new cluster chain */ + fp->org_clust = clust = create_chain(fs, 0); /* Create a new cluster chain */ } else { /* Middle or end of file */ - clust = create_chain(fp->curr_clust); /* Trace or streach cluster chain */ + clust = create_chain(fs, fp->curr_clust); /* Trace or streach cluster chain */ } - if ((clust < 2) || (clust >= fs->max_clust)) break; + if (clust < 2 || clust >= fs->max_clust) break; fp->curr_clust = clust; /* Current cluster */ - sect = clust2sect(clust); /* Get current sector */ + sect = clust2sect(fs, clust); /* Get current sector */ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ } if (fp->flag & FA__DIRTY) { /* Flush file I/O buffer if needed */ - if (disk_write(fp->buffer, fp->curr_sect, 1) != RES_OK) goto fw_error; + if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fw_error; fp->flag &= ~FA__DIRTY; } fp->curr_sect = sect; /* Update current sector */ cc = btw / 512; /* When left bytes >= 512, */ if (cc) { /* Write maximum contiguous sectors directly */ if (cc > fp->sect_clust) cc = fp->sect_clust; - if (disk_write(wbuff, sect, cc) != RES_OK) goto fw_error; + 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; } - if ((fp->fptr < fp->fsize) && /* Fill sector buffer with file data if needed */ - (disk_read(fp->buffer, sect, 1) != RES_OK)) + 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 */ @@ -844,8 +961,10 @@ fw_error: /* Abort this file due to an unrecoverable error */ -/*-------------------*/ -/* Seek File Pointer */ + +/*-----------------------------------------------------------------------*/ +/* Seek File Pointer */ +/*-----------------------------------------------------------------------*/ FRESULT f_lseek ( FIL *fp, /* Pointer to the file object */ @@ -854,15 +973,16 @@ FRESULT f_lseek ( { DWORD clust; BYTE sc; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = fp->fs; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + res = validate(fs, fp->id); + if (res) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; -#ifndef _FS_READONLY +#if _FS_READONLY == 0 if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */ - if (disk_write(fp->buffer, fp->curr_sect, 1) != RES_OK) goto fk_error; + if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) goto fk_error; fp->flag &= ~FA__DIRTY; } #endif @@ -877,12 +997,13 @@ FRESULT f_lseek ( 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; + clust = get_cluster(fs, 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 */ - if (fp->fptr % 512) { /* Load currnet sector if needed */ - if (disk_read(fp->buffer, fp->curr_sect, 1) != RES_OK) + 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; } } @@ -896,31 +1017,35 @@ fk_error: /* Abort this file due to an unrecoverable error */ -/*-------------------------------------------------*/ -/* Synchronize between File and Disk without Close */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Synchronize between File and Disk */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 FRESULT f_sync ( FIL *fp /* Pointer to the file object */ ) { BYTE *ptr; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = fp->fs; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) - return FR_INCORRECT_DISK_CHANGE; + 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(fp->buffer, fp->curr_sect, 1) != RES_OK) return FR_RW_ERROR; + 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(fp->dir_sect)) return FR_RW_ERROR; + 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 */ @@ -930,7 +1055,7 @@ FRESULT f_sync ( fs->winflag = 1; fp->flag &= ~FA__WRITTEN; } - if (!move_window(0)) return FR_RW_ERROR; + if (!move_window(fs, 0)) return FR_RW_ERROR; return FR_OK; } @@ -938,8 +1063,10 @@ FRESULT f_sync ( -/*------------*/ -/* Close File */ + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ FRESULT f_close ( FIL *fp /* Pointer to the file object to be closed */ @@ -948,78 +1075,84 @@ FRESULT f_close ( FRESULT res; -#ifndef _FS_READONLY +#if _FS_READONLY == 0 res = f_sync(fp); #else - res = FR_OK; + res = validate(fp->fs, fp->id); #endif - if (res == FR_OK) { - fp->flag = 0; - FatFs->files--; - } + if (res == FR_OK) + fp->fs = NULL; return res; } + #if _FS_MINIMIZE <= 1 -/*---------------------------*/ -/* Initialize directroy scan */ +/*-----------------------------------------------------------------------*/ +/* Create a directroy object */ +/*-----------------------------------------------------------------------*/ FRESULT f_opendir ( - DIR *scan, /* Pointer to directory object to initialize */ - const char *path /* Pointer to the directory path, null str means the root */ + DIR *dirobj, /* Pointer to directory object to create */ + const char *path /* Pointer to the directory path */ ) { - FRESULT res; BYTE *dir; char fn[8+3+1]; + FRESULT res; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; - - res = trace_path(scan, fn, path, &dir); /* Trace the directory path */ + if ((res = auto_mount(&path, &fs, 0)) != FR_OK) + return res; + dirobj->fs = fs; + 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 */ - scan->clust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); - scan->sect = clust2sect(scan->clust); - scan->index = 0; - } else { /* The entry is not directory */ + dirobj->clust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); + dirobj->sect = clust2sect(fs, dirobj->clust); + dirobj->index = 0; + } else { /* The entry is not a directory */ res = FR_NO_FILE; } } + dirobj->id = ~fs->id; } return res; } -/*----------------------------------*/ -/* Read Directory Entry in Sequense */ + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entry in Sequense */ +/*-----------------------------------------------------------------------*/ FRESULT f_readdir ( - DIR *scan, /* Pointer to the directory object */ + DIR *dirobj, /* Pointer to the directory object */ FILINFO *finfo /* Pointer to file information to return */ ) { - BYTE *dir, c; - FATFS *fs = FatFs; + BYTE *dir, c, res; + FATFS *fs = dirobj->fs; - if (!fs) return FR_NOT_ENABLED; + res = validate(fs, dirobj->id); + if (res) return res; + finfo->fname[0] = 0; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; - - while (scan->sect) { - if (!move_window(scan->sect)) return FR_RW_ERROR; - dir = &(fs->win[(scan->index & 15) * 32]); /* pointer to the directory entry */ + 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 */ 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 && c != '.' && !(*(dir+11) & AM_VOL)) /* Is it a valid entry? */ get_fileinfo(finfo, dir); - if (!next_dir_entry(scan)) scan->sect = 0; /* Next entry */ + if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */ if (finfo->fname[0]) break; /* Found valid entry */ } @@ -1028,24 +1161,28 @@ FRESULT f_readdir ( + #if _FS_MINIMIZE == 0 -/*-----------------*/ -/* Get File Status */ +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ FRESULT f_stat ( const char *path, /* Pointer to the file path */ FILINFO *finfo /* Pointer to file information to return */ ) { - FRESULT res; BYTE *dir; - DIR dirscan; char fn[8+3+1]; + FRESULT res; + DIR dirobj; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + if ((res = auto_mount(&path, &fs, 0)) != 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); @@ -1055,21 +1192,27 @@ FRESULT f_stat ( -#ifndef _FS_READONLY -/*-----------------------------*/ -/* Get Number of Free Clusters */ +#if _FS_READONLY == 0 +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ FRESULT f_getfree ( - DWORD *nclust /* Pointer to the double word to return number of free clusters */ + const char *drv, /* Logical drive number */ + DWORD *nclust, /* Pointer to the double word to return number of free clusters */ + FATFS **fatfs /* Pointer to pointer to the file system object to return */ ) { DWORD n, clust, sect; BYTE fat, f, *p; FRESULT res; - FATFS *fs = FatFs; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; + /* Get drive number */ + if ((res = auto_mount(&drv, &fs, 0)) != FR_OK) + return res; + *fatfs = fs; /* Count number of free clusters */ fat = fs->fs_type; @@ -1077,7 +1220,7 @@ FRESULT f_getfree ( if (fat == FS_FAT12) { clust = 2; do { - if ((WORD)get_cluster(clust) == 0) n++; + if ((WORD)get_cluster(fs, clust) == 0) n++; } while (++clust < fs->max_clust); } else { clust = fs->max_clust; @@ -1085,7 +1228,7 @@ FRESULT f_getfree ( f = 0; p = 0; do { if (!f) { - if (!move_window(sect++)) return FR_RW_ERROR; + if (!move_window(fs, sect++)) return FR_RW_ERROR; p = fs->win; } if (fat == FS_FAT16) { @@ -1104,25 +1247,27 @@ FRESULT f_getfree ( -/*------------------------------*/ -/* Delete a File or a Directory */ + +/*-----------------------------------------------------------------------*/ +/* Delete a File or a Directory */ +/*-----------------------------------------------------------------------*/ FRESULT f_unlink ( const char *path /* Pointer to the file or directory path */ ) { - FRESULT res; BYTE *dir, *sdir; DWORD dclust, dsect; - DIR dirscan; char fn[8+3+1]; - FATFS *fs = FatFs; + FRESULT res; + DIR dirobj; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + 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) return res; /* Trace failed */ if (dir == NULL) return FR_NO_FILE; /* It is a root directory */ @@ -1131,63 +1276,66 @@ FRESULT f_unlink ( dclust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); if (*(dir+11) & AM_DIR) { /* It is a sub-directory */ - dirscan.clust = dclust; /* Check if the sub-dir is empty or not */ - dirscan.sect = clust2sect(dclust); - dirscan.index = 0; + dirobj.clust = dclust; /* Check if the sub-dir is empty or not */ + dirobj.sect = clust2sect(fs, dclust); + dirobj.index = 0; do { - if (!move_window(dirscan.sect)) return FR_RW_ERROR; - sdir = &(fs->win[(dirscan.index & 15) * 32]); + 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)) + if (!((*sdir == 0xE5) || *sdir == '.') && !(*(sdir+11) & AM_VOL)) return FR_DENIED; /* The directory is not empty */ - } while (next_dir_entry(&dirscan)); + } while (next_dir_entry(&dirobj)); } - if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */ + if (!move_window(fs, dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */ *dir = 0xE5; fs->winflag = 1; - if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ - if (!move_window(0)) return FR_RW_ERROR; + 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; } -/*--------------------*/ -/* Create a Directory */ + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( const char *path /* Pointer to the directory path */ ) { - FRESULT res; BYTE *dir, *w, n; - DWORD sect, dsect, dclust, pclust, tim; - DIR dirscan; char fn[8+3+1]; - FATFS *fs = FatFs; + DWORD sect, dsect, dclust, pclust, tim; + FRESULT res; + DIR dirobj; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + 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) return FR_DENIED; /* Any file or directory is already existing */ if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirscan); /* Reserve a directory entry */ + dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ if (dir == NULL) return FR_DENIED; sect = fs->winsect; - dsect = clust2sect(dclust = create_chain(0)); /* Get a new cluster for new directory */ + dsect = clust2sect(fs, dclust = create_chain(fs, 0)); /* Get a new cluster for new directory */ if (!dsect) return FR_DENIED; - if (!move_window(0)) return 0; + if (!move_window(fs, 0)) return 0; w = fs->win; memset(w, 0, 512); /* Initialize the directory table */ for (n = fs->sects_clust - 1; n; n--) { - if (disk_write(w, dsect+n, 1) != RES_OK) return FR_RW_ERROR; + if (disk_write(fs->drive, w, dsect+n, 1) != RES_OK) + return FR_RW_ERROR; } fs->winsect = dsect; /* Create dot directories */ @@ -1199,13 +1347,13 @@ FRESULT f_mkdir ( ST_WORD(w+26, dclust); ST_WORD(w+20, dclust >> 16); memcpy(w+32, w, 32); *(w+33) = '.'; - pclust = dirscan.sclust; + 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); fs->winflag = 1; - if (!move_window(sect)) return FR_RW_ERROR; + 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]; @@ -1215,15 +1363,17 @@ FRESULT f_mkdir ( ST_WORD(dir+20, dclust >> 16); fs->winflag = 1; - if (!move_window(0)) return FR_RW_ERROR; + if (!move_window(fs, 0)) return FR_RW_ERROR; return FR_OK; } -/*-----------------------*/ -/* Change File Attribute */ + +/*-----------------------------------------------------------------------*/ +/* Change File Attribute */ +/*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const char *path, /* Pointer to the file path */ @@ -1233,15 +1383,15 @@ FRESULT f_chmod ( { FRESULT res; BYTE *dir; - DIR dirscan; + DIR dirobj; char fn[8+3+1]; - FATFS *fs = FatFs; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + 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) { @@ -1250,7 +1400,7 @@ FRESULT f_chmod ( 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; + if (!move_window(fs, 0)) res = FR_RW_ERROR; } } return res; @@ -1258,8 +1408,10 @@ FRESULT f_chmod ( -/*-----------------------*/ -/* Rename File/Directory */ + +/*-----------------------------------------------------------------------*/ +/* Rename File/Directory */ +/*-----------------------------------------------------------------------*/ FRESULT f_rename ( const char *path_old, /* Pointer to the old name */ @@ -1269,39 +1421,231 @@ FRESULT f_rename ( FRESULT res; DWORD sect_old; BYTE *dir_old, *dir_new, direntry[32-11]; - DIR dirscan; + DIR dirobj; char fn[8+3+1]; - FATFS *fs = FatFs; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; + if ((res = auto_mount(&path_old, &fs, 1)) != FR_OK) + return res; + dirobj.fs = fs; + res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ - res = trace_path(&dirscan, 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); - res = trace_path(&dirscan, fn, path_new, &dir_new); /* Check new object */ + 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; - dir_new = reserve_direntry(&dirscan); /* Reserve a directory entry */ + 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]; fs->winflag = 1; - if (!move_window(sect_old)) return FR_RW_ERROR; /* Remove old entry */ + if (!move_window(fs, sect_old)) return FR_RW_ERROR; /* Remove old entry */ *dir_old = 0xE5; fs->winflag = 1; - if (!move_window(0)) return FR_RW_ERROR; + if (!move_window(fs, 0)) return FR_RW_ERROR; return FR_OK; } -#endif /* _FS_READONLY */ + + + +#ifdef _USE_MKFS +/*-----------------------------------------------------------------------*/ +/* Create File System on the Drive */ +/*-----------------------------------------------------------------------*/ + +#define ERASE_BLK 32 +#define N_ROOTDIR 512 +#define N_FATS 2 + + +FRESULT f_mkfs ( + BYTE drv, /* Logical drive number */ + BYTE partition, /* Partitioning rule 0:FDISK, 1:SFD */ + BYTE allocsize /* Allocation unit size */ +) +{ + BYTE fmt, m, *tbl; + DWORD b_part, b_fat, b_dir, b_data; /* Area offset (LBA) */ + DWORD n_part, n_rsv, n_fat, n_dir; /* Area size */ + DWORD n_clust, n; + static const BYTE tbl_alloc[] = {1,2,4,8,16,32,64,0}; + FATFS *fs; + DSTATUS stat; + + + /* Check mounted drive */ + if (drv >= _DRIVES) return FR_INVALID_DRIVE; + if (!(fs = FatFs[drv])) return FR_NOT_ENABLED; + memset(fs, 0, sizeof(FATFS)); + 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 */ + 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) + return FR_MKFS_ABORTED; + b_part = (!partition) ? 63 : 0; + n_part -= b_part; + + /* Pre-compute number of clusters and FAT type */ + n_clust = n_part / allocsize; + fmt = FS_FAT12; + if (n_clust >= 0xFF7) fmt = FS_FAT16; + if (n_clust >= 0xFFF7) fmt = FS_FAT32; + switch (fmt) { + case FS_FAT12: + n_fat = ((n_clust * 2 + 1) / 3 + 3 + 511) / 512; + n_rsv = 1 + partition; + n_dir = N_ROOTDIR * 32 / 512; + break; + case FS_FAT16: + n_fat = ((n_clust * 2) + 4 + 511) / 512; + n_rsv = 1 + partition; + n_dir = N_ROOTDIR * 32 / 512; + break; + default: + n_fat = ((n_clust * 4) + 8 + 511) / 512; + 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; + +#ifdef ERASE_BLK + /* Round up data start sector to erase block boundary */ + n = (b_data + ERASE_BLK - 1) & ~(ERASE_BLK - 1); + b_dir += n - b_data; + n_fat += (n - b_data) / N_FATS; +#endif + /* Determine number of cluster and final check of validity of the FAT type */ + n_clust = (n_part - n_rsv - n_fat * 2 - n_dir) / allocsize; + if ( (fmt == FS_FAT16 && n_clust < 0xFF7) + || (fmt == FS_FAT32 && n_clust < 0xFFF7)) + return FR_MKFS_ABORTED; + + /* Create partition table if needed */ + if (!partition) { + DWORD n_disk = b_part + n_part; + + tbl = &fs->win[0x1BE]; + 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); + } else { + ST_WORD(tbl+6, 0xFFFF); + } + *(tbl+5) = 254; + if (fmt != FS_FAT32) /* System ID */ + *(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 */ + 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); + } else { + ST_DWORD(tbl+32, 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 */ + 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); + } 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 */ + } + *(WORD*)(tbl+510) = 0xAA55; /* Signature */ + if (disk_write(drv, tbl, b_part, 1) != RES_OK) + return FR_RW_ERROR; + if (fmt == FS_FAT32) + disk_write(drv, tbl, b_part+6, 1); + + /* 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); + if (disk_write(drv, tbl, b_part+1, 1) != RES_OK) + return FR_RW_ERROR; + disk_write(drv, tbl, b_part+7, 1); + } + + /* Initialize FAT area */ + for (m = 0; m < N_FATS; m++) { + memset(tbl, 0, 512); /* 1st sector of the FAT */ + if (fmt != FS_FAT32) { + n = (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8; + ST_DWORD(tbl+0, n); + } else { + ST_DWORD(tbl+0, 0xFFFFFFF8); + ST_DWORD(tbl+4, 0xFFFFFFFF); + ST_DWORD(tbl+8, 0x0FFFFFFF); + } + if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) + return FR_RW_ERROR; + memset(tbl, 0, 512); /* Following sectors */ + for (n = 1; n < n_fat; n++) { + if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) + return FR_RW_ERROR; + } + } + + /* Initialize Root directory */ + for (m = 0; m < 64; m++) { + if (disk_write(drv, tbl, b_fat++, 1) != RES_OK) + return FR_RW_ERROR; + } + + return FR_OK; +} + +#endif /* _USE_MKFS */ +#endif /* _FS_READONLY == 0 */ #endif /* _FS_MINIMIZE == 0 */ #endif /* _FS_MINIMIZE <= 1 */ diff --git a/src/ff.h b/src/ff.h index fc7128b..f755b7e 100644 --- a/src/ff.h +++ b/src/ff.h @@ -1,11 +1,11 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module include file R0.03a (C)ChaN, 2006 +/ FatFs - FAT file system module include file R0.04 (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, / research and development under license policy of following trems. / -/ Copyright (C) 2006, ChaN, all right reserved. +/ Copyright (C) 2007, ChaN, all right reserved. / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or @@ -16,27 +16,36 @@ #ifndef _FATFS -#error Don't forget to change these options. +#define _MCU_ENDIAN 0 +/* The _MCU_ENDIAN defines which access method is used to the FAT structure. +/ 1: Enable word access. +/ 2: Disable word access and use byte-by-byte access instead. +/ When the architectural byte order of the MCU is big-endian and/or address +/ miss-aligned access is prohibited, the _MCU_ENDIAN must be set to 2. +/ If it is not the case, it can be set to 1 for good code efficiency. */ -//#define _BYTE_ACC -/* The _BYTE_ACC enables byte-by-byte access for multi-byte variables. This -/ MUST be defined when multi-byte variable is stored in big-endian and/or -/ address miss-aligned access is prohibited. */ - -//#define _FS_READONLY -/* Read only configuration. This removes writing functions, f_write, f_sync, -/ f_unlink, f_mkdir, f_chmod, f_rename and f_getfree. */ +#define _FS_READONLY 0 +/* Setting _FS_READONLY to 1 defines read only configuration. This removes +/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename +/ and useless f_getfree. */ #define _FS_MINIMIZE 0 -/* The _FS_MINIMIZE defines minimization level to remove some functions. -/ 0: Not minimized. +/* 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. */ +#define _DRIVES 2 +/* Number of logical drives to be used */ + #define _USE_SJIS /* When _USE_SJIS is defined, 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. */ + #include "integer.h" @@ -48,12 +57,11 @@ typedef unsigned char FRESULT; /* File system object structure */ typedef struct _FATFS { BYTE fs_type; /* FAT type */ - BYTE files; /* Number of files currently opend */ BYTE sects_clust; /* Sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ - WORD n_rootdir; /* Number of root directory entry */ - BYTE winflag; /* win[] dirty flag (1:must be written back) */ - BYTE pad1; + 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[] */ DWORD sects_fat; /* Sectors per fat */ DWORD max_clust; /* Maximum cluster# + 1 */ @@ -61,30 +69,35 @@ typedef struct _FATFS { DWORD dirbase; /* Root directory start sector (cluster# for FAT32) */ DWORD database; /* Data start sector */ DWORD last_clust; /* Last allocated cluster */ + BYTE winflag; /* win[] dirty flag (1:must be written back) */ BYTE win[512]; /* Disk access window for Directory/FAT */ } FATFS; /* Directory object structure */ typedef struct _DIR { + 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 { + FATFS* fs; /* Pointer to the owner file system object */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ DWORD org_clust; /* File start cluster */ DWORD curr_clust; /* Current cluster */ DWORD curr_sect; /* Current sector */ -#ifndef _FS_READONLY +#if _FS_READONLY == 0 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 */ @@ -105,28 +118,27 @@ typedef struct _FILINFO { /*-----------------------------------------------------*/ /* FatFs module application interface */ -extern FATFS *FatFs; /* Pointer to active file system object */ - +FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */ -FRESULT f_read (FIL*, void*, WORD, WORD*); /* Read file */ -FRESULT f_close (FIL*); /* Close file */ -FRESULT f_lseek (FIL*, DWORD); /* Seek file pointer */ -FRESULT f_opendir (DIR*, const char*); /* Open a directory */ +FRESULT f_read (FIL*, void*, WORD, WORD*); /* Read data from a file */ +FRESULT f_write (FIL*, const void*, WORD, WORD*); /* Write data to a file */ +FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */ +FRESULT f_close (FIL*); /* Close an open file object */ +FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */ FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */ FRESULT f_stat (const char*, FILINFO*); /* Get file status */ -FRESULT f_getfree (DWORD*); /* Get number of free clusters */ -FRESULT f_mountdrv (void); /* Force initialized the file system */ -FRESULT f_write (FIL*, const void*, WORD, WORD*); /* Write file */ +FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */ FRESULT f_sync (FIL*); /* Flush cached data of a writing file */ -FRESULT f_unlink (const char*); /* Delete a file or directory */ -FRESULT f_mkdir (const char*); /* Create a directory */ -FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file attriburte */ -FRESULT f_rename (const char*, const char*); /* Rename a file or directory */ +FRESULT f_unlink (const char*); /* Delete an existing file or directory */ +FRESULT f_mkdir (const char*); /* Create a new directory */ +FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */ +FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */ +FRESULT f_mkfs (BYTE, BYTE, BYTE); /* Create a file system on the drive */ /* User defined function to give a current time to fatfs module */ -DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: Day(1-31) */ +DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */ /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */ @@ -138,20 +150,22 @@ DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: #define FR_NO_FILE 2 #define FR_NO_PATH 3 #define FR_INVALID_NAME 4 -#define FR_DENIED 5 -#define FR_DISK_FULL 6 -#define FR_RW_ERROR 7 -#define FR_INCORRECT_DISK_CHANGE 8 +#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 -#ifndef _FS_READONLY +#if _FS_READONLY == 0 #define FA_WRITE 0x02 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 @@ -182,16 +196,20 @@ DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: /* Multi-byte word access macros */ -#ifdef _BYTE_ACC +#if _MCU_ENDIAN == 1 /* Use word access */ +#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) +#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) +#else +#if _MCU_ENDIAN == 2 /* Use byte-by-byte access */ #define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) #define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr)) #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 -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) +#error Don't forget to set _MCU_ENDIAN properly! +#endif #endif diff --git a/src/integer.h b/src/integer.h index 8c02df2..18ce992 100644 --- a/src/integer.h +++ b/src/integer.h @@ -1,14 +1,19 @@ #ifndef _INTEGER -typedef unsigned char BYTE; -typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; + typedef char CHAR; -typedef unsigned short WORD; -typedef unsigned short USHORT; +typedef unsigned char UCHAR; +typedef unsigned char BYTE; + typedef short SHORT; -typedef unsigned long DWORD; -typedef unsigned long ULONG; +typedef unsigned short USHORT; +typedef unsigned short WORD; + typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long DWORD; typedef unsigned char BOOL; #define FALSE 0 diff --git a/src/tff.c b/src/tff.c index 6e0a3ee..e214bef 100644 --- a/src/tff.c +++ b/src/tff.c @@ -1,11 +1,11 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.03a (C)ChaN, 2006 +/ FatFs - FAT file system module R0.04 (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, / research and development under license policy of following trems. / -/ Copyright (C) 2006, ChaN, all right reserved. +/ Copyright (C) 2007, ChaN, all right reserved. / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or @@ -21,22 +21,30 @@ / Sep 22, 2006 R0.03 Added f_rename(). / Changed option _FS_MINIMUM to _FS_MINIMIZE. / 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. /---------------------------------------------------------------------------*/ #include #include "tff.h" /* Tiny-FatFs declarations */ #include "diskio.h" /* Include file for user provided disk functions */ - -FATFS *FatFs; /* Pointer to the file system object */ +static +FATFS *FatFs; /* Pointer to the file system objects (logical drive) */ +static +WORD fsid; /* File system mount ID */ /*------------------------------------------------------------------------- + Module Private Functions + -------------------------------------------------------------------------*/ -/*----------------------*/ -/* Change Window Offset */ + +/*-----------------------------------------------------------------------*/ +/* Change window offset */ +/*-----------------------------------------------------------------------*/ static BOOL move_window ( @@ -49,21 +57,23 @@ BOOL move_window ( wsect = fs->winsect; if (wsect != sector) { /* Changed current window */ -#ifndef _FS_READONLY +#if _FS_READONLY == 0 BYTE n; if (fs->winflag) { /* Write back dirty window if needed */ - if (disk_write(fs->win, wsect, 1) != RES_OK) return FALSE; + if (disk_write(0, fs->win, wsect, 1) != RES_OK) + return FALSE; fs->winflag = 0; if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */ for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to all FAT copies */ wsect += fs->sects_fat; - if (disk_write(fs->win, wsect, 1) != RES_OK) break; + disk_write(0, fs->win, wsect, 1); } } } #endif if (sector) { - if (disk_read(fs->win, sector, 1) != RES_OK) return FALSE; + if (disk_read(0, fs->win, sector, 1) != RES_OK) + return FALSE; fs->winsect = sector; } } @@ -72,12 +82,14 @@ BOOL move_window ( -/*----------------------*/ -/* Get a Cluster Status */ + +/*-----------------------------------------------------------------------*/ +/* Get a cluster status */ +/*-----------------------------------------------------------------------*/ static -WORD get_cluster ( - WORD clust /* Cluster# to get the link information */ +CLUST get_cluster ( + CLUST clust /* Cluster# to get the link information */ ) { WORD wc, bc; @@ -85,11 +97,11 @@ WORD get_cluster ( FATFS *fs = FatFs; - if ((clust >= 2) && (clust < fs->max_clust)) { /* Valid cluster# */ + if (clust >= 2 && clust < fs->max_clust) { /* Valid cluster# */ fatsect = fs->fatbase; switch (fs->fs_type) { case FS_FAT12 : - bc = clust * 3 / 2; + bc = (WORD)clust * 3 / 2; if (!move_window(fatsect + bc / 512)) break; wc = fs->win[bc % 512]; bc++; if (!move_window(fatsect + bc / 512)) break; @@ -98,7 +110,12 @@ WORD get_cluster ( case FS_FAT16 : if (!move_window(fatsect + clust / 256)) break; - return LD_WORD(&(fs->win[(clust * 2) % 512])); + return LD_WORD(&fs->win[((WORD)clust * 2) % 512]); +#if _FAT32 != 0 + case FS_FAT32 : + if (!move_window(fatsect + clust / 128)) break; + return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF; +#endif } } return 1; /* There is no cluster information, or an error occured */ @@ -106,14 +123,16 @@ WORD get_cluster ( -/*-------------------------*/ -/* Change a Cluster Status */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Change a cluster status */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static -BOOL put_cluster ( - WORD clust, /* Cluster# to change */ - WORD val /* New value to mark the cluster */ +BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ + CLUST clust, /* Cluster# to change */ + CLUST val /* New value to mark the cluster */ ) { WORD bc; @@ -123,21 +142,32 @@ BOOL put_cluster ( fatsect = fs->fatbase; - if (fs->fs_type == FS_FAT12) { - bc = clust * 3 / 2; + switch (fs->fs_type) { + case FS_FAT12 : + bc = (WORD)clust * 3 / 2; if (!move_window(fatsect + bc / 512)) return FALSE; p = &fs->win[bc % 512]; *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; bc++; - fs->winflag = 1; + fs->winflag = 1; if (!move_window(fatsect + bc / 512)) return FALSE; p = &fs->win[bc % 512]; *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); - } else { - if (!move_window(fatsect + clust / 256)) return FALSE; - ST_WORD(&(fs->win[((WORD)clust * 2) % 512]), (WORD)val); - } + break; + case FS_FAT16 : + if (!move_window(fatsect + clust / 256)) return FALSE; + ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val); + break; +#if _FAT32 != 0 + case FS_FAT32 : + if (!move_window(fatsect + clust / 128)) return FALSE; + ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val); + break; +#endif + default : + return FALSE; + } fs->winflag = 1; return TRUE; } @@ -145,16 +175,18 @@ BOOL put_cluster ( -/*------------------------*/ -/* Remove a Cluster Chain */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static BOOL remove_chain ( - WORD clust /* Cluster# to remove chain from */ + CLUST clust /* Cluster# to remove chain from */ ) { - WORD nxt; + CLUST nxt; if (clust) { @@ -169,16 +201,18 @@ BOOL remove_chain ( -/*-----------------------------------*/ -/* Stretch or Create a Cluster Chain */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Stretch or create a cluster chain */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 static -WORD create_chain ( - WORD clust /* Cluster# to stretch, 0 means create new */ +CLUST create_chain ( + CLUST clust /* Cluster# to stretch, 0 means create new */ ) { - WORD cstat, ncl, scl, mcl; + CLUST cstat, ncl, scl, mcl; FATFS *fs = FatFs; @@ -193,7 +227,7 @@ WORD create_chain ( if (cstat < mcl) return cstat; /* It is already followed by next cluster */ scl = clust; } - ncl = scl; /* Scan start cluster */ + ncl = scl; /* Start cluster */ do { ncl++; /* Next cluster */ if (ncl >= mcl) { /* Wrap around */ @@ -205,7 +239,7 @@ WORD create_chain ( if (cstat == 1) return 0; /* Any error occured */ } while (cstat); /* Repeat until find a free cluster */ - if (!put_cluster(ncl, 0xFFFF)) return 0; /* Mark the new cluster "in use" */ + 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 */ fs->last_clust = ncl; @@ -215,12 +249,14 @@ WORD create_chain ( -/*----------------------------*/ -/* Get Sector# from Cluster# */ + +/*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ static -DWORD clust2sect ( - WORD clust /* Cluster# to be converted */ +DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ + CLUST clust /* Cluster# to be converted */ ) { FATFS *fs = FatFs; @@ -233,69 +269,46 @@ DWORD clust2sect ( -/*------------------------*/ -/* Check File System Type */ -static -BYTE check_fs ( - DWORD sect /* Sector# to check if it is a FAT boot record or not */ -) -{ - static const char fatsign[] = "FAT12FAT16"; - FATFS *fs = FatFs; - - /* Determines FAT type by signature string but this is not correct. - For further information, refer to fatgen103.doc from Microsoft. */ - memset(fs->win, 0, 512); - if (disk_read(fs->win, sect, 1) == RES_OK) { /* Load boot record */ - if (LD_WORD(&(fs->win[510])) == 0xAA55) { /* Is it valid? */ - if (!memcmp(&(fs->win[0x36]), &fatsign[0], 5)) - return FS_FAT12; - if (!memcmp(&(fs->win[0x36]), &fatsign[5], 5)) - return FS_FAT16; - } - } - return 0; -} - - - -/*--------------------------------*/ -/* Move Directory Pointer to Next */ +/*-----------------------------------------------------------------------*/ +/* Move directory pointer to next */ +/*-----------------------------------------------------------------------*/ static BOOL next_dir_entry ( - DIR *scan /* Pointer to directory object */ + DIR *dirobj /* Pointer to directory object */ ) { - WORD clust; + CLUST clust; WORD idx; FATFS *fs = FatFs; - idx = scan->index + 1; + idx = dirobj->index + 1; if ((idx & 15) == 0) { /* Table sector changed? */ - scan->sect++; /* Next sector */ - if (!scan->clust) { /* In static table */ + 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? */ - clust = get_cluster(scan->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 >= fs->max_clust || clust < 2) /* Reached to end of table */ return FALSE; - scan->clust = clust; /* Initialize for new cluster */ - scan->sect = clust2sect(clust); + dirobj->clust = clust; /* Initialize for new cluster */ + dirobj->sect = clust2sect(clust); } } } - scan->index = idx; /* Lower 4 bit of scan->index indicates offset in scan->sect */ + dirobj->index = idx; /* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */ return TRUE; } -/*--------------------------------------*/ -/* Get File Status from Directory Entry */ + +/*-----------------------------------------------------------------------*/ +/* Get file status from directory entry */ +/*-----------------------------------------------------------------------*/ #if _FS_MINIMIZE <= 1 static @@ -308,13 +321,13 @@ void get_fileinfo ( char *p; - p = &(finfo->fname[0]); + p = &finfo->fname[0]; a = *(dir+12); /* NT flag */ for (n = 0; n < 8; n++) { /* Convert file name (body) */ c = *(dir+n); if (c == ' ') break; if (c == 0x05) c = 0xE5; - if ((a & 0x08) && (c >= 'A') && (c <= 'Z')) c += 0x20; + if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; } if (*(dir+8) != ' ') { /* Convert file name (extension) */ @@ -322,7 +335,7 @@ void get_fileinfo ( for (n = 8; n < 11; n++) { c = *(dir+n); if (c == ' ') break; - if ((a & 0x10) && (c >= 'A') && (c <= 'Z')) c += 0x20; + if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20; *p++ = c; } } @@ -337,8 +350,10 @@ void get_fileinfo ( -/*-------------------------------------------------------------------*/ -/* 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 ( @@ -354,25 +369,25 @@ char make_dirfile ( n = 0; t = 8; for (;;) { c = *(*path)++; - if (c <= ' ') c = 0; - if ((c == 0) || (c == '/')) { /* Reached to end of str or directory separator */ + if (c == '\0' || c == '/') { /* Reached to end of str or directory separator */ if (n == 0) break; dirname[11] = a & b; return c; } + if (c <= ' ') break; /* Reject invisible chars */ if (c == '.') { - if(!(a & 1) && (n >= 1) && (n <= 8)) { /* Enter extension part */ + if(!(a & 1) && n >= 1 && n <= 8) { /* Enter extension part */ n = 8; t = 11; continue; } break; } #ifdef _USE_SJIS - if (((c >= 0x81) && (c <= 0x9F)) || /* Accept S-JIS code */ - ((c >= 0xE0) && (c <= 0xFC))) { - if ((n == 0) && (c == 0xE5)) /* Change heading \xE5 to \x05 */ + if ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ + (c >= 0xE0 && c <= 0xFC)) { + if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ c = 0x05; a ^= 1; goto md_l2; } - if ((c >= 0x7F) && (c <= 0x80)) break; /* Reject \x7F \x80 */ + if (c >= 0x7F && c <= 0x80) break; /* Reject \x7F \x80 */ #else if (c >= 0x7F) goto md_l1; /* Accept \x7F-0xFF */ #endif @@ -383,10 +398,10 @@ char make_dirfile ( if (c <= '?') break; /* Reject : ; < = > ? */ if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */ if (c == '|') break; /* Reject | */ - if ((c >= '[') && (c <= ']')) break;/* Reject [ \ ] */ - if ((c >= 'A') && (c <= 'Z')) + if (c >= '[' && c <= ']') break;/* Reject [ \ ] */ + if (c >= 'A' && c <= 'Z') (t == 8) ? (b &= ~0x08) : (b &= ~0x10); - if ((c >= 'a') && (c <= 'z')) { /* Convert to upper case */ + if (c >= 'a' && c <= 'z') { /* Convert to upper case */ c -= 0x20; (t == 8) ? (a |= 0x08) : (a |= 0x10); } @@ -402,29 +417,36 @@ char make_dirfile ( -/*-------------------*/ -/* Trace a File Path */ +/*-----------------------------------------------------------------------*/ +/* Trace a file path */ +/*-----------------------------------------------------------------------*/ static FRESULT trace_path ( - DIR *scan, /* Pointer to directory object to return last directory */ + 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 */ ) { - WORD clust; + CLUST clust; char ds; BYTE *dptr = NULL; FATFS *fs = FatFs; /* Initialize directory object */ - scan->clust = scan->sclust = 0; - scan->sect = fs->dirbase; - scan->index = 0; + clust = fs->dirbase; + if (_FAT32 != 0 && fs->fs_type == FS_FAT32) { + dirobj->clust = dirobj->sclust = clust; + dirobj->sect = clust2sect(clust); + } else { + dirobj->clust = dirobj->sclust = 0; + dirobj->sect = clust; + } + dirobj->index = 0; + dirobj->fs = fs; - while ((*path == ' ') || (*path == '/')) path++; /* Skip leading spaces */ - if ((BYTE)*path < ' ') { /* Null path means the root directory */ + if (*path == '\0') { /* Null path means the root directory */ *dir = NULL; return FR_OK; } @@ -432,68 +454,73 @@ FRESULT trace_path ( ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */ if (ds == 1) return FR_INVALID_NAME; for (;;) { - if (!move_window(scan->sect)) return FR_RW_ERROR; - dptr = &(fs->win[(scan->index & 15) * 32]); /* Pointer to the directory entry */ - if (*dptr == 0) /* Has it reached to end of dir? */ + 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? */ return !ds ? FR_NO_FILE : FR_NO_PATH; - if ( (*dptr != 0xE5) /* Matched? */ + if ( (*dptr != 0xE5) /* Matched? */ && !(*(dptr+11) & AM_VOL) && !memcmp(dptr, fn, 8+3) ) break; - if (!next_dir_entry(scan)) /* Next directory pointer */ + 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 = LD_WORD(dptr+26); /* Get cluster# of the directory */ - scan->clust = scan->sclust = clust; /* Restart scan with the new directory */ - scan->sect = clust2sect(clust); - scan->index = 0; + 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 _FAT32 != 0 + clust = ((DWORD)LD_WORD(dptr+20) << 16) | LD_WORD(dptr+26); /* Get cluster# of the directory */ +#else + clust = LD_WORD(dptr+26); +#endif + dirobj->clust = dirobj->sclust = clust; /* Restart scannig with the new directory */ + dirobj->sect = clust2sect(clust); + dirobj->index = 0; } } -/*---------------------------*/ -/* Reserve a Directory Entry */ +/*-----------------------------------------------------------------------*/ +/* Reserve a directory entry */ +/*-----------------------------------------------------------------------*/ -#ifndef _FS_READONLY +#if _FS_READONLY == 0 static -BYTE* reserve_direntry ( - DIR *scan /* Target directory to create new entry */ +BYTE* reserve_direntry ( /* !=NULL: successful, NULL: failed */ + DIR *dirobj /* Target directory to create new entry */ ) { - WORD clust; + CLUST clust; DWORD sector; BYTE c, n, *dptr; FATFS *fs = FatFs; /* Re-initialize directory object */ - clust = scan->sclust; + clust = dirobj->sclust; if (clust) { /* Dyanmic directory table */ - scan->clust = clust; - scan->sect = clust2sect(clust); + dirobj->clust = clust; + dirobj->sect = clust2sect(clust); } else { /* Static directory table */ - scan->sect = fs->dirbase; + dirobj->sect = fs->dirbase; } - scan->index = 0; + dirobj->index = 0; do { - if (!move_window(scan->sect)) return NULL; - dptr = &(fs->win[(scan->index & 15) * 32]); /* Pointer to the directory entry */ + 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(scan)); /* Next directory pointer */ + if (c == 0 || c == 0xE5) return dptr; /* Found an empty entry! */ + } 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(scan->clust))) return NULL; + if (!clust || !(clust = create_chain(dirobj->clust))) return NULL; if (!move_window(0)) return 0; fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */ memset(fs->win, 0, 512); for (n = fs->sects_clust; n; n--) { - if (disk_write(fs->win, sector, 1) != RES_OK) return NULL; + if (disk_write(0, fs->win, sector, 1) != RES_OK) return NULL; sector++; } fs->winflag = 1; @@ -503,141 +530,247 @@ BYTE* reserve_direntry ( -/*-----------------------------------------*/ -/* Make Sure that the File System is Valid */ + +/*-----------------------------------------------------------------------*/ +/* Load boot record and check if it is a FAT boot record */ +/*-----------------------------------------------------------------------*/ static -FRESULT check_mounted () +BYTE check_fs ( /* 0:Not a boot record, 1:Valid boot record but not a FAT, 2:FAT boot record */ + 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; - if (!fs) return FR_NOT_ENABLED; /* Has the FatFs been enabled? */ - - if (disk_status() & STA_NOINIT) { /* The drive has not been initialized */ - if (fs->files) /* Drive was uninitialized with any file left opend */ - return FR_INCORRECT_DISK_CHANGE; - else - return f_mountdrv(); /* Initialize file system and return resulut */ - } else { /* The drive has been initialized */ - if (!fs->fs_type) /* But the file system has not been initialized */ - return f_mountdrv(); /* Initialize file system and return resulut */ - } - return FR_OK; /* File system is valid */ + if (!memcmp(&fs->win[54], "FAT", 3)) /* Check FAT signature */ + return 2; +#if _FAT32 != 0 + if (!memcmp(&fs->win[82], "FAT32", 5) && !(fs->win[40] & 0x80)) + return 2; +#endif + return 1; } +/*-----------------------------------------------------------------------*/ +/* Make sure that the file system is valid */ +/*-----------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/* Public Funciotns */ -/*--------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------*/ -/* Load File System Information and Initialize FatFs Module */ - -FRESULT f_mountdrv (void) +static +FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ + const char **path, /* Pointer to pointer to the path name (drive number) */ + BYTE chk_wp /* !=0: Check media write protection for wrinting fuctions */ +) { - BYTE fat; - DWORD sect, fatend, maxsect; + BYTE fmt; + DSTATUS stat; + DWORD basesect, fatsize, totalsect, maxclust; + const char *p = *path; FATFS *fs = FatFs; + + while (*p == ' ') p++; /* Strip leading spaces */ + if (*p == '/') p++; /* Strip heading slash */ + *path = p; /* Return pointer to the path name */ + + /* Is the file system object registered? */ if (!fs) return FR_NOT_ENABLED; - /* Initialize file system object */ - memset(fs, 0, sizeof(FATFS)); - - /* Initialize disk drive */ - if (disk_initialize() & STA_NOINIT) return FR_NOT_READY; - - /* Search FAT partition */ - fat = check_fs(sect = 0); /* Check sector 0 as an SFD format */ - if (!fat) { /* Not a FAT boot record, it will be an FDISK format */ - /* Check first pri-partition listed in the partition table */ - if (fs->win[0x1C2]) { /* Is a partition existing? */ - sect = LD_DWORD(&(fs->win[0x1C6])); /* Partition offset in LBA */ - fat = check_fs(sect); /* Check the partition */ + /* Chekck if the logical drive has been mounted or not */ + if (fs->fs_type) { + stat = disk_status(0); + if (!(stat & STA_NOINIT)) { /* If the physical drive is kept initialized */ +#if _FS_READONLY == 0 + if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; +#endif + return FR_OK; /* The file system object is valid */ } } - if (!fat) return FR_NO_FILESYSTEM; /* No FAT patition */ - /* Initialize file system object */ - fs->fs_type = fat; /* FAT type */ - fs->sects_fat = LD_WORD(&(fs->win[0x16])); /* Sectors per FAT */ - fs->sects_clust = fs->win[0x0D]; /* Sectors per cluster */ - fs->n_fats = fs->win[0x10]; /* Number of FAT copies */ - fs->fatbase = sect + LD_WORD(&(fs->win[0x0E])); /* FAT start sector (physical) */ - fs->n_rootdir = LD_WORD(&(fs->win[0x11])); /* Nmuber of root directory entries */ + /* The logical drive has not been mounted, following code attempts to mount the logical drive */ - fatend = fs->sects_fat * fs->n_fats + fs->fatbase; - fs->dirbase = fatend; /* Directory start sector (physical) */ - fs->database = fs->n_rootdir / 16 + fatend; /* Data start sector (physical) */ + memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */ + stat = disk_initialize(0); /* Initialize low level disk I/O layer */ + if (stat & STA_NOINIT) /* Check if the drive is ready */ + return FR_NOT_READY; +#if _FS_READONLY == 0 + if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; +#endif - maxsect = LD_DWORD(&(fs->win[0x20])); /* Calculate maximum cluster number */ - if (!maxsect) maxsect = LD_WORD(&(fs->win[0x13])); - fs->max_clust = (WORD)((maxsect - fs->database + sect) / fs->sects_clust + 2); + /* Search FAT partition on the drive */ + 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 */ + fmt = check_fs(basesect); /* Check the partition */ + } + } + if (fmt != 2 || fs->win[12] != 2) /* 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]); + 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->max_clust = maxclust = (totalsect /* Last cluster# + 1 */ + - LD_WORD(&fs->win[14]) - fatsize - fs->n_rootdir / 16 + ) / fs->sects_clust + 2; + fmt = FS_FAT12; /* Determins the FAT type */ + if (maxclust >= 0xFF7) fmt = FS_FAT16; +#if _FAT32 == 0 + if (maxclust >= 0xFFF7) return FR_NO_FILESYSTEM; +#else + if (maxclust >= 0xFFF7) fmt = FS_FAT32; + if (fmt == FS_FAT32) + fs->dirbase = LD_DWORD(&fs->win[44]); /* 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; /* FAT type */ + fs->id = ++fsid; /* File system mount ID */ - fs->files = 0; return FR_OK; } -/*-----------------------*/ -/* Open or Create a File */ + +/*-----------------------------------------------------------------------*/ +/* Check if the file/dir object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* FR_OK(0): The id is valid, !=0: Not valid */ + const FATFS *fs, /* Pointer to the file system object */ + WORD id /* id member of the target object to be checked */ +) +{ + if (!fs || (WORD)~fs->id != id) + return FR_INVALID_OBJECT; + if (disk_status(0) & STA_NOINIT) + return FR_NOT_READY; + + return FR_OK; +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +--------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Locical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + BYTE drv, /* Logical drive number to be mounted/unmounted */ + FATFS *fs /* Pointer to new file system object (NULL for unmount)*/ +) +{ + FATFS *fsobj; + + + if (drv) return FR_INVALID_DRIVE; + fsobj = FatFs; + FatFs = fs; + if (fsobj) memset(fsobj, 0, sizeof(FATFS)); + if (fs) memset(fs, 0, sizeof(FATFS)); + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ FRESULT f_open ( - FIL *fp, /* Pointer to the buffer of new file object to create */ - const char *path, /* Pointer to the file path */ + FIL *fp, /* Pointer to the blank file object */ + const char *path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ ) { FRESULT res; BYTE *dir; - DIR dirscan; + DIR dirobj; char fn[8+3+1]; FATFS *fs = FatFs; - if ((res = check_mounted()) != FR_OK) return res; -#ifndef _FS_READONLY - if ((mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) && (disk_status() & STA_PROTECT)) - return FR_WRITE_PROTECTED; +#if _FS_READONLY == 0 + res = auto_mount(&path, mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)); +#else + res = auto_mount(&path, 0); #endif + if (res != FR_OK) return res; - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + /* Trace the file path */ + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ -#ifndef _FS_READONLY +#if _FS_READONLY == 0 /* Create or Open a File */ if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) { - DWORD dw; + CLUST ps, rs; + DWORD tm; if (res != FR_OK) { /* No file, create new */ mode |= FA_CREATE_ALWAYS; if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirscan); /* Reserve a directory entry */ + dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ if (dir == NULL) return FR_DENIED; - memcpy(dir, fn, 8+3); /* Initialize the new entry */ + memset(dir, 0, 32); /* Initialize the new entry */ + memcpy(dir, fn, 8+3); *(dir+12) = fn[11]; - memset(dir+13, 0, 32-13); } else { /* Any object is already existing */ - if ((dir == NULL) || (*(dir+11) & (AM_RDO|AM_DIR))) /* Could not overwrite (R/O or DIR) */ + if (dir == NULL || (*(dir+11) & (AM_RDO|AM_DIR))) /* Could not overwrite (R/O or DIR) */ return FR_DENIED; if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero */ - dw = fs->winsect; /* Remove the cluster chain */ - if (!remove_chain(LD_WORD(dir+26)) || !move_window(dw) ) +#if _FAT32 != 0 + rs = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); + ST_WORD(dir+20, 0); +#else + rs = LD_WORD(dir+26); +#endif + ST_WORD(dir+26, 0); /* cluster = 0 */ + ST_DWORD(dir+28, 0); /* size = 0 */ + fs->winflag = 1; + ps = fs->winsect; /* Remove the cluster chain */ + if (!remove_chain(rs) || !move_window(ps)) return FR_RW_ERROR; - ST_WORD(dir+26, 0); /* cluster = 0 */ - ST_DWORD(dir+28, 0); /* size = 0 */ } } if (mode & FA_CREATE_ALWAYS) { *(dir+11) = AM_ARC; - dw = get_fattime(); - ST_DWORD(dir+14, dw); /* Created time */ - ST_DWORD(dir+22, dw); /* Updated time */ + tm = get_fattime(); + ST_DWORD(dir+14, tm); /* Created time */ + ST_DWORD(dir+22, tm); /* Updated time */ fs->winflag = 1; } } @@ -645,33 +778,35 @@ FRESULT f_open ( else { #endif /* _FS_READONLY */ if (res != FR_OK) return res; /* Trace failed */ - if ((dir == NULL) || (*(dir+11) & AM_DIR)) /* It is a directory */ + if (dir == NULL || (*(dir+11) & AM_DIR)) /* It is a directory */ return FR_NO_FILE; -#ifndef _FS_READONLY +#if _FS_READONLY == 0 if ((mode & FA_WRITE) && (*(dir+11) & AM_RDO)) /* R/O violation */ return FR_DENIED; } #endif -#ifdef _FS_READONLY - fp->flag = mode & FA_READ; -#else +#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 */ - fs->files++; + fp->fs = fs; fp->id = ~fs->id; /* Owner file system object of the file */ return FR_OK; } -/*-----------*/ -/* Read File */ + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ FRESULT f_read ( FIL *fp, /* Pointer to the file object */ @@ -680,19 +815,21 @@ FRESULT f_read ( WORD *br /* Pointer to number of bytes read */ ) { - DWORD sect, ln; - WORD clust, rcnt; + DWORD sect, remain; + WORD rcnt; + CLUST clust; BYTE cc, *rbuff = buff; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = fp->fs; *br = 0; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; /* Check disk ready */ + res = validate(fs, fp->id); + 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) { @@ -700,8 +837,10 @@ FRESULT f_read ( 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) ? fp->org_clust : get_cluster(fp->curr_clust); - if ((clust < 2) || (clust >= fs->max_clust)) goto fr_error; + clust = (fp->fptr == 0) ? + fp->org_clust : get_cluster(fp->curr_clust); + if (clust < 2 || clust >= fs->max_clust) + goto fr_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 */ @@ -710,7 +849,8 @@ FRESULT f_read ( cc = btr / 512; /* When left bytes >= 512, */ if (cc) { /* Read maximum contiguous sectors directly */ if (cc > fp->sect_clust) cc = fp->sect_clust; - if (disk_read(rbuff, sect, cc) != RES_OK) goto fr_error; + if (disk_read(0, rbuff, sect, cc) != RES_OK) + goto fr_error; fp->sect_clust -= cc - 1; fp->curr_sect += cc - 1; rcnt = cc * 512; continue; @@ -731,10 +871,12 @@ fr_error: /* Abort this function due to an unrecoverable error */ -/*------------*/ -/* Write File */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* 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 */ @@ -743,15 +885,17 @@ FRESULT f_write ( ) { DWORD sect; - WORD clust, wcnt; + WORD wcnt; + CLUST clust; BYTE cc; + FRESULT res; const BYTE *wbuff = buff; - FATFS *fs = FatFs; + FATFS *fs = fp->fs; *bw = 0; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + res = validate(fs, fp->id); + 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 */ @@ -769,7 +913,7 @@ 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 < 2 || clust >= fs->max_clust) break; fp->curr_clust = clust; /* Current cluster */ sect = clust2sect(clust); /* Get current sector */ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */ @@ -778,7 +922,8 @@ FRESULT f_write ( cc = btw / 512; /* When left bytes >= 512, */ if (cc) { /* Write maximum contiguous sectors directly */ if (cc > fp->sect_clust) cc = fp->sect_clust; - if (disk_write(wbuff, sect, cc) != RES_OK) goto fw_error; + if (disk_write(0, wbuff, sect, cc) != RES_OK) + goto fw_error; fp->sect_clust -= cc - 1; fp->curr_sect += cc - 1; wcnt = cc * 512; continue; @@ -788,7 +933,8 @@ FRESULT f_write ( fs->winsect = fp->curr_sect; } } - if (!move_window(fp->curr_sect)) goto fw_error; /* Move sector window */ + if (!move_window(fp->curr_sect)) /* Move sector window */ + 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); @@ -807,21 +953,24 @@ fw_error: /* Abort this function due to an unrecoverable error */ -/*-------------------*/ -/* Seek File Pointer */ + +/*-----------------------------------------------------------------------*/ +/* Seek File Pointer */ +/*-----------------------------------------------------------------------*/ FRESULT f_lseek ( FIL *fp, /* Pointer to the file object */ DWORD ofs /* File pointer from top of file */ ) { - WORD clust; + CLUST clust; BYTE sc; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = fp->fs; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + 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 */ @@ -835,7 +984,8 @@ FRESULT f_lseek ( clust = fp->org_clust; /* Seek to current cluster */ while (ofs--) clust = get_cluster(clust); - if ((clust < 2) || (clust >= fs->max_clust)) goto fk_error; + 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 */ } @@ -849,29 +999,36 @@ fk_error: /* Abort this function due to an unrecoverable error */ -/*-------------------------------------------------*/ -/* Synchronize between File and Disk without Close */ -#ifndef _FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Synchronize between File and Disk */ +/*-----------------------------------------------------------------------*/ + +#if _FS_READONLY == 0 FRESULT f_sync ( FIL *fp /* Pointer to the file object */ ) { BYTE *ptr; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = fp->fs; - if (!fs) return FR_NOT_ENABLED; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) - return FR_INCORRECT_DISK_CHANGE; + res = validate(fs, fp->id); + if (res) return res; /* Has the file been written? */ if (fp->flag & FA__WRITTEN) { - if (!move_window(fp->dir_sect)) return FR_RW_ERROR; + /* 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 */ +#if _FAT32 != 0 + ST_WORD(ptr+20, fp->org_clust >> 16); +#endif ST_DWORD(ptr+22, get_fattime()); /* Updated time */ fs->winflag = 1; fp->flag &= ~FA__WRITTEN; @@ -884,8 +1041,10 @@ FRESULT f_sync ( -/*------------*/ -/* Close File */ + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ FRESULT f_close ( FIL *fp /* Pointer to the file object to be closed */ @@ -894,78 +1053,89 @@ FRESULT f_close ( FRESULT res; -#ifndef _FS_READONLY +#if _FS_READONLY == 0 res = f_sync(fp); #else - res = FR_OK; + res = validate(fp->fs, fp->id); #endif - if (res == FR_OK) { - fp->flag = 0; - FatFs->files--; - } + if (res == FR_OK) + fp->fs = NULL; + return res; } + #if _FS_MINIMIZE <= 1 -/*---------------------------*/ -/* Initialize directroy scan */ +/*-----------------------------------------------------------------------*/ +/* Create a directroy object */ +/*-----------------------------------------------------------------------*/ FRESULT f_opendir ( - DIR *scan, /* Pointer to directory object to initialize */ - const char *path /* Pointer to the directory path, null str means the root */ + DIR *dirobj, /* Pointer to directory object to create */ + const char *path /* Pointer to the directory path */ ) { - FRESULT res; BYTE *dir; char fn[8+3+1]; + FRESULT res; + FATFS *fs = FatFs; - if ((res = check_mounted()) != FR_OK) return res; - - res = trace_path(scan, fn, path, &dir); /* Trace the directory path */ + if ((res = auto_mount(&path, 0)) != FR_OK) + return res; + 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 */ - scan->clust = LD_WORD(dir+26); - scan->sect = clust2sect(scan->clust); - scan->index = 0; - } else { /* The entry is not directory */ +#if _FAT32 != 0 + dirobj->clust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); +#else + dirobj->clust = LD_WORD(dir+26); +#endif + dirobj->sect = clust2sect(dirobj->clust); + dirobj->index = 0; + } else { /* The entry is not a directory */ res = FR_NO_FILE; } } + dirobj->id = ~fs->id; } return res; } -/*----------------------------------*/ -/* Read Directory Entry in Sequense */ + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entry in Sequense */ +/*-----------------------------------------------------------------------*/ FRESULT f_readdir ( - DIR *scan, /* Pointer to the directory object */ + DIR *dirobj, /* Pointer to the directory object */ FILINFO *finfo /* Pointer to file information to return */ ) { BYTE *dir, c; - FATFS *fs = FatFs; + FRESULT res; + FATFS *fs = dirobj->fs; - if (!fs) return FR_NOT_ENABLED; + res = validate(fs, dirobj->id); + if (res) return res; + finfo->fname[0] = 0; - if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; - - while (scan->sect) { - if (!move_window(scan->sect)) return FR_RW_ERROR; - dir = &(fs->win[(scan->index & 15) * 32]); /* pointer to the directory entry */ + while (dirobj->sect) { + if (!move_window(dirobj->sect)) + return FR_RW_ERROR; + dir = &fs->win[(dirobj->index & 15) * 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 && c != '.' && !(*(dir+11) & AM_VOL)) /* Is it a valid entry? */ get_fileinfo(finfo, dir); - if (!next_dir_entry(scan)) scan->sect = 0; /* Next entry */ + if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */ if (finfo->fname[0]) break; /* Found valid entry */ } @@ -974,24 +1144,26 @@ FRESULT f_readdir ( + #if _FS_MINIMIZE == 0 -/*-----------------*/ -/* Get File Status */ +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ FRESULT f_stat ( const char *path, /* Pointer to the file path */ FILINFO *finfo /* Pointer to file information to return */ ) { - FRESULT res; BYTE *dir; - DIR dirscan; char fn[8+3+1]; + FRESULT res; + DIR dirobj; - if ((res = check_mounted()) != FR_OK) return res; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + if ((res = auto_mount(&path, 0)) != FR_OK) + return res; + res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */ if (res == FR_OK) /* Trace completed */ get_fileinfo(finfo, dir); @@ -1001,29 +1173,37 @@ FRESULT f_stat ( -#ifndef _FS_READONLY -/*-----------------------------*/ -/* Get Number of Free Clusters */ + +#if _FS_READONLY == 0 +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ FRESULT f_getfree ( - DWORD *nclust /* Pointer to the double word to return number of free clusters */ + const char *drv, /* Logical drive number */ + DWORD *nclust, /* Pointer to the double word to return number of free clusters */ + FATFS **fatfs /* Pointer to pointer to the file system object to return */ ) { DWORD n, sect; - WORD clust; - BYTE f, *p; + CLUST clust; + BYTE fat, f, *p; FRESULT res; - FATFS *fs = FatFs; + FATFS *fs; - if ((res = check_mounted()) != FR_OK) return res; + /* Get drive number */ + if ((res = auto_mount(&drv, 0)) != FR_OK) + return res; + *fatfs = fs = FatFs; /* Count number of free clusters */ + fat = fs->fs_type; n = 0; - if (fs->fs_type == FS_FAT12) { + if (fat == FS_FAT12) { clust = 2; do { - if (get_cluster(clust) == 0) n++; + if ((WORD)get_cluster(clust) == 0) n++; } while (++clust < fs->max_clust); } else { clust = fs->max_clust; @@ -1034,8 +1214,13 @@ FRESULT f_getfree ( if (!move_window(sect++)) return FR_RW_ERROR; p = fs->win; } - if (LD_WORD(p) == 0) n++; - p += 2; f += 1; + if (_FAT32 == 0 || fat == FS_FAT16) { + if (LD_WORD(p) == 0) n++; + p += 2; f += 1; + } else { + if (LD_DWORD(p) == 0) n++; + p += 4; f += 2; + } } while (--clust); } @@ -1045,48 +1230,52 @@ FRESULT f_getfree ( -/*------------------------------*/ -/* Delete a File or a Directory */ + +/*-----------------------------------------------------------------------*/ +/* Delete a File or a Directory */ +/*-----------------------------------------------------------------------*/ FRESULT f_unlink ( const char *path /* Pointer to the file or directory path */ ) { - FRESULT res; BYTE *dir, *sdir; DWORD dsect; - WORD dclust; - DIR dirscan; char fn[8+3+1]; + CLUST dclust; + FRESULT res; + DIR dirobj; FATFS *fs = FatFs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + 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) 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 */ dsect = fs->winsect; +#if _FAT32 != 0 + dclust = ((DWORD)LD_WORD(dir+20) << 16) | LD_WORD(dir+26); +#else dclust = LD_WORD(dir+26); - +#endif if (*(dir+11) & AM_DIR) { /* It is a sub-directory */ - dirscan.clust = dclust; /* Check if the sub-dir is empty or not */ - dirscan.sect = clust2sect(dclust); - dirscan.index = 0; + dirobj.clust = dclust; /* Check if the sub-dir is empty or not */ + dirobj.sect = clust2sect(dclust); + dirobj.index = 0; do { - if (!move_window(dirscan.sect)) return FR_RW_ERROR; - sdir = &(fs->win[(dirscan.index & 15) * 32]); + 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 == 0xE5 || *sdir == '.') && !(*(sdir+11) & AM_VOL)) return FR_DENIED; /* The directory is not empty */ - } while (next_dir_entry(&dirscan)); + } while (next_dir_entry(&dirobj)); } if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */ - *dir = 0xE5; + *dir = 0xE5; fs->winflag = 1; if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ if (!move_window(0)) return FR_RW_ERROR; @@ -1096,31 +1285,32 @@ FRESULT f_unlink ( -/*--------------------*/ -/* Create a Directory */ + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( const char *path /* Pointer to the directory path */ ) { - FRESULT res; BYTE *dir, *w, n; - DWORD sect, dsect, tim; - WORD dclust; - DIR dirscan; char fn[8+3+1]; + DWORD sect, dsect, tim; + CLUST dclust, pclust; + FRESULT res; + DIR dirobj; FATFS *fs = FatFs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + 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) return FR_DENIED; /* Any file or directory is already existing */ if (res != FR_NO_FILE) return res; - dir = reserve_direntry(&dirscan); /* Reserve a directory entry */ + dir = reserve_direntry(&dirobj); /* Reserve a directory entry */ if (dir == NULL) return FR_DENIED; sect = fs->winsect; dsect = clust2sect(dclust = create_chain(0)); /* Get a new cluster for new directory */ @@ -1130,18 +1320,23 @@ FRESULT f_mkdir ( w = fs->win; memset(w, 0, 512); /* Initialize the directory table */ for (n = fs->sects_clust - 1; n; n--) { - if (disk_write(w, dsect+n, 1) != RES_OK) return FR_RW_ERROR; + if (disk_write(0, w, 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); + *w = '.'; *(w+11) = AM_DIR; + tim = get_fattime(); ST_DWORD(w+22, tim); memcpy(w+32, w, 32); *(w+33) = '.'; - ST_WORD(w+26, dclust); - ST_WORD(w+32+26, dirscan.sclust); + pclust = dirobj.sclust; + ST_WORD(w+32+26, pclust); + ST_WORD(w +26, dclust); +#if _FAT32 != 0 + if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0; + ST_WORD(w+32+20, pclust >> 16); + ST_WORD(w +20, dclust >> 16); +#endif fs->winflag = 1; if (!move_window(sect)) return FR_RW_ERROR; @@ -1151,6 +1346,9 @@ FRESULT f_mkdir ( memset(dir+13, 0, 32-13); ST_DWORD(dir+22, tim); /* Crated time */ ST_WORD(dir+26, dclust); /* Table start cluster */ +#if _FAT32 != 0 + ST_WORD(dir+20, dclust >> 16); +#endif fs->winflag = 1; if (!move_window(0)) return FR_RW_ERROR; @@ -1160,8 +1358,10 @@ FRESULT f_mkdir ( -/*-----------------------*/ -/* Change File Attribute */ + +/*-----------------------------------------------------------------------*/ +/* Change File Attribute */ +/*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const char *path, /* Pointer to the file path */ @@ -1171,15 +1371,14 @@ FRESULT f_chmod ( { FRESULT res; BYTE *dir; - DIR dirscan; + DIR dirobj; char fn[8+3+1]; FATFS *fs = FatFs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; - - res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + 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) { @@ -1196,8 +1395,10 @@ FRESULT f_chmod ( -/*-----------------------*/ -/* Rename File/Directory */ + +/*-----------------------------------------------------------------------*/ +/* Rename File/Directory */ +/*-----------------------------------------------------------------------*/ FRESULT f_rename ( const char *path_old, /* Pointer to the old name */ @@ -1207,25 +1408,25 @@ FRESULT f_rename ( FRESULT res; DWORD sect_old; BYTE *dir_old, *dir_new, direntry[32-11]; - DIR dirscan; + DIR dirobj; char fn[8+3+1]; FATFS *fs = FatFs; - if ((res = check_mounted()) != FR_OK) return res; - if (disk_status() & STA_PROTECT) return FR_WRITE_PROTECTED; + if ((res = auto_mount(&path_old, 1)) != FR_OK) + return res; + res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */ - res = trace_path(&dirscan, 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); - res = trace_path(&dirscan, fn, path_new, &dir_new); /* Check new object */ + 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; - dir_new = reserve_direntry(&dirscan); /* Reserve a directory entry */ + 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); @@ -1239,6 +1440,7 @@ FRESULT f_rename ( return FR_OK; } + #endif /* _FS_READONLY */ #endif /* _FS_MINIMIZE == 0 */ #endif /* _FS_MINIMIZE <= 1 */ diff --git a/src/tff.h b/src/tff.h index ad5b736..c5ef8f3 100644 --- a/src/tff.h +++ b/src/tff.h @@ -1,11 +1,11 @@ /*--------------------------------------------------------------------------/ -/ Tiny-FatFs - FAT file system module include file R0.03a (C)ChaN, 2006 +/ Tiny-FatFs - FAT file system module include file R0.04 (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, / research and development under license policy of following trems. / -/ Copyright (C) 2006, ChaN, all right reserved. +/ Copyright (C) 2007, ChaN, all right reserved. / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or @@ -16,23 +16,28 @@ #ifndef _FATFS -#error Don't forget to change these options. +#define _MCU_ENDIAN 0 +/* The _MCU_ENDIAN defines which access method is used to the FAT structure. +/ 1: Enable word access. +/ 2: Disable word access and use byte-by-byte access instead. +/ When the architectural byte order of the MCU is big-endian and/or address +/ miss-aligned access is prohibited, the _MCU_ENDIAN must be set to 2. +/ If it is not the case, it can be set to 1 for good code efficiency. */ -//#define _BYTE_ACC -/* The _BYTE_ACC enables byte-by-byte access for multi-byte variables. This -/ MUST be defined when multi-byte variable is stored in big-endian and/or -/ address miss-aligned access is prohibited. */ - -//#define _FS_READONLY -/* Read only configuration. This removes writing functions, f_write, f_sync, -/ f_unlink, f_mkdir, f_chmod, f_rename and g_getfree. */ +#define _FS_READONLY 0 +/* Setting _FS_READONLY to 1 defines read only configuration. This removes +/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename +/ and useless f_getfree. */ #define _FS_MINIMIZE 0 -/* The _FS_MINIMIZE defines minimization level to remove some functions. -/ 0: Not minimized. +/* 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. */ +/* #define _FAT32 0 */ +/* When enable FAT32 support, set _FAT32 to 1. */ + #define _USE_SJIS /* When _USE_SJIS is defined, Shift-JIS code transparency is enabled, otherwise / only US-ASCII(7bit) code can be accepted as file/directory name. */ @@ -43,48 +48,56 @@ /* Result type for fatfs application interface */ typedef unsigned char FRESULT; +#if _FAT32 == 0 +typedef WORD CLUST; +#else +typedef DWORD CLUST; +#endif /* File system object structure */ typedef struct _FATFS { BYTE fs_type; /* FAT type */ - BYTE files; /* Number of files currently opend */ BYTE sects_clust; /* Sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ - WORD n_rootdir; /* Number of root directory entry */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ - BYTE pad1; + WORD id; /* File system mount ID */ + WORD n_rootdir; /* Number of root directory entries */ DWORD winsect; /* Current sector appearing in the win[] */ - WORD sects_fat; /* Sectors per fat */ - WORD max_clust; /* Maximum cluster# + 1 */ DWORD fatbase; /* FAT start sector */ DWORD dirbase; /* Root directory start sector */ DWORD database; /* Data start sector */ - WORD last_clust; /* Last allocated cluster */ + CLUST sects_fat; /* Sectors per fat */ + CLUST max_clust; /* Maximum cluster# + 1 */ + CLUST last_clust; /* Last allocated cluster */ BYTE win[512]; /* Disk access window for Directory/FAT/File */ } FATFS; /* Directory object structure */ typedef struct _DIR { - WORD sclust; /* Start cluster */ - WORD clust; /* Current cluster */ + 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 { + FATFS* fs; /* Pointer to owner file system */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ - WORD org_clust; /* File start cluster */ - WORD curr_clust; /* Current cluster */ + CLUST org_clust; /* File start cluster */ + CLUST curr_clust; /* Current cluster */ DWORD curr_sect; /* Current sector */ -#ifndef _FS_READONLY +#if _FS_READONLY == 0 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; @@ -104,28 +117,26 @@ typedef struct _FILINFO { /*-----------------------------------------------------*/ /* FatFs module application interface */ -extern FATFS *FatFs; /* Pointer to active file system object */ - +FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */ -FRESULT f_read (FIL*, void*, WORD, WORD*); /* Read file */ -FRESULT f_close (FIL*); /* Close file */ -FRESULT f_lseek (FIL*, DWORD); /* Seek file pointer */ -FRESULT f_opendir (DIR*, const char*); /* Open a directory */ +FRESULT f_read (FIL*, void*, WORD, WORD*); /* Read data from a file */ +FRESULT f_write (FIL*, const void*, WORD, WORD*); /* Write data to a file */ +FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */ +FRESULT f_close (FIL*); /* Close an open file object */ +FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */ FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */ FRESULT f_stat (const char*, FILINFO*); /* Get file status */ -FRESULT f_getfree (DWORD*); /* Get number of free clusters */ -FRESULT f_mountdrv (void); /* Force initialized the file system */ -FRESULT f_write (FIL*, const void*, WORD, WORD*); /* Write file */ +FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */ FRESULT f_sync (FIL*); /* Flush cached data of a writing file */ -FRESULT f_unlink (const char*); /* Delete a file or directory */ -FRESULT f_mkdir (const char*); /* Create a directory */ -FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file attriburte */ -FRESULT f_rename (const char*, const char*); /* Rename a file or directory */ +FRESULT f_unlink (const char*); /* Delete an existing file or directory */ +FRESULT f_mkdir (const char*); /* Create a new directory */ +FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */ +FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */ /* User defined function to give a current time to fatfs module */ -DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: Day(1-31) */ +DWORD get_fattime (void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: Day(1-31) */ /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */ @@ -137,20 +148,21 @@ DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: #define FR_NO_FILE 2 #define FR_NO_PATH 3 #define FR_INVALID_NAME 4 -#define FR_DENIED 5 -#define FR_DISK_FULL 6 -#define FR_RW_ERROR 7 -#define FR_INCORRECT_DISK_CHANGE 8 +#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 -#ifndef _FS_READONLY +#if _FS_READONLY == 0 #define FA_WRITE 0x02 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 @@ -163,6 +175,7 @@ DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: #define FS_FAT12 1 #define FS_FAT16 2 +#define FS_FAT32 3 /* File attribute bits for directory entry */ @@ -179,16 +192,20 @@ DWORD get_fattime(void); /* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: /* Multi-byte word access macros */ -#ifdef _BYTE_ACC +#if _MCU_ENDIAN == 1 /* Use word access */ +#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) +#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) +#else +#if _MCU_ENDIAN == 2 /* Use byte-by-byte access */ #define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) #define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr)) #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 -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) +#error Don't forget to set _MCU_ENDIAN properly! +#endif #endif