fs: add fs.readv() · nodejs/node@30d55a3 · GitHub
Skip to content

Commit 30d55a3

Browse files
SheikhSajidaddaleax
authored andcommitted
fs: add fs.readv()
Fixes: #2298 PR-URL: #32356 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 6d86651 commit 30d55a3

7 files changed

Lines changed: 410 additions & 0 deletions

File tree

doc/api/fs.md

Lines changed: 56 additions & 0 deletions

lib/fs.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,39 @@ function readSync(fd, buffer, offset, length, position) {
565565
return result;
566566
}
567567

568+
function readv(fd, buffers, position, callback) {
569+
function wrapper(err, read) {
570+
callback(err, read || 0, buffers);
571+
}
572+
573+
validateInt32(fd, 'fd', /* min */ 0);
574+
validateBufferArray(buffers);
575+
576+
const req = new FSReqCallback();
577+
req.oncomplete = wrapper;
578+
579+
callback = maybeCallback(callback || position);
580+
581+
if (typeof position !== 'number')
582+
position = null;
583+
584+
return binding.readBuffers(fd, buffers, position, req);
585+
}
586+
587+
function readvSync(fd, buffers, position) {
588+
validateInt32(fd, 'fd', 0);
589+
validateBufferArray(buffers);
590+
591+
const ctx = {};
592+
593+
if (typeof position !== 'number')
594+
position = null;
595+
596+
const result = binding.readBuffers(fd, buffers, position, undefined, ctx);
597+
handleErrorFromBinding(ctx);
598+
return result;
599+
}
600+
568601
// usage:
569602
// fs.write(fd, buffer[, offset[, length[, position]]], callback);
570603
// OR
@@ -1917,6 +1950,8 @@ module.exports = fs = {
19171950
readdirSync,
19181951
read,
19191952
readSync,
1953+
readv,
1954+
readvSync,
19201955
readFile,
19211956
readFileSync,
19221957
readlink,

lib/internal/fs/promises.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class FileHandle {
9999
return read(this, buffer, offset, length, position);
100100
}
101101

102+
readv(buffers, position) {
103+
return readv(this, buffers, position);
104+
}
105+
102106
readFile(options) {
103107
return readFile(this, options);
104108
}
@@ -253,6 +257,18 @@ async function read(handle, buffer, offset, length, position) {
253257
return { bytesRead, buffer };
254258
}
255259

260+
async function readv(handle, buffers, position) {
261+
validateFileHandle(handle);
262+
validateBufferArray(buffers);
263+
264+
if (typeof position !== 'number')
265+
position = null;
266+
267+
const bytesRead = (await binding.readBuffers(handle.fd, buffers, position,
268+
kUsePromises)) || 0;
269+
return { bytesRead, buffers };
270+
}
271+
256272
async function write(handle, buffer, offset, length, position) {
257273
validateFileHandle(handle);
258274

src/node_file.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,52 @@ static void Read(const FunctionCallbackInfo<Value>& args) {
19651965
}
19661966

19671967

1968+
// Wrapper for readv(2).
1969+
//
1970+
// bytesRead = fs.readv(fd, buffers[, position], callback)
1971+
// 0 fd integer. file descriptor
1972+
// 1 buffers array of buffers to read
1973+
// 2 position if integer, position to read at in the file.
1974+
// if null, read from the current position
1975+
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
1976+
Environment* env = Environment::GetCurrent(args);
1977+
1978+
const int argc = args.Length();
1979+
CHECK_GE(argc, 3);
1980+
1981+
CHECK(args[0]->IsInt32());
1982+
const int fd = args[0].As<Int32>()->Value();
1983+
1984+
CHECK(args[1]->IsArray());
1985+
Local<Array> buffers = args[1].As<Array>();
1986+
1987+
int64_t pos = GetOffset(args[2]); // -1 if not a valid JS int
1988+
1989+
MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
1990+
1991+
// Init uv buffers from ArrayBufferViews
1992+
for (uint32_t i = 0; i < iovs.length(); i++) {
1993+
Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
1994+
CHECK(Buffer::HasInstance(buffer));
1995+
iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
1996+
}
1997+
1998+
FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1999+
if (req_wrap_async != nullptr) { // readBuffers(fd, buffers, pos, req)
2000+
AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2001+
uv_fs_read, fd, *iovs, iovs.length(), pos);
2002+
} else { // readBuffers(fd, buffers, undefined, ctx)
2003+
CHECK_EQ(argc, 5);
2004+
FSReqWrapSync req_wrap_sync;
2005+
FS_SYNC_TRACE_BEGIN(read);
2006+
int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2007+
uv_fs_read, fd, *iovs, iovs.length(), pos);
2008+
FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2009+
args.GetReturnValue().Set(bytesRead);
2010+
}
2011+
}
2012+
2013+
19682014
/* fs.chmod(path, mode);
19692015
* Wrapper for chmod(1) / EIO_CHMOD
19702016
*/
@@ -2228,6 +2274,7 @@ void Initialize(Local<Object> target,
22282274
env->SetMethod(target, "open", Open);
22292275
env->SetMethod(target, "openFileHandle", OpenFileHandle);
22302276
env->SetMethod(target, "read", Read);
2277+
env->SetMethod(target, "readBuffers", ReadBuffers);
22312278
env->SetMethod(target, "fdatasync", Fdatasync);
22322279
env->SetMethod(target, "fsync", Fsync);
22332280
env->SetMethod(target, "rename", Rename);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
9+
tmpdir.refresh();
10+
11+
const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف';
12+
const exptectedBuff = Buffer.from(expected);
13+
14+
let cnt = 0;
15+
function getFileName() {
16+
return path.join(tmpdir.path, `readv_promises_${++cnt}.txt`);
17+
}
18+
19+
const allocateEmptyBuffers = (combinedLength) => {
20+
const bufferArr = [];
21+
// Allocate two buffers, each half the size of exptectedBuff
22+
bufferArr[0] = Buffer.alloc(Math.floor(combinedLength / 2)),
23+
bufferArr[1] = Buffer.alloc(combinedLength - bufferArr[0].length);
24+
25+
return bufferArr;
26+
};
27+
28+
(async () => {
29+
{
30+
const filename = getFileName();
31+
await fs.writeFile(filename, exptectedBuff);
32+
const handle = await fs.open(filename, 'r');
33+
// const buffer = Buffer.from(expected);
34+
const bufferArr = allocateEmptyBuffers(exptectedBuff.length);
35+
const expectedLength = exptectedBuff.length;
36+
37+
let { bytesRead, buffers } = await handle.readv([Buffer.from('')],
38+
null);
39+
assert.deepStrictEqual(bytesRead, 0);
40+
assert.deepStrictEqual(buffers, [Buffer.from('')]);
41+
42+
({ bytesRead, buffers } = await handle.readv(bufferArr, null));
43+
assert.deepStrictEqual(bytesRead, expectedLength);
44+
assert.deepStrictEqual(buffers, bufferArr);
45+
assert(Buffer.concat(bufferArr).equals(await fs.readFile(filename)));
46+
handle.close();
47+
}
48+
49+
{
50+
const filename = getFileName();
51+
await fs.writeFile(filename, exptectedBuff);
52+
const handle = await fs.open(filename, 'r');
53+
// const buffer = Buffer.from(expected);
54+
const bufferArr = allocateEmptyBuffers(exptectedBuff.length);
55+
const expectedLength = exptectedBuff.length;
56+
57+
let { bytesRead, buffers } = await handle.readv([Buffer.from('')]);
58+
assert.deepStrictEqual(bytesRead, 0);
59+
assert.deepStrictEqual(buffers, [Buffer.from('')]);
60+
61+
({ bytesRead, buffers } = await handle.readv(bufferArr));
62+
assert.deepStrictEqual(bytesRead, expectedLength);
63+
assert.deepStrictEqual(buffers, bufferArr);
64+
assert(Buffer.concat(bufferArr).equals(await fs.readFile(filename)));
65+
handle.close();
66+
}
67+
})();
Lines changed: 92 additions & 0 deletions

0 commit comments

Comments
 (0)