Comparing version 0.1.4 to 0.1.5
@@ -662,2 +662,3 @@ var inherits = require('util').inherits, | ||
this.outpaused = false; | ||
this._decoder = undefined; | ||
return ret; | ||
@@ -664,0 +665,0 @@ }; |
@@ -742,3 +742,6 @@ var net = require('net'), | ||
if (self._sock.writable) { | ||
var size = 1 + 4, buf, i, len = Math.min(nprompts, nanswers), p = 0; | ||
var size = 1 + 4, | ||
buf, i, | ||
len = (nprompts < nanswers ? nprompts : nanswers), | ||
p = 0; | ||
for (i = 0; i < len; ++i) { | ||
@@ -1009,3 +1012,3 @@ size += 4; | ||
} | ||
if (!this._privateKey.public) { | ||
if (this._privateKey && !this._privateKey.public) { | ||
// we get here if we didn't load a PuTTY key file | ||
@@ -1012,0 +1015,0 @@ if (this._publicKey) { |
@@ -47,2 +47,10 @@ var EventEmitter = require('events').EventEmitter, | ||
SFTP.prototype.createReadStream = function(path, options) { | ||
return new ReadStream(this, path, options); | ||
}; | ||
SFTP.prototype.createWriteStream = function(path, options) { | ||
return new WriteStream(this, path, options); | ||
}; | ||
SFTP.prototype.open = function(filename, mode, attrs, cb) { | ||
@@ -134,20 +142,9 @@ | ||
var isStreaming = false; | ||
if (typeof length === 'function') { | ||
isStreaming = true; | ||
cb = length; | ||
length = buffer; | ||
position = offset; | ||
buffer = undefined; | ||
offset = undefined; | ||
} | ||
if (!Buffer.isBuffer(buffer)) | ||
throw new Error('buffer is not a Buffer'); | ||
else if (offset >= buffer.length) | ||
throw new Error('offset is out of bounds'); | ||
else if (offset + length > buffer.length) | ||
throw new Error('length extends beyond buffer'); | ||
if (!isStreaming) { | ||
if (!Buffer.isBuffer(buffer)) | ||
throw new Error('buffer is not a Buffer'); | ||
else if (offset >= buffer.length) | ||
throw new Error('offset is out of bounds'); | ||
else if (offset + length > buffer.length) | ||
throw new Error('length extends beyond buffer'); | ||
} | ||
if (position === null) | ||
@@ -174,16 +171,7 @@ throw new Error('null position currently unsupported'); | ||
if (isStreaming) { | ||
var stream = new ReadStream(this); | ||
return this._send(buf, function(err) { | ||
if (err) | ||
return cb(err); | ||
cb(undefined, stream); | ||
}, stream); | ||
} else { | ||
return this._send(buf, function(err, bytesRead, data) { | ||
if (err) | ||
return cb(err); | ||
cb(undefined, bytesRead, data); | ||
}, undefined, buffer.slice(offset, offset + length)); | ||
} | ||
return this._send(buf, function(err, bytesRead, data) { | ||
if (err) | ||
return cb(err); | ||
cb(undefined, bytesRead || 0, data); | ||
}, buffer.slice(offset, offset + length)); | ||
}; | ||
@@ -506,3 +494,3 @@ | ||
SFTP.prototype._send = function(data, cb, stream, buffer) { | ||
SFTP.prototype._send = function(data, cb, buffer) { | ||
var err; | ||
@@ -543,10 +531,5 @@ if (this._reqid === MAX_REQID && !this._reqidmaxed) { | ||
cb = EMPTY_CALLBACK; | ||
else if (stream) { | ||
// temporary callback hack used to ensure all is well before sending | ||
// for streaming functions (currently read() and write()) | ||
cb(); | ||
cb = undefined; | ||
} | ||
this._requests[this._reqid] = { cb: cb, stream: stream, buffer: buffer }; | ||
this._requests[this._reqid] = { cb: cb, buffer: buffer }; | ||
/* | ||
@@ -577,3 +560,3 @@ uint32 length | ||
SFTP.prototype._parse = function(chunk) { | ||
var data = this._data, chunklen = chunk.length, cb, stream; | ||
var data = this._data, chunklen = chunk.length, cb; | ||
chunk.i = 0; | ||
@@ -628,12 +611,8 @@ while (chunk.i < chunklen) { | ||
cb = this._requests[data.reqid].cb; | ||
stream = this._requests[data.reqid].stream; | ||
delete this._requests[data.reqid]; | ||
if (data.statusCode === STATUS_CODE.OK) | ||
cb(); | ||
else if (data.statusCode === STATUS_CODE.EOF) { | ||
if (stream) | ||
stream.emit('end'); | ||
else | ||
cb(undefined, false); | ||
} else { | ||
else if (data.statusCode === STATUS_CODE.EOF) | ||
cb(undefined, false); | ||
else { | ||
var err = new Error(data.errMsg); | ||
@@ -671,16 +650,8 @@ err.type = STATUS_CODE[data.statusCode]; | ||
} else if (data.subtype === 'data') { | ||
if (this._requests[data.reqid].stream) { | ||
if ((data.done = this._readString(chunk, undefined, true)) !== false) { | ||
data.type = 'discard'; | ||
this._requests[data.reqid].stream.emit('end'); | ||
delete this._requests[data.reqid]; | ||
} | ||
} else { | ||
if ((data.data = this._readString(chunk)) !== false) { | ||
data.type = 'discard'; | ||
cb = this._requests[data.reqid].cb; | ||
var nbytes = this._requests[data.reqid].nbytes; | ||
delete this._requests[data.reqid]; | ||
cb(undefined, nbytes, data.data); | ||
} | ||
if ((data.data = this._readString(chunk)) !== false) { | ||
data.type = 'discard'; | ||
cb = this._requests[data.reqid].cb; | ||
var nbytes = this._requests[data.reqid].nbytes; | ||
delete this._requests[data.reqid]; | ||
cb(undefined, nbytes, data.data); | ||
} | ||
@@ -798,3 +769,3 @@ } | ||
SFTP.prototype._readString = function(chunk, encoding, isDataStream) { | ||
SFTP.prototype._readString = function(chunk, encoding) { | ||
if (this._count < 4 && this._string === undefined) { | ||
@@ -807,19 +778,17 @@ this._value <<= 8; | ||
if (this._value === 0) { | ||
if (isDataStream) | ||
return true; | ||
else if (!encoding) | ||
if (!encoding) { | ||
if (Buffer.isBuffer(this._requests[this._data.reqid].buffer)) | ||
this._requests[this._data.reqid].nbytes = 0; | ||
return new Buffer(0); | ||
else | ||
} else | ||
return ''; | ||
} | ||
if (!isDataStream) { | ||
if (!encoding) { | ||
if (Buffer.isBuffer(this._requests[this._data.reqid].buffer)) { | ||
this._string = this._requests[this._data.reqid].buffer; | ||
this._requests[this._data.reqid].nbytes = this._value; | ||
} else | ||
this._string = new Buffer(this._value); | ||
if (!encoding) { | ||
if (Buffer.isBuffer(this._requests[this._data.reqid].buffer)) { | ||
this._string = this._requests[this._data.reqid].buffer; | ||
this._requests[this._data.reqid].nbytes = this._value; | ||
} else | ||
this._string = ''; | ||
} | ||
this._string = new Buffer(this._value); | ||
} else | ||
this._string = ''; | ||
} | ||
@@ -830,7 +799,3 @@ } else if (this._string !== undefined) { | ||
var str; | ||
if (isDataStream) { | ||
this._requests[this._data.reqid] | ||
.stream.emit('data', chunk.slice(chunk.i, chunk.i + this._value)); | ||
str = true; | ||
} else if (!encoding) { | ||
if (!encoding) { | ||
chunk.copy(this._string, this._count, chunk.i, chunk.i + this._value); | ||
@@ -852,6 +817,3 @@ str = this._string; | ||
if (diff > 0) { | ||
if (isDataStream) { | ||
this._requests[this._data.reqid] | ||
.stream.emit('data', chunk.slice(chunk.i)); | ||
} else if (!encoding) { | ||
if (!encoding) { | ||
chunk.copy(this._string, this._count, chunk.i); | ||
@@ -1041,44 +1003,210 @@ this._count += diff; | ||
function ReadStream(sftp) { | ||
var kMinPoolSpace = 128, | ||
kPoolSize = 40 * 1024, | ||
pool; | ||
function allocNewPool() { | ||
pool = new Buffer(kPoolSize); | ||
pool.used = 0; | ||
} | ||
function ReadStream(sftp, path, opts) { | ||
var self = this; | ||
this._sftp = sftp; | ||
this._buffer = []; | ||
this.path = path; | ||
if (typeof this.path !== 'string') | ||
throw new Error('path must be a string'); | ||
opts = opts || {}; | ||
this.readable = true; | ||
this._paused = false; | ||
this._decoder = undefined; | ||
this.paused = false; | ||
this.reading = false; | ||
this.flags = opts.flags || 'r'; | ||
this.mode = opts.mode || 438; /*=0666*/ | ||
this.bufferSize = opts.bufferSize || (64 * 1024); | ||
this.end = undefined; | ||
this.pos = 0; | ||
this.handle = undefined; | ||
this.buffer = undefined; | ||
if (opts.encoding) | ||
this._decoder = this.setEncoding(opts.encoding); | ||
else | ||
this._decoder = undefined; | ||
if (opts.start !== undefined) { | ||
if (typeof opts.start !== 'number') | ||
throw TypeError('start must be a Number'); | ||
if (opts.end === undefined) | ||
this.end = Infinity; | ||
else if (typeof opts.end !== 'number') | ||
throw TypeError('end must be a Number'); | ||
else | ||
this.end = opts.end; | ||
if (opts.start > opts.end) | ||
throw new Error('start must be <= end'); | ||
else if (opts.start < 0) | ||
throw new Error('start must be >= zero'); | ||
this.pos = opts.start; | ||
this.end = opts.end; | ||
} | ||
sftp.open(this.path, this.flags, this.mode, function(err, handle) { | ||
if (err) { | ||
self.emit('error', err); | ||
self.readable = false; | ||
return; | ||
} | ||
self.handle = handle; | ||
self.emit('open', handle); | ||
self._read(); | ||
}); | ||
sftp._stream._channel._conn._sock.once('end', function() { | ||
self.readable = false; | ||
}); | ||
sftp._stream._channel._conn._sock.once('close', function() { | ||
self.readable = false; | ||
}); | ||
} | ||
inherits(ReadStream, Stream); | ||
ReadStream.prototype._emit = ReadStream.prototype.emit; | ||
ReadStream.prototype.emit = function(ev, arg1) { | ||
if (this._paused) | ||
this._buffer.push([ev, arg1]); | ||
else { | ||
if (ev === 'data' && this._decoder) | ||
this._emit(ev, this._decoder.write(arg1)); | ||
else | ||
this._emit(ev, arg1); | ||
ReadStream.prototype._read = function() { | ||
var self = this; | ||
if (!this.readable || this.paused || this.reading) return; | ||
this.reading = true; | ||
if (!pool || pool.length - pool.used < kMinPoolSpace) { | ||
// discard the old pool. Can't add to the free list because | ||
// users might have references to slices on it. | ||
pool = undefined; | ||
allocNewPool(); | ||
} | ||
// Grab another reference to the pool in the case that while we're in the | ||
// thread pool another read() finishes up the pool, and allocates a new | ||
// one. | ||
var thisPool = pool, | ||
toRead, | ||
bufSize = ~~this.bufferSize, | ||
diff = pool.length - pool.used, | ||
start = pool.used; | ||
if (diff < bufSize) | ||
toRead = diff; | ||
else | ||
toRead = bufSize; | ||
if (this.pos !== undefined && this.end !== undefined) { | ||
diff = this.end - this.pos + 1; | ||
if (diff < toRead) | ||
toRead = diff; | ||
} | ||
function afterRead(err, bytesRead) { | ||
self.reading = false; | ||
if (err) { | ||
self.emit('error', err); | ||
self.readable = false; | ||
return; | ||
} | ||
if (bytesRead === 0) { | ||
self.emit('end'); | ||
self.destroy(); | ||
return; | ||
} | ||
var b = thisPool.slice(start, start + bytesRead); | ||
// Possible optimizition here? | ||
// Reclaim some bytes if bytesRead < toRead? | ||
// Would need to ensure that pool === thisPool. | ||
// do not emit events if the stream is paused | ||
if (self.paused) { | ||
self.buffer = b; | ||
return; | ||
} | ||
// do not emit events anymore after we declared the stream unreadable | ||
if (!self.readable) | ||
return; | ||
self._emitData(b); | ||
self._read(); | ||
} | ||
this._sftp.read(this.handle, pool, pool.used, toRead, this.pos, afterRead); | ||
this.pos += toRead; | ||
pool.used += toRead; | ||
}; | ||
ReadStream.prototype._emitData = function(d) { | ||
if (this._decoder) { | ||
var string = this._decoder.write(d); | ||
if (string.length) | ||
this.emit('data', string); | ||
} else | ||
this.emit('data', d); | ||
}; | ||
ReadStream.prototype.pause = function() { | ||
this._sftp._stream.pause(); | ||
this._paused = true; | ||
this.paused = true; | ||
}; | ||
ReadStream.prototype.resume = function() { | ||
if (this._buffer.length) { | ||
for (var i = 0, len = this._buffer.length; i < len; ++i) { | ||
if (this._buffer[i][0] === 'data' && this._decoder) | ||
this._emit(this._buffer[i][0], this._decoder.write(this._buffer[i][1])); | ||
else | ||
this._emit(this._buffer[i][0], this._buffer[i][1]); | ||
} | ||
this._buffer = []; | ||
this.paused = false; | ||
if (this.buffer) { | ||
var buffer = this.buffer; | ||
this.buffer = undefined; | ||
this._emitData(buffer); | ||
} | ||
this._paused = false; | ||
this._sftp._stream.resume(); | ||
// hasn't opened yet. | ||
if (this.handle === undefined) | ||
return; | ||
this._read(); | ||
}; | ||
ReadStream.prototype.destroy = function() { | ||
var self = this; | ||
this._decoder = undefined; | ||
if (!this.readable) { | ||
cb && process.nextTick(cb); | ||
return; | ||
} | ||
this.readable = false; | ||
this._buffer = []; | ||
this._decoder = undefined; | ||
function close() { | ||
self._sftp.close(self.handle, function(err) { | ||
if (err) { | ||
cb && cb(err); | ||
self.emit('error', err); | ||
return; | ||
} | ||
cb && cb(); | ||
self.emit('close'); | ||
}); | ||
} | ||
if (this.handle === undefined) | ||
this.once('open', close); | ||
else | ||
close(); | ||
}; | ||
ReadStream.prototype.setEncoding = function(encoding) { | ||
@@ -1088,1 +1216,169 @@ var StringDecoder = require('string_decoder').StringDecoder; // lazy load | ||
}; | ||
function WriteStream(sftp, path, opts) { | ||
var self = this; | ||
this._sftp = sftp; | ||
this.path = path; | ||
if (typeof this.path !== 'string') | ||
throw new TypeError('path must be a String'); | ||
opts = opts || {}; | ||
this.handle = undefined; | ||
this.writable = true; | ||
this.flags = opts.flags || 'w'; | ||
this.mode = opts.mode || 438; /*=0666*/ | ||
this.bytesWritten = 0; | ||
this.pos = 0; | ||
if (opts.start !== undefined) { | ||
if (typeof opts.start !== 'number') | ||
throw TypeError('start must be a Number'); | ||
if (opts.start < 0) | ||
throw new Error('start must be >= zero'); | ||
this.pos = opts.start; | ||
} | ||
this.drainable = false; | ||
this.busy = false; | ||
this._queue = [[this._sftp.open, this.path, this.flags, this.mode, undefined]]; | ||
this.flush(); | ||
sftp._stream._channel._conn._sock.once('end', function() { | ||
self.writable = false; | ||
}); | ||
sftp._stream._channel._conn._sock.once('close', function() { | ||
self.writable = false; | ||
}); | ||
} | ||
inherits(WriteStream, Stream); | ||
WriteStream.prototype.flush = function() { | ||
if (this.busy) | ||
return; | ||
var self = this; | ||
var args = this._queue.shift(); | ||
if (!args) { | ||
if (this.drainable) | ||
this.emit('drain'); | ||
return; | ||
} | ||
this.busy = true; | ||
var method = args.shift(), | ||
cb = args.pop(); | ||
args.push(function(err, arg1) { | ||
self.busy = false; | ||
if (err) { | ||
self.writable = false; | ||
cb && cb(err); | ||
self.emit('error', err); | ||
return; | ||
} | ||
if (method === self._sftp.write) { | ||
self.bytesWritten += arg1; | ||
cb && cb(undefined, arg1); | ||
} else if (method === self._sftp.open) { | ||
// save reference for file handle | ||
self.handle = arg1; | ||
self.emit('open', self.handle); | ||
} else if (method === self._sftp.close) { | ||
// stop flushing after close | ||
cb && cb(); | ||
self.emit('close'); | ||
return; | ||
} | ||
self.flush(); | ||
}); | ||
// Inject the file pointer | ||
if (method !== this._sftp.open) | ||
args.unshift(this.handle); | ||
method.apply(this._sftp, args); | ||
}; | ||
WriteStream.prototype.write = function(data, encoding, cb) { | ||
if (!this.writable) { | ||
this.emit('error', new Error('stream not writable')); | ||
return false; | ||
} | ||
if (typeof encoding === 'function') { | ||
cb = encoding; | ||
encoding = undefined; | ||
} | ||
if (typeof cb !== 'function') | ||
cb = undefined; | ||
this.drainable = true; | ||
if (!Buffer.isBuffer(data)) { | ||
if (typeof encoding !== 'string') | ||
encoding = 'utf8'; | ||
data = new Buffer('' + data, encoding); | ||
} | ||
this._queue.push([this._sftp.write, data, 0, data.length, this.pos, cb]); | ||
this.pos += data.length; | ||
this.flush(); | ||
return false; | ||
}; | ||
WriteStream.prototype.end = function(data, encoding, cb) { | ||
if (typeof data === 'function') | ||
cb = data; | ||
else if (typeof encoding === 'function') { | ||
cb = encoding; | ||
this.write(data); | ||
} else if (data) | ||
this.write(data, encoding); | ||
this.writable = false; | ||
this._queue.push([this._sftp.close, cb]); | ||
this.flush(); | ||
}; | ||
WriteStream.prototype.destroy = function(cb) { | ||
var self = this; | ||
if (!this.writable) { | ||
cb && process.nextTick(cb); | ||
return; | ||
} | ||
this.writable = false; | ||
function close() { | ||
self._sftp.close(self.handle, function(err) { | ||
if (err) { | ||
cb && cb(err); | ||
self.emit('error', err); | ||
return; | ||
} | ||
cb && cb(); | ||
self.emit('close'); | ||
}); | ||
} | ||
if (this.handle === null) | ||
this.once('open', close); | ||
else | ||
close(); | ||
}; | ||
WriteStream.prototype.destroySoon = WriteStream.prototype.end; |
{ "name": "ssh2", | ||
"version": "0.1.4", | ||
"version": "0.1.5", | ||
"author": "Brian White <mscdex@mscdex.net>", | ||
@@ -4,0 +4,0 @@ "description": "An SSH2 client module written in pure JavaScript for node.js", |
@@ -446,2 +446,30 @@ | ||
* **createReadStream**(< _string_ >path[, < _object_ >options]) - _ReadStream_ - Returns a new readable stream for `path`. `options` has the following defaults: | ||
```javascript | ||
{ flags: 'r', | ||
encoding: null, | ||
mode: 0666, | ||
bufferSize: 64 * 1024 | ||
} | ||
``` | ||
`options` can include 'start' and 'end' values to read a range of bytes from the file instead of the entire file. Both 'start' and 'end' are inclusive and start at 0. The encoding can be 'utf8', 'ascii', or 'base64'. | ||
An example to read the last 10 bytes of a file which is 100 bytes long: | ||
```javascript | ||
fs.createReadStream('sample.txt', {start: 90, end: 99}); | ||
``` | ||
* **createWriteStream**(< _string_ >path[, < _object_ >options]) - _WriteStream_ - Returns a new writable stream for `path`. `options` has the following defaults: | ||
```javascript | ||
{ flags: 'w', | ||
encoding: null, | ||
mode: 0666 } | ||
``` | ||
`options` may also include a 'start' option to allow writing data at some position past the beginning of the file. Modifying a file rather than replacing it may require a flags mode of 'r+' rather than the default mode 'w'. | ||
* **open**(< _string_ >filename, < _string_ >mode, [< _ATTRS_ >attributes, ]< _function_ >callback) - _(void)_ - Opens a file `filename` for `mode` with optional `attributes`. `mode` is any of the modes supported by fs.open (except sync mode). `callback` has 2 parameters: < _Error_ >err, < _Buffer_ >handle. | ||
@@ -448,0 +476,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
190254
4788
527