Skip to content

Commit e600f00

Browse files
committed
fs: preserve directory timestamps in cpSync fast path
This completes the work started in PR #65540. While the previous PR fixed directory timestamp preservation for the JavaScript paths, the native C++ fast path (CpSyncCopyDir in src/node_file.cc) used by fs.cpSync when no filter is provided still failed to preserve directory timestamps. This commit invokes the existing CopyUtimes helper for both the root destination directory and all subdirectories after their contents are recursively copied. PR-URL: #65678 Signed-off-by: Abhinandan Kumar <abhi128618@gmail.com>
1 parent 104285a commit e600f00

2 files changed

Lines changed: 28 additions & 3 deletions

File tree

src/node_file.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4207,6 +4207,10 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
42074207
if (!success) {
42084208
return false;
42094209
}
4210+
if (preserve_timestamps &&
4211+
!CopyUtimes(entry_dir_path, dest_file_path, env)) {
4212+
return false;
4213+
}
42104214
} else if (dir_entry.is_regular_file()) {
42114215
std::filesystem::copy_file(
42124216
dir_entry.path(), dest_file_path, file_copy_opts, error);
@@ -4231,7 +4235,9 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
42314235
return true;
42324236
};
42334237

4234-
copy_dir_contents(src_path, dest_path);
4238+
if (copy_dir_contents(src_path, dest_path) && preserve_timestamps) {
4239+
CopyUtimes(src_path, dest_path, env);
4240+
}
42354241
}
42364242

42374243
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(

test/parallel/test-fs-cp-sync-preserve-timestamps-dir.mjs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// This tests that cpSync with a filter preserves directory timestamps
2-
// when preserveTimestamps is true.
1+
// This tests that cpSync preserves directory timestamps
2+
// when preserveTimestamps is true, both on the JS fallback path (with filter)
3+
// and the native fast path (without filter).
34
import '../common/index.mjs';
45
import { nextdir } from '../common/fs.js';
56
import assert from 'node:assert';
@@ -40,3 +41,21 @@ assert.strictEqual(srcDirStat.mtime.getTime(), destDirStat.mtime.getTime());
4041
const srcRootStat = statSync(src);
4142
const destRootStat = statSync(dest);
4243
assert.strictEqual(srcRootStat.mtime.getTime(), destRootStat.mtime.getTime());
44+
45+
// Copy with preserveTimestamps and NO filter (to exercise the native fast path).
46+
const destFast = nextdir();
47+
cpSync(src, destFast, {
48+
recursive: true,
49+
preserveTimestamps: true,
50+
});
51+
52+
// Verify file timestamps are preserved.
53+
const destFastFileStat = statSync(join(destFast, 'subdir', 'file.txt'));
54+
assert.strictEqual(srcFileStat.mtime.getTime(), destFastFileStat.mtime.getTime());
55+
56+
// Verify directory timestamps are preserved.
57+
const destFastDirStat = statSync(join(destFast, 'subdir'));
58+
assert.strictEqual(srcDirStat.mtime.getTime(), destFastDirStat.mtime.getTime());
59+
60+
const destFastRootStat = statSync(destFast);
61+
assert.strictEqual(srcRootStat.mtime.getTime(), destFastRootStat.mtime.getTime());

0 commit comments

Comments
 (0)