Skip to content

Commit 3a5856c

Browse files
Linkgorontargos
authored andcommitted
fs: fix async iterator partial writes
fix an issue where chunks might be partially written when using writeFile with an async iterator. PR-URL: #38615 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 5c38a55 commit 3a5856c

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

lib/internal/fs/promises.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,16 @@ async function writeFileHandle(filehandle, data, signal, encoding) {
281281
if (isCustomIterable(data)) {
282282
for await (const buf of data) {
283283
checkAborted(signal);
284-
await write(
285-
filehandle, buf, undefined,
286-
isArrayBufferView(buf) ? buf.byteLength : encoding);
287-
checkAborted(signal);
284+
const toWrite =
285+
isArrayBufferView(buf) ? buf : Buffer.from(buf, encoding || 'utf8');
286+
let remaining = toWrite.byteLength;
287+
while (remaining > 0) {
288+
const writeSize = MathMin(kWriteFileMaxChunkSize, remaining);
289+
const { bytesWritten } = await write(
290+
filehandle, toWrite, toWrite.byteLength - remaining, writeSize);
291+
remaining -= bytesWritten;
292+
checkAborted(signal);
293+
}
288294
}
289295
return;
290296
}

test/parallel/test-fs-promises-writefile.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ const iterable = {
2525
yield 'c';
2626
}
2727
};
28+
29+
const veryLargeBuffer = {
30+
expected: 'dogs running'.repeat(512 * 1024),
31+
*[Symbol.iterator]() {
32+
yield Buffer.from('dogs running'.repeat(512 * 1024), 'utf8');
33+
}
34+
};
35+
2836
function iterableWith(value) {
2937
return {
3038
*[Symbol.iterator]() {
@@ -106,6 +114,12 @@ async function doWriteAsyncIterable() {
106114
assert.deepStrictEqual(data, asyncIterable.expected);
107115
}
108116

117+
async function doWriteAsyncLargeIterable() {
118+
await fsPromises.writeFile(dest, veryLargeBuffer);
119+
const data = fs.readFileSync(dest, 'utf-8');
120+
assert.deepStrictEqual(data, veryLargeBuffer.expected);
121+
}
122+
109123
async function doWriteInvalidValues() {
110124
await Promise.all(
111125
[42, 42n, {}, Symbol('42'), true, undefined, null, NaN].map((value) =>
@@ -158,5 +172,6 @@ async function doReadWithEncoding() {
158172
await doWriteIterableWithEncoding();
159173
await doWriteBufferIterable();
160174
await doWriteAsyncIterable();
175+
await doWriteAsyncLargeIterable();
161176
await doWriteInvalidValues();
162177
})().then(common.mustCall());

0 commit comments

Comments
 (0)