Skip to content

Commit 7fab656

Browse files
fs: keep timestamps of files skipped by cpSync
With `force: false` and `preserveTimestamps: true`, the native directory copy used by `cpSync()` left existing destination files in place but still copied the source timestamps onto them. The JavaScript walk, used by `cpSync()` with a `filter` and by `fs.cp()`, leaves those files untouched. Only copy the timestamps of files that were actually copied, as is already done for their mode. Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com> PR-URL: #66305 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent d880e74 commit 7fab656

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

‎src/node_file.cc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5079,7 +5079,7 @@ CpError CopyDirRecursive(const std::filesystem::path& src_path,
50795079
return CpError::Std(error, dest_str);
50805080
}
50815081

5082-
if (options.preserve_timestamps) {
5082+
if (copied && options.preserve_timestamps) {
50835083
CpError utimes = CopyUtimes(dir_entry.path(), dest_file_path);
50845084
if (utimes.kind != CpError::kNone) {
50855085
return utimes;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This tests that cpSync with force: false and preserveTimestamps: true leaves
2+
// the timestamps of the destination files it skips untouched.
3+
import { mustNotMutateObjectDeep } from '../common/index.mjs';
4+
import { nextdir } from '../common/fs.js';
5+
import assert from 'node:assert';
6+
import { cpSync, mkdirSync, readFileSync, statSync, utimesSync, writeFileSync } from 'node:fs';
7+
import { join } from 'node:path';
8+
import tmpdir from '../common/tmpdir.js';
9+
10+
tmpdir.refresh();
11+
12+
const src = nextdir();
13+
mkdirSync(src, { recursive: true });
14+
writeFileSync(join(src, 'file.txt'), 'src', 'utf8');
15+
utimesSync(join(src, 'file.txt'), 1000, 1000);
16+
17+
// Without a filter the tree is copied in C++, with one it is walked in
18+
// JavaScript.
19+
for (const filter of [undefined, () => true]) {
20+
const dest = nextdir();
21+
mkdirSync(dest, { recursive: true });
22+
writeFileSync(join(dest, 'file.txt'), 'dest', 'utf8');
23+
utimesSync(join(dest, 'file.txt'), 2000, 2000);
24+
25+
cpSync(src, dest, mustNotMutateObjectDeep({
26+
filter,
27+
force: false,
28+
preserveTimestamps: true,
29+
recursive: true,
30+
}));
31+
32+
assert.strictEqual(readFileSync(join(dest, 'file.txt'), 'utf8'), 'dest');
33+
assert.strictEqual(statSync(join(dest, 'file.txt')).mtime.getTime(), 2000 * 1000);
34+
}

0 commit comments

Comments
 (0)