Skip to content

Commit

Permalink
fs: keep fs.promises.readFile read until EOF is reached
Browse files Browse the repository at this point in the history
PR-URL: #52178
Fixes: #52155
Reviewed-By: Chengzhong Wu <[email protected]>
  • Loading branch information
kylo5aby authored and marco-ippolito committed Jun 17, 2024
1 parent 184cfe5 commit 7d38c2e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 5 deletions.
13 changes: 8 additions & 5 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,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;
Expand All @@ -558,7 +559,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;
Expand All @@ -568,7 +569,7 @@ async function readFileHandle(filehandle, options) {
}

if (!encoding) {
if (size === 0 && !singleRead) {
if (noSize && !singleRead) {
ArrayPrototypePush(buffers, buffer);
return Buffer.concat(buffers, totalRead);
}
Expand All @@ -581,15 +582,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);
}
}
Expand Down
46 changes: 46 additions & 0 deletions test/parallel/test-fs-readfile-eof.js
Original file line number Diff line number Diff line change
@@ -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]);

0 comments on commit 7d38c2e

Please sign in to comment.