From 1c4de1916e36f8462c48a36ce7c88b247465f3cf Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Wed, 1 Nov 2017 13:18:39 +0200 Subject: [PATCH] win: map UV_FS_O_EXLOCK to a share mode of 0 This is necessary to enable writing past the MBR of a raw block device. Fixes: https://github.com/libuv/libuv/issues/1605 PR-URL: https://github.com/libuv/libuv/pull/1613 Reviewed-By: Bartosz Sosnowski --- docs/src/fs.rst | 4 +++- include/uv-win.h | 8 +++---- src/win/fs.c | 9 +++++++- test/test-fs.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 6 +++++ 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index f46c4e761..16d5e05c7 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -409,7 +409,9 @@ File open constants Atomically obtain an exclusive lock. .. note:: - `UV_FS_O_EXLOCK` is only supported on macOS. + `UV_FS_O_EXLOCK` is only supported on macOS and Windows. + + .. versionchanged:: 1.17.0 support is added for Windows. .. c:macro:: UV_FS_O_NOATIME diff --git a/include/uv-win.h b/include/uv-win.h index be150fc48..b96bed22a 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -664,13 +664,13 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_FS_O_WRONLY _O_WRONLY /* fs open() flags supported on other platforms (or mapped on this platform): */ -#define UV_FS_O_DIRECT 0x2000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */ #define UV_FS_O_DIRECTORY 0 -#define UV_FS_O_DSYNC 0x4000000 /* FILE_FLAG_WRITE_THROUGH */ -#define UV_FS_O_EXLOCK 0 +#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */ #define UV_FS_O_NOATIME 0 #define UV_FS_O_NOCTTY 0 #define UV_FS_O_NOFOLLOW 0 #define UV_FS_O_NONBLOCK 0 #define UV_FS_O_SYMLINK 0 -#define UV_FS_O_SYNC 0x8000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/src/win/fs.c b/src/win/fs.c index b90eaa754..11c7c13ed 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -439,8 +439,15 @@ void fs__open(uv_fs_t* req) { * does. We indiscriminately use all the sharing modes, to match * UNIX semantics. In particular, this ensures that the file can * be deleted even whilst it's open, fixing issue #1449. + * We still support exclusive sharing mode, since it is necessary + * for opening raw block devices, otherwise Windows will prevent + * any attempt to write past the master boot record. */ - share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + if (flags & UV_FS_O_EXLOCK) { + share = 0; + } else { + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + } switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { case 0: diff --git a/test/test-fs.c b/test/test-fs.c index 6afa65079..d22384ca6 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -3061,3 +3061,60 @@ TEST_IMPL(fs_null_req) { return 0; } + +#ifdef _WIN32 +TEST_IMPL(fs_exclusive_sharing_mode) { + int r; + + /* Setup. */ + unlink("test_file"); + + ASSERT(UV_FS_O_EXLOCK > 0); + + r = uv_fs_open(NULL, + &open_req1, + "test_file", + O_RDWR | O_CREAT | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_open(NULL, + &open_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r < 0); + ASSERT(open_req2.result < 0); + uv_fs_req_cleanup(&open_req2); + + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(NULL, + &open_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req2.result >= 0); + uv_fs_req_cleanup(&open_req2); + + r = uv_fs_close(NULL, &close_req, open_req2.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; +} +#endif diff --git a/test/test-list.h b/test/test-list.h index 3e88e6c92..23e363813 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -321,6 +321,9 @@ TEST_DECLARE (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) TEST_DECLARE (fs_file_pos_after_op_with_offset) TEST_DECLARE (fs_null_req) +#ifdef _WIN32 +TEST_DECLARE (fs_exclusive_sharing_mode) +#endif TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -832,6 +835,9 @@ TASK_LIST_START TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (fs_file_pos_after_op_with_offset) TEST_ENTRY (fs_null_req) +#ifdef _WIN32 + TEST_ENTRY (fs_exclusive_sharing_mode) +#endif TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval)