tar-stream
Advanced tools
Comparing version 0.4.6 to 0.4.7
298
extract.js
@@ -1,194 +0,194 @@ | ||
var util = require('util'); | ||
var bl = require('bl'); | ||
var xtend = require('xtend'); | ||
var headers = require('./headers'); | ||
var util = require('util') | ||
var bl = require('bl') | ||
var xtend = require('xtend') | ||
var headers = require('./headers') | ||
var Writable = require('readable-stream').Writable; | ||
var PassThrough = require('readable-stream').PassThrough; | ||
var Writable = require('readable-stream').Writable | ||
var PassThrough = require('readable-stream').PassThrough | ||
var noop = function() {}; | ||
var noop = function() {} | ||
var overflow = function(size) { | ||
size &= 511; | ||
return size && 512 - size; | ||
}; | ||
size &= 511 | ||
return size && 512 - size | ||
} | ||
var emptyStream = function() { | ||
var s = new PassThrough(); | ||
s.end(); | ||
return s; | ||
}; | ||
var s = new PassThrough() | ||
s.end() | ||
return s | ||
} | ||
var mixinPax = function(header, pax) { | ||
if (pax.path) header.name = pax.path; | ||
if (pax.linkpath) header.linkname = pax.linkpath; | ||
return header; | ||
}; | ||
if (pax.path) header.name = pax.path | ||
if (pax.linkpath) header.linkname = pax.linkpath | ||
return header | ||
} | ||
var Extract = function(opts) { | ||
if (!(this instanceof Extract)) return new Extract(opts); | ||
Writable.call(this, opts); | ||
if (!(this instanceof Extract)) return new Extract(opts) | ||
Writable.call(this, opts) | ||
this._buffer = bl(); | ||
this._missing = 0; | ||
this._onparse = noop; | ||
this._header = null; | ||
this._stream = null; | ||
this._overflow = null; | ||
this._cb = null; | ||
this._locked = false; | ||
this._destroyed = false; | ||
this._pax = null; | ||
this._paxGlobal = null; | ||
this._buffer = bl() | ||
this._missing = 0 | ||
this._onparse = noop | ||
this._header = null | ||
this._stream = null | ||
this._overflow = null | ||
this._cb = null | ||
this._locked = false | ||
this._destroyed = false | ||
this._pax = null | ||
this._paxGlobal = null | ||
var self = this; | ||
var b = self._buffer; | ||
var self = this | ||
var b = self._buffer | ||
var oncontinue = function() { | ||
self._continue(); | ||
}; | ||
var oncontinue = function() { | ||
self._continue() | ||
} | ||
var onunlock = function(err) { | ||
self._locked = false; | ||
if (err) return self.destroy(err); | ||
if (!self._stream) oncontinue(); | ||
}; | ||
var onunlock = function(err) { | ||
self._locked = false | ||
if (err) return self.destroy(err) | ||
if (!self._stream) oncontinue() | ||
} | ||
var onstreamend = function() { | ||
self._stream = null; | ||
var drain = overflow(self._header.size); | ||
if (drain) self._parse(drain, ondrain); | ||
else self._parse(512, onheader); | ||
if (!self._locked) oncontinue(); | ||
}; | ||
var onstreamend = function() { | ||
self._stream = null | ||
var drain = overflow(self._header.size) | ||
if (drain) self._parse(drain, ondrain) | ||
else self._parse(512, onheader) | ||
if (!self._locked) oncontinue() | ||
} | ||
var ondrain = function() { | ||
self._buffer.consume(overflow(self._header.size)); | ||
self._parse(512, onheader); | ||
oncontinue(); | ||
}; | ||
var ondrain = function() { | ||
self._buffer.consume(overflow(self._header.size)) | ||
self._parse(512, onheader) | ||
oncontinue() | ||
} | ||
var onpaxglobalheader = function() { | ||
var size = self._header.size; | ||
self._paxGlobal = headers.decodePax(b.slice(0, size)); | ||
b.consume(size); | ||
onstreamend(); | ||
} | ||
var onpaxglobalheader = function() { | ||
var size = self._header.size | ||
self._paxGlobal = headers.decodePax(b.slice(0, size)) | ||
b.consume(size) | ||
onstreamend() | ||
} | ||
var onpaxheader = function() { | ||
var size = self._header.size; | ||
self._pax = headers.decodePax(b.slice(0, size)); | ||
if (self._paxGlobal) self._pax = xtend(self._paxGlobal, self._pax); | ||
b.consume(size); | ||
onstreamend(); | ||
}; | ||
var onpaxheader = function() { | ||
var size = self._header.size | ||
self._pax = headers.decodePax(b.slice(0, size)) | ||
if (self._paxGlobal) self._pax = xtend(self._paxGlobal, self._pax) | ||
b.consume(size) | ||
onstreamend() | ||
} | ||
var onheader = function() { | ||
var header | ||
try { | ||
header = self._header = headers.decode(b.slice(0, 512)); | ||
} catch (err) { | ||
self.emit('error', err); | ||
} | ||
b.consume(512); | ||
var onheader = function() { | ||
var header | ||
try { | ||
header = self._header = headers.decode(b.slice(0, 512)) | ||
} catch (err) { | ||
self.emit('error', err) | ||
} | ||
b.consume(512) | ||
if (!header) { | ||
self._parse(512, onheader); | ||
oncontinue(); | ||
return; | ||
} | ||
if (header.type === 'pax-global-header') { | ||
self._parse(header.size, onpaxglobalheader); | ||
oncontinue(); | ||
return; | ||
} | ||
if (header.type === 'pax-header') { | ||
self._parse(header.size, onpaxheader); | ||
oncontinue(); | ||
return; | ||
} | ||
if (!header) { | ||
self._parse(512, onheader) | ||
oncontinue() | ||
return | ||
} | ||
if (header.type === 'pax-global-header') { | ||
self._parse(header.size, onpaxglobalheader) | ||
oncontinue() | ||
return | ||
} | ||
if (header.type === 'pax-header') { | ||
self._parse(header.size, onpaxheader) | ||
oncontinue() | ||
return | ||
} | ||
if (self._pax) { | ||
self._header = header = mixinPax(header, self._pax); | ||
self._pax = null; | ||
} | ||
if (self._pax) { | ||
self._header = header = mixinPax(header, self._pax) | ||
self._pax = null | ||
} | ||
self._locked = true; | ||
self._locked = true | ||
if (!header.size) { | ||
self._parse(512, onheader); | ||
self.emit('entry', header, emptyStream(), onunlock); | ||
return; | ||
} | ||
if (!header.size) { | ||
self._parse(512, onheader) | ||
self.emit('entry', header, emptyStream(), onunlock) | ||
return | ||
} | ||
self._stream = new PassThrough(); | ||
self._stream = new PassThrough() | ||
self.emit('entry', header, self._stream, onunlock); | ||
self._parse(header.size, onstreamend); | ||
oncontinue(); | ||
}; | ||
self.emit('entry', header, self._stream, onunlock) | ||
self._parse(header.size, onstreamend) | ||
oncontinue() | ||
} | ||
this._parse(512, onheader); | ||
}; | ||
this._parse(512, onheader) | ||
} | ||
util.inherits(Extract, Writable); | ||
util.inherits(Extract, Writable) | ||
Extract.prototype.destroy = function(err) { | ||
if (this._destroyed) return; | ||
this._destroyed = true; | ||
if (this._destroyed) return | ||
this._destroyed = true | ||
if (err) this.emit('error', err); | ||
this.emit('close'); | ||
if (this._stream) this._stream.emit('close'); | ||
}; | ||
if (err) this.emit('error', err) | ||
this.emit('close') | ||
if (this._stream) this._stream.emit('close') | ||
} | ||
Extract.prototype._parse = function(size, onparse) { | ||
if (this._destroyed) return; | ||
this._missing = size; | ||
this._onparse = onparse; | ||
}; | ||
if (this._destroyed) return | ||
this._missing = size | ||
this._onparse = onparse | ||
} | ||
Extract.prototype._continue = function(err) { | ||
if (this._destroyed) return; | ||
var cb = this._cb; | ||
this._cb = noop; | ||
if (this._overflow) this._write(this._overflow, undefined, cb); | ||
else cb(); | ||
}; | ||
if (this._destroyed) return | ||
var cb = this._cb | ||
this._cb = noop | ||
if (this._overflow) this._write(this._overflow, undefined, cb) | ||
else cb() | ||
} | ||
Extract.prototype._write = function(data, enc, cb) { | ||
if (this._destroyed) return; | ||
if (this._destroyed) return | ||
var s = this._stream; | ||
var b = this._buffer; | ||
var missing = this._missing; | ||
var s = this._stream | ||
var b = this._buffer | ||
var missing = this._missing | ||
// we do not reach end-of-chunk now. just forward it | ||
// we do not reach end-of-chunk now. just forward it | ||
if (data.length < missing) { | ||
this._missing -= data.length; | ||
this._overflow = null; | ||
if (s) return s.write(data, cb); | ||
b.append(data); | ||
return cb(); | ||
} | ||
if (data.length < missing) { | ||
this._missing -= data.length | ||
this._overflow = null | ||
if (s) return s.write(data, cb) | ||
b.append(data) | ||
return cb() | ||
} | ||
// end-of-chunk. the parser should call cb. | ||
// end-of-chunk. the parser should call cb. | ||
this._cb = cb; | ||
this._missing = 0; | ||
this._cb = cb | ||
this._missing = 0 | ||
var overflow = null; | ||
if (data.length > missing) { | ||
overflow = data.slice(missing); | ||
data = data.slice(0, missing); | ||
} | ||
var overflow = null | ||
if (data.length > missing) { | ||
overflow = data.slice(missing) | ||
data = data.slice(0, missing) | ||
} | ||
if (s) s.end(data); | ||
else b.append(data); | ||
if (s) s.end(data) | ||
else b.append(data) | ||
this._overflow = overflow; | ||
this._onparse(); | ||
}; | ||
this._overflow = overflow | ||
this._onparse() | ||
} | ||
module.exports = Extract; | ||
module.exports = Extract |
338
headers.js
@@ -1,221 +0,221 @@ | ||
var ZEROS = '0000000000000000000'; | ||
var ZERO_OFFSET = '0'.charCodeAt(0); | ||
var USTAR = 'ustar\x0000'; | ||
var ZEROS = '0000000000000000000' | ||
var ZERO_OFFSET = '0'.charCodeAt(0) | ||
var USTAR = 'ustar\x0000' | ||
var clamp = function(index, len, defaultValue) { | ||
if (typeof index !== 'number') return defaultValue; | ||
index = ~~index; // Coerce to integer. | ||
if (index >= len) return len; | ||
if (index >= 0) return index; | ||
index += len; | ||
if (index >= 0) return index; | ||
return 0; | ||
}; | ||
if (typeof index !== 'number') return defaultValue | ||
index = ~~index // Coerce to integer. | ||
if (index >= len) return len | ||
if (index >= 0) return index | ||
index += len | ||
if (index >= 0) return index | ||
return 0 | ||
} | ||
var toType = function(flag) { | ||
switch (flag) { | ||
case 0: | ||
return 'file'; | ||
case 1: | ||
return 'link'; | ||
case 2: | ||
return 'symlink'; | ||
case 3: | ||
return 'character-device'; | ||
case 4: | ||
return 'block-device'; | ||
case 5: | ||
return 'directory'; | ||
case 6: | ||
return 'fifo'; | ||
case 7: | ||
return 'contiguous-file'; | ||
case 72: | ||
return 'pax-header'; | ||
case 55: | ||
return 'pax-global-header' | ||
} | ||
switch (flag) { | ||
case 0: | ||
return 'file' | ||
case 1: | ||
return 'link' | ||
case 2: | ||
return 'symlink' | ||
case 3: | ||
return 'character-device' | ||
case 4: | ||
return 'block-device' | ||
case 5: | ||
return 'directory' | ||
case 6: | ||
return 'fifo' | ||
case 7: | ||
return 'contiguous-file' | ||
case 72: | ||
return 'pax-header' | ||
case 55: | ||
return 'pax-global-header' | ||
} | ||
return null; | ||
}; | ||
return null | ||
} | ||
var toTypeflag = function(flag) { | ||
switch (flag) { | ||
case 'file': | ||
return 0; | ||
case 'link': | ||
return 1; | ||
case 'symlink': | ||
return 2; | ||
case 'character-device': | ||
return 3; | ||
case 'block-device': | ||
return 4; | ||
case 'directory': | ||
return 5; | ||
case 'fifo': | ||
return 6; | ||
case 'contiguous-file': | ||
return 7; | ||
case 'pax-header': | ||
return 72; | ||
} | ||
switch (flag) { | ||
case 'file': | ||
return 0 | ||
case 'link': | ||
return 1 | ||
case 'symlink': | ||
return 2 | ||
case 'character-device': | ||
return 3 | ||
case 'block-device': | ||
return 4 | ||
case 'directory': | ||
return 5 | ||
case 'fifo': | ||
return 6 | ||
case 'contiguous-file': | ||
return 7 | ||
case 'pax-header': | ||
return 72 | ||
} | ||
return 0; | ||
}; | ||
return 0 | ||
} | ||
var alloc = function(size) { | ||
var buf = new Buffer(size); | ||
buf.fill(0); | ||
return buf; | ||
}; | ||
var buf = new Buffer(size) | ||
buf.fill(0) | ||
return buf | ||
} | ||
var indexOf = function(block, num, offset, end) { | ||
for (; offset < end; offset++) { | ||
if (block[offset] === num) return offset; | ||
} | ||
return end; | ||
}; | ||
for (; offset < end; offset++) { | ||
if (block[offset] === num) return offset | ||
} | ||
return end | ||
} | ||
var cksum = function(block) { | ||
var sum = 8 * 32; | ||
for (var i = 0; i < 148; i++) sum += block[i]; | ||
for (var i = 156; i < 512; i++) sum += block[i]; | ||
return sum; | ||
}; | ||
var sum = 8 * 32 | ||
for (var i = 0; i < 148; i++) sum += block[i] | ||
for (var i = 156; i < 512; i++) sum += block[i] | ||
return sum | ||
} | ||
var encodeOct = function(val, n) { | ||
val = val.toString(8); | ||
return ZEROS.slice(0, n-val.length)+val+' '; | ||
}; | ||
val = val.toString(8) | ||
return ZEROS.slice(0, n-val.length)+val+' ' | ||
} | ||
var decodeOct = function(val, offset) { | ||
// Older versions of tar can prefix with spaces | ||
while (val[offset] === 32) offset += 1; | ||
// Older versions of tar can prefix with spaces | ||
while (offset < val.length && val[offset] === 32) offset++ | ||
return parseInt(val.slice(offset, clamp(indexOf(val, 32, offset, val.length), val.length, val.length)).toString(), 8); | ||
}; | ||
return parseInt(val.slice(offset, clamp(indexOf(val, 32, offset, val.length), val.length, val.length)).toString(), 8) | ||
} | ||
var decodeStr = function(val, offset, length) { | ||
return val.slice(offset, indexOf(val, 0, offset, offset+length)).toString(); | ||
}; | ||
return val.slice(offset, indexOf(val, 0, offset, offset+length)).toString(); | ||
} | ||
var addLength = function(str) { | ||
var len = Buffer.byteLength(str); | ||
var digits = Math.floor(Math.log(len) / Math.log(10)) + 1; | ||
if (len + digits > Math.pow(10, digits)) digits++; | ||
var len = Buffer.byteLength(str) | ||
var digits = Math.floor(Math.log(len) / Math.log(10)) + 1 | ||
if (len + digits > Math.pow(10, digits)) digits++ | ||
return (len+digits)+str; | ||
}; | ||
return (len+digits)+str | ||
} | ||
exports.encodePax = function(opts) { // TODO: encode more stuff in pax | ||
var result = ''; | ||
if (opts.name) result += addLength(' path='+opts.name+'\n'); | ||
if (opts.linkname) result += addLength(' linkpath='+opts.linkname+'\n'); | ||
return new Buffer(result); | ||
}; | ||
var result = '' | ||
if (opts.name) result += addLength(' path='+opts.name+'\n') | ||
if (opts.linkname) result += addLength(' linkpath='+opts.linkname+'\n') | ||
return new Buffer(result) | ||
} | ||
exports.decodePax = function(buf) { | ||
var result = {}; | ||
var result = {} | ||
while (buf.length) { | ||
var i = 0; | ||
for (; i < buf.length && buf[i] !== 32; i++); | ||
var len = parseInt(buf.slice(0, i).toString()); | ||
if (!len) return result; | ||
while (buf.length) { | ||
var i = 0 | ||
while (i < buf.length && buf[i] !== 32) i++ | ||
var b = buf.slice(i+1, len-1).toString(); | ||
var keyIndex = b.indexOf('='); | ||
if (keyIndex === -1) return result; | ||
result[b.slice(0, keyIndex)] = b.slice(keyIndex+1); | ||
var len = parseInt(buf.slice(0, i).toString()) | ||
if (!len) return result | ||
buf = buf.slice(len); | ||
} | ||
var b = buf.slice(i+1, len-1).toString() | ||
var keyIndex = b.indexOf('=') | ||
if (keyIndex === -1) return result | ||
result[b.slice(0, keyIndex)] = b.slice(keyIndex+1) | ||
return result; | ||
}; | ||
buf = buf.slice(len) | ||
} | ||
return result | ||
} | ||
exports.encode = function(opts) { | ||
var buf = alloc(512); | ||
var name = opts.name; | ||
var prefix = ''; | ||
var buf = alloc(512) | ||
var name = opts.name | ||
var prefix = '' | ||
if (opts.typeflag === 5 && name[name.length-1] !== '/') name += '/'; | ||
if (Buffer.byteLength(name) !== name.length) return null; // utf-8 | ||
if (opts.typeflag === 5 && name[name.length-1] !== '/') name += '/' | ||
if (Buffer.byteLength(name) !== name.length) return null // utf-8 | ||
while (Buffer.byteLength(name) > 100) { | ||
var i = name.indexOf('/'); | ||
if (i === -1) return null; | ||
prefix += prefix ? '/' + name.slice(0, i) : name.slice(0, i); | ||
name = name.slice(i+1); | ||
} | ||
while (Buffer.byteLength(name) > 100) { | ||
var i = name.indexOf('/') | ||
if (i === -1) return null | ||
prefix += prefix ? '/' + name.slice(0, i) : name.slice(0, i) | ||
name = name.slice(i+1) | ||
} | ||
if (Buffer.byteLength(name) > 100 || Buffer.byteLength(prefix) > 155) return null; | ||
if (opts.linkname && Buffer.byteLength(opts.linkname) > 100) return null; | ||
if (Buffer.byteLength(name) > 100 || Buffer.byteLength(prefix) > 155) return null | ||
if (opts.linkname && Buffer.byteLength(opts.linkname) > 100) return null | ||
buf.write(name); | ||
buf.write(encodeOct(opts.mode & 07777, 6), 100); | ||
buf.write(encodeOct(opts.uid, 6), 108); | ||
buf.write(encodeOct(opts.gid, 6), 116); | ||
buf.write(encodeOct(opts.size, 11), 124); | ||
buf.write(encodeOct((opts.mtime.getTime() / 1000) | 0, 11), 136); | ||
buf.write(name) | ||
buf.write(encodeOct(opts.mode & 07777, 6), 100) | ||
buf.write(encodeOct(opts.uid, 6), 108) | ||
buf.write(encodeOct(opts.gid, 6), 116) | ||
buf.write(encodeOct(opts.size, 11), 124) | ||
buf.write(encodeOct((opts.mtime.getTime() / 1000) | 0, 11), 136) | ||
buf[156] = ZERO_OFFSET + toTypeflag(opts.type); | ||
buf[156] = ZERO_OFFSET + toTypeflag(opts.type) | ||
if (opts.linkname) buf.write(opts.linkname, 157); | ||
if (opts.linkname) buf.write(opts.linkname, 157) | ||
buf.write(USTAR, 257); | ||
if (opts.uname) buf.write(opts.uname, 265); | ||
if (opts.gname) buf.write(opts.gname, 297); | ||
buf.write(encodeOct(opts.devmajor || 0, 6), 329); | ||
buf.write(encodeOct(opts.devminor || 0, 6), 337); | ||
buf.write(USTAR, 257) | ||
if (opts.uname) buf.write(opts.uname, 265) | ||
if (opts.gname) buf.write(opts.gname, 297) | ||
buf.write(encodeOct(opts.devmajor || 0, 6), 329) | ||
buf.write(encodeOct(opts.devminor || 0, 6), 337) | ||
if (prefix) buf.write(prefix, 345); | ||
if (prefix) buf.write(prefix, 345) | ||
buf.write(encodeOct(cksum(buf), 6), 148); | ||
buf.write(encodeOct(cksum(buf), 6), 148) | ||
return buf; | ||
}; | ||
return buf | ||
} | ||
exports.decode = function(buf) { | ||
var typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET; | ||
var type = toType(typeflag); | ||
var typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET | ||
var type = toType(typeflag) | ||
var name = decodeStr(buf, 0, 100); | ||
var mode = decodeOct(buf, 100); | ||
var uid = decodeOct(buf, 108); | ||
var gid = decodeOct(buf, 116); | ||
var size = decodeOct(buf, 124); | ||
var mtime = decodeOct(buf, 136); | ||
var linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100); | ||
var uname = decodeStr(buf, 265, 32); | ||
var gname = decodeStr(buf, 297, 32); | ||
var devmajor = decodeOct(buf, 329); | ||
var devminor = decodeOct(buf, 337); | ||
var name = decodeStr(buf, 0, 100) | ||
var mode = decodeOct(buf, 100) | ||
var uid = decodeOct(buf, 108) | ||
var gid = decodeOct(buf, 116) | ||
var size = decodeOct(buf, 124) | ||
var mtime = decodeOct(buf, 136) | ||
var linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100) | ||
var uname = decodeStr(buf, 265, 32) | ||
var gname = decodeStr(buf, 297, 32) | ||
var devmajor = decodeOct(buf, 329) | ||
var devminor = decodeOct(buf, 337) | ||
if (buf[345]) name = decodeStr(buf, 345, 155)+'/'+name; | ||
if (buf[345]) name = decodeStr(buf, 345, 155)+'/'+name | ||
var c = cksum(buf) | ||
var c = cksum(buf) | ||
//checksum is still initial value if header was null. | ||
if (c === 8*32) return null; | ||
//checksum is still initial value if header was null. | ||
if (c === 8*32) return null | ||
//valid checksum | ||
if (c !== decodeOct(buf, 148)) throw new Error('invalid header'); | ||
//valid checksum | ||
if (c !== decodeOct(buf, 148)) throw new Error('invalid header') | ||
return { | ||
name: name, | ||
mode: mode, | ||
uid: uid, | ||
gid: gid, | ||
size: size, | ||
mtime: new Date(1000 * mtime), | ||
type: toType(typeflag), | ||
linkname: linkname, | ||
uname: uname, | ||
gname: gname, | ||
devmajor: devmajor, | ||
devminor: devminor | ||
}; | ||
}; | ||
return { | ||
name: name, | ||
mode: mode, | ||
uid: uid, | ||
gid: gid, | ||
size: size, | ||
mtime: new Date(1000 * mtime), | ||
type: toType(typeflag), | ||
linkname: linkname, | ||
uname: uname, | ||
gname: gname, | ||
devmajor: devmajor, | ||
devminor: devminor | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
exports.extract = require('./extract'); | ||
exports.pack = require('./pack'); | ||
exports.extract = require('./extract') | ||
exports.pack = require('./pack') |
280
pack.js
@@ -1,194 +0,194 @@ | ||
var util = require('util'); | ||
var eos = require('end-of-stream'); | ||
var headers = require('./headers'); | ||
var util = require('util') | ||
var eos = require('end-of-stream') | ||
var headers = require('./headers') | ||
var Readable = require('readable-stream').Readable; | ||
var Writable = require('readable-stream').Writable; | ||
var PassThrough = require('readable-stream').PassThrough; | ||
var Readable = require('readable-stream').Readable | ||
var Writable = require('readable-stream').Writable | ||
var PassThrough = require('readable-stream').PassThrough | ||
var END_OF_TAR = new Buffer(1024); | ||
END_OF_TAR.fill(0); | ||
var END_OF_TAR = new Buffer(1024) | ||
END_OF_TAR.fill(0) | ||
var noop = function() {}; | ||
var noop = function() {} | ||
var overflow = function(self, size) { | ||
size &= 511; | ||
if (size) self.push(END_OF_TAR.slice(0, 512 - size)); | ||
}; | ||
size &= 511 | ||
if (size) self.push(END_OF_TAR.slice(0, 512 - size)) | ||
} | ||
var Sink = function(to) { | ||
Writable.call(this); | ||
this.written = 0; | ||
this._to = to; | ||
this._destroyed = false; | ||
}; | ||
Writable.call(this) | ||
this.written = 0 | ||
this._to = to | ||
this._destroyed = false | ||
} | ||
util.inherits(Sink, Writable); | ||
util.inherits(Sink, Writable) | ||
Sink.prototype._write = function(data, enc, cb) { | ||
this.written += data.length; | ||
if (this._to.push(data)) return cb(); | ||
this._to._drain = cb; | ||
}; | ||
this.written += data.length | ||
if (this._to.push(data)) return cb() | ||
this._to._drain = cb | ||
} | ||
Sink.prototype.destroy = function() { | ||
if (this._destroyed) return; | ||
this._destroyed = true; | ||
this.emit('close'); | ||
}; | ||
if (this._destroyed) return | ||
this._destroyed = true | ||
this.emit('close') | ||
} | ||
var Void = function() { | ||
Writable.call(this) | ||
this._destroyed = false; | ||
}; | ||
Writable.call(this) | ||
this._destroyed = false | ||
} | ||
util.inherits(Void, Writable); | ||
util.inherits(Void, Writable) | ||
Void.prototype._write = function(data, enc, cb) { | ||
cb(new Error('No body allowed for this entry')) | ||
}; | ||
cb(new Error('No body allowed for this entry')) | ||
} | ||
Void.prototype.destroy = function() { | ||
if (this._destroyed) return; | ||
this._destroyed = true; | ||
this.emit('close') | ||
if (this._destroyed) return | ||
this._destroyed = true | ||
this.emit('close') | ||
} | ||
var Pack = function(opts) { | ||
if (!(this instanceof Pack)) return new Pack(opts); | ||
Readable.call(this, opts); | ||
if (!(this instanceof Pack)) return new Pack(opts) | ||
Readable.call(this, opts) | ||
this._drain = noop; | ||
this._finalized = false; | ||
this._finalizing = false; | ||
this._destroyed = false; | ||
this._stream = null; | ||
}; | ||
this._drain = noop | ||
this._finalized = false | ||
this._finalizing = false | ||
this._destroyed = false | ||
this._stream = null | ||
} | ||
util.inherits(Pack, Readable); | ||
util.inherits(Pack, Readable) | ||
Pack.prototype.entry = function(header, buffer, callback) { | ||
if (this._stream) throw new Error('already piping an entry'); | ||
if (this._finalized || this._destroyed) return; | ||
if (this._stream) throw new Error('already piping an entry') | ||
if (this._finalized || this._destroyed) return | ||
if (typeof buffer === 'function') { | ||
callback = buffer; | ||
buffer = null; | ||
} | ||
if (typeof buffer === 'function') { | ||
callback = buffer | ||
buffer = null | ||
} | ||
if (!callback) callback = noop; | ||
if (!callback) callback = noop | ||
var self = this; | ||
var self = this | ||
if (!header.size) header.size = 0; | ||
if (!header.type) header.type = 'file'; | ||
if (!header.mode) header.mode = header.type === 'directory' ? 0755 : 0644; | ||
if (!header.uid) header.uid = 0; | ||
if (!header.gid) header.gid = 0; | ||
if (!header.mtime) header.mtime = new Date(); | ||
if (!header.size) header.size = 0 | ||
if (!header.type) header.type = 'file' | ||
if (!header.mode) header.mode = header.type === 'directory' ? 0755 : 0644 | ||
if (!header.uid) header.uid = 0 | ||
if (!header.gid) header.gid = 0 | ||
if (!header.mtime) header.mtime = new Date() | ||
if (typeof buffer === 'string') buffer = new Buffer(buffer); | ||
if (Buffer.isBuffer(buffer)) { | ||
header.size = buffer.length; | ||
this._encode(header); | ||
this.push(buffer); | ||
overflow(self, header.size); | ||
process.nextTick(callback); | ||
return new Void(); | ||
} | ||
if (header.type !== 'file' && header.type !== 'contigious-file') { | ||
this._encode(header); | ||
process.nextTick(callback); | ||
return new Void(); | ||
} | ||
if (typeof buffer === 'string') buffer = new Buffer(buffer) | ||
if (Buffer.isBuffer(buffer)) { | ||
header.size = buffer.length | ||
this._encode(header) | ||
this.push(buffer) | ||
overflow(self, header.size) | ||
process.nextTick(callback) | ||
return new Void() | ||
} | ||
if (header.type !== 'file' && header.type !== 'contigious-file') { | ||
this._encode(header) | ||
process.nextTick(callback) | ||
return new Void() | ||
} | ||
var sink = new Sink(this); | ||
var sink = new Sink(this) | ||
this._encode(header); | ||
this._stream = sink; | ||
this._encode(header) | ||
this._stream = sink | ||
eos(sink, function(err) { | ||
self._stream = null; | ||
eos(sink, function(err) { | ||
self._stream = null | ||
if (err) { // stream was closed | ||
self.destroy(); | ||
return callback(err); | ||
} | ||
if (err) { // stream was closed | ||
self.destroy() | ||
return callback(err) | ||
} | ||
if (sink.written !== header.size) { // corrupting tar | ||
self.destroy(); | ||
return callback(new Error('size mismatch')); | ||
} | ||
if (sink.written !== header.size) { // corrupting tar | ||
self.destroy() | ||
return callback(new Error('size mismatch')) | ||
} | ||
overflow(self, header.size); | ||
if (self._finalizing) self.finalize(); | ||
callback(); | ||
}); | ||
overflow(self, header.size) | ||
if (self._finalizing) self.finalize() | ||
callback() | ||
}) | ||
return sink; | ||
}; | ||
return sink | ||
} | ||
Pack.prototype.finalize = function() { | ||
if (this._stream) { | ||
this._finalizing = true; | ||
return; | ||
} | ||
if (this._stream) { | ||
this._finalizing = true | ||
return | ||
} | ||
if (this._finalized) return; | ||
this._finalized = true; | ||
this.push(END_OF_TAR); | ||
this.push(null); | ||
}; | ||
if (this._finalized) return | ||
this._finalized = true | ||
this.push(END_OF_TAR) | ||
this.push(null) | ||
} | ||
Pack.prototype.destroy = function(err) { | ||
if (this._destroyed) return; | ||
this._destroyed = true; | ||
if (this._destroyed) return | ||
this._destroyed = true | ||
if (err) this.emit('error', err); | ||
this.emit('close'); | ||
if (this._stream && this._stream.destroy) this._stream.destroy(); | ||
}; | ||
if (err) this.emit('error', err) | ||
this.emit('close') | ||
if (this._stream && this._stream.destroy) this._stream.destroy() | ||
} | ||
Pack.prototype._encode = function(header) { | ||
var buf = headers.encode(header); | ||
if (buf) this.push(buf); | ||
else this._encodePax(header); | ||
}; | ||
var buf = headers.encode(header) | ||
if (buf) this.push(buf) | ||
else this._encodePax(header) | ||
} | ||
Pack.prototype._encodePax = function(header) { | ||
var paxHeader = headers.encodePax({ | ||
name: header.name, | ||
linkname: header.linkname | ||
}); | ||
var paxHeader = headers.encodePax({ | ||
name: header.name, | ||
linkname: header.linkname | ||
}) | ||
var newHeader = { | ||
name: 'PaxHeader', | ||
mode: header.mode, | ||
uid: header.uid, | ||
gid: header.gid, | ||
size: paxHeader.length, | ||
mtime: header.mtime, | ||
type: 'pax-header', | ||
linkname: header.linkname && 'PaxHeader', | ||
uname: header.uname, | ||
gname: header.gname, | ||
devmajor: header.devmajor, | ||
devminor: header.devminor | ||
}; | ||
var newHeader = { | ||
name: 'PaxHeader', | ||
mode: header.mode, | ||
uid: header.uid, | ||
gid: header.gid, | ||
size: paxHeader.length, | ||
mtime: header.mtime, | ||
type: 'pax-header', | ||
linkname: header.linkname && 'PaxHeader', | ||
uname: header.uname, | ||
gname: header.gname, | ||
devmajor: header.devmajor, | ||
devminor: header.devminor | ||
} | ||
this.push(headers.encode(newHeader)); | ||
this.push(paxHeader); | ||
overflow(this, paxHeader.length); | ||
this.push(headers.encode(newHeader)) | ||
this.push(paxHeader) | ||
overflow(this, paxHeader.length) | ||
newHeader.size = header.size; | ||
newHeader.type = header.type; | ||
this.push(headers.encode(newHeader)); | ||
}; | ||
newHeader.size = header.size | ||
newHeader.type = header.type | ||
this.push(headers.encode(newHeader)) | ||
} | ||
Pack.prototype._read = function(n) { | ||
var drain = this._drain; | ||
this._drain = noop; | ||
drain(); | ||
}; | ||
var drain = this._drain | ||
this._drain = noop | ||
drain() | ||
} | ||
module.exports = Pack; | ||
module.exports = Pack |
{ | ||
"name": "tar-stream", | ||
"version": "0.4.6", | ||
"version": "0.4.7", | ||
"description": "tar-stream is a streaming tar parser and generator and nothing else. It is streams2 and operates purely using streams which means you can easily extract/parse tarballs without ever hitting the file system.", | ||
@@ -5,0 +5,0 @@ "repository": { |
100
README.md
@@ -5,3 +5,5 @@ # tar-stream | ||
npm install tar-stream | ||
``` | ||
npm install tar-stream | ||
``` | ||
@@ -26,18 +28,18 @@ [![build status](https://secure.travis-ci.org/mafintosh/tar-stream.png)](http://travis-ci.org/mafintosh/tar-stream) | ||
``` js | ||
var tar = require('tar-stream'); | ||
var pack = tar.pack(); // p is a streams2 stream | ||
var tar = require('tar-stream') | ||
var pack = tar.pack() // p is a streams2 stream | ||
// add a file called my-test.txt with the content "Hello World!" | ||
pack.entry({ name: 'my-test.txt' }, 'Hello World!'); | ||
pack.entry({ name: 'my-test.txt' }, 'Hello World!') | ||
// add a file called my-stream-test.txt from a stream | ||
var entry = pack.entry({ name: 'my-stream-test.txt' }, function(err) { | ||
// the stream was added | ||
// no more entries | ||
pack.finalize(); | ||
}); | ||
myStream.pipe(entry); | ||
// the stream was added | ||
// no more entries | ||
pack.finalize() | ||
}) | ||
myStream.pipe(entry) | ||
// pipe the pack stream somewhere | ||
pack.pipe(process.stdout); | ||
pack.pipe(process.stdout) | ||
``` | ||
@@ -50,20 +52,20 @@ | ||
``` js | ||
var extract = tar.extract(); | ||
var extract = tar.extract() | ||
extract.on('entry', function(header, stream, callback) { | ||
// header is the tar header | ||
// stream is the content body (might be an empty stream) | ||
// call next when you are done with this entry | ||
// header is the tar header | ||
// stream is the content body (might be an empty stream) | ||
// call next when you are done with this entry | ||
stream.resume(); // just auto drain the stream | ||
stream.on('end', function() { | ||
callback(); // ready for next entry | ||
}); | ||
}); | ||
stream.resume() // just auto drain the stream | ||
stream.on('end', function() { | ||
callback() // ready for next entry | ||
}) | ||
}) | ||
extract.on('finish', function() { | ||
// all entries read | ||
}); | ||
// all entries read | ||
}) | ||
pack.pipe(extract); | ||
pack.pipe(extract) | ||
``` | ||
@@ -78,16 +80,16 @@ | ||
{ | ||
name: 'path/to/this/entry.txt', | ||
size: 1314, // entry size. defaults to 0 | ||
mode: 0644, // entry mode. defaults to to 0755 for dirs and 0644 otherwise | ||
mtime: new Date(), // last modified date for entry. defaults to now. | ||
type: 'file', // type of entry. defaults to file. can be: | ||
// file | link | symlink | directory | block-device | ||
// character-device | fifo | contigious-file | ||
linkname: 'path', // linked file name | ||
uid: 0, // uid of entry owner. defaults to 0 | ||
gid: 0, // gid of entry owner. defaults to 0 | ||
uname: 'maf', // uname of entry owner. defaults to null | ||
gname: 'staff', // gname of entry owner. defaults to null | ||
devmajor: 0, // device major version. defaults to 0 | ||
devminor: 0 // device minor version. defaults to 0 | ||
name: 'path/to/this/entry.txt', | ||
size: 1314, // entry size. defaults to 0 | ||
mode: 0644, // entry mode. defaults to to 0755 for dirs and 0644 otherwise | ||
mtime: new Date(), // last modified date for entry. defaults to now. | ||
type: 'file', // type of entry. defaults to file. can be: | ||
// file | link | symlink | directory | block-device | ||
// character-device | fifo | contigious-file | ||
linkname: 'path', // linked file name | ||
uid: 0, // uid of entry owner. defaults to 0 | ||
gid: 0, // gid of entry owner. defaults to 0 | ||
uname: 'maf', // uname of entry owner. defaults to null | ||
gname: 'staff', // gname of entry owner. defaults to null | ||
devmajor: 0, // device major version. defaults to 0 | ||
devminor: 0 // device minor version. defaults to 0 | ||
} | ||
@@ -101,23 +103,23 @@ ``` | ||
``` js | ||
var extract = tar.extract(); | ||
var pack = tar.pack(); | ||
var path = require('path'); | ||
var extract = tar.extract() | ||
var pack = tar.pack() | ||
var path = require('path') | ||
extract.on('entry', function(header, stream, callback) { | ||
// let's prefix all names with 'tmp' | ||
header.name = path.join('tmp', header.name); | ||
// write the new entry to the pack stream | ||
stream.pipe(pack.entry(header, callback)); | ||
}); | ||
// let's prefix all names with 'tmp' | ||
header.name = path.join('tmp', header.name) | ||
// write the new entry to the pack stream | ||
stream.pipe(pack.entry(header, callback)) | ||
}) | ||
extract.on('finish', function() { | ||
// all entries done - lets finalize it | ||
pack.finalize(); | ||
}); | ||
// all entries done - lets finalize it | ||
pack.finalize() | ||
}) | ||
// pipe the old tarball to the extractor | ||
oldTarball.pipe(extract); | ||
oldTarball.pipe(extract) | ||
// pipe the new tarball the another stream | ||
pack.pipe(newTarball); | ||
pack.pipe(newTarball) | ||
``` | ||
@@ -124,0 +126,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
134355
129