From b0653625e26cef175156403823e0758f550cce3e Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Mon, 18 Sep 2017 18:47:45 -0400 Subject: [PATCH] unix: truncate destination in uv_fs_copyfile() This commit adds the O_TRUNC flag to the destination file in the sendfile() fallback. This allows smaller source files to be properly copied into larger existing destination files. Refs: https://github.com/libuv/libuv/pull/1551 PR-URL: https://github.com/libuv/libuv/pull/1552 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/fs.c | 2 +- test/test-fs-copyfile.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 00af4675..52b3123f 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -810,7 +810,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { goto out; } - dst_flags = O_WRONLY | O_CREAT; + dst_flags = O_WRONLY | O_CREAT | O_TRUNC; if (req->flags & UV_FS_COPYFILE_EXCL) dst_flags |= O_EXCL; diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index e91044e0..460c1dc6 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -68,7 +68,8 @@ static void touch_file(const char* name, unsigned int size) { int r; unsigned int i; - r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, + S_IWUSR | S_IRUSR, NULL); uv_fs_req_cleanup(&req); ASSERT(r >= 0); file = r; @@ -136,6 +137,12 @@ TEST_IMPL(fs_copyfile) { ASSERT(r == UV_EEXIST); uv_fs_req_cleanup(&req); + /* Truncates when an existing destination is larger than the source file. */ + touch_file(src, 1); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + /* Copies a larger file. */ unlink(dst); touch_file(src, 4096 * 2); @@ -148,9 +155,9 @@ TEST_IMPL(fs_copyfile) { unlink(dst); r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); ASSERT(r == 0); - ASSERT(result_check_count == 4); - uv_run(loop, UV_RUN_DEFAULT); ASSERT(result_check_count == 5); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(result_check_count == 6); unlink(dst); /* Cleanup */ return 0;