diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index c1842fdb4640cd..a035a8b5a0a609 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -539,6 +539,7 @@ async function readFileHandle(filehandle, options) { throw new ERR_FS_FILE_TOO_LARGE(size); let totalRead = 0; + const noSize = size === 0; let buffer = Buffer.allocUnsafeSlow(length); let result = ''; let offset = 0; @@ -561,7 +562,7 @@ async function readFileHandle(filehandle, options) { if (bytesRead === 0 || totalRead === size || - (bytesRead !== buffer.length && !chunkedRead)) { + (bytesRead !== buffer.length && !chunkedRead && !noSize)) { const singleRead = bytesRead === totalRead; const bytesToCheck = chunkedRead ? totalRead : bytesRead; @@ -571,7 +572,7 @@ async function readFileHandle(filehandle, options) { } if (!encoding) { - if (size === 0 && !singleRead) { + if (noSize && !singleRead) { ArrayPrototypePush(buffers, buffer); return Buffer.concat(buffers, totalRead); } @@ -584,15 +585,17 @@ async function readFileHandle(filehandle, options) { result += decoder.end(buffer); return result; } - + const readBuffer = bytesRead !== buffer.length ? + buffer.subarray(0, bytesRead) : + buffer; if (encoding) { - result += decoder.write(buffer); + result += decoder.write(readBuffer); } else if (size !== 0) { offset = totalRead; } else { buffers ??= []; // Unknown file size requires chunks. - ArrayPrototypePush(buffers, buffer); + ArrayPrototypePush(buffers, readBuffer); buffer = Buffer.allocUnsafeSlow(kReadFileUnknownBufferLength); } } diff --git a/test/parallel/test-fs-readfile-eof.js b/test/parallel/test-fs-readfile-eof.js new file mode 100644 index 00000000000000..94354b915b8dd5 --- /dev/null +++ b/test/parallel/test-fs-readfile-eof.js @@ -0,0 +1,46 @@ +'use strict'; +const common = require('../common'); + +if (common.isWindows || common.isAIX || common.isIBMi) + common.skip(`No /dev/stdin on ${process.platform}.`); + +const assert = require('assert'); +const fs = require('fs/promises'); +const childType = ['child-encoding', 'child-non-encoding']; + +if (process.argv[2] === childType[0]) { + fs.readFile('/dev/stdin', 'utf8').then((data) => { + process.stdout.write(data); + }); + return; +} else if (process.argv[2] === childType[1]) { + fs.readFile('/dev/stdin').then((data) => { + process.stdout.write(data); + }); + return; +} + +const data1 = 'Hello'; +const data2 = 'World'; +const expected = `${data1}\n${data2}\n`; + +const exec = require('child_process').exec; +const f = JSON.stringify(__filename); +const node = JSON.stringify(process.execPath); + +function test(child) { + const cmd = `(echo ${data1}; sleep 0.5; echo ${data2}) | ${node} ${f} ${child}`; + exec(cmd, common.mustSucceed((stdout, stderr) => { + assert.strictEqual( + stdout, + expected, + `expected to read(${child === childType[0] ? 'with' : 'without'} encoding): '${expected}' but got: '${stdout}'`); + assert.strictEqual( + stderr, + '', + `expected not to read anything from stderr but got: '${stderr}'`); + })); +} + +test(childType[0]); +test(childType[1]);