File Allocation Table(FAT)ファミリーは、小規模なMicrosoftシステムで始まり、DOSおよびIBM PCメディアの交換形式になった。単純なデータ構造により、FATはブートファームウェアや制約のあるオペレーティングシステムで実用的だった。同じ設計にはジャーナリング、所有権、トランザクションのセマンティクスがないため、現在も使われ続けている理由は障害の分離ではなく、相互運用性にある。
ボリュームレイアウト #
FATボリュームは、論理セクター単位で測定される領域から構成される。
- 予約領域は、ボリュームブートセクターとそのBIOS Parameter Block(BPB)から始まる。FAT32では、ここにFSInfoセクターと、通常はブートセクターのバックアップも配置できる。
- 1つ以上の FATコピーには、固定幅の割り当てエントリが含まれる。2つのコピーが慣例的だが、実際の数はBPBに記録される。
- ルートディレクトリ領域の位置とエントリ数は、FAT12およびFAT16では固定されている。
- データ領域には番号付きクラスターが含まれる。FAT32では、ルートディレクトリは固定領域ではなく、この領域内の通常のクラスター・チェーンとなる。
BPBには、1セクターあたりのバイト数、クラスターあたりのセクター数、予約セクター数、FAT数、総セクター数、FATサイズが記録される。読み取り側は、ディレクトリのシグネチャを検索するのではなく、それらのフィールドから領域境界を導出する。BPBが破損していると、読み取りがボリューム外へ誘導される可能性があるため、算術演算ではオーバーフローを検査しなければならない。
クラスターとFATの分類 #
クラスターはファイルシステムの割り当て単位であり、Microsoftが定義したFAT形式では、2のべき乗個のセクターを含む。クラスター番号0と1は予約済みで、データクラスターは2から始まる。データクラスター数はBPBから次のように求められる。
root_dir_sectors =
ceil(root_entry_count × 32 / bytes_per_sector)
first_data_sector =
reserved_sectors + fat_count × sectors_per_fat + root_dir_sectors
data_clusters =
floor((total_sectors - first_data_sector) / sectors_per_cluster)ボリュームを分類するのはラベル文字列やパーティションタイプのバイトではなく、クラスター数である。
| 分類 | データクラスター数 | エントリ表現 |
|---|---|---|
| FAT12 | 4,085未満 | パックされた12ビットエントリ |
| FAT16 | 4,085以上65,524以下 | 16ビットエントリ |
| FAT32 | 65,525以上 | 32ビットエントリ、下位28ビットが有効 |
実用上の上限は、クラスターサイズ、実装方針、BPB内のフィールドにも依存する。幅の広いエントリはより多くのクラスターを扱えるが、FATコピーごとにより多くのセクターを消費する。
割り当てエントリとクラスター・チェーン #
各FATエントリは、対応するクラスターを記述する。値は次のいずれかを表す。
- 空きクラスターを示すゼロ
- チェーン内の次のリンクを示す別のクラスター番号
- 予約済みまたは不良クラスターのマーカー
- チェーン終端の範囲にある値
ファイルの短いディレクトリエントリには、最初のクラスターとバイト長が格納される。ファイルの読み取りはそこから始まり、必要なバイト数を取得するか、終端マーカーが現れるまでFATリンクをたどる。最後のクラスターには、論理長を超えるスラックバイトが含まれることがある。FAT32のディレクトリ、およびルート以外のすべてのディレクトリも同じチェーン機構を使用する。
リンク割り当てにより、ファイルは連続した1つのエクステントを確保しなくても拡張できる。しかし、断片化したチェーンでは、追加のFAT参照と非シーケンシャルI/Oが必要になる。テーブル自体も共有される障害点である。ループ、範囲外のリンク、早すぎる終端マーカー、または2つのファイルによる同一クラスターの重複所有があると、ディレクトリメタデータと割り当て状態は不整合になる。
複数のFATコピーはジャーナルを構成しない。書き込み処理は、1つのコピー、ディレクトリエントリ、またはチェーンの一部を更新した後に失敗する可能性がある。修復ソフトウェアは、古いコピーと推測された所有関係の中から選択しなければならない。2つのコピーがバイト単位で一致していても、ディレクトリエントリが正しいとは証明できない。FAT32のFSInfoにある空き数および次の空きクラスターのヒントも古くなる可能性があるため、読み取り側はそれらをヒントとして扱わなければならない。
ディレクトリエントリとタイムスタンプ #
標準的なディレクトリスロットは32バイトである。短い名前のエントリには、8.3形式の名前、属性フラグ、タイムスタンプフィールド、開始クラスター、ファイルサイズが含まれる。FAT32では、開始クラスターを上位ワードと下位ワードに分割する。先頭バイトの特殊な値は未使用スロットまたは削除済みエントリを示し、ディレクトリ属性はサブディレクトリと通常ファイルを区別する。
従来のFATタイムスタンプは、UTCの時点ではなく現地の暦時刻をエンコードする。
- 更新時刻の精度は2秒である。
- 更新日付と作成日付には、年、月、日をパックしたフィールドを使用する。
- 作成時刻には、0.1秒単位のフィールドを含められる。
- 最終アクセス時刻には日付だけが格納され、時刻は格納されない。
タイムゾーンと夏時間の解釈は実装に依存する。したがって、ボリュームをシステム間でコピーすると、ディスク上のビットを変更しなくても表示される時点が変わる可能性がある。検証処理では、パックされた値をそのままカレンダーAPIに渡すのではなく、存在しない日付を拒否しなければならない。
VFAT長いファイル名 #
VFATは、短いファイル名(8.3)を扱う読み取り側との互換性を維持するため、長いファイル名(LFN)エントリを対応する短いエントリの直前に配置する。LFNスロットは次の特徴を持つ。
- 属性値
0x0Fを使用する。この値により、古いFAT読み取り側は通常ファイルとして扱わない。 - 連続していないフィールドに最大13個のUTF-16コード単位を格納する。
- 位置と、最後のスロットであるかどうかを示す序数を保持する。
- 短い8.3名から導出したチェックサムを繰り返し格納する。
スロットはディスク上では序数の逆順に現れ、その後に短いエントリが続く。読み取り側は、序数、属性、チェックサムが一致する場合にのみ名前を再構成する。それ以外の場合、安全な識別子として短い名前を使用する。UTF-16コード単位にはサロゲートペアを含められる一方、FATで禁止される文字と末尾スペースの規則は別の検証上の問題である。
ブートセクターのジオメトリとパーティションメタデータ #
FATはBIOSのCHSブートおよびパーティション分割されたディスクとともに発展したため、BPBにはセクター/トラック、ヘッド数、メディア記述子、隠しセクターなどのフィールドが残っている。現代のシステムはLBAを介してボリュームにアクセスするため、ジオメトリ値は合成されたものになり得る。これらは物理的なプラッター配置ではなく、ブート時の互換性を記述する。
ボリュームブートセクターはFATに属するが、MBRまたはGPTエントリはボリュームの外部からその位置を示す。パーティションの開始位置と長さは、BPBから導出した境界と一致しなければならないが、一方の構造が他方を置き換えることはない。UEFIファームウェアは、追加のUEFI要件の下でEFI System PartitionにFATファイルシステムを使用する。適切なパーティションメタデータとブートパスがなければ、任意のFATボリュームがEFI System Partitionになるわけではない。
運用上の帰結 #
FATは、独立した実装が少ない仕組みで解析できるため、リムーバブルメディア、ファームウェアから見えるボリューム、制約のあるデバイスに適している。アプリケーションは、取り外す前にデータをフラッシュし、信頼できないイメージの読み取り時にはすべてのオフセットとチェーン長を検証し、修復を試みる前にイメージを保存すべきである。ジャーナルがなければ、電源障害によって残された中間状態と更新完了状態を区別できない。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)