diff --git a/lib/internal/fs/cp/cp.js b/lib/internal/fs/cp/cp.js index f59bbdb1e59..f5add19e4eb 100644 --- a/lib/internal/fs/cp/cp.js +++ b/lib/internal/fs/cp/cp.js @@ -306,7 +306,14 @@ function onDir(srcStat, destStat, src, dest, opts) { } async function mkDirAndCopy(srcMode, src, dest, opts) { - await mkdir(dest); + try { + await mkdir(dest); + } catch (error) { + // If the folder already exists, skip it. + if (error.code === 'EEXIST' && !opts.errorOnExist); else + throw error; + } + await copyDir(src, dest, opts); return setDestMode(dest, srcMode); } diff --git a/test/parallel/test-fs-cp.mjs b/test/parallel/test-fs-cp.mjs index 63bc813ae22..afe512fd424 100644 --- a/test/parallel/test-fs-cp.mjs +++ b/test/parallel/test-fs-cp.mjs @@ -933,6 +933,38 @@ if (!isWindows) { ); } +// It can ignore EEXIST error when the destination folder has been created by other file operations in parallel (#53534) +{ + const src = './test/fixtures/copy/kitchen-sink'; + const dest = nextdir(); + + await Promise.all([ + fs.promises.cp(src, dest, { + recursive: true, + errorOnExist: false + }), + + fs.promises.mkdir(dest, { recursive: true }), + ]); + + assertDirEquivalent(src, dest); + + const dest2 = nextdir(); + + await assert.rejects( + async () => + Promise.all([ + fs.promises.cp(src, dest2, { + recursive: true, + errorOnExist: true + }), + + fs.promises.mkdir(dest2, { recursive: true }), + ]), + { code: 'EEXIST' } + ); +} + // It rejects if options is not object. { await assert.rejects(