Skip to content

Commit aaccbff

Browse files
committed
fs: check subdir correctly in cpSync
1 parent 8b8fc53 commit aaccbff

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

src/node_file.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3192,8 +3192,13 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
31923192
}
31933193

31943194
std::string dest_path_str = dest_path.string();
3195+
std::string src_path_str = src_path.string();
3196+
if (!src_path_str.ends_with(std::filesystem::path::preferred_separator)) {
3197+
src_path_str += std::filesystem::path::preferred_separator;
3198+
}
31953199
// Check if dest_path is a subdirectory of src_path.
3196-
if (src_is_dir && dest_path_str.starts_with(src_path.string())) {
3200+
if (src_is_dir &&
3201+
dest_path_str.starts_with(src_path_str)) {
31973202
std::string message = "Cannot copy " + src_path.string() +
31983203
" to a subdirectory of self " + dest_path.string();
31993204
return THROW_ERR_FS_CP_EINVAL(env, message.c_str());

test/parallel/test-fs-cp.mjs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import tmpdir from '../common/tmpdir.js';
2424
tmpdir.refresh();
2525

2626
let dirc = 0;
27-
function nextdir() {
28-
return tmpdir.resolve(`copy_${++dirc}`);
27+
function nextdir(dirname) {
28+
return tmpdir.resolve(dirname || `copy_${++dirc}`);
2929
}
3030

3131
// Synchronous implementation of copy.
@@ -312,6 +312,45 @@ function nextdir() {
312312
);
313313
}
314314

315+
// It must not throw error if attempt is made to copy to dest
316+
// directory with same prefix as src directory
317+
// regression test for https://github.com/nodejs/node/issues/54285
318+
{
319+
const src = nextdir('prefix');
320+
const dest = nextdir('prefix-a');
321+
mkdirSync(src);
322+
mkdirSync(dest);
323+
cpSync(src, dest, mustNotMutateObjectDeep({ recursive: true }));
324+
}
325+
326+
// It must not throw error if attempt is made to copy to dest
327+
// directory if the parent of dest has same prefix as src directory
328+
// regression test for https://github.com/nodejs/node/issues/54285
329+
{
330+
const src = nextdir('aa');
331+
const destParent = nextdir('aaa');
332+
const dest = nextdir('aaa/aabb');
333+
mkdirSync(src);
334+
mkdirSync(destParent);
335+
mkdirSync(dest);
336+
cpSync(src, dest, mustNotMutateObjectDeep({ recursive: true }));
337+
}
338+
339+
// It throws error if attempt is made to copy src to dest
340+
// when src is parent directory of the parent of dest
341+
{
342+
const src = nextdir('a');
343+
const destParent = nextdir('a/b');
344+
const dest = nextdir('a/b/c');
345+
mkdirSync(src);
346+
mkdirSync(destParent);
347+
mkdirSync(dest);
348+
assert.throws(
349+
() => cpSync(src, dest, mustNotMutateObjectDeep({ recursive: true })),
350+
{ code: 'ERR_FS_CP_EINVAL' },
351+
);
352+
}
353+
315354
// It throws error if attempt is made to copy to subdirectory of self.
316355
{
317356
const src = './test/fixtures/copy/kitchen-sink';

0 commit comments

Comments
 (0)