Skip to content

Commit 3612229

Browse files
Linkgoronjasnell
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 <duhamelantoine1995@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 61a67c1 commit 3612229

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

lib/internal/fs/promises.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,16 @@ async function writeFileHandle(filehandle, data, signal, encoding) {
296296
if (isCustomIterable(data)) {
297297
for await (const buf of data) {
298298
checkAborted(signal);
299-
await write(
300-
filehandle, buf, undefined,
301-
isArrayBufferView(buf) ? buf.byteLength : encoding);
302-
checkAborted(signal);
299+
const toWrite =
300+
isArrayBufferView(buf) ? buf : Buffer.from(buf, encoding || 'utf8');
301+
let remaining = toWrite.byteLength;
302+
while (remaining > 0) {
303+
const writeSize = MathMin(kWriteFileMaxChunkSize, remaining);
304+
const { bytesWritten } = await write(
305+
filehandle, toWrite, toWrite.byteLength - remaining, writeSize);
306+
remaining -= bytesWritten;
307+
checkAborted(signal);
308+
}
303309
}
304310
return;
305311
}

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)