fs: fix async iterator partial writes

fix an issue where chunks might be partially written when
using writeFile with an async iterator.

PR-URL: https://github.com/nodejs/node/pull/38615
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Nitzan Uziely authored and James M Snell committed 2021-05-17 12:16:27 -07:00
1 parent 61a67c1625
commit 3612229d44
2 files changed
+25 -4

No files matched your search

+10 -4
View File
@@ -296,10 +296,16 @@ async function writeFileHandle(filehandle, data, signal, encoding) {
if (isCustomIterable(data)) {
for await (const buf of data) {
checkAborted(signal);
await write(
filehandle, buf, undefined,
isArrayBufferView(buf) ? buf.byteLength : encoding);
checkAborted(signal);
const toWrite =
isArrayBufferView(buf) ? buf : Buffer.from(buf, encoding || 'utf8');
let remaining = toWrite.byteLength;
while (remaining > 0) {
const writeSize = MathMin(kWriteFileMaxChunkSize, remaining);
const { bytesWritten } = await write(
filehandle, toWrite, toWrite.byteLength - remaining, writeSize);
remaining -= bytesWritten;
checkAborted(signal);
}
}
return;
}
@@ -25,6 +25,14 @@ const iterable = {
yield 'c';
}
};
const veryLargeBuffer = {
expected: 'dogs running'.repeat(512 * 1024),
*[Symbol.iterator]() {
yield Buffer.from('dogs running'.repeat(512 * 1024), 'utf8');
}
};
function iterableWith(value) {
return {
*[Symbol.iterator]() {
@@ -106,6 +114,12 @@ async function doWriteAsyncIterable() {
assert.deepStrictEqual(data, asyncIterable.expected);
}
async function doWriteAsyncLargeIterable() {
await fsPromises.writeFile(dest, veryLargeBuffer);
const data = fs.readFileSync(dest, 'utf-8');
assert.deepStrictEqual(data, veryLargeBuffer.expected);
}
async function doWriteInvalidValues() {
await Promise.all(
[42, 42n, {}, Symbol('42'), true, undefined, null, NaN].map((value) =>
@@ -158,5 +172,6 @@ async function doReadWithEncoding() {
await doWriteIterableWithEncoding();
await doWriteBufferIterable();
await doWriteAsyncIterable();
await doWriteAsyncLargeIterable();
await doWriteInvalidValues();
})().then(common.mustCall());