Repository: mesos Updated Branches: refs/heads/1.5.x c8dd080af -> f0f1b55e0
Windows: Changed sharing semantics in `get_handle_follow`. In the internal Windows functions `get_handle(_no)_follow`, we erroneously only opened with `FILE_SHARE_READ` permissions. While we are only opening the files for reading (indicated by the `GENERIC_READ` flag), we need to open with write and delete sharing semantics too, in order to avoid obtaining a lock on the file. A regression test using `os::realpath` on a file that was already being written to was added to ensure the correct behavior. Review: https://reviews.apache.org/r/65936/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/59d59cab Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/59d59cab Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/59d59cab Branch: refs/heads/1.5.x Commit: 59d59cab981f92a363f7c8612ce7c05a6c8a97ea Parents: c8dd080 Author: John Kordich <[email protected]> Authored: Fri Mar 9 15:10:25 2018 -0800 Committer: Andrew Schwartzmeyer <[email protected]> Committed: Fri Mar 9 18:12:43 2018 -0800 ---------------------------------------------------------------------- .../stout/internal/windows/reparsepoint.hpp | 18 ++++++---- 3rdparty/stout/tests/os/filesystem_tests.cpp | 37 ++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/59d59cab/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp b/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp index 858b3c7..280956f 100644 --- a/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp +++ b/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp @@ -179,8 +179,9 @@ inline Try<SharedHandle> get_handle_follow(const std::string& absolute_path) // can be found in MSDN[2]. // // The `GENERIC_READ` flag is being used because it's the most common way of - // opening a file for reading only. The `FILE_SHARE_READ` allows other - // processes to read the file at the same time. MSDN[1] provides a more + // opening a file for reading only. The `SHARE` flags allow other processes + // to read the file at the same time, as well as allow this process to read + // files that were also opened with these flags. MSDN[1] provides a more // detailed explanation of these flags. // // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx // NOLINT(whitespace/line_length) @@ -192,7 +193,9 @@ inline Try<SharedHandle> get_handle_follow(const std::string& absolute_path) const HANDLE handle = ::CreateFileW( longpath(absolute_path).data(), GENERIC_READ, // Open the file for reading only. - FILE_SHARE_READ, // Just reading this file, allow others to do the same. + // Must pass in all SHARE flags below, in case file is already open. + // Otherwise, we may get an access denied error. + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, // Ignored. OPEN_EXISTING, // Open existing file. access_flags, // Open file, not the symlink itself. @@ -234,8 +237,9 @@ inline Try<SharedHandle> get_handle_no_follow(const std::string& absolute_path) // can be found in MSDN[2]. // // The `GENERIC_READ` flag is being used because it's the most common way of - // opening a file for reading only. The `FILE_SHARE_READ` allows other - // processes to read the file at the same time. MSDN[1] provides a more + // opening a file for reading only. The `SHARE` flags allow other processes + // to read the file at the same time, as well as allow this process to read + // files that were also opened with these flags. MSDN[1] provides a more // detailed explanation of these flags. // // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx // NOLINT(whitespace/line_length) @@ -247,7 +251,9 @@ inline Try<SharedHandle> get_handle_no_follow(const std::string& absolute_path) const HANDLE handle = ::CreateFileW( longpath(absolute_path).data(), GENERIC_READ, // Open the file for reading only. - FILE_SHARE_READ, // Just reading this file, allow others to do the same. + // Must pass in all SHARE flags below, in case file is already open. + // Otherwise, we may get an access denied error. + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, // Ignored. OPEN_EXISTING, // Open existing symlink. access_flags, // Open symlink, not the file it points to. http://git-wip-us.apache.org/repos/asf/mesos/blob/59d59cab/3rdparty/stout/tests/os/filesystem_tests.cpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/tests/os/filesystem_tests.cpp b/3rdparty/stout/tests/os/filesystem_tests.cpp index 2204d10..ab44eee 100644 --- a/3rdparty/stout/tests/os/filesystem_tests.cpp +++ b/3rdparty/stout/tests/os/filesystem_tests.cpp @@ -259,6 +259,43 @@ TEST_F(FsTest, CreateDirectoryLongerThanMaxPath) EXPECT_SOME_TRUE(os::access(testfile, R_OK | W_OK)); EXPECT_SOME_EQ(testfile, os::realpath(testfile)); } + + +// This test ensures that `os::realpath` will work on open files. +TEST_F(FsTest, RealpathValidationOnOpenFile) +{ + // Open a file to write, with "SHARE" read/write permissions, + // then call `os::realpath` on that file. + const string file = path::join(sandbox.get(), id::UUID::random().toString()); + + const string data = "data"; + + const SharedHandle handle( + ::CreateFileW( + wide_stringify(file).data(), + FILE_APPEND_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, // No inheritance. + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + nullptr), // No template file. + ::CloseHandle); + EXPECT_NE(handle.get_handle(), INVALID_HANDLE_VALUE); + + DWORD bytes_written; + BOOL written = ::WriteFile( + handle.get_handle(), + data.c_str(), + static_cast<DWORD>(data.size()), + &bytes_written, + nullptr); // No overlapped I/O. + EXPECT_EQ(written, TRUE); + EXPECT_EQ(data.size(), bytes_written); + + // Verify that `os::realpath` (which calls `CreateFileW` on Windows) is + // successful even though the file is open elsewhere. + EXPECT_SOME_EQ(file, os::realpath(file)); +} #endif // __WINDOWS__
