Skip to content

Commit 99a79e3

Browse files
targosMylesBorins
authored andcommitted
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 PR-URL: #35376 Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Zeyu Yang <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 70ad69b commit 99a79e3

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

lib/internal/fs/promises.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ const kReadFileMaxChunkSize = 2 ** 14;
1010
const kWriteFileMaxChunkSize = 2 ** 14;
1111

1212
const {
13+
Error,
1314
MathMax,
1415
MathMin,
1516
NumberIsSafeInteger,
16-
Symbol,
17-
Error,
1817
Promise,
18+
Symbol,
19+
Uint8Array,
1920
} = primordials;
2021

2122
const {
@@ -237,14 +238,20 @@ async function fsCall(fn, handle, ...args) {
237238
}
238239

239240
async function writeFileHandle(filehandle, data) {
241+
// `data` could be any kind of typed array.
242+
data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
240243
let remaining = data.length;
241244
if (remaining === 0) return;
242245
do {
243246
const { bytesWritten } =
244247
await write(filehandle, data, 0,
245248
MathMin(kWriteFileMaxChunkSize, data.length));
246249
remaining -= bytesWritten;
247-
data = data.slice(bytesWritten);
250+
data = new Uint8Array(
251+
data.buffer,
252+
data.byteOffset + bytesWritten,
253+
data.byteLength - bytesWritten
254+
);
248255
} while (remaining > 0);
249256
}
250257

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fs = require('fs');
5+
const fsPromises = fs.promises;
6+
const path = require('path');
7+
const tmpdir = require('../common/tmpdir');
8+
const assert = require('assert');
9+
const tmpDir = tmpdir.path;
10+
11+
tmpdir.refresh();
12+
13+
const dest = path.resolve(tmpDir, 'tmp.txt');
14+
// Use a file size larger than `kReadFileMaxChunkSize`.
15+
const buffer = Buffer.from('012'.repeat(2 ** 14));
16+
17+
(async () => {
18+
for (const Constructor of [Uint8Array, Uint16Array, Uint32Array]) {
19+
const array = new Constructor(buffer.buffer);
20+
await fsPromises.writeFile(dest, array);
21+
const data = await fsPromises.readFile(dest);
22+
assert.deepStrictEqual(data, buffer);
23+
}
24+
})().then(common.mustCall());

0 commit comments

Comments
 (0)