commit 4f7376e6aa57973a38d503ed2bfaa1831da556d9 Author: savelij13 Date: Thu Sep 11 08:52:19 2025 +0300 fatfs v0.01 Apr 29, 2006: - First stable version diff --git a/doc/00index_e.html b/doc/00index_e.html new file mode 100644 index 0000000..7ca5d00 --- /dev/null +++ b/doc/00index_e.html @@ -0,0 +1,99 @@ + + + + + + + +FatFs - FAT Files System Module + + + +

FAT File System Module

+
+ +
+ +

FatFs module is an experimental project to implement a FAT file system to small embdded system. Because the module is written in compliance with ANSI C, it can be used for most 8/16 bit microcontrollers, such as PIC, AVR, H8, Z80 and etc..., without any modification. To use the FatFs module, low level disk I/O functions for each recording media must be provided by user. I created two modules in different configurations in consideration of various use. For read only applications, wriiting codes can also be eliminated to reduce the code size.

+ +

Features of FatFs Module

+ +

Features of Tiny-FatFs Module

+ +
+ + +
+

Application Interface

+

FatFs module and Tiny-FatFs module provide following functions.

+ +
+ + +
+

Disk I/O Interface

+

FatFs module and Tiny-FatFs module require following functions to lower layer to read/write to physical disk and to get current time.

+ +
+ + +
+

Resources

+

The FatFs module is opened for education, reserch and development. You can use, modify and republish it for personal, non-profit or profit use without any limitation under your responsibility.

+
+ +
+ + +
+ + diff --git a/doc/00index_j.html b/doc/00index_j.html new file mode 100644 index 0000000..8ef4a2d --- /dev/null +++ b/doc/00index_j.html @@ -0,0 +1,98 @@ + + + + + + + +FatFs - FAT Files System Module + + + +

FATファイルシステム・モジュール

+
+ +
+ +

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

+

FatFsモジュールの特徴

+ +

Tiny-FatFsモジュールの特徴

+ +
+ + +
+

上位レイヤI/F

+

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

+ +
+ + +
+

下位レイヤI/F

+

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

+ +
+ + +
+

資料

+

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

+
+ +
+ + +
+ + diff --git a/doc/css_e.css b/doc/css_e.css new file mode 100644 index 0000000..7a926ef --- /dev/null +++ b/doc/css_e.css @@ -0,0 +1,51 @@ +* {margin: 0; padding: 0; border-width: 0;} +body {margin: 8px; background-color: #e0ffff; font-color: black; line-height: 133%; max-width: 1024px;} +a:link {color: blue;} +a:visited {color: darkmagenta;} +a:hover {background-color: #a0ffff;} +a:active {color: darkmagenta; position: relative; top: 1px; left: 1px;} +abbr {border-width: 1px;} + +p {margin: 0 0 0.3em 1em;} +em {} +strong {} +pre {margin: 1em; line-height: 1.2em; background-color: white;} +tt {margin: 0 0.2em;} +ol {margin: 0 2em;} +ul {margin: 0 2em;} +dl {margin: 0 1em;} +dt {font-family: monospace;} +dl.par dt {margin: 0.5em 0 0 0 ; font-style: italic; } +dl.ret dt {margin: 0.5em 0 0 0 ; font-weight: bold;} +dd {margin: 0 2em;} +hr {border-width: 1px; margin: 1em;} +div.abst {font-family: sans-serif;} +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;} +ul.flat li {list-style-type: none; margin: 0;} +a.imglnk img {border: 1px solid;} +.iequ {white-space: nowrap; font-weight: bold;} +.clr {clear: both;} +.it {font-style: italic;} + +h1 {line-height: 1em; font-size: 2em; font-family: sans-serif; padding: 0.3em 0 0.3em;} +p.hdd {float: right; text-align: right; margin-top: 0.5em;} +hr.hds {clear: both; margin-bottom: 1em;} + +h2 {font-size: 1.5em; font-family: sans-serif; margin: 0 0 0.5em;} +h3 {font-size: 1.5em; font-family: sans-serif; margin: 2em 0 0.5em;} +h4 {font-size: 1.2em; font-family: sans-serif; margin: 1.5em 0 0.2em;} +h5 {font-size: 1em; font-family: sans-serif; margin: 0.5em 0 0em;} +small {font-size: 80%;} +.indent {margin-left: 2em;} + +/* Tables */ +table.lst {margin: 4px; border-collapse: collapse; border-style: solid; border-width: 2px; border-color: black; } +table.lst th {background-color: white; border-style: solid; border-width: 1px 1px 2px; border-color: black; padding: 0 3px; vertical-align: top; white-space: nowrap;} +table.lst td {background-color: white; border-style: solid; border-width: 1px; border-color: black; padding: 0 3px; vertical-align: top; line-height: 1.3em;} +table.lst td:first-child {font-family: monospace;} + +p.foot {clear: both; text-indent: 0; margin: 1em 0.5em 1em;} diff --git a/doc/css_j.css b/doc/css_j.css new file mode 100644 index 0000000..8299ab3 --- /dev/null +++ b/doc/css_j.css @@ -0,0 +1,54 @@ +@charset "Shift_JIS"; +/* Common style sheet for Tech Notes */ + +* {margin: 0; padding: 0; border-width: 0;} +body {margin: 8px; background-color: #e0ffff; font-color: black; line-height: 133%; letter-spacing: 1px; max-width: 1024px;} +a:link {color: blue;} +a:visited {color: darkmagenta;} +a:hover {background-color: #a0ffff;} +a:active {color: darkmagenta; position: relative; top: 1px; left: 1px;} +abbr {border-width: 1px;} + +p {text-indent: 1em; margin: 0 0 0.3em 0.5em;} +em {} +strong {} +pre {margin: 1em; line-height: 1.2em; letter-spacing: 0; background-color: white;} +tt {margin: 0 0.2em; letter-spacing: 0;} +ol {margin: 0 2em;} +ul {margin: 0 2em;} +dl {margin: 0 1em;} +dt {font-family: monospace;} +dl.par dt {margin: 0.5em 0 0 0 ; font-style: italic; letter-spacing: 0;} +dl.ret dt {margin: 0.5em 0 0 0 ; font-family: monospace; letter-spacing: 0; font-weight: bold;} +dd {margin: 0 2em;} +hr {border-width: 1px; margin: 1em;} +div.abst {font-family: "MS Pゴシック",sans-serif;} +div.para {clear: both; font-family: "MS P明朝",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;} +ul.flat li {list-style-type: none; margin: 0;} +a.imglnk img {border: 1px solid;} +.iequ {white-space: nowrap; font-weight: bold;} +.clr {clear: both;} +.it {font-style: italic;} + +h1 {line-height: 1em; font-size: 2em; font-family: sans-serif; padding: 0.3em 0 0.3em;} +p.hdd {float: right; text-align: right; margin-top: 0.5em;} +hr.hds {clear: both; margin-bottom: 1em;} + +h2 {font-size: 1.5em; font-family: sans-serif; margin: 0 0 0.5em;} +h3 {font-size: 1.5em; font-family: sans-serif; margin: 2em 0 0.5em;} +h4 {font-size: 1.2em; font-family: sans-serif; margin: 1.5em 0 0.2em;} +h5 {font-size: 1em; font-family: sans-serif; margin: 0.5em 0 0em;} +small {font-size: 80%;} +.indent {margin-left: 2em;} + +/* Tables */ +table.lst {margin: 4px; border-collapse: collapse; border-style: solid; border-width: 2px; border-color: black; letter-spacing: 0;} +table.lst th {background-color: white; border-style: solid; border-width: 1px 1px 2px; border-color: black; padding: 0 3px; vertical-align: top;} +table.lst td {background-color: white; border-style: solid; border-width: 1px; border-color: black; padding: 0 3px; vertical-align: top; line-height: 1.3em;} +table.lst td:first-child {font-family: monospace; white-space: nowrap;} + +p.foot {clear: both; text-indent: 0; margin: 1em 0.5em 1em;} diff --git a/doc/en/chmod.html b/doc/en/chmod.html new file mode 100644 index 0000000..b715378 --- /dev/null +++ b/doc/en/chmod.html @@ -0,0 +1,88 @@ + + + + + + +FatFs - f_chmod + + + + +
+

f_chmod

+

The f_chmod 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
+);
+
+
+ +
+

Parameter

+
+
FileName
+
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.
+ + + + + + +
AttributeDescription
AR_RDORead only
AR_ARCArchive
AR_SYSSystem
AR_HIDHidden
+
+
AttributeMask
+
Attribute mask that specifies which attribute is changed. The specified aattributes are set or cleard.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
FR_NOFILE
+
Could not find the file.
+
FR_NOPATH
+
Could not find the path.
+
FR_INVALID_NAME
+
The file name 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 in write protected.
+
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 opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

Description

+

The f_chmod changes the attribute of a file or directory. This function is not supported in read-only configuration.

+
+ + +
+

Sample Code

+
+    // Set read-only flag, clear archive flag and others are not changed.
+    f_chmod("/file.txt", AR_RDO, AR_RDO | AR_ARC);
+
+
+ +

Return

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

f_close

+

Function f_close closes a file.

+
+FRESULT f_close (
+  FIL* FileObject     // Pointer to the file object structure
+);
+
+
+ +
+

Parameter

+
+
FileObject
+
Pointer to the file object structure to be closed.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The file has been closed successfuly.
+
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 opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module is not enabled.
+
+
+ + +
+

Description

+

Function f_close closes a file. When the function succeeded, the file object structure can be discarded.

+
+ + +
+

References

+

f_open, f_read, f_write, f_sync, FIL, FATFS

+
+ +

Return

+ + diff --git a/doc/en/dinit.html b/doc/en/dinit.html new file mode 100644 index 0000000..74ff0e4 --- /dev/null +++ b/doc/en/dinit.html @@ -0,0 +1,32 @@ + + + + + + +FatFs - disk_initialize + + + + +
+

disk_initialize

+

The disk_initialize initializes the disk drive.

+
+DSTATUS disk_initialize ();
+
+
+ +
+

Return Values

+

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

+
+ +
+

Description

+

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

+
+ +

Return

+ + diff --git a/doc/en/dread.html b/doc/en/dread.html new file mode 100644 index 0000000..2eaf97b --- /dev/null +++ b/doc/en/dread.html @@ -0,0 +1,54 @@ + + + + + + +FatFs - disk_read + + + + +
+

disk_read

+

The disk_read 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.
+);
+
+
+ +
+

Parameters

+
+
Buffer
+
Pointer to the read buffer to store the read data. SectorCount * 512 bytes is required for the size of the read buffer.
+
SectorNumber
+
Specifies the sector number in logical block address to read from.
+
SectorCount
+
Specifies number of sectors to read. The value can be 1 to 255.
+
+
+ + +
+

Return Value

+
+
RES_OK
+
The function succeeded.
+
RES_ERROR
+
Any error occured during read operation.
+
RES_PARERR
+
Invalid parameter.
+
RES_NOTRDY
+
The disk dirve has not been initialized.
+
+
+ + +

Return

+ + diff --git a/doc/en/dstat.html b/doc/en/dstat.html new file mode 100644 index 0000000..576da2d --- /dev/null +++ b/doc/en/dstat.html @@ -0,0 +1,35 @@ + + + + + + +FatFs - disk_status + + + + +
+

disk_status

+

The disk_status gets the disk status.

+
+DSTATUS disk_status ();
+
+
+ +
+

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.
+
STA_NODISK
+
Indicates that no disk in the drive. It is always cleared on non-removable drive.
+
STA_PROTECTED
+
Indicates that the disk is write protected. It is always cleared on the disk that has not write protect notch.
+
+
+ +

Return

+ + diff --git a/doc/en/dwrite.html b/doc/en/dwrite.html new file mode 100644 index 0000000..ab044bb --- /dev/null +++ b/doc/en/dwrite.html @@ -0,0 +1,62 @@ + + + + + + +FatFs - disk_write + + + + +
+

disk_write

+

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

Parameters

+
+
Buffer
+
Pointer to the data to be written.
+
SectorNumber +
Specifies the sector number in logical block address to write from.
+
SectorCount
+
Specifies number of sectors to write. The value can be 1 to 255.
+
+
+ + +
+

Return Values

+
+
RES_OK
+
The function succeeded.
+
RES_ERROR
+
Any error occured during read operation.
+
RES_WRPRT
+
The disk is write protected.
+
RES_PARERR
+
Invalid parameter.
+
RES_NOTRDY
+
The disk dirve has not been initialized.
+
+
+ + +
+

Description

+

This function is not required in read only configuration.

+
+ + +

Return

+ + diff --git a/doc/en/fattime.html b/doc/en/fattime.html new file mode 100644 index 0000000..faf7dcc --- /dev/null +++ b/doc/en/fattime.html @@ -0,0 +1,49 @@ + + + + + + +FatFs - get_fattime + + + + +
+

get_fattime

+

The get_fattime gets current time.

+
+DWORD get_fattime ();
+
+
+ + +
+

Return Value

+

Currnet time is returned with packed into a DWORD value. The bit field is as follows:

+
+
bit31:25
+
Year from 1980 (0..127)
+
bit24:21
+
Month (1..12)
+
bit20:16
+
Date (1..31)
+
bit15:11
+
Hour (0..23)
+
bit10:5
+
Minute (0..59)
+
bit4:0
+
Second/2 (0..29)
+
+
+ + +
+

Description

+

The function must be 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.

+
+ + +

Return

+ + diff --git a/doc/en/getfree.html b/doc/en/getfree.html new file mode 100644 index 0000000..60826f7 --- /dev/null +++ b/doc/en/getfree.html @@ -0,0 +1,78 @@ + + + + + + +FatFs - f_getfree + + + + +
+

f_getfree

+

The f_getfree gets number of the free clusters.

+
+FRESULT f_getfree (
+  DWORD* Clusters     // Pointer to the variable to store number of free clusters.
+);
+
+
+ +
+

Parameters

+
+
Clusters
+
Pointer to the DWORD variable to store number of free clusters.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded. The *Clusters havs number of free clusters.
+
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, such as a medium change during any file opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

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.

+
+ + +
+

Samples Code

+
+    DWORD clust;
+
+    // Get free clusters
+    res = f_getfree(&clust);
+    if (res) die(res);
+
+    // Get free bytes
+    printf("%lu bytes available on the disk.\n", clust * FatFs->sects_clust * 512);
+
+
+ + +
+

References

+

FATFS

+
+ +

Return

+ + diff --git a/doc/en/lseek.html b/doc/en/lseek.html new file mode 100644 index 0000000..8754204 --- /dev/null +++ b/doc/en/lseek.html @@ -0,0 +1,82 @@ + + + + + + +FatFs - f_lseek + + + + +
+

f_lseek

+

The f_lseek moves the file read/write pointer.

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

Parameters

+
+
FileObject
+
Pointer to the file object structure.
+
Offset
+
Number of bytes where from start of file
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
FR_ALIGN_ERROR
+
Out of alignment. In unbuffered mode, specified offset must be aligned on 512 byte boundary.
+
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 opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
+
+ + +
+

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.

+
+ + +
+

Sample Code

+
+    // Move to offset of 5000 from top of file.
+    res = f_lseek(&file, 5000);
+    if (res) die(res);
+
+    // Move to 3000 bytes front of current offset.
+    res = f_lseek(&file, file.fptr + 3000);
+    if (res) die(res);
+
+    // Move to 2000 bytes back of current offset.
+    res = f_lseek(&file, file.fptr - 2000);
+    if (res) die(res);
+
+
+ + +
+

References

+

f_open, FIL

+
+ +

Return

+ + diff --git a/doc/en/mkdir.html b/doc/en/mkdir.html new file mode 100644 index 0000000..72242ce --- /dev/null +++ b/doc/en/mkdir.html @@ -0,0 +1,80 @@ + + + + + + +FatFs - f_mkdir + + + + +
+

f_mkdir

+

The f_mkdir creates a directory.

+
+FRESULT f_mkdir (
+  const char* DirName // Pointer to the directory name
+);
+
+
+ +
+

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

Return Value

+
+
FR_OK
+
The function succeeded.
+
FR_NOPATH
+
Could not find the path.
+
FR_INVALID_NAME
+
The path name 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 the directory table or disk full.
+
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, such as a medium change during any file opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

Description

+

The f_mkdir creates an empty directory. This function is not supported in read only configuration.

+

+

+
+ + +
+

Sample Code

+
+    res = f_mkdir("/sub1");
+    if (res) die(res);
+    res = f_mkdir("/sub1/sub2");
+    if (res) die(res);
+    res = f_mkdir("/sub1/sub2/sub3");
+    if (res) die(res);
+
+
+ +

Return

+ + diff --git a/doc/en/mountdrv.html b/doc/en/mountdrv.html new file mode 100644 index 0000000..acc96b8 --- /dev/null +++ b/doc/en/mountdrv.html @@ -0,0 +1,56 @@ + + + + + + +FatFs - f_mountdrv + + + + +
+

f_mountdrv

+

The f_mountdrv forces mounted the partition.

+
+FRESULT f_mountdrv ();
+
+
+ +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
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_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

Description

+

The f_mountdrv mounts a partition (initializes FATFS structure) and put all file functions can be used. The file system is mounted (initialized) automatically in accordance with the necessity when any file function is called, so that any initialization is not needed before using file functions. To terminate use of the FatFs module, close all files and clear the global variable FatFs, then the FATFS structure can be discarded. In this function, following process is executed.

+
+ +
+ + +
+

References

+

FATFS

+
+ +

Return

+ + diff --git a/doc/en/open.html b/doc/en/open.html new file mode 100644 index 0000000..e64490e --- /dev/null +++ b/doc/en/open.html @@ -0,0 +1,138 @@ + + + + + + +FatFs - f_open + + + + +
+

f_open

+

The f_open function creates or opens the file and initialize a file object structure 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
+);
+
+
+ +
+

Parameters

+
+
FileObject
+
Pointer to the blank file object structure to be initialized. After the f_open function succeeded, the file can be accessed with the file object structure until it is closed. The member buffer in the structure must be initialized with the address of a 512 bytes file read/write buffer before or immediataly after the f_open function. The initialization is not needed when FA_UNBUFFERED flag has been specified.
+
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.
+
ModeFlags
+
Specifies the type of access and open method for the file. It is specified by a combination of following flags.
+ + + + + + + + +
ValueDescription
FA_READSpecifies read access to the object. Data can be read from the file.
Combine with FA_WRITE for read-write access.
FA_WRITESpecifies write access to the object. Data can be written to the file.
Combine with FA_READ for read-write access.
FA_UNBUFFEREDThis is for only FatFs module. When not specified, the file can be read/written in
stream I/O via the file read/write buffer pointed by member 'buffer' in the file
object. When specified, file read/write buffer is not used and number of bytes
to read/write must be integer multiple of 512.
FA_OPEN_EXISTINGOpens the file. The function fails if the file does not exist.
FA_CREATE_ALWAYSCreates a new file. If the file exists, it is truncated and overwritten.
FA_OPEN_ALWAYSOpens the file, if it exists. If the file does not exist, the function creates the file.
+
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded. The FileObject structure is used for subsequent calls to refer to the file. When close the file, use function f_close().
+
FR_NOFILE
+
Could not find the file.
+
FR_NOPATH
+
Could not find the path.
+
FR_INVALID_NAME
+
The file name 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
+
The disk drive cannot work due to no medium in the drive or any other reason.
+
FR_WRITE_PROTECTED
+
Write mode open or creation under the medium is write protected.
+
FR_RW_ERROR
+
Any error occured in low level disk I/O.
+
FR_INCORRECT_DISK_CHANGE
+
Incorrect disk removal, such as a medium change during any file opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

Description

+

To start to use the FatFs module, prepare a work area (FATFS structure), clear the structure and store the address to the global variable 'FatFs' to allocate the work area to the FatFs module. Then the FatFs module can work.

+

Flags FA_WRITE, FA_CREATE_ALWAYS, FA_OPEN_ALWAYS are not supported in read-only configuration. Flag FA_UNBUFFERED is not supported in Tiny-FatFs.

+
+ + +
+

Sample Code

+
+void main ()
+{
+    FATFS fs;            // FatFs work area
+    FIL fsrc, fdst;      // file structures
+    BYTE fbuff[512*2];   // file r/w buffers (not required for Tiny-FatFs)
+    BYTE buffer[4096];   // file copy buffer
+    FRESULT res;         // FatFs function common result code
+    WORD br, bw;         // File R/W count
+
+
+    // Activate FatFs module
+    memset(&fs, 0, sizeof(FATFS));
+    FatFs = &fs;
+
+    // Open source file
+    fsrc.buffer = fbuff+0;	// (not required for Tiny-FatFs)
+    res = f_open(&fsrc, "/srcfile.dat", FA_OPEN_EXISTING | FA_READ);
+    if (res) die(res);
+
+    // Create destination file
+    fdst.buffer = fbuff+512;	// (not required for Tiny-FatFs)
+    res = f_open(&fdst, "/dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE);
+    if (res) die(res);
+
+    // Copy source to destination
+    for (;;) {
+        res = f_read(&fsrc, buffer, sizeof(buffer), &br);
+        if (res) die(res);
+        if (br == 0) break;
+        res = f_write(&fdst, buffer, br, &bw);
+        if (res) die(res);
+        if (bw < br) break;
+    }
+
+    // Close all files
+    f_close(&fsrc);
+    f_close(&fdst);
+
+    // Deactivate FatFs module
+    FatFs = NULL;
+}
+
+
+ + +
+

References

+

f_read, f_write, f_close, FIL, FATFS

+
+ +

Return

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

f_opendir

+

The f_opendir opens a directory.

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

Parameter

+
+
DirObject
+
Pointer to the blank directory object to be initialized
+
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 "/".
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded. The DirObject structure is used for subsequent calls to read the directory items.
+
FR_NOPATH
+
Could not find the path.
+
FR_INVALID_NAME
+
The path name 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, such as a medium change during any file opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

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.

+
+ + +
+

References

+

f_readdir, DIR

+
+ +

Return

+ + diff --git a/doc/en/read.html b/doc/en/read.html new file mode 100644 index 0000000..e5e091b --- /dev/null +++ b/doc/en/read.html @@ -0,0 +1,72 @@ + + + + + + +FatFs - f_read + + + + +
+

f_read

+

The f_read reads data from a file.

+
+FRESULT f_read (
+  FIL* FileObject,    // Pointer to the file object structure
+  BYTE* 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
+);
+
+
+ +
+

Parameters

+
+
FileObject
+
Pointer to the valid file object structure.
+
Buffer
+
Pointer to the buffer to store read data
+
ByteToRead
+
Number of bytes to read
+
ByteRead
+
Pointer to the WORD variable to return number of bytes read.
+ +
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
FR_DENIED
+
The function denied due to the file has been opened in write only mode.
+
FR_ALIGN_ERROR
+
The file has been opened in unbufferred mode but unaligned access was detected.
+
FR_RW_ERROR
+
Any error 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 has not been enabled.
+
+
+ + +
+

Description

+

The read/write pointer increases in number of bytes read. The ByteRead will be smaller than ByteToRead when the read pointer reached to end of the file or alignment error occured during the read operation. In unbufferred mode, last fractional bytes cannot be read due to FR_ALIGN_ERROR.

+
+ + +
+

References

+

f_open, f_write, f_close, FIL

+
+ +

Return

+ + diff --git a/doc/en/readdir.html b/doc/en/readdir.html new file mode 100644 index 0000000..37995ad --- /dev/null +++ b/doc/en/readdir.html @@ -0,0 +1,88 @@ + + + + + + +FatFs - f_readdir + + + + +
+

f_readdir

+

The f_readdir reads directory items.

+
+FRESULT f_readdir (
+  DIR* DirObject,    // Pointer to the directory object strcture
+  FILINFO* FileInfo  // Pointer to the blank file information structure
+);
+
+
+ +
+

Parameters

+
+
DirObject
+
Pointer to the valid directory object strcture.
+
FileInfo
+
Pointer to the file information structure to store the read item.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
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_NOT_ENABLED
+
FatFs module has not been enabled.
+
+
+ + +
+

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.

+
+ + +
+

Sample Code

+
+void scan_files (char* path)
+{
+    FILINFO finfo;
+    DIR dirs;
+    int i;
+
+    if (f_opendir(&dirs, path) == FR_OK) {
+        i = strlen(path);
+        while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.f_name[0]) {
+            if (finfo.f_attrib & AM_DIR) {
+                sprintf(path+i, "/%s", &finfo.f_name[0]);
+                scan_files(path);
+                *(path+i) = '\0';
+            } else {
+                printf("%s/%s\n", path, &finfo.f_name[0]);
+            }
+        }
+    }
+}
+
+
+ + +
+

References

+

f_opendir, f_stat, FILINFO, DIR

+
+ +

Return

+ + diff --git a/doc/en/sdir.html b/doc/en/sdir.html new file mode 100644 index 0000000..ee15cab --- /dev/null +++ b/doc/en/sdir.html @@ -0,0 +1,37 @@ + + + + + + +FatFs - DIR + + + + +
+

DIR

+

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

+

FatFs

+
+typedef struct _DIR {
+    DWORD   sclust;       // Directory start cluster
+    DWORD   clust;        // Current reading cluster
+    DWORD   sect;         // Current reading sector
+    WORD    index;        // Current index
+} 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
+} DIR;
+
+
+ +

Return

+ + diff --git a/doc/en/sfatfs.html b/doc/en/sfatfs.html new file mode 100644 index 0000000..b4baae7 --- /dev/null +++ b/doc/en/sfatfs.html @@ -0,0 +1,58 @@ + + + + + + +FatFs - FATFS + + + + +
+

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.

+

FatFs

+
+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 (always 0 in FAT32)
+    BYTE    winflag;        // win[] dirty flag (1:must be written back)
+    BYTE    pad1;
+    DWORD   sects_fat;      // Sectors per fat
+    DWORD   max_clust;      // Maximum cluster# + 1
+    DWORD   fatbase;        // FAT start sector
+    DWORD   dirbase;        // Root directory start sector (cluster# for FAT32)
+    DWORD   database;       // Data start sector
+    DWORD   winsect;        // Current sector# appearing in the win[]
+    BYTE    win[512];       // Disk access window for directory and FAT
+} FATFS;
+
+ +

Tiny-FatFs

+
+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    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
+    DWORD   winsect;        // Current sector# appearing in the win[]
+    BYTE    win[512];       // Disk access window for directory, FAT and file
+} FATFS;
+
+
+ +

Return

+ + diff --git a/doc/en/sfile.html b/doc/en/sfile.html new file mode 100644 index 0000000..271fc9e --- /dev/null +++ b/doc/en/sfile.html @@ -0,0 +1,50 @@ + + + + + + +FatFs - FIL + + + + +
+

FIL

+

The FIL structure holds state of a file and it is allocated by an application program. Only buffer member can be initialized 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*   buffer;         // Pointer to 512 byte file R/W buffer
+    BYTE    flag;           // File status flags
+    BYTE    sect_clust;     // Left sectors in current cluster
+} 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
+} FIL;
+
+
+ +

Return

+ + diff --git a/doc/en/sfileinfo.html b/doc/en/sfileinfo.html new file mode 100644 index 0000000..6508fab --- /dev/null +++ b/doc/en/sfileinfo.html @@ -0,0 +1,42 @@ + + + + + + +FatFs - FILINFO + + + + +
+

FILINFO

+

The FILINFO structure holds a file information returned by f_stat() and f_readdir().

+
+typedef struct _FILINFO {
+    DWORD fsize;            // Size
+    WORD fdate;             // Date
+    WORD ftime;             // Time
+    BYTE fattrib;           // Attribute
+    char fname[8+1+3+1];    // Name
+} FILINFO;
+
+
+ +

Members

+
+
fsize
+
Indicates size of the file in unit of byte. This is always zero when it is a directory.
+
fdate
+
Indicates the date that the file was modified or the directory was created.
+
ftime
+
Indicates the time that the file was modified or the directory was created.
+
fattrib
+
Indicates the file/directory attribute in combination of AM_DIR, AM_RDO, AM_HID, AM_SYS and AM_ARC.
+
fname[]
+
Indicates the file/directory name in 8.3 format null-terminated string.
+
+ +

Return

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

f_stat

+

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
+);
+
+
+ +
+

Parameters

+
+
FileName
+
Pointer to the null-terminated string that specifies the file or directory name to get the information .
+
FileInfo
+
Pointer to the FILINFO structure to store the information.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
FR_NOPATH
+
Could not find the path.
+
FR_INVALID_NAME
+
The file name 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, such as a medium change during any file opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +
+

Description

+

The f_stat gets the information of a file or directory. For details of the infomation, refer to the FILINFO structure.

+
+ + +
+

References

+

f_opendir, f_readdir, FILINFO

+
+ +

Return

+ + diff --git a/doc/en/sync.html b/doc/en/sync.html new file mode 100644 index 0000000..5ea8bad --- /dev/null +++ b/doc/en/sync.html @@ -0,0 +1,59 @@ + + + + + + +FatFs - f_sync + + + + +
+

f_sync

+

The f_sync flushes the cached information of the wriiting file.

+
+FRESULT f_sync (
+  FIL* FileObject     // Pointer to the file object structure
+);
+
+
+ +
+

Parameters

+
+
FileObject
+
Pointer to the file object to be flushed.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
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 opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
+
+ + +
+

Description

+

The f_sync writes back the cached information of a file being written into the disk. This is the same function as f_close but the file is left opened and can continue the file access. This is suitable for an application of data logger that opens a file for long time in writing mode. The f_sync of periodic or immediataly after f_wriete can minimize the lost data due to an unintentional black out or disk removal. This function is not supported in read-only configuration.

+
+ + +
+

References

+

f_close

+
+ +

Return

+ + diff --git a/doc/en/unlink.html b/doc/en/unlink.html new file mode 100644 index 0000000..4e386c3 --- /dev/null +++ b/doc/en/unlink.html @@ -0,0 +1,62 @@ + + + + + + +FatFs - f_unlink + + + + +
+

f_unlink

+

The f_unlink removes file or directory.

+
+FRESULT f_unlink (
+  const char* FileName  // Pointer to the file or directory name
+);
+
+
+ +
+

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 configuration, this function is not supported.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
FR_NOFILE
+
Could not find the file or directory.
+
FR_NOPATH
+
Could not find the path.
+
FR_INVALID_NAME
+
The path name is invalid.
+
FR_DENIED
+
The function was denied due to any of following reasons: the file or directory has read-only attribute, the directory is not empty.
+
FR_NOT_READY
+
The disk drive cannot work due to no medium in the drive or any other reason.
+
FR_WRITE_PROTECTED
+
Write mode open or creation under the medium is write protected.
+
FR_RW_ERROR
+
Any error occured in low level disk I/O.
+
FR_INCORRECT_DISK_CHANGE
+
Incorrect disk removal, such as a medium change during any file opend, has been occured.
+
FR_NOT_ENABLED
+
FatFs module has not been enabled.
+
FR_NO_FILESYSTEM
+
There is no valid FAT partition on the disk.
+
+
+ + +

Return

+ + diff --git a/doc/en/write.html b/doc/en/write.html new file mode 100644 index 0000000..54307a0 --- /dev/null +++ b/doc/en/write.html @@ -0,0 +1,72 @@ + + + + + + +FatFs - f_write + + + + +
+

f_write

+

The f_write writes data to a file.

+
+FRESULT f_write (
+  FIL* FileObject,     // Pointer to the file object structure
+  const BYTE* 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
+);
+
+
+ +
+

Parameter

+
+
FileObject
+
Pointer to the valid file object structure.
+
Buffer
+
Pointer to the data to be written.
+
ByteToWrite
+
Specifies number of bytes to write.
+
ByteWritten
+
Pointer to the WORD variable to return number of bytes written.
+
+
+ + +
+

Return Values

+
+
FR_OK
+
The function succeeded.
+
FR_DENIED
+
The function denied due to the file has been opened in read only mode.
+
FR_ALIGN_ERROR
+
The file has been opened in unbufferred mode but unaligned access was detected.
+
FR_RW_ERROR
+
Any error 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 has not been enabled.
+
+
+ + +
+

Description

+

The read/write pointer increases in number of bytes written. The ByteWritten will be smaller than ByteToWrite when disk full or alignment error occured during write function. This function is not supported in read only configuration.

+
+ + +
+

References

+

f_open, f_read, f_close, FIL

+
+ +

Return

+ + diff --git a/doc/ja/chmod.html b/doc/ja/chmod.html new file mode 100644 index 0000000..32a89e7 --- /dev/null +++ b/doc/ja/chmod.html @@ -0,0 +1,88 @@ + + + + + + +FatFs - f_chmod + + + + +
+

f_chmod

+

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

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

パラメータ

+
+
FileName
+
属性変更対象のファイルまたはディレクトリのフルパス名の入った'\0'で終わる文字列を指定します。
+
Attribute
+
設定する属性。指定可能な属性は次の通りで、これらの組み合わせで指定します。指定されなかった属性は解除されます。
+ + + + + + +
意味
AR_RDOリードオンリー
AR_ARCアーカイブ
AR_SYSシステム
AR_HIDヒドゥン
+
+
AttributeMask
+
変更する属性のマスク。指定した属性が設定または解除されます。Attributeと同じ値を使います。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOFILE
+
ファイルが見つからない。
+
FR_NOPATH
+
パスが見つからない。
+
FR_INVALID_NAME
+
パス名が不正。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_WRITE_PROTECTED
+
メディアが書き込み禁止状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATパーテーションが見つからない。
+
+
+ + +
+

解説

+

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

+
+ + +
+

使用例

+
+    // Set read-only flag , clear archive flag and others are not changed.
+    f_chmod("/file.txt", AR_RDO, AR_RDO | AR_ARC);
+
+
+ +

戻る

+ + diff --git a/doc/ja/close.html b/doc/ja/close.html new file mode 100644 index 0000000..90458d9 --- /dev/null +++ b/doc/ja/close.html @@ -0,0 +1,59 @@ + + + + + + +FatFs - f_close + + + + +
+

f_close

+

ファイルを閉じます。

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

パラメータ

+
+
FileObject
+
閉じるファイルオブジェクト構造体へのポインタを指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
+
+ + +
+

解説

+

ファイルを閉じます。関数が正常終了したら、そのファイルオブジェクト構造体を破棄できます。

+
+ + +
+

参照

+f_open, f_read, f_write, f_sync, FIL, FATFS +
+ +

戻る

+ + diff --git a/doc/ja/dinit.html b/doc/ja/dinit.html new file mode 100644 index 0000000..1cf4c80 --- /dev/null +++ b/doc/ja/dinit.html @@ -0,0 +1,32 @@ + + + + + + +FatFs - disk_initialize + + + + +
+

disk_initialize

+

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

+
+DSTATUS disk_initialize ();
+
+
+ +
+

戻り値

+

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

+
+ +
+

解説

+

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

+
+ +

戻る

+ + diff --git a/doc/ja/dread.html b/doc/ja/dread.html new file mode 100644 index 0000000..846bb09 --- /dev/null +++ b/doc/ja/dread.html @@ -0,0 +1,54 @@ + + + + + + +FatFs - disk_read + + + + +
+

disk_read

+

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

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

パラメータ

+
+
Buffer
+
ディスクから読み出したセクタデータを格納するバッファ。SectorCount * 512バイトのサイズが必要です。
+
SectorNumber
+
読み出しを開始するセクタ番号。LBAで指定します。
+
SectorCount
+
読み出すセクタ数。 1〜255で設定します
+
+
+ + +
+

戻り値

+
+
RES_OK
+
正常終了。
+
RES_ERROR
+
読み込み中にエラーが発生した。
+
RES_PARERR
+
パラメータが不正。
+
RES_NOTRDY
+
ドライブが動作可能状態ではない(初期化されていない)。
+
+
+ + +

戻る

+ + diff --git a/doc/ja/dstat.html b/doc/ja/dstat.html new file mode 100644 index 0000000..f1c20fe --- /dev/null +++ b/doc/ja/dstat.html @@ -0,0 +1,35 @@ + + + + + + +FatFs - disk_status + + + + +
+

disk_status

+

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

+
+DSTATUS disk_status ();
+
+
+ +
+

戻り値

+

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

+
+
STA_NOINIT
+
ドライブが初期化されていないことを示すフラグ。電源ONまたはメディアの取り外しでセットされ、disk_initialize()の正常終了でクリア、失敗でセットされます。
+
STA_NODISK
+
メディアがセットされていないことを示すフラグ。メディアが取り外されているときセットされ、メディアがセットされているときクリアされます。ハードディスクでは常にクリアされています。
+
STA_PROTECTED
+
メディアがライトプロテクトされていることを示すフラグ。ライトプロテクトノッチのないメディアでは常にクリアされています。
+
+
+ +

戻る

+ + diff --git a/doc/ja/dwrite.html b/doc/ja/dwrite.html new file mode 100644 index 0000000..1792aaa --- /dev/null +++ b/doc/ja/dwrite.html @@ -0,0 +1,62 @@ + + + + + + +FatFs - disk_write + + + + +
+

disk_write

+

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

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

パラメータ

+
+
Buffer
+
ディスクに書き込むセクタデータを指定します。
+
SectorNumber
+
書き込みを開始するセクタ番号。LBAで指定します。
+
SectorCount
+
書き込むセクタ数。 1〜255で設定します。
+
+
+ + +
+

戻り値

+
+
RES_OK
+
正常終了。
+
RES_ERROR
+
書き込み中にエラーが発生した。
+
RES_WRPRT
+
ディスクが書き込み禁止状態。
+
RES_PARERR
+
パラメータが不正。
+
RES_NOTRDY
+
ドライブが動作可能状態ではない(初期化されていない)。
+
+
+ + +
+

解説

+

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

+
+ + +

戻る

+ + diff --git a/doc/ja/fattime.html b/doc/ja/fattime.html new file mode 100644 index 0000000..fcd49ac --- /dev/null +++ b/doc/ja/fattime.html @@ -0,0 +1,49 @@ + + + + + + +FatFs - get_fattime + + + + +
+

get_fattime

+

現在時刻を取得します。

+
+DWORD get_fattime ();
+
+
+ + +
+

戻り値

+

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

+
+
bit31:25
+
1980年を起点とした年が 0..127 で入ります。
+
bit24:21
+
月が 1..12 の値で入ります。
+
bit20:16
+
日が 1..31 の値で入ります。
+
bit15:11
+
時が 0..23 の値で入ります。
+
bit10:5
+
分が 0..59 の値で入ります。
+
bit4:0
+
秒/2が 0..29 の値で入ります。
+
+
+ + +
+

解説

+

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

+
+ + +

戻る

+ + diff --git a/doc/ja/getfree.html b/doc/ja/getfree.html new file mode 100644 index 0000000..f5066c9 --- /dev/null +++ b/doc/ja/getfree.html @@ -0,0 +1,78 @@ + + + + + + +FatFs - f_getfree + + + + +
+

f_getfree

+

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

+
+FRESULT f_getfree (
+  DWORD* Clusters     // 空きクラスタ数を格納する変数へのポインタ
+);
+
+
+ +
+

パラメータ

+
+
Clusters
+
空きクラスタ数を格納するDWORD変数へのポインタを指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。*Clustersに空きクラスタ数が返されます。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATパーテーションが見つからない。
+
+
+ + +
+

解説

+

ファイルシステム上の空きクラスタ数を取得します。FatFs.sects_clust がクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。

+
+ + +
+

使用例

+
+    DWORD clust;
+
+    // Get free clusters
+    res = f_getfree(&clust);
+    if (res) die(res);
+
+    // Get free bytes
+    printf("%lu bytes available on the disk.\n", clust * FatFs->sects_clust * 512);
+
+
+ + +
+

参照

+FATFS +
+ +

戻る

+ + diff --git a/doc/ja/lseek.html b/doc/ja/lseek.html new file mode 100644 index 0000000..b8b3373 --- /dev/null +++ b/doc/ja/lseek.html @@ -0,0 +1,82 @@ + + + + + + +FatFs - f_lseek + + + + +
+

f_lseek

+

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

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

パラメータ

+
+
FileObject
+
対象となるファイルオブジェクト構造体へのポインタを指定します。
+
Offset
+
移動先のオフセット(R/Wポインタ)値。ファイル先頭からのオフセットをバイト単位で指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_ALIGN_ERROR
+
アンバッファモードで開いたファイルで、512の整数倍でないオフセットを指定した。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
+
+ + +
+

解説

+

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

+
+ + +
+

使用例

+
+    // Move to offset of 5000 from top of file.
+    res = f_lseek(&file, 5000);
+    if (res) die(res);
+
+    // Move to 3000 bytes front of current offset.
+    res = f_lseek(&file, file.fptr + 3000);
+    if (res) die(res);
+
+    // Move to 2000 bytes back of current offset.
+    res = f_lseek(&file, file.fptr - 2000);
+    if (res) die(res);
+
+
+ + +
+

参照

+

f_open, FIL

+
+ +

戻る

+ + diff --git a/doc/ja/mkdir.html b/doc/ja/mkdir.html new file mode 100644 index 0000000..dd67dff --- /dev/null +++ b/doc/ja/mkdir.html @@ -0,0 +1,80 @@ + + + + + + +FatFs - f_mkdir + + + + +
+

f_mkdir

+

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

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

パラメータ

+
+
DirName
+
作成するディレクトリのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。ディレクトリセパレータには'/'を使用します。FatFsモジュールにはカレントディレクトリの概念がないので、パスはルートディレクトリから辿る絶対パスとなります。文字列先頭のスペースはスキップされます。パス先頭の'/'はあってもなくてもかまいません。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOPATH
+
パスが見つからない。
+
FR_INVALID_NAME
+
パス名が不正。
+
FR_DENIED
+
同名のディレクトリやファイルの存在、ディスクやディレクトリエントリが満杯の場合など。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_WRITE_PROTECTED
+
メディアが書き込み禁止状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATパーテーションが見つからない。
+
+
+ + +
+

解説

+

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

+

+

+
+ + +
+

使用例

+
+    res = f_mkdir("/sub1");
+    if (res) die(res);
+    res = f_mkdir("/sub1/sub2");
+    if (res) die(res);
+    res = f_mkdir("/sub1/sub2/sub3");
+    if (res) die(res);
+
+
+ +

戻る

+ + diff --git a/doc/ja/mountdrv.html b/doc/ja/mountdrv.html new file mode 100644 index 0000000..2bd37be --- /dev/null +++ b/doc/ja/mountdrv.html @@ -0,0 +1,57 @@ + + + + + + +FatFs - f_mountdrv + + + + +
+

f_mountdrv

+

ファイルシステムを明示的に初期化します。

+
+FRESULT f_mountdrv ();
+
+
+ +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATファイルシステムが見つからない。
+
+
+ + +
+

解説

+

ファイルシステムを初期化(マウント)して他の全てのファイル関数が使える状態にします。FatFsモジュールではマウント動作はファイル関数呼び出し時に必要に応じて行われるため、通常はこの関数を使用する必要はありません。自動マウント動作中に回復不能エラー(たとえばFR_INCORRECT_DISK_CHANGE)が発生した場合、全てのファイル関数が使えなくなるので、そのときはこの関数で強制マウントして回復します。

+

FatFsモジュールの使用を終了するには、全てのファイルを閉じたあとグローバル変数FatFsをクリアします。その後、ワークエリアは解放できます。f_mountdrv関数内では次の処理が行われます。

+
+ +
+ + +
+

参照

+

FATFS

+
+ +

戻る

+ + diff --git a/doc/ja/open.html b/doc/ja/open.html new file mode 100644 index 0000000..cd95f5d --- /dev/null +++ b/doc/ja/open.html @@ -0,0 +1,141 @@ + + + + + + +FatFs - f_open + + + + +
+

f_open

+

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

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

パラメータ

+
+
FileObject
+
新しく作成するファイルオブジェクト構造体へのポインタを指定します。以降、このファイルを閉じるまでそのファイルオブジェクトを使用してファイル操作をします。構造体メンバのbufferは、オープン前または直後にそのファイルで使用するR/Wバッファへのアドレスで初期化しておく必要があります(FA_UNBUFFEREDを指定した場合はバッファは不要)。
+
FileName
+
作成する (またはオープンする) ファイルのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。ディレクトリセパレータには'/'を使用します。FatFsモジュールにはカレントディレクトリの概念がないので、パスはルートディレクトリから辿る絶対パスとなります。文字列先頭のスペースはスキップされます。パス先頭の'/'はあってもなくてもかまいません。
+
ModeFlags
+
ファイルのアクセス方法やオープン方法を決めるフラグです。このパラメータには次の組み合わせを指定します。
+ + + + + + + + +
意味
FA_READ読み出しモードでオープンします。読み書きする場合はFA_WRITEと共に指定します。
FA_WRITE書き込みモードでオープンします。読み書きする場合はFA_READと共に指定します。
FA_UNBUFFERED +FatFsでのみ指定可。指定するとファイルR/Wバッファを使用せず、メモリを節約できます。
+read/write/seekは512の整数倍単位でなければなりません。指定しない場合は、ファイル
+R/Wバッファ(ファイルオブジェクト構造体メンバのbufferで指定)を使用。
FA_OPEN_EXISTING既存のファイルを開きます。ファイルが無いときはエラーになります。
FA_CREATE_ALWAYSファイルを作成します。既存のファイルがある場合は、サイズを0にしてから開きます。
FA_OPEN_ALWAYS既存のファイルを開きます。ファイルが無いときはファイルを作成します。
+
+
+
+ + +
+

戻り値

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

解説

+

FatFsモジュールの使用を開始するにはまず、FatFsモジュールにワークエリア(構造体FATFS)を割り当てます。確保したワークエリアを0で初期化したあと、FatFsモジュールのグローバル変数FatFsにそのアドレスを代入するだけでモジュールは動作可能状態になり、ファイル関数が使えるようになります。

+

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

+
+ + +
+

使用例

+
+void main ()
+{
+    FATFS fs;            // FatFs work area
+    FIL fsrc, fdst;      // file structures
+    BYTE fbuff[512*2];   // file r/w buffers (not required for Tiny-FatFs)
+    BYTE buffer[4096];   // file copy buffer
+    FRESULT res;         // FatFs function common result code
+    WORD br, bw;         // File R/W count
+
+
+    // Activate FatFs module
+    memset(&fs, 0, sizeof(FATFS));
+    FatFs = &fs;
+
+    // Open source file
+    fsrc.buffer = fbuff+0;	// (not required for Tiny-FatFs)
+    res = f_open(&fsrc, "/srcfile.dat", FA_OPEN_EXISTING | FA_READ);
+    if (res) die(res);
+
+    // Create destination file
+    fdst.buffer = fbuff+512;	// (not required for Tiny-FatFs)
+    res = f_open(&fdst, "/dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE);
+    if (res) die(res);
+
+    // Copy source to destination
+    for (;;) {
+        res = f_read(&fsrc, buffer, sizeof(buffer), &br);
+        if (res) die(res);
+        if (br == 0) break;
+        res = f_write(&fdst, buffer, br, &bw);
+        if (res) die(res);
+        if (bw < br) break;
+    }
+
+    // Close all files
+    f_close(&fsrc);
+    f_close(&fdst);
+
+    // Deactivate FatFs module
+    FatFs = NULL;
+}
+
+
+ + +
+

参照

+

f_read, f_write, f_close, FIL, FATFS

+
+ +

戻る

+ + diff --git a/doc/ja/opendir.html b/doc/ja/opendir.html new file mode 100644 index 0000000..72610c8 --- /dev/null +++ b/doc/ja/opendir.html @@ -0,0 +1,70 @@ + + + + + + +FatFs - f_opendir + + + + +
+

f_opendir

+

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

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

パラメータ

+
+
DirObject
+
初期化するディレクトリオブジェクト構造体へのポインタを指定します。
+
DirName
+
オープンするディレクトリのフルパス名が入った'\0'で終わる文字列へのポインタを指定します。ディレクトリセパレータには'/'を使用します。FatFsモジュールにはカレントディレクトリの概念がないので、パスはルートディレクトリから辿る絶対パスとなります。先頭のスペースはスキップされます。パス先頭の'/'はあってもなくてもかまいませんが、最後のディレクトリ名の後ろに'/'を付けることはできません。ルートディレクトリを開くときは、""または"/"を指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOPATH
+
パスが見つからない。
+
FR_INVALID_NAME
+
パス名が不正。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATパーテーションが見つからない。
+
+
+ + +
+

解説

+

ディレクトリをオープンします。正常終了したら、DirObject構造体を使ってこのディレクトリの項目を順次読み出せます。使用後の処理は必要ありません。DirObject構造体は任意の時点で破棄できます。

+
+ + +
+

参照

+

f_readdir, DIR

+
+ +

戻る

+ + diff --git a/doc/ja/read.html b/doc/ja/read.html new file mode 100644 index 0000000..d745285 --- /dev/null +++ b/doc/ja/read.html @@ -0,0 +1,72 @@ + + + + + + +FatFs - f_read + + + + +
+

f_read

+

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

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

パラメータ

+
+
FileObject
+
ファイルオブジェクト構造体へのポインタを指定します。
+
Buffer
+
読み出したデータを格納するバッファを指すポインタを指定します。
+
ByteToRead
+
読み出すバイト数を指定します。
+
ByteRead
+
実際に読み出されたバイト数を格納する変数を指すポインタを指定します。
+ +
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_DENIED
+
書き込み専用モードで開いたファイルから読み込もうとした。
+
FR_ALIGN_ERROR
+
アンバッファモードで開かれたファイルで、512の整数倍でないアクセスを検出した。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
+
+ + +
+

解説

+

読み込み開始位置は、現在のファイルR/Wポインタからになります。ファイルR/Wポインタは読み込まれたバイト数だけ進みます。読み込み中にファイルの終端に達すると、*ByteReadByteToReadよりも小さくなります。アンバッファモードでは最後の端数バイトを残してFR_ALIGN_ERRORになります。

+
+ + +
+

参照

+

f_open, f_write, f_close, FIL

+
+ +

戻る

+ + diff --git a/doc/ja/readdir.html b/doc/ja/readdir.html new file mode 100644 index 0000000..a9c73cb --- /dev/null +++ b/doc/ja/readdir.html @@ -0,0 +1,88 @@ + + + + + + +FatFs - f_readdir + + + + +
+

f_readdir

+

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

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

パラメータ

+
+
DirObject
+
初期化済みのディレクトリオブジェクト構造体へのポインタを指定します。
+
FileInfo
+
読み出したディレクトリ項目を格納するファイル情報構造体へのポインタを指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
+
+ + +
+

解説

+

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

+
+ + +
+

使用例

+
+void scan_files (char* path)
+{
+    FILINFO finfo;
+    DIR dirs;
+    int i;
+
+    if (f_opendir(&dirs, path) == FR_OK) {
+        i = strlen(path);
+        while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.f_name[0]) {
+            if (finfo.f_attrib & AM_DIR) {
+                sprintf(path+i, "/%s", &finfo.f_name[0]);
+                scan_files(path);
+                *(path+i) = '\0';
+            } else {
+                printf("%s/%s\n", path, &finfo.f_name[0]);
+            }
+        }
+    }
+}
+
+
+ + +
+

参照

+

f_opendir, f_stat, FILINFO, DIR

+
+ +

戻る

+ + diff --git a/doc/ja/sdir.html b/doc/ja/sdir.html new file mode 100644 index 0000000..ee07752 --- /dev/null +++ b/doc/ja/sdir.html @@ -0,0 +1,37 @@ + + + + + + +FatFs - DIR + + + + +
+

DIR

+

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

+

FatFs

+
+typedef struct _DIR {
+    DWORD   sclust;       // Directory start cluster
+    DWORD   clust;        // Current reading cluster
+    DWORD   sect;         // Current reading sector
+    WORD    index;        // Current index
+} 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
+} DIR;
+
+
+ +

戻る

+ + diff --git a/doc/ja/sfatfs.html b/doc/ja/sfatfs.html new file mode 100644 index 0000000..d08b8f0 --- /dev/null +++ b/doc/ja/sfatfs.html @@ -0,0 +1,58 @@ + + + + + + +FatFs - FATFS + + + + +
+

FATFS

+

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

+

FatFs

+
+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;
+    DWORD   sects_fat;      // Sectors per fat
+    DWORD   max_clust;      // Maximum cluster# + 1
+    DWORD   fatbase;        // FAT start sector
+    DWORD   dirbase;        // Root directory start sector (cluster# for FAT32)
+    DWORD   database;       // Data start sector
+    DWORD   winsect;        // Current sector# appearing in the win[]
+    BYTE    win[512];       // Disk access window for Directory/FAT area
+} FATFS;
+
+ +

Tiny-FatFs

+
+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    sects_fat;      // Sectors per fat
+    WORD    max_clust;      // Maximum cluster# + 1
+    DWORD   fatbase;        // FAT start sector
+    DWORD   dirbase;        // Root directory start sector (cluster# for FAT32)
+    DWORD   database;       // Data start sector
+    DWORD   winsect;        // Current sector# appearing in the win[]
+    BYTE    win[512];       // Disk access window
+} FATFS;
+
+
+ +

戻る

+ + diff --git a/doc/ja/sfile.html b/doc/ja/sfile.html new file mode 100644 index 0000000..c2f42a1 --- /dev/null +++ b/doc/ja/sfile.html @@ -0,0 +1,49 @@ + + + + + + +FatFs - FIL + + + + +
+

FIL

+

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

+

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*   buffer;         // Pointer to 512 byte file R/W buffer
+    BYTE    flag;           // File status flags
+    BYTE    sect_clust;     // Left sectors in current cluster
+} 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
+} FIL;
+
+
+ +

戻る

+ + diff --git a/doc/ja/sfileinfo.html b/doc/ja/sfileinfo.html new file mode 100644 index 0000000..bf3261f --- /dev/null +++ b/doc/ja/sfileinfo.html @@ -0,0 +1,42 @@ + + + + + + +FatFs - FILINFO + + + + +
+

FILINFO

+

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
+} FILINFO;
+
+
+ +

メンバ

+
+
fsize
+
ファイルのバイト単位のサイズが格納されます。ディレクトリの場合は常に0です。
+
fdate
+
ファイルの変更された日付、またはディレクトリの作成された日付が格納されます。
+
ftime
+
ファイルの変更された時刻、またはディレクトリの作成された時刻が格納されます。
+
fattrib
+
属性フラグが格納されます。フラグはAM_DIR, AM_RDO, AM_HID, AM_SYS, AM_ARCの組み合わせとなります。
+
fname[]
+
8.3形式の名前が'\0'で終わる文字列として格納されます。
+
+ +

戻る

+ + diff --git a/doc/ja/stat.html b/doc/ja/stat.html new file mode 100644 index 0000000..18ee293 --- /dev/null +++ b/doc/ja/stat.html @@ -0,0 +1,70 @@ + + + + + + +FatFs - f_stat + + + + +
+

f_stat

+

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

パラメータ

+
+
FileName
+
情報を得るファイルまたはディレクトリ名の'\0'で終わる文字列を指すポインタを指定します。
+
FileInfo
+
読み出し結果を格納するファイル情報構造体へのポインタを指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOPATH
+
パスが見つからない。
+
FR_INVALID_NAME
+
パス名が不正。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATパーテーションが見つからない。
+
+
+ + +
+

解説

+

ファイルまたはディレクトリに関する情報を得ます。得られるファイル情報の詳細については FILINFO構造体を参照してください。

+
+ + +
+

参照

+

f_opendir, f_readdir, FILINFO, DIR

+
+ +

戻る

+ + diff --git a/doc/ja/sync.html b/doc/ja/sync.html new file mode 100644 index 0000000..8c1f423 --- /dev/null +++ b/doc/ja/sync.html @@ -0,0 +1,60 @@ + + + + + + +FatFs - f_sync + + + + +
+

f_sync

+

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

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

パラメータ

+
+
FileObject
+
syncするファイルオブジェクト構造体へのポインタを指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
+
+ + +
+

解説

+

書き込み中のファイルのそこまでの状態(R/Wバッファ上のデータ、変更されたFATやディレクトリ項目)をディスクに書き込みます。この関数はファイルクローズのプロセスを実行しますが、ファイルは引き続き開かれたままになり、読み書きを続行できます。ロギングなど、書き込みモードで長時間ファイルが開かれているアプリケーションにおいて、定期的または区切りの良いところでsyncすることにより、不意の電源断やメディアの取り外しにより失われるデータを最小限にします。

+

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

+
+ + +
+

参照

+

f_close

+
+ +

戻る

+ + diff --git a/doc/ja/unlink.html b/doc/ja/unlink.html new file mode 100644 index 0000000..33af9db --- /dev/null +++ b/doc/ja/unlink.html @@ -0,0 +1,67 @@ + + + + + + +FatFs - f_unlink + + + + +
+

f_unlink

+

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

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

パラメータ

+
+
FileName
+
削除対象のファイルまたはディレクトリ名の入った'\0'で終わる文字列へのポインタを指定します。リードオンリー構成ではこの関数はサポートされません。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_NOFILE
+
ファイルが見つからない。
+
FR_NOPATH
+
パスが見つからない。
+
FR_INVALID_NAME
+
パス名が不正。
+
FR_DENIED
+
対象ファイル・ディレクトリがリードオンリー状態、対象ディレクトリが空でない場合など。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_WRITE_PROTECTED
+
メディアが書き込み禁止状態。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_INCORRECT_DISK_CHANGE
+
不正なメディアの取り外しがあった。ファイルを開いたままのメディア交換など。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
FR_NO_FILESYSTEM
+
ディスク上に有効なFATパーテーションが見つからない。
+
+
+ + +
+

解説

+

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

+
+ +

戻る

+ + diff --git a/doc/ja/write.html b/doc/ja/write.html new file mode 100644 index 0000000..d7339c6 --- /dev/null +++ b/doc/ja/write.html @@ -0,0 +1,72 @@ + + + + + + +FatFs - f_write + + + + +
+

f_write

+

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

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

パラメータ

+
+
FileObject
+
ファイルオブジェクト構造体へのポインタを指定します。
+
Buffer
+
書き込むデータを格納したバッファを指すポインタを指定します。
+
ByteToWrite
+
書き込むバイト数を指定します。
+
ByteWritten
+
実際に書き込まれたバイト数を格納する変数を指すポインタを指定します。
+
+
+ + +
+

戻り値

+
+
FR_OK
+
正常終了。
+
FR_DENIED
+
読み込み専用モードで開いたファイルに書き込もうとした。
+
FR_ALIGN_ERROR
+
アンバッファモードで開かれたファイルで、512の整数倍でないアクセスを検出した。
+
FR_RW_ERROR
+
ディスクアクセスでエラーが発生した。
+
FR_NOT_READY
+
メディアがセットされていないなど、ディスクドライブが動作不能状態。
+
FR_NOT_ENABLED
+
FatFsモジュールが停止状態。
+
+
+ + +
+

解説

+

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

+
+ + +
+

参照

+

f_open, f_read, f_close, FIL

+
+ +

戻る

+ + diff --git a/doc/layers.png b/doc/layers.png new file mode 100644 index 0000000..739fadf Binary files /dev/null and b/doc/layers.png differ diff --git a/doc/rw_ata.jpeg b/doc/rw_ata.jpeg new file mode 100644 index 0000000..2b97d93 Binary files /dev/null and b/doc/rw_ata.jpeg differ diff --git a/doc/rw_cfc.jpeg b/doc/rw_cfc.jpeg new file mode 100644 index 0000000..c92d5fe Binary files /dev/null and b/doc/rw_cfc.jpeg differ diff --git a/doc/rw_mmc.jpeg b/doc/rw_mmc.jpeg new file mode 100644 index 0000000..5f8115e Binary files /dev/null and b/doc/rw_mmc.jpeg differ diff --git a/doc/rwtest.png b/doc/rwtest.png new file mode 100644 index 0000000..d2e646f Binary files /dev/null and b/doc/rwtest.png differ diff --git a/src/00readme.txt b/src/00readme.txt new file mode 100644 index 0000000..4c2637c --- /dev/null +++ b/src/00readme.txt @@ -0,0 +1,60 @@ +FatFs/Tiny-FatFs Module Source Files R0.01 (C)ChaN, 2006 + + +Files + + ff.h Common include file for FatFs and application module. + ff.c FatFs module + tff.h Common include file for Tiny-FatFs and application module. + tff.c Tiny-FatFs module + diskio.h Common include file for (Tiny-)FatFs and disk I/O module. + integer.h Alternative type definitions for unsigned integers. + + Low level disk I/O module is not included in this archive because the + FatFs/Tiny-FatFs module is only a generic file system layer and not depend + on any specific storage device. You have to provide a low level disk I/O + module that written to control your storage device. + + + +Configuration Options + + There are several configuration options for various envilonment and requirement. + The configuration options are in include files ff.h and tff.h. + + #define _BYTE_ACC + + 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. + + - Muti-byte integers (short, long) are stored in Big-Endian. + - Address unaligned word access causes an address error or incorrect behavior. + + + #define _FS_READONLY + + When application program does not require any write access, _FS_READONLY can be + defined to eliminate writing code to reduce module size. + + + #define _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. + + + +Agreements + + The FatFs/Tiny-FatFs module is a free software and there is no warranty. + The FatFs/Tiny-FatFs module is opened for education, reserch and development. + You can use, modify and republish it for personal, non-profit or profit use + without any limitation under your responsibility. + + + +Revision History + + Feb 26, 2006 R0.00 Prototype + Apr 29, 2006 R0.01 First stable version diff --git a/src/diskio.h b/src/diskio.h new file mode 100644 index 0000000..2bea802 --- /dev/null +++ b/src/diskio.h @@ -0,0 +1,57 @@ +/*----------------------------------------------------------------------- +/ Low level disk interface modlue include file R0.01 (C)ChaN, 2006 +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIF + +//#define _READONLY /* Define this for read-only use */ + +#include "integer.h" + +typedef unsigned char DSTATUS; +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); +#endif +DRESULT disk_ioctl (BYTE, void*); +void disk_timerproc (); + + +/* Results of Disk Functions (DRESULT) */ + +#define RES_OK 0 /* Successful */ +#define RES_ERROR 1 /* R/W Error */ +#define RES_WRPRT 2 /* Write Protected */ +#define RES_NOTRDY 3 /* Not Ready */ +#define RES_PARERR 4 /* Invalid Parameter */ + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl() */ + +#define GET_SECTORS 1 +#define PUT_IDLE_STATE 2 +#define MMC_GET_CSD 10 +#define MMC_GET_CID 11 +#define MMC_GET_OCR 12 +#define ATA_GET_REV 20 +#define ATA_GET_MODEL 21 + + +#define _DISKIF +#endif diff --git a/src/ff.c b/src/ff.c new file mode 100644 index 0000000..110efb3 --- /dev/null +++ b/src/ff.c @@ -0,0 +1,1202 @@ +/*--------------------------------------------------------------------------/ +/ FatFs - FAT file system module R0.01 (C)ChaN, 2006 +/---------------------------------------------------------------------------/ +/ FatFs module is an experimenal project to implement FAT file system to +/ cheap microcontrollers. This is opened for education, reserch and +/ development. You can use, modify and republish it for non-profit or profit +/ use without any limitation under your responsibility. +/---------------------------------------------------------------------------/ +/ Feb 26, 2006 R0.00 Prototype +/ Apr 29, 2006 R0.01 First stable version +/---------------------------------------------------------------------------*/ + +#include +#include "ff.h" /* FatFs declarations */ +#include "diskio.h" /* Include file for user provided functions */ + + +FATFS *FatFs; /* Pointer to the file system object */ + + +/*------------------------------------------------------------------------- + Module Private Functions +-------------------------------------------------------------------------*/ + +/*----------------------*/ +/* Change Window Offset */ + +static +BOOL move_window ( + DWORD sector /* Sector number to make apperance in the FatFs->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 + BYTE n; + if (fs->winflag) { /* Write back dirty window if needed */ + if (disk_write(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; + } + } + } +#endif + if (sector) { + if (disk_read(fs->win, sector, 1) != RES_OK) return FALSE; + fs->winsect = sector; + } + } + return TRUE; +} + + + +/*---------------------*/ +/* Get Cluster State */ + +static +DWORD get_cluster ( + DWORD clust /* Cluster# to get the link information */ +) +{ + FATFS *fs = FatFs; + + + if ((clust >= 2) && (clust < fs->max_clust)) { /* Valid cluster# */ + switch (fs->fs_type) { + case FS_FAT16 : + if (!move_window(clust / 256 + fs->fatbase)) break; + return LD_WORD(&(fs->win[((WORD)clust * 2) & 511])); + case FS_FAT32 : + if (!move_window(clust / 128 + fs->fatbase)) break; + return LD_DWORD(&(fs->win[((WORD)clust * 4) & 511])); + } + } + return 1; /* Return with 1 means failed */ +} + + + +/*--------------------------*/ +/* Change a Cluster State */ + +#ifndef _FS_READONLY +static +BOOL put_cluster ( + DWORD clust, /* Cluster# to change */ + DWORD val /* New value to mark the cluster */ +) +{ + FATFS *fs = FatFs; + + + switch (fs->fs_type) { + case FS_FAT16 : + if (!move_window(clust / 256 + fs->fatbase)) return FALSE; + ST_WORD(&(fs->win[((WORD)clust * 2) & 511]), (WORD)val); + break; + case FS_FAT32 : + if (!move_window(clust / 128 + fs->fatbase)) return FALSE; + ST_DWORD(&(fs->win[((WORD)clust * 4) & 511]), val); + break; + default : + return FALSE; + } + fs->winflag = 1; + return TRUE; +} +#endif + + + +/*------------------------*/ +/* Remove a Cluster Chain */ + +#ifndef _FS_READONLY +static +BOOL remove_chain ( + DWORD clust /* Cluster# to remove chain from */ +) +{ + DWORD nxt; + + + while ((nxt = get_cluster(clust)) >= 2) { + if (!put_cluster(clust, 0)) return FALSE; + clust = nxt; + } + return TRUE; +} +#endif + + + +/*-----------------------------------*/ +/* Stretch or Create a Cluster Chain */ + +#ifndef _FS_READONLY +static +DWORD create_chain ( + DWORD clust /* Cluster# to stretch, 0 means create new */ +) +{ + DWORD ncl, ccl, mcl = FatFs->max_clust; + + + if (clust == 0) { /* Create new chain */ + ncl = 1; + do { + ncl++; /* Check next cluster */ + if (ncl >= mcl) return 0; /* No free custer was found */ + ccl = get_cluster(ncl); /* Get the cluster status */ + if (ccl == 1) return 0; /* Any error occured */ + } while (ccl); /* Repeat until find a free cluster */ + } + else { /* Stretch existing chain */ + ncl = get_cluster(clust); /* Check the cluster status */ + if (ncl < 2) return 0; /* It is an invalid cluster */ + if (ncl < mcl) return ncl; /* It is already followed by next cluster */ + ncl = clust; /* Search free cluster */ + do { + ncl++; /* Check next cluster */ + if (ncl >= mcl) ncl = 2; /* Wrap around */ + if (ncl == clust) return 0; /* No free custer was found */ + ccl = get_cluster(ncl); /* Get the cluster status */ + if (ccl == 1) return 0; /* Any error occured */ + } while (ccl); /* Repeat until find a free cluster */ + } + + if (!put_cluster(ncl, 0xFFFFFFFF)) return 0; /* Mark the new cluster "in use" */ + if (clust && !put_cluster(clust, ncl)) return 0; /* Link it to previous one if needed */ + + return ncl; /* Return new cluster number */ +} +#endif + + + +/*----------------------------*/ +/* Get Sector# from Cluster# */ + +static +DWORD clust2sect ( + 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; +} + + + +/*------------------------*/ +/* 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[] = "FAT16FAT32"; + FATFS *fs = FatFs; + + + 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_FAT16; + if (!memcmp(&(fs->win[0x52]), &fatsign[5], 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 */ +) +{ + DWORD clust; + WORD idx; + FATFS *fs = FatFs; + + + idx = scan->index + 1; + if ((idx & 15) == 0) { /* Table sector changed? */ + scan->sect++; /* Next sector */ + if (!scan->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 */ + return FALSE; + scan->clust = clust; /* Initialize for new cluster */ + scan->sect = clust2sect(clust); + } + } + } + scan->index = idx; /* Lower 4 bit of scan->index indicates offset in scan->sect */ + return TRUE; +} + + + +/*--------------------------------------*/ +/* Get File Status from Directory Entry */ + +static +void get_fileinfo ( + FILINFO *finfo, /* Ptr to Store the File Information */ + const BYTE *dir /* Ptr to the Directory Entry */ +) +{ + BYTE n, c, a; + char *p; + + + 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; + *p++ = c; + } + if (*(dir+8) != ' ') { /* Convert file name (extension) */ + *p++ = '.'; + for (n = 8; n < 11; n++) { + c = *(dir+n); + if (c == ' ') break; + if ((a & 0x10) && (c >= 'A') && (c <= 'Z')) c += 0x20; + *p++ = c; + } + } + *p = '\0'; + + finfo->fattrib = *(dir+11); /* Attribute */ + finfo->fsize = LD_DWORD(dir+28); /* Size */ + finfo->fdate = LD_WORD(dir+24); /* Date */ + finfo->ftime = LD_WORD(dir+22); /* Time */ +} + + + +/*-------------------------------------------------------------------*/ +/* Pick a Paragraph and Create the Name in Format of Directory Entry */ + +static +char make_dirfile ( + const char **path, /* Pointer to the file path pointer */ + char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */ +) +{ + BYTE n, t, c, a, b; + + + memset(dirname, ' ', 8+3); /* Fill buffer with spaces */ + a = 0; b = 0x18; /* NT flag */ + n = 0; t = 8; + for (;;) { + c = *(*path)++; + if (c <= ' ') c = 0; + if ((c == 0) || (c == '/')) { /* Reached to end of str or directory separator */ + if (n == 0) break; + dirname[11] = a & b; return c; + } + if (c == '.') { + 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 */ + c = 0x05; + a ^= 1; goto md_l2; + } + if ((c >= 0x7F) && (c <= 0x80)) break; /* Reject \x7F \x80 */ +#else + if (c >= 0x7F) goto md_l1; /* Accept \x7F-0xFF */ +#endif + if (c == '"') break; /* Reject " */ + if (c <= ')') goto md_l1; /* Accept ! # $ % & ' ( ) */ + if (c <= ',') break; /* Reject * + , */ + if (c <= '9') goto md_l1; /* Accept - 0-9 */ + 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')) + (t == 8) ? (b &= ~0x08) : (b &= ~0x10); + if ((c >= 'a') && (c <= 'z')) { /* Convert to upper case */ + c -= 0x20; + (t == 8) ? (a |= 0x08) : (a |= 0x10); + } + } + md_l1: + a &= ~1; + md_l2: + if (n >= t) break; + dirname[n++] = c; + } + return 1; +} + + + +/*-------------------*/ +/* 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 */ + const char *path, /* Full-path string to trace a file or directory */ + BYTE **dir /* Directory pointer in Win[] to retutn */ +) +{ + DWORD clust; + char ds; + BYTE *dptr = NULL; + FATFS *fs = FatFs; + + /* Initialize directory object */ + clust = fs->dirbase; + if (fs->fs_type == FS_FAT32) { + scan->clust = scan->sclust = clust; + scan->sect = clust2sect(clust); + } else { + scan->clust = scan->sclust = 0; + scan->sect = clust; + } + scan->index = 0; + + while ((*path == ' ') || (*path == '/')) path++; /* Skip leading spaces */ + if ((BYTE)*path < ' ') { /* Null path means the root directory */ + *dir = NULL; return FR_OK; + } + + for (;;) { + 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? */ + return !ds ? FR_NO_FILE : FR_NO_PATH; + if ( (*dptr != 0xE5) /* Matched? */ + && !(*(dptr+11) & AM_VOL) + && !memcmp(dptr, fn, 8+3) ) break; + if (!next_dir_entry(scan)) /* Next directory pointer */ + return !ds ? FR_NO_FILE : FR_NO_PATH; + } + if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */ + if (!(*(dptr+11) & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */ + clust = ((DWORD)LD_WORD(dptr+20) << 16) | LD_WORD(dptr+26); /* Get cluster# of the directory */ + scan->clust = scan->sclust = clust; /* Restart scan with the new directory */ + scan->sect = clust2sect(clust); + scan->index = 0; + } +} + + + +/*---------------------------*/ +/* Reserve a Directory Entry */ + +#ifndef _FS_READONLY +static +BYTE* reserve_direntry ( + DIR *scan /* Target directory to create new entry */ +) +{ + DWORD clust, sector; + BYTE c, n, *dptr; + FATFS *fs = FatFs; + + + /* Re-initialize directory object */ + clust = scan->sclust; + if (clust) { /* Dyanmic directory table */ + scan->clust = clust; + scan->sect = clust2sect(clust); + } else { /* Static directory table */ + scan->sect = fs->dirbase; + } + scan->index = 0; + + do { + if (!move_window(scan->sect)) return NULL; + dptr = &(fs->win[(scan->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 */ + /* 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; + + 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; + sector++; + } + fs->winflag = 1; + return fs->win; +} +#endif + + + +/*-----------------------------------------*/ +/* Make Sure that the File System is Valid */ + +static +FRESULT check_mounted () +{ + FATFS *fs = FatFs; + + + 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 */ +} + + + + + +/*--------------------------------------------------------------------------*/ +/* Public Funciotns */ +/*--------------------------------------------------------------------------*/ + + +/*----------------------------------------------------------*/ +/* Load File System Information and Initialize FatFs Module */ + +FRESULT f_mountdrv () +{ + BYTE fat; + DWORD sect, fatend; + FATFS *fs = FatFs; + + + 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 a pri-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 */ + } + } + 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 */ + + fatend = fs->sects_fat * fs->n_fats + fs->fatbase; + if (fat == FS_FAT32) { + fs->dirbase = LD_DWORD(&(fs->win[0x2C])); /* Directory start cluster */ + fs->database = fatend; /* Data start sector (physical) */ + } else { + fs->dirbase = fatend; /* Directory start sector (physical) */ + fs->database = fs->n_rootdir / 16 + fatend; /* Data start sector (physical) */ + } + fs->max_clust = /* Maximum cluster number */ + (LD_DWORD(&(fs->win[0x20])) - fs->database + sect) / fs->sects_clust + 2; + + return FR_OK; +} + + + +/*-----------------------------*/ +/* Get Number of Free Clusters */ + +FRESULT f_getfree ( + DWORD *nclust /* Pointer to the double word to return number of free clusters */ +) +{ + DWORD n, clust, sect; + BYTE m, *ptr, fat; + FRESULT res; + FATFS *fs = FatFs; + + + if ((res = check_mounted()) != FR_OK) return res; + fat = fs->fs_type; + + /* Count number of free clusters */ + n = m = clust = 0; + ptr = NULL; + sect = fs->fatbase; + do { + if (m == 0) { + if (!move_window(sect++)) return FR_RW_ERROR; + ptr = fs->win; + } + if (fat == FS_FAT32) { + if (LD_DWORD(ptr) == 0) n++; + ptr += 4; m += 2; + } else { + if (LD_WORD(ptr) == 0) n++; + ptr += 2; m++; + } + clust++; + } while (clust < fs->max_clust); + + *nclust = n; + 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 */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + BYTE *dir; + DIR dirscan; + 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)) && (disk_status() & STA_PROTECT)) + return FR_WRITE_PROTECTED; +#endif + + res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + +#ifndef _FS_READONLY + /* Create or Open a File */ + if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) { + DWORD dw; + 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 */ + if (dir == NULL) return FR_DENIED; + memcpy(dir, fn, 8+3); /* Initialize the new entry */ + *(dir+12) = fn[11]; + memset(dir+13, 0, 32-13); + } else { /* File already exists */ + 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; + ST_WORD(dir+20, 0); 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 */ + fs->winflag = 1; + } + } + /* Open a File */ + else { +#endif + if (res != FR_OK) return res; /* Trace failed */ + if ((dir == NULL) || (*(dir+11) & AM_DIR)) /* It is a directory */ + return FR_NO_FILE; +#ifndef _FS_READONLY + if ((mode & FA_WRITE) && (*(dir+11) & AM_RDO)) /* R/O violation */ + return FR_DENIED; + } +#endif + +#ifdef _FS_READONLY + fp->flag = mode & (FA_UNBUFFERED|FA_READ); +#else + fp->flag = mode & (FA_UNBUFFERED|FA_WRITE|FA_READ); + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dir; +#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++; + return FR_OK; +} + + + +/*-----------*/ +/* Read File */ + +FRESULT f_read ( + FIL *fp, /* Pointer to the file object */ + BYTE *buff, /* Pointer to data buffer */ + WORD btr, /* Number of bytes to read */ + WORD *br /* Pointer to number of bytes read */ +) +{ + DWORD clust, sect, ln; + WORD rcnt; + BYTE cc; + FATFS *fs = FatFs; + + + *br = 0; + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; /* Check disk ready */ + 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 = ln; /* Truncate read count by number of bytes left */ + + for ( ; btr; /* Repeat until all data transferred */ + buff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if ((fp->fptr & 511) == 0) { /* On the sector boundary */ + if (--(fp->sect_clust)) { /* Decrement sector counter */ + sect = fp->curr_sect + 1; /* Next sector */ + } else { /* Next cluster */ + 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); /* Current sector */ + fp->sect_clust = fs->sects_clust; /* Re-initialize the sector counter */ + } +#ifndef _FS_READONLY + 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; + fp->flag &= ~FA__DIRTY; + } +#endif + fp->curr_sect = sect; /* Update current sector */ + cc = btr / 512; /* When left bytes >= 512 */ + if (cc) { /* Read maximum contiguous sectors */ + if (cc > fp->sect_clust) cc = fp->sect_clust; + if (disk_read(buff, sect, cc) != RES_OK) goto fr_error; + fp->sect_clust -= cc - 1; + fp->curr_sect += cc - 1; + rcnt = cc * 512; continue; + } + if (fp->flag & FA_UNBUFFERED) /* Reject unaligned access when unbuffered mode */ + return FR_ALIGN_ERROR; + if (disk_read(fp->buffer, sect, 1) != RES_OK) /* Load the sector into file I/O buffer */ + goto fr_error; + } + rcnt = 512 - (fp->fptr & 511); /* Copy fractional bytes from file I/O buffer */ + if (rcnt > btr) rcnt = btr; + memcpy(buff, &fp->buffer[fp->fptr & 511], rcnt); + } + + return FR_OK; + +fr_error: /* Abort this file due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} + + + +/*------------*/ +/* Write File */ + +#ifndef _FS_READONLY +FRESULT f_write ( + FIL *fp, /* Pointer to the file object */ + const BYTE *buff, /* Pointer to the data to be written */ + WORD btw, /* Number of bytes to write */ + WORD *bw /* Pointer to number of bytes written */ +) +{ + DWORD clust, sect; + WORD wcnt; + BYTE cc; + FATFS *fs = FatFs; + + + *bw = 0; + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + 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 */ + + for ( ; btw; /* Repeat until all data transferred */ + buff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { + if ((fp->fptr & 511) == 0) { /* On the sector boundary */ + if (--(fp->sect_clust)) { /* Decrement sector counter */ + sect = fp->curr_sect + 1; /* Next sector */ + } else { /* Next cluster */ + if (fp->fptr == 0) { /* Top of the file */ + clust = fp->org_clust; + if (clust == 0) /* No cluster is created */ + fp->org_clust = clust = create_chain(0); /* Create a new cluster chain */ + } 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; + fp->curr_clust = clust; /* Current cluster */ + sect = clust2sect(clust); /* Current sector */ + fp->sect_clust = fs->sects_clust; /* Re-initialize the 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; + fp->flag &= ~FA__DIRTY; + } + fp->curr_sect = sect; /* Update current sector */ + cc = btw / 512; /* When left bytes >= 512 */ + if (cc) { /* Write maximum contiguous sectors */ + if (cc > fp->sect_clust) cc = fp->sect_clust; + if (disk_write(buff, sect, cc) != RES_OK) goto fw_error; + fp->sect_clust -= cc - 1; + fp->curr_sect += cc - 1; + wcnt = cc * 512; continue; + } + if (fp->flag & FA_UNBUFFERED) /* Reject unalighend access when unbuffered mode */ + return FR_ALIGN_ERROR; + if ((fp->fptr < fp->fsize) && /* Fill sector buffer with file data if needed */ + (disk_read(fp->buffer, sect, 1) != RES_OK)) + goto fw_error; + } + wcnt = 512 - (fp->fptr & 511); /* Copy fractional bytes to file I/O buffer */ + if (wcnt > btw) wcnt = btw; + memcpy(&fp->buffer[fp->fptr & 511], buff, wcnt); + fp->flag |= FA__DIRTY; + } + + if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ + fp->flag |= FA__WRITTEN; /* Set file changed flag */ + return FR_OK; + +fw_error: /* Abort this file due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} +#endif + + + +/*-------------------*/ +/* Seek File Pointer */ + +FRESULT f_lseek ( + FIL *fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + DWORD clust; + BYTE sc; + FATFS *fs = FatFs; + + + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + if (fp->flag & FA__ERROR) return FR_RW_ERROR; +#ifndef _FS_READONLY + 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; + fp->flag &= ~FA__DIRTY; + } +#endif + if (ofs > fp->fsize) ofs = fp->fsize; /* Clip offset by file size */ + if ((ofs & 511) && (fp->flag & FA_UNBUFFERED)) return FR_ALIGN_ERROR; + fp->fptr = ofs; fp->sect_clust = 1; /* Re-initialize file pointer */ + + /* Seek file pinter if needed */ + if (ofs) { + ofs = (ofs - 1) / 512; /* Calcurate current sector */ + sc = fs->sects_clust; /* Number of sectors in a cluster */ + fp->sect_clust = sc - (ofs % sc); /* Calcurate sector counter */ + ofs /= sc; /* Number of clusters to skip */ + clust = fp->org_clust; /* Seek to current cluster */ + while (ofs--) + clust = get_cluster(clust); + if ((clust < 2) || (clust >= fs->max_clust)) goto fk_error; + fp->curr_clust = clust; + fp->curr_sect = clust2sect(clust) + sc - fp->sect_clust; /* Current sector */ + if (fp->fptr & 511) { /* Load currnet sector if needed */ + if (disk_read(fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fk_error; + } + } + + return FR_OK; + +fk_error: /* Abort this file due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} + + + +/*-------------------------------------------------*/ +/* Synchronize between File and Disk without Close */ + +#ifndef _FS_READONLY +FRESULT f_sync ( + FIL *fp /* Pointer to the file object */ +) +{ + BYTE *ptr; + FATFS *fs = FatFs; + + + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) + return FR_INCORRECT_DISK_CHANGE; + + /* 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; + fp->flag &= ~FA__DIRTY; + } + /* 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 */ + ST_WORD(ptr+20, fp->org_clust >> 16); + ST_DWORD(ptr+22, get_fattime()); /* Updated time */ + fs->winflag = 1; + fp->flag &= ~FA__WRITTEN; + } + if (!move_window(0)) return FR_RW_ERROR; + + return FR_OK; +} +#endif + + + +/*------------*/ +/* Close File */ + +FRESULT f_close ( + FIL *fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + + +#ifndef _FS_READONLY + res = f_sync(fp); +#else + res = FR_OK; +#endif + if (res == FR_OK) { + fp->flag = 0; + FatFs->files--; + } + return res; +} + + + +/*------------------------------*/ +/* Delete a File or a Directory */ + +#ifndef _FS_READONLY +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; + + + 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 != 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; + 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; + do { + if (!move_window(dirscan.sect)) return FR_RW_ERROR; + sdir = &(fs->win[(dirscan.index & 15) * 32]); + if (*sdir == 0) break; + if (!((*sdir == 0xE5) || (*sdir == '.')) && !(*(sdir+11) & AM_VOL)) + return FR_DENIED; /* The directory is not empty */ + } while (next_dir_entry(&dirscan)); + } + + if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ + if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry deleted */ + *dir = 0xE5; fs->winflag = 1; + if (!move_window(0)) return FR_RW_ERROR; + + return FR_OK; +} +#endif + + + +/*--------------------*/ +/* Create a Directory */ + +#ifndef _FS_READONLY +FRESULT f_mkdir ( + const char *path /* Pointer to the directory path */ +) +{ + FRESULT res; + BYTE *dir, *w, n; + DWORD sect, dsect, dclust, tim; + DIR dirscan; + 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 == 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 */ + if (dir == NULL) return FR_DENIED; + sect = fs->winsect; + dsect = clust2sect(dclust = create_chain(0)); /* Get a new cluster for new directory */ + if (!dsect) return FR_DENIED; + if (!move_window(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; + } + + fs->winsect = dsect; /* Create dot directories */ + memset(w, ' ', 8+3); + *w = '.'; + *(w+11) = AM_DIR; + tim = get_fattime(); + ST_DWORD(w+22, tim); + memcpy(w+32, w, 32); *(w+33) = '.'; + ST_WORD(w+26, dclust); + ST_WORD(w+20, dclust >> 16); + ST_WORD(w+32+26, dirscan.sclust); + ST_WORD(w+32+20, dirscan.sclust >> 16); + fs->winflag = 1; + + if (!move_window(sect)) return FR_RW_ERROR; + memcpy(dir, fn, 8+3); /* Initialize the new entry */ + *(dir+11) = AM_DIR; + *(dir+12) = fn[11]; + memset(dir+13, 0, 32-13); + ST_DWORD(dir+22, tim); /* Crated time */ + ST_WORD(dir+26, dclust); /* Table start cluster */ + ST_WORD(dir+20, dclust >> 16); + fs->winflag = 1; + + if (!move_window(0)) return FR_RW_ERROR; + + return FR_OK; +} +#endif + + + +/*---------------------------*/ +/* Initialize directroy scan */ + +FRESULT f_opendir ( + DIR *scan, /* Pointer to directory object to initialize */ + const char *path /* Pointer to the directory path, null str means the root */ +) +{ + FRESULT res; + BYTE *dir; + char fn[8+3+1]; + + + if ((res = check_mounted()) != FR_OK) return res; + + res = trace_path(scan, 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 a file */ + res = FR_NO_PATH; + } + } + } + return res; +} + + + +/*----------------------------------*/ +/* Read Directory Entry in Sequense */ + +FRESULT f_readdir ( + DIR *scan, /* Pointer to the directory object */ + FILINFO *finfo /* Pointer to file information to return */ +) +{ + BYTE *dir, c; + FATFS *fs = FatFs; + + + if (!fs) return FR_NOT_ENABLED; + 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 */ + 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? */ + get_fileinfo(finfo, dir); + if (!next_dir_entry(scan)) scan->sect = 0; /* Next entry */ + if (finfo->fname[0]) break; /* Found valid entry */ + } + + return FR_OK; +} + + + +/*-----------------*/ +/* 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]; + + + if ((res = check_mounted()) != FR_OK) return res; + + res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + + if (res == FR_OK) /* Trace completed */ + get_fileinfo(finfo, dir); + + return res; +} + + + +/*-----------------------*/ +/* Change File Attribute */ + +#ifndef _FS_READONLY +FRESULT f_chmod ( + const char *path, /* Pointer to the file path */ + BYTE value, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + BYTE *dir; + DIR dirscan; + 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 == FR_OK) { /* Trace completed */ + if (dir == NULL) { + res = FR_NO_FILE; + } else { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + *(dir+11) = (value & mask) | (*(dir+11) & ~mask); /* Apply attribute change */ + fs->winflag = 1; + if(!move_window(0)) res = FR_RW_ERROR; + } + } + return res; +} +#endif + + diff --git a/src/ff.h b/src/ff.h new file mode 100644 index 0000000..663377d --- /dev/null +++ b/src/ff.h @@ -0,0 +1,186 @@ +/*--------------------------------------------------------------------------/ +/ FatFs - FAT file system module include file R0.01 (C)ChaN, 2006 +/---------------------------------------------------------------------------/ +/ FatFs module is an experimenal project to implement FAT file system to +/ cheap microcontrollers. This is opened for education, reserch and +/ development. You can use it for non-profit or profit use without any +/ limitation under your responsibility. +/---------------------------------------------------------------------------/ +/ Feb 26, 2006 R0.00 Prototype +/ Apr 29, 2006 R0.01 First stable version +/---------------------------------------------------------------------------*/ + +#ifndef _FATFS + +//#define _BYTE_ACC +/* This enables byte-by-byte access for multi-byte variables */ +/* It must be defined on the big-endian processor, or to prevent address error */ + +//#define _FS_READONLY +/* This removes writing code for read-only applications */ + +#define _USE_SJIS +/* This enables Shift-JIS code transparency, or only US-ASCII file name can be accepted */ + + +#include "integer.h" + + +/* Result type for fatfs application interface */ +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; + DWORD sects_fat; // Sectors per fat + DWORD max_clust; // Maximum cluster# + 1 + DWORD fatbase; // FAT start sector + DWORD dirbase; // Root directory start sector (cluster# for FAT32) + DWORD database; // Data start sector + DWORD winsect; // Current sector appearing in the win[] + BYTE win[512]; // Disk access window for Directory/FAT area +} FATFS; + + +/* Directory object structure */ +typedef struct _DIR { + DWORD sclust; // Start cluster + DWORD clust; // Current cluster + DWORD sect; // Current sector + WORD index; // Current index +} DIR; + + +/* File object structure */ +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 +#ifndef _FS_READONLY + DWORD dir_sect; // Sector containing the directory entry + BYTE* dir_ptr; // Ponter to the directory entry in the window +#endif + BYTE* buffer; // Pointer to 512 byte file R/W buffer + BYTE flag; // File status flags + BYTE sect_clust; // Left sectors in cluster +} FIL; + + +/* File status structure */ +typedef struct _FILINFO { + DWORD fsize; // Size + WORD fdate; // Date + WORD ftime; // Time + BYTE fattrib; // Attribute + char fname[8+1+3+1]; // Name (8.3 format) +} FILINFO; + + + +/*-----------------------------------------------------*/ +/* FatFs module application interface */ + +extern FATFS *FatFs; // Pointer to active file system object + +FRESULT f_open (FIL*, const char*, BYTE); // Open or create a file +FRESULT f_read (FIL*, BYTE*, WORD, WORD*); // Read file +FRESULT f_close (FIL*); // Close file +FRESULT f_lseek (FIL*, DWORD); // Seek file pointer +FRESULT f_opendir (DIR*, const char*); // Initialize to read a 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 (); // Force initialized the file system +#ifndef _FS_READONLY +FRESULT f_write (FIL*, const BYTE*, WORD, WORD*); // Write file +FRESULT f_sync (FIL*); // Flush cached information 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 +#endif + + +/* User defined function to give a current time to fatfs module */ + +#ifndef _FS_READONLY +DWORD get_fattime(); // 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) +#endif + + + +/* File function return code */ + +#define FR_OK 0 +#define FR_NOT_READY 1 +#define FR_NO_FILE 2 +#define FR_NO_PATH 3 +#define FR_INVALID_NAME 4 +#define FR_DENIED 5 +#define FR_DISK_FULL 6 +#define FR_RW_ERROR 7 +#define FR_ALIGN_ERROR 8 +#define FR_INCORRECT_DISK_CHANGE 9 +#define FR_WRITE_PROTECTED 10 +#define FR_NOT_ENABLED 11 +#define FR_NO_FILESYSTEM 12 + + +/* File access control and file status flags */ + +#define FA_READ 0x01 +#define FA_UNBUFFERED 0x04 +#define FA_OPEN_EXISTING 0x00 +#ifndef _FS_READONLY +#define FA_WRITE 0x02 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA__WRITTEN 0x20 +#define FA__DIRTY 0x40 +#endif +#define FA__ERROR 0x80 + + +/* FAT type signature (fs_type) */ + +#define FS_FAT16 1 +#define FS_FAT32 2 + + +/* File attribute mask for directory entry */ + +#define AM_RDO 0x01 // Read Only +#define AM_HID 0x02 // Hidden +#define AM_SYS 0x04 // System +#define AM_VOL 0x08 // Volume Label +#define AM_DIR 0x10 // Directory +#define AM_ARC 0x20 // Archive + + + +/* Multi-byte word access macros */ + +#ifdef _BYTE_ACC +#define LD_WORD(ptr) (((WORD)*(BYTE*)(ptr+1)<<8)|*(ptr)) +#define LD_DWORD(ptr) (((DWORD)*(BYTE*)(ptr+3)<<24)|((DWORD)*(BYTE*)(ptr+2)<<16)|((WORD)*(BYTE*)(ptr+1)<<8)|*(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(BYTE*)(ptr)=val; *(BYTE*)(ptr+1)=val>>8 +#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=val; *(BYTE*)(ptr+1)=val>>8; *(BYTE*)(ptr+2)=val>>16; *(BYTE*)(ptr+3)=val>>24 +#else +#define LD_WORD(ptr) (*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(val) +#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(val) +#endif + + +#define _FATFS +#endif diff --git a/src/integer.h b/src/integer.h new file mode 100644 index 0000000..651f34e --- /dev/null +++ b/src/integer.h @@ -0,0 +1,12 @@ +#ifndef _INTEGER + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +typedef unsigned char BOOL; +#define FALSE 0 +#define TRUE 1 + +#define _INTEGER +#endif diff --git a/src/tff.c b/src/tff.c new file mode 100644 index 0000000..e6c4fb9 --- /dev/null +++ b/src/tff.c @@ -0,0 +1,1141 @@ +/*--------------------------------------------------------------------------/ +/ Tiny FatFs - FAT file system module R0.01 (C)ChaN, 2006 +/---------------------------------------------------------------------------/ +/ FatFs module is an experimenal project to implement FAT file system to +/ cheap microcontrollers. This is opened for education, reserch and +/ development. You can use, modify and republish it for non-profit or profit +/ use without any limitation under your responsibility. +/---------------------------------------------------------------------------/ +/ Feb 26, 2006 R0.00 Prototype +/ Apr 29, 2006 R0.01 First stable version +/---------------------------------------------------------------------------*/ + + +#include +#include "tff.h" /* Tiny-FatFs declarations */ +#include "diskio.h" /* Include file for user provided functions */ + + +FATFS *FatFs; /* Pointer to the file system object */ + + +/*------------------------------------------------------------------------- + Module Private Functions +-------------------------------------------------------------------------*/ + +/*----------------------*/ +/* Change Window Offset */ + +static +BOOL move_window ( + DWORD sector /* Sector number to make apperance in the FatFs->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 + BYTE n; + if (fs->winflag) { /* Write back dirty window if needed */ + if (disk_write(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; + } + } + } +#endif + if (sector) { + if (disk_read(fs->win, sector, 1) != RES_OK) return FALSE; + fs->winsect = sector; + } + } + return TRUE; +} + + + +/*---------------------*/ +/* Get a Cluster State */ + +static +DWORD get_cluster (WORD clust) /* Cluster# to get the link information */ +{ + FATFS *fs = FatFs; + + + if ((clust >= 2) && (clust < fs->max_clust)) { /* Valid cluster# */ + if (fs->fs_type == FS_FAT16) { + if (move_window(clust / 256 + fs->fatbase)) + return LD_WORD(&(fs->win[(clust * 2) & 511])); + } + } + return 1; /* Return with 1 means failed */ +} + + + +/*------------------------*/ +/* Change a Cluster State */ + +#ifndef _FS_READONLY +static +BOOL put_cluster ( + WORD clust, /* Cluster# to change */ + WORD val /* New value to mark the cluster */ +) +{ + FATFS *fs = FatFs; + + + if (fs->fs_type != FS_FAT16) return FALSE; + if (!move_window(clust / 256 + fs->fatbase)) return FALSE; + ST_WORD(&(fs->win[((WORD)clust * 2) & 511]), (WORD)val); + + fs->winflag = 1; + return TRUE; +} +#endif + + + +/*------------------------*/ +/* Remove a Cluster Chain */ + +#ifndef _FS_READONLY +static +BOOL remove_chain ( + WORD clust /* Cluster# to remove chain from */ +) +{ + WORD nxt; + + + while ((nxt = get_cluster(clust)) >= 2) { + if (!put_cluster(clust, 0)) return FALSE; + clust = nxt; + } + return TRUE; +} +#endif + + + +/*-----------------------------------*/ +/* Stretch or Create a Cluster Chain */ + +#ifndef _FS_READONLY +static +DWORD create_chain ( + WORD clust /* Cluster# to stretch, 0 means create new */ +) +{ + WORD ncl, ccl, mcl = FatFs->max_clust; + + + if (clust == 0) { /* Create new chain */ + ncl = 1; + do { + ncl++; /* Check next cluster */ + if (ncl >= mcl) return 0; /* No free custer was found */ + ccl = get_cluster(ncl); /* Get the cluster status */ + if (ccl == 1) return 0; /* Any error occured */ + } while (ccl); /* Repeat until find a free cluster */ + } + else { /* Stretch existing chain */ + ncl = get_cluster(clust); /* Check the cluster status */ + if (ncl < 2) return 0; /* It is an invalid cluster */ + if (ncl < mcl) return ncl; /* It is already followed by next cluster */ + ncl = clust; /* Search free cluster */ + do { + ncl++; /* Check next cluster */ + if (ncl >= mcl) ncl = 2; /* Wrap around */ + if (ncl == clust) return 0; /* No free custer was found */ + ccl = get_cluster(ncl); /* Get the cluster status */ + if (ccl == 1) return 0; /* Any error occured */ + } while (ccl); /* Repeat until find a free cluster */ + } + + if (!put_cluster(ncl, 0xFFFF)) return 0; /* Mark the new cluster "in use" */ + if (clust && !put_cluster(clust, ncl)) return 0; /* Link it to previous one if needed */ + + return ncl; /* Return new cluster number */ +} +#endif + + + +/*----------------------------*/ +/* Get Sector# from Cluster# */ + +static +DWORD clust2sect ( + WORD clust /* Cluster# to be converted */ +) +{ + FATFS *fs = FatFs; + + + clust -= 2; + if (clust >= fs->max_clust) return 0; /* Invalid cluster# */ + return (DWORD)clust * fs->sects_clust + fs->database; +} + + + +/*------------------------*/ +/* 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[] = "FAT16"; + FATFS *fs = FatFs; + + + 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_FAT16; + } + } + return 0; +} + + + +/*--------------------------------*/ +/* Move Directory Pointer to Next */ + +static +BOOL next_dir_entry ( + DIR *scan /* Pointer to directory object */ +) +{ + WORD clust; + WORD idx; + FATFS *fs = FatFs; + + + idx = scan->index + 1; + if ((idx & 15) == 0) { /* Table sector changed? */ + scan->sect++; /* Next sector */ + if (!scan->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 */ + return FALSE; + scan->clust = clust; /* Initialize for new cluster */ + scan->sect = clust2sect(clust); + } + } + } + scan->index = idx; /* Lower 4 bit of scan->index indicates offset in scan->sect */ + return TRUE; +} + + + +/*--------------------------------------*/ +/* Get File Status from Directory Entry */ + +static +void get_fileinfo ( + FILINFO *finfo, /* Ptr to Store the File Information */ + const BYTE *dir /* Ptr to the Directory Entry */ +) +{ + BYTE n, c, a; + char *p; + + + 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; + *p++ = c; + } + if (*(dir+8) != ' ') { /* Convert file name (extension) */ + *p++ = '.'; + for (n = 8; n < 11; n++) { + c = *(dir+n); + if (c == ' ') break; + if ((a & 0x10) && (c >= 'A') && (c <= 'Z')) c += 0x20; + *p++ = c; + } + } + *p = '\0'; + + finfo->fattrib = *(dir+11); /* Attribute */ + finfo->fsize = LD_DWORD(dir+28); /* Size */ + finfo->fdate = LD_WORD(dir+24); /* Date */ + finfo->ftime = LD_WORD(dir+22); /* Time */ +} + + + +/*-----------------------------------------------------*/ +/* Pick a Paragraph and Create Name in Directory Entry */ + +static +char make_dirfile ( + const char **path, /* Pointer to the file path pointer */ + char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */ +) +{ + BYTE n, t, c, a, b; + + + memset(dirname, ' ', 8+3); /* Fill buffer with spaces */ + a = 0; b = 0x18; /* NT flag */ + n = 0; t = 8; + for (;;) { + c = *(*path)++; + if (c <= ' ') c = 0; + if ((c == 0) || (c == '/')) { /* Reached to end of str or directory separator */ + if (n == 0) break; + dirname[11] = a & b; return c; + } + if (c == '.') { + 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 */ + c = 0x05; + a ^= 1; goto md_l2; + } + if ((c >= 0x7F) && (c <= 0x80)) break; /* Reject \x7F \x80 */ +#else + if (c >= 0x7F) goto md_l1; /* Accept \x7F-0xFF */ +#endif + if (c == '"') break; /* Reject " */ + if (c <= ')') goto md_l1; /* Accept ! # $ % & ' ( ) */ + if (c <= ',') break; /* Reject * + , */ + if (c <= '9') goto md_l1; /* Accept - 0-9 */ + 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')) + (t == 8) ? (b &= ~0x08) : (b &= ~0x10); + if ((c >= 'a') && (c <= 'z')) { /* Convert to upper case */ + c -= 0x20; + (t == 8) ? (a |= 0x08) : (a |= 0x10); + } + } + md_l1: + a &= ~1; + md_l2: + if (n >= t) break; + dirname[n++] = c; + } + return 1; +} + + + +/*-------------------*/ +/* 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 */ + const char *path, /* Full-path string to trace a file or directory */ + BYTE **dir /* Directory pointer in Win[] to retutn */ +) +{ + WORD clust; + char ds; + BYTE *dptr = NULL; + FATFS *fs = FatFs; + + /* Initialize directory object */ + clust = fs->dirbase; + scan->clust = scan->sclust = 0; + scan->sect = clust; + scan->index = 0; + + while ((*path == ' ') || (*path == '/')) path++; /* Skip leading spaces */ + if ((BYTE)*path < ' ') { /* Null path means the root directory */ + *dir = NULL; return FR_OK; + } + + for (;;) { + 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? */ + return !ds ? FR_NO_FILE : FR_NO_PATH; + if ( (*dptr != 0xE5) /* Matched? */ + && !(*(dptr+11) & AM_VOL) + && !memcmp(dptr, fn, 8+3) ) break; + if (!next_dir_entry(scan)) /* 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; + } +} + + + +/*---------------------------*/ +/* Reserve a Directory Entry */ + +#ifndef _FS_READONLY +static +BYTE* reserve_direntry ( + DIR *scan /* Target directory to create new entry */ +) +{ + WORD clust; + DWORD sector; + BYTE c, n, *dptr; + FATFS *fs = FatFs; + + + /* Re-initialize directory object */ + clust = scan->sclust; + if (clust) { /* Dyanmic directory table */ + scan->clust = clust; + scan->sect = clust2sect(clust); + } else { /* Static directory table */ + scan->sect = fs->dirbase; + } + scan->index = 0; + + do { + if (!move_window(scan->sect)) return NULL; + dptr = &(fs->win[(scan->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 */ + /* 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; + + 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; + sector++; + } + fs->winflag = 1; + return fs->win; +} +#endif + + + +/*-----------------------------------------*/ +/* Make Sure that the File System is Valid */ + +static +FRESULT check_mounted () +{ + FATFS *fs = FatFs; + + + 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 */ +} + + + + + +/*--------------------------------------------------------------------------*/ +/* Public Funciotns */ +/*--------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------*/ +/* Load File System Information and Initialize the Module */ + +FRESULT f_mountdrv () +{ + BYTE fat; + DWORD sect, fatend; + FATFS *fs = FatFs; + + + 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 */ + } + } + 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 */ + + 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) */ + fs->max_clust = /* Maximum cluster number */ + (LD_DWORD(&(fs->win[0x20])) - fs->database + sect) / fs->sects_clust + 2; + + fs->files = 0; + return FR_OK; +} + + + +/*-----------------------------*/ +/* Get Number of Free Clusters */ + +FRESULT f_getfree ( + DWORD *nclust /* Pointer to the double word to return number of free clusters */ +) +{ + WORD clust; + DWORD n, sect; + BYTE m, *ptr, fat; + FRESULT res; + FATFS *fs = FatFs; + + + if ((res = check_mounted()) != FR_OK) return res; + fat = fs->fs_type; + + /* Count number of free clusters */ + n = clust = m = 0; + ptr = NULL; + sect = fs->fatbase; + do { + if (m == 0) { + if (!move_window(sect++)) return FR_RW_ERROR; + ptr = fs->win; + } + if (LD_WORD(ptr) == 0) n++; + ptr += 2; m++; + clust++; + } while (clust < fs->max_clust); + + *nclust = n; + return FR_OK; +} + + + +/*---------------------*/ +/* Open or Create File */ + +FRESULT f_open ( + FIL *fp, /* Pointer to the buffer of new file object to create */ + const char *path, /* Pointer to the file path */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + BYTE *dir; + DIR dirscan; + 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; +#endif + + res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + +#ifndef _FS_READONLY + /* Create or Open a File */ + if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS)) { + DWORD dw; + 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 */ + if (dir == NULL) return FR_DENIED; + memcpy(dir, fn, 8+3); /* Initialize the new entry */ + *(dir+12) = fn[11]; + memset(dir+13, 0, 32-13); + } else { /* File already exists */ + 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) ) + 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 */ + fs->winflag = 1; + } + } + /* Open a File */ + else { +#endif + if (res != FR_OK) return res; /* Trace failed */ + if ((dir == NULL) || (*(dir+11) & AM_DIR)) /* It is a directory */ + return FR_NO_FILE; +#ifndef _FS_READONLY + if ((mode & FA_WRITE) && (*(dir+11) & AM_RDO)) /* R/O violation */ + return FR_DENIED; + } +#endif + +#ifdef _FS_READONLY + fp->flag = mode & FA_READ; +#else + fp->flag = mode & (FA_WRITE|FA_READ); + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dir; +#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++; + return FR_OK; +} + + + +/*-----------*/ +/* Read File */ + +FRESULT f_read ( + FIL *fp, /* Pointer to the file object */ + BYTE *buff, /* Pointer to data buffer */ + WORD btr, /* Number of bytes to read */ + WORD *br /* Pointer to number of bytes read */ +) +{ + DWORD sect, ln; + WORD clust, rcnt; + BYTE cc; + FATFS *fs = FatFs; + + + *br = 0; + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; /* Check disk ready */ + 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 = ln; /* Truncate read count by number of bytes left */ + + for ( ; btr; /* Repeat until all data transferred */ + buff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if ((fp->fptr & 511) == 0) { /* On the sector boundary */ + if (--(fp->sect_clust)) { /* Decrement sector counter */ + sect = fp->curr_sect + 1; /* Next sector */ + } else { /* Next cluster */ + 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); /* Current sector */ + fp->sect_clust = fs->sects_clust; /* Re-initialize the sector counter */ + } + fp->curr_sect = sect; /* Update current sector */ + cc = btr / 512; /* When left bytes >= 512 */ + if (cc) { /* Read maximum contiguous sectors */ + if (cc > fp->sect_clust) cc = fp->sect_clust; + if (disk_read(buff, sect, cc) != RES_OK) goto fr_error; + fp->sect_clust -= cc - 1; + fp->curr_sect += cc - 1; + rcnt = cc * 512; continue; + } + } + if (!move_window(fp->curr_sect)) goto fr_error; /* Move sector window */ + rcnt = 512 - (fp->fptr & 511); /* Copy fractional bytes from sector window */ + if (rcnt > btr) rcnt = btr; + memcpy(buff, &fs->win[fp->fptr & 511], rcnt); + } + + return FR_OK; + +fr_error: /* Abort this function due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} + + + +/*------------*/ +/* Write File */ + +#ifndef _FS_READONLY +FRESULT f_write ( + FIL *fp, /* Pointer to the file object */ + const BYTE *buff, /* Pointer to the data to be written */ + WORD btw, /* Number of bytes to write */ + WORD *bw /* Pointer to number of bytes written */ +) +{ + DWORD sect; + WORD clust, wcnt; + BYTE cc; + FATFS *fs = FatFs; + + + *bw = 0; + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + 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 */ + + for ( ; btw; /* Repeat until all data transferred */ + buff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { + if ((fp->fptr & 511) == 0) { /* On the sector boundary */ + if (--(fp->sect_clust)) { /* Decrement sector counter */ + sect = fp->curr_sect + 1; /* Next sector */ + } else { /* Next cluster */ + if (fp->fptr == 0) { /* Top of the file */ + clust = fp->org_clust; + if (clust == 0) /* No cluster is created */ + fp->org_clust = clust = create_chain(0); /* Create a new cluster chain */ + } 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; + fp->curr_clust = clust; /* Current cluster */ + sect = clust2sect(clust); /* Current sector */ + fp->sect_clust = fs->sects_clust; /* Re-initialize the sector counter */ + } + fp->curr_sect = sect; /* Update current sector */ + cc = btw / 512; /* When left bytes >= 512 */ + if (cc) { /* Write maximum contiguous sectors */ + if (cc > fp->sect_clust) cc = fp->sect_clust; + if (disk_write(buff, 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) { /* Flush R/W window if needed */ + if (!move_window(0)) goto fw_error; + fs->winsect = fp->curr_sect; + } + } + if (!move_window(fp->curr_sect)) goto fw_error; /* Move sector window */ + wcnt = 512 - (fp->fptr & 511); /* Copy fractional bytes bytes to sector window */ + if (wcnt > btw) wcnt = btw; + memcpy(&fs->win[fp->fptr & 511], buff, wcnt); + fs->winflag = 1; + } + + if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ + fp->flag |= FA__WRITTEN; /* Set file changed flag */ + return FR_OK; + +fw_error: /* Abort this function due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} +#endif + + + +/*-------------------*/ +/* Seek File Pointer */ + +FRESULT f_lseek ( + FIL *fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + WORD clust; + BYTE sc; + FATFS *fs = FatFs; + + + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) return FR_NOT_READY; + if (fp->flag & FA__ERROR) return FR_RW_ERROR; + if (ofs > fp->fsize) ofs = fp->fsize; /* Clip offset by file size */ + fp->fptr = ofs; fp->sect_clust = 1; /* Re-initialize file pointer */ + + /* Seek file pinter if needed */ + if (ofs) { + ofs = (ofs - 1) / 512; /* Calcurate current sector */ + sc = fs->sects_clust; /* Number of sectors in a cluster */ + fp->sect_clust = sc - (ofs % sc); /* Calcurate sector counter */ + ofs /= sc; /* Number of clusters to skip */ + clust = fp->org_clust; /* Seek to current cluster */ + while (ofs--) + clust = get_cluster(clust); + if ((clust < 2) || (clust >= fs->max_clust)) goto fk_error; + fp->curr_clust = clust; + fp->curr_sect = clust2sect(clust) + sc - fp->sect_clust; /* Current sector */ + } + + return FR_OK; + +fk_error: /* Abort this function due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} + + + +/*-------------------------------------------------*/ +/* Synchronize between File and Disk without Close */ + +#ifndef _FS_READONLY +FRESULT f_sync ( + FIL *fp /* Pointer to the file object */ +) +{ + BYTE *ptr; + FATFS *fs = FatFs; + + + if (!fs) return FR_NOT_ENABLED; + if ((disk_status() & STA_NOINIT) || !fs->fs_type) + return FR_INCORRECT_DISK_CHANGE; + + /* Has the file been written? */ + if (fp->flag & FA__WRITTEN) { + 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 */ + ST_DWORD(ptr+22, get_fattime()); /* Updated time */ + fs->winflag = 1; + fp->flag &= ~FA__WRITTEN; + } + if (!move_window(0)) return FR_RW_ERROR; + + return FR_OK; +} +#endif + + + +/*------------*/ +/* Close File */ + +FRESULT f_close ( + FIL *fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + + +#ifndef _FS_READONLY + res = f_sync(fp); +#else + res = FR_OK; +#endif + if (res == FR_OK) { + fp->flag = 0; + FatFs->files--; + } + return res; +} + + + +/*----------------------------*/ +/* Delete a File or Directory */ + +#ifndef _FS_READONLY +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]; + 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 != 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; + dclust = 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; + do { + if (!move_window(dirscan.sect)) return FR_RW_ERROR; + sdir = &(fs->win[(dirscan.index & 15) * 32]); + if (*sdir == 0) break; + if (!((*sdir == 0xE5) || (*sdir == '.')) && !(*(sdir+11) & AM_VOL)) + return FR_DENIED; /* The directory is not empty */ + } while (next_dir_entry(&dirscan)); + } + + if (!remove_chain(dclust)) return FR_RW_ERROR; /* Remove the cluster chain */ + if (!move_window(dsect)) return FR_RW_ERROR; /* Mark the directory entry deleted */ + *dir = 0xE5; fs->winflag = 1; + if (!move_window(0)) return FR_RW_ERROR; + + return FR_OK; +} +#endif + + + +/*--------------------*/ +/* Create a Directory */ + +#ifndef _FS_READONLY +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]; + 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 == 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 */ + if (dir == NULL) return FR_DENIED; + sect = fs->winsect; + dsect = clust2sect(dclust = create_chain(0)); /* Get a new cluster for new directory */ + if (!dsect) return FR_DENIED; + if (!move_window(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; + } + + fs->winsect = dsect; /* Create dot directories */ + memset(w, ' ', 8+3); + *w = '.'; + *(w+11) = AM_DIR; + tim = get_fattime(); + ST_DWORD(w+22, tim); + memcpy(w+32, w, 32); *(w+33) = '.'; + ST_WORD(w+26, dclust); + ST_WORD(w+32+26, dirscan.sclust); + fs->winflag = 1; + + if (!move_window(sect)) return FR_RW_ERROR; + memcpy(dir, fn, 8+3); /* Initialize the new entry */ + *(dir+11) = AM_DIR; + *(dir+12) = fn[11]; + memset(dir+13, 0, 32-13); + ST_DWORD(dir+22, tim); /* Crated time */ + ST_WORD(dir+26, dclust); /* Table start cluster */ + fs->winflag = 1; + + if (!move_window(0)) return FR_RW_ERROR; + + return FR_OK; +} +#endif + + + +/*---------------------------*/ +/* Initialize directroy scan */ + +FRESULT f_opendir ( + DIR *scan, /* Pointer to directory object to initialize */ + const char *path /* Pointer to the directory path, null str means the root */ +) +{ + FRESULT res; + BYTE *dir; + char fn[8+3+1]; + + + if ((res = check_mounted()) != FR_OK) return res; + + res = trace_path(scan, 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 a file */ + res = FR_NO_PATH; + } + } + } + return res; +} + + + +/*----------------------------------*/ +/* Read Directory Entry in Sequense */ + +FRESULT f_readdir ( + DIR *scan, /* Pointer to the directory object */ + FILINFO *finfo /* Pointer to file information to return */ +) +{ + BYTE *dir, c; + FATFS *fs = FatFs; + + + if (!fs) return FR_NOT_ENABLED; + 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 */ + 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? */ + get_fileinfo(finfo, dir); + if (!next_dir_entry(scan)) scan->sect = 0; /* Next entry */ + if (finfo->fname[0]) break; /* Found valid entry */ + } + + return FR_OK; +} + + + +/*-----------------*/ +/* 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]; + + + if ((res = check_mounted()) != FR_OK) return res; + + res = trace_path(&dirscan, fn, path, &dir); /* Trace the file path */ + + if (res == FR_OK) /* Trace completed */ + get_fileinfo(finfo, dir); + + return res; +} + + + +/*-----------------------*/ +/* Change File Attribute */ + +#ifndef _FS_READONLY +FRESULT f_chmod ( + const char *path, /* Pointer to the file path */ + BYTE value, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + BYTE *dir; + DIR dirscan; + 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 == FR_OK) { /* Trace completed */ + if (dir == NULL) { + res = FR_NO_FILE; + } else { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + *(dir+11) = (value & mask) | (*(dir+11) & ~mask); /* Apply attribute change */ + fs->winflag = 1; + if(!move_window(0)) res = FR_RW_ERROR; + } + } + return res; +} +#endif + + diff --git a/src/tff.h b/src/tff.h new file mode 100644 index 0000000..b1d8597 --- /dev/null +++ b/src/tff.h @@ -0,0 +1,181 @@ +/*--------------------------------------------------------------------------/ +/ FatFs - FAT file system module include file R0.01 (C)ChaN, 2006 +/---------------------------------------------------------------------------/ +/ FatFs module is an experimenal project to implement FAT file system to +/ cheap microcontrollers. This is opened for education, reserch and +/ development. You can use it for non-profit or profit use without any +/ limitation under your responsibility. +/---------------------------------------------------------------------------/ +/ Feb 26, 2006 R0.00 Prototype +/ Apr 29, 2006 R0.01 First stable version +/---------------------------------------------------------------------------*/ + +#ifndef _FATFS + +//#define _BYTE_ACC +/* This enables byte-by-byte access for multi-byte variables */ +/* It must be defined on the big-endian processor, or to prevent address error */ + +//#define _FS_READONLY +/* This removes writing code for read-only applications */ + +#define _USE_SJIS +/* This enables Shift-JIS code transparency, or only US-ASCII file name can be accepted */ + + +#include "integer.h" + + +/* Result type for fatfs application interface */ +typedef unsigned char FRESULT; + + +/* File system object */ +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 sects_fat; // Sectors per fat + WORD max_clust; // Maximum cluster# + 1 + DWORD fatbase; // FAT start sector + DWORD dirbase; // Root directory start sector (cluster# for FAT32) + DWORD database; // Data start sector + DWORD winsect; // Current sector appearing in the win[] + BYTE win[512]; // Disk access window +} FATFS; + + +/* Directory scan object */ +typedef struct _DIR { + WORD sclust; // Start cluster + WORD clust; // Current cluster + DWORD sect; // Current sector + WORD index; // Current index +} DIR; + + +/* File object */ +typedef struct _FIL { + DWORD fptr; // File Pointer + DWORD fsize; // File Size + WORD org_clust; // File start cluster + WORD curr_clust; // Current cluster + DWORD curr_sect; // Current sector +#ifndef _FS_READONLY + DWORD dir_sect; // Sector containing the directory entry + BYTE* dir_ptr; // Ponter to the directory entry in the window +#endif + BYTE flag; // File status flags + BYTE sect_clust; // Left sectors in cluster +} FIL; + + +/* File status structure */ +typedef struct _FILINFO { + DWORD fsize; // Size + WORD fdate; // Date + WORD ftime; // Time + BYTE fattrib; // Attribute + char fname[8+1+3+1]; // File/Directory name (8.3 format) +} FILINFO; + + + +/* fatfs module application interface */ + +extern FATFS *FatFs; // Pointer to active file system object + +FRESULT f_open (FIL*, const char*, BYTE); // Open or create a file +FRESULT f_read (FIL*, BYTE*, WORD, WORD*); // Read file +FRESULT f_close (FIL*); // Close file +FRESULT f_lseek (FIL*, DWORD); // Seek file pointer +FRESULT f_opendir (DIR*, const char*); // Initialize to read a 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 (); // Force initialized the file system +#ifndef _FS_READONLY +FRESULT f_write (FIL*, const BYTE*, WORD, WORD*); // Write file +FRESULT f_sync (FIL*); // Flush cached information 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 +#endif + + +/* User defined function to give a current time to fatfs module */ + +#ifndef _FS_READONLY +DWORD get_fattime(); // 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) +#endif + + + +/* File function return code */ + +#define FR_OK 0 +#define FR_NOT_READY 1 +#define FR_NO_FILE 2 +#define FR_NO_PATH 3 +#define FR_INVALID_NAME 4 +#define FR_DENIED 5 +#define FR_DISK_FULL 6 +#define FR_RW_ERROR 7 +#define FR_ALIGN_ERROR 8 +#define FR_INCORRECT_DISK_CHANGE 9 +#define FR_WRITE_PROTECTED 10 +#define FR_NOT_ENABLED 11 +#define FR_NO_FILESYSTEM 12 + + +/* File access control and file status flags */ + +#define FA_READ 0x01 +#define FA_OPEN_EXISTING 0x00 +#ifndef _FS_READONLY +#define FA_WRITE 0x02 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA__WRITTEN 0x20 +#endif +#define FA__ERROR 0x80 + + +/* FAT type signature (fs_type) */ + +#define FS_FAT16 1 + + +/* File attribute mask for directory entry */ + +#define AM_RDO 0x01 // Read Only +#define AM_HID 0x02 // Hidden +#define AM_SYS 0x04 // System +#define AM_VOL 0x08 // Volume Label +#define AM_DIR 0x10 // Directory +#define AM_ARC 0x20 // Archive + + + +/* Multi-byte word access macros */ + +#ifdef _BYTE_ACC +#define LD_WORD(ptr) (((WORD)*(BYTE*)(ptr+1)<<8)|*(ptr)) +#define LD_DWORD(ptr) (((DWORD)*(BYTE*)(ptr+3)<<24)|((DWORD)*(BYTE*)(ptr+2)<<16)|((WORD)*(BYTE*)(ptr+1)<<8)|*(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(BYTE*)(ptr)=val; *(BYTE*)(ptr+1)=val>>8 +#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=val; *(BYTE*)(ptr+1)=val>>8; *(BYTE*)(ptr+2)=val>>16; *(BYTE*)(ptr+3)=val>>24 +#else +#define LD_WORD(ptr) (*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(val) +#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(val) +#endif + + +#define _FATFS +#endif