Skip to content

Commit b01bd80

Browse files
addaleaxMylesBorins
authored andcommitted
fs: fix createReadStream(…,{end: n}) for non-seekable fds
82bdf8f fixed an issue by silently modifying the `start` option for the case when only `end` is passed, in order to perform reads from a specified range in the file. However, that approach does not work for non-seekable files, since a numeric `start` option means that positioned reads will be used to read data from the file. This patch fixes that, and instead ends reading after a specified size by adjusting the read buffer size. This way we avoid re-introducing the bug that 82bdf8f fixed, and align behaviour with the native file stream mechanism introduced in #18936 as well. PR-URL: #19329Fixes: #19240 Refs: #18121 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Chen Gang <[email protected]>
1 parent 16ab3b5 commit b01bd80

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

‎lib/fs.js‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,8 +2011,7 @@ function ReadStream(path, options){
20112011
this.flags=options.flags===undefined ? 'r' : options.flags;
20122012
this.mode=options.mode===undefined ? 0o666 : options.mode;
20132013

2014-
this.start=typeofthis.fd!=='number'&&options.start===undefined ?
2015-
0 : options.start;
2014+
this.start=options.start;
20162015
this.end=options.end;
20172016
this.autoClose=options.autoClose===undefined ? true : options.autoClose;
20182017
this.pos=undefined;
@@ -2046,6 +2045,12 @@ function ReadStream(path, options){
20462045
this.pos=this.start;
20472046
}
20482047

2048+
// Backwards compatibility: Make sure `end` is a number regardless of `start`.
2049+
// TODO(addaleax): Make the above typecheck not depend on `start` instead.
2050+
// (That is a semver-major change).
2051+
if(typeofthis.end!=='number')
2052+
this.end=Infinity;
2053+
20492054
if(typeofthis.fd!=='number')
20502055
this.open();
20512056

@@ -2100,6 +2105,8 @@ ReadStream.prototype._read = function(n){
21002105

21012106
if(this.pos!==undefined)
21022107
toRead=Math.min(this.end-this.pos+1,toRead);
2108+
else
2109+
toRead=Math.min(this.end-this.bytesRead+1,toRead);
21032110

21042111
// already read everything we were supposed to read!
21052112
// treat as EOF.

‎test/parallel/test-fs-read-stream.js‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
'use strict';
2323
constcommon=require('../common');
24+
consttmpdir=require('../common/tmpdir');
2425

26+
constchild_process=require('child_process');
2527
constassert=require('assert');
2628
constfs=require('fs');
2729
constfixtures=require('../common/fixtures');
@@ -178,6 +180,31 @@ common.expectsError(
178180
}));
179181
}
180182

183+
if(!common.isWindows){
184+
// Verify that end works when start is not specified, and we do not try to
185+
// use positioned reads. This makes sure that this keeps working for
186+
// non-seekable file descriptors.
187+
tmpdir.refresh();
188+
constfilename=`${tmpdir.path}/foo.pipe`;
189+
constmkfifoResult=child_process.spawnSync('mkfifo',[filename]);
190+
if(!mkfifoResult.error){
191+
child_process.exec(`echo "xyz foobar" > '${filename}'`);
192+
conststream=newfs.createReadStream(filename,{end: 1});
193+
stream.data='';
194+
195+
stream.on('data',function(chunk){
196+
stream.data+=chunk;
197+
});
198+
199+
stream.on('end',common.mustCall(function(){
200+
assert.strictEqual('xy',stream.data);
201+
fs.unlinkSync(filename);
202+
}));
203+
}else{
204+
common.printSkipMessage('mkfifo not available');
205+
}
206+
}
207+
181208
{
182209
// pause and then resume immediately.
183210
constpauseRes=fs.createReadStream(rangeFile);

0 commit comments

Comments
(0)