diff --git a/src/unix/fs.c b/src/unix/fs.c index a6b2aa25c0b..0c6c585c6d6 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1233,6 +1233,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { uv_file dstfd; struct stat src_statsbuf; struct stat dst_statsbuf; + struct timespec times[2]; int dst_flags; int result; int err; @@ -1310,6 +1311,29 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { } } + /** + * Change the timestamps of the destination file to match the source file. + */ +#if defined(__APPLE__) + times[0] = src_statsbuf.st_atimespec; + times[1] = src_statsbuf.st_mtimespec; +#else + times[0] = src_statsbuf.st_atim; + times[1] = src_statsbuf.st_mtim; +#endif + + if (futimens(dstfd, times) == -1) { + err = UV__ERR(errno); + goto out; + } + + /* + * Change the ownership and permissions of the destination file to match the + * source file. + * `cp -p` does not care about errors here, so we don't either. + */ + fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid); + if (fchmod(dstfd, src_statsbuf.st_mode) == -1) { err = UV__ERR(errno); #ifdef __linux__ diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 3aacf12596f..f7a0c2363e8 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -46,6 +46,8 @@ static void handle_result(uv_fs_t* req) { uv_fs_t stat_req; uint64_t size; uint64_t mode; + uint64_t uid; + uint64_t gid; int r; ASSERT_EQ(req->fs_type, UV_FS_COPYFILE); @@ -56,11 +58,15 @@ static void handle_result(uv_fs_t* req) { ASSERT_OK(r); size = stat_req.statbuf.st_size; mode = stat_req.statbuf.st_mode; + uid = stat_req.statbuf.st_uid; + gid = stat_req.statbuf.st_gid; uv_fs_req_cleanup(&stat_req); r = uv_fs_stat(NULL, &stat_req, dst, NULL); ASSERT_OK(r); ASSERT_EQ(stat_req.statbuf.st_size, size); ASSERT_EQ(stat_req.statbuf.st_mode, mode); + ASSERT_EQ(stat_req.statbuf.st_uid, uid); + ASSERT_EQ(stat_req.statbuf.st_gid, gid); uv_fs_req_cleanup(&stat_req); uv_fs_req_cleanup(req); result_check_count++;