Windows I/Oの深層(第5回) ── NTFSの内部構造:MFTから理解するファイルシステム

· 更新日: · · Windows, NTFS, I/O, ファイルシステム, MFT, カーネル, .NET, 不具合調査

更新履歴(3件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

知識マップの「$LogFileはボリューム破損を防ぐ」という関係を、「軽減する」に改めました。$LogFileの再生で回復できるのはメタデータ操作の中断による不整合で、不良セクタやメディア故障、$LogFile自体の損傷による破損までは回復できないためです。本文の説明は変えていません。
記事の冒頭に「この記事の知識マップ」を追加しました。本文で扱う概念どうしの関係を一枚の図で見渡せます。関係の全一覧(根拠のURL・確度・確認日つき)と主要概念の定義は知識マップ詳細ページにまとめ、機械可読データをJSON-LDとTurtleで公開しています。
連載第5回として前提になる用語(IRP、デバイススタック、キャッシュマネージャー)を、前回へのリンク付きで冒頭に定義しました。あわせて常駐と非常駐の対比図、確認コマンドごとの「ここを見る」注釈、2つのジャーナルの対比表、短縮名が環境依存である旨を追加しています。
初版公開
この記事を引用する(DOI(登録済みアーカイブ): 10.5281/zenodo.21739476)

以下のDOIは過去に登録されたアーカイブを指しており、現在の本文とは一致しない場合があります。現在の本文を参照するときは、このページのURLを使用してください。

小村 豪(2026)「Windows I/Oの深層(第5回) ── NTFSの内部構造:MFTから理解するファイルシステム」合同会社小村ソフト. https://comcomponent.com/blog/ntfs-internals-mft-structure/

DOI(登録済みアーカイブ)
10.5281/zenodo.21739476
DOI(前回登録した版)
10.5281/zenodo.21739477

ダウンロードしたファイルに付く見えない Zone.Identifier。同じ合計サイズでも、小さいファイル1万個のコピーが遅い理由。「NTFSはジャーナリングだから安心」という説明が守っている範囲。これらを、ディスク上のデータの置き方から整理します。

中心になるのは、ファイルを台帳管理するMFT(マスターファイルテーブル)です。まず「ファイルは属性の集合」と捉え、データ、名前、リンク、ジャーナル、ディスク領域の順に見ていきます。

連載の第1〜3回ではI/O要求の流れ、第4回ではキャッシュの働きを扱いました。今回は、要求が最後に届くファイルシステムの代表であるNTFSを取り上げます。「要求がどう流れるか」という動的な話から、「データがどう置かれるか」という静的な構造へ視点を移す回です。

連載「Windows I/Oの深層」の第5回です。

困っていることから読む

仕組みを順に学ぶなら2章から、調査中なら次の案内から読めます。確認コマンドと出力の見方は8章にまとめています。

知りたいこと・困っていること 読むところ
MFTとは何か。ファイルを削除してもMFTが縮まないのはなぜか 2.1節: ボリュームの台帳
小ファイルのコピーが遅い。常駐・非常駐や断片化を理解したい 2.2節: 属性とデータの置き場所
Zone.Identifierの正体や、コピーで失われる付加情報を知りたい 3章: データストリーム
別名から同じ内容が見える。名前を消しても実体が残る 4.1節: ハードリンクと削除
短縮名が環境によって存在しない。除去の影響を調べたい 4.2節: 8.3名
フォルダーの走査がループする。開くと通信が走る 5章: リパースポイント
電源断で何が守られるか。変更履歴を調査したい 6章: 2つのジャーナル
「サイズ」と「ディスク上のサイズ」が合わない 7章: スパースと圧縮
手元のWindowsで確認したい 8章: コマンドと出力の見方

この回で使う前提用語

この回を読む前提: 第1回のIRPとデバイススタックの基本を押さえていると読みやすくなります。とはいえ単独で読んでも困らないよう、本文に出てくる前回までの用語を先に定義しておきます。

用語 一行で言うと 詳しくは
IRP(I/O Request Packet) ReadFile などのAPI呼び出しがカーネル内で変換される「I/O要求の伝票」。ドライバーはこの伝票を受け取って処理する 第1回
I/Oマネージャーとデバイススタック IRPを作り、目的のデバイスに至るまで積み重なったドライバー(スタック)へ順に渡していくカーネルの部品と、その積み重ね 第1回
キャッシュマネージャー ファイルの内容をメモリ上に保持し、WriteFile の内容を後からまとめてディスクへ書き出す部品。「書いた直後にディスクに届いているとは限らない」の元凶 第4回

表1: この回で前提にする前回までの用語

もう1つ、第1回で扱ったcleanup(最後のハンドルが閉じたとき)close(カーネル内の参照がすべて消えたとき)の2段階も、4章のファイル削除の説明で使います。

1. まず結論

ファイルの実体とデータの置き場所

  • NTFSの中心はMFT(マスターファイルテーブル)です。全ファイルがMFT内のレコードとして台帳管理され、ファイルに関するすべての情報は「MFTエントリの中」か「エントリが指すMFT外の領域」にあります(2章)。1
  • ファイルの実体は「属性の集合」です。小さいファイルはデータ本体ごとMFTレコード内に収まり(常駐)、大きいファイルはクラスター列への参照だけを持ちます(非常駐)。小ファイル大量処理の遅さはここから説明できます(2章)。1
  • データは複数持てます(複数データストリーム)。普段のデータは「名前のないストリーム」で、file.txt:名前 で追加のストリームを持てます。Zone.Identifier(Mark of the Web)の正体です(3章)。2

名前と、開くときの処理

  • 名前も属性です。同じレコードに複数の名前を付けたものがハードリンク。8.3短縮名も「もう一つの名前」として同居しています(4章)。34
  • リパースポイントは「開いたら別の場所」の公式な仕掛けです。シンボリックリンク・ジャンクション・OneDrive のファイルオンデマンドは、みなこのタグ付きデータの応用です(5章)。56

障害回復と、ディスク領域の割り当て

  • ジャーナルは2つあります。$LogFileメタデータ整合性の回復用(壊れないための先行ログ)、USNジャーナル変更履歴の記録用(何が変わったかの台帳)。役割がまったく違います(6章)。78
  • 「サイズ」と「ディスク上のサイズ」は別物です。スパースファイルと圧縮が乖離を生みます。第2回で見た「圧縮ファイルは非同期にならない」の背景もここにあります(7章)。910

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全35件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. すべてはMFTのレコードである

2.1. ボリュームの台帳

NTFSボリュームをフォーマットすると、MFT(master file table)と、$ で始まる一連のメタデータファイルが作られます。MFTには、ボリューム上のすべてのファイルについて少なくとも1つのエントリがあり、MFT自身のエントリも含まれます1

NTFSボリュームレコードが位置を指す$MFT ── マスターファイルテーブル全ファイルのレコードの台帳(自分自身も載っている)ユーザーデータ領域(非常駐データの置き場所)$LogFile ── メタデータ操作のトランザクションログ(6章)$Bitmap ── クラスターの使用状況$Boot / $Secure / $UpCase などその他のメタデータファイル

図1: NTFSボリュームの構造。「ファイルシステム自身の管理情報もファイルとして持つ」のがNTFSの設計

情報は、レコード内か、レコードが指す外部領域にある

サイズ、タイムスタンプ、アクセス許可、そしてデータの内容まで、ファイルの情報はMFTエントリの中か、エントリが位置を記述するMFT外の領域に格納されます。1

削除で空いたレコードは再利用されるが、MFT自体は縮まない

ファイルを削除すると、そのエントリは「空き」としてマークされ、再利用されます。ただし、MFT自体のサイズは縮みません

MFTが大きくなるときにできるだけ連続した領域を使えるよう、MFTゾーンが予約されています。ボリュームが埋まっていくとMFTの断片化が始まる、という運用中の変化も公式ドキュメントで説明されています。1

2.2. ファイル=属性の集合、常駐と非常駐

ファイルレコードの中身は属性のリストです。標準情報(タイムスタンプ等)、ファイル名、セキュリティ、データを、このまとまりで管理します。

データの置き場所は、次の2つに分かれます。

置き方 MFTレコードに入るもの データ本体の場所
常駐(resident) 小さいデータ本体 MFTレコード内
非常駐(non-resident) クラスター列への参照(データラン) MFT外のユーザーデータ領域

図2で分岐を、図3でレコードの中身の違いを見てください。

MFTファイルレコード(1ファイルぶんの台帳)数百バイト程度までそれ以上標準情報属性タイムスタンプ・属性フラグファイル名属性(複数持てる ── 4章)データ属性データは小さいか常駐(resident)データ本体がレコード内に収まる読み出しはMFTアクセスだけで完結非常駐(non-resident)レコードには「クラスター列への参照」だけ実データはユーザーデータ領域に

図2: ファイルレコードは属性の集合。データが小さければレコード内に「常駐」する

同じレコードの中身が、常駐と非常駐でどう変わるかを並べて見ると分かりやすくなります。

非常駐(non-resident) ── 大きいファイル位置を指す位置を指すMFTファイルレコード(固定長)標準情報 / ファイル名 / セキュリティ─────────────データ属性 = データランの表『どこから何クラスター』の並びユーザーデータ領域ラン1: 連続クラスターユーザーデータ領域ラン2: 別の場所の連続クラスター常駐(resident) ── 小さいファイルMFTファイルレコード(固定長)標準情報 / ファイル名 / セキュリティ─────────────データ属性 = 中身そのもの『設定値=1』がここに直接入るディスク上に別の置き場所は無い読み出しはMFTへのアクセスだけで完結

図3: 常駐と非常駐の対比。非常駐では、レコードが持つのは「実データがどこにいくつあるか」の表(データラン)だけになる

データランの数が増えるほど、1つのファイルを読むために散らばった領域を渡り歩くことになります。これが次に挙げる断片化の正体です。

この構造から、現場で出会う現象がいくつも説明できます。

小ファイルのコピーでは、ファイルごとの台帳処理が積み重なる

1ファイルごとにMFTレコードの作成・名前の登録・セキュリティ設定というメタデータ操作が発生します。データ転送そのものより台帳仕事が支配的になるのです(そしてその1つ1つが、第6回で見るフィルターの検査対象にもなります)。

断片化とは、データランが複数の領域に分かれること

非常駐データは「クラスターの連続区間(ラン)の列」として記録されます。連続領域が取れないとランの数が増え、読み出しに必要なシークが増える──これが断片化です。ランの実際の並びは fsutil file layout で覗けます。

ディレクトリも、名前を引く索引を持ったファイル

ディレクトリは「ファイル名からMFTレコード番号への索引(インデックス)を持つファイル」です。台帳の上では、すべてが同じ仕組みの上に乗っています。

3. データは「ストリーム」の1つにすぎない

3.1. 1つのファイル、複数のバイト列

NTFSでは、1つのファイルが複数のデータストリームを持てます。普段 ReadFile/WriteFile で読み書きしているのは名前のない既定ストリームで、ファイル名:ストリーム名 という構文で代替データストリーム(ADS)を作れます。2

report.docx というファイル(1つのMFTレコード)既定ストリーム(無名)= 普段見ている中身:Zone.Identifier出所情報(Mark of the Web):任意の名前アプリ独自の付加情報

図4: 複数データストリーム。エクスプローラーのサイズ表示に出るのは既定ストリームだけ

Zone.Identifierは、出所情報を持つストリーム

身近な例が Zone.Identifier です。ブラウザーでダウンロードしたファイルの出所(インターネット由来である等)が記録され、SmartScreenの「WindowsによってPCが保護されました」やOfficeの保護ビューの判定材料になります。

警告の仕組みは「Windowsで「Windows によって PC が保護されました」が出る理由」で扱いました。その出所情報を保存する側の仕組みが、NTFSの追加ストリームです。

3.2. 開発者が踏む落とし穴

通常の一覧やサイズ表示だけでは見えない

エクスプローラーのサイズにも dir の一覧にも出ません。dir /r かSysinternalsの streams で確認できます。11

コピー先や経路によっては失われる

ADSはNTFSの機能なので、FATのUSBメモリやクラウドストレージ経由のコピーでは失われがちです。「ダウンロード警告がコピーしたら消えた」はこれです。

アプリから使えても、業務データ本体の保存先にはしない

CreateFile("data.txt:meta", ...) のようにパスにコロンを含めるだけで読み書きできます。2 便利ですが、前項の「運べない」性質ごと引き受けることになるため、業務データの本体を入れる場所ではありません。

4. 名前もまた属性である ── ハードリンクと8.3名

4.1. ハードリンク ── 同じレコードへの複数の名前

図2で「ファイル名属性は複数持てる」と書きました。同一ボリューム内で、複数のパスが単一のファイルを参照する──これがハードリンクです(CreateHardLink / mklink /H)。3

C:\backup\ のインデックスC:\app\ のインデックスconfig-link.json → レコード#1234config.json → レコード#1234MFTレコード#1234データ本体(またはランへの参照)リンク数: 2

図5: ハードリンク。ディレクトリの索引が同じMFTレコードを指しているだけで、どちらも「本物」

どの名前も、同じファイルを指している

どの名前から変更しても同じファイルなので、内容は即座に一致します。3 一方を本物、他方をコピーと考えるのではなく、同じ実体に同格の名前が付いていると捉えます。

名前を外すことと、実体が消えることを分ける

ハードリンクがあると、DeleteFile は「名前を1つ外す」という意味になります。実体が消えるのは、最後の名前が外れ、開いているハンドルが閉じ、メモリマップのセクションなどカーネル内の参照もすべて消えたときです。

第1回のcleanup(最後のハンドルが閉じたとき)とclose(最後の参照が消えたとき)の2段階は、この削除の寿命にも関係します。

内容の共有と、属性表示の更新は同じではない

あるリンクから属性を変更しても、別のリンクの見かけ上の属性表示が古いままになることがあります。これは公式ドキュメントにも注記された表示上の癖です。3

4.2. 8.3名 ── もう一つの隠れた名前

短縮名は互換性のための別名

NTFSは歴史的互換性のため、長いファイル名に REPORT~1.DOC のような8.3形式の短縮名を自動生成できます。これも、同じレコードに同居する「もう一つの名前」です。

大量のファイルがあるフォルダーでは、短縮名の生成や衝突回避にもコストがかかります。fsutil 8dot3name で生成を無効化したり、既存の短縮名を除去したりできます。4

ただし、短縮名をレジストリパスに記録する古いアプリがあると、除去によって壊れます。strip前に影響を検査する機能があるのは、そのためです。4

生成設定を確認してから、短縮名に依存する

短縮名が存在するかどうかは環境依存です。既定の動作を決めるレジストリ値 NtfsDisable8dot3NameCreation には、次の4通りがあります。4

短縮名の生成方法
0 全ボリュームで生成する
1 全ボリュームで生成しない
2 ボリューム単位で設定する
3 システムボリューム以外では生成しない

2 ならボリュームごとに切り替えられます。「Windowsなら PROGRA~1 のような短縮名が必ずある」とは限りません。

短縮名に依存するコードや手順を書く前に、fsutil 8dot3name query C: で状態を確認してください。ボリュームを省略すると、全ボリューム共通の既定設定を確認できます。

パスと名前をめぐる落とし穴(MAX_PATH、予約名、末尾ドット)は「MAX_PATHとWindowsのパス・ファイル名の落とし穴」で詳しく扱っています。第1回の名前解決(オブジェクトマネージャー)とこの章(ファイルシステム内の名前)を合わせると、Windowsの「名前」の全体像になります。

5. リパースポイント ── 「開いたら別の場所」の仕掛け

タグを見て、開くときの処理を切り替える

ファイルやディレクトリにはリパースポイントを付けられます。実体は、タグとユーザー定義データを持つ属性です。

リパースポイント付きのファイルを開くと、タグに応じて処理が切り替わります。タグを理解するフィルタードライバーが引き受ける場合と、名前の付け替え系のタグによりリンク先のパスで解決をやり直す場合があります。5

NTFSI/OマネージャーアプリNTFSI/Oマネージャーアプリ対象にリパースポイント発見タグとデータを返すタグを理解するフィルターが処理を引き受ける(第6回)alt[シンボリックリンク/ジャンクション(名前の付け替-え)][フィルター管理のタグ(クラウドファイル等)]CreateFile("C:\data\link.txt")IRP_MJ_CREATE(第1回の世界)「本当の場所はこちら」リンク先のパスで解決をやり直す

図6: リパースポイントの解決。「開く」という操作に割り込む公式のフックになっている

シンボリックリンク、ジャンクション、ファイルオンデマンド

この1つの仕掛けの上に、見慣れた機能が並んでいます。

  • シンボリックリンク(mklink)──リンク先パスを保持する標識。別ボリュームやUNCパスも指せます。6
  • ジャンクション/マウントポイント──ディレクトリを別のローカルボリュームの位置へつなぐ古参の仕組み。3
  • OneDriveのファイルオンデマンド──実データが手元にないファイルをリパースポイントで表現し、開かれた瞬間にフィルターがダウンロードして中身を差し出します。「エクスプローラーには見えるのに、開くと通信が走る」の正体です(フィルターの仕組み自体は第6回で)。

ツリーを辿るコードは、リパースポイントを確認する

実務では、パスの先が本当にローカルのその場所とは限らないことが重要です。存在を考慮しないコードでは、次のような問題を踏みます。

  • 再帰的な走査がジャンクションでループする。
  • サイズ集計が二重になる。
  • バックアップがクラウドファイルの実体化を大量に引き起こす。

対策の入口は、FindFirstFile 系で FILE_ATTRIBUTE_REPARSE_POINT を確認することです。5

6. 2つのジャーナル ── $LogFileとUSN

「NTFSはジャーナリングファイルシステム」とよく言われますが、NTFSには役割の違う2つのジャーナルがあります。混同すると保証を読み違えます。

USNジャーナル ── 変更履歴(何が変わったかを知るため)ファイル/ディレクトリへの変更のたびに変更内容と名前を記録バックアップ・検索インデックス・同期ツールが「前回から何が変わったか」を全走査なしで把握$LogFile ── 先行ログ(壊れないため)メタデータ操作(レコード更新・名前変更等)を実行前にログへ記録システム障害後の次回起動時にログを再生して構造の整合性を回復

図7: 2つのジャーナル。$LogFileは「壊さない」ため、USNは「変更を知る」ため

違いを表にすると次のようになります。

観点 $LogFile(トランザクションログ) USNジャーナル(変更ジャーナル)
目的 障害後にファイルシステムの構造を整合状態へ戻す7 「前回から何が変わったか」を後から知る8
記録する内容 メタデータ操作(レコード更新・名前変更など)の先行ログ。ファイルの中身は対象外 変更のたびに、変更の内容と対象ファイル/ディレクトリの名前8
使うのは誰か NTFS自身。次回マウント時の自動回復に使う バックアップ・検索インデックス・同期ツールなどのアプリ
どこまで遡れるか 回復に必要な範囲だけ。固定サイズを使い回すため、過去の履歴を辿る用途には使えない 目標最大サイズ(MaximumSize)を超えるとチェックポイント時に古いレコードから切り捨てられる。遡れる範囲はサイズ設定とボリュームの更新量しだい12
参照方法 中身を読む公式な手段はない(サイズは chkdsk /L で確認できる) fsutil usn queryjournal で状態、fsutil usn readjournal で中身。プログラムからは FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL12
止められるか 止められない(NTFSの一部) 管理者が削除・無効化できる。ただし利用中のサービスに全走査を強いるので影響は大きい12

表2: 2つのジャーナルの対比

$LogFileは構造の整合性を回復する

$LogFileは、メタデータ操作の先行ログです。システム障害の後、NTFSは次回起動時にログとチェックポイント情報からファイルシステムの整合性を自動回復します。7

ここで守るのは構造の整合性であり、ファイルに書いたデータ内容そのものではありません。第4回で見たとおり、キャッシュ上のダーティなデータは電源断で失われることがあります。構造を回復できることと、最後の書き込み内容が残ることを分けて考えてください。

USNは、前回から何が変わったかを調べる台帳

USNジャーナルは、ボリューム内のファイルやディレクトリに変更が起きるたびに、変更の内容と対象の名前を記録します。8

バックアップやインデクサーが「前回から変わったものだけ」を全走査せずに拾うための仕組みで、障害後のインデックス再構築の回避にも使われます。8

調査では、FileSystemWatcher の取りこぼしを補う突き合わせ台帳として fsutil usn readjournal を使えます。監視の取りこぼし自体は「FileSystemWatcher実務ガイド」を参照してください。

7. スパースと圧縮 ── 「サイズ」が二つある話

NTFSでは、ファイルの論理的な長さ実際に割り当てられた領域が別々に管理されます。プロパティ画面の「サイズ」と「ディスク上のサイズ」です。乖離を生む代表が2つあります。

スパースは、ゼロの範囲を「穴」として持つ

スパースファイルは、ゼロが続く範囲に実領域を割り当てず「穴」として管理します。9 論理サイズ42GBの仮想ディスクファイルが、ディスク上では500MBしか使っていない──が普通に起こります。穴を読めばゼロが返り、書けばそのぶんだけ割り当てられます。

ディスク上の割り当て(15MB+管理情報)論理的なファイル(サイズ: 1GB)ラン: R1の実体ラン: R2の実体データ 10MB穴(ゼロ) 500MBデータ 5MB穴(ゼロ) 残り

図8: スパースファイル。「穴」には割り当てが無く、論理サイズとディスク上のサイズが乖離する

圧縮は、使用量だけでなくI/Oの動作にも関わる

NTFS圧縮は、データを圧縮ユニット単位で圧縮して格納します。10 透過的で便利ですが、コストも透過的ではありません──読み書きのたびに展開・再圧縮が走り、断片化も進みやすくなります。そして第2回5章で見たとおり、圧縮ファイルへのアクセスは非同期になりません(ファイルシステムが同期に変換します)。「非同期I/Oにしたのに速くならないファイルがある」ときに疑う場所の一つです。

サイズが合わないときに見る4つの要因

割り当てベースの実サイズは GetCompressedFileSize で取得できます。「ファイルサイズの合計」と「ディスク使用量」が合わないときは、次の4つを順に確認します。

要因 確認すること
スパース ゼロの範囲が、実領域のない「穴」になっていないか
圧縮 圧縮後のデータとして格納されていないか
ADS 既定ストリーム以外のデータがないか(3章)
クラスター切り上げ クラスター単位の割り当てによる差ではないか

論理的な長さと割り当てられた領域を分けると、表示の違いを追いやすくなります。

8. 自分の目で確かめる

今回も、手元のWindowsですべて観察できます(一部は管理者権限が必要です)。実行結果が正しいかを自分で判定できるよう、コマンドごとにどこを見れば何が分かるかを添えます。

8.1. ADSの有無を、ストリーム名付きの行で見る

:: 代替データストリームを見る
dir /r C:\Users\%USERNAME%\Downloads

ここを見る: 通常のファイル行の下に、字下げされた ファイル名:Zone.Identifier:$DATA の形の行が長さ付きで並びます。この行があれば、そのファイルにMark of the Webが付いている状態です(3章)。ブラウザーでダウンロードしたファイルには付き、自分で作ったファイルには付きません。両方の場所で実行して見比べると、ADSの有無がはっきりします。

8.2. 常駐・非常駐と、データの配置を見る

:: ファイルのMFT上の配置(ラン)や属性を見る
fsutil file layout C:\path\to\file.dat

:: エクステントだけを見る(公式ドキュメントに記載のあるサブコマンド)
fsutil file queryextents C:\path\to\file.dat

ここを見る: layout はストリームごとに、サイズ・割り当てサイズと、非常駐であればエクステント(VCN・LCN・クラスター数の組)の一覧を並べます。エクステントの行が出ないごく小さいファイルは常駐(2.2節)、複数行に分かれていれば断片化しています。数バイトのテキストファイルと数百MBのファイルで実行して見比べるのが、常駐/非常駐を最短で体感する方法です。

8.3. 短縮名の生成設定と、実際の名前を見比べる

:: 8.3短縮名の生成設定と、既存の短縮名
fsutil 8dot3name query C:
dir /x

ここを見る: query はそのボリュームで短縮名の生成が有効か無効かを返します(ボリュームを省略すると全ボリューム共通の既定設定)。4 dir /x は長い名前の隣に短縮名の列を表示するので、列が空なら短縮名が作られていないということです。4.2節の「短縮名があるとは限らない」を自分の環境で確かめられます。

8.4. USNジャーナルの状態と、記録の進み方を見る

:: USNジャーナルの状態
fsutil usn queryjournal C:

ここを見る: ジャーナルID、有効なUSNの範囲(First USN / Next USN)、目標最大サイズ(MaximumSize)と割り当て単位(AllocationDelta)が表示されます。12 何かファイルを作ってからもう一度実行すると Next USN が進んでいるはずで、これが「変更が記録されている」ことの確認になります。MaximumSizeは6章で触れた「どこまで遡れるか」の目安です。ジャーナルが無効なボリュームではエラーになります。

8.5. リパースポイントの属性とタグを見る

:: リパースポイントの確認(リンク先とタグ)
dir /aL C:\Users\%USERNAME%
fsutil reparsepoint query "C:\Users\%USERNAME%\OneDrive"

ここを見る: dir /aL に出てきたものがリパースポイント(FILE_ATTRIBUTE_REPARSE_POINT が立っているもの)です。シンボリックリンクやジャンクションは <SYMLINKD> <JUNCTION> のような種別付きで表示されます。fsutil reparsepoint query はリパースタグの値と、名前の付け替え系ならリンク先のパスを表示します。リパースポイントでない対象を指定するとエラーになるので、エラーになること自体が「ここは普通のフォルダー」の確認になります。

8.6. 実際のファイル操作はProcmonで追う

Procmonでファイル操作を追うと、今回の登場人物が実名で流れていきます($LogFile への書き込み、ストリーム名付きのパス、リパース処理)。使い方は「Process Monitor(ProcMon)実践ガイド」を参照してください。

9. まとめ

  • NTFSの中心はMFT。全ファイルが台帳のレコードで、情報は「レコード内」か「レコードが指す外部領域」にあります。小さいデータは常駐、大きいデータはラン参照で、小ファイル大量処理の遅さや断片化はこの構造の帰結です。1
  • データストリームは複数持てます。Zone.Identifier(Mark of the Web)はただのADSで、dir /r で見え、NTFSの外へは運ばれません。211
  • 名前は属性で、複数持てます。ハードリンクは同じレコードへの同格の名前、8.3名は互換用のもう一つの名前。「削除=名前を外す」であり、実体の消滅は最後の名前・ハンドル・カーネル内参照(マップ済みセクション等)がすべて無くなったときです。34
  • リパースポイントは「開く」への公式フックで、シンボリックリンクもジャンクションもファイルオンデマンドもこの応用です。ツリーを辿るコードは FILE_ATTRIBUTE_REPARSE_POINT を意識する必要があります。56
  • ジャーナルは2つ。$LogFile は構造の整合性回復(壊れない)、USNは変更履歴(何が変わったか)。「ジャーナリングだからデータも安全」ではありません──データの耐久性は第4回の道具で作ります。78
  • 論理サイズと割り当ては別物。スパース・圧縮・ADS・クラスター切り上げが「サイズが合わない」の四大要因です。圧縮ファイルが非同期I/Oにならない件も含め、性能調査の引き出しになります。910

続きは最終回、第6回「フィルタードライバーとミニフィルター ── ProcmonとウイルススキャンがI/Oに割り込める理由」です。第1回から折に触れて登場してきた「間に挟まる者たち」──ウイルス対策、Procmon、OneDrive、暗号化──がどうI/Oに割り込んでいるのか。連載の総仕上げとして、デバイススタックの隙間に立つ住人たちの正体を明かします。

関連記事

関連する相談領域

合同会社小村ソフトでは、ファイルサイズやコピー性能の不可解な挙動、リンク・ストリーム絡みの不具合など、NTFSの仕組みに根ざしたWindows業務アプリの設計・調査を扱っています。

参考リンク

  1. Microsoft Learn, Master File Table. NTFSボリューム上のすべてのファイルについてMFTに少なくとも1つのエントリがあり、MFT自身のエントリも含まれること、ファイルのサイズ・タイムスタンプ・アクセス許可・データ内容を含むすべての情報がMFTエントリ内かMFTエントリが位置を記述するMFT外の領域に格納されること、ファイル削除時にエントリが空きとしてマークされ再利用されるがMFTのサイズは縮まないこと、MFTを連続に保つためのMFTゾーンが予約されること、割り当ての進行によりMFTの断片化が起こることについて。  2 3 4 5 6

  2. Microsoft Learn, File Streams. NTFSのファイルデータが1つ以上のストリームとして格納されること、既定の(名前のない)データストリームと名前付きの代替データストリームがあること、「ファイル名:ストリーム名」の形式でストリームを指定してCreateFileで開けることについて。  2 3 4

  3. Microsoft Learn, fsutil 8dot3name. NTFSが長いファイル名に対して8.3形式の短縮名を生成できること、fsutil 8dot3nameで短縮名生成の有効/無効の照会と設定、既存の短縮名の除去(strip)、除去した場合に影響を受けるレジストリ参照の走査ができることについて。  2 3 4 5 6

  4. Microsoft Learn, Reparse points. リパースポイントがユーザー定義データとそのデータ形式を一意に識別するリパースタグの集まりであること、リパースポイント付きファイルのオープン時にファイルシステムがタグに対応する処理(タグを解釈するファイルシステムフィルターによる処理)を試みること、NTFSのファイルシステムリンクやリモートストレージ(階層記憶)の実装に使われていること、FILE_ATTRIBUTE_REPARSE_POINT属性で存在を確認できることについて。  2 3 4

  5. Microsoft Learn, NTFS overview. NTFSがログファイルとチェックポイント情報を使い、システム障害が起きた場合に次回起動時にトランザクションログを再生してファイルシステムの整合性を自動的に回復すること、不良セクターの動的な再マップや、バックグラウンドで軽微な破損を修復するself-healing NTFSを備えることについて。  2 3 4

  6. Microsoft Learn, Change Journals. ボリューム内のファイルやディレクトリに変更が加えられるたびに、そのボリュームのUSN変更ジャーナルに変更の内容と対象ファイル/ディレクトリの名前が記録されること、ボリュームごとにジャーナルが維持されること、障害後のファイルシステムインデックスの回復に使え、ボリューム全体の再インデックスを回避できることについて。  2 3 4 5 6

  7. Microsoft Learn, Sparse Files. スパースファイルにおいて、ゼロで構成される大きな範囲に物理的なディスク領域を割り当てず、データを含む部分にのみ領域を割り当てること、割り当てのない範囲を読むとゼロが返ることについて。  2 3

  8. Microsoft Learn, File Compression and Decompression. NTFSのファイル圧縮が透過的に行われ、圧縮単位ごとにデータが圧縮・格納されること、GetCompressedFileSizeで圧縮(実割り当て)後のサイズを取得できること、圧縮ファイルの読み書きに展開・再圧縮のコストが伴うことについて。  2 3

  9. Microsoft Learn, Streams - Sysinternals. Sysinternalsのstreamsユーティリティが、NTFSファイルの代替データストリームを列挙・削除できることについて。  2

  10. Microsoft Learn, Creating, Modifying, and Deleting a Change Journalおよびfsutil usn. 変更ジャーナルのMaximumSizeが目標値であり、サイズがMaximumSizeとAllocationDeltaの合計を超えるとNTFSのチェックポイント時に切り詰められること、AllocationDeltaがジャーナルの末尾への追加と先頭からの削除の単位であること、fsutil usn queryjournalでジャーナルの状態と容量を、readjournalで記録内容を参照できること、プログラムからはFSCTL_CREATE_USN_JOURNAL / FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL / FSCTL_DELETE_USN_JOURNALを使うこと、アクティブなジャーナルの削除・無効化がMFT全体の走査を伴い、ジャーナルを利用しているサービスにボリュームの再スキャンを強いることについて。  2 3 4

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

Windowsのショートカットは、移動したファイルをどうやって見つけるのか? ── ファイルの「場所」と「同じファイルであること」は別の話

元のファイルを移動したのに、ショートカットから開けるのはなぜでしょうか。一つの企画書を移動・改名・コピーして考えながら、Windowsがパス以外の識別情報や特徴を手がかりにリンク先を探す仕組みと、その限界を解説します。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

MFT(マスターファイルテーブル)とは何ですか?
NTFSボリュームの心臓部にあたるデータ構造で、ボリューム上のすべてのファイルについて少なくとも1つのエントリ(ファイルレコード)を持つ台帳です。MFT自身のエントリも含まれます。ファイルのサイズ、タイムスタンプ、アクセス許可、そしてデータ本体に至るまで、ファイルに関するすべての情報は、MFTエントリの中か、MFTエントリが指し示すMFT外の領域に格納されます。小さなファイルならデータ本体ごとMFTエントリ内に収まり(常駐)、大きなファイルはデータの置き場所(クラスターの並び)への参照だけがエントリに記録されます(非常駐)。ファイルを削除するとエントリは空きとしてマークされ再利用されますが、MFT自体のサイズは縮みません。
ファイルに付いている「Zone.Identifier」という見えないデータは何ですか?
NTFSの複数データストリーム(代替データストリーム)の一つです。NTFSでは1つのファイルが複数のバイト列(ストリーム)を持て、普段読み書きしているのは名前のない既定ストリームです。「file.txt:Zone.Identifier」のようにコロン区切りで指定する追加ストリームに、Windowsはファイルの出所(インターネットからダウンロードした等)を記録します。これがいわゆる「Mark of the Web」で、SmartScreenの警告やOfficeの保護ビューの判定材料になります。代替ストリームはエクスプローラーのサイズ表示に現れず、dir /rコマンドやSysinternalsのstreamsツールで確認できます。NTFS以外のファイルシステム(FATなど)へコピーすると保持されない点にも注意が必要です。
ハードリンクとシンボリックリンクは何が違いますか?
ハードリンクは「同じファイル実体(同じMFTレコード)を指す、同格の名前がもう一つ増える」ことです。同一ボリューム内でしか作れず、どの名前からアクセスしても同じファイルで、1つの名前を削除しても他の名前が残っていればファイルは消えません。シンボリックリンクは「別のパスへ案内する標識」で、リパースポイントとして実装されます。リンク先のパス文字列を保持しているだけなので、別ボリュームやリモートも指せますが、リンク先が消えれば行き止まりになります。実務では、ハードリンクは実体の共有(削除の意味が変わる)、シンボリックリンクはパスの付け替え(移設やリダイレクト)と使い分けるのが基本です。
NTFSはジャーナリングファイルシステムだから、電源断でもデータは消えないのですか?
守られる範囲を正確に理解する必要があります。NTFSのトランザクションログ($LogFile)が守るのは、ファイルシステムの構造(メタデータ)の整合性です。システム障害が起きても、次回起動時にログを使って整合性を自動回復し、「ボリュームが壊れて読めない」事態を防ぎます。しかし、書き込み途中だったファイルのデータ内容そのものが復元されるわけではありません。連載第4回で見たとおり、キャッシュ上のダーティなデータは電源断で失われます。つまり「ボリュームは壊れないが、最後の書き込み内容は消えうる」が正しい理解で、データ自体の耐久性が必要ならFlushFileBuffersやWRITE_THROUGH、あるいはアプリ側の書き込み設計(一時ファイル+リネーム等)で作り込む必要があります。
ファイルの「サイズ」と「ディスク上のサイズ」が違うのはなぜですか?
NTFSでは、ファイルの論理的な長さと、実際に割り当てられたディスク領域が別々に管理されているからです。通常のファイルでもクラスター単位(既定4KB)で切り上げて割り当てるため差が出ますが、大きく乖離するのはスパースファイルと圧縮ファイルです。スパースファイルでは、ゼロが続く範囲に実領域を割り当てず「穴」として管理するため、論理サイズ数GBでもディスク上は数MBということが起こります。圧縮ファイルでは圧縮後のサイズだけが割り当てられます。逆に「ディスク上のサイズ」の方が大きく見える場合は、クラスター切り上げや代替データストリームが原因のことがあります。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る