目次
この文章はTarの仕様について調べた事をまとめたものです。
調査方法は、GNU Tarのinfoを基礎として、その他不明な所はGNU Tarの実装やその他の実装、インターネットに公開されている資料を参考にしました。
tarは512バイトのブロックが連なった形式になっています。この512バイトのブロックそれぞれに意味を持たせる事によって、tarファイルになっています。
512バイトのブロックは、以下の種類があります。
上記のブロックは以下のように配置されます。
+------------------------+ | directory header block | +------------------------+ | header block 1 | +------------------------+ | file content block 1-1 | +------------------------+ | file content block 1-2 | +------------------------+ | header block 2 | +------------------------+ | file content block 2-1 | +------------------------+ | file content block 2-2 | +------------------------+ | end of tar block 1 | +------------------------+ | end of tar block 2 | +------------------------+
list:[tarの512バイトのブロックの種類]の1は、実際にtarに格納されるファイルまたはディレクトリの所有者やサイズなどの情報を格納します。list:[tarの512バイトのブロックの種類]の1に格納される数字の基数は8進数となっています。
list:[tarの512バイトのブロックの種類]の2のaは0個以上のブロックで構成され、実際のファイルが格納されています。list:[tarの512バイトのブロックの種類]の1と2が合わさって一つのtarエントリーを構成します。このブロックは、格納されるファイルの大きさが512の倍数にならない場合、ファイルの大きさが丁度格納できる、最小の512の倍数の数のブロックを必要とします。例えば、513バイトのファイルを格納しようとするなら、2つの512バイトのブロックが必要になります。このブロック数は、以下の式で求められます。
( (size) + 511 ) / 512
list:[tarの512バイトのブロックの種類]の2のbは、0個のブロックで構成されます。これは、エントリーを構成するlist:[tarの512バイトのブロックの種類]の1にディレクトリ名やパーミッション、所有者などが記録されているので、特に何も格納する必要がないためです。
list:[tarの512バイトのブロックの種類]の2のcは、拡張された属性などを格納します。これは、formatの種類によってまちまちなので「formatの種類」以降で詳しく解説します。
list:[tarの512バイトのブロックの種類]の3は、tarファイルの終わりを表わすブロックです。このブロックは少し特殊で、512バイト全てが0で埋められたブロックを二つ連続で配置します。[6], [7]
tarには以下のファイル形式が存在します。これ以外にもstarという形式もあるようですが[2]、作成する事ができなかったので詳細は不明です。
v7 format
ustar format
pax format
POSIX format
GNU format
図1「Tarのformatの関連性」は、formatの種類の関連性を図示したものです。pax/POSIX formatはustarを改良したものになり、形式的には同一のものとされています[2]。GNU formatはustarにGNU独自の改良を施したものとなります。また、GNU Tarの1.13以降は新しい形式に移行しました。これによって、GNU formatは、1.13以前の古いGNU old formatが出来る事となりました。新しいGNU formatは、未だ開発の途上ですが、いずれはPOSIX形式に準拠するとされています[1]。
v7 formatは一番初めにtarが作成された時に使用されたものです。表1「v7 format header」はheaderのフィールド名とその大きさです。このformatは古い時代に制定されたものなので、様々な制限があります。
以下はその制限です。
v7 formatの制限
ファイル名とシンボリックリンクの最大長は99文字
ブロックファイル、キャラクターファイル、FIFOを格納できない
uidとgidの最大値が2097151(8進数で7777777)
unameとgnameが格納されない
一つのエントリーに格納できるファイルのサイズは最大で8GB
表1 v7 format header
|
name |
size(byte) |
offset |
|---|---|---|
|
name |
100 |
0 |
|
mode |
8 |
100 |
|
uid |
8 |
108 |
|
gid |
8 |
116 |
|
size |
12 |
124 |
|
mtime |
12 |
136 |
|
chksum |
8 |
148 |
|
typeflag |
1 |
156 |
|
linkname |
100 |
157 |
|
pad |
255 |
257 |
ustar formatは、1988年にPOSIXで制定されたformatです。ustar formatのheaderは表2「ustar format header」のフィールドを持っています。これはv7 formatを改良する形で行われました。これによってv7 formatの制限はある程度緩和できたのですが、それでもなおいくつかの制限は残ったままでした。
以下はその制限です。
list:[ustarの制限]の1に関してですが、最大長は256文字になりましたが、これはheaderの余白部分(表2「ustar format header」のpad)を使用して無理矢理実現したものでした。ustar formatでは、99文字以上のパス名が来た場合、まずディレクトリとそれ以外の部分に分けます。そしてディレクトリの部分を表2「ustar format header」のpad部分に格納し、残りの部分をnameに格納する事になります。従って、ディレクトリの最大長は155文字となります。
表2 ustar format header
name | size(byte) | offset |
|---|---|---|
name | 100 | 0 |
mode | 8 | 100 |
uid | 8 | 108 |
gid | 8 | 116 |
size | 12 | 124 |
mtime | 12 | 136 |
chksum | 8 | 148 |
typeflag | 1 | 156 |
linkname | 100 | 157 |
magic | 6 | 257 |
version | 2 | 263 |
uname | 32 | 265 |
gname | 32 | 297 |
devmajor | 8 | 329 |
devminor | 8 | 337 |
prefix | 155 | 345 |
pad | 12 | 500 |
GNU old formatは、ustar formatにGNU独自の拡張を施したformatで、GNU Tarのバージョン1.13まで使用されています。GNU old formatのheaderは表3「GNU Tar old format header」と同じフィールドを持っています。
このformatは、パス名の制限はなくなりました。これは、list:[tarの512バイトのブロックの種類]の2のcに実際のファイル名やリンク名を格納する事で実現しています。
また、必要ならばheaderに格納する数字の基数を256とする事で、ファイルサイズは事実上の無制限に、uid,gidの最大値は1.8e19までに、special fileのdevice major,minorの値の最大値は63bitまでになりました。
表3 GNU Tar old format header
|
name |
size(byte) |
offset |
|---|---|---|
|
unused |
345 |
0 |
|
atime |
12 |
345 |
|
ctime |
12 |
357 |
|
offset |
12 |
369 |
|
longnames |
4 |
381 |
|
unused_pad2 |
1 |
385 |
|
sparse |
96 |
386 |
|
isextended |
1 |
482 |
|
realsize |
12 |
483 |
|
pad |
17 |
495 |
pax/POSIX formatは2001年にPOSXIで制定されたformatです。pax/POSIX formatのheaderは表2「ustar format header」と同じフィールドを持っています。
このformatは以前のformatにあった制限が全てなくなりました。これを可能にしたのが、list:[tarの512バイトのブロックの種類]の2のcの存在です。このformatは、通常のheaderブロック以外に拡張ブロックを持っています。そこに、長くなったパス名などを格納する事によって制限をなくす事に成功しました。この拡張ブロックには以下の二つの種類があります。
list:[pax拡張ヘッダの種類]の1は各ファイルやディレクトリの情報を格納するためのブロックです。list:[pax拡張ヘッダの種類]の2は、内容的には1と同じですが、これは、このブロックが存在する場所より後のブロック全てに影響が及びます。このブロックで指定された内容は、アーカイブからの抽出などの場合に1より優先される事になります。このブロックはアーカイブ中に複数個存在しても良く、その場合は、そのブロックが存在していた場所より後のブロックが影響を受けます。ブロックの配置は以下のようになります。
+--------------------------+ | pax global extend header | +--------------------------+ | pax extend header | +--------------------------+ | header block 1 | +--------------------------+ | content block 1 | +--------------------------+ | pax extend header | +--------------------------+ | header block 2 | +--------------------------+ | content block 2 | +--------------------------+
以下のような配置になっていた場合、pax global extend header 1の影響を受けるのはheader block 1,2だけで、header block 3,4はpax global extend header 2の影響を受けます。
+----------------------------+ | pax global extend header 1 | +----------------------------+ | pax extend header | +----------------------------+ | header block 1 | +----------------------------+ | content block 1 | +----------------------------+ | pax extend header | +----------------------------+ | header block 2 | +----------------------------+ | content block 2 | +----------------------------+ | pax global extend header 2 | +----------------------------+ | pax extend header | +----------------------------+ | header block 3 | +----------------------------+ | content block 3 | +----------------------------+ | pax extend header | +----------------------------+ | header block 4 | +----------------------------+ | content block 4 | +----------------------------+
このformatは、プログラムの側が対応していない場合はustar formatに見えるようになっており、pax extend headerは通常のファイルとして扱われるようになっています。[5]
フォーマットの判別には、ヘッダのmagicとversionフィールドを使用します。表4「magicとversionフィールドの値」がフォーマットとその値です。少し分かりにくいですが、ustar/pax/posixは、magicの値が「ustar0(数字の0)」とversionが「"00"(文字列の0が二つ)」、GNUは、magicの値が「ustar (スペース)」とversionが「 0(スペースと数字の0)」になります。v7の場合はそもそもフォーマットを判別する必要がなかったので、どちらも数字の0になります。
表4 magicとversionフィールドの値
|
format |
magic |
version |
|---|---|---|
|
v7 |
0 |
0 |
|
ustar/pax/POSIX |
[uster\x00] |
["00"] |
|
GNU |
[ustar ] |
[ \x00] |
GNU formatとGNU old formatの判別方法ですが、これはheaderブロックのmodeの値を見ます。通常、ここには最大で8進数の7777までしか格納されませんが、長さは8byte確保されています。GNU old formatはこの部分を利用して5桁目以降を0以外の値にする事でGNU formatと区別しています。実際に確認した所(GNU TAR 1.30で --format=gnuoldで作成)、ファイルのモードが644のファイルをGNU old formatで格納した場合には0100644が格納されていました。
Tarのheaderはそれ自体の妥当性を検証するためにチェックサムの値を持っています。
チェックサムの計算方法は、headerの全ての値を足し合せたものになります。これはチェックサムフィールド自身も含みますが、実際にチェックサムフィールドを計算する時には、ここには空白文字(10進数で32)が入っていると仮定して計算を行います。
Tarのheaderの種類を判別するにはtypeflagの値を見ます。表5「typeflagの値と意味」はその一覧です。
表5 typeflagの値と意味
flag value | description |
|---|---|
0 | 通常のファイル |
\0 | |
1 | ハードリンク |
2 | シンボリックリンク |
3 | キャラクターファイル |
4 | ブロックファイル |
5 | ディレクトリ |
6 | FIFO |
x | pax/POSIX extend header |
g | pax/POSIX global extend header |
D | GNU old formatインクリメンタルディレクトリ(-G: GNU拡張) |
K | longlink(GNU拡張) |
L | longname(GNU拡張) |
M | multi volume(--multi: GNU拡張) |
S | スパースファイル(--sparse: GNU拡張) |
V | volume header(--volume: GNU拡張) |
Tarのformatの種類により、上記の表5「typeflagの値と意味」の中にはサポートしていないものもあります。表6「typeflag matrix」は、それを表にしたものです。
表6 typeflag matrix
v7 | ustar | GNU old | GNU | pax/POSIX | ||
|---|---|---|---|---|---|---|
0/"\0" | 通常のファイル | ○ | ○ | ○ | ○ | ○ |
1 | ハードリンク | ○ | ○ | ○ | ○ | ○ |
2 | シンボリックリンク | ○ | ○ | ○ | ○ | ○ |
3 | キャラクターファイル | - | ○ | ○ | ○ | ○ |
4 | ブロックファイル | - | ○ | ○ | ○ | ○ |
5 | ディレクトリ | ○ | ○ | ○ | ○ | ○ |
6 | FIFO | - | ○ | ○ | ○ | ○ |
x | pax/POSIX extend header | - | - | - | - | ○ |
g | pax/POSIX global extend header | - | - | - | - | ○ |
D | GNU old formatインクリメンタルディレクトリ(-G: GNU拡張) | - | - | ○ | - | - |
K | longlink(GNU拡張) | - | - | ○ | ○ | - |
L | longname(GNU拡張) | - | - | ○ | ○ | - |
M | multi volume(--multi: GNU拡張) | - | - | ○ | ○ | - |
S | スパースファイル(--sparse: GNU拡張) | - | - | ○ | ○ | - |
V | volume header(--volume: GNU拡張) | - | - | ○ | ○ | - |
ustar, GNU old, GNU, pax/POSIX formatは、99文字以上のパス名をサポートしています。しかし、それぞれのformatでサポートの仕方が違うので、ここでまとめて説明します。
まず、ustar formatですが、このformatは「ustar format」にあるように、最大255文字のパス名をサポートします。これは、表2「ustar format header」のpadフィールドを使用して実現しています。長いパス名が表れた時、ustar formatは、まず、それをディレクトリとそれ以外とに分割します。この時にディレクトリの長さが155文字を越えるとエラーになります。こうして分解されたディレクトリはheaderのpadフィールドに、それ以外はnameフィールドに格納されます。これは、ファイル名、ハードリンク、シンボリックリンクの全てに当てはまります。
次にGNU old, GNU formatについてですが、このformatは長いパス名が表れた時に、それ専用のブロックを作成する事で対処します。以下は、その配置です。
+------------------------------+ | longname header block | +------------------------------+ | longname content block | +------------------------------+ | file/directory header block | +------------------------------+ | file/directory content block | +------------------------------+
longname header blockは、通常のheaderと要素自体は変わりありませんが、フィールドにセットされる値が少し特殊なものになっています。まず、nameフィールドは「././@LongLink」という文字列が格納されます。そして、typeflagフィールドには'L’または'K'が、uid,gidフィールドには0が、格納されsizeフィールドには続くlongname content blockの大きさが格納されます。longname content blockには、実際の長いパス名が格納されます。
最後にpax/POSIX formatですが、このformatは長いパス名が表れた場合にはpax extend headerにそのパス名が格納されます。
ここでは、pax/POSIX extend headerについて説明します。
pax/POSIX extend headerは、「pax/POSIX format」で書いた通り、ustar formatを拡張して制定されました。そのため、もしアプリケーションの側が対応していない場合でもustarのheaderに見えるように、ustarの通常のファイルと同じフィールドを持ち、そこに設定される値を少し変える事でextend headerとしています。これによって、もし、対応していないアプリケーションで扱う事があっても、最悪の場合でも通常のファイルとして扱われる事となります。
pax/POSIX extend headerは、以下のような構成になっています。
+---------------------------------+ | pax/POSIX extend header data | +---------------------------------+ | pax/POSIX extend header content | +---------------------------------+
pax/POSIX extend header dataがustar formatの通常のファイル用のheaderに当たり、pax/POSIX extend header contentの部分がustar formatの通常のファイルの内容に当たります。そして、この部分に拡張された属性の値が格納されます。
格納する属性の値の書式は決まっており、以下のようになっています。
%d %s=%s\n
上記の書式を一つのレコードとして、それが必要な数だけ続きます。書式は「[length] [keyword]=[value]」という構成なっており、[length]は、改行を含むレコード全体の長さを10進数で格納します。[keyword]は以下のものから一つ選びます。[value]は[keyword]に関連した値を設定します。[value]の文字コードはUTF-8が推奨され、長さに特に制限はありません。[4]
表7「pax標準キーワード一覧」は、pax/POSIXで規定されている[keyword]の一覧です。表8「pax拡張キーワード一覧」は、pax/POSIXで規定されていませんが、ある程度有益な情報を格納するための[keyword]の一覧です。最後の表9「GNU用pax拡張キーワード一覧」は、GNU Tarが使用する[keyword]の一覧です。
表7 pax標準キーワード一覧
field | note |
|---|---|
path | ファイル名かディレクトリ名 |
linkpath | ハードリンク名かシンボリックリンク名 |
size | |
uid | |
gid | |
uname | |
gname | |
mtime | ミリ秒まで格納可能 |
atime | ミリ秒まで格納可能 |
ctime | ミリ秒まで格納可能 |
charset | |
comment |
引用: [3]
表8 pax拡張キーワード一覧
field | note |
|---|---|
RHT.security.selinux | SELinux用 |
SCHILY.acl.access | for xattr ACL |
SCHILY.acl.default | for xattr ACL |
SCHILY.xattr. | xattr用のprefix。この後にxattrの属性名が続く。 |
引用: [2]
表9 GNU用pax拡張キーワード一覧
field | note |
|---|---|
GNU.sparse. | スパースファイル用のprefix。実際には表れない。 |
GNU.sparse.numblocks | PAX 0 version 0.0およびversion 0.1が使用する。 |
GNU.sparse.offset | PAX 0 version 0.0が使用する。 |
GNU.sparse.numbytes | PAX 0 version 0.0が使用する。 |
GNU.sparse.map | PAX 0 version 0.1が使用する。 |
GNU.sparse.name | PAX 0 version 0.1が使用する。 |
GNU.sparse.major | PAX 1 version 1.0が使用する。 |
GNU.sparse.minor | PAX 1 version 1.0が使用する。 |
GNU.sparse.size | Tarに格納されている大きさ。PAX 0 version 0.0が使用する。 |
GNU.sparse.realsize | スパースファイルの本当の大きさ |
GNU.dumpdir | |
GNU.volume.label | |
GNU.volume.filename | |
GNU.volume.size | |
GNU.volume.offset |
引用: [2]
GNU Tarはスパースファイルを扱う事ができます。その時、スパースファイルの情報はアーカイブの中に保存されますが、そのformatは数種類あります。
以下はそのformatの種類です。
上記のformatは使われるGNU Tarのバージョンによって変化し、list:[スパースファイルの種類]の1はバージョン1.14までのGNU Tarが使用し、list:[スパースファイルの種類]の2のversion 0.0はバージョン1.14から1.15.1のGNU Tarが使用します。list:[スパースファイルの種類]の2のversion 0.1はバージョン1.15.2のGNU Tarが使用し、list:[スパースファイルの種類]の3はバージョン1.15.92以降のGNU Tarが使用します。list:[スパースファイルの種類]の2と3は、Tarのformatがpax/POSIXの場合にしか使用されません。
各formatはそれぞれ互換性がありません。
Old GNU Formatでは、スパースファイルの情報は例1「sparse.c」の構造体に格納されます。この構造体だけでスパースファイルの情報が収まらなかった場合は、次以降に512byteのスパースファイルの情報だけを格納したブロックを必要な数だけ並べます。
以下はその模式図です。
+-------------------------------------+ | file header with sparse information | +-------------------------------------+ | sparse header 1 (if any) | +-------------------------------------+ | sparse header 2 (if any) | +-------------------------------------+ | file content | +-------------------------------------+
スパースファイルの0でない部分の先頭からのoffsetは例1「sparse.c」の(1)に、その部分のサイズが例1「sparse.c」の(2)に格納されます。
例1「sparse.c」の(5)が1の場合は次のブロックは(3)が格納されたものになります。
例1「sparse.c」の(4)の値が1だった場合には、次のブロックも(3)が格納されたものになります。
例1 sparse.c
struct sparse { /* byte offset */ char offset[12]; /* 0 */ (1) char numbytes[12]; /* 12 */ (2) /* 24 */ }; #define SPARSES_IN_EXTRA_HEADER 16 #define SPARSES_IN_OLDGNU_HEADER 4 #define SPARSES_IN_SPARSE_HEADER 21 struct sparse_header (3) { /* byte offset */ (3) struct sparse sp[SPARSES_IN_SPARSE_HEADER]; /* 0 */ (3) char isextended; /* 504 */ (3)(4) /* 505 */ (3) }; (3) struct { /* byte offset */ char unused1[345]; /* 0 */ char atime[12]; /* 345 Incr. archive: atime of the file */ char ctime[12]; /* 357 Incr. archive: ctime of the file */ char offset[12]; /* 369 Multivolume archive: the offset of the start of this volume */ char longnames[4]; /* 381 Not used */ char unused_pad2; /* 385 */ struct sparse sp[SPARSES_IN_OLDGNU_HEADER]; /* 386 */ char isextended; /* 482 Sparse file: Extension sparse header follows */ (5) char realsize[12]; /* 483 Sparse file: Real size*/ char pad[17]; /* 495 */ };
引用: [2]
PAX 0では、pax extend headerを利用してスパースファイルの情報を格納します。
version 0.0は、以下の拡張キーワードを使用します。
PAX0 version 0.0の拡張キーワード
GNU.sparse.size 格納されているスパースファイルの本当の大きさ
GNU.sparse.numblocks スパースファイルの情報のブロックの数
GNU.sparse.offset 先頭からのオフセット
GNU.sparse.numbytes 0でない部分のサイズ
これらのキーワードは以下のように配置されます。(引用: [1])
GNU.sparse.size=SIZE
GNU.sparse.numblocks=NUMBLOCKS
repeat NUMBLOCKS times
GNU.sparse.offset=OFFSET
GNU.sparse.numbytes=NUMBYTES
end repeatversion 0.1は、以下の拡張キーワードを使用します。
PAX 0 version 0.1の拡張キーワード
GNU.sparse.map スパースファイルの情報を格納するmap
GNU.sparse.mapには以下の書式のデータが格納されます。(引用: [1])
OFFSET,SIZE[,OFFSET-1,SIZE-1...]
PAX 1では、pax extend headerを利用してスパースファイルの情報を格納します。
PAX 1では、以下の拡張キーワードを使用します。
PAX1の拡張キーワード
GNU.sparse.major メジャーバージョン。1が格納される
GNU.sparse.minor マイナーバージョン。0が格納される。
実際のスパースファイルの情報はcontentブロックの先頭に格納されます。
以下はその模式図です。
+---------------------------------------------------+ | pax/POSIX extend header with sparse file keywords | +---------------------------------------------------+ | pax/POSIX extend header content | +---------------------------------------------------+ | file header | +---------------------------------------------------+ | sparse file information block 1 | +---------------------------------------------------+ | sparse file information block 2 | +---------------------------------------------------+ | file content | +---------------------------------------------------+
スパースファイルの情報は以下の書式で格納されます。
NUMBLOCKS OFFSET NUMBYTES [OFFSET1 NUMBYTES1 . . . ]
簡単にですがTarの仕様をまとめてみました。調査の結果分かった事は、Tarの構造自体は簡単なものでしたが、それ故沢山の実装が林立し、その結果、複数の良く似たformatが誕生する事になりました。
Tarの種々のformatは膨大で複雑なため、この文章で全てをまとめる事は出来ませんでした。しかし、世に出回っている大半のTarの実装が採用している仕様は文章化できたと思います。
[1] GNU Tar 1.30: E. Tar Internals. http://www.gnu.org/software/tar/manual/html_chapter/tar_15.html.
[4] IBM Knowledge Center - pax extended header. https://www.ibm.com/support/knowledgecenter/SSLTBW_2.3.0/com.ibm.zos.v2r3.bpxa500/paxex.htm.