diff --git a/repertory/repertory_test/src/winfsp_drive_read_write_test.cpp b/repertory/repertory_test/src/winfsp_drive_read_write_test.cpp new file mode 100644 index 00000000..e6ce4e93 --- /dev/null +++ b/repertory/repertory_test/src/winfsp_drive_read_write_test.cpp @@ -0,0 +1,208 @@ +/* + Copyright <2018-2024> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include +#if defined(_WIN32) + +// +// Implemented test cases based on WinFsp tests: +// https://github.com/winfsp/winfsp/blob/v2.0/tst/winfsp-tests +// +#include "fixtures/winfsp_fixture.hpp" + +namespace repertory { +TYPED_TEST_CASE(winfsp_test, winfsp_provider_types); + +static void test_file(auto &&file_path, auto &&flags) { + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | flags, nullptr); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + auto pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN); + EXPECT_EQ(0, pointer); + + auto write_buffer = utils::generate_secure_random(16U); + + DWORD bytes_written{}; + EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), write_buffer.size(), + &bytes_written, nullptr)); + + EXPECT_EQ(static_cast(write_buffer.size()), bytes_written); + EXPECT_EQ(pointer + bytes_written, + ::SetFilePointer(handle, 0, 0, FILE_CURRENT)); + + pointer = ::SetFilePointer(handle, 2U * write_buffer.size(), 0, FILE_BEGIN); + EXPECT_EQ(static_cast(2U * write_buffer.size()), pointer); + + EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), write_buffer.size(), + &bytes_written, nullptr)); + EXPECT_EQ(static_cast(write_buffer.size()), bytes_written); + EXPECT_EQ(pointer + bytes_written, + ::SetFilePointer(handle, 0, 0, FILE_CURRENT)); + + pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN); + EXPECT_EQ(0U, pointer); + + DWORD bytes_read{}; + std::array read_buffer{}; + EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(), + &bytes_read, nullptr)); + + // ASSERT(BytesPerSector == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + // FilePointer = SetFilePointer(Handle, 2 * BytesPerSector, 0, FILE_BEGIN); + // ASSERT(2 * BytesPerSector == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = ReadFile(Handle, Buffer[1], BytesPerSector, &BytesTransferred, + // 0); ASSERT(Success); ASSERT(BytesPerSector == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + // FilePointer = SetFilePointer(Handle, 2 * BytesPerSector, 0, FILE_BEGIN); + // ASSERT(2 * BytesPerSector == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = + // ReadFile(Handle, Buffer[1], 2 * BytesPerSector, &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(BytesPerSector == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + // FilePointer = SetFilePointer(Handle, 3 * BytesPerSector, 0, FILE_BEGIN); + // ASSERT(3 * BytesPerSector == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = ReadFile(Handle, Buffer[1], BytesPerSector, &BytesTransferred, + // 0); ASSERT(Success); ASSERT(0 == BytesTransferred); ASSERT(FilePointer + + // BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // Success = WriteFile(Handle, Buffer[0], 2 * SystemInfo.dwPageSize, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + // Buffer[0] = AllocBuffer[0]; + // Buffer[1] = AllocBuffer[0]; + // + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // Success = WriteFile(Handle, Buffer[0], 2 * SystemInfo.dwPageSize, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // Success = + // WriteFile(Handle, Buffer[0], 2 * SystemInfo.dwPageSize + + // BytesPerSector, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = + // ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize + BytesPerSector, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + EXPECT_TRUE(::CloseHandle(handle)); + + handle = ::CreateFileA( + file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | flags | FILE_FLAG_DELETE_ON_CLOSE, nullptr); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + // FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + // ASSERT(0 == FilePointer); + // memset(AllocBuffer[1], 0, AllocBufferSize); + // Success = + // ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize + BytesPerSector, + // &BytesTransferred, 0); + // ASSERT(Success); + // ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred); + // ASSERT(FilePointer + BytesTransferred == + // SetFilePointer(Handle, 0, 0, FILE_CURRENT)); + // ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + // + EXPECT_TRUE(::CloseHandle(handle)); + + handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, 0, nullptr); + ASSERT_EQ(INVALID_HANDLE_VALUE, handle); + ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); +} + +TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_cache) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_5"}), + }; + test_file(file_path, FILE_FLAG_NO_BUFFERING); +} +} // namespace repertory + +#endif // defined(_WIN32) diff --git a/repertory/repertory_test/src/winfsp_drive_test.cpp b/repertory/repertory_test/src/winfsp_drive_test.cpp index eee43dc4..0a927907 100644 --- a/repertory/repertory_test/src/winfsp_drive_test.cpp +++ b/repertory/repertory_test/src/winfsp_drive_test.cpp @@ -39,6 +39,8 @@ // TODO revisit rename_standby_test // TODO revisit rename_pid_test // TODO revisit rename_ex_test +// TODO revisit setvolinfo_test +// TODO revisit query_winfsp_test // // Implemented test cases based on WinFsp tests: diff --git a/repertory/repertory_test/src/winfsp_drive_volume_test.cpp b/repertory/repertory_test/src/winfsp_drive_volume_test.cpp index d389e65b..646119c4 100644 --- a/repertory/repertory_test/src/winfsp_drive_volume_test.cpp +++ b/repertory/repertory_test/src/winfsp_drive_volume_test.cpp @@ -84,6 +84,17 @@ TYPED_TEST(winfsp_test, volume_can_get_size_info) { EXPECT_NE(0U, free_bytes.QuadPart); } } + +TYPED_TEST(winfsp_test, volume_can_get_file_type) { + auto handle = ::CreateFileA( + this->mount_location.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + EXPECT_EQ(FILE_TYPE_REMOTE, ::GetFileType(handle)); + + ::CloseHandle(handle); +} } // namespace repertory #endif // defined(_WIN32)