From 513d9397202b46fb10da41d88ddb747417f8b870 Mon Sep 17 00:00:00 2001 From: Michaƫl Zasso Date: Wed, 14 Feb 2018 10:04:22 +0100 Subject: fs: move fs.promises API to fs/promises PR-URL: https://github.com/nodejs/node/pull/18777 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Gus Caplan Reviewed-By: James M Snell Reviewed-By: Joyee Cheung --- lib/fs.js | 459 -------------------------------------------------------------- 1 file changed, 459 deletions(-) (limited to 'lib/fs.js') 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; - } -}); -- cgit v1.2.3