From 884d2d6890212791f3e121d868d893a22ff923bd Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Tue, 29 Oct 2024 14:15:04 -0500 Subject: [PATCH] winfsp unit tests --- .../drives/fuse/remotefuse/remote_server.cpp | 170 ++++++----- .../src/drives/winfsp/winfsp_drive.cpp | 11 +- .../include/fixtures/winfsp_fixture.hpp | 8 +- .../repertory_test/src/winfsp_drive_test.cpp | 276 ++++-------------- 4 files changed, 165 insertions(+), 300 deletions(-) diff --git a/repertory/librepertory/src/drives/fuse/remotefuse/remote_server.cpp b/repertory/librepertory/src/drives/fuse/remotefuse/remote_server.cpp index 66115976..5a750472 100644 --- a/repertory/librepertory/src/drives/fuse/remotefuse/remote_server.cpp +++ b/repertory/librepertory/src/drives/fuse/remotefuse/remote_server.cpp @@ -208,8 +208,8 @@ auto remote_server::fuse_access(const char *path, const std::int32_t &mask) return ret; } -auto remote_server::fuse_chflags(const char *path, - std::uint32_t flags) -> packet::error_type { +auto remote_server::fuse_chflags(const char *path, std::uint32_t flags) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -316,9 +316,10 @@ length); ret = ((res < 0) ? -errno : 0); #endif return ret; }*/ -auto remote_server::fuse_fgetattr( - const char *path, remote::stat &r_stat, bool &directory, - const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_fgetattr(const char *path, remote::stat &r_stat, + bool &directory, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); r_stat = {}; @@ -328,7 +329,7 @@ auto remote_server::fuse_fgetattr( auto res = has_open_info(static_cast(handle), EBADF); if (res == 0) { directory = utils::file::directory(file_path).exists(); - struct stat64 unix_st {}; + struct stat64 unix_st{}; res = fstat64(static_cast(handle), &unix_st); if (res == 0) { populate_stat(unix_st, r_stat); @@ -340,9 +341,10 @@ auto remote_server::fuse_fgetattr( return ret; } -auto remote_server::fuse_fsetattr_x( - const char *path, const remote::setattr_x &attr, - const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_fsetattr_x(const char *path, + const remote::setattr_x &attr, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -458,9 +460,10 @@ auto remote_server::fuse_fsync(const char *path, const std::int32_t &datasync, return ret; } -auto remote_server::fuse_ftruncate( - const char *path, const remote::file_offset &size, - const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_ftruncate(const char *path, + const remote::file_offset &size, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); @@ -488,7 +491,7 @@ auto remote_server::fuse_getattr(const char *path, remote::stat &r_stat, directory = utils::file::directory(file_path).exists(); - struct stat64 unix_st {}; + struct stat64 unix_st{}; auto res = stat64(file_path.c_str(), &unix_st); if (res == 0) { populate_stat(unix_st, r_stat); @@ -553,9 +556,10 @@ STATUS_NOT_IMPLEMENTED; #endif RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret); return ret; }*/ -auto remote_server::fuse_getxtimes( - const char *path, remote::file_time &bkuptime, - remote::file_time &crtime) -> packet::error_type { +auto remote_server::fuse_getxtimes(const char *path, + remote::file_time &bkuptime, + remote::file_time &crtime) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -655,10 +659,11 @@ auto remote_server::fuse_opendir(const char *path, remote::file_handle &handle) return ret; } -auto remote_server::fuse_read( - const char *path, char *buffer, const remote::file_size &read_size, - const remote::file_offset &read_offset, - const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_read(const char *path, char *buffer, + const remote::file_size &read_size, + const remote::file_offset &read_offset, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); @@ -679,8 +684,8 @@ auto remote_server::fuse_read( return static_cast(ret); } -auto remote_server::fuse_rename(const char *from, - const char *to) -> packet::error_type { +auto remote_server::fuse_rename(const char *from, const char *to) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto from_path = utils::path::combine(mount_location_, {from}); @@ -718,8 +723,9 @@ auto remote_server::fuse_readdir(const char *path, return ret; } -auto remote_server::fuse_release( - const char *path, const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_release(const char *path, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); packet::error_type ret = 0; @@ -736,8 +742,9 @@ auto remote_server::fuse_release( return ret; } -auto remote_server::fuse_releasedir( - const char *path, const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_releasedir(const char *path, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); @@ -788,8 +795,9 @@ auto remote_server::fuse_setattr_x(const char *path, remote::setattr_x &attr) return ret; } -auto remote_server::fuse_setbkuptime( - const char *path, const remote::file_time &bkuptime) -> packet::error_type { +auto remote_server::fuse_setbkuptime(const char *path, + const remote::file_time &bkuptime) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -808,8 +816,9 @@ auto remote_server::fuse_setbkuptime( return ret; } -auto remote_server::fuse_setchgtime( - const char *path, const remote::file_time &chgtime) -> packet::error_type { +auto remote_server::fuse_setchgtime(const char *path, + const remote::file_time &chgtime) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -828,8 +837,9 @@ auto remote_server::fuse_setchgtime( return ret; } -auto remote_server::fuse_setcrtime( - const char *path, const remote::file_time &crtime) -> packet::error_type { +auto remote_server::fuse_setcrtime(const char *path, + const remote::file_time &crtime) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -920,8 +930,9 @@ auto remote_server::fuse_statfs_x(const char *path, std::uint64_t bsize, return 0; } -auto remote_server::fuse_truncate( - const char *path, const remote::file_offset &size) -> packet::error_type { +auto remote_server::fuse_truncate(const char *path, + const remote::file_offset &size) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); @@ -942,8 +953,8 @@ auto remote_server::fuse_unlink(const char *path) -> packet::error_type { } auto remote_server::fuse_utimens(const char *path, const remote::file_time *tv, - std::uint64_t op0, - std::uint64_t op1) -> packet::error_type { + std::uint64_t op0, std::uint64_t op1) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); @@ -970,10 +981,11 @@ auto remote_server::fuse_utimens(const char *path, const remote::file_time *tv, return ret; } -auto remote_server::fuse_write( - const char *path, const char *buffer, const remote::file_size &write_size, - const remote::file_offset &write_offset, - const remote::file_handle &handle) -> packet::error_type { +auto remote_server::fuse_write(const char *path, const char *buffer, + const remote::file_size &write_size, + const remote::file_offset &write_offset, + const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); @@ -1003,8 +1015,8 @@ auto remote_server::fuse_write_base64( } // WinFSP Layer -auto remote_server::winfsp_can_delete(PVOID file_desc, - PWSTR file_name) -> packet::error_type { +auto remote_server::winfsp_can_delete(PVOID file_desc, PWSTR file_name) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto relative_path = utils::string::to_utf8(file_name); @@ -1020,8 +1032,7 @@ auto remote_server::winfsp_can_delete(PVOID file_desc, utils::path::create_api_path(relative_path)) ? STATUS_DIRECTORY_NOT_EMPTY : STATUS_SUCCESS - : drive_.is_processing(utils::path::create_api_path(relative_path)) - ? STATUS_DEVICE_BUSY + : STATUS_SUCCESS); } @@ -1030,8 +1041,8 @@ auto remote_server::winfsp_can_delete(PVOID file_desc, } auto remote_server::winfsp_cleanup(PVOID /*file_desc*/, PWSTR file_name, - UINT32 flags, - BOOLEAN &was_closed) -> packet::error_type { + UINT32 flags, BOOLEAN &was_closed) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto relative_path = utils::string::to_utf8(file_name); @@ -1108,8 +1119,8 @@ auto remote_server::winfsp_create(PWSTR file_name, UINT32 create_options, UINT32 granted_access, UINT32 attributes, UINT64 /*allocation_size*/, PVOID *file_desc, remote::file_info *file_info, - std::string &normalized_name, - BOOLEAN &exists) -> packet::error_type { + std::string &normalized_name, BOOLEAN &exists) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto relative_path = utils::string::to_utf8(file_name); @@ -1176,8 +1187,9 @@ auto remote_server::winfsp_flush(PVOID file_desc, remote::file_info *file_info) return ret; } -auto remote_server::winfsp_get_file_info( - PVOID file_desc, remote::file_info *file_info) -> packet::error_type { +auto remote_server::winfsp_get_file_info(PVOID file_desc, + remote::file_info *file_info) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto handle = reinterpret_cast(file_desc); @@ -1220,9 +1232,10 @@ auto remote_server::winfsp_get_security_by_name( return ret; } -auto remote_server::winfsp_get_volume_info( - UINT64 &total_size, UINT64 &free_size, - std::string &volume_label) -> packet::error_type { +auto remote_server::winfsp_get_volume_info(UINT64 &total_size, + UINT64 &free_size, + std::string &volume_label) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); drive_.get_volume_info(total_size, free_size, volume_label); @@ -1239,10 +1252,11 @@ auto remote_server::winfsp_mounted(const std::wstring &location) return STATUS_SUCCESS; } -auto remote_server::winfsp_open( - PWSTR file_name, UINT32 create_options, UINT32 granted_access, - PVOID *file_desc, remote::file_info *file_info, - std::string &normalized_name) -> packet::error_type { +auto remote_server::winfsp_open(PWSTR file_name, UINT32 create_options, + UINT32 granted_access, PVOID *file_desc, + remote::file_info *file_info, + std::string &normalized_name) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto relative_path = utils::string::to_utf8(file_name); @@ -1278,10 +1292,11 @@ auto remote_server::winfsp_open( return ret; } -auto remote_server::winfsp_overwrite( - PVOID file_desc, UINT32 attributes, BOOLEAN replace_attributes, - UINT64 /*allocation_size*/, - remote::file_info *file_info) -> packet::error_type { +auto remote_server::winfsp_overwrite(PVOID file_desc, UINT32 attributes, + BOOLEAN replace_attributes, + UINT64 /*allocation_size*/, + remote::file_info *file_info) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto handle = reinterpret_cast(file_desc); @@ -1397,9 +1412,10 @@ auto remote_server::winfsp_read_directory(PVOID file_desc, PWSTR /*pattern*/, return ret; } -auto remote_server::winfsp_rename( - PVOID /*file_desc*/, PWSTR file_name, PWSTR new_file_name, - BOOLEAN replace_if_exists) -> packet::error_type { +auto remote_server::winfsp_rename(PVOID /*file_desc*/, PWSTR file_name, + PWSTR new_file_name, + BOOLEAN replace_if_exists) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto relative_path = utils::string::to_utf8(file_name); @@ -1493,9 +1509,10 @@ auto remote_server::winfsp_set_basic_info( return ret; } -auto remote_server::winfsp_set_file_size( - PVOID file_desc, UINT64 new_size, BOOLEAN set_allocation_size, - remote::file_info *file_info) -> packet::error_type { +auto remote_server::winfsp_set_file_size(PVOID file_desc, UINT64 new_size, + BOOLEAN set_allocation_size, + remote::file_info *file_info) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto handle = reinterpret_cast(file_desc); @@ -1531,10 +1548,12 @@ auto remote_server::winfsp_unmounted(const std::wstring &location) return STATUS_SUCCESS; } -auto remote_server::winfsp_write( - PVOID file_desc, PVOID buffer, UINT64 offset, UINT32 length, - BOOLEAN write_to_end, BOOLEAN constrained_io, PUINT32 bytes_transferred, - remote::file_info *file_info) -> packet::error_type { +auto remote_server::winfsp_write(PVOID file_desc, PVOID buffer, UINT64 offset, + UINT32 length, BOOLEAN write_to_end, + BOOLEAN constrained_io, + PUINT32 bytes_transferred, + remote::file_info *file_info) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); *bytes_transferred = 0; @@ -1582,8 +1601,9 @@ auto remote_server::winfsp_write( return ret; } -auto remote_server::json_create_directory_snapshot( - const std::string &path, json &json_data) -> packet::error_type { +auto remote_server::json_create_directory_snapshot(const std::string &path, + json &json_data) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto api_path = utils::path::create_api_path(path); @@ -1642,8 +1662,8 @@ auto remote_server::json_read_directory_snapshot( } auto remote_server::json_release_directory_snapshot( - const std::string &path, - const remote::file_handle &handle) -> packet::error_type { + const std::string &path, const remote::file_handle &handle) + -> packet::error_type { REPERTORY_USES_FUNCTION_NAME(); const auto file_path = construct_path(path); diff --git a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp index d10f7b8b..bdcff678 100644 --- a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp +++ b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp @@ -72,11 +72,11 @@ auto winfsp_drive::handle_error(std::string_view function_name, FileInfo *file_info, std::uint64_t file_size, bool raise_on_failure_only) const -> NTSTATUS { auto ret = utils::from_api_error(error); - if (not raise_on_failure_only || error != api_error::success) { + if (not raise_on_failure_only) { RAISE_WINFSP_EVENT(function_name, api_path, ret); } - if (file_info == nullptr || error != api_error::success) { + if (file_info == nullptr) { return ret; } @@ -172,8 +172,7 @@ auto winfsp_drive::CanDelete(PVOID /*file_node*/, PVOID file_desc, : api_error::directory_not_empty); } - return handle_error(fm_->is_processing(api_path) ? api_error::file_in_use - : api_error::success); + return handle_error(api_error::success); } VOID winfsp_drive::Cleanup(PVOID file_node, PVOID file_desc, @@ -569,7 +568,7 @@ auto winfsp_drive::Init(PVOID host) -> NTSTATUS { file_system_host->SetCasePreservedNames(TRUE); file_system_host->SetNamedStreams(FALSE); file_system_host->SetUnicodeOnDisk(TRUE); - file_system_host->SetMaxComponentLength(4096U); + // file_system_host->SetMaxComponentLength(4096U); file_system_host->SetPersistentAcls(FALSE); file_system_host->SetPostCleanupWhenModifiedOnly(TRUE); file_system_host->SetPassQueryDirectoryPattern(FALSE); @@ -684,8 +683,8 @@ auto winfsp_drive::Open(PWSTR file_name, UINT32 create_options, bool directory{}; auto error = provider_.is_directory(api_path, directory); if (error == api_error::success) { - error = api_error::directory_not_found; if (((create_options & FILE_DIRECTORY_FILE) != 0U) && not directory) { + error = api_error::directory_not_found; } else { error = api_error::success; if (not directory && diff --git a/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp b/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp index cd21ea54..b5719f17 100644 --- a/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp @@ -159,8 +159,9 @@ public: auto file_path = utils::path::combine(mount_location, {file_name}); auto handle = - ::CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); EXPECT_NE(INVALID_HANDLE_VALUE, handle); EXPECT_TRUE(::CloseHandle(handle)); @@ -242,7 +243,8 @@ std::string winfsp_test::test_directory; template std::unique_ptr winfsp_test::drive; -using winfsp_provider_types = ::testing::Types; +using winfsp_provider_types = ::testing::Types; +// using winfsp_provider_types = ::testing::Types; } // 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 37da6465..c1c8aec6 100644 --- a/repertory/repertory_test/src/winfsp_drive_test.cpp +++ b/repertory/repertory_test/src/winfsp_drive_test.cpp @@ -21,231 +21,75 @@ */ #if defined(_WIN32) +// +// Implemented test cased 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); -// TYPED_TEST(winfsp_test, root_is_created) { -// WIN32_FILE_ATTRIBUTE_DATA ad{}; -// ASSERT_TRUE(::GetFileAttributesEx(this->mount_location.c_str(), -// GetFileExInfoStandard, &ad)); -// EXPECT_EQ(FILE_ATTRIBUTE_DIRECTORY, ad.dwFileAttributes); -// EXPECT_EQ(0, ad.nFileSizeHigh); -// EXPECT_EQ(0, ad.nFileSizeLow); -// } -// -// TYPED_TEST(winfsp_test, can_create_and_delete_directory) { -// std::string dir_name{"test_create_and_delete_dir"}; -// auto dir_path = this->create_directory_and_test(dir_name); -// this->delete_directory_and_test(dir_path); -// } -// -// TYPED_TEST(winfsp_test, can_create_and_delete_file) { -// std::string file_name{"test_create_and_delete_file"}; -// auto file_path = this->create_file_and_test(file_name); -// this->delete_file_and_test(file_path); -// } -// -// TYPED_TEST(winfsp_test, can_write_to_and_read_from_file) { -// std::string file_name{"test_write_file"}; -// auto file_path = this->create_file_and_test(file_name); -// -// auto handle = -// ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, -// FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, -// nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); -// EXPECT_NE(INVALID_HANDLE_VALUE, handle); -// if (handle == INVALID_HANDLE_VALUE) { -// return; -// } -// -// std::string write_buffer{"0123456789"}; -// { -// DWORD bytes_written{0}; -// EXPECT_TRUE(::WriteFile(handle, write_buffer.c_str(), -// static_cast(write_buffer.size()), -// &bytes_written, nullptr)); -// EXPECT_EQ(static_cast(write_buffer.size()), bytes_written); -// -// auto opt_size = utils::file::file(file_path).size(); -// EXPECT_TRUE(opt_size.has_value()); -// EXPECT_EQ(write_buffer.size(), opt_size.value()); -// } -// -// { -// data_buffer read_buffer; -// read_buffer.resize(write_buffer.size()); -// -// DWORD bytes_read{0}; -// EXPECT_EQ(0, ::SetFilePointer(handle, 0, nullptr, FILE_BEGIN)); -// EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), -// static_cast(read_buffer.size()), -// &bytes_read, nullptr)); -// EXPECT_EQ(static_cast(write_buffer.size()), bytes_read); -// EXPECT_EQ(0, -// std::memcmp(write_buffer.data(), read_buffer.data(), -// std::min(read_buffer.size(), -// write_buffer.size()))); -// } -// -// EXPECT_TRUE(::CloseHandle(handle)); -// -// this->delete_file_and_test(file_path); -// } -// -// TYPED_TEST(winfsp_test, can_rename_file) { -// std::string file_name{"rename_file"}; -// auto file_path = this->create_file_and_test(file_name); -// auto api_path = utils::path::create_api_path(file_name); -// -// api_meta_map meta1{}; -// EXPECT_EQ(api_error::success, this->provider->get_item_meta(api_path, -// meta1)); -// -// auto file_path2 = -// utils::path::combine(this->mount_location, {file_name + "_2"}); -// auto api_path2 = api_path + "_2"; -// EXPECT_TRUE(::MoveFile(file_path.c_str(), file_path2.c_str())); -// -// EXPECT_TRUE(utils::file::file(file_path2).exists()); -// EXPECT_FALSE(utils::file::file(file_path).exists()); -// -// api_meta_map meta2{}; -// EXPECT_EQ(api_error::success, -// this->provider->get_item_meta(api_path2, meta2)); -// EXPECT_STREQ(meta1[META_SOURCE].c_str(), meta2[META_SOURCE].c_str()); -// -// filesystem_item fsi{}; -// EXPECT_EQ(api_error::success, -// this->provider->get_filesystem_item(api_path2, false, fsi)); -// EXPECT_STREQ(meta1[META_SOURCE].c_str(), fsi.source_path.c_str()); -// -// filesystem_item fsi2{}; -// EXPECT_EQ(api_error::success, -// this->provider->get_filesystem_item_from_source_path( -// fsi.source_path, fsi2)); -// EXPECT_STREQ(api_path2.c_str(), fsi2.api_path.c_str()); -// -// EXPECT_EQ(api_error::item_not_found, -// this->provider->get_item_meta(api_path, meta2)); -// -// this->delete_file_and_test(file_path2); -// } -// -// TYPED_TEST(winfsp_test, can_rename_directory) { -// std::string dir_name{"rename_dir"}; -// auto dir_path = this->create_directory_and_test(dir_name); -// -// auto dir_path2{dir_path + "_2"}; -// -// EXPECT_TRUE(::MoveFileA(dir_path.c_str(), dir_path2.c_str())); -// EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str())); -// EXPECT_TRUE(::PathIsDirectoryA(dir_path2.c_str())); -// -// this->delete_directory_and_test(dir_path2); -// } -// -// TYPED_TEST(winfsp_test, can_overwrite_file) { -// std::string file_name{"overwrite_file"}; -// auto file_path = this->create_file_and_test(file_name); -// -// auto file_path2{file_path + "_2"}; -// EXPECT_TRUE(::CopyFile(file_path.c_str(), file_path2.c_str(), TRUE)); -// EXPECT_TRUE(::CopyFile(file_path.c_str(), file_path2.c_str(), FALSE)); -// EXPECT_FALSE(::CopyFile(file_path.c_str(), file_path2.c_str(), TRUE)); -// -// this->delete_file_and_test(file_path); -// this->delete_file_and_test(file_path2); -// } -// -// TYPED_TEST(winfsp_test, can_get_and_set_basic_info_test) { -// std::string file_name{"overwrite_file"}; -// auto file_path = this->create_file_and_test(file_name); -// -// auto handle = -// ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, -// FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, -// nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); -// EXPECT_NE(INVALID_HANDLE_VALUE, handle); -// if (handle == INVALID_HANDLE_VALUE) { -// return; -// } -// -// SYSTEMTIME st{}; -// ::GetSystemTime(&st); -// st.wMinute = 0; -// -// FILETIME test_ch_time{}; -// st.wMinute++; -// ::SystemTimeToFileTime(&st, &test_ch_time); -// -// FILETIME test_cr_time{}; -// st.wMinute++; -// ::SystemTimeToFileTime(&st, &test_cr_time); -// -// FILETIME test_la_time{}; -// st.wMinute++; -// ::SystemTimeToFileTime(&st, &test_la_time); -// -// FILETIME test_lw_time{}; -// st.wMinute++; -// ::SystemTimeToFileTime(&st, &test_lw_time); -// -// FILE_BASIC_INFO fbi{}; -// fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN; -// fbi.ChangeTime.HighPart = static_cast(test_ch_time.dwHighDateTime); -// fbi.ChangeTime.LowPart = test_ch_time.dwLowDateTime; -// fbi.CreationTime = *reinterpret_cast(&test_cr_time); -// fbi.LastAccessTime = *reinterpret_cast(&test_la_time); -// fbi.LastWriteTime = *reinterpret_cast(&test_lw_time); -// -// EXPECT_TRUE(::SetFileInformationByHandle(handle, FileBasicInfo, &fbi, -// sizeof(FILE_BASIC_INFO))); -// -// FILE_BASIC_INFO fbi2{}; -// EXPECT_TRUE(::GetFileInformationByHandleEx(handle, FileBasicInfo, &fbi2, -// sizeof(FILE_BASIC_INFO))); -// -// EXPECT_EQ(0, memcmp(&fbi, &fbi2, sizeof(FILE_BASIC_INFO))); -// -// std::cout << fbi.FileAttributes << " " << fbi.ChangeTime.QuadPart << " " -// << fbi.CreationTime.QuadPart << " " << -// fbi.LastAccessTime.QuadPart -// << " " << fbi.LastWriteTime.QuadPart << std::endl; -// std::cout << fbi2.FileAttributes << " " << fbi2.ChangeTime.QuadPart << " " -// << fbi2.CreationTime.QuadPart << " " << -// fbi2.LastAccessTime.QuadPart -// << " " << fbi2.LastWriteTime.QuadPart << std::endl; -// -// EXPECT_TRUE(::CloseHandle(handle)); -// -// this->delete_file_and_test(file_path); -// } - -TYPED_TEST(winfsp_test, run_winfsp_tests) { - if (this->provider->is_read_only()) { - return; - } - - auto cur = std::filesystem::current_path(); - std::filesystem::current_path(this->mount_location); - - std::vector test_options{ - "--external", - "--resilient", +TYPED_TEST(winfsp_test, can_create_normal_file) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_0"}), }; + auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, 0); + EXPECT_NE(INVALID_HANDLE_VALUE, handle); + ::CloseHandle(handle); +} - auto test_exec = utils::path::combine(test::get_test_input_dir(), - { - "bin", - "winfsp-tests-x64.exe", - }) + - ' ' + utils::string::join(test_options, ' '); +TYPED_TEST(winfsp_test, create_new_fails_when_file_exists) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_0"}), + }; + auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, 0); + EXPECT_EQ(INVALID_HANDLE_VALUE, handle); + EXPECT_EQ(ERROR_FILE_EXISTS, ::GetLastError()); +} - EXPECT_EQ(0, system(test_exec.c_str())); +TYPED_TEST(winfsp_test, can_open_existing_file) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_0"}), + }; + auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + EXPECT_NE(INVALID_HANDLE_VALUE, handle); + ::CloseHandle(handle); +} - std::filesystem::current_path(cur); +TYPED_TEST(winfsp_test, create_always_succeeds_when_file_exists) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_0"}), + }; + auto handle = ::CreateFileA(file_path.cstr(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0); + EXPECT_NE(INVALID_HANDLE_VALUE, handle); + // EXPECT file_size is 0 + ::CloseHandle(handle); +} + +TYPED_TEST(winfsp_test, can_delete_file_after_close) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_0"}), + }; + auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0); + EXPECT_NE(INVALID_HANDLE_VALUE, handle); + ::CloseHandle(handle); + + handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, + FILE_FLAG_DELETE_ON_CLOSE, 0); + EXPECT_EQ(INVALID_HANDLE_VALUE, handle); + EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); } } // namespace repertory