Skip to content

Commit

Permalink
fs: make promises/write and writeSync params optional
Browse files Browse the repository at this point in the history
This change allows passing objects as "named parameters" and
prohibits passing objects with own toString property as strings.

Fixes: nodejs#41666
  • Loading branch information
LiviaMedeiros committed Jan 25, 2022
1 parent e2e2bc8 commit b653a35
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 27 deletions.
64 changes: 45 additions & 19 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ changes:
buffers anymore.
-->
* `buffer` {Buffer|TypedArray|DataView|string|Object}
* `buffer` {Buffer|TypedArray|DataView}
* `offset` {integer} The start position from within `buffer` where the data
to write begins. **Default:** `0`
* `length` {integer} The number of bytes from `buffer` to write. **Default:**
Expand All @@ -599,13 +599,10 @@ changes:
Write `buffer` to the file.
If `buffer` is a plain object, it must have an own (not inherited) `toString`
function property.
The promise is resolved with an object containing two properties:
* `bytesWritten` {integer} the number of bytes written
* `buffer` {Buffer|TypedArray|DataView|string|Object} a reference to the
* `buffer` {Buffer|TypedArray|DataView} a reference to the
`buffer` written.
It is unsafe to use `filehandle.write()` multiple times on the same file
Expand All @@ -616,6 +613,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`
* `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 All @@ -631,21 +647,21 @@ changes:
strings anymore.
-->
* `string` {string|Object}
* `string` {string}
* `position` {integer} The offset from the beginning of the file where the
data from `string` should be written. If `position` is not a `number` the
data will be written at the current position. See the POSIX pwrite(2)
documentation for more detail.
* `encoding` {string} The expected string encoding. **Default:** `'utf8'`
* Returns: {Promise}
Write `string` to the file. If `string` is not a string, or an object with an
own `toString` function property, the promise is rejected with an error.
Write `string` to the file. If `string` is not a string, the promise is
rejected with an error.
The promise is resolved with an object containing two properties:
* `bytesWritten` {integer} the number of bytes written
* `buffer` {string|Object} a reference to the `string` written.
* `buffer` {string} a reference to the `string` written.
It is unsafe to use `filehandle.write()` multiple times on the same file
without waiting for the promise to be resolved (or rejected). For this
Expand Down Expand Up @@ -4161,7 +4177,7 @@ changes:
-->
* `fd` {integer}
* `buffer` {Buffer|TypedArray|DataView|string|Object}
* `buffer` {Buffer|TypedArray|DataView}
* `offset` {integer}
* `length` {integer}
* `position` {integer}
Expand All @@ -4170,8 +4186,7 @@ changes:
* `bytesWritten` {integer}
* `buffer` {Buffer|TypedArray|DataView}
Write `buffer` to the file specified by `fd`. If `buffer` is a normal object, it
must have an own `toString` function property.
Write `buffer` to the file specified by `fd`.
`offset` determines the part of the buffer to be written, and `length` is
an integer specifying the number of bytes to write.
Expand Down Expand Up @@ -5542,14 +5557,28 @@ changes:
-->
* `fd` {integer}
* `buffer` {Buffer|TypedArray|DataView|string|Object}
* `buffer` {Buffer|TypedArray|DataView}
* `offset` {integer}
* `length` {integer}
* `position` {integer}
* Returns: {number} The number of bytes written.
If `buffer` is a plain object, it must have an own (not inherited) `toString`
function property.
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`
* `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...)`][].
Expand All @@ -5573,14 +5602,11 @@ changes:
-->
* `fd` {integer}
* `string` {string|Object}
* `string` {string}
* `position` {integer}
* `encoding` {string}
* Returns: {number} The number of bytes written.
If `string` is a plain object, it must have an own (not inherited) `toString`
function property.
For detailed information, see the documentation of the asynchronous version of
this API: [`fs.write(fd, string...)`][].
Expand Down
24 changes: 18 additions & 6 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const {
validateRmOptionsSync,
validateRmdirOptions,
validateStringAfterArrayBufferView,
validatePrimitiveStringAfterArrayBufferView,
warnOnNonPortableTemplate
} = require('internal/fs/utils');
const {
Expand Down Expand Up @@ -687,7 +688,7 @@ function readSync(fd, buffer, offset, length, position) {
validateBuffer(buffer);

if (arguments.length <= 3) {
// Assume fs.read(fd, buffer, options)
// Assume fs.readSync(fd, buffer, options)
const options = offset || {};

({ offset = 0, length = buffer.byteLength, position } = options);
Expand Down Expand Up @@ -849,16 +850,27 @@ ObjectDefineProperty(write, internalUtil.customPromisifyArgs,
* Synchronously writes `buffer` to the
* specified `fd` (file descriptor).
* @param {number} fd
* @param {Buffer | TypedArray | DataView | string | object} buffer
* @param {number} [offset]
* @param {number} [length]
* @param {number} [position]
* @param {Buffer | TypedArray | DataView | string} buffer
* @param {{
* offset?: number;
* length?: number;
* position?: number;
* }} [offset]
* @returns {number}
*/
function writeSync(fd, buffer, offset, length, position) {
fd = getValidatedFd(fd);
const ctx = {};
let result;

if (typeof offset === 'object' && offset !== null) {
({
offset = 0,
length = buffer.byteLength,
position = null
} = offset);
}

if (isArrayBufferView(buffer)) {
if (position === undefined)
position = null;
Expand All @@ -873,7 +885,7 @@ function writeSync(fd, buffer, offset, length, position) {
result = binding.writeBuffer(fd, buffer, offset, length, position,
undefined, ctx);
} else {
validateStringAfterArrayBufferView(buffer, 'buffer');
validatePrimitiveStringAfterArrayBufferView(buffer, 'buffer');
validateEncoding(buffer, length);

if (offset === undefined)
Expand Down
16 changes: 14 additions & 2 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const {
validateRmOptions,
validateRmdirOptions,
validateStringAfterArrayBufferView,
validatePrimitiveStringAfterArrayBufferView,
warnOnNonPortableTemplate,
} = require('internal/fs/utils');
const { opendir } = require('internal/fs/dir');
Expand Down Expand Up @@ -562,7 +563,18 @@ async function readv(handle, buffers, position) {
return { bytesRead, buffers };
}

async function write(handle, buffer, offset, length, position) {
async function write(handle, bufferOrOptions, offset, length, position) {
let buffer = bufferOrOptions;
if (!isArrayBufferView(buffer) && typeof buffer !== 'string') {
validateBuffer(bufferOrOptions?.buffer);
({
buffer,
offset = 0,
length = buffer.byteLength,
position = null
} = bufferOrOptions);
}

if (buffer?.byteLength === 0)
return { bytesWritten: 0, buffer };

Expand All @@ -583,7 +595,7 @@ async function write(handle, buffer, offset, length, position) {
return { bytesWritten, buffer };
}

validateStringAfterArrayBufferView(buffer, 'buffer');
validatePrimitiveStringAfterArrayBufferView(buffer, 'buffer');
validateEncoding(buffer, length);
const bytesWritten = (await binding.writeString(handle.fd, buffer, offset,
length, kUsePromises)) || 0;
Expand Down
13 changes: 13 additions & 0 deletions lib/internal/fs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,18 @@ const validateStringAfterArrayBufferView = hideStackFrames((buffer, name) => {
);
});

const validatePrimitiveStringAfterArrayBufferView = hideStackFrames((buffer, name) => {
if (typeof buffer === 'string') {
return;
}

throw new ERR_INVALID_ARG_TYPE(
name,
['string', 'Buffer', 'TypedArray', 'DataView'],
buffer
);
});

const validatePosition = hideStackFrames((position, name) => {
if (typeof position === 'number') {
validateInteger(position, 'position');
Expand Down Expand Up @@ -937,5 +949,6 @@ module.exports = {
validateRmOptionsSync,
validateRmdirOptions,
validateStringAfterArrayBufferView,
validatePrimitiveStringAfterArrayBufferView,
warnOnNonPortableTemplate
};

0 comments on commit b653a35

Please sign in to comment.