exFAT 構造解析 2008/06/27 K.Takata 1.初めに  この文書では、Windows Vista SP1 と Windows CE 6.0 で新たに採用された ファイルシステムである exFAT の構造を独自に解析した結果を示す。 2.仕様の概要  exFAT の仕様の概要を示す。以下は、WinHEC 2006 のスライド [1] および、 MSDN の情報 [2,3] からの抜粋である。 ・フラッシュメディア向けのファイルシステム ・32GB より大きなメディアに対応 ・1つのディレクトリで千以上のファイルを扱える ・空きスペースビットマップ - 高速な領域割り当て、高速な削除 ・ファイルサイズを 64bit で管理 ・大きなクラスタサイズ(理論上の最大は 2^255、実装上の最大は 32MB) ・将来への拡張性 - 柔軟で拡張可能なディレクトリ構造 - 互換性を保ったまま機能追加可能 ・ファイル名のハッシュ - 大文字ファイル名の 2バイトチェックサム - ファイル名のチェックの高速化 ・OEM 固有パラメータ ・Transaction-Safe FAT (TFAT) ・FAT32 との後方互換性は無し ・短いファイル名は無し  また、解析結果から類推される仕様を以下に示す。 ・ボリュームサイズは最大で、セクタサイズ × 2^64 (512Bセクタで 8ZiB) ・32bit クラスタ番号 - クラスタ番号の扱い方は従来と同様 ・ファイル名のハッシュ算出用の大文字変換テーブルを持つ ・FAT32 と同様に、ルートディレクトリは特殊なサブディレクトリの扱い - ルートディレクトリのサイズ拡張可能 ・空きスペースビットマップと大文字変換テーブルは特殊なファイルの扱い 3.解析結果 3.1. ボリューム先頭 ・セクタ 0 +00h: BYTE[3] ジャンプ命令 +03h: BYTE[8] OEM名 ("EXFAT ") +0bh: BPB32 (00h) +40h: DWORD ??? (78h) +44h: DWORD ??? (00h) +48h: QWORD ボリュームのセクタ数 +50h: DWORD FAT開始セクタ番号 +54h: DWORD FATセクタ数 +58h: DWORD 先頭クラスタ開始セクタ番号 +5ch: DWORD ボリュームのクラスタ数 +60h: DWORD ルートディレクトリ開始クラスタ番号 +64h: DWORD Volume ID +68h: DWORD ??? (0100h) +6ch: BYTE SectorSizeShift +6dh: BYTE ClusterShift +6eh: BYTE ??? (01h) +6fh: BYTE ??? (80h) +1feh: WORD Signature (AA55h) FAT32 の BPB に相当する +0bh〜+3fh の部分は 0 で埋められている。 SectorSize = 1 << SectorSizeShift ClusterSize = SectorSize << ClusterShift ・セクタ 0〜8 +00h: BYTE[510] Data (00h) +1feh: WORD Signature (AA55h) ・セクタ 9〜10 空き? ・セクタ 11 不明 (ex. 3ah cbh 3fh abh ...) ・セクタ 12〜23 セクタ 0〜11 のバックアップ ・セクタ 24〜FAT直前 空き 3.2. ディレクトリエントリ ディレクトリエントリは 1つ 32bytes から成り、それらを複数組み合わせて 1つの ファイルの情報を表す。ディレクトリエントリの先頭 1byte は、エントリの種別を 示しており、残りの 31bytes は種別により異なる情報が格納される。 現在確認できているエントリ種別は以下の通り。詳細は後述。 ・81h, 82h, 83h, 85h, C0h, C1h, 05h, 40h, 41h, 00h ルートディレクトリには、通常、先頭から 83h, 81h, 82h の順にディレクトリ エントリが並び、一般のファイルはその後に並ぶ。 一般のファイルやサブディレクトリのディレクトリエントリは、85h, C0h, C1h の 順に並ぶ。ファイル名が 15文字を超える場合は、C1h が複数並ぶ。 (例: 85h, C0h, C1h, C1h ... C1h) 従来 FAT とは異なり、サブディレクトリには、親ディレクトリや自身を示す ".." や "." といったディレクトリエントリは作成されない。 ○ DirectoryEntry +00h: BYTE type +01h: BYTE[31] Data ○ type=83h VolumeID +00h: BYTE type (83h) +01h: BYTE len (max:11) +02h: WCHAR[11] VolumeID +18h: BYTE[8] reserved ボリューム名を格納するエントリ。 ○ type=81h ClusterBitmapFile +00h: BYTE type (81h) +01h: BYTE reserved (00h) +02h: BYTE[18] reserved +14h: DWORD StartCluster (0002h) +18h: QWORD FileSize クラスタの使用状況を示すビットマップを格納した特殊ファイルの格納位置とサイズを 示すエントリ。 ○ type=82h CharUpperTableFile +00h: BYTE type (82h) +01h: BYTE reserved (00h) +02h: BYTE[2] reserved +04h: DWORD ??? +08h: BYTE[12] reserved +14h: DWORD StartCluster +18h: QWORD FileSize ファイル名のハッシュの算出に使用する、大文字変換テーブルを格納した特殊ファイル の格納位置とサイズを示すエントリ。 ○ type=85h FileAttributes1 +00h: BYTE type (85h) +01h: BYTE AdditionalEntryNum (2〜18 ?) +02h: WORD Checksum +04h: DWORD Attributes +08h: DWORD CreationTime +0Ch: DWORD LastWriteTime +10h: DWORD LastAccessTime +14h: BYTE CreationTime (10ms) +15h: BYTE[3] reserved +18h: BYTE[8] reserved ファイルの属性などを格納するエントリ。 ・日時の形式は従来 FAT と同様。 ・Checksum の算出方法は後述。 ・Attributes の値は、従来 FAT と同様。 ○ type=C0h FileAttributes2 +00h: BYTE type (C0h) +01h: BYTE FragmentFlag ??? (01h or 03h) +02h: BYTE reserved ??? +03h: BYTE FileNameLength WCHAR単位のファイル名長 +04h: WORD FileNameHash +06h: WORD reserved +08h: QWORD FileSize1 +10h: DWORD reserved +14h: DWORD StartCluster +18h: QWORD FileSize2 ファイルの属性などを格納するエントリ。 ・ファイルサイズが 2つあるが、NTFS のようなファイルの圧縮を想定したものと 思われる。どちらが圧縮後のファイルサイズかは不明。(現在はどちらも同じ値が 格納されている。) ・FragmentFlag は、ファイルサイズが 0 のとき、あるいはファイルが分断している ときは 01h、ファイルが連続しているときは 03h となる模様。(詳細不明) ・FileNameHash の算出方法は後述。 ・従来 FAT とは異なり、ディレクトリの場合にもファイルサイズが書き込まれる。 (クラスタビットマップだけではどこまでで終わりとなるかが分からないため。) サイズは、クラスタサイズの倍数となる。 ○ type=C1h FileName +00h: BYTE type (C1h) +01h: BYTE reserved +02h: WCHAR[15] FileName ファイル名を格納するエントリ。 ・ファイル名が 15文字を超える場合は複数使用する。その際、ファイル名は先頭から 順に格納する。(従来 FAT のように逆順にはならない。) ○ type=05h, 40h, 41h DeletedEntry 削除済みエントリ。 ・ファイルを削除した場合、type の最上位ビットは 0 になる。 ・削除の際、チェックサムの再計算は行わない。 ○ type=00h LastEntry 最後のエントリ。 ・Checksum 算出方法  ディレクトリエントリの整合性を確認するためのチェックサムの算出方法を示す。 通常、ファイルの情報は複数のディレクトリエントリに渡って格納されているが、 チェックサムはそれらのエントリ全体に対して計算を行う。なお、チェックサム 算出時には、チェックサム領域そのものは飛ばして計算する。 WORD CalcChecksum(LPCBYTE entry) { WORD chk = 0; int len, i; len = 32 * (entry[1] + 1); for (i = 0; i < len; i++) { if (i == 2 || i == 3) continue; chk = (WORD) (((chk << 15) | (chk >> 1)) + entry[i]); } return chk; } ・ファイル名ハッシュ算出方法  ファイル名のハッシュは、Unicode で大文字に変換してから 1バイト単位で計算を 行う。大文字への変換は、下記のコードでは CharUpperW() を利用しているが、実際 には後述の大文字変換テーブルを用いる。 WORD CalcFileNameHash(LPCWSTR filename) { WORD chk = 0; int len, i; len = lstrlenW(filename); for (i = 0; i < len; i++) { WCHAR c = (WCHAR) CharUpperW((LPWSTR) filename[i]); chk = (WORD) (((chk << 15) | (chk >> 1)) + LOBYTE(c)); chk = (WORD) (((chk << 15) | (chk >> 1)) + HIBYTE(c)); } return chk; } 3.3. FAT  FAT の構造は FAT32 とほぼ同等。ただし、クラスタ番号は 28bit ではなく、32bit となっている。  FAT の個数は 1個。(TFAT を使う場合は 2個?)  クラスタビットマップ、大文字変換テーブル、ルートディレクトリは、必ず FAT に クラスタの使用状況が書き込まれるが、それ以外のファイル・ディレクトリについて は、分断が発生した場合だけクラスタ使用状況が書き込まれる。 3.4. クラスタビットマップ  クラスタの使用状況を示したビットマップ。1bit が 1クラスタに対応しており、 先頭クラスタである No.2 クラスタは 0バイト目の 0bit に対応する。 ビットが立っていれば、そのクラスタは使用中である。  FAT 上での使用状況と、ビットマップ上での使用状況が一致していない場合は、 ビットマップの方が優先される。 3.5. 大文字変換テーブル  ファイル名ハッシュの算出の際に利用する大文字への変換テーブルである。 WCHAR 単位で、U+0000 から U+FFFF までの変換情報が格納されているが、サイズ 削減のため、変換の必要ない部分に関しては省略されている。有効な区間の終端には FFFFh が格納され、その次の 2バイトには、スキップする文字数が格納されている。  以下に、大文字変換テーブルの例を示す。 +0000h: 0000h (U+0000) +0002h: 0001h (U+0001) +0004h: 0002h (U+0002) : +0B0Ch: 0556h (U+0586) +0B0Eh: FFFFh 終端 +0B10h: 17F6h スキップ数 +0B12h: 2C63h (U+1D7D) (0586h + 17F6h + 1 = 1D7Dh) +0B14h: 1D7Eh (U+1D7E) : +1320h: 2183h (U+2184) +1322h: FFFFh 終端 +1324h: 034Bh スキップ数 +1326h: 24B6h (U+24D0) (2184h + 034Bh + 1 = 24D0h) : +1358h: 24CFh (U+24E9) +135Ah: FFFFh 終端 +135Ch: 0746h スキップ数 +135Eh: 2C00h (U+2C30) (24E9h + 0746h + 1 = 2C30h) : +1548h: 10C5h (U+2D25) +154Ah: FFFFh 終端 +154Ch: D21Bh スキップ数 +154Eh: FF21h (U+FF41) (2D25h + D12Bh + 1 = FF41h) : +16C8h: FFFEh (U+FFFE) +16CAh: FFFFh (U+FFFF) 終端 4.更新履歴 2008/06/25 ・初公開。 2008/06/27 ・小修正。 5.参考文献 [1] Personal Storage: Opportunities and Challenges for Pocket-Sized Storage Devices in the Windows World http://download.microsoft.com/download/5/b/9/5b97017b-e28a-4bae-ba48-174cf47d23cd/STO072_WH06.ppt [2] Extended FAT File System http://msdn.microsoft.com/en-us/library/aa914353.aspx [3] Transaction-Safe FAT File System http://msdn.microsoft.com/en-us/library/aa911939.aspx [4] FAT32 File System Specification http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx -- K.Takata http://webs.to/ken/ http://homepage3.nifty.com/k-takata/