Skip to content

Commit 3273d0e

Browse files
committed
fs: add writev() promises version
#25925 added fs.writev() and fs.writevSync(), but did not include a Promises based equivalent. This commit adds the missing method. Refs: #25925 PR-URL: #29186 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 9f9a201 commit 3273d0e

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

doc/api/fs.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4274,6 +4274,32 @@ If one or more `filehandle.write()` calls are made on a file handle and then a
42744274
current position till the end of the file. It doesn't always write from the
42754275
beginning of the file.
42764276

4277+
#### filehandle.writev(buffers[, position])
4278+
<!-- YAML
4279+
added: REPLACEME
4280+
-->
4281+
4282+
* `buffers` {ArrayBufferView[]}
4283+
* `position` {integer}
4284+
* Returns: {Promise}
4285+
4286+
Write an array of `ArrayBufferView`s to the file.
4287+
4288+
The `Promise` is resolved with an object containing a `bytesWritten` property
4289+
identifying the number of bytes written, and a `buffers` property containing
4290+
a reference to the `buffers` input.
4291+
4292+
`position` is the offset from the beginning of the file where this data
4293+
should be written. If `typeof position !== 'number'`, the data will be written
4294+
at the current position.
4295+
4296+
It is unsafe to call `writev()` multiple times on the same file without waiting
4297+
for the previous operation to complete.
4298+
4299+
On Linux, positional writes don't work when the file is opened in append mode.
4300+
The kernel ignores the position argument and always appends the data to
4301+
the end of the file.
4302+
42774303
### fsPromises.access(path[, mode])
42784304
<!-- YAML
42794305
added: v10.0.0

lib/internal/fs/promises.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const {
2929
stringToFlags,
3030
stringToSymlinkType,
3131
toUnixTimestamp,
32+
validateBufferArray,
3233
validateOffsetLengthRead,
3334
validateOffsetLengthWrite,
3435
warnOnNonPortableTemplate
@@ -104,6 +105,10 @@ class FileHandle {
104105
return write(this, buffer, offset, length, position);
105106
}
106107

108+
writev(buffers, position) {
109+
return writev(this, buffers, position);
110+
}
111+
107112
writeFile(data, options) {
108113
return writeFile(this, data, options);
109114
}
@@ -263,6 +268,18 @@ async function write(handle, buffer, offset, length, position) {
263268
return { bytesWritten, buffer };
264269
}
265270

271+
async function writev(handle, buffers, position) {
272+
validateFileHandle(handle);
273+
validateBufferArray(buffers);
274+
275+
if (typeof position !== 'number')
276+
position = null;
277+
278+
const bytesWritten = (await binding.writeBuffers(handle.fd, buffers, position,
279+
kUsePromises)) || 0;
280+
return { bytesWritten, buffers };
281+
}
282+
266283
async function rename(oldPath, newPath) {
267284
oldPath = getValidatedPath(oldPath, 'oldPath');
268285
newPath = getValidatedPath(newPath, 'newPath');

lib/internal/fs/utils.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515
hideStackFrames
1616
} = require('internal/errors');
1717
const {
18+
isArrayBufferView,
1819
isUint8Array,
1920
isDate,
2021
isBigUint64Array
@@ -500,6 +501,18 @@ const getValidatedPath = hideStackFrames((fileURLOrPath, propName = 'path') => {
500501
return path;
501502
});
502503

504+
const validateBufferArray = hideStackFrames((buffers, propName = 'buffers') => {
505+
if (!Array.isArray(buffers))
506+
throw new ERR_INVALID_ARG_TYPE(propName, 'ArrayBufferView[]', buffers);
507+
508+
for (let i = 0; i < buffers.length; i++) {
509+
if (!isArrayBufferView(buffers[i]))
510+
throw new ERR_INVALID_ARG_TYPE(propName, 'ArrayBufferView[]', buffers);
511+
}
512+
513+
return buffers;
514+
});
515+
503516
let nonPortableTemplateWarn = true;
504517

505518
function warnOnNonPortableTemplate(template) {
@@ -528,6 +541,7 @@ module.exports = {
528541
stringToSymlinkType,
529542
Stats,
530543
toUnixTimestamp,
544+
validateBufferArray,
531545
validateOffsetLengthRead,
532546
validateOffsetLengthWrite,
533547
validatePath,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
const path = require('path');
6+
const fs = require('fs').promises;
7+
const tmpdir = require('../common/tmpdir');
8+
const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف';
9+
let cnt = 0;
10+
11+
function getFileName() {
12+
return path.join(tmpdir.path, `writev_promises_${++cnt}.txt`);
13+
}
14+
15+
tmpdir.refresh();
16+
17+
(async () => {
18+
{
19+
const filename = getFileName();
20+
const handle = await fs.open(filename, 'w');
21+
const buffer = Buffer.from(expected);
22+
const bufferArr = [buffer, buffer];
23+
const expectedLength = bufferArr.length * buffer.byteLength;
24+
let { bytesWritten, buffers } = await handle.writev([Buffer.from('')],
25+
null);
26+
assert.deepStrictEqual(bytesWritten, 0);
27+
assert.deepStrictEqual(buffers, [Buffer.from('')]);
28+
({ bytesWritten, buffers } = await handle.writev(bufferArr, null));
29+
assert.deepStrictEqual(bytesWritten, expectedLength);
30+
assert.deepStrictEqual(buffers, bufferArr);
31+
assert(Buffer.concat(bufferArr).equals(await fs.readFile(filename)));
32+
handle.close();
33+
}
34+
35+
// fs.promises.writev() with an array of buffers without position.
36+
{
37+
const filename = getFileName();
38+
const handle = await fs.open(filename, 'w');
39+
const buffer = Buffer.from(expected);
40+
const bufferArr = [buffer, buffer, buffer];
41+
const expectedLength = bufferArr.length * buffer.byteLength;
42+
let { bytesWritten, buffers } = await handle.writev([Buffer.from('')]);
43+
assert.deepStrictEqual(bytesWritten, 0);
44+
assert.deepStrictEqual(buffers, [Buffer.from('')]);
45+
({ bytesWritten, buffers } = await handle.writev(bufferArr));
46+
assert.deepStrictEqual(bytesWritten, expectedLength);
47+
assert.deepStrictEqual(buffers, bufferArr);
48+
assert(Buffer.concat(bufferArr).equals(await fs.readFile(filename)));
49+
handle.close();
50+
}
51+
})();

0 commit comments

Comments
 (0)