(2018.11.4) 新規作成。Samba の挙動を確認。
Windows では, NTFS ファイルシステム上に "疎ら" (まばら; sparse) なファイルを作ることができます。スカスカのファイルで、バイト列の実体が飛び飛びにしかありません。
ここでは、ディスクドライブの大きさよりはるかに大きいファイルを作ってみます。
NTFS でのファイルサイズの上限は, どれぐらいでしょうか。Web上には、相互に異なることを書いてあるページが多数あり、混乱します。
正しくは次のとおりです:
つまり, ファイルサイズの上限が、何か単独で決まるわけではありません。それから、ディスクドライブのクラスタサイズによって上限が決まります。ここが明確になっていないため、混乱が生じています.
Windowsバージョン | クラスタサイズの上限 | volumeサイズの上限 |
---|---|---|
Windows 7, Windows Server 2008 R2 以前 | 4KB | 16 TB |
Windows 8 〜 10 v1703, Windows Server 2012 〜 2016 | 64 KB | 256 TB |
Windows 10 v1709, Windows Server 2019以降 | 2 MB | 8 PB |
実際のクラスタの大きさを知るには, SysInternals の ntfsinfo コマンドが簡単です。次のように表示されます (抜粋):
Allocation Size ---------------- Bytes per sector : 512 Bytes per cluster : 4096 Bytes per MFT record : 0 Clusters per MFT record: 0
DeviceIoControl()
で FSCTL_SET_SPARSE
を与えると、疎らなファイルになります。
データを書き込まずに, SetFilePointerEx()
でポインタを進めると, その間が穴になります。
実行結果::
> .\sparse1.exe SetEndOfFile() failed: 2 ret_bytes = 20 dwStreamId = 1, dwStreamAttributes = 8, Size = 0, dwStreamNameSize = 0 stream name: (none) ret_bytes = 20 dwStreamId = 9, dwStreamAttributes = 8, Size = 65544, dwStreamNameSize = 0 stream name: (none) ret_bytes = 20 dwStreamId = 9, dwStreamAttributes = 8, Size = 8, dwStreamNameSize = 0 stream name: (none) ret_bytes = 0
ストリームに「疎ら」の属性が付きます。dwStreamAttributes
に STREAM_SPARSE_ATTRIBUTE
フラグが立ちます.
一つのストリームの中で, dwStreamId = 1
は BACKUP_DATA
です。この例だと, dwStreamId = 9
は BACKUP_SPARSE_BLOCK
で, 65544 は 16進で 0x10008 です。
どうやら, 書き込んだのは1バイトだけですが, 64Kバイトを1ブロックとして実在バイトで埋められるようです。+ 8バイトの何か、という形式のようです。
このように, 巨大に見えるファイルができます。
> dir Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2018/11/04 19:56 4294967296 large-1 -a---- 2018/11/04 19:56 16750372454400 large-2 -a---- 2018/11/04 19:56 5001 large-3 -a---- 2018/11/04 19:44 113152 sparse1.exe
ディスクドライブよりはるかに大きいファイルです。エクスプローラのプロパティで見ると、実際には64KBしか消費していません。
疎らなファイルは、Samba上にも作ることができます。ただし、設定によります。
先ほどのサンプルを Sambaドライブを宛先にして走らせます。実行結果は, 上とほとんど同じです。こちらは4Kバイトが1ブロックのようです。
SetEndOfFile() failed: 2 ret_bytes = 20 dwStreamId = 1, dwStreamAttributes = 8, Size = 0, dwStreamNameSize = 0 stream name: (none) ret_bytes = 20 dwStreamId = 9, dwStreamAttributes = 8, Size = 4104, dwStreamNameSize = 0 stream name: (none) ret_bytes = 20 dwStreamId = 9, dwStreamAttributes = 8, Size = 8, dwStreamNameSize = 0 stream name: (none) ret_bytes = 0
単に ls で表示すると、非常に巨大です。実際の消費は 8Kバイトだけです。
$ ls -l -rw-r--r--. 1 hori hori 4294967296 Nov 4 20:22 large-1 -rw-r--r--. 1 hori hori 16750372454400 Nov 4 20:22 large-2 -rw-r--r--. 1 hori hori 5001 Nov 4 20:22 large-3
$ ls -lhs 8.0K -rw-r--r--. 1 hori hori 4.0G Nov 4 20:22 large-1 8.0K -rw-r--r--. 1 hori hori 16T Nov 4 20:22 large-2 8.0K -rw-r--r--. 1 hori hori 4.9K Nov 4 20:22 large-3