ホール
ファイルの末尾を越えて lseek() して書き込むと、ファイルの末尾だった地点から書き込んだ地点までの間はゼロで埋められるが、このときファイルシステムによっては物理的にゼロを書き込むことなく sparse なファイルを作るらしい(その結果として生じる、物理ディスク上に存在しない部分はホールと呼ばれる)。たとえば、ls の -s オプションの説明には次のように書いてある。
それぞれのファイルのディスク割り当て量をファイル名の左に表示する。これはファイルによって使用されるディスクの総量である。この大きさは普通はファイルのサイズよりいくらか大きいが、ファイルがホール (穴) を持っている場合は小さくなることもある。
HFS+ (with Mac OS) はホールをサポートしていないらしく、実験してみたら次のようになった。
$ cat test.c #include <unistd.h> #include <fcntl.h> int main() { int fd = open("zero", O_CREAT | O_RDWR, 0644); lseek(fd, 1024 * 1024 * 1024 - 1, SEEK_SET); write(fd, "\0", 1); } $ gcc test.c && ./a.out $ stat -f "%N: %z bytes, %b blocks" zero zero: 1073741824 bytes, 2097152 blocks
$ gcc test.c && ./a.out $ stat -c "%n: %s bytes, %b blocks" zero zero: 1073741824 bytes, 24 blocks
ちなみに、GNU の cp にはホールを保つ機能があって(連続するゼロをコピーせずに lseek() でスキップする)、--sparse オプションで設定できるようだ。以下 ext3 にて。
$ time dd bs=4k count=256k if=/dev/zero of=zero-a 2> /dev/null real 0m47.057s user 0m0.015s sys 0m2.100s $ time dd bs=4k count=256k if=/dev/zero 2> /dev/null | cp --sparse=always /dev/stdin zero-b real 0m1.072s user 0m0.003s sys 0m1.040s $ stat -c "%n: %s bytes, %b blocks" zero-a zero-b zero-a: 1073741824 bytes, 2099208 blocks zero-b: 1073741824 bytes, 0 blocks
上は 1 GB のゼロを書き込むのに対し、下は単にスキップするだけなので速い。