From a794beaf6c9626f242af331fc1f3ecfedec321d3 Mon Sep 17 00:00:00 2001 From: Nitzan Uziely Date: Fri, 16 Apr 2021 15:50:36 +0300 Subject: [PATCH] fs: aggregate errors in fsPromises to avoid error swallowing Add AggregateError support to fsPromises, instead of swallowing errors if fs.close throws. --- lib/internal/fs/promises.js | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index 5d51248c8417b92..39ab2f8be31b829 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -33,6 +33,7 @@ const { ERR_METHOD_NOT_IMPLEMENTED, }, AbortError, + aggregateTwoErrors, } = require('internal/errors'); const { isArrayBufferView } = require('internal/util/types'); const { rimrafPromises } = require('internal/fs/rimraf'); @@ -250,6 +251,27 @@ class FileHandle extends EventEmitterMixin(JSTransferable) { } } +async function handleFdClose(fileOpPromise, closeFunc) { + let opError; + try { + return await fileOpPromise; + } catch (err) { + opError = err; + throw err; + } finally { + try { + await closeFunc(); + } catch (closeError) { + if (!opError) { + // eslint-disable-next-line no-unsafe-finally + throw closeError; + } + // eslint-disable-next-line no-unsafe-finally + throw aggregateTwoErrors(closeError, opError); + } + } +} + async function fsCall(fn, handle, ...args) { if (handle[kRefs] === undefined) { throw new ERR_INVALID_ARG_TYPE('filehandle', 'FileHandle', handle); @@ -498,7 +520,7 @@ async function rename(oldPath, newPath) { async function truncate(path, len = 0) { const fd = await open(path, 'r+'); - return PromisePrototypeFinally(ftruncate(fd, len), fd.close); + return handleFdClose(ftruncate(fd, len), fd.close); } async function ftruncate(handle, len = 0) { @@ -629,7 +651,7 @@ async function lchmod(path, mode) { throw new ERR_METHOD_NOT_IMPLEMENTED('lchmod()'); const fd = await open(path, O_WRONLY | O_SYMLINK); - return PromisePrototypeFinally(fchmod(fd, mode), fd.close); + return handleFdClose(fchmod(fd, mode), fd.close); } async function lchown(path, uid, gid) { @@ -708,7 +730,7 @@ async function writeFile(path, data, options) { checkAborted(options.signal); const fd = await open(path, flag, options.mode); - return PromisePrototypeFinally( + return handleFdClose( writeFileHandle(fd, data, options.signal, options.encoding), fd.close); } @@ -733,7 +755,7 @@ async function readFile(path, options) { checkAborted(options.signal); const fd = await open(path, flag, 0o666); - return PromisePrototypeFinally(readFileHandle(fd, options), fd.close); + return handleFdClose(readFileHandle(fd, options), fd.close); } module.exports = {