mirror of
https://github.com/nodejs/node.git
synced 2025-08-16 06:08:50 +02:00
fs: add initial set of fs.promises APIs
Initial set of fs.promises APIs with documentation and one benchmark. PR-URL: https://github.com/nodejs/node/pull/18297 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
85b37db684
commit
329fc78e49
10 changed files with 1957 additions and 187 deletions
28
benchmark/fs/bench-stat-promise.js
Normal file
28
benchmark/fs/bench-stat-promise.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
n: [20e4],
|
||||||
|
statType: ['fstat', 'lstat', 'stat']
|
||||||
|
});
|
||||||
|
|
||||||
|
async function run(n, statType) {
|
||||||
|
const arg = statType === 'fstat' ?
|
||||||
|
await fs.promises.open(__filename, 'r') : __filename;
|
||||||
|
let remaining = n;
|
||||||
|
bench.start();
|
||||||
|
while (remaining-- > 0)
|
||||||
|
await fs.promises[statType](arg);
|
||||||
|
bench.end(n);
|
||||||
|
|
||||||
|
if (typeof arg.close === 'function')
|
||||||
|
await arg.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
const n = conf.n >>> 0;
|
||||||
|
const statType = conf.statType;
|
||||||
|
run(n, statType).catch(console.log);
|
||||||
|
}
|
992
doc/api/fs.md
992
doc/api/fs.md
File diff suppressed because it is too large
Load diff
492
lib/fs.js
492
lib/fs.js
|
@ -53,6 +53,9 @@ Object.defineProperty(exports, 'constants', {
|
||||||
value: constants
|
value: constants
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const kHandle = Symbol('handle');
|
||||||
|
const { kUsePromises } = binding;
|
||||||
|
|
||||||
const kMinPoolSpace = 128;
|
const kMinPoolSpace = 128;
|
||||||
const { kMaxLength } = require('buffer');
|
const { kMaxLength } = require('buffer');
|
||||||
|
|
||||||
|
@ -343,13 +346,11 @@ Stats.prototype.isSocket = function() {
|
||||||
|
|
||||||
const statValues = binding.statValues;
|
const statValues = binding.statValues;
|
||||||
|
|
||||||
function statsFromValues() {
|
function statsFromValues(stats = statValues) {
|
||||||
return new Stats(statValues[0], statValues[1], statValues[2], statValues[3],
|
return new Stats(stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
|
||||||
statValues[4], statValues[5],
|
stats[6] < 0 ? undefined : stats[6], stats[7], stats[8],
|
||||||
statValues[6] < 0 ? undefined : statValues[6], statValues[7],
|
stats[9] < 0 ? undefined : stats[9], stats[10], stats[11],
|
||||||
statValues[8], statValues[9] < 0 ? undefined : statValues[9],
|
stats[12], stats[13]);
|
||||||
statValues[10], statValues[11], statValues[12],
|
|
||||||
statValues[13]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow mode to accidentally be overwritten.
|
// Don't allow mode to accidentally be overwritten.
|
||||||
|
@ -2654,3 +2655,480 @@ Object.defineProperty(fs, 'SyncWriteStream', {
|
||||||
set: internalUtil.deprecate((val) => { SyncWriteStream = val; },
|
set: internalUtil.deprecate((val) => { SyncWriteStream = val; },
|
||||||
'fs.SyncWriteStream is deprecated.', 'DEP0061')
|
'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) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(path);
|
||||||
|
validatePath(path);
|
||||||
|
|
||||||
|
mode = mode | 0;
|
||||||
|
return binding.access(pathModule.toNamespacedPath(path), mode,
|
||||||
|
kUsePromises);
|
||||||
|
},
|
||||||
|
|
||||||
|
async copyFile(src, dest, flags) {
|
||||||
|
handleError((src = getPathFromURL(src)));
|
||||||
|
handleError((dest = getPathFromURL(dest)));
|
||||||
|
nullCheck(src);
|
||||||
|
nullCheck(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);
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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) {
|
||||||
|
handleError((oldPath = getPathFromURL(oldPath)));
|
||||||
|
handleError((newPath = getPathFromURL(newPath)));
|
||||||
|
nullCheck(oldPath);
|
||||||
|
nullCheck(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) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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);
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(path);
|
||||||
|
validatePath(path);
|
||||||
|
validateUint32(mode, 'mode');
|
||||||
|
return binding.mkdir(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
||||||
|
},
|
||||||
|
|
||||||
|
async readdir(path, options) {
|
||||||
|
options = getOptions(options, {});
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(path);
|
||||||
|
validatePath(path);
|
||||||
|
return binding.readdir(pathModule.toNamespacedPath(path),
|
||||||
|
options.encoding, kUsePromises);
|
||||||
|
},
|
||||||
|
|
||||||
|
async readlink(path, options) {
|
||||||
|
options = getOptions(options, {});
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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);
|
||||||
|
handleError((target = getPathFromURL(target)));
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(target);
|
||||||
|
nullCheck(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) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(path);
|
||||||
|
validatePath(path);
|
||||||
|
return statsFromValues(
|
||||||
|
await binding.lstat(pathModule.toNamespacedPath(path), kUsePromises));
|
||||||
|
},
|
||||||
|
|
||||||
|
async stat(path) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(path);
|
||||||
|
validatePath(path);
|
||||||
|
return statsFromValues(
|
||||||
|
await binding.stat(pathModule.toNamespacedPath(path), kUsePromises));
|
||||||
|
},
|
||||||
|
|
||||||
|
async link(existingPath, newPath) {
|
||||||
|
handleError((existingPath = getPathFromURL(existingPath)));
|
||||||
|
handleError((newPath = getPathFromURL(newPath)));
|
||||||
|
nullCheck(existingPath);
|
||||||
|
nullCheck(newPath);
|
||||||
|
validatePath(existingPath, 'existingPath');
|
||||||
|
validatePath(newPath, 'newPath');
|
||||||
|
return binding.link(pathModule.toNamespacedPath(existingPath),
|
||||||
|
pathModule.toNamespacedPath(newPath),
|
||||||
|
kUsePromises);
|
||||||
|
},
|
||||||
|
|
||||||
|
async unlink(path) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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.fschmod(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.fschmod(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) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(path);
|
||||||
|
validatePath(path);
|
||||||
|
validateUint32(uid, 'uid');
|
||||||
|
validateUint32(gid, 'gid');
|
||||||
|
return binding.chown(pathModule.toNamespacedPath(path),
|
||||||
|
uid, gid, kUsePromises);
|
||||||
|
},
|
||||||
|
|
||||||
|
async utimes(path, atime, mtime) {
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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, {});
|
||||||
|
handleError((path = getPathFromURL(path)));
|
||||||
|
nullCheck(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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -242,7 +242,6 @@ class ModuleWrap;
|
||||||
V(sni_context_string, "sni_context") \
|
V(sni_context_string, "sni_context") \
|
||||||
V(stack_string, "stack") \
|
V(stack_string, "stack") \
|
||||||
V(status_string, "status") \
|
V(status_string, "status") \
|
||||||
V(statfields_string, "statFields") \
|
|
||||||
V(stdio_string, "stdio") \
|
V(stdio_string, "stdio") \
|
||||||
V(subject_string, "subject") \
|
V(subject_string, "subject") \
|
||||||
V(subjectaltname_string, "subjectaltname") \
|
V(subjectaltname_string, "subjectaltname") \
|
||||||
|
@ -284,6 +283,7 @@ class ModuleWrap;
|
||||||
V(context, v8::Context) \
|
V(context, v8::Context) \
|
||||||
V(domain_callback, v8::Function) \
|
V(domain_callback, v8::Function) \
|
||||||
V(fd_constructor_template, v8::ObjectTemplate) \
|
V(fd_constructor_template, v8::ObjectTemplate) \
|
||||||
|
V(fsreqpromise_constructor_template, v8::ObjectTemplate) \
|
||||||
V(fdclose_constructor_template, v8::ObjectTemplate) \
|
V(fdclose_constructor_template, v8::ObjectTemplate) \
|
||||||
V(host_import_module_dynamically_callback, v8::Function) \
|
V(host_import_module_dynamically_callback, v8::Function) \
|
||||||
V(host_initialize_import_meta_object_callback, v8::Function) \
|
V(host_initialize_import_meta_object_callback, v8::Function) \
|
||||||
|
@ -313,6 +313,7 @@ class ModuleWrap;
|
||||||
V(vm_parsing_context_symbol, v8::Symbol) \
|
V(vm_parsing_context_symbol, v8::Symbol) \
|
||||||
V(url_constructor_function, v8::Function) \
|
V(url_constructor_function, v8::Function) \
|
||||||
V(write_wrap_constructor_function, v8::Function) \
|
V(write_wrap_constructor_function, v8::Function) \
|
||||||
|
V(fs_use_promises_symbol, v8::Symbol)
|
||||||
|
|
||||||
class Environment;
|
class Environment;
|
||||||
|
|
||||||
|
|
392
src/node_file.cc
392
src/node_file.cc
|
@ -85,6 +85,7 @@ namespace fs {
|
||||||
|
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
|
using v8::EscapableHandleScope;
|
||||||
using v8::Float64Array;
|
using v8::Float64Array;
|
||||||
using v8::Function;
|
using v8::Function;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
|
@ -100,6 +101,7 @@ using v8::Object;
|
||||||
using v8::ObjectTemplate;
|
using v8::ObjectTemplate;
|
||||||
using v8::Promise;
|
using v8::Promise;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
|
using v8::Symbol;
|
||||||
using v8::Undefined;
|
using v8::Undefined;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
|
@ -169,7 +171,7 @@ inline void FileHandle::Close() {
|
||||||
|
|
||||||
// If the close was successful, we still want to emit a process warning
|
// If the close was successful, we still want to emit a process warning
|
||||||
// to notify that the file descriptor was gc'd. We want to be noisy about
|
// to notify that the file descriptor was gc'd. We want to be noisy about
|
||||||
// this because not explicitly closing the garbage collector is a bug.
|
// this because not explicitly closing the FileHandle is a bug.
|
||||||
env()->SetUnrefImmediate([](Environment* env, void* data) {
|
env()->SetUnrefImmediate([](Environment* env, void* data) {
|
||||||
char msg[70];
|
char msg[70];
|
||||||
err_detail* detail = static_cast<err_detail*>(data);
|
err_detail* detail = static_cast<err_detail*>(data);
|
||||||
|
@ -182,22 +184,22 @@ inline void FileHandle::Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileHandle::CloseReq::Resolve() {
|
void FileHandle::CloseReq::Resolve() {
|
||||||
InternalCallbackScope callback_scope(this);
|
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
|
InternalCallbackScope callback_scope(this);
|
||||||
Local<Promise> promise = promise_.Get(env()->isolate());
|
Local<Promise> promise = promise_.Get(env()->isolate());
|
||||||
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
||||||
resolver->Resolve(env()->context(), Undefined(env()->isolate()));
|
resolver->Resolve(env()->context(), Undefined(env()->isolate())).FromJust();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileHandle::CloseReq::Reject(Local<Value> reason) {
|
void FileHandle::CloseReq::Reject(Local<Value> reason) {
|
||||||
InternalCallbackScope callback_scope(this);
|
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
|
InternalCallbackScope callback_scope(this);
|
||||||
Local<Promise> promise = promise_.Get(env()->isolate());
|
Local<Promise> promise = promise_.Get(env()->isolate());
|
||||||
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
||||||
resolver->Reject(env()->context(), reason);
|
resolver->Reject(env()->context(), reason).FromJust();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHandle* FileHandle::CloseReq::fd() {
|
FileHandle* FileHandle::CloseReq::file_handle() {
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
Local<Value> val = ref_.Get(env()->isolate());
|
Local<Value> val = ref_.Get(env()->isolate());
|
||||||
Local<Object> obj = val.As<Object>();
|
Local<Object> obj = val.As<Object>();
|
||||||
|
@ -209,9 +211,9 @@ FileHandle* FileHandle::CloseReq::fd() {
|
||||||
// there was a problem closing the fd. This is the preferred mechanism for
|
// there was a problem closing the fd. This is the preferred mechanism for
|
||||||
// closing the FD object even tho the object will attempt to close
|
// closing the FD object even tho the object will attempt to close
|
||||||
// automatically on gc.
|
// automatically on gc.
|
||||||
inline Local<Promise> FileHandle::ClosePromise() {
|
inline MaybeLocal<Promise> FileHandle::ClosePromise() {
|
||||||
Isolate* isolate = env()->isolate();
|
Isolate* isolate = env()->isolate();
|
||||||
HandleScope scope(isolate);
|
EscapableHandleScope scope(isolate);
|
||||||
Local<Context> context = env()->context();
|
Local<Context> context = env()->context();
|
||||||
auto maybe_resolver = Promise::Resolver::New(context);
|
auto maybe_resolver = Promise::Resolver::New(context);
|
||||||
CHECK(!maybe_resolver.IsEmpty());
|
CHECK(!maybe_resolver.IsEmpty());
|
||||||
|
@ -223,12 +225,12 @@ inline Local<Promise> FileHandle::ClosePromise() {
|
||||||
auto AfterClose = [](uv_fs_t* req) {
|
auto AfterClose = [](uv_fs_t* req) {
|
||||||
CloseReq* close = static_cast<CloseReq*>(req->data);
|
CloseReq* close = static_cast<CloseReq*>(req->data);
|
||||||
CHECK_NE(close, nullptr);
|
CHECK_NE(close, nullptr);
|
||||||
close->fd()->closing_ = false;
|
close->file_handle()->closing_ = false;
|
||||||
Isolate* isolate = close->env()->isolate();
|
Isolate* isolate = close->env()->isolate();
|
||||||
if (req->result < 0) {
|
if (req->result < 0) {
|
||||||
close->Reject(UVException(isolate, req->result, "close"));
|
close->Reject(UVException(isolate, req->result, "close"));
|
||||||
} else {
|
} else {
|
||||||
close->fd()->closed_ = true;
|
close->file_handle()->closed_ = true;
|
||||||
close->Resolve();
|
close->Resolve();
|
||||||
}
|
}
|
||||||
delete close;
|
delete close;
|
||||||
|
@ -241,15 +243,16 @@ inline Local<Promise> FileHandle::ClosePromise() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Already closed. Just reject the promise immediately
|
// Already closed. Just reject the promise immediately
|
||||||
resolver->Reject(context, UVException(isolate, UV_EBADF, "close"));
|
resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
|
||||||
|
.FromJust();
|
||||||
}
|
}
|
||||||
return promise;
|
return scope.Escape(promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
|
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
|
||||||
FileHandle* fd;
|
FileHandle* fd;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
|
||||||
args.GetReturnValue().Set(fd->ClosePromise());
|
args.GetReturnValue().Set(fd->ClosePromise().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -273,24 +276,31 @@ void FSReqWrap::Resolve(Local<Value> value) {
|
||||||
MakeCallback(env()->oncomplete_string(), arraysize(argv), argv);
|
MakeCallback(env()->oncomplete_string(), arraysize(argv), argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FSReqWrap::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
args.GetReturnValue().SetUndefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSReqPromise::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Local<Context> context = env()->context();
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
object()->Get(context, env()->promise_string()).ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
|
void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args.IsConstructCall());
|
CHECK(args.IsConstructCall());
|
||||||
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
||||||
new FSReqWrap(env, args.This());
|
new FSReqWrap(env, args.This());
|
||||||
}
|
}
|
||||||
|
|
||||||
FSReqPromise::FSReqPromise(Environment* env, Local<Object> req)
|
FSReqPromise::FSReqPromise(Environment* env)
|
||||||
: FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQPROMISE) {
|
: FSReqBase(env,
|
||||||
|
env->fsreqpromise_constructor_template()
|
||||||
|
->NewInstance(env->context()).ToLocalChecked(),
|
||||||
|
AsyncWrap::PROVIDER_FSREQPROMISE),
|
||||||
|
stats_field_array_(env->isolate(), 14) {
|
||||||
auto resolver = Promise::Resolver::New(env->context()).ToLocalChecked();
|
auto resolver = Promise::Resolver::New(env->context()).ToLocalChecked();
|
||||||
req->Set(env->context(), env->promise_string(),
|
object()->Set(env->context(), env->promise_string(),
|
||||||
resolver.As<Promise>()).FromJust();
|
resolver.As<Promise>()).FromJust();
|
||||||
|
|
||||||
Local<ArrayBuffer> ab =
|
|
||||||
ArrayBuffer::New(env->isolate(), statFields_,
|
|
||||||
sizeof(double) * 14);
|
|
||||||
object()->Set(env->context(),
|
|
||||||
env->statfields_string(),
|
|
||||||
Float64Array::New(ab, 0, 14)).FromJust();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FSReqPromise::~FSReqPromise() {
|
FSReqPromise::~FSReqPromise() {
|
||||||
|
@ -300,44 +310,35 @@ FSReqPromise::~FSReqPromise() {
|
||||||
|
|
||||||
void FSReqPromise::Reject(Local<Value> reject) {
|
void FSReqPromise::Reject(Local<Value> reject) {
|
||||||
finished_ = true;
|
finished_ = true;
|
||||||
InternalCallbackScope callback_scope(this);
|
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
|
InternalCallbackScope callback_scope(this);
|
||||||
Local<Value> value =
|
Local<Value> value =
|
||||||
object()->Get(env()->context(),
|
object()->Get(env()->context(),
|
||||||
env()->promise_string()).ToLocalChecked();
|
env()->promise_string()).ToLocalChecked();
|
||||||
CHECK(value->IsPromise());
|
CHECK(value->IsPromise());
|
||||||
Local<Promise> promise = value.As<Promise>();
|
Local<Promise> promise = value.As<Promise>();
|
||||||
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
||||||
resolver->Reject(env()->context(), reject);
|
resolver->Reject(env()->context(), reject).FromJust();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSReqPromise::FillStatsArray(const uv_stat_t* stat) {
|
void FSReqPromise::FillStatsArray(const uv_stat_t* stat) {
|
||||||
node::FillStatsArray(statFields_, stat);
|
node::FillStatsArray(&stats_field_array_, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSReqPromise::ResolveStat() {
|
void FSReqPromise::ResolveStat() {
|
||||||
Resolve(
|
Resolve(stats_field_array_.GetJSArray());
|
||||||
object()->Get(env()->context(),
|
|
||||||
env()->statfields_string()).ToLocalChecked());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSReqPromise::Resolve(Local<Value> value) {
|
void FSReqPromise::Resolve(Local<Value> value) {
|
||||||
finished_ = true;
|
finished_ = true;
|
||||||
InternalCallbackScope callback_scope(this);
|
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
|
InternalCallbackScope callback_scope(this);
|
||||||
Local<Value> val =
|
Local<Value> val =
|
||||||
object()->Get(env()->context(),
|
object()->Get(env()->context(),
|
||||||
env()->promise_string()).ToLocalChecked();
|
env()->promise_string()).ToLocalChecked();
|
||||||
CHECK(val->IsPromise());
|
CHECK(val->IsPromise());
|
||||||
Local<Promise> promise = val.As<Promise>();
|
Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
|
||||||
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
resolver->Resolve(env()->context(), value).FromJust();
|
||||||
resolver->Resolve(env()->context(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewFSReqPromise(const FunctionCallbackInfo<Value>& args) {
|
|
||||||
CHECK(args.IsConstructCall());
|
|
||||||
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
|
||||||
new FSReqPromise(env, args.This());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
|
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
|
||||||
|
@ -519,11 +520,10 @@ class fs_req_wrap {
|
||||||
|
|
||||||
template <typename Func, typename... Args>
|
template <typename Func, typename... Args>
|
||||||
inline FSReqBase* AsyncDestCall(Environment* env,
|
inline FSReqBase* AsyncDestCall(Environment* env,
|
||||||
|
FSReqBase* req_wrap,
|
||||||
const FunctionCallbackInfo<Value>& args,
|
const FunctionCallbackInfo<Value>& args,
|
||||||
const char* syscall, const char* dest, size_t len,
|
const char* syscall, const char* dest, size_t len,
|
||||||
enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
|
enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
|
||||||
Local<Object> req = args[args.Length() - 1].As<Object>();
|
|
||||||
FSReqBase* req_wrap = Unwrap<FSReqBase>(req);
|
|
||||||
CHECK_NE(req_wrap, nullptr);
|
CHECK_NE(req_wrap, nullptr);
|
||||||
req_wrap->Init(syscall, dest, len, enc);
|
req_wrap->Init(syscall, dest, len, enc);
|
||||||
int err = fn(env->event_loop(), req_wrap->req(), fn_args..., after);
|
int err = fn(env->event_loop(), req_wrap->req(), fn_args..., after);
|
||||||
|
@ -544,10 +544,11 @@ inline FSReqBase* AsyncDestCall(Environment* env,
|
||||||
|
|
||||||
template <typename Func, typename... Args>
|
template <typename Func, typename... Args>
|
||||||
inline FSReqBase* AsyncCall(Environment* env,
|
inline FSReqBase* AsyncCall(Environment* env,
|
||||||
|
FSReqBase* req_wrap,
|
||||||
const FunctionCallbackInfo<Value>& args,
|
const FunctionCallbackInfo<Value>& args,
|
||||||
const char* syscall, enum encoding enc,
|
const char* syscall, enum encoding enc,
|
||||||
uv_fs_cb after, Func fn, Args... fn_args) {
|
uv_fs_cb after, Func fn, Args... fn_args) {
|
||||||
return AsyncDestCall(env, args,
|
return AsyncDestCall(env, req_wrap, args,
|
||||||
syscall, nullptr, 0, enc,
|
syscall, nullptr, 0, enc,
|
||||||
after, fn, fn_args...);
|
after, fn, fn_args...);
|
||||||
}
|
}
|
||||||
|
@ -576,10 +577,10 @@ inline int SyncCall(Environment* env, Local<Value> ctx, fs_req_wrap* req_wrap,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SYNC_DEST_CALL(func, path, dest, ...) \
|
#define SYNC_DEST_CALL(func, path, dest, ...) \
|
||||||
fs_req_wrap req_wrap; \
|
fs_req_wrap sync_wrap; \
|
||||||
env->PrintSyncTrace(); \
|
env->PrintSyncTrace(); \
|
||||||
int err = uv_fs_ ## func(env->event_loop(), \
|
int err = uv_fs_ ## func(env->event_loop(), \
|
||||||
&req_wrap.req, \
|
&sync_wrap.req, \
|
||||||
__VA_ARGS__, \
|
__VA_ARGS__, \
|
||||||
nullptr); \
|
nullptr); \
|
||||||
if (err < 0) { \
|
if (err < 0) { \
|
||||||
|
@ -589,10 +590,19 @@ inline int SyncCall(Environment* env, Local<Value> ctx, fs_req_wrap* req_wrap,
|
||||||
#define SYNC_CALL(func, path, ...) \
|
#define SYNC_CALL(func, path, ...) \
|
||||||
SYNC_DEST_CALL(func, path, nullptr, __VA_ARGS__) \
|
SYNC_DEST_CALL(func, path, nullptr, __VA_ARGS__) \
|
||||||
|
|
||||||
#define SYNC_REQ req_wrap.req
|
#define SYNC_REQ sync_wrap.req
|
||||||
|
|
||||||
#define SYNC_RESULT err
|
#define SYNC_RESULT err
|
||||||
|
|
||||||
|
inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value) {
|
||||||
|
if (value->IsObject()) {
|
||||||
|
return Unwrap<FSReqBase>(value.As<Object>());
|
||||||
|
} else if (value->StrictEquals(env->fs_use_promises_symbol())) {
|
||||||
|
return new FSReqPromise(env);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Access(const FunctionCallbackInfo<Value>& args) {
|
void Access(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
||||||
HandleScope scope(env->isolate());
|
HandleScope scope(env->isolate());
|
||||||
|
@ -606,10 +616,11 @@ void Access(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
CHECK_NE(*path, nullptr);
|
CHECK_NE(*path, nullptr);
|
||||||
|
|
||||||
if (args[2]->IsObject()) { // access(path, mode, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(argc, 3);
|
if (req_wrap != nullptr) { // access(path, mode, req)
|
||||||
AsyncCall(env, args, "access", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "access", UTF8, AfterNoArgs,
|
||||||
uv_fs_access, *path, mode);
|
uv_fs_access, *path, mode);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else { // access(path, mode, undefined, ctx)
|
} else { // access(path, mode, undefined, ctx)
|
||||||
CHECK_EQ(argc, 4);
|
CHECK_EQ(argc, 4);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req_wrap;
|
||||||
|
@ -627,10 +638,11 @@ void Close(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args[0]->IsInt32());
|
CHECK(args[0]->IsInt32());
|
||||||
int fd = args[0].As<Int32>()->Value();
|
int fd = args[0].As<Int32>()->Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // close(fd, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) { // close(fd, req)
|
||||||
AsyncCall(env, args, "close", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "close", UTF8, AfterNoArgs,
|
||||||
uv_fs_close, fd);
|
uv_fs_close, fd);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else { // close(fd, undefined, ctx)
|
} else { // close(fd, undefined, ctx)
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req_wrap;
|
||||||
|
@ -732,10 +744,11 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
CHECK_NE(*path, nullptr);
|
CHECK_NE(*path, nullptr);
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // stat(path, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) { // stat(path, req)
|
||||||
AsyncCall(env, args, "stat", UTF8, AfterStat,
|
AsyncCall(env, req_wrap, args, "stat", UTF8, AfterStat,
|
||||||
uv_fs_stat, *path);
|
uv_fs_stat, *path);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else { // stat(path, undefined, ctx)
|
} else { // stat(path, undefined, ctx)
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req_wrap;
|
||||||
|
@ -756,10 +769,11 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
CHECK_NE(*path, nullptr);
|
CHECK_NE(*path, nullptr);
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // lstat(path, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) { // lstat(path, req)
|
||||||
AsyncCall(env, args, "lstat", UTF8, AfterStat,
|
AsyncCall(env, req_wrap, args, "lstat", UTF8, AfterStat,
|
||||||
uv_fs_lstat, *path);
|
uv_fs_lstat, *path);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else { // lstat(path, undefined, ctx)
|
} else { // lstat(path, undefined, ctx)
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req_wrap;
|
||||||
|
@ -780,10 +794,11 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args[0]->IsInt32());
|
CHECK(args[0]->IsInt32());
|
||||||
int fd = args[0].As<Int32>()->Value();
|
int fd = args[0].As<Int32>()->Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // fstat(fd, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) { // fstat(fd, req)
|
||||||
AsyncCall(env, args, "fstat", UTF8, AfterStat,
|
AsyncCall(env, req_wrap, args, "fstat", UTF8, AfterStat,
|
||||||
uv_fs_fstat, fd);
|
uv_fs_fstat, fd);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else { // fstat(fd, undefined, ctx)
|
} else { // fstat(fd, undefined, ctx)
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req_wrap;
|
||||||
|
@ -809,14 +824,14 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args[2]->IsInt32());
|
CHECK(args[2]->IsInt32());
|
||||||
int flags = args[2].As<Int32>()->Value();
|
int flags = args[2].As<Int32>()->Value();
|
||||||
|
|
||||||
if (args[3]->IsObject()) { // symlink(target, path, flags, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) { // symlink(target, path, flags, req)
|
||||||
AsyncDestCall(env, args, "symlink", *path, path.length(), UTF8,
|
AsyncDestCall(env, req_wrap, args, "symlink", *path, path.length(), UTF8,
|
||||||
AfterNoArgs, uv_fs_symlink, *target, *path, flags);
|
AfterNoArgs, uv_fs_symlink, *target, *path, flags);
|
||||||
} else { // symlink(target, path, flags, undefinec, ctx)
|
} else { // symlink(target, path, flags, undefinec, ctx)
|
||||||
CHECK_EQ(argc, 5);
|
CHECK_EQ(argc, 5);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[4], &req_wrap, "symlink",
|
SyncCall(env, args[4], &req, "symlink",
|
||||||
uv_fs_symlink, *target, *path, flags);
|
uv_fs_symlink, *target, *path, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -833,14 +848,15 @@ static void Link(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue dest(env->isolate(), args[1]);
|
BufferValue dest(env->isolate(), args[1]);
|
||||||
CHECK_NE(*dest, nullptr);
|
CHECK_NE(*dest, nullptr);
|
||||||
|
|
||||||
if (args[2]->IsObject()) { // link(src, dest, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(argc, 3);
|
if (req_wrap != nullptr) { // link(src, dest, req)
|
||||||
AsyncDestCall(env, args, "link", *dest, dest.length(), UTF8,
|
AsyncDestCall(env, req_wrap, args, "link", *dest, dest.length(), UTF8,
|
||||||
AfterNoArgs, uv_fs_link, *src, *dest);
|
AfterNoArgs, uv_fs_link, *src, *dest);
|
||||||
} else { // link(src, dest, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else { // link(src, dest)
|
||||||
CHECK_EQ(argc, 4);
|
CHECK_EQ(argc, 4);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[3], &req_wrap, "link",
|
SyncCall(env, args[3], &req, "link",
|
||||||
uv_fs_link, *src, *dest);
|
uv_fs_link, *src, *dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -856,19 +872,20 @@ static void ReadLink(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
|
|
||||||
if (args[2]->IsObject()) { // readlink(path, encoding, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(argc, 3);
|
if (req_wrap != nullptr) { // readlink(path, encoding, req)
|
||||||
AsyncCall(env, args, "readlink", encoding, AfterStringPtr,
|
AsyncCall(env, req_wrap, args, "readlink", encoding, AfterStringPtr,
|
||||||
uv_fs_readlink, *path);
|
uv_fs_readlink, *path);
|
||||||
} else { // readlink(path, encoding, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else {
|
||||||
CHECK_EQ(argc, 4);
|
CHECK_EQ(argc, 4);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
int err = SyncCall(env, args[3], &req_wrap, "readlink",
|
int err = SyncCall(env, args[3], &req, "readlink",
|
||||||
uv_fs_readlink, *path);
|
uv_fs_readlink, *path);
|
||||||
if (err) {
|
if (err) {
|
||||||
return; // syscall failed, no need to continue, error info is in ctx
|
return; // syscall failed, no need to continue, error info is in ctx
|
||||||
}
|
}
|
||||||
const char* link_path = static_cast<const char*>(req_wrap.req.ptr);
|
const char* link_path = static_cast<const char*>(req.req.ptr);
|
||||||
|
|
||||||
Local<Value> error;
|
Local<Value> error;
|
||||||
MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
|
MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
|
||||||
|
@ -896,15 +913,15 @@ static void Rename(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue new_path(env->isolate(), args[1]);
|
BufferValue new_path(env->isolate(), args[1]);
|
||||||
CHECK_NE(*new_path, nullptr);
|
CHECK_NE(*new_path, nullptr);
|
||||||
|
|
||||||
if (args[2]->IsObject()) { // rename(old_path, new_path, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(argc, 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncDestCall(env, args, "rename", *new_path, new_path.length(),
|
AsyncDestCall(env, req_wrap, args, "rename", *new_path, new_path.length(),
|
||||||
UTF8, AfterNoArgs, uv_fs_rename, *old_path, *new_path);
|
UTF8, AfterNoArgs, uv_fs_rename, *old_path, *new_path);
|
||||||
} else { // rename(old_path, new_path, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else {
|
||||||
CHECK_EQ(argc, 4);
|
CHECK_EQ(argc, 4);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[3], &req_wrap, "rename",
|
SyncCall(env, args[3], &req, "rename", uv_fs_rename, *old_path, *new_path);
|
||||||
uv_fs_rename, *old_path, *new_path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,15 +937,15 @@ static void FTruncate(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args[1]->IsNumber());
|
CHECK(args[1]->IsNumber());
|
||||||
const int64_t len = args[1].As<Integer>()->Value();
|
const int64_t len = args[1].As<Integer>()->Value();
|
||||||
|
|
||||||
if (args[2]->IsObject()) { // ftruncate(fd, len, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(argc, 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "ftruncate", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "ftruncate", UTF8, AfterNoArgs,
|
||||||
uv_fs_ftruncate, fd, len);
|
uv_fs_ftruncate, fd, len);
|
||||||
} else { // ftruncate(fd, len, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else {
|
||||||
CHECK_EQ(argc, 4);
|
CHECK_EQ(argc, 4);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[3], &req_wrap, "ftruncate",
|
SyncCall(env, args[3], &req, "ftruncate", uv_fs_ftruncate, fd, len);
|
||||||
uv_fs_ftruncate, fd, len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,15 +958,15 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args[0]->IsInt32());
|
CHECK(args[0]->IsInt32());
|
||||||
const int fd = args[0].As<Int32>()->Value();
|
const int fd = args[0].As<Int32>()->Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // fdatasync(fd, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "fdatasync", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "fdatasync", UTF8, AfterNoArgs,
|
||||||
uv_fs_fdatasync, fd);
|
uv_fs_fdatasync, fd);
|
||||||
} else { // fdatasync(fd, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else {
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[2], &req_wrap, "fdatasync",
|
SyncCall(env, args[2], &req, "fdatasync", uv_fs_fdatasync, fd);
|
||||||
uv_fs_fdatasync, fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,15 +979,15 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args[0]->IsInt32());
|
CHECK(args[0]->IsInt32());
|
||||||
const int fd = args[0].As<Int32>()->Value();
|
const int fd = args[0].As<Int32>()->Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // fsync(fd, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "fsync", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "fsync", UTF8, AfterNoArgs,
|
||||||
uv_fs_fsync, fd);
|
uv_fs_fsync, fd);
|
||||||
} else { // fsync(fd, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else {
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[2], &req_wrap, "fsync",
|
SyncCall(env, args[2], &req, "fsync", uv_fs_fsync, fd);
|
||||||
uv_fs_fsync, fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,15 +1000,15 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
CHECK_NE(*path, nullptr);
|
CHECK_NE(*path, nullptr);
|
||||||
|
|
||||||
if (args[1]->IsObject()) { // unlink(fd, req)
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(argc, 2);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "unlink", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "unlink", UTF8, AfterNoArgs,
|
||||||
uv_fs_unlink, *path);
|
uv_fs_unlink, *path);
|
||||||
} else { // unlink(fd, undefined, ctx)
|
req_wrap->SetReturnValue(args);
|
||||||
|
} else {
|
||||||
CHECK_EQ(argc, 3);
|
CHECK_EQ(argc, 3);
|
||||||
fs_req_wrap req_wrap;
|
fs_req_wrap req;
|
||||||
SyncCall(env, args[2], &req_wrap, "unlink",
|
SyncCall(env, args[2], &req, "unlink", uv_fs_unlink, *path);
|
||||||
uv_fs_unlink, *path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,10 +1020,11 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) {
|
||||||
BufferValue path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
CHECK_NE(*path, nullptr);
|
CHECK_NE(*path, nullptr);
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[1]);
|
||||||
CHECK_EQ(args.Length(), 2);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "rmdir", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "rmdir", UTF8, AfterNoArgs,
|
||||||
uv_fs_rmdir, *path);
|
uv_fs_rmdir, *path);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(rmdir, *path, *path)
|
SYNC_CALL(rmdir, *path, *path)
|
||||||
}
|
}
|
||||||
|
@ -1023,10 +1041,11 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(args.Length(), 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "mkdir", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "mkdir", UTF8, AfterNoArgs,
|
||||||
uv_fs_mkdir, *path, mode);
|
uv_fs_mkdir, *path, mode);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(mkdir, *path, *path, mode)
|
SYNC_CALL(mkdir, *path, *path, mode)
|
||||||
}
|
}
|
||||||
|
@ -1040,10 +1059,11 @@ static void RealPath(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(args.Length(), 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "realpath", encoding, AfterStringPtr,
|
AsyncCall(env, req_wrap, args, "realpath", encoding, AfterStringPtr,
|
||||||
uv_fs_realpath, *path);
|
uv_fs_realpath, *path);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(realpath, *path, *path);
|
SYNC_CALL(realpath, *path, *path);
|
||||||
const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
|
const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
|
||||||
|
@ -1071,10 +1091,11 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(args.Length(), 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "scandir", encoding, AfterScanDir,
|
AsyncCall(env, req_wrap, args, "scandir", encoding, AfterScanDir,
|
||||||
uv_fs_scandir, *path, 0 /*flags*/);
|
uv_fs_scandir, *path, 0 /*flags*/);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
|
SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
|
||||||
|
|
||||||
|
@ -1135,10 +1156,11 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
|
||||||
int flags = args[1]->Int32Value(context).ToChecked();
|
int flags = args[1]->Int32Value(context).ToChecked();
|
||||||
int mode = args[2]->Int32Value(context).ToChecked();
|
int mode = args[2]->Int32Value(context).ToChecked();
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "open", UTF8, AfterInteger,
|
AsyncCall(env, req_wrap, args, "open", UTF8, AfterInteger,
|
||||||
uv_fs_open, *path, flags, mode);
|
uv_fs_open, *path, flags, mode);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(open, *path, *path, flags, mode)
|
SYNC_CALL(open, *path, *path, flags, mode)
|
||||||
args.GetReturnValue().Set(SYNC_RESULT);
|
args.GetReturnValue().Set(SYNC_RESULT);
|
||||||
|
@ -1159,10 +1181,11 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
|
||||||
int flags = args[1]->Int32Value(context).ToChecked();
|
int flags = args[1]->Int32Value(context).ToChecked();
|
||||||
int mode = args[2]->Int32Value(context).ToChecked();
|
int mode = args[2]->Int32Value(context).ToChecked();
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "open", UTF8, AfterOpenFileHandle,
|
AsyncCall(env, req_wrap, args, "open", UTF8, AfterOpenFileHandle,
|
||||||
uv_fs_open, *path, flags, mode);
|
uv_fs_open, *path, flags, mode);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(open, *path, *path, flags, mode)
|
SYNC_CALL(open, *path, *path, flags, mode)
|
||||||
if (SYNC_RESULT < 0) {
|
if (SYNC_RESULT < 0) {
|
||||||
|
@ -1187,10 +1210,11 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK_NE(*dest, nullptr);
|
CHECK_NE(*dest, nullptr);
|
||||||
int flags = args[2]->Int32Value();
|
int flags = args[2]->Int32Value();
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "copyfile", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "copyfile", UTF8, AfterNoArgs,
|
||||||
uv_fs_copyfile, *src, *dest, flags);
|
uv_fs_copyfile, *src, *dest, flags);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags)
|
SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags)
|
||||||
}
|
}
|
||||||
|
@ -1229,11 +1253,11 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
|
uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
|
||||||
|
|
||||||
if (args[5]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[5]);
|
||||||
CHECK_EQ(args.Length(), 6);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "write", UTF8, AfterInteger,
|
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
|
||||||
uv_fs_write, fd, &uvbuf, 1, pos);
|
uv_fs_write, fd, &uvbuf, 1, pos);
|
||||||
return;
|
return req_wrap->SetReturnValue(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
|
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
|
||||||
|
@ -1266,11 +1290,11 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
|
||||||
iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
|
iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "write", UTF8, AfterInteger,
|
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
|
||||||
uv_fs_write, fd, *iovs, iovs.length(), pos);
|
uv_fs_write, fd, *iovs, iovs.length(), pos);
|
||||||
return;
|
return req_wrap->SetReturnValue(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos)
|
SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos)
|
||||||
|
@ -1299,7 +1323,9 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const int64_t pos = GET_OFFSET(args[2]);
|
const int64_t pos = GET_OFFSET(args[2]);
|
||||||
const auto enc = ParseEncoding(env->isolate(), args[3], UTF8);
|
const auto enc = ParseEncoding(env->isolate(), args[3], UTF8);
|
||||||
const auto is_async = args[4]->IsObject();
|
|
||||||
|
FSReqBase* req_wrap = GetReqWrap(env, args[4]);
|
||||||
|
const auto is_async = req_wrap != nullptr;
|
||||||
|
|
||||||
// Avoid copying the string when it is externalized but only when:
|
// Avoid copying the string when it is externalized but only when:
|
||||||
// 1. The target encoding is compatible with the string's encoding, and
|
// 1. The target encoding is compatible with the string's encoding, and
|
||||||
|
@ -1333,10 +1359,10 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
uv_buf_t uvbuf = uv_buf_init(buf, len);
|
uv_buf_t uvbuf = uv_buf_init(buf, len);
|
||||||
|
|
||||||
if (is_async) {
|
if (req_wrap != nullptr) {
|
||||||
CHECK_EQ(args.Length(), 5);
|
AsyncCall(env, req_wrap, args, "write", UTF8, AfterInteger,
|
||||||
AsyncCall(env, args, "write", UTF8, AfterInteger,
|
|
||||||
uv_fs_write, fd, &uvbuf, 1, pos);
|
uv_fs_write, fd, &uvbuf, 1, pos);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
|
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
|
||||||
return args.GetReturnValue().Set(SYNC_RESULT);
|
return args.GetReturnValue().Set(SYNC_RESULT);
|
||||||
|
@ -1387,10 +1413,11 @@ static void Read(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
|
uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
|
||||||
|
|
||||||
if (args[5]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[5]);
|
||||||
CHECK_EQ(args.Length(), 6);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "read", UTF8, AfterInteger,
|
AsyncCall(env, req_wrap, args, "read", UTF8, AfterInteger,
|
||||||
uv_fs_read, fd, &uvbuf, 1, pos);
|
uv_fs_read, fd, &uvbuf, 1, pos);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
|
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
|
||||||
args.GetReturnValue().Set(SYNC_RESULT);
|
args.GetReturnValue().Set(SYNC_RESULT);
|
||||||
|
@ -1412,10 +1439,11 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(args.Length(), 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "chmod", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "chmod", UTF8, AfterNoArgs,
|
||||||
uv_fs_chmod, *path, mode);
|
uv_fs_chmod, *path, mode);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(chmod, *path, *path, mode);
|
SYNC_CALL(chmod, *path, *path, mode);
|
||||||
}
|
}
|
||||||
|
@ -1434,10 +1462,11 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
|
||||||
int fd = args[0]->Int32Value();
|
int fd = args[0]->Int32Value();
|
||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(args.Length(), 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "fchmod", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "fchmod", UTF8, AfterNoArgs,
|
||||||
uv_fs_fchmod, fd, mode);
|
uv_fs_fchmod, fd, mode);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fchmod, 0, fd, mode);
|
SYNC_CALL(fchmod, 0, fd, mode);
|
||||||
}
|
}
|
||||||
|
@ -1461,10 +1490,11 @@ static void Chown(const FunctionCallbackInfo<Value>& args) {
|
||||||
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
|
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
|
||||||
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "chown", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "chown", UTF8, AfterNoArgs,
|
||||||
uv_fs_chown, *path, uid, gid);
|
uv_fs_chown, *path, uid, gid);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(chown, *path, *path, uid, gid);
|
SYNC_CALL(chown, *path, *path, uid, gid);
|
||||||
}
|
}
|
||||||
|
@ -1485,10 +1515,11 @@ static void FChown(const FunctionCallbackInfo<Value>& args) {
|
||||||
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
|
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
|
||||||
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "fchown", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "fchown", UTF8, AfterNoArgs,
|
||||||
uv_fs_fchown, fd, uid, gid);
|
uv_fs_fchown, fd, uid, gid);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fchown, 0, fd, uid, gid);
|
SYNC_CALL(fchown, 0, fd, uid, gid);
|
||||||
}
|
}
|
||||||
|
@ -1508,10 +1539,11 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) {
|
||||||
const double atime = static_cast<double>(args[1]->NumberValue());
|
const double atime = static_cast<double>(args[1]->NumberValue());
|
||||||
const double mtime = static_cast<double>(args[2]->NumberValue());
|
const double mtime = static_cast<double>(args[2]->NumberValue());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "utime", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "utime", UTF8, AfterNoArgs,
|
||||||
uv_fs_utime, *path, atime, mtime);
|
uv_fs_utime, *path, atime, mtime);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(utime, *path, *path, atime, mtime);
|
SYNC_CALL(utime, *path, *path, atime, mtime);
|
||||||
}
|
}
|
||||||
|
@ -1528,10 +1560,11 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
|
||||||
const double atime = static_cast<double>(args[1]->NumberValue());
|
const double atime = static_cast<double>(args[1]->NumberValue());
|
||||||
const double mtime = static_cast<double>(args[2]->NumberValue());
|
const double mtime = static_cast<double>(args[2]->NumberValue());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[3]);
|
||||||
CHECK_EQ(args.Length(), 4);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "futime", UTF8, AfterNoArgs,
|
AsyncCall(env, req_wrap, args, "futime", UTF8, AfterNoArgs,
|
||||||
uv_fs_futime, fd, atime, mtime);
|
uv_fs_futime, fd, atime, mtime);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(futime, 0, fd, atime, mtime);
|
SYNC_CALL(futime, 0, fd, atime, mtime);
|
||||||
}
|
}
|
||||||
|
@ -1547,10 +1580,11 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
FSReqBase* req_wrap = GetReqWrap(env, args[2]);
|
||||||
CHECK_EQ(args.Length(), 3);
|
if (req_wrap != nullptr) {
|
||||||
AsyncCall(env, args, "mkdtemp", encoding, AfterStringPath,
|
AsyncCall(env, req_wrap, args, "mkdtemp", encoding, AfterStringPath,
|
||||||
uv_fs_mkdtemp, *tmpl);
|
uv_fs_mkdtemp, *tmpl);
|
||||||
|
req_wrap->SetReturnValue(args);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
|
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
|
||||||
const char* path = static_cast<const char*>(SYNC_REQ.path);
|
const char* path = static_cast<const char*>(SYNC_REQ.path);
|
||||||
|
@ -1629,14 +1663,14 @@ void InitFs(Local<Object> target,
|
||||||
target->Set(context, wrapString, fst->GetFunction()).FromJust();
|
target->Set(context, wrapString, fst->GetFunction()).FromJust();
|
||||||
|
|
||||||
// Create Function Template for FSReqPromise
|
// Create Function Template for FSReqPromise
|
||||||
Local<FunctionTemplate> fpt =
|
Local<FunctionTemplate> fpt = FunctionTemplate::New(env->isolate());
|
||||||
FunctionTemplate::New(env->isolate(), NewFSReqPromise);
|
|
||||||
fpt->InstanceTemplate()->SetInternalFieldCount(1);
|
|
||||||
AsyncWrap::AddWrapMethods(env, fpt);
|
AsyncWrap::AddWrapMethods(env, fpt);
|
||||||
Local<String> promiseString =
|
Local<String> promiseString =
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqPromise");
|
FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqPromise");
|
||||||
fpt->SetClassName(promiseString);
|
fpt->SetClassName(promiseString);
|
||||||
target->Set(context, promiseString, fpt->GetFunction()).FromJust();
|
Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
|
||||||
|
fpo->SetInternalFieldCount(1);
|
||||||
|
env->set_fsreqpromise_constructor_template(fpo);
|
||||||
|
|
||||||
// Create FunctionTemplate for FileHandle
|
// Create FunctionTemplate for FileHandle
|
||||||
Local<FunctionTemplate> fd = FunctionTemplate::New(env->isolate());
|
Local<FunctionTemplate> fd = FunctionTemplate::New(env->isolate());
|
||||||
|
@ -1658,6 +1692,14 @@ void InitFs(Local<Object> target,
|
||||||
Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
|
Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
|
||||||
fdcloset->SetInternalFieldCount(1);
|
fdcloset->SetInternalFieldCount(1);
|
||||||
env->set_fdclose_constructor_template(fdcloset);
|
env->set_fdclose_constructor_template(fdcloset);
|
||||||
|
|
||||||
|
Local<Symbol> use_promises_symbol =
|
||||||
|
Symbol::New(env->isolate(),
|
||||||
|
FIXED_ONE_BYTE_STRING(env->isolate(), "use promises"));
|
||||||
|
env->set_fs_use_promises_symbol(use_promises_symbol);
|
||||||
|
target->Set(env->context(),
|
||||||
|
FIXED_ONE_BYTE_STRING(env->isolate(), "kUsePromises"),
|
||||||
|
use_promises_symbol).FromJust();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
|
@ -12,6 +12,7 @@ using v8::Context;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
|
using v8::MaybeLocal;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::Persistent;
|
using v8::Persistent;
|
||||||
using v8::Promise;
|
using v8::Promise;
|
||||||
|
@ -51,6 +52,7 @@ class FSReqBase : public ReqWrap<uv_fs_t> {
|
||||||
virtual void Reject(Local<Value> reject) = 0;
|
virtual void Reject(Local<Value> reject) = 0;
|
||||||
virtual void Resolve(Local<Value> value) = 0;
|
virtual void Resolve(Local<Value> value) = 0;
|
||||||
virtual void ResolveStat() = 0;
|
virtual void ResolveStat() = 0;
|
||||||
|
virtual void SetReturnValue(const FunctionCallbackInfo<Value>& args) = 0;
|
||||||
|
|
||||||
const char* syscall() const { return syscall_; }
|
const char* syscall() const { return syscall_; }
|
||||||
const char* data() const { return data_; }
|
const char* data() const { return data_; }
|
||||||
|
@ -77,6 +79,7 @@ class FSReqWrap : public FSReqBase {
|
||||||
void Reject(Local<Value> reject) override;
|
void Reject(Local<Value> reject) override;
|
||||||
void Resolve(Local<Value> value) override;
|
void Resolve(Local<Value> value) override;
|
||||||
void ResolveStat() override;
|
void ResolveStat() override;
|
||||||
|
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
|
DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
|
||||||
|
@ -84,7 +87,7 @@ class FSReqWrap : public FSReqBase {
|
||||||
|
|
||||||
class FSReqPromise : public FSReqBase {
|
class FSReqPromise : public FSReqBase {
|
||||||
public:
|
public:
|
||||||
FSReqPromise(Environment* env, Local<Object> req);
|
explicit FSReqPromise(Environment* env);
|
||||||
|
|
||||||
~FSReqPromise() override;
|
~FSReqPromise() override;
|
||||||
|
|
||||||
|
@ -92,10 +95,11 @@ class FSReqPromise : public FSReqBase {
|
||||||
void Reject(Local<Value> reject) override;
|
void Reject(Local<Value> reject) override;
|
||||||
void Resolve(Local<Value> value) override;
|
void Resolve(Local<Value> value) override;
|
||||||
void ResolveStat() override;
|
void ResolveStat() override;
|
||||||
|
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool finished_ = false;
|
bool finished_ = false;
|
||||||
double statFields_[14] {};
|
AliasedBuffer<double, v8::Float64Array> stats_field_array_;
|
||||||
DISALLOW_COPY_AND_ASSIGN(FSReqPromise);
|
DISALLOW_COPY_AND_ASSIGN(FSReqPromise);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,7 +156,7 @@ class FileHandle : public AsyncWrap {
|
||||||
ref_.Empty();
|
ref_.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHandle* fd();
|
FileHandle* file_handle();
|
||||||
|
|
||||||
size_t self_size() const override { return sizeof(*this); }
|
size_t self_size() const override { return sizeof(*this); }
|
||||||
|
|
||||||
|
@ -166,7 +170,7 @@ class FileHandle : public AsyncWrap {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Asynchronous close
|
// Asynchronous close
|
||||||
inline Local<Promise> ClosePromise();
|
inline MaybeLocal<Promise> ClosePromise();
|
||||||
|
|
||||||
int fd_;
|
int fd_;
|
||||||
bool closing_ = false;
|
bool closing_ = false;
|
||||||
|
|
25
test/parallel/test-fs-filehandle.js
Normal file
25
test/parallel/test-fs-filehandle.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Flags: --expose-gc --no-warnings --expose-internals
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = process.binding('fs');
|
||||||
|
const { stringToFlags } = require('internal/fs');
|
||||||
|
|
||||||
|
// Verifies that the FileHandle object is garbage collected and that a
|
||||||
|
// warning is emitted if it is not closed.
|
||||||
|
|
||||||
|
let fdnum;
|
||||||
|
{
|
||||||
|
fdnum = fs.openFileHandle(path.toNamespacedPath(__filename),
|
||||||
|
stringToFlags('r'), 0o666).fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
common.expectWarning(
|
||||||
|
'Warning',
|
||||||
|
`Closing file descriptor ${fdnum} on garbage collection`
|
||||||
|
);
|
||||||
|
|
||||||
|
gc(); // eslint-disable-line no-undef
|
||||||
|
|
||||||
|
setTimeout(() => {}, 10);
|
40
test/parallel/test-fs-promises-writefile.js
Normal file
40
test/parallel/test-fs-promises-writefile.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const tmpdir = require('../common/tmpdir');
|
||||||
|
const assert = require('assert');
|
||||||
|
const tmpDir = tmpdir.path;
|
||||||
|
|
||||||
|
tmpdir.refresh();
|
||||||
|
|
||||||
|
common.crashOnUnhandledRejection();
|
||||||
|
|
||||||
|
const dest = path.resolve(tmpDir, 'tmp.txt');
|
||||||
|
const buffer = Buffer.from('abc'.repeat(1000));
|
||||||
|
const buffer2 = Buffer.from('xyz'.repeat(1000));
|
||||||
|
|
||||||
|
async function doWrite() {
|
||||||
|
await fs.promises.writeFile(dest, buffer);
|
||||||
|
const data = fs.readFileSync(dest);
|
||||||
|
assert.deepStrictEqual(data, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doAppend() {
|
||||||
|
await fs.promises.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 buf = fs.readFileSync(dest);
|
||||||
|
assert.deepStrictEqual(buf, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
doWrite()
|
||||||
|
.then(doAppend)
|
||||||
|
.then(doRead)
|
||||||
|
.then(common.mustCall());
|
150
test/parallel/test-fs-promises.js
Normal file
150
test/parallel/test-fs-promises.js
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const tmpdir = require('../common/tmpdir');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const {
|
||||||
|
access,
|
||||||
|
chmod,
|
||||||
|
copyFile,
|
||||||
|
fchmod,
|
||||||
|
fdatasync,
|
||||||
|
fstat,
|
||||||
|
fsync,
|
||||||
|
ftruncate,
|
||||||
|
futimes,
|
||||||
|
link,
|
||||||
|
lstat,
|
||||||
|
mkdir,
|
||||||
|
mkdtemp,
|
||||||
|
open,
|
||||||
|
read,
|
||||||
|
readdir,
|
||||||
|
readlink,
|
||||||
|
realpath,
|
||||||
|
rename,
|
||||||
|
rmdir,
|
||||||
|
stat,
|
||||||
|
symlink,
|
||||||
|
write,
|
||||||
|
unlink,
|
||||||
|
utimes
|
||||||
|
} = fs.promises;
|
||||||
|
|
||||||
|
const tmpDir = tmpdir.path;
|
||||||
|
|
||||||
|
common.crashOnUnhandledRejection();
|
||||||
|
|
||||||
|
{
|
||||||
|
access(__filename, 'r')
|
||||||
|
.then(common.mustCall())
|
||||||
|
.catch(common.mustNotCall());
|
||||||
|
|
||||||
|
access('this file does not exist', 'r')
|
||||||
|
.then(common.mustNotCall())
|
||||||
|
.catch(common.expectsError({
|
||||||
|
code: 'ENOENT',
|
||||||
|
type: Error,
|
||||||
|
message:
|
||||||
|
/^ENOENT: no such file or directory, access/
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyStatObject(stat) {
|
||||||
|
assert.strictEqual(typeof stat, 'object');
|
||||||
|
assert.strictEqual(typeof stat.dev, 'number');
|
||||||
|
assert.strictEqual(typeof stat.mode, 'number');
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
async function doTest() {
|
||||||
|
tmpdir.refresh();
|
||||||
|
const dest = path.resolve(tmpDir, 'baz.js');
|
||||||
|
await copyFile(fixtures.path('baz.js'), dest);
|
||||||
|
await access(dest, 'r');
|
||||||
|
|
||||||
|
const handle = await open(dest, 'r+');
|
||||||
|
assert.strictEqual(typeof handle, 'object');
|
||||||
|
|
||||||
|
let stats = await fstat(handle);
|
||||||
|
verifyStatObject(stats);
|
||||||
|
assert.strictEqual(stats.size, 35);
|
||||||
|
|
||||||
|
await ftruncate(handle, 1);
|
||||||
|
|
||||||
|
stats = await fstat(handle);
|
||||||
|
verifyStatObject(stats);
|
||||||
|
assert.strictEqual(stats.size, 1);
|
||||||
|
|
||||||
|
stats = await stat(dest);
|
||||||
|
verifyStatObject(stats);
|
||||||
|
|
||||||
|
await fdatasync(handle);
|
||||||
|
await fsync(handle);
|
||||||
|
|
||||||
|
const buf = Buffer.from('hello world');
|
||||||
|
|
||||||
|
await write(handle, buf);
|
||||||
|
|
||||||
|
const ret = await read(handle, Buffer.alloc(11), 0, 11, 0);
|
||||||
|
assert.strictEqual(ret.bytesRead, 11);
|
||||||
|
assert.deepStrictEqual(ret.buffer, buf);
|
||||||
|
|
||||||
|
await chmod(dest, 0o666);
|
||||||
|
await fchmod(handle, 0o666);
|
||||||
|
|
||||||
|
await utimes(dest, new Date(), new Date());
|
||||||
|
|
||||||
|
try {
|
||||||
|
await futimes(handle, new Date(), new Date());
|
||||||
|
} catch (err) {
|
||||||
|
// Some systems do not have futimes. If there is an error,
|
||||||
|
// expect it to be ENOSYS
|
||||||
|
common.expectsError({
|
||||||
|
code: 'ENOSYS',
|
||||||
|
type: Error
|
||||||
|
})(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
await handle.close();
|
||||||
|
|
||||||
|
const newPath = path.resolve(tmpDir, 'baz2.js');
|
||||||
|
await rename(dest, newPath);
|
||||||
|
stats = await stat(newPath);
|
||||||
|
verifyStatObject(stats);
|
||||||
|
|
||||||
|
const newLink = path.resolve(tmpDir, 'baz3.js');
|
||||||
|
await symlink(newPath, newLink);
|
||||||
|
|
||||||
|
const newLink2 = path.resolve(tmpDir, 'baz4.js');
|
||||||
|
await link(newPath, newLink2);
|
||||||
|
|
||||||
|
stats = await lstat(newLink);
|
||||||
|
verifyStatObject(stats);
|
||||||
|
|
||||||
|
assert.strictEqual(newPath.toLowerCase(),
|
||||||
|
(await realpath(newLink)).toLowerCase());
|
||||||
|
assert.strictEqual(newPath.toLowerCase(),
|
||||||
|
(await readlink(newLink)).toLowerCase());
|
||||||
|
|
||||||
|
await unlink(newLink);
|
||||||
|
await unlink(newLink2);
|
||||||
|
|
||||||
|
const newdir = path.resolve(tmpDir, 'dir');
|
||||||
|
await mkdir(newdir);
|
||||||
|
stats = await stat(newdir);
|
||||||
|
assert(stats.isDirectory());
|
||||||
|
|
||||||
|
const list = await readdir(tmpDir);
|
||||||
|
assert.deepStrictEqual(list, ['baz2.js', 'dir']);
|
||||||
|
|
||||||
|
await rmdir(newdir);
|
||||||
|
|
||||||
|
await mkdtemp(path.resolve(tmpDir, 'FOO'));
|
||||||
|
}
|
||||||
|
|
||||||
|
doTest().then(common.mustCall());
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ const fixtures = require('../common/fixtures');
|
||||||
const tmpdir = require('../common/tmpdir');
|
const tmpdir = require('../common/tmpdir');
|
||||||
const { getSystemErrorName } = require('util');
|
const { getSystemErrorName } = require('util');
|
||||||
|
|
||||||
|
common.crashOnUnhandledRejection();
|
||||||
|
|
||||||
// Make sure that all Providers are tested.
|
// Make sure that all Providers are tested.
|
||||||
{
|
{
|
||||||
const hooks = require('async_hooks').createHook({
|
const hooks = require('async_hooks').createHook({
|
||||||
|
@ -167,6 +169,14 @@ if (common.hasCrypto) { // eslint-disable-line crypto-check
|
||||||
testInitialized(new Signal(), 'Signal');
|
testInitialized(new Signal(), 'Signal');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
async function openTest() {
|
||||||
|
const fd = await fs.promises.open(__filename, 'r');
|
||||||
|
testInitialized(fd, 'FileHandle');
|
||||||
|
await fd.close();
|
||||||
|
}
|
||||||
|
openTest().then(common.mustCall()).catch(common.mustNotCall());
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const binding = process.binding('stream_wrap');
|
const binding = process.binding('stream_wrap');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue