summaryrefslogtreecommitdiff
path: root/lib
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 /lib
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>
Diffstat (limited to 'lib')
-rw-r--r--lib/fs.js459
-rw-r--r--lib/fs/promises.js507
2 files changed, 507 insertions, 459 deletions
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
+};