てきとうなメモ

本の感想とか技術メモとか

GNU tarと@LongLink

アーカイブソフトでtar.gzファイルを解凍すると@LongLinkという名前のファイルが解凍されて「上書きしますか」と繰り返し言われてうざいことがある。

@LongLinkというのはGNU tarによるtarファイルの独自拡張らしい。これを一部の解凍ソフトでは解釈できなくてこんなファイルが生成されてしまう。

tarのファイル形式はヘッダとデータに分かれ、ファイルごとにヘッダ、データの繰り返しのデータ構造になっている。

/* POSIX header.  */

struct posix_header
{                              /* byte offset */
  char name[100];               /*   0 */
  char mode[8];                 /* 100 */
  char uid[8];                  /* 108 */
  char gid[8];                  /* 116 */
  char size[12];                /* 124 */
  char mtime[12];               /* 136 */
  char chksum[8];               /* 148 */
  char typeflag;                /* 156 */
  char linkname[100];           /* 157 */
  char magic[6];                /* 257 */
  char version[2];              /* 263 */
  char uname[32];               /* 265 */
  char gname[32];               /* 297 */
  char devmajor[8];             /* 329 */
  char devminor[8];             /* 337 */
  char prefix[155];             /* 345 */
                                /* 500 */
};

nameの部分がファイルのフルパスなので最大100文字にしかならない。(本当はprefixを使って255文字まで可能らしいんだが、prefixはあまり使われていないらしい。)

もともと100文字までしかなかったのでGNU tarはtypeflag(ファイルとかディレクトリとかファイルの種類)を独自に拡張してL(LONGLINK)とK(LONGNAME)を追加している

/* Identifies the *next* file on the tape as having a long linkname.  */
#define GNUTYPE_LONGLINK 'K'

/* Identifies the *next* file on the tape as having a long name.  */
#define GNUTYPE_LONGNAME 'L'

このtypeflagが出てくると現在のエントリのデータ部がそのファイルのフルパスになり、次のエントリのデータ部がそのファイルの中身になる。

よって、GNU形式のtarファイルをダンプすると以下のようになる

$ cat > aaa.....aaa.txt
Hello, world
$ tar cvf gnu.tar aaa.....aaa.txt
aaa.....aaa.txt
$ od -c gnu.tar
# エントリ1(ヘッダ)
0000000   .   /   .   /   @   L   o   n   g   L   i   n   k  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
...
# エントリ1(データ)
0001000   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a
*
0001140   .   t   x   t  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0001160  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
...
# エントリ2(ヘッダ)
0002000   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a
*
0002140   .   t   x   t   0   0   0   0   6   4   4  \0   0   0   0   1
....
# エントリ2(データ)
0003000   H   e   l   l   o   ,       W   o   r   l   d  \n  \0  \0  \0
0003020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0024000

で、POSIXではどうなっているかというと、pax拡張ヘッダを利用している。typeflagがxだと現在のエントリのデータ部は拡張ヘッダになり、ファイルの中身は次のエントリのデータ部に書き込まれる。

拡張ヘッダの形式は以下のようになっている

"%d %s=%s\n", , ,

keywordはPOSIXで定義されているものと独自に設定できるものがあり、POSIXのもののうちpathはフルパスを表している

そういうわけで、POSIX形式のtarファイルをダンプすると以下のようになる。POSIX形式のtarファイルを作成したい場合は--format=posixをつければ良い。

$ cat > aaa.....aaa.txt
Hello, world
$ tar cvf posix.tar --format=posix aaa.....aaa.txt
aaa.....aaa.txt
$ od -c posix.tar
    # エントリ1(ヘッダ)
0000000    P   a   x   H   e   a   d   e   r   /   a   a   a   a   a   a
0000020    a   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a
*
0000140    a   a  \0  \0   0   0   0   6   4   4      \0   0   0   0   7
... # エントリ1(データ=pax拡張ヘッダ)
0001000    1   1   1       p   a   t   h   =   a   a   a   a   a   a   a
0001020    a   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a
*
0001140    a   a   a   a   a   a   a   a   a   a   .   t   x   t  \n   2
0001160    0       c   t   i   m   e   =   1   2   8   0   2   2   6   0
.... # エントリ 2(ヘッダ)
0002000    a   a   a   a   a   a   a   a   a   a   a   a   a   a   a   a
*
0002140    a   .   t  \0   0   0   0   6   4   4      \0   0   0   0   7
.... # エントリ 2(データ)
*
0003000    H   e   l   l   o   ,       W   o   r   l   d  \n  \0  \0  \0
0003020   \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0006000