Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -2204,8 +2204,14 @@ async function writeFile(path, data, options) {

if (!flush && !isCustomIterable(data) && data.byteLength <= kWriteFileMaxChunkSize) {
path = getValidatedPath(path);
await writeFileInOneRoundTrip(path, stringToFlags(flag, 'options.flag'),
parseFileMode(options.mode, 'mode', 0o666), data);
const flagsNumber = stringToFlags(flag, 'options.flag');
const mode = parseFileMode(options.mode, 'mode', 0o666);
try {
await writeFileInOneRoundTrip(path, flagsNumber, mode, data);
} catch (err) {
ErrorCaptureStackTrace(err);
throw err;
}
checkAborted(options.signal); // An abort during the write still wins.
return;
}
Expand All @@ -2222,6 +2228,8 @@ async function writeFile(path, data, options) {

/**
* Open + write + close as one thread pool round trip.
* The caller is responsible for capturing the stack trace of a rejection,
* as no JS frames are on the stack when the job completes.
* @param {string|Buffer} path Validated path
* @param {number} flagsNumber
* @param {number} mode
Expand All @@ -2233,15 +2241,13 @@ function writeFileInOneRoundTrip(path, flagsNumber, mode, data) {
const job = new binding.WriteFileJob(path, flagsNumber, mode, data);
job.ondone = (err) => {
if (err != null) {
ErrorCaptureStackTrace(err, writeFileInOneRoundTrip);
reject(err);
} else {
resolve();
}
};
const accessError = job.run(path);
if (accessError !== undefined) {
ErrorCaptureStackTrace(accessError, writeFileInOneRoundTrip);
reject(accessError);
}
});
Expand Down Expand Up @@ -2287,7 +2293,15 @@ async function readFile(path, options) {
// up to one chunk; larger files come back as an open fd + size and are
// read by readFileHandle() as before.
path = getValidatedPath(path);
const { 0: buffer, 1: fd, 2: size } = await readFileInOneRoundTrip(path, stringToFlags(flag));
const flagsNumber = stringToFlags(flag);
let result;
try {
result = await readFileInOneRoundTrip(path, flagsNumber);
} catch (err) {
ErrorCaptureStackTrace(err);
throw err;
}
const { 0: buffer, 1: fd, 2: size } = result;
if (fd === -1) {
checkAborted(options.signal); // An abort during the read still wins.
return options.encoding ? buffer.toString(options.encoding) : buffer;
Expand All @@ -2301,6 +2315,8 @@ async function readFile(path, options) {
}

/**
* The caller is responsible for capturing the stack trace of a rejection,
* as no JS frames are on the stack when the job completes.
* @param {string|Buffer} path Validated path
* @param {number} flagsNumber
* @returns {Promise<[Buffer|undefined, number, number|undefined]>} [buffer, -1] or [undefined, fd, size]
Expand All @@ -2311,15 +2327,13 @@ function readFileInOneRoundTrip(path, flagsNumber) {
job.ondone = (err, buffer, fd, size, closeErr) => {
const error = err ?? closeErr;
if (error != null) {
ErrorCaptureStackTrace(error, readFileInOneRoundTrip);
reject(error);
} else {
resolve([buffer, fd, size]);
}
};
const accessError = job.run(path);
if (accessError !== undefined) {
ErrorCaptureStackTrace(accessError, readFileInOneRoundTrip);
reject(accessError);
}
});
Expand Down
25 changes: 25 additions & 0 deletions test/parallel/test-fs-promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const fs = require('fs');
const fsPromises = fs.promises;
const {
access,
appendFile,
chmod,
chown,
copyFile,
Expand Down Expand Up @@ -62,6 +63,30 @@ assert.strictEqual(
}
).then(common.mustCall());

assert.rejects(
readFile('this file does not exist'),
{
code: 'ENOENT',
stack: /at async assert\.rejects/
}
).then(common.mustCall());

assert.rejects(
writeFile(path.join('this dir does not exist', 'file'), 'data'),
{
code: 'ENOENT',
stack: /at async assert\.rejects/
}
).then(common.mustCall());

assert.rejects(
appendFile(path.join('this dir does not exist', 'file'), 'data'),
{
code: 'ENOENT',
stack: /at async assert\.rejects/
}
).then(common.mustCall());

assert.rejects(
access(__filename, 8),
{
Expand Down
Loading