TARで利用できる最新のフォーマットであるpaxについて調べていたところ掲題のことが分かって面白かったので紹介します。調査不足な箇所があったら教えてください。
tl;dr
tarするときは-H paxしよう- ファイル名の文字化けなどが回避されるぞ
- 長いパスがぶっ壊れなくなるぞ
- 現代においてデメリットはほぼない
本編
こんにちは、TARの話ばっかりしている人間です。
paxとは
Paxとは、tar(1)やpax(1)で扱うことができるファイルフォーマットで、POSIX(POSIX.1-2001, 2008)で規定されている。
要するにtarの最新のフォーマットだと思ってもらったらいいです。
ustarの時代
皆さんtarが吐き出すフォーマットはtarフォーマットでしょ、と素朴に思ってるかもしれないが、あれって実は特にどこに規定されているわけでも規格が策定されているわけでもなくて、勘で運用されてる、という時代が実に1988年まで続いていた。実装ごとになんか微妙に振舞いが違うという時代で、アーカイブするとなんか解凍できないとか、内容が化けて滅茶苦茶になる、みたいなイメージはこのへんにできてそう。
そんで1988年にPOSIX.1-1988によってTARフォーマットの規格化が実行され、大統一フォーマットが作られる。これがustarフォーマットというやつ。 ustarは規格化されているので、POSIXに準拠したどのOSのどの実装でも相互運用ができるようになっている。
ただし限られたコンピューティングリソースやASCIIを前提とした古い規格なので、ustarは現代で使うには制約が多いフォーマットになっている:
- パスを含めたファイル名が255バイトまで
- 日本語を含む場合割とすぐ到達する
- ファイル名単体だとそんなに到達しないがパスを含めると割とすぐ到達する
- ファイルヘッダが最大約8GBまでしか表現できない
- 大きなファイルを含むアーカイブを作成できない
- パス名がengoding-agnosticになっている
- つまり、規格ではエンコーディングを関知しないということ
- 単にバイト列として扱われるため、実装や環境によって文字化けが生じる
- 所有者名やグループ名の長さが32バイトまで
- タイムスタンプの精度により2038年以降に問題が生じる
- 将来的な拡張性がない
pax format
そこで、POSIX.1-2001, 2008ではさらにTARフォーマットの結集と規格化が再び実行され、大統一フォーマットが作られる。これこそがpaxフォーマットというやつ。
Paxは前述したustarの欠点を拡張ヘッダという機構で互換性をある程度保ちつつ克服している:
- ファイル名は任意長まで表現できる
- ファイルヘッダは任意長まで表現できる
- パス名のエンコーディングはUTF-8で標準化された
- 明示も可能
- 所有者名やタイムスタンプなどが任意長、任意精度になった
- 拡張ヘッダという機構を導入した
- ustarからはファイルが格納されているように見えるが、内部はkey value store
- 前述したファイル名やタイムスタンプなどはこの拡張ヘッダに記録される
- それ以外はustarに準拠しているので古い実装でも展開ができる
このため、可能であればこのpaxフォーマットを利用することが望ましいといえる。paxフォーマットは、以下のように--formatを用いることで指定できる:
tar -cvf tarfile.tar --format=pax . # または -H pax (posixも等価)
ファイル名がUTF-8で固定されたのが偉いと思う。アーカイバの動作環境がUTF-8ではないエンコーディングを利用している場合は、アーカイバが自動的に変換すべきである、と暗にPOSIXに規定されている。
The extended header records shall be encoded according to the ISO/IEC 10646-1:2000 standard UTF-8 encoding. The
field, , <equals-sign>, and shown shall be limited to the portable character set, as encoded in UTF-8. The fields can be any UTF-8 characters. The field shall be the decimal length of the extended header record in octets, including the trailing . If there is a hdrcharset extended header in effect for a file, the value field for any gname, linkpath, path, and uname extended header records shall be encoded using the character set specified by the hdrcharset extended header record; otherwise, the value field shall be encoded using UTF-8. The value field for all other keywords specified by POSIX.1-2017 shall be encoded using UTF-8.
このため、ユーザは特に意識しなくて良いというメリットがある。また、変換によって表現が潰れる場合に配慮して、tarでは--pax-option=invalid=binaryといったオプションが用意されている。(pax(1)の-o optionsに詳細が記載されている)
GNU tar format
ところで、それとは別にGNUは独自にustarを拡張している。これもustarの欠点を克服するいくつかの拡張を持っているが、全く規格化されていないので完全に実装依存であるという問題がある。つまりGNU tar以外のアーカイバでの動作が全く保証されていない。
最近のtar(1)はデフォルトではこの拡張形式を利用せずにpax形式を利用することが多い。GNU tarのデフォルト設定はコンパイルタイムに規定され、tar --helpで確認できる:
% tar --help ... 「この」tar の規定値: --format=posix -f- -b20 --quoting-style=escape --rmt-command=/usr/bin/rmt --rsh-command=/usr/bin/ssh %
このように最終行に出力される。posixであればpaxが利用されている。
ソフトウェア開発者であれば、仕事や趣味では大抵Linuxを使っているという人が多いと思うけれど、macOSのtarはBSD版のtarなので、GNU tar formatを使っていると普通に展開に失敗しうることを覚えておこう。POSIXとして規格化されているpaxであればこのような事は避けられる。
OpenBSDのpax対応
ちなみにOpenBSDはtarコマンドがデフォルトでpaxを出力するようになった。これはcurrentブランチの話なので、安定版に降ってくるのはもうすこし先だろう。
想い
個人的な想いとしては、普遍的でオープンなファイル形式を使うことがオープンなインターネットの思想に沿うものだと考えているため、あらかじめ規格化されたフォーマットを使うべきだと思う。実装依存のフォーマットは使いたくない。