From 99a79e32a6a8dfcad5c03430fb3ad863f7303201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sun, 27 Sep 2020 14:34:05 +0200 Subject: [PATCH] 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 Reviewed-By: Zeyu Yang Reviewed-By: Anna Henningsen --- lib/internal/fs/promises.js | 13 +++++++--- .../test-fs-promises-writefile-typedarray.js | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 test/parallel/test-fs-promises-writefile-typedarray.js diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index a938b382eb1268..60a28735a982ec 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -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); } diff --git a/test/parallel/test-fs-promises-writefile-typedarray.js b/test/parallel/test-fs-promises-writefile-typedarray.js new file mode 100644 index 00000000000000..32d9cffa236e57 --- /dev/null +++ b/test/parallel/test-fs-promises-writefile-typedarray.js @@ -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());