HN 日本語サマリー

← 一覧へ戻る
プログラミング

最も難しいtarball?

The Hardest Tarball? (stoppels.ch)

63 pointsby thatslast1 コメント

要約

この記事は、様々なアーカイブツールで抽出動作が大きく異なる、奇妙なtarアーカイブを探求しています。単一の`tar`コマンドで作成されたこのアーカイブは、ハードリンクとPAXヘッダーを悪用して曖昧さを生み出し、GNU tar、bsdtar、7-Zipなどのツールで多様な解釈を引き起こし、tarアーカイブ処理の複雑さと不整合性を浮き彫りにしています。

全文翻訳

最も難しいtarball?

2026年11月7日

これは奇妙なものです。単一のGNU tar呼び出しで構築でき、使用するツールによって8通りの異なる方法で抽出されるアーカイブです。

$ printf hello > file
$ touch empty
$ tar --format=pax --pax-option='delete=?time,size:=512' \
      --transform='s,^\./file$,café,' \
      -cf hardest.tar file ./file empty

これは、file、./file、emptyの3つのファイルから、fileが繰り返されることでGNU tarが2番目のファイルをハードリンクとして保存し、emptyは空であるというシーケンスでアーカイブhardest.tarを作成します。2番目のエントリのユニークなパスを利用して、ハードリンクはcaféにリネームされます。これにより、tarはファイル名をUTF-8で保存するためにpaxヘッダーを作成します。paxヘッダーにsize=512レコードを追加すると、ハードリンクからのデフォルトのsize=0が上書きされます。値512は偶然ではありません。これはtarヘッダーの正確なサイズです。

視覚的には、このアーカイブはハードリンクにサイズを持たせることができるかどうかによって、2つの基本的な解釈に基づいた構造を持っています。

[画像: The structure of hardest.tar, with two basic interpretations based on whether a hard link can have a size or not.]

さて、POSIXは、ハードリンクのデータブロックはpaxアーカイブに「含めることができる」と述べていますが、その意味合いは完全には明らかではありません。したがって、ハードリンクの後の512バイトは、アーカイブしたemptyのヘッダーではなく、そのデータなのでしょうか?ハードリンクがその前のfileとは異なる内容を持つことができるのでしょうか?

抽出

このアーカイブは、よく知られたtarユーティリティやライブラリで抽出する際に、私がこれまでに遭遇した中で最も豊かで驚くべき結果をもたらします。以下の結果は、執筆時点ですべてのパッケージの最新リリースを使用して生成されました。

GNU tar, BusyBox, Python, Go and Perl

このグループは原則として合理的です。ハードリンクのサイズを無視し、file、そのハードリンクcafé、およびemptyを抽出します。

bsdtar

これはmacOSのシステムtarユーティリティであり、ハードリンクのサイズという概念に関してPOSIXの精神に近く、512バイトをハードリンクに書き込みます。最終結果として、fileにはemptyのtarヘッダーが含まれることになります。

7-Zip, node-tar, tar-fs, and Rust's tar & astral-tokio-tar

このグループはbsdtarと同様に512バイトをハードリンクのデータと見なしますが、それをハードリンクに書き込みません。代わりに、データの先へスキップし、emptyなしでfileとcaféだけが残ります。

Java's Commons Compress

ここで想像力が必要になります。なぜならcaféにはデータが含まれているため、emptyのヘッダーをデータとして含む別のファイルが作成され、fileは元の内容を保持するからです。

PHP's PharData

caféを別の空ファイルにし、emptyも抽出します。なぜだめなのでしょうか?

RubyGems

caféはまったく抽出されませんが、その代わりにfileとemptyの隣にPaxHeadersという空のディレクトリを作成します。

R

Rはまったく異なるアプローチを取ります。512バイトのヌルバイトを含むemptyを抽出します。誤ってハードリンクではなくemptyにサイズを適用しており、その512バイトはアーカイブ終了マーカーからのものです。

ボーナス: Haskell

Haskellのtarは、文字列デコードの問題がなければGNU tarとまったく同じですが、その問題により、ファイルcaféはディスク上でcaféになります(2026年現在、これはブラウザのレンダリングの問題ではありません)。

.NET, Julia and uv's tar-codec

これらの実装はtarballを拒否します。技術的にはPOSIX準拠ではありませんが、これが最善の対応だと考えます。

さらに詳しく

このtarballは、私がテストスイートhaampie/tar-minefieldで収集・分類している134個のトリッキーなtarballの1つです。このウェブサイトhttps://stoppels.ch/tarには、実装がこれらのケースにどのように対応するかを示す大きなテーブルと、各テストケースの詳細情報が掲載されています。この投稿のtarballのバリアントはテストケースとして含まれています。

これについて議論したい場合は、firstname[at]lastname.chまでメールを送信してください。