NTFSの最大ファイル数はいくつなのか？

## 答え

NTFSの$MFTのレコード数4,294,967,040（2<sup>32</sup>-256）個が上限だと思われる。ファイルもフォルダもNTFSが内部で使用するファイルやフォルダも1レコードを使う。断片化が激しい場合などに1ファイルやフォルダが複数のレコードを使用することもある。

## 詳細

気になってググってみたら、Wikipediaが出てきた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/3bc42fa9-f300-6062-4dd8-e92ce31d406a.png)

https://ja.wikipedia.org/wiki/NT_File_System

日本語版。要出典。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/acf5f131-4067-1bd0-7899-e1292540b769.png)

https://en.wikipedia.org/wiki/NTFS

英語版はちゃんと出典が書いてあって偉い。

出典はMicrosoftのドキュメント。232は2<sup>32</sup>だろう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/6e24115d-defa-a6b2-cf88-4443dd2874aa.png)

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc781134(v=ws.10)

Microsoftが言っているなら正しそうだけれど、気になることもある。

- いちいち既存のファイルを数えていたら遅くなるが、NTFSにファイル数を保持しておく機能なんてあったっけ？
- なぜファイルだけがカウント対象？　フォルダは？
- 上限が低すぎないか？
  - 小さなファイルならばディスクの使用量は1 KiB。小さなファイルをだけを作っていると、8 TBくらいのディスクが普通に売っているのに、4 TiB＋αでこの上限に達する

そもそも、NTFSの仕様上は上限がここに来ることは無さそうに思える。

- https://qiita.com/kusano_k/items/45b0a86649aabb8040ff#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E5%86%85%E5%AE%B93%E6%AE%B5%E9%9A%8E%E7%9B%AE
- https://flatcap.org/linux-ntfs/ntfs/
- http://www.writeblocked.org/resources/ntfs_cheat_sheets.pdf

NTFSの仕様はこの辺に。NTFSでは全てのファイルとフォルダは$MFTというファイルにインデックスが書かれている。このレコードは連番で参照され、参照するところでは6バイト確保されている。2<sup>48</sup>-αくらい扱えても良いのでは。

ということで実際に試してみた。環境はWindows 10 Pro 1809。

今のWindowsはディスクの管理から、VHDを扱えるので、新しく作ってマウント。下記のスクリプトでひたすらファイルを作っていく。

```make.py
import os

T = ["%02x"%i for i in range(256)]

for a in range(256):
  print T[a]
  os.mkdir(T[a])
  for b in range(256):
    print "  "+T[b]
    os.mkdir(T[a]+"\\"+T[b])
    for c in range(256):
      os.mkdir(T[a]+"\\"+T[b]+"\\"+T[c])
      for d in range(256):
        with open(T[a]+"\\"+T[b]+"\\"+T[c]+"\\"+T[d]+".txt", "wt") as f:
          f.write(T[a]+T[b]+T[c]+T[d]+"\n")
```

1フォルダに40億個のファイルを作ると、NTFSは耐えられてもエクスプローラーがダメだったりしそうなので、サブフォルダを作っていくようにした。ルートに00, 01, ..., ffというフォルダを作り、それぞれの中に00, 01, ..., ffを作り、もう1段階繰り返して、その中に00.txt, 01.txt, ... ff.txtを作る。`F:\00\00\00\00.txt`から`F:\ff\ff\ff\ff.txt`まで作れれば2<sup>32</sup>個のファイルになる。

結果。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/4ebd3652-ae9f-4ebf-b56d-cdc9d43bcc6c.png)

![20190524ntfs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/c90354a5-9cc4-cf1b-eb2b-2352bc5f4e70.png)

![20190525ntfs2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/15951694-6695-ffe0-1752-3cddef243e13.png)

`F:\fe\ff\fb\bb.txt`を作ろうとしてエラーになった。2<sup>32</sup>-1個のファイルを作ることすらできなかった。ドライブのルートで普通に見えている上記のスクリプトと00からfeまでのフォフォルダを選択してプロパティを表示すると、ファイル数4,278,188,988個、フォルダ数16,777,211。4,278,188,988=0xfefffbbcなので計算は合う。このドライブで手動でファイルを作ろうとすると、「エラー 0x80070299」になった。VHDのフォーマットはVHDXで可変サイズにしていて、5 TiB。

新規にファイルを作ろうとするとエラーにはなるものの、このドライブでフォルダやファイルを開いていっても特に重かったりはしない。NTFS強い。まあ、この記事を書くためにアンマウントしていたVHDをマウントしてみたら数分掛かったけど。$MFTのレコードの空きを管理するビットマップはあるけれど、数十億個となると愚直に調べるとパフォーマンスが悪いので、マウント時に何かデータ構造を作っているのかもしれない。

このスクリプトがエラーになるまでに5日間くらい。プロパティを表示し始めてからカウントが止まるまでに3日間くらい掛かった。Windows Defenderが若干足を引っ張るらしく、停止するとちょっと速くなる。でも、しばらくすると勝手に復活する。Fドライブを丸ごと除外してもなぜかダメ。

この制限がどこから来ているのか気になる。

Microsoftのサイトには「ファイル数」と書かれているけれど、まあフォルダも対象だろうと思って足し合わせると、4,294,966,199=0xfffffbb7。0xffffffffには448個足りない。NTFSやWindowsが使っているファイルがあるとはいえ、数十個のはず。

以前に作ったNTFSをダンプするツールが、大きな（3段階目と4段階目の）$MFTと、断片化の激しい（4段階目の）ファイルに対応していなかったので、改良してダンプしてみた。

https://github.com/kusano/ntfsdump

```dump.txt
OEM ID: "NTFS    "
Byte/Sector: 512
Sector/Cluster: 8
Total Sector: 17179832319
Cluster of MFT: 786432
Cluster/Record: 4294967286
Cluster Size: 4096
Record Size: 1024
MFT stage: 4
MFT size: 4398046248960
Record number: 4294967040
MFT run list: 20917
             c0000           29e640
            35e646             c81a
            36e05a             c806
            37da55             c80b
 :
          4ffc2109             c817
          4ffd1b18             c808
          4ffe151b             c805
          4fff0f19             601a
File List:
           0       $MFT
           1       $MFTMirr
           2       $LogFile
           3       $Volume
           4       $AttrDef
           5   dir .
           6       $Bitmap
           7       $Boot
           8       $BadClus
           9 ????? $Secure
          10       $UpCase
          11   dir $Extend
          12       Failed to find $File_Name attribute
          13       Failed to find $File_Name attribute
          14       Failed to find $File_Name attribute
          15 extension for 0
          16 extension for 0
          17 extension for 0
          18 extension for 0
          19 extension for 0
          20 extension for 0
          21 extension for 0
          22 extension for 0
          23       4d.txt
          24 ????? $Quota
          25 ????? $ObjId
          26 ????? $Reparse
          27   dir $RmMetadata
          28 ????? $Repair
          29 ????? $Deleted
          30   dir $TxfLog
          31   dir $Txf
          32       $Tops
          33       $TxfLog.blf
          34       $TxfLogContainer00000000000000000001
          35       $TxfLogContainer00000000000000000002
          36   dir System Volume Information
          37       WPSettings.dat
          38       IndexerVolumeGuid
          39       make.py
          40   dir $RECYCLE.BIN
          41   dir S-1-5-21-2575406132-4124664520-3855573027-1001
          42       desktop.ini
          43   dir 00
          44   dir 00
          45   dir 00
          46       00.txt
          47       01.txt
          48       02.txt
 :
```

\$MFTは20,917個に断片化していた。普通は数個程度。普通は使われない\$MFTの最初のほうのレコード（23）が通常のファイルに使われている。

\$MFTのレコード数が4,294,967,040個。これは0xffffff00なのでキリが良い。末尾の00はおそらく\$MFTの拡張が256レコードごとだから。256個レコードを使っている状態で新規にファイルを作ると、使われていないレコードも合わせて確保されて、レコード数が512個になる。\$MFTのレコード数は2<sup>32</sup>個未満という制約と、256個ずつ拡張されるという制約が合わさって、上限が2<sup>32</sup>-256になっているのではないだろうか。もしかすると、1個ずつ確保する実装があって、それならば2<sup>32</sup>-1レコードまで作れたのかもしれない。

$MFTを眺めていたら、ここのMFT Record Noが32ビットで、レコードのインデックスが入っていた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/9b11691a-7847-7d00-3e4a-87eea95d5a9f.png)

http://www.writeblocked.org/resources/ntfs_cheat_sheets.pdf#page=2

自分自身のインデックスだから、ここを見ている時点で得られる情報のはず。何に使うのだろう。何かの間違いでファイルのオフセットがズレたときのチェック用？　それならば、レコード数が32ビットを越えても問題は無さそう。そもそも、32ビットならば、2<sup>32</sup>個ピッタリまで使えても良さそう。謎。最近のMicrosoftは色々とオープンにしているので、NTFSの仕様とソースコードもオープンにしてほしい。