diff --git a/lib/internal/fs/cp/cp-sync.js b/lib/internal/fs/cp/cp-sync.js index 03fcae9b7cdbda..1769ef50b97109 100644 --- a/lib/internal/fs/cp/cp-sync.js +++ b/lib/internal/fs/cp/cp-sync.js @@ -134,6 +134,15 @@ function setDestTimestamps(src, dest) { // TODO(@anonrig): Move this function to C++. function onDir(srcStat, destStat, src, dest, opts) { if (!destStat) return copyDir(src, dest, opts, true, srcStat.mode); + if (opts.errorOnExist && !opts.force) { + throw new ERR_FS_CP_EEXIST({ + message: `${dest} already exists`, + path: dest, + syscall: 'cp', + errno: EEXIST, + code: 'EEXIST', + }); + } return copyDir(src, dest, opts); } diff --git a/test/parallel/test-fs-cp-sync-dir-exists-error-on-exist.mjs b/test/parallel/test-fs-cp-sync-dir-exists-error-on-exist.mjs new file mode 100644 index 00000000000000..bcc95476a9f655 --- /dev/null +++ b/test/parallel/test-fs-cp-sync-dir-exists-error-on-exist.mjs @@ -0,0 +1,32 @@ +// This tests that cpSync() throws if errorOnExist is true, force is false, +// and the destination directory already exists (even if contents don't +// conflict), matching the asynchronous cp() behavior. + +import '../common/index.mjs'; +import { nextdir } from '../common/fs.js'; +import assert from 'node:assert'; +import { cpSync, mkdirSync, writeFileSync } from 'node:fs'; +import tmpdir from '../common/tmpdir.js'; + +tmpdir.refresh(); + +const src = nextdir(); +const dest = nextdir(); + +// Create source directory with a file +mkdirSync(src); +writeFileSync(`${src}/file.txt`, 'test'); + +// Create destination directory with a different (non-conflicting) file +mkdirSync(dest); +writeFileSync(`${dest}/other.txt`, 'existing'); + +// Should throw because dest directory already exists +assert.throws( + () => cpSync(src, dest, { + recursive: true, + errorOnExist: true, + force: false, + }), + { code: 'ERR_FS_CP_EEXIST' }, +);