本文へスキップ
AZ Tools

xz(.xz)ストリーム解析ツール

.xz はフレーム構造を持つ形式で、そこが gzip との決定的な違いです。どのストリームも 12 バイトのフッターで終わり、そのバックワードサイズがインデックスの位置を指します。インデックスにはブロックごとに 1 件のレコードがあり、そのブロックのアンパディッドサイズと展開後サイズが記録されています。つまり本当の展開後サイズも、ブロック数も、シーク地点も、ファイル末尾の数百バイトを読むだけで分かります。4 GB のアーカイブでも xz --list が即答できる理由であり、逆に gzip -l が .gz の最後の 4 バイトをそのまま読み上げて全体を表していることを祈るしかない理由でもあります。このページは xz と同じく末尾から逆向きに辿って同じフレーミングを読み、すべてを表示します。fd 37 7a 58 5a 00 のマジック、チェック種別(None、CRC32、既定の CRC64、SHA-256)を持つストリームフラグと、その 2 バイトを守る CRC32。続いてブロックごとに、ヘッダー長、ヘッダー自身が圧縮後・展開後サイズを宣言しているかどうか、格納されたチェック値、そして正しく解釈したフィルターチェーンです。LZMA2 の辞書サイズは単なる数値ではなく 4 KiB から 4 GiB まで続く 6 ビットの符号で、その前段には x86、ARM、ARM64、PowerPC、IA-64、SPARC、ARM-Thumb、RISC-V 向けの BCJ フィルターが独自の開始オフセットとともに置かれることがあります。--x86 で作ったファイルのチェーンにフィルターが 2 つある理由で、ここでは xz にそのまま渡せる書式で表示します。ブロックの後にはインデックスレコード、インデックス自身の CRC32、フッターのバックワードサイズ、繰り返されたストリームフラグ、YZ マジックが続きます。展開は一切しません。LZMA2 を実装していないこと自体がこのツールの主旨ですが、同時にブロックのチェック値は検証した結果ではなく書き写した値だという意味でもあります。CRC64 が正しいと示すには結局ペイロードをデコードするしかないからです。一方でフレーミングを守る 4 種類の CRC32 はすべて計算し直し、不一致があってもファイルを拒否せずそのまま報告します。インデックスが壊れたファイルや、フッターのフラグがヘッダーと食い違うファイルでも、無事な部分はすべて確認できます。ブロック数は見た目以上に重要です。ブロックが 1 つなら複数コアでの展開も途中へのシークもできません。xz -T0 が変えるのはまさにそこですが、入力を辞書サイズの約 3 倍で切るため、それより小さい入力はスレッドをいくつ指定しても 1 ブロックのままです。1 つのファイルに複数のストリームを連結することもでき、その間のパディングは 4 の倍数のゼロバイトでなければなりません。ここではストリームを 1 つずつ並べ、どのストリームにも属さない末尾のバイトも別に指摘します。

使い方

  1. .xz または .tar.xz をボックスにドロップしてください。ページ内で読むだけで、アップロードも展開もしません。
  2. まずサマリーを見ます。ストリーム数、ブロック数、インデックスから取った本当の展開後サイズ、圧縮比、そしてこのファイルが使うチェック種別が並びます。
  3. ストリームを開くとヘッダー、ブロック表、インデックスが出ます。フィルター列は xz にそのまま渡せる書式なので、--x86 --lzma2=dict=8MiB がそのブロックを作ったチェーンです。
  4. 並列展開や部分読み出しを計画する前にブロック数を確認してください。ブロックが 1 つなら、スレッドをいくつ用意してもコアは 1 つ、シークもできません。
  5. フレーミングのタイルが不一致なら赤いバッジを探します。ストリームヘッダー、各ブロックヘッダー、インデックス、フッターはそれぞれ固有の CRC32 を持ち、フッターはストリームフラグをもう一度繰り返します。

よくある質問

展開せずに、どうして展開後のサイズが分かるのですか。
.xz 形式がその数値をファイルに書き残しているからです。各ストリームの末尾には、ブロックごとのアンパディッドサイズと展開後サイズを並べたインデックスがあり、フッターのバックワードサイズがインデックスの開始位置を示します。読む側は最後の 12 バイトへシークし、インデックスへ飛び、レコードを合計すれば終わりです。xz --list がしていることであり、このページがしていることでもあります。.xz が途中から読める理由も同じで、ある展開後オフセットがどのブロックにあるかをインデックスが教えてくれます。gzip に相当する仕組みはありません。ISIZE はファイル最後の 4 バイトにあり、最後のメンバーだけを表し、しかも 2^32 の剰余なので、複数メンバーの .gz や 4 GB を超える .gz はフレーミングだけではサイズを名乗れません。
-T0 で圧縮したのに、なぜブロックが 1 つしかないのですか。
スレッド圧縮は入力を辞書サイズのおよそ 3 倍で切るからです。既定のプリセット 6 では辞書が 8 MiB なので、約 24 MiB 未満の入力は決して 2 つに分かれません。-T0 はコア数だけスレッドを使えという指定にすぎず、1 つに収まる入力から 2 つ目のブロックを作り出すことはできません。並列展開やシークのためにブロックそのものが必要なら、--block-size か --block-list で明示してください。代償は圧縮率です。ブロックごとに辞書が空の状態から始まるため、境界をまたいだ一致は見つけられません。
チェック種別は何を選ぶべきで、コストはどれくらいですか。
ストリームフラグが None、CRC32、CRC64、SHA-256 のいずれかを指定し、ブロックごとに 0、4、8、32 バイトを後ろに付けます。既定の CRC64 がほぼ常に正解です。ブロックあたり数バイトで、ストレージや転送が現実に起こす偶発的な破損を検出できます。SHA-256 はブロックあたり 32 バイトに加え CPU も大きく使いますが、何を買えないのかははっきりさせておくべきです。ダイジェストはファイルの中にあるので、ペイロードを書き換えられる者はダイジェストも書き換えられます。事故の検出であって攻撃者への防御ではなく、その用途にはファイル全体への署名が必要です。--check=none は 4〜8 バイトを節約する代わりに、データが壊れたと知らせてくれる唯一の手段を捨てます。ペイロードが自前のチェックサムを持つ場合くらいしか正当化できません。
アンパディッドサイズ、トータルサイズ、圧縮後サイズはどう違うのですか。
同じブロックを 3 つの角度から見た値です。圧縮後サイズは LZMA2 が出したバイト数だけを数えます。インデックスに実際に格納されるアンパディッドサイズは、ブロックヘッダーとその圧縮データとチェック値の合計で、パディングは数えません。トータルサイズはアンパディッドサイズを 4 の倍数へ切り上げた値で、次のブロックが整列した位置から始まるよう各ブロックがゼロバイトで埋められるためです。差を取れば 0〜3 バイトのパディングが出ます。このページは圧縮データ長とパディングを別々に示し、ヘッダーが自分のサイズを宣言している場合は両方をブロックヘッダーと突き合わせます。サイズ欄の c と u はその宣言の有無を表します。
このページは不一致と言うのに、xz -t は「データが壊れている」としか言いません。どちらが正しいのですか。
深さが違うだけで、どちらも正しいです。xz -t はペイロード全体をデコードしてブロックごとのチェック値を検証するので、どこの破損でも捉えますが、最初のエラーで止まり、何が壊れていても同じ文言で報告します。このページはペイロードを一切デコードしないため、圧縮データ内部の破損はそもそも見えません。その代わりフレーミングの CRC32 を個別に計算し直すので、どの構造が壊れているのか、ストリームヘッダーなのか、どのブロックのヘッダーなのか、インデックスなのか、フッターなのかを言い当てられます。ヘッダーのストリームフラグとフッター側の写しも比較します。サイズだけの点検では見えないこの食い違いは、本物の破損の兆候です。破損箇所の切り分けはこのページで、データが使えるかどうかの判断は xz -t で行ってください。
.tar.xz の中のファイル一覧は見られますか。
見られません。展開しない限りどのツールにも見えません。ファイル名やサイズや権限を含む tar アーカイブそのものがペイロードであり、そのペイロードは LZMA2 で圧縮された不透明なバイト列だからです。フレーミングから分かるのは、展開したときにその tar がどれだけの大きさになるか(始める前に置き場所が足りるか分かります)、ブロックがいくつあるか(展開に複数コアを使えるか分かります)、そしてコンテナが無事かどうかです。展開後サイズが 512 の倍数でぴったり割り切れるなら、本当に tar である可能性は高いといえます。tar は各メンバーもアーカイブ全体もそのブロック長で埋めるからです。
フィルターチェーンに書かれた辞書サイズは何を教えてくれますか。
圧縮側がどこまで遡って一致を探せたか、したがって展開側がおおよそどれだけメモリを使うかです。デコーダーは辞書サイズ分のバッファを確保するので、-9(64 MiB)で作られた .xz を開くには 65 MB 前後が必要で、それだけの余裕がない機器もあります。ノート PC では問題なく開くファイルが組み込み機器や CI では展開に失敗する、よくある原因です。LZMA2 はこの値を 6 ビットの符号で保存します。ビット 0 が仮数 2 か 3 を選び、残りが指数なので、4 KiB、6 KiB、8 KiB、12 KiB と上がって 3 GiB まで続き、値 40 だけが 4 GiB から 1 を引いた大きさに予約されています。単なる整数として読むと、既定の 8 MiB の辞書は 22 に見えてしまいます。

関連ツール