fs: fix fs.promises.writeFile with typed arrays

Before this change, only the first part of typed arrays which have more
than 1 byte per element (e.g. Uint16Array) would be written.
This also removes the use of the `slice` method to avoid unnecessary
copying the data.

Fixes: https://github.com/nodejs/node/issues/35343

PR-URL: https://github.com/nodejs/node/pull/35376
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Zeyu Yang <himself65@outlook.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Michaël Zasso 2020-09-27 14:34:05 +02:00 committed by Node.js GitHub Bot
parent 1390574d66
commit 56e36f41aa
2 changed files with 34 additions and 3 deletions

View File

@ -10,12 +10,13 @@ const kReadFileMaxChunkSize = 2 ** 14;
const kWriteFileMaxChunkSize = 2 ** 14;
const {
Error,
MathMax,
MathMin,
NumberIsSafeInteger,
Symbol,
Error,
Promise,
Symbol,
Uint8Array,
} = primordials;
const {
@ -237,6 +238,8 @@ async function fsCall(fn, handle, ...args) {
}
async function writeFileHandle(filehandle, data) {
// `data` could be any kind of typed array.
data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
let remaining = data.length;
if (remaining === 0) return;
do {
@ -244,7 +247,11 @@ async function writeFileHandle(filehandle, data) {
await write(filehandle, data, 0,
MathMin(kWriteFileMaxChunkSize, data.length));
remaining -= bytesWritten;
data = data.slice(bytesWritten);
data = new Uint8Array(
data.buffer,
data.byteOffset + bytesWritten,
data.byteLength - bytesWritten
);
} while (remaining > 0);
}

View File

@ -0,0 +1,24 @@
'use strict';
const common = require('../common');
const fs = require('fs');
const fsPromises = fs.promises;
const path = require('path');
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const tmpDir = tmpdir.path;
tmpdir.refresh();
const dest = path.resolve(tmpDir, 'tmp.txt');
// Use a file size larger than `kReadFileMaxChunkSize`.
const buffer = Buffer.from('012'.repeat(2 ** 14));
(async () => {
for (const Constructor of [Uint8Array, Uint16Array, Uint32Array]) {
const array = new Constructor(buffer.buffer);
await fsPromises.writeFile(dest, array);
const data = await fsPromises.readFile(dest);
assert.deepStrictEqual(data, buffer);
}
})().then(common.mustCall());