From 6760d51b52e35bdcc7102e3ddf6db9c8d275563e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 19 Oct 2014 20:48:51 -0700 Subject: [PATCH] windows: fix fs_write with nbufs > 1 and offset When multiple bufs are specified, overlapped needs to be advanced manually between each write. Without this, each buf will be written to the same position (if offset is specified.) ReadFile() automatically advances, but WriteFile() does not. --- src/win/fs.c | 13 ++++++---- test/test-fs.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 47e65e84..11d20f2d 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -613,11 +613,6 @@ void fs__write(uv_fs_t* req) { if (offset != -1) { memset(&overlapped, 0, sizeof overlapped); - - offset_.QuadPart = offset; - overlapped.Offset = offset_.LowPart; - overlapped.OffsetHigh = offset_.HighPart; - overlapped_ptr = &overlapped; } else { overlapped_ptr = NULL; @@ -627,6 +622,14 @@ void fs__write(uv_fs_t* req) { bytes = 0; do { DWORD incremental_bytes; + + /* WriteFile() does not advance overlapped as ReadFile() does. */ + if (offset != -1) { + offset_.QuadPart = offset + bytes; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + } + result = WriteFile(handle, req->bufs[index].base, req->bufs[index].len, diff --git a/test/test-fs.c b/test/test-fs.c index 6095ff89..3e9dcb81 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -110,6 +110,7 @@ static uv_fs_t futime_req; static char buf[32]; static char test_buf[] = "test-buffer\n"; +static char test_buf2[] = "second-buffer\n"; static uv_buf_t iov; static void check_permission(const char* filename, unsigned int mode) { @@ -2164,3 +2165,64 @@ TEST_IMPL(fs_read_file_eof) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(fs_write_multiple_bufs) { + uv_buf_t iovs[2]; + int r; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + iovs[0] = uv_buf_init(test_buf, sizeof(test_buf)); + iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2)); + r = uv_fs_write(loop, &write_req, open_req1.result, iovs, 2, 0, NULL); + ASSERT(r >= 0); + ASSERT(write_req.result >= 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + memset(buf, 0, sizeof(buf)); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); + ASSERT(r >= 0); + ASSERT(read_req.result >= 0); + ASSERT(memcmp(buf, test_buf, sizeof(test_buf)) == 0); + ASSERT(strcmp(buf + sizeof(test_buf), test_buf2) == 0); + uv_fs_req_cleanup(&read_req); + + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, + read_req.result, NULL); + ASSERT(r == 0); + ASSERT(read_req.result == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index eff34306..85ddac82 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -246,6 +246,7 @@ TEST_DECLARE (fs_scandir_empty_dir) TEST_DECLARE (fs_scandir_file) TEST_DECLARE (fs_open_dir) TEST_DECLARE (fs_rename_to_existing_file) +TEST_DECLARE (fs_write_multiple_bufs) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -619,6 +620,7 @@ TASK_LIST_START TEST_ENTRY (fs_scandir_file) TEST_ENTRY (fs_open_dir) TEST_ENTRY (fs_rename_to_existing_file) + TEST_ENTRY (fs_write_multiple_bufs) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) TEST_ENTRY (threadpool_multiple_event_loops)