diff --git a/repertory/repertory_test/src/winfsp_drive_rdrw_test.cpp b/repertory/repertory_test/src/winfsp_drive_rdrw_test.cpp index 0d7e0b0c..91542e40 100644 --- a/repertory/repertory_test/src/winfsp_drive_rdrw_test.cpp +++ b/repertory/repertory_test/src/winfsp_drive_rdrw_test.cpp @@ -577,168 +577,179 @@ static void test_mixed_file(auto &&mount_location, auto &&file_path) { EXPECT_TRUE(::DeleteFileA(file_path.c_str())); } -// static void test_mmap_file(auto &&mount_location, auto &&file_path, -// auto &&flags) { -// SYSTEM_INFO sys_info{}; -// ::GetSystemInfo(&sys_info); -// -// DWORD bytes_per_sector{}; -// DWORD free_clusters{}; -// DWORD sectors_per_cluster{}; -// DWORD total_clusters{}; -// EXPECT_TRUE(::GetDiskFreeSpaceA(mount_location.c_str(), -// §ors_per_cluster, -// &bytes_per_sector, &free_clusters, -// &total_clusters)); -// const auto buffer_size = 16U * sys_info.dwPageSize; -// auto write_buffer = -// utils::generate_secure_random(buffer_size); -// -// handle1 = CreateFileW(FilePath, GENERIC_READ | GENERIC_WRITE, -// FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, -// FILE_ATTRIBUTE_NORMAL | CreateFlags, 0); -// ASSERT(INVALID_HANDLE_VALUE != handle1); -// -// Mapping = CreateFileMappingW(handle1, 0, PAGE_READWRITE, 0, -// FileSize0 + FileSize1, 0); -// ASSERT(0 != Mapping); -// -// if (EarlyClose) { -// Success = CloseHandle(Handle); -// ASSERT(Success); -// } -// -// MappedView = MapViewOfFile(Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); -// ASSERT(0 != MappedView); -// -// srand(seed); -// for (PUINT8 Bgn = MappedView + FileSize1 / 2, End = Bgn + FileSize0; -// End > Bgn; Bgn++) -// *Bgn = rand() & 0xff; -// -// Success = UnmapViewOfFile(MappedView); -// ASSERT(Success); -// -// MappedView = MapViewOfFile(Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); -// ASSERT(0 != MappedView); -// -// srand(seed); -// for (PUINT8 Bgn = MappedView + FileSize1 / 2, End = Bgn + FileSize0; -// End > Bgn; Bgn++) -// ASSERT(*Bgn == (rand() & 0xff)); -// -// Success = UnmapViewOfFile(MappedView); -// ASSERT(Success); -// -// Success = CloseHandle(Mapping); -// ASSERT(Success); -// -// if (!EarlyClose) { -// Success = CloseHandle(Handle); -// ASSERT(Success); -// } -// -// handle1 = CreateFileW(FilePath, GENERIC_READ | GENERIC_WRITE, -// FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, -// FILE_ATTRIBUTE_NORMAL | CreateFlags, 0); -// ASSERT(INVALID_HANDLE_VALUE != handle1); -// -// Mapping = CreateFileMappingW(handle1, 0, PAGE_READWRITE, 0, -// FileSize0 + FileSize1, 0); -// ASSERT(0 != Mapping); -// -// if (EarlyClose) { -// Success = CloseHandle(Handle); -// ASSERT(Success); -// } -// -// MappedView = MapViewOfFile(Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); -// ASSERT(0 != MappedView); -// -// srand(seed); -// for (PUINT8 Bgn = MappedView + FileSize1 / 2, End = Bgn + FileSize0; -// End > Bgn; Bgn++) -// ASSERT(*Bgn == (rand() & 0xff)); -// -// if (!EarlyClose) { -// pointer = SetFilePointer(handle1, FileSize0 / 2, 0, FILE_BEGIN); -// ASSERT(FileSize0 / 2 == pointer); -// Success = -// WriteFile(handle1, Buffer[0], bytes_per_sector, &BytesTransferred, 0); -// ASSERT(Success); -// ASSERT(bytes_per_sector == BytesTransferred); -// ASSERT(pointer + BytesTransferred == -// SetFilePointer(handle1, 0, 0, FILE_CURRENT)); -// } -// -// Success = UnmapViewOfFile(MappedView); -// ASSERT(Success); -// -// Success = CloseHandle(Mapping); -// ASSERT(Success); -// -// if (!EarlyClose) { -// Success = CloseHandle(Handle); -// ASSERT(Success); -// } -// -// handle1 = CreateFileW(FilePath, GENERIC_READ | GENERIC_WRITE, -// FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, -// FILE_ATTRIBUTE_NORMAL | CreateFlags, 0); -// ASSERT(INVALID_HANDLE_VALUE != handle1); -// -// Mapping = CreateFileMappingW(handle1, 0, PAGE_READWRITE, 0, -// FileSize0 + FileSize1, 0); -// ASSERT(0 != Mapping); -// -// if (EarlyClose) { -// Success = CloseHandle(Handle); -// ASSERT(Success); -// } -// -// MappedView = MapViewOfFile(Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); -// ASSERT(0 != MappedView); -// -// if (!EarlyClose) { -// pointer = SetFilePointer(handle1, FileSize0 / 2, 0, FILE_BEGIN); -// ASSERT(FileSize0 / 2 == pointer); -// memset(Buffer[1], 0, bytes_per_sector); -// Success = ReadFile(handle1, Buffer[1], bytes_per_sector, &BytesTransferred, -// 0); ASSERT(Success); ASSERT(bytes_per_sector == BytesTransferred); -// ASSERT(pointer + BytesTransferred == -// SetFilePointer(handle1, 0, 0, FILE_CURRENT)); -// ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); -// } -// -// srand(seed); -// for (PUINT8 Bgn = MappedView + FileSize1 / 2, -// End = MappedView + FileSize0 / 2; -// End > Bgn; Bgn++) -// ASSERT(*Bgn == (rand() & 0xff)); -// if (!EarlyClose) -// ASSERT(0 == memcmp(Buffer[0], MappedView + FileSize0 / 2, -// bytes_per_sector)); -// for (size_t i = 0; bytes_per_sector > i; i++) -// rand(); -// for (PUINT8 Bgn = MappedView + FileSize0 / 2 + bytes_per_sector, -// End = MappedView + FileSize1 / 2 + FileSize0; -// End > Bgn; Bgn++) -// ASSERT(*Bgn == (rand() & 0xff)); -// -// Success = UnmapViewOfFile(MappedView); -// ASSERT(Success); -// -// Success = CloseHandle(Mapping); -// ASSERT(Success); -// -// if (!EarlyClose) { -// Success = CloseHandle(Handle); -// ASSERT(Success); -// } -// -// Success = DeleteFileW(FilePath); -// ASSERT(Success); -// } +static void test_mmap_file(auto &&mount_location, auto &&file_path, + auto &&flags, auto &&early_close) { + SYSTEM_INFO sys_info{}; + ::GetSystemInfo(&sys_info); + + DWORD bytes_per_sector{}; + DWORD free_clusters{}; + DWORD sectors_per_cluster{}; + DWORD total_clusters{}; + EXPECT_TRUE(::GetDiskFreeSpaceA(mount_location.c_str(), §ors_per_cluster, + &bytes_per_sector, &free_clusters, + &total_clusters)); + const auto buffer_size = 16U * sys_info.dwPageSize; + auto write_buffer = utils::generate_secure_random(buffer_size); + + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | flags, nullptr); + EXPECT_NE(INVALID_HANDLE_VALUE, handle); + + DWORD file_size0{ + 2U * sys_info.dwAllocationGranularity, + }; + DWORD file_size1{100U}; + auto *mapping = ::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0, + file_size0 + file_size1, nullptr); + ASSERT_NE(nullptr, mapping); + + if (early_close) { + EXPECT_TRUE(::CloseHandle(handle)); + } + + auto *view = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ASSERT_NE(nullptr, view); + + auto seed = static_cast(std::time(nullptr)); + srand(seed); + for (PUINT8 begin = reinterpret_cast(view) + file_size1 / 2U, + end = begin + file_size0; + end > begin; ++begin) { + *begin = rand() & 0xFF; + } + + EXPECT_TRUE(::UnmapViewOfFile(view)); + + view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ASSERT_NE(nullptr, view); + + srand(seed); + for (PUINT8 begin = reinterpret_cast(view) + file_size1 / 2U, + end = begin + file_size0; + end > begin; begin++) { + EXPECT_EQ(*begin, (rand() & 0xFF)); + } + + EXPECT_TRUE(::UnmapViewOfFile(view)); + + EXPECT_TRUE(::CloseHandle(mapping)); + + if (not early_close) { + 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, nullptr); + EXPECT_NE(INVALID_HANDLE_VALUE, handle); + + mapping = ::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0, + file_size0 + file_size1, nullptr); + ASSERT_NE(nullptr, mapping); + + if (early_close) { + EXPECT_TRUE(::CloseHandle(handle)); + } + + view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ASSERT_NE(nullptr, view); + + srand(seed); + for (PUINT8 begin = reinterpret_cast(view) + file_size1 / 2U, + end = begin + file_size0; + end > begin; ++begin) { + EXPECT_EQ(*begin, (rand() & 0xFF)); + } + + if (not early_close) { + auto pointer = ::SetFilePointer(handle, file_size0 / 2U, 0, FILE_BEGIN); + EXPECT_EQ(file_size0 / 2U, pointer); + + DWORD bytes_written{}; + EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), bytes_per_sector, + &bytes_written, nullptr)); + EXPECT_EQ(bytes_per_sector, bytes_written); + EXPECT_EQ(pointer + bytes_written, + ::SetFilePointer(handle, 0, 0, FILE_CURRENT)); + } + + EXPECT_TRUE(::UnmapViewOfFile(view)); + + EXPECT_TRUE(::CloseHandle(mapping)); + + if (not early_close) { + 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, nullptr); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + mapping = ::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0, + file_size0 + file_size1, nullptr); + ASSERT_NE(nullptr, mapping); + + if (early_close) { + EXPECT_TRUE(::CloseHandle(handle)); + } + + view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ASSERT_NE(nullptr, view); + + if (not early_close) { + auto pointer = ::SetFilePointer(handle, file_size0 / 2U, 0, FILE_BEGIN); + EXPECT_EQ(file_size0 / 2U, pointer); + + data_buffer read_buffer{}; + read_buffer.resize(buffer_size); + DWORD bytes_read{}; + EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), bytes_per_sector, + &bytes_read, nullptr)); + EXPECT_EQ(bytes_per_sector, bytes_read); + EXPECT_EQ(pointer + bytes_read, + ::SetFilePointer(handle, 0, 0, FILE_CURRENT)); + EXPECT_EQ(0, + std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read)); + } + + srand(seed); + for (PUINT8 begin = reinterpret_cast(view) + file_size1 / 2U, + end = reinterpret_cast(view) + file_size0 / 2U; + end > begin; begin++) { + EXPECT_EQ(*begin, (rand() & 0xFF)); + } + + if (not early_close) { + EXPECT_EQ(0, std::memcmp(write_buffer.data(), view + file_size0 / 2U, + bytes_per_sector)); + } + + for (size_t idx = 0U; bytes_per_sector > idx; ++idx) { + rand(); + } + + for (PUINT8 + begin = reinterpret_cast(view) + file_size0 / 2U + + bytes_per_sector, + end = reinterpret_cast(view) + file_size1 / 2U + file_size0; + end > begin; ++begin) { + EXPECT_EQ(*begin, (rand() & 0xFF)); + } + + EXPECT_TRUE(::UnmapViewOfFile(view)); + + EXPECT_TRUE(::CloseHandle(mapping)); + + if (not early_close) { + EXPECT_TRUE(::CloseHandle(handle)); + } + + EXPECT_TRUE(DeleteFileA(file_path.c_str())); +} TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_flags) { auto file_path{ @@ -805,26 +816,32 @@ TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_overlapped_write_through) { FILE_FLAG_WRITE_THROUGH); } -// TYPED_TEST(winfsp_test, rdrw_can_read_and_write_mmap_file_no_flags) { -// auto file_path{ -// utils::path::combine(this->mount_location, {"test_file_5"}), -// }; -// test_mmap_file(this->mount_location, file_path, 0U); -// } -// -// TYPED_TEST(winfsp_test, rdrw_can_read_and_write_mmap_file_no_buffering) { -// auto file_path{ -// utils::path::combine(this->mount_location, {"test_file_5"}), -// }; -// test_mmap_file(this->mount_location, file_path, FILE_FLAG_NO_BUFFERING); -// } -// -// TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_mmap_write_through) { -// auto file_path{ -// utils::path::combine(this->mount_location, {"test_file_5"}), -// }; -// test_mmap_file(this->mount_location, file_path, FILE_FLAG_WRITE_THROUGH); -// } +TYPED_TEST(winfsp_test, rdrw_can_read_and_write_mmap_file_no_flags) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_5"}), + }; + test_mmap_file(this->mount_location, file_path, 0U, false); + test_mmap_file(this->mount_location, file_path, 0U, true); +} + +TYPED_TEST(winfsp_test, rdrw_can_read_and_write_mmap_file_no_buffering) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_5"}), + }; + test_mmap_file(this->mount_location, file_path, FILE_FLAG_NO_BUFFERING, + false); + test_mmap_file(this->mount_location, file_path, FILE_FLAG_NO_BUFFERING, true); +} + +TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_mmap_write_through) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_5"}), + }; + test_mmap_file(this->mount_location, file_path, FILE_FLAG_WRITE_THROUGH, + false); + test_mmap_file(this->mount_location, file_path, FILE_FLAG_WRITE_THROUGH, + true); +} TYPED_TEST(winfsp_test, rdrw_can_read_and_write_mixed_file) { auto file_path{