summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2018-02-14 10:04:22 +0100
committerMichaël Zasso <targos@protonmail.com>2018-02-17 10:15:20 +0100
commit513d9397202b46fb10da41d88ddb747417f8b870 (patch)
tree0da623b315289f49f585991d2e42afdb64198473
parent2620358624b6c0f6c7d02dc2e4333eae9e73b3ea (diff)
downloadandroid-node-v8-513d9397202b46fb10da41d88ddb747417f8b870.tar.gz
android-node-v8-513d9397202b46fb10da41d88ddb747417f8b870.tar.bz2
android-node-v8-513d9397202b46fb10da41d88ddb747417f8b870.zip
fs: move fs.promises API to fs/promises
PR-URL: https://github.com/nodejs/node/pull/18777 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
-rw-r--r--benchmark/fs/bench-stat-promise.js6
-rw-r--r--doc/api/fs.md124
-rw-r--r--lib/fs.js459
-rw-r--r--lib/fs/promises.js507
-rw-r--r--node.gyp1
-rw-r--r--test/parallel/test-fs-promises-writefile.js7
-rw-r--r--test/parallel/test-fs-promises.js4
-rw-r--r--test/sequential/test-async-wrap-getasyncid.js3
8 files changed, 581 insertions, 530 deletions
diff --git a/benchmark/fs/bench-stat-promise.js b/benchmark/fs/bench-stat-promise.js
index adc0ed4965..b031745572 100644
--- a/benchmark/fs/bench-stat-promise.js
+++ b/benchmark/fs/bench-stat-promise.js
@@ -1,7 +1,7 @@
'use strict';
const common = require('../common');
-const fs = require('fs');
+const fsPromises = require('fs/promises');
const bench = common.createBenchmark(main, {
n: [20e4],
@@ -10,11 +10,11 @@ const bench = common.createBenchmark(main, {
async function run(n, statType) {
const arg = statType === 'fstat' ?
- await fs.promises.open(__filename, 'r') : __filename;
+ await fsPromises.open(__filename, 'r') : __filename;
let remaining = n;
bench.start();
while (remaining-- > 0)
- await fs.promises[statType](arg);
+ await fsPromises[statType](arg);
bench.end(n);
if (typeof arg.close === 'function')
diff --git a/doc/api/fs.md b/doc/api/fs.md
index 15afc61e56..a4a9e5fd3f 100644
--- a/doc/api/fs.md
+++ b/doc/api/fs.md
@@ -3231,9 +3231,9 @@ Synchronous versions of [`fs.write()`][]. Returns the number of bytes written.
> Stability: 1 - Experimental
-The `fs.promises` API provides an alternative set of asynchronous file system
+The `fs/promises` API provides an alternative set of asynchronous file system
methods that return `Promise` objects rather than using callbacks. The
-API is accessible via `fs.promises`.
+API is accessible via `require('fs/promises)`.
### class: FileHandle
<!-- YAML
@@ -3247,11 +3247,11 @@ in that, if the `FileHandle` is not explicitly closed using the
and will emit a process warning, thereby helping to prevent memory leaks.
Instances of the `FileHandle` object are created internally by the
-`fs.promises.open()` method.
+`fsPromises.open()` method.
Unlike callback-based such as `fs.fstat()`, `fs.fchown()`, `fs.fchmod()`,
`fs.ftruncate()`, `fs.read()`, and `fs.write()`, operations -- all of which
-use a simple numeric file descriptor, all `fs.promises.*` variations use the
+use a simple numeric file descriptor, all `fsPromises.*` variations use the
`FileHandle` class in order to help protect against accidental leaking of
unclosed file descriptors after a `Promise` is resolved or rejected.
@@ -3317,7 +3317,7 @@ Closes the file descriptor.
async function openAndClose() {
let filehandle;
try {
- filehandle = await fs.promises.open('thefile.txt', 'r');
+ filehandle = await fsPromises.open('thefile.txt', 'r');
} finally {
if (filehandle !== undefined)
await filehandle.close();
@@ -3378,7 +3378,7 @@ object. Otherwise, the data will be a string.
If `options` is a string, then it specifies the encoding.
-When the `path` is a directory, the behavior of `fs.promises.readFile()` is
+When the `path` is a directory, the behavior of `fsPromises.readFile()` is
platform-specific. On macOS, Linux, and Windows, the promise will be rejected
with an error. On FreeBSD, a representation of the directory's contents will be
returned.
@@ -3422,8 +3422,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
// Prints: Node.js
async function doTruncate() {
- const fd = await fs.promises.open('temp.txt', 'r+');
- await fs.promises.ftruncate(fd, 4);
+ const fd = await fsPromises.open('temp.txt', 'r+');
+ await fsPromises.ftruncate(fd, 4);
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints: Node
}
@@ -3438,8 +3438,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
// Prints: Node.js
async function doTruncate() {
- const fd = await fs.promises.open('temp.txt', 'r+');
- await fs.promises.ftruncate(fd, 10);
+ const fd = await fsPromises.open('temp.txt', 'r+');
+ await fsPromises.ftruncate(fd, 10);
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints Node.js\0\0\0
}
@@ -3518,7 +3518,7 @@ The `FileHandle` has to support writing.
It is unsafe to use `filehandle.writeFile()` multiple times on the same file
without waiting for the `Promise` to be resolved (or rejected).
-### fs.promises.access(path[, mode])
+### fsPromises.access(path[, mode])
<!-- YAML
added: REPLACEME
-->
@@ -3547,18 +3547,18 @@ with an `Error` object. The following example checks if the file
`/etc/passwd` can be read and written by the current process.
```js
-fs.promises.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK)
+fsPromises.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK)
.then(() => console.log('can access'))
.catch(() => console.error('cannot access'));
```
-Using `fs.promises.access()` to check for the accessibility of a file before
-calling `fs.promises.open()` is not recommended. Doing so introduces a race
+Using `fsPromises.access()` to check for the accessibility of a file before
+calling `fsPromises.open()` is not recommended. Doing so introduces a race
condition, since other processes may change the file's state between the two
calls. Instead, user code should open/read/write the file directly and handle
the error raised if the file is not accessible.
-### fs.promises.appendFile(file, data[, options])
+### fsPromises.appendFile(file, data[, options])
<!-- YAML
added: REPLACEME
-->
@@ -3578,9 +3578,9 @@ resolved with no arguments upon success.
If `options` is a string, then it specifies the encoding.
The `file` may be specified as a `FileHandle` that has been opened
-for appending (using `fs.promises.open()`).
+for appending (using `fsPromises.open()`).
-### fs.promises.chmod(path, mode)
+### fsPromises.chmod(path, mode)
<!-- YAML
added: REPLACEME
-->
@@ -3592,7 +3592,7 @@ added: REPLACEME
Changes the permissions of a file then resolves the `Promise` with no
arguments upon succces.
-### fs.promises.chown(path, uid, gid)
+### fsPromises.chown(path, uid, gid)
<!-- YAML
added: REPLACEME
-->
@@ -3605,7 +3605,7 @@ added: REPLACEME
Changes the ownership of a file then resolves the `Promise` with no arguments
upon success.
-### fs.promises.copyFile(src, dest[, flags])
+### fsPromises.copyFile(src, dest[, flags])
<!-- YAML
added: REPLACEME
-->
@@ -3632,7 +3632,7 @@ Example:
const fs = require('fs');
// destination.txt will be created or overwritten by default.
-fs.promises.copyFile('source.txt', 'destination.txt')
+fsPromises.copyFile('source.txt', 'destination.txt')
.then(() => console.log('source.txt was copied to destination.txt'))
.catch(() => console.log('The file could not be copied'));
```
@@ -3645,12 +3645,12 @@ const fs = require('fs');
const { COPYFILE_EXCL } = fs.constants;
// By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
-fs.promises.copyFile('source.txt', 'destination.txt', COPYFILE_EXCL)
+fsPromises.copyFile('source.txt', 'destination.txt', COPYFILE_EXCL)
.then(() => console.log('source.txt was copied to destination.txt'))
.catch(() => console.log('The file could not be copied'));
```
-### fs.promises.fchmod(filehandle, mode)
+### fsPromises.fchmod(filehandle, mode)
<!-- YAML
added: REPLACEME
-->
@@ -3662,7 +3662,7 @@ added: REPLACEME
Asynchronous fchmod(2). The `Promise` is resolved with no arguments upon
success.
-### fs.promises.fchown(filehandle, uid, gid)
+### fsPromises.fchown(filehandle, uid, gid)
<!-- YAML
added: REPLACEME
-->
@@ -3675,7 +3675,7 @@ added: REPLACEME
Changes the ownership of the file represented by `filehandle` then resolves
the `Promise` with no arguments upon success.
-### fs.promises.fdatasync(filehandle)
+### fsPromises.fdatasync(filehandle)
<!-- YAML
added: REPLACEME
-->
@@ -3686,7 +3686,7 @@ added: REPLACEME
Asynchronous fdatasync(2). The `Promise` is resolved with no arguments upon
success.
-### fs.promises.fstat(filehandle)
+### fsPromises.fstat(filehandle)
<!-- YAML
added: REPLACEME
-->
@@ -3696,7 +3696,7 @@ added: REPLACEME
Retrieves the [`fs.Stats`][] for the given `filehandle`.
-### fs.promises.fsync(filehandle)
+### fsPromises.fsync(filehandle)
<!-- YAML
added: REPLACEME
-->
@@ -3707,7 +3707,7 @@ added: REPLACEME
Asynchronous fsync(2). The `Promise` is resolved with no arguments upon
success.
-### fs.promises.ftruncate(filehandle[, len])
+### fsPromises.ftruncate(filehandle[, len])
<!-- YAML
added: REPLACEME
-->
@@ -3730,8 +3730,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
// Prints: Node.js
async function doTruncate() {
- const fd = await fs.promises.open('temp.txt', 'r+');
- await fs.promises.ftruncate(fd, 4);
+ const fd = await fsPromises.open('temp.txt', 'r+');
+ await fsPromises.ftruncate(fd, 4);
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints: Node
}
@@ -3746,8 +3746,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
// Prints: Node.js
async function doTruncate() {
- const fd = await fs.promises.open('temp.txt', 'r+');
- await fs.promises.ftruncate(fd, 10);
+ const fd = await fsPromises.open('temp.txt', 'r+');
+ await fsPromises.ftruncate(fd, 10);
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints Node.js\0\0\0
}
@@ -3756,7 +3756,7 @@ doTruncate().catch(console.error);
The last three bytes are null bytes ('\0'), to compensate the over-truncation.
-### fs.promises.futimes(filehandle, atime, mtime)
+### fsPromises.futimes(filehandle, atime, mtime)
<!-- YAML
added: REPLACEME
-->
@@ -3772,7 +3772,7 @@ Change the file system timestamps of the object referenced by the supplied
This function does not work on AIX versions before 7.1, it will resolve the
`Promise` with an error using code `UV_ENOSYS`.
-### fs.promises.lchmod(path, mode)
+### fsPromises.lchmod(path, mode)
<!-- YAML
deprecated: REPLACEME
-->
@@ -3784,7 +3784,7 @@ deprecated: REPLACEME
Changes the permissions on a symbolic link then resolves the `Promise` with
no arguments upon success. This method is only implemented on macOS.
-### fs.promises.lchown(path, uid, gid)
+### fsPromises.lchown(path, uid, gid)
<!-- YAML
deprecated: REPLACEME
-->
@@ -3797,7 +3797,7 @@ deprecated: REPLACEME
Changes the ownership on a symbolic link then resolves the `Promise` with
no arguments upon success. This method is only implemented on macOS.
-### fs.promises.link(existingPath, newPath)
+### fsPromises.link(existingPath, newPath)
<!-- YAML
added: REPLACEME
-->
@@ -3808,7 +3808,7 @@ added: REPLACEME
Asynchronous link(2). The `Promise` is resolved with no arguments upon success.
-### fs.promises.lstat(path)
+### fsPromises.lstat(path)
<!-- YAML
added: REPLACEME
-->
@@ -3819,7 +3819,7 @@ added: REPLACEME
Asynchronous lstat(2). The `Promise` is resolved with the [`fs.Stats`][] object
for the given symbolic link `path`.
-### fs.promises.mkdir(path[, mode])
+### fsPromises.mkdir(path[, mode])
<!-- YAML
added: REPLACEME
-->
@@ -3831,7 +3831,7 @@ added: REPLACEME
Asynchronously creates a directory then resolves the `Promise` with no
arguments upon success.
-### fs.promises.mkdtemp(prefix[, options])
+### fsPromises.mkdtemp(prefix[, options])
<!-- YAML
added: REPLACEME
-->
@@ -3851,7 +3851,7 @@ object with an `encoding` property specifying the character encoding to use.
Example:
```js
-fs.promises.mkdtemp(path.join(os.tmpdir(), 'foo-'))
+fsPromises.mkdtemp(path.join(os.tmpdir(), 'foo-'))
.catch(console.error);
```
@@ -3861,7 +3861,7 @@ intention is to create a temporary directory *within* `/tmp`, the `prefix`
*must* end with a trailing platform-specific path separator
(`require('path').sep`).
-### fs.promises.open(path, flags[, mode])
+### fsPromises.open(path, flags[, mode])
<!-- YAML
added: REPLACEME
-->
@@ -3889,7 +3889,7 @@ An exception occurs if the file does not exist.
the potentially stale local cache. It has a very real impact on I/O
performance so using this flag is not recommended unless it is needed.
- Note that this does not turn `fs.promises.open()` into a synchronous blocking
+ Note that this does not turn `fsPromises.open()` into a synchronous blocking
call.
* `'w'` - Open file for writing.
@@ -3929,7 +3929,7 @@ 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.
-The behavior of `fs.promises.open()` is platform-specific for some
+The behavior of `fsPromises.open()` is platform-specific for some
flags. As such, opening a directory on macOS and Linux with the `'a+'` flag will
return an error. In contrast, on Windows and FreeBSD, a `FileHandle` will be
returned.
@@ -3940,11 +3940,11 @@ a colon, Node.js will open a file system stream, as described by
[this MSDN page][MSDN-Using-Streams].
*Note:* On Windows, opening an existing hidden file using the `w` flag (e.g.
-using `fs.promises.open()`) will fail with `EPERM`. Existing hidden
+using `fsPromises.open()`) will fail with `EPERM`. Existing hidden
files can be opened for writing with the `r+` flag. A call to
-`fs.promises.ftruncate()` can be used to reset the file contents.
+`fsPromises.ftruncate()` can be used to reset the file contents.
-### fs.promises.read(filehandle, buffer, offset, length, position)
+### fsPromises.read(filehandle, buffer, offset, length, position)
<!-- YAML
added: REPLACEME
-->
@@ -3973,7 +3973,7 @@ Following successful read, the `Promise` is resolved with an object with a
`bytesRead` property specifying the number of bytes read, and a `buffer` property
that is a reference to the passed in `buffer` argument.
-### fs.promises.readdir(path[, options])
+### fsPromises.readdir(path[, options])
<!-- YAML
added: REPLACEME
-->
@@ -3991,7 +3991,7 @@ object with an `encoding` property specifying the character encoding to use for
the filenames. If the `encoding` is set to `'buffer'`, the filenames returned
will be passed as `Buffer` objects.
-### fs.promises.readFile(path[, options])
+### fsPromises.readFile(path[, options])
<!-- YAML
added: REPLACEME
-->
@@ -4010,14 +4010,14 @@ object. Otherwise, the data will be a string.
If `options` is a string, then it specifies the encoding.
-When the `path` is a directory, the behavior of `fs.promises.readFile()` is
+When the `path` is a directory, the behavior of `fsPromises.readFile()` is
platform-specific. On macOS, Linux, and Windows, the promise will be rejected
with an error. On FreeBSD, a representation of the directory's contents will be
returned.
Any specified `FileHandle` has to support reading.
-### fs.promises.readlink(path[, options])
+### fsPromises.readlink(path[, options])
<!-- YAML
added: REPLACEME
-->
@@ -4035,7 +4035,7 @@ object with an `encoding` property specifying the character encoding to use for
the link path returned. If the `encoding` is set to `'buffer'`, the link path
returned will be passed as a `Buffer` object.
-### fs.promises.realpath(path[, options])
+### fsPromises.realpath(path[, options])
<!-- YAML
added: REPLACEME
-->
@@ -4060,7 +4060,7 @@ On Linux, when Node.js is linked against musl libc, the procfs file system must
be mounted on `/proc` in order for this function to work. Glibc does not have
this restriction.
-### fs.promises.rename(oldPath, newPath)
+### fsPromises.rename(oldPath, newPath)
<!-- YAML
added: REPLACEME
-->
@@ -4072,7 +4072,7 @@ added: REPLACEME
Renames `oldPath` to `newPath` and resolves the `Promise` with no arguments
upon success.
-### fs.promises.rmdir(path)
+### fsPromises.rmdir(path)
<!-- YAML
added: REPLACEME
-->
@@ -4083,11 +4083,11 @@ added: REPLACEME
Removes the directory identified by `path` then resolves the `Promise` with
no arguments upon success.
-Using `fs.promises.rmdir()` on a file (not a directory) results in the
+Using `fsPromises.rmdir()` on a file (not a directory) results in the
`Promise` being rejected with an `ENOENT` error on Windows and an `ENOTDIR`
error on POSIX.
-### fs.promises.stat(path)
+### fsPromises.stat(path)
<!-- YAML
added: REPLACEME
-->
@@ -4097,7 +4097,7 @@ added: REPLACEME
The `Promise` is resolved with the [`fs.Stats`][] object for the given `path`.
-### fs.promises.symlink(target, path[, type])
+### fsPromises.symlink(target, path[, type])
<!-- YAML
added: REPLACEME
-->
@@ -4115,7 +4115,7 @@ The `type` argument is only used on Windows platforms and can be one of `'dir'`,
points require the destination path to be absolute. When using `'junction'`,
the `target` argument will automatically be normalized to absolute path.
-### fs.promises.truncate(path[, len])
+### fsPromises.truncate(path[, len])
<!-- YAML
added: REPLACEME
-->
@@ -4127,7 +4127,7 @@ added: REPLACEME
Truncates the `path` then resolves the `Promise` with no arguments upon
success. The `path` *must* be a string or `Buffer`.
-### fs.promises.unlink(path)
+### fsPromises.unlink(path)
<!-- YAML
added: REPLACEME
-->
@@ -4138,7 +4138,7 @@ added: REPLACEME
Asynchronous unlink(2). The `Promise` is resolved with no arguments upon
success.
-### fs.promises.utimes(path, atime, mtime)
+### fsPromises.utimes(path, atime, mtime)
<!-- YAML
added: REPLACEME
-->
@@ -4157,7 +4157,7 @@ The `atime` and `mtime` arguments follow these rules:
- If the value can not be converted to a number, or is `NaN`, `Infinity` or
`-Infinity`, an `Error` will be thrown.
-### fs.promises.write(filehandle, buffer[, offset[, length[, position]]])
+### fsPromises.write(filehandle, buffer[, offset[, length[, position]]])
<!-- YAML
added: REPLACEME
-->
@@ -4182,7 +4182,7 @@ an integer specifying the number of bytes to write.
should be written. If `typeof position !== 'number'`, the data will be written
at the current position. See pwrite(2).
-It is unsafe to use `fs.promises.write()` multiple times on the same file
+It is unsafe to use `fsPromises.write()` multiple times on the same file
without waiting for the `Promise` to be resolved (or rejected). For this
scenario, `fs.createWriteStream` is strongly recommended.
@@ -4190,7 +4190,7 @@ 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.
-### fs.promises.writeFile(file, data[, options])
+### fsPromises.writeFile(file, data[, options])
<!-- YAML
added: REPLACEME
-->
@@ -4214,7 +4214,7 @@ If `options` is a string, then it specifies the encoding.
Any specified `FileHandle` has to support writing.
-It is unsafe to use `fs.promises.writeFile()` multiple times on the same file
+It is unsafe to use `fsPromises.writeFile()` multiple times on the same file
without waiting for the `Promise` to be resolved (or rejected).
diff --git a/lib/fs.js b/lib/fs.js
index f787037629..92e8d4fe3e 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -72,9 +72,6 @@ Object.defineProperty(exports, 'constants', {
value: constants
});
-const kHandle = Symbol('handle');
-const { kUsePromises } = binding;
-
const kMinPoolSpace = 128;
const { kMaxLength } = require('buffer');
@@ -2284,459 +2281,3 @@ Object.defineProperty(fs, 'SyncWriteStream', {
set: internalUtil.deprecate((val) => { SyncWriteStream = val; },
'fs.SyncWriteStream is deprecated.', 'DEP0061')
});
-
-// Promises API
-
-class FileHandle {
- constructor(filehandle) {
- this[kHandle] = filehandle;
- }
-
- getAsyncId() {
- return this[kHandle].getAsyncId();
- }
-
- get fd() {
- return this[kHandle].fd;
- }
-
- appendFile(data, options) {
- return promises.appendFile(this, data, options);
- }
-
- chmod(mode) {
- return promises.fchmod(this, mode);
- }
-
- chown(uid, gid) {
- return promises.fchown(this, uid, gid);
- }
-
- datasync() {
- return promises.fdatasync(this);
- }
-
- sync() {
- return promises.fsync(this);
- }
-
-
- read(buffer, offset, length, position) {
- return promises.read(this, buffer, offset, length, position);
- }
-
- readFile(options) {
- return promises.readFile(this, options);
- }
-
- stat() {
- return promises.fstat(this);
- }
-
- truncate(len = 0) {
- return promises.ftruncate(this, len);
- }
-
- utimes(atime, mtime) {
- return promises.futimes(this, atime, mtime);
- }
-
- write(buffer, offset, length, position) {
- return promises.write(this, buffer, offset, length, position);
- }
-
- writeFile(data, options) {
- return promises.writeFile(this, data, options);
- }
-
- close() {
- return this[kHandle].close();
- }
-}
-
-
-function validateFileHandle(handle) {
- if (!(handle instanceof FileHandle))
- throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
- 'filehandle', 'FileHandle');
-}
-
-async function writeFileHandle(filehandle, data, options) {
- let buffer = isUint8Array(data) ?
- data : Buffer.from('' + data, options.encoding || 'utf8');
- let remaining = buffer.length;
- if (remaining === 0) return;
- do {
- const { bytesWritten } =
- await promises.write(filehandle, buffer, 0,
- Math.min(16384, buffer.length));
- remaining -= bytesWritten;
- buffer = buffer.slice(bytesWritten);
- } while (remaining > 0);
-}
-
-async function readFileHandle(filehandle, options) {
- const statFields = await binding.fstat(filehandle.fd, kUsePromises);
-
- let size;
- if ((statFields[1/*mode*/] & S_IFMT) === S_IFREG) {
- size = statFields[8/*size*/];
- } else {
- size = 0;
- }
-
- if (size === 0)
- return Buffer.alloc(0);
-
- if (size > kMaxLength)
- throw new errors.RangeError('ERR_BUFFER_TOO_LARGE');
-
- const chunks = [];
- const chunkSize = Math.min(size, 16384);
- const buf = Buffer.alloc(chunkSize);
- let read = 0;
- do {
- const { bytesRead, buffer } =
- await promises.read(filehandle, buf, 0, buf.length);
- read = bytesRead;
- if (read > 0)
- chunks.push(buffer.slice(0, read));
- } while (read === chunkSize);
-
- return Buffer.concat(chunks);
-}
-
-// All of the functions in fs.promises are defined as async in order to
-// ensure that errors thrown cause promise rejections rather than being
-// thrown synchronously
-const promises = {
- async access(path, mode = fs.F_OK) {
- path = getPathFromURL(path);
- validatePath(path);
-
- mode = mode | 0;
- return binding.access(pathModule.toNamespacedPath(path), mode,
- kUsePromises);
- },
-
- async copyFile(src, dest, flags) {
- src = getPathFromURL(src);
- dest = getPathFromURL(dest);
- validatePath(src, 'src');
- validatePath(dest, 'dest');
- flags = flags | 0;
- return binding.copyFile(pathModule.toNamespacedPath(src),
- pathModule.toNamespacedPath(dest),
- flags, kUsePromises);
- },
-
- // Note that unlike fs.open() which uses numeric file descriptors,
- // promises.open() uses the fs.FileHandle class.
- async open(path, flags, mode) {
- mode = modeNum(mode, 0o666);
- path = getPathFromURL(path);
- validatePath(path);
- validateUint32(mode, 'mode');
- return new FileHandle(
- await binding.openFileHandle(pathModule.toNamespacedPath(path),
- stringToFlags(flags),
- mode, kUsePromises));
- },
-
- async read(handle, buffer, offset, length, position) {
- validateFileHandle(handle);
- validateBuffer(buffer);
-
- offset |= 0;
- length |= 0;
-
- if (length === 0)
- return { bytesRead: length, buffer };
-
- validateOffsetLengthRead(offset, length, buffer.length);
-
- if (!isUint32(position))
- position = -1;
-
- const bytesRead = (await binding.read(handle.fd, buffer, offset, length,
- position, kUsePromises)) || 0;
-
- return { bytesRead, buffer };
- },
-
- async write(handle, buffer, offset, length, position) {
- validateFileHandle(handle);
-
- if (buffer.length === 0)
- return { bytesWritten: 0, buffer };
-
- if (isUint8Array(buffer)) {
- if (typeof offset !== 'number')
- offset = 0;
- if (typeof length !== 'number')
- length = buffer.length - offset;
- if (typeof position !== 'number')
- position = null;
- validateOffsetLengthWrite(offset, length, buffer.byteLength);
- const bytesWritten =
- (await binding.writeBuffer(handle.fd, buffer, offset,
- length, position, kUsePromises)) || 0;
- return { bytesWritten, buffer };
- }
-
- if (typeof buffer !== 'string')
- buffer += '';
- if (typeof position !== 'function') {
- if (typeof offset === 'function') {
- position = offset;
- offset = null;
- } else {
- position = length;
- }
- length = 'utf8';
- }
- const bytesWritten = (await binding.writeString(handle.fd, buffer, offset,
- length, kUsePromises)) || 0;
- return { bytesWritten, buffer };
- },
-
- async rename(oldPath, newPath) {
- oldPath = getPathFromURL(oldPath);
- newPath = getPathFromURL(newPath);
- validatePath(oldPath, 'oldPath');
- validatePath(newPath, 'newPath');
- return binding.rename(pathModule.toNamespacedPath(oldPath),
- pathModule.toNamespacedPath(newPath),
- kUsePromises);
- },
-
- async truncate(path, len = 0) {
- return promises.ftruncate(await promises.open(path, 'r+'), len);
- },
-
- async ftruncate(handle, len = 0) {
- validateFileHandle(handle);
- validateLen(len);
- len = Math.max(0, len);
- return binding.ftruncate(handle.fd, len, kUsePromises);
- },
-
- async rmdir(path) {
- path = getPathFromURL(path);
- validatePath(path);
- return binding.rmdir(pathModule.toNamespacedPath(path), kUsePromises);
- },
-
- async fdatasync(handle) {
- validateFileHandle(handle);
- return binding.fdatasync(handle.fd, kUsePromises);
- },
-
- async fsync(handle) {
- validateFileHandle(handle);
- return binding.fsync(handle.fd, kUsePromises);
- },
-
- async mkdir(path, mode) {
- mode = modeNum(mode, 0o777);
- path = getPathFromURL(path);
- validatePath(path);
- validateUint32(mode, 'mode');
- return binding.mkdir(pathModule.toNamespacedPath(path), mode, kUsePromises);
- },
-
- async readdir(path, options) {
- options = getOptions(options, {});
- path = getPathFromURL(path);
- validatePath(path);
- return binding.readdir(pathModule.toNamespacedPath(path),
- options.encoding, kUsePromises);
- },
-
- async readlink(path, options) {
- options = getOptions(options, {});
- path = getPathFromURL(path);
- validatePath(path, 'oldPath');
- return binding.readlink(pathModule.toNamespacedPath(path),
- options.encoding, kUsePromises);
- },
-
- async symlink(target, path, type_) {
- const type = (typeof type_ === 'string' ? type_ : null);
- target = getPathFromURL(target);
- path = getPathFromURL(path);
- validatePath(target, 'target');
- validatePath(path);
- return binding.symlink(preprocessSymlinkDestination(target, type, path),
- pathModule.toNamespacedPath(path),
- stringToSymlinkType(type),
- kUsePromises);
- },
-
- async fstat(handle) {
- validateFileHandle(handle);
- return statsFromValues(await binding.fstat(handle.fd, kUsePromises));
- },
-
- async lstat(path) {
- path = getPathFromURL(path);
- validatePath(path);
- return statsFromValues(
- await binding.lstat(pathModule.toNamespacedPath(path), kUsePromises));
- },
-
- async stat(path) {
- path = getPathFromURL(path);
- validatePath(path);
- return statsFromValues(
- await binding.stat(pathModule.toNamespacedPath(path), kUsePromises));
- },
-
- async link(existingPath, newPath) {
- existingPath = getPathFromURL(existingPath);
- newPath = getPathFromURL(newPath);
- validatePath(existingPath, 'existingPath');
- validatePath(newPath, 'newPath');
- return binding.link(pathModule.toNamespacedPath(existingPath),
- pathModule.toNamespacedPath(newPath),
- kUsePromises);
- },
-
- async unlink(path) {
- path = getPathFromURL(path);
- validatePath(path);
- return binding.unlink(pathModule.toNamespacedPath(path), kUsePromises);
- },
-
- async fchmod(handle, mode) {
- mode = modeNum(mode);
- validateFileHandle(handle);
- validateUint32(mode, 'mode');
- if (mode < 0 || mode > 0o777)
- throw new errors.RangeError('ERR_OUT_OF_RANGE', 'mode');
- return binding.fchmod(handle.fd, mode, kUsePromises);
- },
-
- async chmod(path, mode) {
- path = getPathFromURL(path);
- validatePath(path);
- mode = modeNum(mode);
- validateUint32(mode, 'mode');
- return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
- },
-
- async lchmod(path, mode) {
- if (constants.O_SYMLINK !== undefined) {
- const fd = await promises.open(path,
- constants.O_WRONLY | constants.O_SYMLINK);
- return promises.fchmod(fd, mode).finally(fd.close.bind(fd));
- }
- throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
- },
-
- async lchown(path, uid, gid) {
- if (constants.O_SYMLINK !== undefined) {
- const fd = await promises.open(path,
- constants.O_WRONLY | constants.O_SYMLINK);
- return promises.fchown(fd, uid, gid).finally(fd.close.bind(fd));
- }
- throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
- },
-
- async fchown(handle, uid, gid) {
- validateFileHandle(handle);
- validateUint32(uid, 'uid');
- validateUint32(gid, 'gid');
- return binding.fchown(handle.fd, uid, gid, kUsePromises);
- },
-
- async chown(path, uid, gid) {
- path = getPathFromURL(path);
- validatePath(path);
- validateUint32(uid, 'uid');
- validateUint32(gid, 'gid');
- return binding.chown(pathModule.toNamespacedPath(path),
- uid, gid, kUsePromises);
- },
-
- async utimes(path, atime, mtime) {
- path = getPathFromURL(path);
- validatePath(path);
- return binding.utimes(pathModule.toNamespacedPath(path),
- toUnixTimestamp(atime),
- toUnixTimestamp(mtime),
- kUsePromises);
- },
-
- async futimes(handle, atime, mtime) {
- validateFileHandle(handle);
- atime = toUnixTimestamp(atime, 'atime');
- mtime = toUnixTimestamp(mtime, 'mtime');
- return binding.futimes(handle.fd, atime, mtime, kUsePromises);
- },
-
- async realpath(path, options) {
- options = getOptions(options, {});
- path = getPathFromURL(path);
- validatePath(path);
- return binding.realpath(path, options.encoding, kUsePromises);
- },
-
- async mkdtemp(prefix, options) {
- options = getOptions(options, {});
- if (!prefix || typeof prefix !== 'string') {
- throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
- 'prefix',
- 'string',
- prefix);
- }
- nullCheck(prefix);
- return binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, kUsePromises);
- },
-
- async writeFile(path, data, options) {
- options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
- const flag = options.flag || 'w';
-
- if (path instanceof FileHandle)
- return writeFileHandle(path, data, options);
-
- const fd = await promises.open(path, flag, options.mode);
- return writeFileHandle(fd, data, options).finally(fd.close.bind(fd));
- },
-
- async appendFile(path, data, options) {
- options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
- options = copyObject(options);
- options.flag = options.flag || 'a';
- return promises.writeFile(path, data, options);
- },
-
- async readFile(path, options) {
- options = getOptions(options, { flag: 'r' });
-
- if (path instanceof FileHandle)
- return readFileHandle(path, options);
-
- const fd = await promises.open(path, options.flag, 0o666);
- return readFileHandle(fd, options).finally(fd.close.bind(fd));
- }
-};
-
-let warn = true;
-
-// TODO(jasnell): Exposing this as a property with a getter works fine with
-// commonjs but is going to be problematic for named imports support under
-// ESM. A different approach will have to be followed there.
-Object.defineProperty(fs, 'promises', {
- configurable: true,
- enumerable: true,
- get() {
- if (warn) {
- warn = false;
- process.emitWarning('The fs.promises API is experimental',
- 'ExperimentalWarning');
- }
- return promises;
- }
-});
diff --git a/lib/fs/promises.js b/lib/fs/promises.js
new file mode 100644
index 0000000000..8cbcd963c7
--- /dev/null
+++ b/lib/fs/promises.js
@@ -0,0 +1,507 @@
+'use strict';
+
+process.emitWarning('The fs/promises API is experimental',
+ 'ExperimentalWarning');
+
+const {
+ F_OK,
+ O_SYMLINK,
+ O_WRONLY,
+ S_IFMT,
+ S_IFREG
+} = process.binding('constants').fs;
+const binding = process.binding('fs');
+const { Buffer, kMaxLength } = require('buffer');
+const errors = require('internal/errors');
+const { getPathFromURL } = require('internal/url');
+const { isUint8Array } = require('internal/util/types');
+const {
+ copyObject,
+ getOptions,
+ isUint32,
+ modeNum,
+ nullCheck,
+ preprocessSymlinkDestination,
+ statsFromValues,
+ stringToFlags,
+ stringToSymlinkType,
+ toUnixTimestamp,
+ validateBuffer,
+ validateLen,
+ validateOffsetLengthRead,
+ validateOffsetLengthWrite,
+ validatePath,
+ validateUint32
+} = require('internal/fs');
+const pathModule = require('path');
+
+const kHandle = Symbol('handle');
+const { kUsePromises } = binding;
+
+class FileHandle {
+ constructor(filehandle) {
+ this[kHandle] = filehandle;
+ }
+
+ getAsyncId() {
+ return this[kHandle].getAsyncId();
+ }
+
+ get fd() {
+ return this[kHandle].fd;
+ }
+
+ appendFile(data, options) {
+ return appendFile(this, data, options);
+ }
+
+ chmod(mode) {
+ return fchmod(this, mode);
+ }
+
+ chown(uid, gid) {
+ return fchown(this, uid, gid);
+ }
+
+ datasync() {
+ return fdatasync(this);
+ }
+
+ sync() {
+ return fsync(this);
+ }
+
+ read(buffer, offset, length, position) {
+ return read(this, buffer, offset, length, position);
+ }
+
+ readFile(options) {
+ return readFile(this, options);
+ }
+
+ stat() {
+ return fstat(this);
+ }
+
+ truncate(len = 0) {
+ return ftruncate(this, len);
+ }
+
+ utimes(atime, mtime) {
+ return futimes(this, atime, mtime);
+ }
+
+ write(buffer, offset, length, position) {
+ return write(this, buffer, offset, length, position);
+ }
+
+ writeFile(data, options) {
+ return writeFile(this, data, options);
+ }
+
+ close() {
+ return this[kHandle].close();
+ }
+}
+
+
+function validateFileHandle(handle) {
+ if (!(handle instanceof FileHandle))
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ 'filehandle', 'FileHandle');
+}
+
+async function writeFileHandle(filehandle, data, options) {
+ let buffer = isUint8Array(data) ?
+ data : Buffer.from('' + data, options.encoding || 'utf8');
+ let remaining = buffer.length;
+ if (remaining === 0) return;
+ do {
+ const { bytesWritten } =
+ await write(filehandle, buffer, 0,
+ Math.min(16384, buffer.length));
+ remaining -= bytesWritten;
+ buffer = buffer.slice(bytesWritten);
+ } while (remaining > 0);
+}
+
+async function readFileHandle(filehandle, options) {
+ const statFields = await binding.fstat(filehandle.fd, kUsePromises);
+
+ let size;
+ if ((statFields[1/*mode*/] & S_IFMT) === S_IFREG) {
+ size = statFields[8/*size*/];
+ } else {
+ size = 0;
+ }
+
+ if (size === 0)
+ return Buffer.alloc(0);
+
+ if (size > kMaxLength)
+ throw new errors.RangeError('ERR_BUFFER_TOO_LARGE');
+
+ const chunks = [];
+ const chunkSize = Math.min(size, 16384);
+ const buf = Buffer.alloc(chunkSize);
+ let totalRead = 0;
+ do {
+ const { bytesRead, buffer } =
+ await read(filehandle, buf, 0, buf.length);
+ totalRead = bytesRead;
+ if (totalRead > 0)
+ chunks.push(buffer.slice(0, totalRead));
+ } while (totalRead === chunkSize);
+
+ return Buffer.concat(chunks);
+}
+
+// All of the functions are defined as async in order to ensure that errors
+// thrown cause promise rejections rather than being thrown synchronously.
+async function access(path, mode = F_OK) {
+ path = getPathFromURL(path);
+ validatePath(path);
+
+ mode = mode | 0;
+ return binding.access(pathModule.toNamespacedPath(path), mode,
+ kUsePromises);
+}
+
+async function copyFile(src, dest, flags) {
+ src = getPathFromURL(src);
+ dest = getPathFromURL(dest);
+ validatePath(src, 'src');
+ validatePath(dest, 'dest');
+ flags = flags | 0;
+ return binding.copyFile(pathModule.toNamespacedPath(src),
+ pathModule.toNamespacedPath(dest),
+ flags, kUsePromises);
+}
+
+// Note that unlike fs.open() which uses numeric file descriptors,
+// fsPromises.open() uses the fs.FileHandle class.
+async function open(path, flags, mode) {
+ mode = modeNum(mode, 0o666);
+ path = getPathFromURL(path);
+ validatePath(path);
+ validateUint32(mode, 'mode');
+ return new FileHandle(
+ await binding.openFileHandle(pathModule.toNamespacedPath(path),
+ stringToFlags(flags),
+ mode, kUsePromises));
+}
+
+async function read(handle, buffer, offset, length, position) {
+ validateFileHandle(handle);
+ validateBuffer(buffer);
+
+ offset |= 0;
+ length |= 0;
+
+ if (length === 0)
+ return { bytesRead: length, buffer };
+
+ validateOffsetLengthRead(offset, length, buffer.length);
+
+ if (!isUint32(position))
+ position = -1;
+
+ const bytesRead = (await binding.read(handle.fd, buffer, offset, length,
+ position, kUsePromises)) || 0;
+
+ return { bytesRead, buffer };
+}
+
+async function write(handle, buffer, offset, length, position) {
+ validateFileHandle(handle);
+
+ if (buffer.length === 0)
+ return { bytesWritten: 0, buffer };
+
+ if (isUint8Array(buffer)) {
+ if (typeof offset !== 'number')
+ offset = 0;
+ if (typeof length !== 'number')
+ length = buffer.length - offset;
+ if (typeof position !== 'number')
+ position = null;
+ validateOffsetLengthWrite(offset, length, buffer.byteLength);
+ const bytesWritten =
+ (await binding.writeBuffer(handle.fd, buffer, offset,
+ length, position, kUsePromises)) || 0;
+ return { bytesWritten, buffer };
+ }
+
+ if (typeof buffer !== 'string')
+ buffer += '';
+ if (typeof position !== 'function') {
+ if (typeof offset === 'function') {
+ position = offset;
+ offset = null;
+ } else {
+ position = length;
+ }
+ length = 'utf8';
+ }
+ const bytesWritten = (await binding.writeString(handle.fd, buffer, offset,
+ length, kUsePromises)) || 0;
+ return { bytesWritten, buffer };
+}
+
+async function rename(oldPath, newPath) {
+ oldPath = getPathFromURL(oldPath);
+ newPath = getPathFromURL(newPath);
+ validatePath(oldPath, 'oldPath');
+ validatePath(newPath, 'newPath');
+ return binding.rename(pathModule.toNamespacedPath(oldPath),
+ pathModule.toNamespacedPath(newPath),
+ kUsePromises);
+}
+
+async function truncate(path, len = 0) {
+ return ftruncate(await open(path, 'r+'), len);
+}
+
+async function ftruncate(handle, len = 0) {
+ validateFileHandle(handle);
+ validateLen(len);
+ len = Math.max(0, len);
+ return binding.ftruncate(handle.fd, len, kUsePromises);
+}
+
+async function rmdir(path) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ return binding.rmdir(pathModule.toNamespacedPath(path), kUsePromises);
+}
+
+async function fdatasync(handle) {
+ validateFileHandle(handle);
+ return binding.fdatasync(handle.fd, kUsePromises);
+}
+
+async function fsync(handle) {
+ validateFileHandle(handle);
+ return binding.fsync(handle.fd, kUsePromises);
+}
+
+async function mkdir(path, mode) {
+ mode = modeNum(mode, 0o777);
+ path = getPathFromURL(path);
+ validatePath(path);
+ validateUint32(mode, 'mode');
+ return binding.mkdir(pathModule.toNamespacedPath(path), mode, kUsePromises);
+}
+
+async function readdir(path, options) {
+ options = getOptions(options, {});
+ path = getPathFromURL(path);
+ validatePath(path);
+ return binding.readdir(pathModule.toNamespacedPath(path),
+ options.encoding, kUsePromises);
+}
+
+async function readlink(path, options) {
+ options = getOptions(options, {});
+ path = getPathFromURL(path);
+ validatePath(path, 'oldPath');
+ return binding.readlink(pathModule.toNamespacedPath(path),
+ options.encoding, kUsePromises);
+}
+
+async function symlink(target, path, type_) {
+ const type = (typeof type_ === 'string' ? type_ : null);
+ target = getPathFromURL(target);
+ path = getPathFromURL(path);
+ validatePath(target, 'target');
+ validatePath(path);
+ return binding.symlink(preprocessSymlinkDestination(target, type, path),
+ pathModule.toNamespacedPath(path),
+ stringToSymlinkType(type),
+ kUsePromises);
+}
+
+async function fstat(handle) {
+ validateFileHandle(handle);
+ return statsFromValues(await binding.fstat(handle.fd, kUsePromises));
+}
+
+async function lstat(path) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ return statsFromValues(
+ await binding.lstat(pathModule.toNamespacedPath(path), kUsePromises));
+}
+
+async function stat(path) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ return statsFromValues(
+ await binding.stat(pathModule.toNamespacedPath(path), kUsePromises));
+}
+
+async function link(existingPath, newPath) {
+ existingPath = getPathFromURL(existingPath);
+ newPath = getPathFromURL(newPath);
+ validatePath(existingPath, 'existingPath');
+ validatePath(newPath, 'newPath');
+ return binding.link(pathModule.toNamespacedPath(existingPath),
+ pathModule.toNamespacedPath(newPath),
+ kUsePromises);
+}
+
+async function unlink(path) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ return binding.unlink(pathModule.toNamespacedPath(path), kUsePromises);
+}
+
+async function fchmod(handle, mode) {
+ mode = modeNum(mode);
+ validateFileHandle(handle);
+ validateUint32(mode, 'mode');
+ if (mode < 0 || mode > 0o777)
+ throw new errors.RangeError('ERR_OUT_OF_RANGE', 'mode');
+ return binding.fchmod(handle.fd, mode, kUsePromises);
+}
+
+async function chmod(path, mode) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ mode = modeNum(mode);
+ validateUint32(mode, 'mode');
+ return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
+}
+
+async function lchmod(path, mode) {
+ if (O_SYMLINK !== undefined) {
+ const fd = await open(path,
+ O_WRONLY | O_SYMLINK);
+ return fchmod(fd, mode).finally(fd.close.bind(fd));
+ }
+ throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
+}
+
+async function lchown(path, uid, gid) {
+ if (O_SYMLINK !== undefined) {
+ const fd = await open(path,
+ O_WRONLY | O_SYMLINK);
+ return fchmod(fd, uid, gid).finally(fd.close.bind(fd));
+ }
+ throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
+}
+
+async function fchown(handle, uid, gid) {
+ validateFileHandle(handle);
+ validateUint32(uid, 'uid');
+ validateUint32(gid, 'gid');
+ return binding.fchown(handle.fd, uid, gid, kUsePromises);
+}
+
+async function chown(path, uid, gid) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ validateUint32(uid, 'uid');
+ validateUint32(gid, 'gid');
+ return binding.chown(pathModule.toNamespacedPath(path),
+ uid, gid, kUsePromises);
+}
+
+async function utimes(path, atime, mtime) {
+ path = getPathFromURL(path);
+ validatePath(path);
+ return binding.utimes(pathModule.toNamespacedPath(path),
+ toUnixTimestamp(atime),
+ toUnixTimestamp(mtime),
+ kUsePromises);
+}
+
+async function futimes(handle, atime, mtime) {
+ validateFileHandle(handle);
+ atime = toUnixTimestamp(atime, 'atime');
+ mtime = toUnixTimestamp(mtime, 'mtime');
+ return binding.futimes(handle.fd, atime, mtime, kUsePromises);
+}
+
+async function realpath(path, options) {
+ options = getOptions(options, {});
+ path = getPathFromURL(path);
+ validatePath(path);
+ return binding.realpath(path, options.encoding, kUsePromises);
+}
+
+async function mkdtemp(prefix, options) {
+ options = getOptions(options, {});
+ if (!prefix || typeof prefix !== 'string') {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ 'prefix',
+ 'string',
+ prefix);
+ }
+ nullCheck(prefix);
+ return binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, kUsePromises);
+}
+
+async function writeFile(path, data, options) {
+ options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
+ const flag = options.flag || 'w';
+
+ if (path instanceof FileHandle)
+ return writeFileHandle(path, data, options);
+
+ const fd = await open(path, flag, options.mode);
+ return writeFileHandle(fd, data, options).finally(fd.close.bind(fd));
+}
+
+async function appendFile(path, data, options) {
+ options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
+ options = copyObject(options);
+ options.flag = options.flag || 'a';
+ return writeFile(path, data, options);
+}
+
+async function readFile(path, options) {
+ options = getOptions(options, { flag: 'r' });
+
+ if (path instanceof FileHandle)
+ return readFileHandle(path, options);
+
+ const fd = await open(path, options.flag, 0o666);
+ return readFileHandle(fd, options).finally(fd.close.bind(fd));
+}
+
+module.exports = {
+ access,
+ copyFile,
+ open,
+ read,
+ write,
+ rename,
+ truncate,
+ ftruncate,
+ rmdir,
+ fdatasync,
+ fsync,
+ mkdir,
+ readdir,
+ readlink,
+ symlink,
+ fstat,
+ lstat,
+ stat,
+ link,
+ unlink,
+ fchmod,
+ chmod,
+ lchmod,
+ lchown,
+ fchown,
+ chown,
+ utimes,
+ futimes,
+ realpath,
+ mkdtemp,
+ writeFile,
+ appendFile,
+ readFile
+};
diff --git a/node.gyp b/node.gyp
index 8e41cc053d..08eee42856 100644
--- a/node.gyp
+++ b/node.gyp
@@ -39,6 +39,7 @@
'lib/domain.js',
'lib/events.js',
'lib/fs.js',
+ 'lib/fs/promises.js',
'lib/http.js',
'lib/http2.js',
'lib/_http_agent.js',
diff --git a/test/parallel/test-fs-promises-writefile.js b/test/parallel/test-fs-promises-writefile.js
index 655dc73a1d..e2ae289b18 100644
--- a/test/parallel/test-fs-promises-writefile.js
+++ b/test/parallel/test-fs-promises-writefile.js
@@ -2,6 +2,7 @@
const common = require('../common');
const fs = require('fs');
+const fsPromises = require('fs/promises');
const path = require('path');
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
@@ -16,20 +17,20 @@ const buffer = Buffer.from('abc'.repeat(1000));
const buffer2 = Buffer.from('xyz'.repeat(1000));
async function doWrite() {
- await fs.promises.writeFile(dest, buffer);
+ await fsPromises.writeFile(dest, buffer);
const data = fs.readFileSync(dest);
assert.deepStrictEqual(data, buffer);
}
async function doAppend() {
- await fs.promises.appendFile(dest, buffer2);
+ await fsPromises.appendFile(dest, buffer2);
const data = fs.readFileSync(dest);
const buf = Buffer.concat([buffer, buffer2]);
assert.deepStrictEqual(buf, data);
}
async function doRead() {
- const data = await fs.promises.readFile(dest);
+ const data = await fsPromises.readFile(dest);
const buf = fs.readFileSync(dest);
assert.deepStrictEqual(buf, data);
}
diff --git a/test/parallel/test-fs-promises.js b/test/parallel/test-fs-promises.js
index 5d493208ff..e24374602b 100644
--- a/test/parallel/test-fs-promises.js
+++ b/test/parallel/test-fs-promises.js
@@ -5,7 +5,7 @@ const assert = require('assert');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const path = require('path');
-const fs = require('fs');
+const fsPromises = require('fs/promises');
const {
access,
chmod,
@@ -32,7 +32,7 @@ const {
write,
unlink,
utimes
-} = fs.promises;
+} = fsPromises;
const tmpDir = tmpdir.path;
diff --git a/test/sequential/test-async-wrap-getasyncid.js b/test/sequential/test-async-wrap-getasyncid.js
index 2db6ba9db6..1877d53dbf 100644
--- a/test/sequential/test-async-wrap-getasyncid.js
+++ b/test/sequential/test-async-wrap-getasyncid.js
@@ -3,6 +3,7 @@
const common = require('../common');
const assert = require('assert');
const fs = require('fs');
+const fsPromises = require('fs/promises');
const net = require('net');
const providers = Object.assign({}, process.binding('async_wrap').Providers);
const fixtures = require('../common/fixtures');
@@ -171,7 +172,7 @@ if (common.hasCrypto) { // eslint-disable-line crypto-check
{
async function openTest() {
- const fd = await fs.promises.open(__filename, 'r');
+ const fd = await fsPromises.open(__filename, 'r');
testInitialized(fd, 'FileHandle');
await fd.close();
}