2018年3月11日日曜日

TAR

 TARファイルのはなし。

 tar(4)
 tar の構造


 基本的に1つの変数を除いて、すべてヌル文字終端の文字列として格納されて、その基数は8進。ただし幅が足りない場合はヌル文字を省略できる、という感じらしい。
 ヘッダは512バイトの固定長、データは512バイトを1ブロックとするが、ヘッダに元の大きさが格納されているので、詰め物を除去できないとかの問題はない。
 ヘッダの先頭から1024バイトの0(ヌル文字)が連続したら、そこをTARの終点とする、みたいな処理になってる。厳密に実装するとヘッダを読み込んだらまず512バイトすべて0か探索して、もしそうなら次の512バイトを読んで、それも0かチェックする、みたいな処理になる。ちょーめんどい。今回はsizeの最初の文字がヌル文字なら終了する、というふうにした。

 8進数が実際に使われてるの初めて見た。

 C#だとこんな感じでファイル一覧を吐ける。
 null終端文字列を切る方法を知らないのでてきとーに関数作った。IndexOfしてSubstringしてるだけ。

using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
    bool loop = true;

    while(loop)
    {
        byte[] buffer = new byte[512];
        fs.Read(buffer, 0, buffer.Length);
                    
        if(buffer[124] != '\0')
        {
            string name = Encoding.ASCII.GetString(buffer, 0, 100);
            string mode = Encoding.ASCII.GetString(buffer, 100, 8);
            string uid = Encoding.ASCII.GetString(buffer, 108, 8);
            string gid = Encoding.ASCII.GetString(buffer, 116, 8);
            string size = Encoding.ASCII.GetString(buffer, 124, 12);
            string mtime = Encoding.ASCII.GetString(buffer, 136, 12);
            string chksum = Encoding.ASCII.GetString(buffer, 148, 8);
            string typeflag = Encoding.ASCII.GetString(buffer, 156, 1);
            string linkname = Encoding.ASCII.GetString(buffer, 157, 100);
            string magic = Encoding.ASCII.GetString(buffer, 257, 6);
            string version = Encoding.ASCII.GetString(buffer, 263, 2);
            string uname = Encoding.ASCII.GetString(buffer, 265, 32);
            string gname = Encoding.ASCII.GetString(buffer, 297, 32);
            string devmagor = Encoding.ASCII.GetString(buffer, 329, 8);
            string devminor = Encoding.ASCII.GetString(buffer, 337, 8);
            string prefix = Encoding.ASCII.GetString(buffer, 345, 155);

            UInt32 data_size_byte = Convert.ToUInt32(size.clip_null_char(), 8);
            UInt32 data_size_block = (data_size_byte + 511) / 512;


            Console.WriteLine(name.clip_null_char() + " " + data_size_byte);

            fs.Position += data_size_block * 512;
        }
        else
        {
            loop = false;
        }
    }
}

 普段使ってる圧縮展開ソフトではTARにできなかった。ファイル数が多すぎたみたい。動画を切り出した連番画像なので3700個もある。
 今回はbashのtarコマンドで作ったけど、*.jpgで全部突っ込んだら単純なASCII文字列でソートした順番になった。自然数順じゃないので、必要に応じて0埋めとかにリネームしておく必要があるかも。ちゃんとしたやりかたはありそうだけど。

 すべて512バイト単位ってのは便利でいいなぁ。格納時に気をつければシーケンシャルリードできるし、まるちめでぃあかーどでも早そう。ファイル名を指定したランダムリードはクッソ遅そう。今回はシーケンシャルで十分だけど。


 とりあえず眠いのでマタアシタ~

0 件のコメント:

コメントを投稿