Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
b3c8e60
deps: update V8 to 10.2.154.2
targos Apr 19, 2022
b8b5e6d
build: reset embedder string to "-node.0"
targos Apr 19, 2022
4be7584
deps: V8: un-cherry-pick bd019bd
refack Mar 27, 2019
f83323f
deps: V8: forward declaration of `Rtl*FunctionTable`
refack May 22, 2019
e678b6c
deps: fix V8 build issue with inline methods
gengjiawen Oct 14, 2020
2130891
deps: disable trap handler for Windows cross-compiler
targos Oct 20, 2021
45e1fd4
deps: silence V8's warning on CompileFunction
targos Nov 22, 2021
76546b1
deps: V8: fix v8-cppgc.h for MSVC
gengjiawen Mar 17, 2022
c626a53
deps: make V8 compilable with older glibc
targos Mar 18, 2022
742ffef
deps: make V8 10.2 ABI-compatible with 10.1
targos Apr 19, 2022
5228028
tools: update V8 gypfiles for 10.2
targos Apr 12, 2022
d663470
build: run V8 tests with detected Python version
richardlau Apr 5, 2022
5eff7b4
Revert "build: make x86 Windows support temporarily experimental"
targos Apr 14, 2022
0000654
deps: patch V8 to 10.2.154.4
targos May 17, 2022
9577878
src: replace TraceEventScope with sync events
legendecas May 5, 2022
b318185
doc: add strategic initiative for shadow realm
legendecas May 16, 2022
82fb037
src: move context snapshot index to SnapshotData
joyeecheung May 9, 2022
85d81a7
bootstrap: include code cache in the embedded snapshot
joyeecheung Nov 18, 2021
72a767b
src: remove SecureContext::operator*
tniessen May 17, 2022
3e89b73
fs: make params in writing methods optional
LiviaMedeiros Apr 4, 2022
4e9393e
doc: use ASCII apostrophes consistently
tniessen May 17, 2022
6f48dfb
fs: add trailing commas
LiviaMedeiros May 17, 2022
d8a14a2
src: fix static analysis warning and use smart ptr
tniessen May 18, 2022
d42de13
deps: upgrade npm to 8.10.0
May 11, 2022
4d9f43a
doc: use serial comma in dns docs
tniessen May 19, 2022
7d8d9d6
meta: add mailmap entry for Morgan Roderick
lpinca May 19, 2022
11c783f
net: remoteAddress always undefined called before connected
Y1D7NG May 8, 2022
d91b489
worker: fix heap snapshot crash on exit
legendecas May 17, 2022
1be254b
meta: add mailmap entry for npm team
lpinca May 19, 2022
093a3cf
doc: fix errors in Performance hooks doc
Y1D7NG May 19, 2022
56fc712
doc: use serial comma in assert docs
tniessen May 20, 2022
945f228
doc: add release key for RafaelGSS
RafaelGSS May 20, 2022
1da6b7c
meta: add mailmap entry for legendecas
legendecas May 20, 2022
1183058
tools: refactor update-authors.js to ESM
F3n67u May 21, 2022
1e2552b
src: reuse GetServerName
tniessen May 21, 2022
9cc5ce6
test: improve readline/emitKeypressEvents.js coverage
Y1D7NG May 22, 2022
ed352a9
tools: update eslint to 8.16.0
nodejs-github-bot May 22, 2022
2b8b224
doc: remove outdated footnote (Python 2 --> 3 for V8 tests)
DeeDeeG May 22, 2022
285ef30
console: fix console.dir crash on a revoked proxy
daeyeon May 22, 2022
0efeceb
tools: update lint-md-dependencies to rollup@2.74.1
nodejs-github-bot May 22, 2022
71074ee
doc: improve callback params for `fs.mkdir`
daeyeon May 22, 2022
f90a3d7
doc: improved parallel specification
mawaregetsuka May 22, 2022
c76caad
debugger: throw a more useful error when the frame is missing
cola119 May 22, 2022
d9fb25c
tools: refactor build-addons.js to ESM
F3n67u May 22, 2022
701d404
lib: refactor `validateInt32` and `validateUint32`
mawaregetsuka May 22, 2022
b772c13
doc: use serial comma in process docs
tniessen May 22, 2022
9539cfa
http: add uniqueHeaders option to request and createServer
ShogunPanda Jan 10, 2022
41b69e3
src,lib: migrate to console on context's extra binding
legendecas May 18, 2022
8f5b457
net: add ability to reset a tcp socket
PupilTong May 15, 2022
d7ca223
test: use mustSucceed instead of mustCall with assert.ifError
fossamagna May 23, 2022
598c1f1
doc: use serial comma in dgram docs
tniessen May 23, 2022
6ee9fb1
src: make SecureContext fields private
tniessen May 24, 2022
3082c75
doc: make minor adjustments
LiviaMedeiros May 24, 2022
a07f5f2
http2: improve tests and docs
daeyeon May 24, 2022
baa5d00
src: refactor GetCipherValue and related functions
tniessen May 24, 2022
d6cf409
util: add parseArgs module
May 24, 2022
87b248e
deps: update undici to 5.3.0
nodejs-github-bot May 24, 2022
3e1ed1e
test: improve code coverage for inspector connection errors
cola119 May 25, 2022
b187060
http2: set origin name correctly when servername is empty
ofirbarak May 25, 2022
920d8c5
crypto: align webcrypto RSA key import/export with other implementations
panva May 25, 2022
76b4680
doc: document `signal` option for `EventTarget#addEventListener`
aduh95 May 25, 2022
54d68b1
perf_hooks: fix start_time of perf_hooks
theanarkh May 12, 2022
41fdc26
deps: upgrade npm to 8.11.0
May 25, 2022
9c4e070
node-api: emit uncaught-exception on unhandled tsfn callbacks
legendecas Dec 14, 2020
776e746
doc: fix napi version for node_api_symbol_for
danielleadams Apr 27, 2022
badf72d
doc: use serial comma in worker_threads docs
tniessen May 28, 2022
0098933
doc: add note regarding `%Array.prototype.concat%` in `primordials.md`
aduh95 May 29, 2022
447bbd0
tls: fix convertALPNProtocols accepting ArrayBufferViews
LiviaMedeiros May 26, 2022
09da764
meta: update AUTHORS
nodejs-github-bot May 29, 2022
df69146
tools: update lint-md-dependencies to rollup@2.75.1
nodejs-github-bot May 29, 2022
ecacc3a
deps: exclude linker scripts for windows builds
danbev May 5, 2022
35250bf
deps: regenerate OpenSSL archs files
danbev May 16, 2022
0afdc3e
doc: use serial comma in errors docs
tniessen May 30, 2022
aefc9dd
benchmark: add node-error benchmark
RafaelGSS May 12, 2022
dc3b91f
deps: update undici to 5.4.0
nodejs-github-bot Jun 1, 2022
49362ef
2022-06-01, Version 18.3.0 (Current)
bengl May 31, 2022
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
Prev Previous commit
Next Next commit
fs: make params in writing methods optional
This change allows passing objects as "named parameters":
- `fs.write(fd, buffer[, options], callback)`
- `fs.writeSync(fd, buffer[, options])`
- `filehandle.write(buffer[, options])`

Fixes: #41666

PR-URL: #42601
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
LiviaMedeiros authored and bengl committed May 30, 2022
commit 3e89b7336dbdfb7bec601e52b49d63fa3a0105f4
67 changes: 63 additions & 4 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ added: v10.0.0
Change the file system timestamps of the object referenced by the {FileHandle}
then resolves the promise with no arguments upon success.

#### `filehandle.write(buffer[, offset[, length[, position]]])`
#### `filehandle.write(buffer, offset[, length[, position]])`

<!-- YAML
added: v10.0.0
Expand All @@ -621,7 +621,7 @@ changes:

* `buffer` {Buffer|TypedArray|DataView}
* `offset` {integer} The start position from within `buffer` where the data
to write begins. **Default:** `0`
to write begins.
* `length` {integer} The number of bytes from `buffer` to write. **Default:**
`buffer.byteLength - offset`
* `position` {integer|null} The offset from the beginning of the file where the
Expand All @@ -646,6 +646,25 @@ On Linux, positional writes do not work when the file is opened in append mode.
The kernel ignores the position argument and always appends the data to
the end of the file.

#### `filehandle.write(buffer[, options])`

<!-- YAML
added: REPLACEME
-->

* `buffer` {Buffer|TypedArray|DataView}
* `options` {Object}
* `offset` {integer} **Default:** `0`
* `length` {integer} **Default:** `buffer.byteLength - offset`
* `position` {integer} **Default:** `null`
* Returns: {Promise}

Write `buffer` to the file.

Similar to the above `filehandle.write` function, this version takes an
optional `options` object. If no `options` object is specified, it will
default with the above values.

#### `filehandle.write(string[, position[, encoding]])`

<!-- YAML
Expand Down Expand Up @@ -4372,7 +4391,7 @@ This happens when:
* the file is deleted, followed by a restore
* the file is renamed and then renamed a second time back to its original name

### `fs.write(fd, buffer[, offset[, length[, position]]], callback)`
### `fs.write(fd, buffer, offset[, length[, position]], callback)`

<!-- YAML
added: v0.0.2
Expand Down Expand Up @@ -4439,6 +4458,29 @@ On Linux, positional writes don't work when the file is opened in append mode.
The kernel ignores the position argument and always appends the data to
the end of the file.

### `fs.write(fd, buffer[, options], callback)`

<!-- YAML
added: REPLACEME
-->

* `fd` {integer}
* `buffer` {Buffer|TypedArray|DataView}
* `options` {Object}
* `offset` {integer} **Default:** `0`
* `length` {integer} **Default:** `buffer.byteLength - offset`
* `position` {integer} **Default:** `null`
* `callback` {Function}
* `err` {Error}
* `bytesWritten` {integer}
* `buffer` {Buffer|TypedArray|DataView}

Write `buffer` to the file specified by `fd`.

Similar to the above `fs.write` function, this version takes an
optional `options` object. If no `options` object is specified, it will
default with the above values.

### `fs.write(fd, string[, position[, encoding]], callback)`

<!-- YAML
Expand Down Expand Up @@ -5787,7 +5829,7 @@ for more details.
For detailed information, see the documentation of the asynchronous version of
this API: [`fs.writeFile()`][].

### `fs.writeSync(fd, buffer[, offset[, length[, position]]])`
### `fs.writeSync(fd, buffer, offset[, length[, position]])`

<!-- YAML
added: v0.1.21
Expand Down Expand Up @@ -5818,6 +5860,23 @@ changes:
For detailed information, see the documentation of the asynchronous version of
this API: [`fs.write(fd, buffer...)`][].

### `fs.writeSync(fd, buffer[, options])`

<!-- YAML
added: REPLACEME
-->

* `fd` {integer}
* `buffer` {Buffer|TypedArray|DataView}
* `options` {Object}
* `offset` {integer} **Default:** `0`
* `length` {integer} **Default:** `buffer.byteLength - offset`
* `position` {integer} **Default:** `null`
* Returns: {number} The number of bytes written.

For detailed information, see the documentation of the asynchronous version of
this API: [`fs.write(fd, buffer...)`][].

### `fs.writeSync(fd, string[, position[, encoding]])`

<!-- YAML
Expand Down
37 changes: 29 additions & 8 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ function read(fd, buffer, offsetOrOptions, length, position, callback) {
({
offset = 0,
length = buffer.byteLength - offset,
position = null
position = null,
} = params ?? ObjectCreate(null));
}

Expand Down Expand Up @@ -705,7 +705,7 @@ function readSync(fd, buffer, offset, length, position) {
({
offset = 0,
length = buffer.byteLength - offset,
position = null
position = null,
} = options);
}

Expand Down Expand Up @@ -801,7 +801,7 @@ function readvSync(fd, buffers, position) {
* Writes `buffer` to the specified `fd` (file descriptor).
* @param {number} fd
* @param {Buffer | TypedArray | DataView | string | object} buffer
* @param {number} [offset]
* @param {number | object} [offsetOrOptions]
* @param {number} [length]
* @param {number | null} [position]
* @param {(
Expand All @@ -811,16 +811,26 @@ function readvSync(fd, buffers, position) {
* ) => any} callback
* @returns {void}
*/
function write(fd, buffer, offset, length, position, callback) {
function write(fd, buffer, offsetOrOptions, length, position, callback) {
function wrapper(err, written) {
// Retain a reference to buffer so that it can't be GC'ed too soon.
callback(err, written || 0, buffer);
}

fd = getValidatedFd(fd);

let offset = offsetOrOptions;
if (isArrayBufferView(buffer)) {
callback = maybeCallback(callback || position || length || offset);

if (typeof offset === 'object') {
({
offset = 0,
length = buffer.byteLength - offset,
position = null,
} = offsetOrOptions ?? ObjectCreate(null));
}

if (offset == null || typeof offset === 'function') {
offset = 0;
} else {
Expand Down Expand Up @@ -869,16 +879,27 @@ ObjectDefineProperty(write, internalUtil.customPromisifyArgs,
* specified `fd` (file descriptor).
* @param {number} fd
* @param {Buffer | TypedArray | DataView | string} buffer
* @param {number} [offset]
* @param {number} [length]
* @param {number | null} [position]
* @param {{
* offset?: number;
* length?: number;
* position?: number | null;
* }} [offsetOrOptions]
* @returns {number}
*/
function writeSync(fd, buffer, offset, length, position) {
function writeSync(fd, buffer, offsetOrOptions, length, position) {
fd = getValidatedFd(fd);
const ctx = {};
let result;

let offset = offsetOrOptions;
if (isArrayBufferView(buffer)) {
if (typeof offset === 'object') {
({
offset = 0,
length = buffer.byteLength - offset,
position = null
} = offsetOrOptions ?? ObjectCreate(null));
}
if (position === undefined)
position = null;
if (offset == null) {
Expand Down
11 changes: 10 additions & 1 deletion lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -569,11 +569,20 @@ async function readv(handle, buffers, position) {
return { bytesRead, buffers };
}

async function write(handle, buffer, offset, length, position) {
async function write(handle, buffer, offsetOrOptions, length, position) {
if (buffer?.byteLength === 0)
return { bytesWritten: 0, buffer };

let offset = offsetOrOptions;
if (isArrayBufferView(buffer)) {
if (typeof offset === 'object') {
({
offset = 0,
length = buffer.byteLength - offset,
position = null
} = offsetOrOptions ?? ObjectCreate(null));
}

if (offset == null) {
offset = 0;
} else {
Expand Down
95 changes: 95 additions & 0 deletions test/parallel/test-fs-promises-write-optional-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
'use strict';

const common = require('../common');

// This test ensures that filehandle.write accepts "named parameters" object
// and doesn't interpret objects as strings

const assert = require('assert');
const fsPromises = require('fs').promises;
const path = require('path');
const tmpdir = require('../common/tmpdir');

tmpdir.refresh();

const dest = path.resolve(tmpdir.path, 'tmp.txt');
const buffer = Buffer.from('zyx');

async function testInvalid(dest, expectedCode, ...params) {
let fh;
try {
fh = await fsPromises.open(dest, 'w+');
await assert.rejects(
fh.write(...params),
{ code: expectedCode });
} finally {
await fh?.close();
}
}

async function testValid(dest, buffer, options) {
let fh;
try {
fh = await fsPromises.open(dest, 'w+');
const writeResult = await fh.write(buffer, options);
const writeBufCopy = Uint8Array.prototype.slice.call(writeResult.buffer);

const readResult = await fh.read(buffer, options);
const readBufCopy = Uint8Array.prototype.slice.call(readResult.buffer);

assert.ok(writeResult.bytesWritten >= readResult.bytesRead);
if (options.length !== undefined && options.length !== null) {
assert.strictEqual(writeResult.bytesWritten, options.length);
}
if (options.offset === undefined || options.offset === 0) {
assert.deepStrictEqual(writeBufCopy, readBufCopy);
}
assert.deepStrictEqual(writeResult.buffer, readResult.buffer);
} finally {
await fh?.close();
}
}

(async () => {
// Test if first argument is not wrongly interpreted as ArrayBufferView|string
for (const badBuffer of [
undefined, null, true, 42, 42n, Symbol('42'), NaN, [], () => {},
Promise.resolve(new Uint8Array(1)),
{},
{ buffer: 'amNotParam' },
{ string: 'amNotParam' },
{ buffer: new Uint8Array(1).buffer },
new Date(),
new String('notPrimitive'),
{ toString() { return 'amObject'; } },
{ [Symbol.toPrimitive]: (hint) => 'amObject' },
]) {
await testInvalid(dest, 'ERR_INVALID_ARG_TYPE', badBuffer, {});
}

// First argument (buffer or string) is mandatory
await testInvalid(dest, 'ERR_INVALID_ARG_TYPE');

// Various invalid options
await testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: 5 });
await testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: 5 });
await testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: 1, offset: 3 });
await testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: -1 });
await testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: -1 });
await testInvalid(dest, 'ERR_INVALID_ARG_TYPE', buffer, { offset: false });
await testInvalid(dest, 'ERR_INVALID_ARG_TYPE', buffer, { offset: true });

// Test compatibility with filehandle.read counterpart
for (const options of [
{},
{ length: 1 },
{ position: 5 },
{ length: 1, position: 5 },
{ length: 1, position: -1, offset: 2 },
{ length: null },
{ position: null },
{ offset: 1 },
]) {
await testValid(dest, buffer, options);
}
})().then(common.mustCall());
Loading