winfsp unit tests and fixes

This commit is contained in:
Scott E. Graves 2024-11-09 09:16:17 -06:00
parent 1d53cd8e8b
commit c8cc0feae5

View File

@ -19,7 +19,6 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include <array>
#if defined(_WIN32) #if defined(_WIN32)
// //
@ -31,7 +30,20 @@
namespace repertory { namespace repertory {
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types); TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
static void test_file(auto &&file_path, auto &&flags) { static void test_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(), &sectors_per_cluster,
&bytes_per_sector, &free_clusters,
&total_clusters));
const auto buffer_size = 16U * sys_info.dwPageSize;
auto write_buffer = utils::generate_secure_random<data_buffer>(buffer_size);
auto handle = auto handle =
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
@ -39,127 +51,121 @@ static void test_file(auto &&file_path, auto &&flags) {
ASSERT_NE(INVALID_HANDLE_VALUE, handle); ASSERT_NE(INVALID_HANDLE_VALUE, handle);
auto pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN); auto pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0, pointer); EXPECT_EQ(0U, pointer);
auto write_buffer = utils::generate_secure_random<data_buffer>(16U);
DWORD bytes_written{}; DWORD bytes_written{};
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), write_buffer.size(), EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), bytes_per_sector,
&bytes_written, nullptr)); &bytes_written, nullptr));
EXPECT_EQ(bytes_per_sector, bytes_written);
EXPECT_EQ(static_cast<DWORD>(write_buffer.size()), bytes_written);
EXPECT_EQ(pointer + bytes_written, EXPECT_EQ(pointer + bytes_written,
::SetFilePointer(handle, 0, 0, FILE_CURRENT)); ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
pointer = ::SetFilePointer(handle, 2U * write_buffer.size(), 0, FILE_BEGIN); pointer = ::SetFilePointer(handle, 2U * bytes_per_sector, 0, FILE_BEGIN);
EXPECT_EQ(static_cast<DWORD>(2U * write_buffer.size()), pointer); EXPECT_EQ(2U * bytes_per_sector, pointer);
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), bytes_per_sector,
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), write_buffer.size(), &bytes_written, 0));
&bytes_written, nullptr)); EXPECT_EQ(bytes_per_sector, bytes_written);
EXPECT_EQ(static_cast<DWORD>(write_buffer.size()), bytes_written);
EXPECT_EQ(pointer + bytes_written, EXPECT_EQ(pointer + bytes_written,
::SetFilePointer(handle, 0, 0, FILE_CURRENT)); ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN); pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer); EXPECT_EQ(0U, pointer);
data_buffer read_buffer{};
read_buffer.resize(buffer_size);
DWORD bytes_read{}; DWORD bytes_read{};
std::array<std::uint8_t, 16U> read_buffer{}; EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), bytes_per_sector,
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(),
&bytes_read, nullptr)); &bytes_read, nullptr));
EXPECT_EQ(bytes_per_sector, bytes_read);
EXPECT_EQ(static_cast<DWORD>(16U), bytes_read);
EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT)); EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
EXPECT_EQ(0, EXPECT_EQ(0,
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read)); std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
for (auto idx = 0U; idx < 2U; ++idx) { for (auto idx = 0; idx < 2; ++idx) {
pointer = ::SetFilePointer(handle, 2U * write_buffer.size(), 0, FILE_BEGIN); read_buffer.clear();
EXPECT_EQ(2U * write_buffer.size(), pointer); read_buffer.resize(buffer_size);
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(), pointer = ::SetFilePointer(handle, 2U * bytes_per_sector, 0, FILE_BEGIN);
&bytes_read, nullptr)); EXPECT_EQ(2U * bytes_per_sector, pointer);
EXPECT_EQ(static_cast<DWORD>(16U), bytes_read); EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), bytes_per_sector,
&bytes_read, 0));
EXPECT_EQ(bytes_per_sector, bytes_read);
EXPECT_EQ(pointer + bytes_read, EXPECT_EQ(pointer + bytes_read,
::SetFilePointer(handle, 0, 0, FILE_CURRENT)); ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
EXPECT_EQ(0, EXPECT_EQ(0,
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read)); std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
} }
pointer = ::SetFilePointer(handle, 3U * write_buffer.size(), 0, FILE_BEGIN); read_buffer.clear();
EXPECT_EQ(3U * write_buffer.size(), pointer); read_buffer.resize(buffer_size);
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(), pointer = ::SetFilePointer(handle, 3U * bytes_per_sector, 0, FILE_BEGIN);
EXPECT_EQ(3U * bytes_per_sector, pointer);
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), bytes_per_sector,
&bytes_read, nullptr)); &bytes_read, nullptr));
EXPECT_EQ(static_cast<DWORD>(16U), bytes_read); EXPECT_EQ(0U, 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));
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), 2U * sys_info.dwPageSize,
&bytes_written, nullptr));
EXPECT_EQ(2U * sys_info.dwPageSize, bytes_written);
EXPECT_EQ(pointer + bytes_written,
::SetFilePointer(handle, 0, 0, FILE_CURRENT));
read_buffer.clear();
read_buffer.resize(buffer_size);
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), 2U * sys_info.dwPageSize,
&bytes_read, 0U));
EXPECT_EQ(2U * sys_info.dwPageSize, 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));
write_buffer = utils::generate_secure_random<data_buffer>(buffer_size);
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), 2U * sys_info.dwPageSize,
&bytes_written, nullptr));
EXPECT_EQ(2U * sys_info.dwPageSize, bytes_written);
EXPECT_EQ(pointer + bytes_written,
::SetFilePointer(handle, 0, 0, FILE_CURRENT));
read_buffer.clear();
read_buffer.resize(buffer_size);
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), 2U * sys_info.dwPageSize,
&bytes_read, nullptr));
EXPECT_EQ(2U * sys_info.dwPageSize, 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));
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(),
2U * sys_info.dwPageSize + bytes_per_sector,
&bytes_written, nullptr));
EXPECT_EQ(2U * sys_info.dwPageSize + bytes_per_sector, bytes_written);
EXPECT_EQ(pointer + bytes_written,
::SetFilePointer(handle, 0, 0, FILE_CURRENT));
read_buffer.clear();
read_buffer.resize(buffer_size);
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(),
2U * sys_info.dwPageSize + bytes_per_sector,
&bytes_read, nullptr));
EXPECT_EQ(2U * sys_info.dwPageSize + bytes_per_sector, bytes_read);
EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT)); EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
EXPECT_EQ(0, EXPECT_EQ(0,
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read)); std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
// 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)); EXPECT_TRUE(::CloseHandle(handle));
handle = ::CreateFileA( handle = ::CreateFileA(
@ -168,46 +174,131 @@ static void test_file(auto &&file_path, auto &&flags) {
FILE_ATTRIBUTE_NORMAL | flags | FILE_FLAG_DELETE_ON_CLOSE, nullptr); FILE_ATTRIBUTE_NORMAL | flags | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
ASSERT_NE(INVALID_HANDLE_VALUE, handle); ASSERT_NE(INVALID_HANDLE_VALUE, handle);
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); read_buffer.clear();
// ASSERT(0 == FilePointer); read_buffer.resize(buffer_size);
// memset(AllocBuffer[1], 0, AllocBufferSize); pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
// Success = EXPECT_EQ(0U, pointer);
// ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize + BytesPerSector, EXPECT_TRUE(::ReadFile(handle, read_buffer.data(),
// &BytesTransferred, 0); 2U * sys_info.dwPageSize + bytes_per_sector,
// ASSERT(Success); &bytes_read, nullptr));
// ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred); EXPECT_EQ(2U * sys_info.dwPageSize + bytes_per_sector, bytes_read);
// ASSERT(FilePointer + BytesTransferred == EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
// SetFilePointer(Handle, 0, 0, FILE_CURRENT)); EXPECT_EQ(0,
// ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
//
EXPECT_TRUE(::CloseHandle(handle)); EXPECT_TRUE(::CloseHandle(handle));
handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
OPEN_EXISTING, 0, nullptr); OPEN_EXISTING, 0, nullptr);
ASSERT_EQ(INVALID_HANDLE_VALUE, handle); EXPECT_EQ(INVALID_HANDLE_VALUE, handle);
ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
}
static void test_append_file(auto mount_location, auto &&file_path,
auto &&flags, bool should_fail = false) {
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(), &sectors_per_cluster,
&bytes_per_sector, &free_clusters,
&total_clusters));
const auto buffer_size = 16U * sys_info.dwPageSize;
auto write_buffer = utils::generate_secure_random<data_buffer>(buffer_size);
auto handle =
CreateFileA(file_path.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ, nullptr,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | flags, nullptr);
if (should_fail) {
EXPECT_EQ(INVALID_HANDLE_VALUE, handle);
return;
}
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
DWORD bytes_written{};
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), bytes_per_sector,
&bytes_written, nullptr));
EXPECT_EQ(bytes_per_sector, bytes_written);
EXPECT_TRUE(::WriteFile(handle, write_buffer.data() + bytes_per_sector,
bytes_per_sector, &bytes_written, nullptr));
EXPECT_EQ(bytes_per_sector, bytes_written);
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);
auto pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
EXPECT_EQ(0U, pointer);
data_buffer read_buffer{};
read_buffer.resize(buffer_size);
DWORD bytes_read{};
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), 2U * bytes_per_sector,
&bytes_read, nullptr));
EXPECT_EQ(2U * bytes_per_sector, bytes_read);
EXPECT_EQ(0,
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
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);
EXPECT_EQ(INVALID_HANDLE_VALUE, handle);
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
} }
TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_flags) { TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_flags) {
auto file_path{ auto file_path{
utils::path::combine(this->mount_location, {"test_file_5"}), utils::path::combine(this->mount_location, {"test_file_5"}),
}; };
test_file(file_path, 0U); test_file(this->mount_location, file_path, 0U);
} }
TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_buffering) { TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_buffering) {
auto file_path{ auto file_path{
utils::path::combine(this->mount_location, {"test_file_5"}), utils::path::combine(this->mount_location, {"test_file_5"}),
}; };
test_file(file_path, FILE_FLAG_NO_BUFFERING); test_file(this->mount_location, file_path, FILE_FLAG_NO_BUFFERING);
} }
TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_write_through) { TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_write_through) {
auto file_path{ auto file_path{
utils::path::combine(this->mount_location, {"test_file_5"}), utils::path::combine(this->mount_location, {"test_file_5"}),
}; };
test_file(file_path, FILE_FLAG_WRITE_THROUGH); test_file(this->mount_location, file_path, FILE_FLAG_WRITE_THROUGH);
}
TYPED_TEST(winfsp_test, rdrw_can_append_file_no_flags) {
auto file_path{
utils::path::combine(this->mount_location, {"test_file_5"}),
};
test_append_file(this->mount_location, file_path, 0U);
}
TYPED_TEST(winfsp_test, rdrw_can_append_file_no_buffering) {
auto file_path{
utils::path::combine(this->mount_location, {"test_file_5"}),
};
test_append_file(this->mount_location, file_path, FILE_FLAG_NO_BUFFERING,
true);
}
TYPED_TEST(winfsp_test, rdrw_can_append_file_write_through) {
auto file_path{
utils::path::combine(this->mount_location, {"test_file_5"}),
};
test_append_file(this->mount_location, file_path, FILE_FLAG_WRITE_THROUGH);
} }
} // namespace repertory } // namespace repertory