diff --git a/doc/00index_e.html b/doc/00index_e.html index 13cef08..8407cbb 100644 --- a/doc/00index_e.html +++ b/doc/00index_e.html @@ -75,10 +75,11 @@
The FatFs/Tiny-FatFs module is a free software and is opened for education, research and development. You can use, modify and/or republish it for personal, non-profit or profit use without any restriction under your responsibility.
FatFs/Tiny-FatFsモジュールはフリー・ソフトウェアとして教育・研究・開発用に公開しています。どのような利用目的(個人・非商用・商用)でも使用・改変・配布について一切の制限はありませんが、全て利用者の責任の下での利用とします。
These are the memory usage on some target systems. The memory sizes are in unit of byte, D means number of logical drives and F means number of open files. All samples are optimezed in code size.
| AVR | H8/300H | MSP430 | TLCS-870/C | V850ES | SH2 | |
|---|---|---|---|---|---|---|
| Compiler | gcc | CH38 | CL430 | CC870C | CA850 | SHC | 
| _MCU_ENDIAN | 1 | 2 | 2 | 1 | 1 | 2 | 
| FatFs Code (Full, R/W cfg.) | 8672 | 8746 | 6384 | 7390 | ||
| FatFs Code (Full, R/O cfg.) | 4230 | 4100 | 3012 | 3510 | ||
| FatFs Code (Mininum, R/W cfg.) | 5706 | 5678 | 4042 | 4882 | ||
| FatFs Code (Minimum, R/O cfg.) | 3016 | 3116 | 2198 | 2702 | ||
| FatFs Code (Standard, R/W cfg.) | 8722 | 8776 | 6402 | 7338 | ||
| FatFs Code (Minimum, R/W cfg.) | 5814 | 5722 | 4094 | 4906 | ||
| FatFs Code (Standard, R/O cfg.) | 4248 | 4096 | 3010 | 3506 | ||
| FatFs Code (Minimum, R/O cfg.) | 3038 | 3110 | 2210 | 2698 | ||
| FatFs Work (Static) | D*2 + 2 | D*4 + 2 | D*4 + 2 | D*4 + 2 | ||
| FatFs Work (Dynamic) | D*550 + F*544 | D*550 + F*550 | D*550 + F*550 | D*550 + F*550 | ||
| Tiny-FatFs Code (Full, R/W cfg.) | 7188 | 7206 | 6590 | 8799 | ||
| Tiny-FatFs Code (Full, R/O cfg.) | 3592 | 3560 | 3162 | 4353 | ||
| Tiny-FatFs Code (Minimum, R/W cfg.) | 4670 | 4772 | 4322 | 6073 | ||
| Tiny-FatFs Code (Minimum, R/O cfg.) | 2576 | 2714 | 2378 | 3324 | ||
| FatFs Work (Dynamic) | D*554 + F*544 | D*554 + F*550 | D*554 + F*550 | D*554 + F*550 | ||
| Tiny-FatFs Code (Standard, R/W cfg.) | 7264 | 7240 | 6634 | 8837 | ||
| Tiny-FatFs Code (Minimum, R/W cfg.) | 4750 | 4806 | 4366 | 6163 | ||
| Tiny-FatFs Code (Standard, R/O cfg.) | 3600 | 3548 | 3212 | 4347 | ||
| Tiny-FatFs Code (Minimum, R/O cfg.) | 2568 | 2702 | 2394 | 3322 | ||
| Tiny-FatFs Wrok (Static) | 4 | 6 | 4 | 4 | ||
| Tiny-FatFs Work (Dynamic) | 542 + F*28 | 542 + F*32 | 542 + F*28 | 542 + F*28 | ||
| Tiny-FatFs Work (Dynamic) | 544 + F*28 | 544 + F*32 | 544 + F*28 | 544 + F*28 | 
The f_close function closes an open file object. If any data has been written to the file, the cached information of the file is written back to the disk. After the function succeeded, the file object is no longer valid and it can be discarded.
+The f_close function closes an open file object. If any data has been written to the file, the cached information of the file is written back to the disk. After the function succeeded, the file object is no longer valid and it can be discarded. If the file object has been opened in read-only mode, it may be discarded without closing process by this function.
The f_getfree function gets number of free clusters on the drive. The sects_clust member in the file system object refreting number of sectors per cluster, so that the free space in unit of sector can be calcurated with this. This function is not supported in read-only configuration and minimization level of >= 1.
+The f_getfree function gets number of free clusters on the drive. The sects_clust member in the file system object refreting number of sectors per cluster, so that the free space in unit of sector can be calcurated with this. When _USE_FSINFO option is enabled, this function can return inaccurate free cluster count on FAT32 volume. When _USE_FSINFO option is disabled, this function will take a time on FAT32 volume.
+This function is not supported in read-only configuration and minimization level of >= 1.
The FATFS structure holds dynamic work area of individual logical drives. It is given by application program and registerd/unregisterd to the FatFs module with f_mount function. There is no member that can be changed from the application program.
+The FATFS structure holds dynamic work area of individual logical drives. It is given by application program and registerd/unregisterd to the FatFs module with f_mount function. Following members are in standard configuration. There is no member that can be changed from the application program.
 typedef struct _FATFS {
@@ -25,6 +25,7 @@ typedef struct _FATFS {
     DWORD   dirbase;        /* Root directory start sector (cluster# for FAT32) */
     DWORD   database;       /* Data start sector */
     DWORD   last_clust;     /* Last allocated cluster */
+    DWORD   free_clust;     /* Number of free clusters */
     BYTE    fs_type;        /* FAT type (0:Not mounted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
@@ -47,6 +48,7 @@ typedef struct _FATFS {
     CLUST   sects_fat;      /* Sectors per fat */
     CLUST   max_clust;      /* Maximum cluster# + 1 */
     CLUST   last_clust;     /* Last allocated cluster */
+    CLUST   free_clust;     /* Number of free clusters */
     BYTE    fs_type;        /* FAT type (0:Not mounted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
diff --git a/doc/ja/appnote.html b/doc/ja/appnote.html
index f6e6df9..2b48a41 100644
--- a/doc/ja/appnote.html
+++ b/doc/ja/appnote.html
@@ -18,36 +18,36 @@
 各種環境でのモジュールのメモリ使用量の例を示します。数値の単位はバイトで、Dは論理ドライブ数、Fは同時オープン・ファイル数を示します。最適化オプションは、全てコード・サイズとしています。
| AVR | H8/300H | MSP430 | TLCS-870/C | V850ES | SH2 | |
|---|---|---|---|---|---|---|
| コンパイラ | gcc | CH38 | CL430 | CC870C | CA850 | SHC | 
| _MCU_ENDIAN | 1 | 2 | 2 | 1 | 1 | 2 | 
| FatFs コード (標準, R/W構成) | 8672 | 8746 | 6384 | 7390 | ||
| FatFs コード (標準, R/O構成) | 4232 | 4100 | 3012 | 3510 | ||
| FatFs コード (最小, R/W構成) | 5706 | 5678 | 4042 | 4882 | ||
| FatFs コード (最小, R/O構成) | 3018 | 3116 | 2198 | 2702 | ||
| FatFs コード (標準, R/W構成) | 8722 | 8776 | 6402 | 7338 | ||
| FatFs コード (最小, R/W構成) | 5814 | 5722 | 4094 | 4906 | ||
| FatFs コード (標準, R/O構成) | 4248 | 4096 | 3010 | 3506 | ||
| FatFs コード (最小, R/O構成) | 3038 | 3110 | 2210 | 2698 | ||
| FatFs 静的ワーク | D*2 + 2 | D*4 + 2 | D*4 + 2 | D*4 + 2 | ||
| FatFs 動的ワーク | D*550 + F*544 | D*550 + F*550 | D*550 + F*550 | D*550 + F*550 | ||
| Tiny-FatFs コード (標準, R/W構成) | 7188 | 7206 | 6590 | 8799 | ||
| Tiny-FatFs コード (標準, R/O構成) | 3592 | 3560 | 3162 | 4353 | ||
| Tiny-FatFs コード (最小, R/W構成) | 4670 | 4772 | 4322 | 6073 | ||
| Tiny-FatFs コード (最小, R/O構成) | 2576 | 2714 | 2378 | 3324 | ||
| FatFs 動的ワーク | D*554 + F*544 | D*554 + F*550 | D*554 + F*550 | D*554 + F*550 | ||
| Tiny-FatFs コード (標準, R/W構成) | 7264 | 7240 | 6634 | 8837 | ||
| Tiny-FatFs コード (最小, R/W構成) | 4750 | 4806 | 4366 | 6163 | ||
| Tiny-FatFs コード (標準, R/O構成) | 3600 | 3548 | 3212 | 4347 | ||
| Tiny-FatFs コード (最小, R/O構成) | 2568 | 2702 | 2394 | 3322 | ||
| Tiny-FatFs 静的ワーク | 4 | 6 | 4 | 4 | ||
| Tiny-FatFs 動的ワーク | 542 + F*28 | 542 + F*32 | 542 + F*28 | 542 + F*28 | ||
| Tiny-FatFs 動的ワーク | 544 + F*28 | 544 + F*32 | 544 + F*28 | 544 + F*28 | 
ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsは標準構成ではFAT32に対応していないので、使用できるディスクは2GB(FAT64で4GB)までという制約があります。_USE_FAT32オプションでFAT32を追加できますが、その分コード・サイズが膨らみます。フル機能のFatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な場合に有効です。
+ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsは標準構成ではFAT32に対応していないので、使用できるディスクは2GB(FAT64で4GB)までという制約があります。_FAT32オプションでFAT32対応を追加できますが、その分コード・サイズが膨らみます。フル機能のFatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な場合に有効です。
| メモリ容量 | FATタイプ | 
|---|---|
| >= 4GB | FAT32 | 
右の表にメモリ・カードの容量と規定のFATタイプ(SDメモリの場合)を示します。出荷時はこれらのFATタイプでフォーマットされていて、最大のパフォーマンスが出るようにデータ領域の境界が調整されています。したがって、PCでフォーマットするなどして規定と違うフォーマットになると書き込み性能が大幅に低下する場合があるので注意が必要です。
+2GBまでのカードに限るなら、FAT32への対応は不要です。右の表にメモリ・カードの容量と規定のFATタイプ(SDメモリの場合)を示します。メモリ・カードの出荷時は、最大のパフォーマンスが出るようにデータ領域の境界が調整されたフォーマットになっています。したがって、PCでフォーマットするなどして規定と違うフォーマットになると、書き込み性能が大幅に低下する場合があるので注意が必要です。
ファイルを閉じます。書き込みの行われたファイルの場合、キャッシュされた状態(R/Wバッファ上のデータ、変更されたFATやディレクトリ項目)はディスクに書き戻されます。関数が正常終了すると、そのファイル・オブジェクトは無効になり、そのメモリも解放できます。
+ファイルを閉じます。書き込みの行われたファイルの場合、キャッシュされた状態(R/Wバッファ上のデータ、変更されたFATやディレクトリ項目)はディスクに書き戻されます。関数が正常終了すると、そのファイル・オブジェクトは無効になり、そのメモリも解放できます。読み込み専用モードで開かれたファイル・オブジェクトは、この関数によるクローズ処理を経ずに破棄することもできます。
物理ドライブの種類によりサポートされるコマンドは異なりますが、FatFsモジュールでは、ドライブの種類に依存した制御は行いません。次のドライブ共通コマンドを使用します。リード・オンリー構成ではこの関数は必要とされません。
+物理ドライブの種類によりサポートされるコマンドは異なりますが、FatFsモジュールでは、ドライブの種類に依存した制御は行いません。次のドライブ共通コマンドを使用します。
+リード・オンリー構成ではこの関数は必要とされません。
| コマンド | 解説 | 
|---|---|
| GET_SECTOR_COUNT | Bufferの指すDWORD変数にドライブ上の総セクタ数を返します。 | 
| CTRL_SYNC | ディスクへのデータの書き込みが完了するのを待ちます。ライト・バック・キャッシュを持っている場合は、書き込まれていないデータを即時書き戻します。 | 
| CTRL_SYNC | ドライブがデータの書き込みを完了するのを待ちます。ライト・バック・キャッシュを持っている場合は、書き込まれていないデータを即時書き戻します。 | 
ディスクの未使用クラスタ数を得ます。
+論理ドライブ上の未使用クラスタ数を得ます。
FRESULT f_getfree ( const char* Path, /* 対象ドライブのルート・ディレクトリ */ @@ -26,11 +26,11 @@ FRESULT f_getfree (引数
論理ドライブ上の空きクラスタ数を取得します。返されたファイル・システム・オブジェクトのsects_clustメンバがクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。
+論理ドライブ上の空きクラスタ数を取得します。返されたファイル・システム・オブジェクトのsects_clustメンバがクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。FAT32ボリュームにおいて、_USE_FSINFOが指定されている場合、不正確な値を返す場合があります。指定されていない場合、処理に時間がかかります。
+リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。
FATFS構造体は、個々の論理ドライブのダイナミック・ワーク・エリアを保持し、f_mount()でFatFsモジュールに登録されます。アプリケーションから書き換え可能なメンバはありません。
+FATFS構造体は、個々の論理ドライブのダイナミック・ワーク・エリアを保持し、f_mount()でFatFsモジュールに登録されます。標準状態では次のようなメンバになっています。アプリケーションから書き換え可能なメンバはありません。
 typedef struct _FATFS {
@@ -25,6 +25,7 @@ typedef struct _FATFS {
     DWORD   dirbase;        /* Root directory start sector (cluster# for FAT32) */
     DWORD   database;       /* Data start sector */
     DWORD   last_clust;     /* Last allocated cluster */
+    DWORD   free_clust;     /* Number of free clusters */
     BYTE    fs_type;        /* FAT type (0:Not mounted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
@@ -47,6 +48,7 @@ typedef struct _FATFS {
     CLUST   sects_fat;      /* Sectors per fat */
     CLUST   max_clust;      /* Maximum cluster# + 1 */
     CLUST   last_clust;     /* Last allocated cluster */
+    CLUST   free_clust;     /* Number of free clusters */
     BYTE    fs_type;        /* FAT type (0:Not mounted) */
     BYTE    sects_clust;    /* Sectors per cluster */
     BYTE    n_fats;         /* Number of FAT copies */
diff --git a/doc/ja/sfileinfo.html b/doc/ja/sfileinfo.html
index a510ed6..d9d94f5 100644
--- a/doc/ja/sfileinfo.html
+++ b/doc/ja/sfileinfo.html
@@ -15,9 +15,9 @@
 FILINFO構造体は、f_stat(), f_readdir()で返されるファイル情報を保持します。
 
 typedef struct _FILINFO {
-    DWORD fsize;            /* Size */
-    WORD fdate;             /* Date */
-    WORD ftime;             /* Time */
+    DWORD fsize;            /* Size [bytes] */
+    WORD fdate;             /* Date [15-9]:Year-1980, [8-5]:Month, [4-0]:Mday */
+    WORD ftime;             /* Time [15-11]:Hour, [10-5]:Minute, [4-0]:Sec/2 */
     BYTE fattrib;           /* Attribute */
     char fname[8+1+3+1];    /* Name */
 } FILINFO;
diff --git a/doc/updates.txt b/doc/updates.txt
index 44cb1b1..740f0e2 100644
--- a/doc/updates.txt
+++ b/doc/updates.txt
@@ -1,9 +1,16 @@
+R0.04b, May 05, 2007
+  Added _USE_NTFLAG option.
+  Added FSInfo support.
+  Fixed some problems corresponds to FAT32. (Tiny-FatFs)
+  Fixed DBCS name can result FR_INVALID_NAME.
+  Fixed short seek (<= csize) collapses the file object.
+
 R0.04a, Apr 01, 2007
   Supported multiple partitions on a plysical drive. (FatFs)
-  Fixed an endian sensitive code in f_mkfs(). (FatFs)
-  Added a capability of extending file size to f_lseek().
   Added minimization level 3.
-  Fixed a problem that can collapse a sector when recreate an existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs)
+  Added a capability of extending file size to f_lseek().
+  Fixed an endian sensitive code in f_mkfs(). (FatFs)
+  Fixed a problem corresponds to FAT32 support. (Tiny-FatFs)
 
 R0.04, Feb 04, 2007
   Supported multiple drive system. (FatFs)
diff --git a/src/00readme.txt b/src/00readme.txt
index 1c6ab55..6d2697f 100644
--- a/src/00readme.txt
+++ b/src/00readme.txt
@@ -1,4 +1,4 @@
-FatFs/Tiny-FatFs Module Source Files R0.04a   (C)ChaN, 2007
+FatFs/Tiny-FatFs Module Source Files R0.04b   (C)ChaN, 2007
 
 
 FILES
@@ -48,29 +48,40 @@ CONFIGURATION OPTIONS
   _FS_MINIMIZE
 
   When application program requires only file read/write function, _FS_MINIMIZE
-  can be defined to eliminate some functions to reduce the module size. The
+  can be changed to eliminate some functions to reduce the module size. The
   initial value is 0. (full function)
 
 
   _DRIVES
 
-  Number of drives to be used. This option is not supported on Tiny-FatFs.
+  Number of drives to be used. This option is not available on Tiny-FatFs.
   The initial value is 2.
 
   _FAT32
 
   When _FAT32 is set to 1, the FAT32 support is added with an additional
-  code size. This is for only Tiny-FatFs and not supported on FatFs. FatFs
-  always supports all FAT type. The initial value is 0. (disabled)
+  code size. This option is for only Tiny-FatFs. FatFs always supports all
+  FAT sub-types. The initial value is 0. (no FAT32 support)
+
+
+  _USE_FSINFO
+
+  When _USE_FSINFO is set to 1, FSInfo is used for FAT32 volume.
 
 
   _USE_SJIS
 
-  When _USE_SJIS is set to 1, Shift-JIS code set can be used as a file name,
+  When _USE_SJIS is set to 1, Shift_JIS code set can be used as a file name,
   otherwire second byte of double-byte characters will be collapted.
   The initial value is 1.
 
 
+  _USE_NTFLAG
+
+  When _USE_NTFLAG is set to 1, upper/lower case of the file/dir name is
+  preserved. Note that the files are always accessed in case insensitive.
+
+
   _USE_MKFS
 
   When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function
@@ -97,7 +108,7 @@ CONFIGURATION OPTIONS
    f_mkdir       x    x    x         x                 
    f_chmod       x    x    x         x                 
    f_rename      x    x    x         x                 
-   f_mkfs                            x          x      
+   f_mkfs        x    x    x         x          x      
 
 
 
@@ -140,3 +151,8 @@ REVISION HISTORY
                        Fixed a problem that can collapse a sector when recreate an
                        existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs)
 
+  May 05, 2007  R0.04b  Added _USE_NTFLAG option.
+                        Added FSInfo support.
+                        Fixed some problems corresponds to FAT32. (Tiny-FatFs)
+                        Fixed DBCS name can result FR_INVALID_NAME.
+                        Fixed short seek (<= csize) collapses the file object.
diff --git a/src/ff.c b/src/ff.c
index 7d11e8e..6e76bf2 100644
--- a/src/ff.c
+++ b/src/ff.c
@@ -1,5 +1,5 @@
 /*--------------------------------------------------------------------------/
-/  FatFs - FAT file system module  R0.04a                    (C)ChaN, 2007
+/  FatFs - FAT file system module  R0.04b                    (C)ChaN, 2007
 /---------------------------------------------------------------------------/
 / The FatFs module is an experimenal project to implement FAT file system to
 / cheap microcontrollers. This is a free software and is opened for education,
@@ -15,7 +15,8 @@
 /---------------------------------------------------------------------------/
 /  Feb 26, 2006  R0.00  Prototype.
 /  Apr 29, 2006  R0.01  First stable version.
-/  Jun 01, 2006  R0.02  Added FAT12. Removed unbuffered mode.
+/  Jun 01, 2006  R0.02  Added FAT12 support.
+/                       Removed unbuffered mode.
 /                       Fixed a problem on small (<32M) patition.
 /  Jun 10, 2006  R0.02a Added a configuration option (_FS_MINIMUM).
 /  Sep 22, 2006  R0.03  Added f_rename().
@@ -24,11 +25,16 @@
 /                       Fixed f_mkdir() creates incorrect directory on FAT32.
 /  Feb 04, 2007  R0.04  Supported multiple drive system.
 /                       Changed some interfaces for multiple drive system.
+/                       Changed f_mountdrv() to f_mount().
 /                       Added f_mkfs().
 /  Apr 01, 2007  R0.04a Supported multiple partitions on a plysical drive.
-/                       Fixed an endian sensitive code in f_mkfs().
 /                       Added a capability of extending file size to f_lseek().
 /                       Added minimization level 3.
+/                       Fixed an endian sensitive code in f_mkfs().
+/  May 05, 2007  R0.04b Added a configuration option _USE_NTFLAG.
+/                       Added FSInfo support.
+/                       Fixed DBCS name can result FR_INVALID_NAME.
+/                       Fixed short seek (<= csize) collapses the file object.
 /---------------------------------------------------------------------------*/
 
 #include 
@@ -64,7 +70,7 @@ BOOL move_window (		/* TRUE: successful, FALSE: failed */
 
 	wsect = fs->winsect;
 	if (wsect != sector) {	/* Changed current window */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 		BYTE n;
 		if (fs->winflag) {	/* Write back dirty window if needed */
 			if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
@@ -94,7 +100,7 @@ BOOL move_window (		/* TRUE: successful, FALSE: failed */
 /* Clean-up cached data                                                  */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 FRESULT sync (			/* FR_OK: successful, FR_RW_ERROR: failed */
 	FATFS *fs			/* File system object */
@@ -102,6 +108,19 @@ FRESULT sync (			/* FR_OK: successful, FR_RW_ERROR: failed */
 {
 	fs->winflag = 1;
 	if (!move_window(fs, 0)) return FR_RW_ERROR;
+#if _USE_FSINFO
+	if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {		/* Update FSInfo sector if needed */
+		fs->winsect = 0;
+		memset(fs->win, 0, 512);
+		ST_WORD(&fs->win[BS_55AA], 0xAA55);
+		ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252);
+		ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272);
+		ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust);
+		ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust);
+		disk_write(0, fs->win, fs->fsi_sector, 1);
+		fs->fsi_flag = 0;
+	}
+#endif
 	if (disk_ioctl(fs->drive, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR;
 	return FR_OK;
 }
@@ -155,7 +174,7 @@ DWORD get_cluster (		/* 0,>=2: successful, 1: failed */
 /* Change a cluster status                                               */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 	FATFS *fs,			/* File system object */
@@ -198,7 +217,7 @@ BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 	fs->winflag = 1;
 	return TRUE;
 }
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -207,7 +226,7 @@ BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 /* Remove a cluster chain                                                */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 BOOL remove_chain (		/* TRUE: successful, FALSE: failed */
 	FATFS *fs,			/* File system object */
@@ -221,6 +240,12 @@ BOOL remove_chain (		/* TRUE: successful, FALSE: failed */
 		nxt = get_cluster(fs, clust);
 		if (nxt == 1) return FALSE;
 		if (!put_cluster(fs, clust, 0)) return FALSE;
+		if (fs->free_clust != 0xFFFFFFFF) {
+			fs->free_clust++;
+#if _USE_FSINFO
+			fs->fsi_flag = 1;
+#endif
+		}
 		clust = nxt;
 	}
 	return TRUE;
@@ -234,7 +259,7 @@ BOOL remove_chain (		/* TRUE: successful, FALSE: failed */
 /* Stretch or create a cluster chain                                     */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 DWORD create_chain (	/* 0: no free cluster, 1: error, >=2: new cluster number */
 	FATFS *fs,			/* File system object */
@@ -270,11 +295,18 @@ DWORD create_chain (	/* 0: no free cluster, 1: error, >=2: new cluster number */
 
 	if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1;		/* Mark the new cluster "in use" */
 	if (clust && !put_cluster(fs, clust, ncl)) return 1;	/* Link it to previous one if needed */
-	fs->last_clust = ncl;
+
+	fs->last_clust = ncl;				/* Update fsinfo */
+	if (fs->free_clust != 0xFFFFFFFF) {
+		fs->free_clust--;
+#if _USE_FSINFO
+		fs->fsi_flag = 1;
+#endif
+	}
 
 	return ncl;		/* Return new cluster number */
 }
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -349,7 +381,7 @@ void get_fileinfo (		/* No return code */
 
 
 	p = &finfo->fname[0];
-	a = dir[DIR_NTres];		/* NT flag */
+	a = _USE_NTFLAG ? dir[DIR_NTres] : 0;		/* NT flag */
 	for (n = 0; n < 8; n++) {	/* Convert file name (body) */
 		c = dir[n];
 		if (c == ' ') break;
@@ -398,39 +430,36 @@ char make_dirfile (			/* 1: error - detected an invalid format, '\0'or'/': next
 		c = *(*path)++;
 		if (c == '\0' || c == '/') {		/* Reached to end of str or directory separator */
 			if (n == 0) break;
-			dirname[11] = a & b; return c;
+			dirname[11] = _USE_NTFLAG ? (a & b) : 0;
+			return c;
 		}
-		if (c <= ' ') break;		/* Reject invisible chars */
+		if (c <= ' ' || c == 0x7F) break;		/* Reject invisible chars */
 		if (c == '.') {
-			if(!(a & 1) && n >= 1 && n <= 8) {	/* Enter extension part */
+			if (!(a & 1) && n >= 1 && n <= 8) {	/* Enter extension part */
 				n = 8; t = 11; continue;
 			}
 			break;
 		}
-#if _USE_SJIS != 0
-		if ((c >= 0x81 && c <= 0x9F) ||			/* Accept S-JIS code */
-		    (c >= 0xE0 && c <= 0xFC)) {
-			if (n == 0 && c == 0xE5)			/* Change heading \xE5 to \x05 */
+		if (_USE_SJIS &&
+			((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 (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 == '|') break;			/* Reject | */
 			if (c >= '[' && c <= ']') break;/* Reject [ \ ] */
-			if (c >= 'A' && c <= 'Z')
+			if (_USE_NTFLAG && c >= 'A' && c <= 'Z')
 				(t == 8) ? (b &= ~0x08) : (b &= ~0x10);
-			if (c >= 'a' && c <= 'z') {			/* Convert to upper case */
+			if (c >= 'a' && c <= 'z') {		/* Convert to upper case */
 				c -= 0x20;
-				(t == 8) ? (a |= 0x08) : (a |= 0x10);
+				if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
 			}
 		}
 	md_l1:
@@ -508,7 +537,7 @@ FRESULT trace_path (	/* FR_OK(0): successful, !=0: error code */
 /* Reserve a directory entry                                             */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 FRESULT reserve_direntry (	/* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */
 	DIR *dirobj,			/* Target directory to create new entry */
@@ -555,7 +584,7 @@ FRESULT reserve_direntry (	/* FR_OK: successful, FR_DENIED: no free entry, FR_RW
 	*dir = fs->win;
 	return FR_OK;
 }
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -599,7 +628,7 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 {
 	BYTE drv, fmt, *tbl;
 	DSTATUS stat;
-	DWORD basesect, fatsize, totalsect, maxclust;
+	DWORD bootsect, fatsize, totalsect, maxclust;
 	const char *p = *path;
 	FATFS *fs;
 
@@ -623,7 +652,7 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	if (fs->fs_type) {
 		stat = disk_status(fs->drive);
 		if (!(stat & STA_NOINIT)) {				/* If the physical drive is kept initialized */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 			if (chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
 				return FR_WRITE_PROTECTED;
 #endif
@@ -642,18 +671,18 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	if (disk_ioctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK || S_SIZ > S_MAX_SIZ)
 		return FR_NO_FILESYSTEM;
 #endif
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	if (chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
 		return FR_WRITE_PROTECTED;
 #endif
 	/* Search FAT partition on the drive */
-	fmt = check_fs(fs, basesect = 0);	/* Check sector 0 as an SFD format */
+	fmt = check_fs(fs, bootsect = 0);	/* Check sector 0 as an SFD format */
 	if (fmt == 1) {						/* Not a FAT boot record, it may be patitioned */
 		/* Check a partition listed in top of the partition table */
 		tbl = &fs->win[MBR_Table + LD2PT(drv) * 16];	/* Partition table */
 		if (tbl[4]) {								/* Is the partition existing? */
-			basesect = LD_DWORD(&tbl[8]);			/* Partition offset in LBA */
-			fmt = check_fs(fs, basesect);			/* Check the partition */
+			bootsect = LD_DWORD(&tbl[8]);			/* Partition offset in LBA */
+			fmt = check_fs(fs, bootsect);			/* Check the partition */
 		}
 	}
 	if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != S_SIZ)	/* No valid FAT patition is found */
@@ -665,14 +694,13 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	fs->sects_fat = fatsize;
 	fs->n_fats = fs->win[BPB_NumFATs];					/* Number of FAT copies */
 	fatsize *= fs->n_fats;								/* (Number of sectors in FAT area) */
-	fs->fatbase = basesect += LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
-	basesect += fatsize;								/* (Next sector of FAT area (lba)) */
+	fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
 	fs->sects_clust = fs->win[BPB_SecPerClus];			/* Number of sectors per cluster */
 	fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]);	/* Nmuber of root directory entries */
 	totalsect = LD_WORD(&fs->win[BPB_TotSec16]);		/* Number of sectors on the file system */
 	if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]);
 	fs->max_clust = maxclust = (totalsect				/* Last cluster# + 1 */
-		- LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (S_SIZ / 32)
+		- LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (S_SIZ/32)
 		) / fs->sects_clust + 2;
 
 	fmt = FS_FAT12;										/* Determine the FAT sub type */
@@ -683,11 +711,26 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	if (fmt == FS_FAT32)
 		fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]);	/* Root directory start cluster */
 	else
-		fs->dirbase = basesect;							/* Root directory start sector (lba) */
-	fs->database = basesect + fs->n_rootdir / (S_SIZ / 32);	/* Data start sector (lba) */
+		fs->dirbase = fs->fatbase + fatsize;			/* Root directory start sector (lba) */
+	fs->database = fs->fatbase + fatsize + fs->n_rootdir / (S_SIZ/32);	/* Data start sector (lba) */
 
+#if !_FS_READONLY
+	fs->free_clust = 0xFFFFFFFF;
+#if _USE_FSINFO
+	/* Load fsinfo sector if needed */
+	if (fmt == FS_FAT32) {
+		fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]);
+		if (disk_read(0, fs->win, fs->fsi_sector, 1) == RES_OK &&
+			LD_WORD(&fs->win[BS_55AA]) == 0xAA55 &&
+			LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 &&
+			LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272) {
+			fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]);
+			fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]);
+		}
+	}
+#endif
+#endif
 	fs->id = ++fsid;									/* File system mount ID */
-
 	return FR_OK;
 }
 
@@ -764,7 +807,8 @@ FRESULT f_open (
 	FATFS *fs;
 
 
-#if _FS_READONLY == 0
+	fp->fs = NULL;
+#if !_FS_READONLY
 	mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
 	res = auto_mount(&path, &fs, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
 #else
@@ -776,7 +820,7 @@ FRESULT f_open (
 
 	/* Trace the file path */
 	res = trace_path(&dirobj, fn, path, &dir);
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	/* Create or Open a file */
 	if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
 		DWORD ps, rs;
@@ -816,11 +860,11 @@ FRESULT f_open (
 	}
 	/* Open an existing file */
 	else {
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 		if (res != FR_OK) return res;		/* Trace failed */
 		if (dir == NULL || (dir[DIR_Attr] & AM_DIR))	/* It is a directory */
 			return FR_NO_FILE;
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 		if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
 			return FR_DENIED;
 	}
@@ -882,7 +926,7 @@ FRESULT f_read (
 				sect = clust2sect(fs, clust);		/* Get current sector */
 				fp->sect_clust = fs->sects_clust;	/* Re-initialize the left sector counter */
 			}
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 			if (fp->flag & FA__DIRTY) {				/* Flush file I/O buffer if needed */
 				if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
 					goto fr_error;
@@ -917,7 +961,7 @@ fr_error:	/* Abort this file due to an unrecoverable error */
 
 
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 /*-----------------------------------------------------------------------*/
 /* Write File                                                            */
 /*-----------------------------------------------------------------------*/
@@ -1040,7 +1084,7 @@ FRESULT f_sync (
 	return res;
 }
 
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -1056,7 +1100,7 @@ FRESULT f_close (
 	FRESULT res;
 
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	res = f_sync(fp);
 #else
 	res = validate(fp->fs, fp->id);
@@ -1088,7 +1132,7 @@ FRESULT f_lseek (
 	res = validate(fs, fp->id);			/* Check validity of the object */
 	if (res) return res;
 	if (fp->flag & FA__ERROR) return FR_RW_ERROR;
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	if (fp->flag & FA__DIRTY) {			/* Write-back dirty buffer if needed */
 		if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
 			goto fk_error;
@@ -1104,33 +1148,33 @@ FRESULT f_lseek (
 	/* Move file R/W pointer if needed */
 	if (ofs) {
 		clust = fp->org_clust;	/* Get start cluster */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 		if (!clust) {			/* If the file does not have a cluster chain, create new cluster chain */
 			clust = create_chain(fs, 0);
 			if (clust == 1) goto fk_error;
-			fp->org_clust = fp->curr_clust = clust;
+			fp->org_clust = clust;
 		}
 #endif
 		if (clust) {			/* If the file has a cluster chain, it can be followed */
 			csize = (DWORD)fs->sects_clust * S_SIZ;		/* Cluster size in unit of byte */
-			while (ofs > csize) {						/* Skip leading clusters */
-#if _FS_READONLY == 0
-				if (fp->flag & FA_WRITE)					/* Check if in write mode or not */
-					clust = create_chain(fs, clust);		/* Force streached if in write mode */
+			for (;;) {									/* Loop to skip leading clusters */
+				fp->curr_clust = clust;					/* Update current cluster */
+				if (ofs <= csize) break;
+#if !_FS_READONLY
+				if (fp->flag & FA_WRITE)				/* Check if in write mode or not */
+					clust = create_chain(fs, clust);	/* Force streached if in write mode */
 				else
 #endif
-					clust = get_cluster(fs, clust);			/* Only follow cluster chain if not in write mode */
-				if (clust == 0) {							/* Stop if could not follow the cluster chain */
-					ofs = csize;
-					break;
+					clust = get_cluster(fs, clust);		/* Only follow cluster chain if not in write mode */
+				if (clust == 0) {						/* Stop if could not follow the cluster chain */
+					ofs = csize; break;
 				}
-				if (clust == 1 || clust >= fs->max_clust) goto fk_error; /* Abort when any error occured */
-				fp->curr_clust = clust;						/* Update current cluster and R/W pointer */
-				fp->fptr += csize;
+				if (clust == 1 || clust >= fs->max_clust) goto fk_error;
+				fp->fptr += csize;						/* Update R/W pointer */
 				ofs -= csize;
 			}
 			csect = (BYTE)((ofs - 1) / S_SIZ);			/* Sector offset in the cluster */
-			fp->curr_sect = clust2sect(fs, clust) + csect;	/* Get current cluster */
+			fp->curr_sect = clust2sect(fs, clust) + csect;	/* Current sector */
 			if ((ofs & (S_SIZ - 1)) &&					/* Load current sector if needed */
 				disk_read(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
 				goto fk_error;
@@ -1138,7 +1182,7 @@ FRESULT f_lseek (
 			fp->fptr += ofs;							/* Update file R/W pointer */
 		}
 	}
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) {	/* Set updated flag if in write mode */
 		fp->fsize = fp->fptr;
 		fp->flag |= FA__WRITTEN;
@@ -1263,7 +1307,7 @@ FRESULT f_stat (
 
 
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 /*-----------------------------------------------------------------------*/
 /* Get Number of Free Clusters                                           */
 /*-----------------------------------------------------------------------*/
@@ -1285,6 +1329,12 @@ FRESULT f_getfree (
 	if (res != FR_OK) return res;
 	*fatfs = fs;
 
+	/* If number of free cluster is valid, return it without cluster scan. */
+	if (fs->free_clust <= fs->max_clust - 2) {
+		*nclust = fs->free_clust;
+		return FR_OK;
+	}
+
 	/* Count number of free clusters */
 	fat = fs->fs_type;
 	n = 0;
@@ -1311,6 +1361,10 @@ FRESULT f_getfree (
 			}
 		} while (--clust);
 	}
+	fs->free_clust = n;
+#if _USE_FSINFO
+	if (fat == FS_FAT32) fs->fsi_flag = 1;
+#endif
 
 	*nclust = n;
 	return FR_OK;
@@ -1378,7 +1432,7 @@ FRESULT f_mkdir (
 	const char *path		/* Pointer to the directory path */
 )
 {
-	BYTE *dir, *sec, n;
+	BYTE *dir, *fw, n;
 	char fn[8+3+1];
 	DWORD sect, dsect, dclust, pclust, tim;
 	FRESULT res;
@@ -1401,31 +1455,31 @@ FRESULT f_mkdir (
 	if (dclust == 1) return FR_RW_ERROR;
 	dsect = clust2sect(fs, dclust);
 	if (!dsect) return FR_DENIED;
-	if (!move_window(fs, 0)) return FR_RW_ERROR;
+	if (!move_window(fs, dsect)) return FR_RW_ERROR;
 
-	sec = fs->win;
-	memset(sec, 0, S_SIZ);						/* Initialize the directory table */
-	for (n = fs->sects_clust - 1; n; n--) {
-		if (disk_write(fs->drive, sec, dsect+n, 1) != RES_OK)
+	fw = fs->win;
+	memset(fw, 0, S_SIZ);						/* Clear the new directory table */
+	for (n = 1; n < fs->sects_clust; n++) {
+		if (disk_write(fs->drive, fw, ++dsect, 1) != RES_OK)
 			return FR_RW_ERROR;
 	}
-
-	fs->winsect = dsect;						/* Create "." ".." directories */
-	memset(&sec[DIR_Name], ' ', 8+3);			/* "." entry */
-	sec[DIR_Name] = '.';
-	sec[DIR_Attr] = AM_DIR;
+	memset(&fw[DIR_Name], ' ', 8+3);			/* Create "." entry */
+	fw[DIR_Name] = '.';
+	fw[DIR_Attr] = AM_DIR;
 	tim = get_fattime();
-	ST_DWORD(&sec[DIR_WrtTime], tim);
-	memcpy(&sec[32], &sec[0], 32); sec[33] = '.'; /* ".." entry */
-	ST_WORD(&sec[DIR_FstClusLO], dclust);
-	ST_WORD(&sec[DIR_FstClusHI], dclust >> 16);
+	ST_DWORD(&fw[DIR_WrtTime], tim);
+	memcpy(&fw[32], &fw[0], 32); fw[33] = '.';	/* Create ".." entry */
 	pclust = dirobj.sclust;
+#if _FAT32
+	ST_WORD(&fw[   DIR_FstClusHI], dclust >> 16);
 	if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0;
-	ST_WORD(&sec[32+DIR_FstClusLO], pclust);
-	ST_WORD(&sec[32+DIR_FstClusHI], pclust >> 16);
+	ST_WORD(&fw[32+DIR_FstClusHI], pclust >> 16);
+#endif
+	ST_WORD(&fw[   DIR_FstClusLO], dclust);
+	ST_WORD(&fw[32+DIR_FstClusLO], pclust);
 	fs->winflag = 1;
-	if (!move_window(fs, sect)) return FR_RW_ERROR;
 
+	if (!move_window(fs, sect)) return FR_RW_ERROR;
 	memset(&dir[0], 0, 32);						/* Initialize the new entry */
 	memcpy(&dir[DIR_Name], fn, 8+3);			/* Name */
 	dir[DIR_NTres] = fn[11];
@@ -1523,7 +1577,7 @@ FRESULT f_rename (
 
 
 
-#if _USE_MKFS != 0
+#if _USE_MKFS
 /*-----------------------------------------------------------------------*/
 /* Create File System on the Drive                                       */
 /*-----------------------------------------------------------------------*/
@@ -1531,7 +1585,7 @@ FRESULT f_rename (
 #define N_ROOTDIR 512
 #define N_FATS 1
 #define MAX_SECTOR 64000000UL
-#define MIN_SECTOR 1000UL
+#define MIN_SECTOR 2000UL
 #define ERASE_BLK 32
 
 
@@ -1545,12 +1599,11 @@ FRESULT f_mkfs (
 	DWORD b_part, b_fat, b_dir, b_data;		/* Area offset (LBA) */
 	DWORD n_part, n_rsv, n_fat, n_dir;		/* Area size */
 	DWORD n_clust, n;
-	static const BYTE tbl_alloc[] = {1,2,4,8,16,32,64,0};
 	FATFS *fs;
 	DSTATUS stat;
 
 
-	/* Check mounted drive */
+	/* Check and mounted drive and clear work area */
 	if (drv >= _DRIVES) return FR_INVALID_DRIVE;
 	fs = FatFs[drv];
 	if (!fs) return FR_NOT_ENABLED;
@@ -1558,8 +1611,8 @@ FRESULT f_mkfs (
 	drv = LD2PD(drv);
 
 	/* Check validity of the parameters */
-	for (n = 0; allocsize != tbl_alloc[n] && tbl_alloc[n]; n++);
-	if (!tbl_alloc[n] || partition >= 2) return FR_MKFS_ABORTED;
+	for (n = 1; n <= 64 && allocsize != n; n <<= 1);
+	if (n > 64 || partition >= 2) return FR_MKFS_ABORTED;
 
 	/* Get disk statics */
 	stat = disk_initialize(drv);
@@ -1671,23 +1724,11 @@ FRESULT f_mkfs (
 		memcpy(&tbl[BS_VolLab32], "NO NAME    FAT32   ", 19);	/* Volume lavel, FAT signature */
 	}
 	ST_WORD(&tbl[BS_55AA], 0xAA55);			/* Signature */
-	if (disk_write(drv, tbl, b_part, 1) != RES_OK)
+	if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
 		return FR_RW_ERROR;
 	if (fmt == FS_FAT32)
 		disk_write(drv, tbl, b_part+6, 1);
 
-	/* Create FSInfo record if needed */
-	if (fmt == FS_FAT32) {
-		memset(tbl, 0, 510);
-		ST_DWORD(&tbl[0], 0x41615252);		/* "RRaA" */
-		ST_DWORD(&tbl[484], 0x61417272);	/* "rrAa" */
-		ST_DWORD(&tbl[488], 0xFFFFFFFF);	/* Free count */
-		ST_DWORD(&tbl[492], 0xFFFFFFFF);	/* Last allocated */
-		if (disk_write(drv, tbl, b_part+1, 1) != RES_OK)
-			return FR_RW_ERROR;
-		disk_write(drv, tbl, b_part+7, 1);
-	}
-
 	/* Initialize FAT area */
 	for (m = 0; m < N_FATS; m++) {
 		memset(tbl, 0, S_SIZ);		/* 1st sector of the FAT  */
@@ -1714,11 +1755,22 @@ FRESULT f_mkfs (
 			return FR_RW_ERROR;
 	}
 
+	/* Create FSInfo record if needed */
+	if (fmt == FS_FAT32) {
+		ST_WORD(&tbl[BS_55AA], 0xAA55);
+		ST_DWORD(&tbl[FSI_LeadSig], 0x41615252);
+		ST_DWORD(&tbl[FSI_StrucSig], 0x61417272);
+		ST_DWORD(&tbl[FSI_Free_Count], n_clust - 1);
+		ST_DWORD(&tbl[FSI_Nxt_Free], 0xFFFFFFFF);
+		disk_write(drv, tbl, b_part+1, 1);
+		disk_write(drv, tbl, b_part+7, 1);
+	}
+
 	return (disk_ioctl(drv, CTRL_SYNC, NULL) == RES_OK) ? FR_OK : FR_RW_ERROR;
 }
 
-#endif /* _USE_MKFS != 0 */
-#endif /* _FS_READONLY == 0 */
+#endif /* _USE_MKFS */
+#endif /* !_FS_READONLY */
 #endif /* _FS_MINIMIZE == 0 */
 #endif /* _FS_MINIMIZE <= 1 */
 #endif /* _FS_MINIMIZE <= 2 */
diff --git a/src/ff.h b/src/ff.h
index 9b11233..ce30ae8 100644
--- a/src/ff.h
+++ b/src/ff.h
@@ -1,5 +1,5 @@
 /*--------------------------------------------------------------------------/
-/  FatFs - FAT file system module include file  R0.04a       (C)ChaN, 2007
+/  FatFs - FAT file system module include file  R0.04b       (C)ChaN, 2007
 /---------------------------------------------------------------------------/
 / FatFs module is an experimenal project to implement FAT file system to
 / cheap microcontrollers. This is a free software and is opened for education,
@@ -36,13 +36,9 @@
 /  2: f_opendir and f_readdir are removed in addition to level 1.
 /  3: f_lseek is removed in addition to level 2. */
 
-#define _DRIVES		1
+#define _DRIVES		2
 /* Number of logical drives to be used. This affects the size of internal table. */
 
-#define	_USE_SJIS	1
-/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
-/  only US-ASCII(7bit) code can be accepted as file/directory name. */
-
 #define	_USE_MKFS	0
 /* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is
 /  enabled. */
@@ -52,6 +48,18 @@
 /  physical drive number and can mount only 1st primaly partition. When it is
 /  set to 1, each logical drive can mount a partition listed in Drives[]. */
 
+#define _USE_FSINFO	0
+/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
+
+#define	_USE_SJIS	1
+/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
+/  only US-ASCII(7bit) code can be accepted as file/directory name. */
+
+#define	_USE_NTFLAG	1
+/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
+/  Note that the files are always accessed in case insensitive. */
+
+
 #include "integer.h"
 
 
@@ -75,12 +83,20 @@ typedef struct _FATFS {
 	DWORD	fatbase;		/* FAT start sector */
 	DWORD	dirbase;		/* Root directory start sector (cluster# for FAT32) */
 	DWORD	database;		/* Data start sector */
+#if !_FS_READONLY
 	DWORD	last_clust;		/* Last allocated cluster */
-#if S_MAX_SIZ > 512
-	WORD	s_size;			/* Sector size */
+	DWORD	free_clust;		/* Number of free clusters */
+#if _USE_FSINFO
+	DWORD	fsi_sector;		/* fsinfo sector */
+	BYTE	fsi_flag;		/* fsinfo dirty flag (1:must be written back) */
+	BYTE	pad2;
+#endif
 #endif
 	BYTE	fs_type;		/* FAT sub type */
 	BYTE	sects_clust;	/* Sectors per cluster */
+#if S_MAX_SIZ > 512
+	WORD	s_size;			/* Sector size */
+#endif
 	BYTE	n_fats;			/* Number of FAT copies */
 	BYTE	drive;			/* Physical drive number */
 	BYTE	winflag;		/* win[] dirty flag (1:must be written back) */
@@ -270,6 +286,11 @@ DWORD get_fattime (void);	/* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20
 #define BS_VolLab32			71
 #define BS_FilSysType32		82
 
+#define	FSI_LeadSig			0
+#define	FSI_StrucSig		484
+#define	FSI_Free_Count		488
+#define	FSI_Nxt_Free		492
+
 #define MBR_Table			446
 
 #define	DIR_Name			0
diff --git a/src/tff.c b/src/tff.c
index 4692f5b..e4c9081 100644
--- a/src/tff.c
+++ b/src/tff.c
@@ -1,5 +1,5 @@
 /*--------------------------------------------------------------------------/
-/  FatFs - Tiny FAT file system module  R0.04a                (C)ChaN, 2007
+/  FatFs - Tiny FAT file system module  R0.04b                (C)ChaN, 2007
 /---------------------------------------------------------------------------/
 / The FatFs module is an experimenal project to implement FAT file system to
 / cheap microcontrollers. This is a free software and is opened for education,
@@ -15,7 +15,8 @@
 /---------------------------------------------------------------------------/
 /  Feb 26, 2006  R0.00  Prototype.
 /  Apr 29, 2006  R0.01  First stable version.
-/  Jun 01, 2006  R0.02  Added FAT12. Removed unbuffered mode.
+/  Jun 01, 2006  R0.02  Added FAT12 support.
+/                       Removed unbuffered mode.
 /                       Fixed a problem on small (<32M) patition.
 /  Jun 10, 2006  R0.02a Added a configuration option (_FS_MINIMUM).
 /  Sep 22, 2006  R0.03  Added f_rename().
@@ -23,16 +24,22 @@
 /  Dec 09, 2006  R0.03a Improved cluster scan algolithm to write files fast.
 /  Feb 04, 2007  R0.04  Added FAT32 supprt.
 /                       Changed some interfaces incidental to FatFs.
+/                       Changed f_mountdrv() to f_mount().
 /  Apr 01, 2007  R0.04a Added a capability of extending file size to f_lseek().
 /                       Added minimization level 3.
-/                       Fixed a problem that can collapse a sector when recreate
-/                       an existing file in any sub-directory at non FAT32 cfg.
+/                       Fixed a problem in FAT32 support.
+/  May 05, 2007  R0.04b Added a configuration option _USE_NTFLAG.
+/                       Added FSInfo support.
+/                       Fixed some problems corresponds to FAT32 support.
+/                       Fixed DBCS name can result FR_INVALID_NAME.
+/                       Fixed short seek (<= csize) collapses the file object.
 /---------------------------------------------------------------------------*/
 
 #include 
 #include "tff.h"		/* Tiny-FatFs declarations */
 #include "diskio.h"		/* Include file for user provided disk functions */
 
+
 static
 FATFS *FatFs;			/* Pointer to the file system objects (logical drive) */
 static
@@ -61,7 +68,7 @@ BOOL move_window (		/* TRUE: successful, FALSE: failed */
 
 	wsect = fs->winsect;
 	if (wsect != sector) {	/* Changed current window */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 		BYTE n;
 		if (fs->winflag) {	/* Write back dirty window if needed */
 			if (disk_write(0, fs->win, wsect, 1) != RES_OK)
@@ -91,12 +98,28 @@ BOOL move_window (		/* TRUE: successful, FALSE: failed */
 /* Clean-up cached data                                                  */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 FRESULT sync (void)		/* FR_OK: successful, FR_RW_ERROR: failed */
 {
-	FatFs->winflag = 1;
+	FATFS *fs = FatFs;
+
+
+	fs->winflag = 1;
 	if (!move_window(0)) return FR_RW_ERROR;
+#if _USE_FSINFO
+	if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {		/* Update FSInfo sector if needed */
+		fs->winsect = 0;
+		memset(fs->win, 0, 512);
+		ST_WORD(&fs->win[BS_55AA], 0xAA55);
+		ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252);
+		ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272);
+		ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust);
+		ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust);
+		disk_write(0, fs->win, fs->fsi_sector, 1);
+		fs->fsi_flag = 0;
+	}
+#endif
 	if (disk_ioctl(0, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR;
 	return FR_OK;
 }
@@ -133,7 +156,7 @@ CLUST get_cluster (		/* 0,>=2: successful, 1: failed */
 		case FS_FAT16 :
 			if (!move_window(fatsect + clust / 256)) break;
 			return LD_WORD(&fs->win[((WORD)clust * 2) % 512]);
-#if _FAT32 != 0
+#if _FAT32
 		case FS_FAT32 :
 			if (!move_window(fatsect + clust / 128)) break;
 			return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF;
@@ -151,7 +174,7 @@ CLUST get_cluster (		/* 0,>=2: successful, 1: failed */
 /* Change a cluster status                                               */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 	CLUST clust,		/* Cluster# to change */
@@ -182,7 +205,7 @@ BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 		if (!move_window(fatsect + clust / 256)) return FALSE;
 		ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val);
 		break;
-#if _FAT32 != 0
+#if _FAT32
 	case FS_FAT32 :
 		if (!move_window(fatsect + clust / 128)) return FALSE;
 		ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val);
@@ -194,7 +217,7 @@ BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 	fs->winflag = 1;
 	return TRUE;
 }
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -203,19 +226,26 @@ BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
 /* Remove a cluster chain                                                */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 BOOL remove_chain (		/* TRUE: successful, FALSE: failed */
 	CLUST clust			/* Cluster# to remove chain from */
 )
 {
 	CLUST nxt;
+	FATFS *fs = FatFs;
 
 
-	while (clust >= 2 && clust < FatFs->max_clust) {
+	while (clust >= 2 && clust < fs->max_clust) {
 		nxt = get_cluster(clust);
 		if (nxt == 1) return FALSE;
 		if (!put_cluster(clust, 0)) return FALSE;
+		if (fs->free_clust != (CLUST)0xFFFFFFFF) {
+			fs->free_clust++;
+#if _USE_FSINFO
+			fs->fsi_flag = 1;
+#endif
+		}
 		clust = nxt;
 	}
 	return TRUE;
@@ -229,7 +259,7 @@ BOOL remove_chain (		/* TRUE: successful, FALSE: failed */
 /* Stretch or create a cluster chain                                     */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 CLUST create_chain (	/* 0: no free cluster, 1: error, >=2: new cluster number */
 	CLUST clust			/* Cluster# to stretch, 0 means create new */
@@ -266,11 +296,18 @@ CLUST create_chain (	/* 0: no free cluster, 1: error, >=2: new cluster number */
 
 	if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1;	/* Mark the new cluster "in use" */
 	if (clust && !put_cluster(clust, ncl)) return 1;	/* Link it to previous one if needed */
-	fs->last_clust = ncl;
+
+	fs->last_clust = ncl;				/* Update fsinfo */
+	if (fs->free_clust != (CLUST)0xFFFFFFFF) {
+		fs->free_clust--;
+#if _USE_FSINFO
+		fs->fsi_flag = 1;
+#endif
+	}
 
 	return ncl;		/* Return new cluster number */
 }
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -347,7 +384,7 @@ void get_fileinfo (		/* No return code */
 
 
 	p = &finfo->fname[0];
-	a = dir[DIR_NTres];	/* NT flag */
+	a = _USE_NTFLAG ? dir[DIR_NTres] : 0;	/* NT flag */
 	for (n = 0; n < 8; n++) {	/* Convert file name (body) */
 		c = dir[n];
 		if (c == ' ') break;
@@ -396,39 +433,36 @@ char make_dirfile (			/* 1: error - detected an invalid format, '\0'or'/': next
 		c = *(*path)++;
 		if (c == '\0' || c == '/') {		/* Reached to end of str or directory separator */
 			if (n == 0) break;
-			dirname[11] = a & b; return c;
+			dirname[11] = _USE_NTFLAG ? (a & b) : 0;
+			return c;
 		}
-		if (c <= ' ') break;		/* Reject invisible chars */
+		if (c <= ' ' || c == 0x7F) break;		/* Reject invisible chars */
 		if (c == '.') {
-			if(!(a & 1) && n >= 1 && n <= 8) {	/* Enter extension part */
+			if (!(a & 1) && n >= 1 && n <= 8) {	/* Enter extension part */
 				n = 8; t = 11; continue;
 			}
 			break;
 		}
-#if _USE_SJIS != 0
-		if ((c >= 0x81 && c <= 0x9F) ||		/* Accept S-JIS code */
-		    (c >= 0xE0 && c <= 0xFC)) {
+		if (_USE_SJIS && 
+			((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 (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 == '|') break;			/* Reject | */
 			if (c >= '[' && c <= ']') break;/* Reject [ \ ] */
-			if (c >= 'A' && c <= 'Z')
+			if (_USE_NTFLAG && 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);
+				if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
 			}
 		}
 	md_l1:
@@ -461,7 +495,7 @@ FRESULT trace_path (	/* FR_OK(0): successful, !=0: error code */
 
 	/* Initialize directory object */
 	clust = fs->dirbase;
-#if _FAT32 != 0
+#if _FAT32
 	if (fs->fs_type == FS_FAT32) {
 		dirobj->clust = dirobj->sclust = clust;
 		dirobj->sect = clust2sect(clust);
@@ -493,12 +527,12 @@ FRESULT trace_path (	/* FR_OK(0): successful, !=0: error code */
 				return !ds ? FR_NO_FILE : FR_NO_PATH;
 		}
 		if (!ds) { *dir = dptr; return FR_OK; }				/* Matched with end of path */
-		if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH;/* Cannot trace because it is a file */
-#if _FAT32 != 0
-		clust = ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) | LD_WORD(&dptr[DIR_FstClusLO]);	/* Get cluster# of the directory */
-#else
-		clust = LD_WORD(&dptr[DIR_FstClusLO]);
+		if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH;	/* Cannot trace because it is a file */
+		clust =												/* Get cluster# of the directory */
+#if _FAT32
+			((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) |
 #endif
+			LD_WORD(&dptr[DIR_FstClusLO]);
 		dirobj->clust = dirobj->sclust = clust;				/* Restart scannig with the new directory */
 		dirobj->sect = clust2sect(clust);
 		dirobj->index = 2;
@@ -511,7 +545,7 @@ FRESULT trace_path (	/* FR_OK(0): successful, !=0: error code */
 /* Reserve a directory entry                                             */
 /*-----------------------------------------------------------------------*/
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 static
 FRESULT reserve_direntry (	/* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */
 	DIR *dirobj,			/* Target directory to create new entry */
@@ -559,7 +593,7 @@ FRESULT reserve_direntry (	/* FR_OK: successful, FR_DENIED: no free entry, FR_RW
 	*dir = fs->win;
 	return FR_OK;
 }
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -582,7 +616,7 @@ BYTE check_fs (		/* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2
 
 	if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3))	/* Check FAT signature */
 		return 0;
-#if _FAT32 != 0
+#if _FAT32
 	if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))
 		return 0;
 #endif
@@ -604,7 +638,7 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 {
 	BYTE fmt;
 	DSTATUS stat;
-	DWORD basesect, fatsize, totalsect, maxclust;
+	DWORD bootsect, fatsize, totalsect, maxclust;
 	const char *p = *path;
 	FATFS *fs = FatFs;
 
@@ -621,7 +655,7 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	if (fs->fs_type) {
 		stat = disk_status(0);
 		if (!(stat & STA_NOINIT)) {				/* If the physical drive is kept initialized */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 			if (chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
 				return FR_WRITE_PROTECTED;
 #endif
@@ -635,18 +669,18 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	stat = disk_initialize(0);			/* Initialize low level disk I/O layer */
 	if (stat & STA_NOINIT)				/* Check if the drive is ready */
 		return FR_NOT_READY;
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	if (chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
 		return FR_WRITE_PROTECTED;
 #endif
 
 	/* Search FAT partition on the drive */
-	fmt = check_fs(basesect = 0);		/* Check sector 0 as an SFD format */
+	fmt = check_fs(bootsect = 0);		/* Check sector 0 as an SFD format */
 	if (fmt == 1) {						/* Not a FAT boot record, it may be patitioned */
 		/* Check a partition listed in top of the partition table */
 		if (fs->win[MBR_Table+4]) {					/* Is the 1st partition existing? */
-			basesect = LD_DWORD(&fs->win[MBR_Table+8]);	/* Partition offset in LBA */
-			fmt = check_fs(basesect);				/* Check the partition */
+			bootsect = LD_DWORD(&fs->win[MBR_Table+8]);	/* Partition offset in LBA */
+			fmt = check_fs(bootsect);				/* Check the partition */
 		}
 	}
 	if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512)	/* No valid FAT patition is found */
@@ -658,8 +692,7 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	fs->sects_fat = (CLUST)fatsize;
 	fs->n_fats = fs->win[BPB_NumFATs];					/* Number of FAT copies */
 	fatsize *= fs->n_fats;								/* (Number of sectors in FAT area) */
-	fs->fatbase = basesect += LD_WORD(&fs->win[BPB_RsvdSecCnt]);	/* FAT start sector (lba) */
-	basesect += fatsize;								/* (Next sector of FAT area (lba)) */
+	fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]);	/* FAT start sector (lba) */
 	fs->sects_clust = fs->win[BPB_SecPerClus];			/* Number of sectors per cluster */
 	fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]);	/* Nmuber of root directory entries */
 	totalsect = LD_WORD(&fs->win[BPB_TotSec16]);		/* Number of sectors on the file system */
@@ -671,7 +704,7 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 	fmt = FS_FAT12;										/* Determine the FAT sub type */
 	if (maxclust > 0xFF7) fmt = FS_FAT16;
 	if (maxclust > 0xFFF7)
-#if _FAT32 == 0
+#if !_FAT32
 		return FR_NO_FILESYSTEM;
 #else
 		fmt = FS_FAT32;
@@ -679,12 +712,27 @@ FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
 		fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]);	/* Root directory start cluster */
 	else
 #endif
-		fs->dirbase = basesect;							/* Root directory start sector (lba) */
-	fs->database = basesect + fs->n_rootdir / 16;		/* Data start sector (lba) */
-	fs->fs_type = fmt;
+		fs->dirbase = fs->fatbase + fatsize;			/* Root directory start sector (lba) */
+	fs->database = fs->fatbase + fatsize + fs->n_rootdir / 16;	/* Data start sector (lba) */
+	fs->fs_type = fmt;									/* FAT sub-type */
 
+#if !_FS_READONLY
+	fs->free_clust = (CLUST)0xFFFFFFFF;
+#if _USE_FSINFO
+	/* Load fsinfo sector if needed */
+	if (fmt == FS_FAT32) {
+		fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]);
+		if (disk_read(0, fs->win, fs->fsi_sector, 1) == RES_OK &&
+			LD_WORD(&fs->win[BS_55AA]) == 0xAA55 &&
+			LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 &&
+			LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272) {
+			fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]);
+			fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]);
+		}
+	}
+#endif
+#endif
 	fs->id = ++fsid;									/* File system mount ID */
-
 	return FR_OK;
 }
 
@@ -760,7 +808,8 @@ FRESULT f_open (
 	FATFS *fs = FatFs;
 
 
-#if _FS_READONLY == 0
+	fp->fs = NULL;
+#if !_FS_READONLY
 	mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
 	res = auto_mount(&path, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
 #else
@@ -772,7 +821,7 @@ FRESULT f_open (
 	/* Trace the file path */
 	res = trace_path(&dirobj, fn, path, &dir);	/* Trace the file path */
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	/* Create or Open a File */
 	if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
 		CLUST rs;
@@ -791,7 +840,7 @@ FRESULT f_open (
 			if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR)))	/* Cannot overwrite (R/O or DIR) */
 				return FR_DENIED;
 			if (mode & FA_CREATE_ALWAYS) {		/* Resize it to zero */
-#if _FAT32 != 0
+#if _FAT32
 				rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
 				ST_WORD(&dir[DIR_FstClusHI], 0);
 #else
@@ -816,11 +865,11 @@ FRESULT f_open (
 	}
 	/* Open a File */
 	else {
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 		if (res != FR_OK) return res;		/* Trace failed */
 		if (dir == NULL || (dir[DIR_Attr] & AM_DIR))	/* It is a directory */
 			return FR_NO_FILE;
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 		if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
 			return FR_DENIED;
 	}
@@ -829,8 +878,12 @@ FRESULT f_open (
 	fp->dir_ptr = dir;
 #endif
 	fp->flag = mode;							/* File access mode */
-	fp->org_clust =	LD_WORD(&dir[DIR_FstClusLO]);	/* File start cluster */
-	fp->fsize = LD_DWORD(&dir[DIR_FileSize]);		/* File size */
+	fp->org_clust =								/* File start cluster */
+#if _FAT32
+		((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
+#endif
+		LD_WORD(&dir[DIR_FstClusLO]);
+	fp->fsize = LD_DWORD(&dir[DIR_FileSize]);	/* File size */
 	fp->fptr = 0;								/* File ptr */
 	fp->sect_clust = 1;							/* Sector counter */
 	fp->fs = fs; fp->id = fs->id;				/* Owner file system object of the file */
@@ -909,7 +962,7 @@ fr_error:	/* Abort this function due to an unrecoverable error */
 
 
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 /*-----------------------------------------------------------------------*/
 /* Write File                                                            */
 /*-----------------------------------------------------------------------*/
@@ -1015,7 +1068,7 @@ FRESULT f_sync (
 			dir[DIR_Attr] |= AM_ARC;						/* Set archive bit */
 			ST_DWORD(&dir[DIR_FileSize], fp->fsize);		/* Update file size */
 			ST_WORD(&dir[DIR_FstClusLO], fp->org_clust);	/* Update start cluster */
-#if _FAT32 != 0
+#if _FAT32
 			ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16);
 #endif
 			tim = get_fattime();					/* Updated time */
@@ -1027,7 +1080,7 @@ FRESULT f_sync (
 	return res;
 }
 
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 
 
 
@@ -1043,7 +1096,7 @@ FRESULT f_close (
 	FRESULT res;
 
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	res = f_sync(fp);
 #else
 	res = validate(fp->fs, fp->id);
@@ -1078,7 +1131,7 @@ FRESULT f_lseek (
 	if (res) return res;
 
 	if (fp->flag & FA__ERROR) return FR_RW_ERROR;
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	if (ofs > fp->fsize && !(fp->flag & FA_WRITE))
 #else
 	if (ofs > fp->fsize)
@@ -1089,38 +1142,38 @@ FRESULT f_lseek (
 	/* Move file R/W pointer if needed */
 	if (ofs) {
 		clust = fp->org_clust;	/* Get start cluster */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 		if (!clust) {			/* If the file does not have a cluster chain, create new cluster chain */
 			clust = create_chain(0);
 			if (clust == 1) goto fk_error;
-			fp->org_clust = fp->curr_clust = clust;
+			fp->org_clust = clust;
 		}
 #endif
 		if (clust) {			/* If the file has a cluster chain, it can be followed */
 			csize = (DWORD)fs->sects_clust * 512;		/* Cluster size in unit of byte */
-			while (ofs > csize) {						/* Skip leading clusters */
-#if _FS_READONLY == 0
-				if (fp->flag & FA_WRITE)					/* Check if in write mode or not */
-					clust = create_chain(clust);			/* Force streached if in write mode */
+			for (;;) {									/* Loop to skip leading clusters */
+				fp->curr_clust = clust;					/* Update current cluster */
+				if (ofs <= csize) break;
+#if !_FS_READONLY
+				if (fp->flag & FA_WRITE)				/* Check if in write mode or not */
+					clust = create_chain(clust);		/* Force streached if in write mode */
 				else
 #endif
-					clust = get_cluster(clust);				/* Only follow cluster chain if not in write mode */
-				if (clust == 0) {							/* Stop if could not follow the cluster chain */
-					ofs = csize;
-					break;
+					clust = get_cluster(clust);			/* Only follow cluster chain if not in write mode */
+				if (clust == 0) {						/* Stop if could not follow the cluster chain */
+					ofs = csize; break;
 				}
-				if (clust == 1 || clust >= fs->max_clust) goto fk_error; /* Abort when any error occured */
-				fp->curr_clust = clust;						/* Update current cluster and R/W pointer */
-				fp->fptr += csize;
+				if (clust == 1 || clust >= fs->max_clust) goto fk_error;
+				fp->fptr += csize;						/* Update R/W pointer */
 				ofs -= csize;
 			}
 			csect = (BYTE)((ofs - 1) / 512);			/* Sector offset in the cluster */
-			fp->curr_sect = clust2sect(clust) + csect;	/* Get current cluster */
+			fp->curr_sect = clust2sect(clust) + csect;	/* Current sector */
 			fp->sect_clust = fs->sects_clust - csect;	/* Left sector counter in the cluster */
 			fp->fptr += ofs;							/* Update file R/W pointer */
 		}
 	}
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) {	/* Set updated flag if in write mode */
 		fp->fsize = fp->fptr;
 		fp->flag |= FA__WRITTEN;
@@ -1160,11 +1213,11 @@ FRESULT f_opendir (
 	if (res == FR_OK) {							/* Trace completed */
 		if (dir != NULL) {						/* It is not the root dir */
 			if (dir[DIR_Attr] & AM_DIR) {		/* The entry is a directory */
-#if _FAT32 != 0
-				dirobj->clust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
-#else
-				dirobj->clust = LD_WORD(&dir[DIR_FstClusLO]);
+	 			dirobj->clust =
+#if _FAT32
+					((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
 #endif
+					LD_WORD(&dir[DIR_FstClusLO]);
 				dirobj->sect = clust2sect(dirobj->clust);
 				dirobj->index = 2;
 			} else {						/* The entry is not a directory */
@@ -1248,7 +1301,7 @@ FRESULT f_stat (
 
 
 
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 /*-----------------------------------------------------------------------*/
 /* Get Number of Free Clusters                                           */
 /*-----------------------------------------------------------------------*/
@@ -1271,6 +1324,12 @@ FRESULT f_getfree (
 	if (res != FR_OK) return res;
 	*fatfs = fs = FatFs;
 
+	/* If number of free cluster is valid, return it without cluster scan. */
+	if (fs->free_clust <= fs->max_clust - 2) {
+		*nclust = fs->free_clust;
+		return FR_OK;
+	}
+
 	/* Count number of free clusters */
 	fat = fs->fs_type;
 	n = 0;
@@ -1288,7 +1347,7 @@ FRESULT f_getfree (
 				if (!move_window(sect++)) return FR_RW_ERROR;
 				p = fs->win;
 			}
-			if (_FAT32 == 0 || fat == FS_FAT16) {
+			if (!_FAT32 || fat == FS_FAT16) {
 				if (LD_WORD(p) == 0) n++;
 				p += 2; f += 1;
 			} else {
@@ -1297,6 +1356,10 @@ FRESULT f_getfree (
 			}
 		} while (--clust);
 	}
+	fs->free_clust = n;
+#if _USE_FSINFO
+	if (fat == FS_FAT32) fs->fsi_flag = 1;
+#endif
 
 	*nclust = n;
 	return FR_OK;
@@ -1330,11 +1393,11 @@ FRESULT f_unlink (
 	if (dir == NULL) return FR_INVALID_NAME;	/* It is the root directory */
 	if (dir[DIR_Attr] & AM_RDO) return FR_DENIED;	/* It is a R/O object */
 	dsect = fs->winsect;
-#if _FAT32 != 0
-	dclust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
-#else
-	dclust = LD_WORD(&dir[DIR_FstClusLO]);
+	dclust =
+#if _FAT32
+		((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
 #endif
+		LD_WORD(&dir[DIR_FstClusLO]);
 	if (dir[DIR_Attr] & AM_DIR) {				/* It is a sub-directory */
 		dirobj.clust = dclust;					/* Check if the sub-dir is empty or not */
 		dirobj.sect = clust2sect(dclust);
@@ -1367,7 +1430,7 @@ FRESULT f_mkdir (
 	const char *path		/* Pointer to the directory path */
 )
 {
-	BYTE *dir, *sec, n;
+	BYTE *dir, *fw, n;
 	char fn[8+3+1];
 	DWORD sect, dsect, tim;
 	CLUST dclust, pclust;
@@ -1390,40 +1453,39 @@ FRESULT f_mkdir (
 	if (dclust == 1) return FR_RW_ERROR;
 	dsect = clust2sect(dclust);
 	if (!dsect) return FR_DENIED;
-	if (!move_window(0)) return FR_RW_ERROR;
+	if (!move_window(dsect)) return FR_RW_ERROR;
 
-	sec = fs->win;
-	memset(sec, 0, 512);						/* Initialize the directory table */
-	for (n = fs->sects_clust - 1; n; n--) {
-		if (disk_write(0, sec, dsect+n, 1) != RES_OK)
+	fw = fs->win;
+	memset(fw, 0, 512);							/* Clear the directory table */
+	for (n = 1; n < fs->sects_clust; n++) {
+		if (disk_write(0, fw, ++dsect, 1) != RES_OK)
 			return FR_RW_ERROR;
 	}
 
-	fs->winsect = dsect;						/* Create "." ".." directories */
-	memset(&sec[DIR_Name], ' ', 8+3);			/* "." entry */
-	sec[DIR_Name] = '.';
-	sec[DIR_Attr] = AM_DIR;
+	memset(&fw[DIR_Name], ' ', 8+3);			/* Create "." entry */
+	fw[DIR_Name] = '.';
+	fw[DIR_Attr] = AM_DIR;
 	tim = get_fattime();
-	ST_DWORD(&sec[DIR_WrtTime], tim);
-	memcpy(&sec[32], &sec[0], 32); sec[33] = '.'; /* ".." entry */
+	ST_DWORD(&fw[DIR_WrtTime], tim);
+	memcpy(&fw[32], &fw[0], 32); fw[33] = '.';	/* Create ".." entry */
 	pclust = dirobj.sclust;
-	ST_WORD(&sec[   DIR_FstClusLO], dclust);
-	ST_WORD(&sec[32+DIR_FstClusLO], pclust);
-#if _FAT32 != 0
-	ST_WORD(&sec[  +DIR_FstClusHI], dclust >> 16);
+#if _FAT32
+	ST_WORD(&fw[   DIR_FstClusHI], dclust >> 16);
 	if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0;
-	ST_WORD(&sec[32+DIR_FstClusHI], pclust >> 16);
+	ST_WORD(&fw[32+DIR_FstClusHI], pclust >> 16);
 #endif
+	ST_WORD(&fw[   DIR_FstClusLO], dclust);
+	ST_WORD(&fw[32+DIR_FstClusLO], pclust);
 	fs->winflag = 1;
-	if (!move_window(sect)) return FR_RW_ERROR;
 
-	memset(&dir[0], 0, 32);						/* Initialize the new entry */
+	if (!move_window(sect)) return FR_RW_ERROR;
+	memset(&dir[0], 0, 32);						/* Clean-up the new entry */
 	memcpy(&dir[DIR_Name], fn, 8+3);			/* Name */
 	dir[DIR_NTres] = fn[11];
 	dir[DIR_Attr] = AM_DIR;						/* Attribute */
 	ST_DWORD(&dir[DIR_WrtTime], tim);			/* Crated time */
 	ST_WORD(&dir[DIR_FstClusLO], dclust);		/* Table start cluster */
-#if _FAT32 != 0
+#if _FAT32
 	ST_WORD(&dir[DIR_FstClusHI], dclust >> 16);
 #endif
 
@@ -1506,12 +1568,12 @@ FRESULT f_rename (
 	fs->winflag = 1;
 
 	if (!move_window(sect_old)) return FR_RW_ERROR;	/* Remove old entry */
-	*dir_old = 0xE5;
+	dir_old[DIR_Name] = 0xE5;
 
 	return sync();
 }
 
-#endif /* _FS_READONLY == 0 */
+#endif /* !_FS_READONLY */
 #endif /* _FS_MINIMIZE == 0 */
 #endif /* _FS_MINIMIZE <= 1 */
 #endif /* _FS_MINIMIZE <= 2 */
diff --git a/src/tff.h b/src/tff.h
index dd1d222..e5f5807 100644
--- a/src/tff.h
+++ b/src/tff.h
@@ -1,5 +1,5 @@
 /*--------------------------------------------------------------------------/
-/  Tiny-FatFs - FAT file system module include file  R0.04a   (C)ChaN, 2007
+/  Tiny-FatFs - FAT file system module include file  R0.04b   (C)ChaN, 2007
 /---------------------------------------------------------------------------/
 / FatFs module is an experimenal project to implement FAT file system to
 / cheap microcontrollers. This is a free software and is opened for education,
@@ -37,21 +37,30 @@
 /  3: f_lseek is removed in addition to level 2. */
 
 #define _FAT32	0
-/* To add FAT32 support, set _FAT32 to 1. */
+/* To enable FAT32 support in addition of FAT12/16, set _FAT32 to 1. */
+
+#define _USE_FSINFO	0
+/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
 
 #define	_USE_SJIS	1
 /* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
 /  only US-ASCII(7bit) code can be accepted as file/directory name. */
 
+#define	_USE_NTFLAG	1
+/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
+/  Note that the files are always accessed in case insensitive. */
+
 
 #include "integer.h"
 
 
 /* Type definition for cluster number */
-#if _FAT32 == 0
-typedef WORD	CLUST;
-#else
+#if _FAT32
 typedef DWORD	CLUST;
+#else
+typedef WORD	CLUST;
+#undef _USE_FSINFO
+#define _USE_FSINFO	0
 #endif
 
 
@@ -65,7 +74,15 @@ typedef struct _FATFS {
 	DWORD	database;		/* Data start sector */
 	CLUST	sects_fat;		/* Sectors per fat */
 	CLUST	max_clust;		/* Maximum cluster# + 1 */
+#if !_FS_READONLY
 	CLUST	last_clust;		/* Last allocated cluster */
+	CLUST	free_clust;		/* Number of free clusters */
+#if _USE_FSINFO
+	DWORD	fsi_sector;		/* fsinfo sector */
+	BYTE	fsi_flag;		/* fsinfo dirty flag (1:must be written back) */
+	BYTE	pad1;
+#endif
+#endif
 	BYTE	fs_type;		/* FAT sub type */
 	BYTE	sects_clust;	/* Sectors per cluster */
 	BYTE	n_fats;			/* Number of FAT copies */
@@ -96,7 +113,7 @@ typedef struct _FIL {
 	CLUST	org_clust;		/* File start cluster */
 	CLUST	curr_clust;		/* Current cluster */
 	DWORD	curr_sect;		/* Current sector */
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 	DWORD	dir_sect;		/* Sector containing the directory entry */
 	BYTE*	dir_ptr;		/* Ponter to the directory entry in the window */
 #endif
@@ -164,7 +181,7 @@ DWORD get_fattime (void);	/* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16
 
 #define	FA_READ				0x01
 #define	FA_OPEN_EXISTING	0x00
-#if _FS_READONLY == 0
+#if !_FS_READONLY
 #define	FA_WRITE			0x02
 #define	FA_CREATE_NEW		0x04
 #define	FA_CREATE_ALWAYS	0x08
@@ -229,6 +246,11 @@ DWORD get_fattime (void);	/* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16
 #define BS_VolLab32			71
 #define BS_FilSysType32		82
 
+#define	FSI_LeadSig			0
+#define	FSI_StrucSig		484
+#define	FSI_Free_Count		488
+#define	FSI_Nxt_Free		492
+
 #define MBR_Table			446
 
 #define	DIR_Name			0