Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: #35343
  • Loading branch information
targos committed Sep 27, 2020
commit 5c604bc3e25fa2cd7d7ed43f1abe87d3d48b2060
13 changes: 10 additions & 3 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ const kReadFileMaxChunkSize = 2 ** 14;
const kWriteFileMaxChunkSize = 2 ** 14;

const {
Error,
MathMax,
MathMin,
NumberIsSafeInteger,
Symbol,
Error,
Promise,
Symbol,
Uint8Array,
} = primordials;

const {
Expand Down Expand Up @@ -237,14 +238,20 @@ 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 {
const { bytesWritten } =
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);
}

Expand Down
24 changes: 24 additions & 0 deletions test/parallel/test-fs-promises-writefile-typedarray.js
Original file line number Diff line number Diff line change
@@ -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());