Skip to content

Commit a30f200

Browse files
yohannesjoyaaduh95
authored andcommitted
fs: fix cpSync() abort when dest is a dangling symlink
CpSyncCheckPaths() used the throwing overload of std::filesystem::equivalent(), which fails when dest is a dangling symlink. The uncaught C++ exception aborted the process. Use the std::error_code overload instead: a dangling dest is not the same file as src, so the copy goes ahead and replaces the link. Fixes: #67141 Signed-off-by: yohannesjoya <yohannesdestagebru10@gmail.com> PR-URL: #67142 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Jason Zhang <xzha4350@gmail.com>
1 parent 64cdd36 commit a30f200

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

‎src/node_file.cc‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4643,8 +4643,10 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
46434643
auto dest_path_str = ConvertPathToUTF8(dest_path);
46444644

46454645
if (!error_code) {
4646-
// Check if src and dest are identical.
4647-
if (std::filesystem::equivalent(src_path, dest_path)) {
4646+
// Check if src and dest are identical. A dangling dest symlink makes
4647+
// equivalent() fail, which means they are not the same file.
4648+
std::error_code equivalent_error;
4649+
if (std::filesystem::equivalent(src_path, dest_path, equivalent_error)) {
46484650
static constexpr const char* message =
46494651
"src and dest cannot be the same %s";
46504652
return THROW_ERR_FS_CP_EINVAL(env, message, dest_path_str);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This tests that cpSync() replaces a dangling symlink in dest with a file
2+
// instead of aborting the process.
3+
import { mustNotMutateObjectDeep } from '../common/index.mjs';
4+
import { nextdir } from '../common/fs.js';
5+
import assert from 'node:assert';
6+
import {
7+
cpSync,
8+
existsSync,
9+
lstatSync,
10+
mkdirSync,
11+
readFileSync,
12+
symlinkSync,
13+
writeFileSync,
14+
} from 'node:fs';
15+
import { join } from 'node:path';
16+
import tmpdir from '../common/tmpdir.js';
17+
18+
tmpdir.refresh();
19+
20+
const dir = nextdir();
21+
mkdirSync(dir);
22+
const src = join(dir, 'src');
23+
const dest = join(dir, 'dest');
24+
writeFileSync(src, 'data');
25+
symlinkSync('missing', dest);
26+
27+
cpSync(src, dest, mustNotMutateObjectDeep({ force: true }));
28+
assert(lstatSync(dest).isFile());
29+
assert.strictEqual(readFileSync(dest, 'utf8'), 'data');
30+
assert(!existsSync(join(dir, 'missing')));

0 commit comments

Comments
 (0)