diff --git a/lib/fs.js b/lib/fs.js index f890e431d2a9f5..352d2fd1ffd12d 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1967,8 +1967,7 @@ function ReadStream(path, options) { this.flags = options.flags === undefined ? 'r' : options.flags; this.mode = options.mode === undefined ? 0o666 : options.mode; - this.start = typeof this.fd !== 'number' && options.start === undefined ? - 0 : options.start; + this.start = options.start; this.end = options.end; this.autoClose = options.autoClose === undefined ? true : options.autoClose; this.pos = undefined; @@ -1993,6 +1992,12 @@ function ReadStream(path, options) { this.pos = this.start; } + // Backwards compatibility: Make sure `end` is a number regardless of `start`. + // TODO(addaleax): Make the above typecheck not depend on `start` instead. + // (That is a semver-major change). + if (typeof this.end !== 'number') + this.end = Infinity; + if (typeof this.fd !== 'number') this.open(); @@ -2047,6 +2052,8 @@ ReadStream.prototype._read = function(n) { if (this.pos !== undefined) toRead = Math.min(this.end - this.pos + 1, toRead); + else + toRead = Math.min(this.end - this.bytesRead + 1, toRead); // already read everything we were supposed to read! // treat as EOF. diff --git a/test/parallel/test-fs-read-stream.js b/test/parallel/test-fs-read-stream.js index 7fc7a0d56bce37..75b2fe3d14b880 100644 --- a/test/parallel/test-fs-read-stream.js +++ b/test/parallel/test-fs-read-stream.js @@ -21,7 +21,9 @@ 'use strict'; const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const child_process = require('child_process'); const assert = require('assert'); const fs = require('fs'); const fixtures = require('../common/fixtures'); @@ -178,6 +180,31 @@ common.expectsError( })); } +{ + // Verify that end works when start is not specified, and we do not try to + // use positioned reads. This makes sure that this keeps working for + // non-seekable file descriptors. + tmpdir.refresh(); + const filename = `${tmpdir.path}/foo.pipe`; + const mkfifoResult = child_process.spawnSync('mkfifo', [filename]); + if (!mkfifoResult.error) { + child_process.exec(`echo "xyz foobar" > '${filename}'`); + const stream = new fs.createReadStream(filename, { end: 1 }); + stream.data = ''; + + stream.on('data', function(chunk) { + stream.data += chunk; + }); + + stream.on('end', common.mustCall(function() { + assert.strictEqual('xy', stream.data); + fs.unlinkSync(filename); + })); + } else { + common.printSkipMessage('mkfifo not available'); + } +} + { // pause and then resume immediately. const pauseRes = fs.createReadStream(rangeFile);