- 518GiB の tar.gz を展開すると極端に遅くなるため、調査を開始
- Tar フォーマットの説明と、高速な tar extractor のコードを書きながら解説
オリジナルの Tar ファイルフォーマット
- Tar はアーカイブファイルとしては非常に異例
→ アーカイブヘッダーがなく、検索用のファイルインデックスもなく、tar であることを確認できるマジックバイトもなく、フッターもなく、メタデータもない
→ Tar の中にあるのは、ファイルオブジェクトという 1 種類だけ
- ファイルタイプ: 0(通常ファイル)、1(ハードリンク)、2(シンボリックリンク)
- 512 バイトのファイルオブジェクトヘッダーの構造を説明
→ 最大の制限はファイルパス長が 100 文字しかないこと。また、ファイルサイズは最大 8GiB
UStar 拡張ファイル
- ファイルパス長は最大 256 で、新しいファイルタイプも追加
- ヘッダーを拡張し、マジックバイトと prefix フィールドを追加
- ファイルタイプ追加: 3(キャラクターデバイス)、4(ブロックデバイス)、5(ディレクトリ)、6(FIFO ファイル)、7(連続ファイル)
- ただし 8GiB のサイズ制限はそのまま
Pax ファイルフォーマット
- POSIX.1-2001 標準として、pax CLI を通じて tar フォーマットを拡張
- UStar と同じだが、x と g のファイルフォーマットを追加
→ 拡張ヘッダーレコードとして、x は次のファイルにのみ適用され、g は後続のすべてのファイルに適用
GNU Tar ファイルフォーマット
- 独自フォーマットは gnu で、pax とは異なる
- pax に似ており UStar ベースだが、パスや大きなファイルをエンコードする別の方法を使う
→ L タイプ: 次のファイルオブジェクトのペイロードが "file_path" を表す
→ K タイプ: 次のファイルオブジェクトのペイロードが "link_path" を表す
→ この 2 つは連続して適用可能
→ ファイルが 8GiB より大きい場合は file_size の先頭文字のハイビットをセットし、その後は文字列の残りを base 256 として解析(95 ビット整数)
なぜ GNU tar は展開が遅いのか?
- ファイルヘッダーに
file_path="../hello.txt" のような値を入れるとセキュリティ問題が発生する。しかし防ぐのは簡単ではない
- GNU tar は link_path に
.. を見つけるとプレースホルダーを作成し、遅延して処理する
- しかし
.. のないハードリンクの場合は直接作成したくても、すでにプレースホルダーがあるため作成できない
- つまりハードリンクを作成するには、それが遅延リンクかどうかをまずすべて確認する必要があり、もしそうなら新しいリンクもやはり遅延処理しなければならない
→ すべてのハードリンクについて遅延リンクを探索する必要がある。理由は不明だが、実際には 2 回探索している
- 筆者の Tar ファイルには
.. を含むリンクが 80 万件超、ハードリンクが 540 万件以上あり、そのため展開が遅くなっていた
- これを防ぐには tar に
--absolute-paths または -P オプションを追加すること
→ 絶対パスを保存し、.. を拒否するオプション
→ つまり -P オプションを付けると遅延リンク機構が無効になる
1件のコメント
tar 関連の記事はいつも面白い気がしますね..
hop - tar より10倍速いアーカイブ形式
Python で作成した tar.xz ファイルは、なぜデフォルトの tar で作成したファイルより小さいのですか?