読者です 読者をやめる 読者になる 読者になる

フニゲの開発日記

Electronとか...

tar-streamのテスト

Electron

 いま作っているのは、.csnfという超マイナーなフォーマットのエディタだ。これは簡単に言うと(あんまり簡単に言いたくないんだけど)JSONと画像データをtarで固めたもの。編集とか保存はおいおい作ることにして、まず既存のデータを読み込んで画面に表示するところまで作りたい。
 いろいろ素人なので作りながら勉強しようと思っているのだが、Electronでtarを扱うにはtar-streamというのを使うといいらしい。
http://stackoverflow.com/questions/13690613/how-to-untar-file-in-node-js

var tar = require('tar-stream');

var extract = tar.extract();
extract.on('entry', function(header, stream, callback) {
    // make directories or files depending on the header here...
    // call callback() when you're done with this entry
    console.log(header);
    callback();
});

extract.on('finish', function() {
    console.log('done!')
});

fs.createReadStream("hoge.csnf").pipe(extract);

 これに適当なサンプルを食わせると、だいたいこんなログが得られる。

{ name: '/1',
  mode: 1941,
  uid: 1941,
  gid: 1941,
  size: 1941,
  mtime: 1970-01-01T00:32:21.000Z,
  type: 'directory',
  ... }
{ name: '/1/1/ly_f0_b',
  mode: 2288,
  uid: 2288,
  gid: 2288,
  size: 2288,
  mtime: 1970-01-01T00:42:47.000Z,
  type: 'file',
  ... }
...
done!

 エントリのtypeがfileだった時だけmkdir -pしてstreamの内容をpipeでファイルに書き出せば、ディレクトリをテンポラリに復元できるだろう。

...
extract.on('entry', function(header, stream, callback) {
    // make directories or files depending on the header here...
    // call callback() when you're done with this entry
    if (header.type == 'file') {
        var filename = "." + header.name;
        var dirname = require('path').dirname(filename);
        mkdirp(dirname, function(err) {
            if (!err) {
                var writeStream = fs.createWriteStream(filename);
                stream.pipe(writeStream);
            }
        });
    }
    console.log(header);
    callback();
});
...

 これで終わり……だったら世の中美しいんだけどね。

 現実は泥臭いものだ。
 ディレクトリが複数あるデータを食わせるとなぜかエラーが出る。上のログをよく見ると、sizeがおかしいことに気づく。だいたいuidやgidとsizeが同じ値になるとか、常識で考えてありえないだろう。

 ありえないんだけど、まあtarは歴史の長いフォーマットだから、そういう実装もありなのかも知れない。実際コマンドラインのtarを使えば、警告も出さずに黙って展開してくれる。(外部の人間がデータに触らないように)悪意のあるトラップが仕込まれている可能性は否定できないが、ここは何も無いと信じて先に進む。

 tar-streamにパッチを当てるために、まずnode_modules/tar-streamの内容をソースコードディレクトリにコピーする。

> mkdir src/csnf-stream
> cp node_modules/tar-stream/*.js src/csnf-stream

 それから、ディレクトリを展開する時は、ヘッダを無視してサイズを0にするようにコードを修正。

// src/csnf-stream/header.js

...
// to support old tar versions that use trailing / to indicate dirs
if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5

// dir size of CSNF is always wrong. just ignore them...
if (typeflag == 5) size = 0; // この1行を追加
    
var c = cksum(buf)
...

tar−streamの代わりにこのモジュールをrequireして使えばいい。

//var tar = require('tar-stream');
var tar = require('./src/csnf-stream');
広告を非表示にする