From a09d11b5ef9240e3c70a2039f40885a24fa1a3b0 Mon Sep 17 00:00:00 2001 From: ShenHongFei Date: Sat, 22 Jun 2024 00:53:22 +0800 Subject: [PATCH 1/2] fs: calling mkdir in fs.cp function can ignore EEXIST error --- lib/internal/fs/cp/cp.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/internal/fs/cp/cp.js b/lib/internal/fs/cp/cp.js index f59bbdb1e59..7b22638b84c 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') + throw error; + } + await copyDir(src, dest, opts); return setDestMode(dest, srcMode); } From 56590001991e4eaa9d7f543ad62b6e3690fe690c Mon Sep 17 00:00:00 2001 From: ShenHongFei Date: Mon, 24 Jun 2024 12:24:07 +0800 Subject: [PATCH 2/2] fs: add test for fs.cp ignoring EEXIST --- lib/internal/fs/cp/cp.js | 2 +- test/parallel/test-fs-cp.mjs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/internal/fs/cp/cp.js b/lib/internal/fs/cp/cp.js index 7b22638b84c..f5add19e4eb 100644 --- a/lib/internal/fs/cp/cp.js +++ b/lib/internal/fs/cp/cp.js @@ -310,7 +310,7 @@ async function mkDirAndCopy(srcMode, src, dest, opts) { await mkdir(dest); } catch (error) { // If the folder already exists, skip it. - if (error.code !== 'EEXIST') + if (error.code === 'EEXIST' && !opts.errorOnExist); else throw error; } 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(