答え
NTFSの$MFTのレコード数4,294,967,040(232-256)個が上限だと思われる。ファイルもフォルダもNTFSが内部で使用するファイルやフォルダも1レコードを使う。断片化が激しい場合などに1ファイルやフォルダが複数のレコードを使用することもある。
詳細
気になってググってみたら、Wikipediaが出てきた。
日本語版。要出典。
英語版はちゃんと出典が書いてあって偉い。
出典はMicrosoftのドキュメント。232は232だろう。
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バイト確保されている。248-αくらい扱えても良いのでは。
ということで実際に試してみた。環境はWindows 10 Pro 1809。
今のWindowsはディスクの管理から、VHDを扱えるので、新しく作ってマウント。下記のスクリプトでひたすらファイルを作っていく。
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
まで作れれば232個のファイルになる。
結果。
F:\fe\ff\fb\bb.txt
を作ろうとしてエラーになった。232-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段階目の)ファイルに対応していなかったので、改良してダンプしてみた。
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のレコード数は232個未満という制約と、256個ずつ拡張されるという制約が合わさって、上限が232-256になっているのではないだろうか。もしかすると、1個ずつ確保する実装があって、それならば232-1レコードまで作れたのかもしれない。
$MFTを眺めていたら、ここのMFT Record Noが32ビットで、レコードのインデックスが入っていた。
自分自身のインデックスだから、ここを見ている時点で得られる情報のはず。何に使うのだろう。何かの間違いでファイルのオフセットがズレたときのチェック用? それならば、レコード数が32ビットを越えても問題は無さそう。そもそも、32ビットならば、232個ピッタリまで使えても良さそう。謎。最近のMicrosoftは色々とオープンにしているので、NTFSの仕様とソースコードもオープンにしてほしい。