diff --git a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp index 5a4ef6bb..64fa0cd9 100644 --- a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp +++ b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp @@ -986,16 +986,14 @@ auto remote_server::winfsp_create(PWSTR file_name, UINT32 create_options, {utils::string::to_utf8(file_name)})) .exists()); - auto create_flags = FILE_FLAG_BACKUP_SEMANTICS; + auto create_flags{FILE_FLAG_BACKUP_SEMANTICS}; if ((create_options & FILE_DIRECTORY_FILE) != 0U) { create_flags |= FILE_FLAG_POSIX_SEMANTICS; - attributes |= FILE_ATTRIBUTE_DIRECTORY; - } else { - attributes &= static_cast( - ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NORMAL)); - attributes |= FILE_ATTRIBUTE_ARCHIVE; } + attributes |= + ((create_options & FILE_DIRECTORY_FILE) == 0U ? FILE_ATTRIBUTE_ARCHIVE + : FILE_ATTRIBUTE_DIRECTORY); auto *handle = ::CreateFileW( file_path.c_str(), granted_access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, @@ -1161,34 +1159,23 @@ auto remote_server::winfsp_overwrite(PVOID file_desc, UINT32 attributes, auto *handle = reinterpret_cast(file_desc); auto ret = has_open_info(handle, STATUS_INVALID_HANDLE); if (ret == STATUS_SUCCESS) { - if (replace_attributes != 0U) { - if (attributes == 0U) { - attributes = FILE_ATTRIBUTE_ARCHIVE; - } + attributes |= FILE_ATTRIBUTE_ARCHIVE; + if (replace_attributes != 0U) { FILE_BASIC_INFO basic_info{}; basic_info.FileAttributes = attributes; if (::SetFileInformationByHandle(handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO)) == 0) { ret = FspNtStatusFromWin32(::GetLastError()); } - } else if (attributes != 0U) { + } else { FILE_ATTRIBUTE_TAG_INFO tag_info{}; - if (::GetFileInformationByHandleEx( - handle, FileAttributeTagInfo, &tag_info, - sizeof(FILE_ATTRIBUTE_TAG_INFO)) == 0) { - ret = FspNtStatusFromWin32(::GetLastError()); + if (::GetFileInformationByHandleEx(handle, FileAttributeTagInfo, + &tag_info, + sizeof(FILE_ATTRIBUTE_TAG_INFO))) { + attributes |= tag_info.FileAttributes; } else { - FILE_BASIC_INFO basic_info{}; - basic_info.FileAttributes = - attributes | (tag_info.FileAttributes & - static_cast(~FILE_ATTRIBUTE_NORMAL)); - if ((basic_info.FileAttributes != tag_info.FileAttributes)) { - if (::SetFileInformationByHandle(handle, FileBasicInfo, &basic_info, - sizeof(FILE_BASIC_INFO)) == 0) { - ret = FspNtStatusFromWin32(::GetLastError()); - } - } + ret = FspNtStatusFromWin32(::GetLastError()); } } diff --git a/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp b/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp index 3be4c49c..9eace8be 100644 --- a/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp @@ -26,7 +26,7 @@ #include "test_common.hpp" #include "app_config.hpp" -#include "comm/curl/curl_comm.hpp" +#include "drives/winfsp/remotewinfsp/remote_winfsp_drive.hpp" #include "drives/winfsp/winfsp_drive.hpp" #include "platform/platform.hpp" #include "providers/i_provider.hpp" @@ -42,215 +42,242 @@ constexpr const auto SLEEP_SECONDS{1.5s}; } // namespace namespace repertory { +struct local_s3 final { + static constexpr const provider_type type{provider_type::s3}; + static constexpr const provider_type type2{provider_type::s3}; +}; + +struct local_sia final { + static constexpr const provider_type type{provider_type::sia}; + static constexpr const provider_type type2{provider_type::sia}; +}; + +struct remote_s3 final { + static constexpr const provider_type type{provider_type::remote}; + static constexpr const provider_type type2{provider_type::s3}; +}; + +struct remote_sia final { + static constexpr const provider_type type{provider_type::remote}; + static constexpr const provider_type type2{provider_type::sia}; +}; + template class winfsp_test : public ::testing::Test { public: - static std::string cfg_directory; - static std::unique_ptr comm; - static std::unique_ptr config; static std::filesystem::path current_directory; - static std::unique_ptr drive; - static std::vector drive_args; - static std::string mount_location; - static std::unique_ptr provider; - static std::string test_directory; static provider_type current_provider; + static std::vector drive_args; + static std::vector drive_args2; + static std::string mount_location; + static std::string mount_location2; protected: static void SetUpTestCase() { current_directory = std::filesystem::current_path(); - test_directory = utils::path::combine( - test::get_test_output_dir(), - { - "winfsp_test", - app_config::get_provider_name(current_provider), - }); - - mount_location = "U:"; - - cfg_directory = utils::path::combine(test_directory, {"cfg"}); - ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory()); - - config = std::make_unique(current_provider, cfg_directory); - - switch (current_provider) { - case provider_type::s3: { + const auto mount_s3 = [&]() { { - app_config src_cfg{ - provider_type::s3, - utils::path::combine(test::get_test_config_dir(), {"s3"}), - }; - config->set_enable_drive_events(true); - config->set_event_level(event_level::trace); - config->set_s3_config(src_cfg.get_s3_config()); + auto test_directory = utils::path::combine( + test::get_test_output_dir(), + { + "winfsp_test", + app_config::get_provider_name(provider_type::s3), + }); + + mount_location = "U:"; + + auto cfg_directory = utils::path::combine(test_directory, {"cfg"}); + ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory()); + + auto config = + std::make_unique(provider_type::s3, cfg_directory); + { + app_config src_cfg{ + provider_type::s3, + utils::path::combine(test::get_test_config_dir(), {"s3"}), + }; + config->set_enable_drive_events(true); + config->set_event_level(event_level::trace); + config->set_s3_config(src_cfg.get_s3_config()); + config->set_enable_remote_mount(true); + config->set_remote_port(30000U); + } + + drive_args = std::vector({ + "-dd", + config->get_data_directory(), + "-s3", + "-na", + "s3", + mount_location, + }); + } + execute_mount(drive_args, mount_location); + }; + + const auto mount_sia = [&]() { + { + auto test_directory = utils::path::combine( + test::get_test_output_dir(), + { + "winfsp_test", + app_config::get_provider_name(provider_type::sia), + }); + + mount_location = "U:"; + + auto cfg_directory = utils::path::combine(test_directory, {"cfg"}); + ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory()); + + auto config = + std::make_unique(provider_type::s3, cfg_directory); + { + app_config src_cfg{ + provider_type::sia, + utils::path::combine(test::get_test_config_dir(), {"sia"}), + }; + config->set_enable_drive_events(true); + config->set_event_level(event_level::trace); + config->set_host_config(src_cfg.get_host_config()); + config->set_sia_config(src_cfg.get_sia_config()); + config->set_enable_remote_mount(true); + config->set_remote_port(30000U); + } + + drive_args = std::vector({ + "-dd", + config->get_data_directory(), + "-na", + "sia", + mount_location, + }); } - drive_args = std::vector({ - "-s3", - "-na", - "s3", - }); + execute_mount(drive_args, mount_location); + }; + + const auto mount_remote = [&]() { + { + auto test_directory = utils::path::combine( + test::get_test_output_dir(), + { + "winfsp_test", + app_config::get_provider_name(provider_type::remote), + }); + + mount_location2 = mount_location; + mount_location = "V:"; + + auto cfg_directory = utils::path::combine(test_directory, {"cfg2"}); + ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory()); + + auto config = + std::make_unique(provider_type::remote, cfg_directory); + config->set_enable_drive_events(true); + config->set_event_level(event_level::trace); + + drive_args2 = std::vector({ + "-dd", + config->get_data_directory(), + "-rm", + "localhost:30000", + mount_location, + }); + } + + execute_mount(drive_args2, mount_location); + }; + + switch (provider_t::type) { + case provider_type::s3: { + mount_s3(); } break; case provider_type::sia: { - { - app_config src_cfg{ - provider_type::sia, - utils::path::combine(test::get_test_config_dir(), {"sia"}), - }; - config->set_enable_drive_events(true); - config->set_event_level(event_level::trace); - config->set_host_config(src_cfg.get_host_config()); - config->set_sia_config(src_cfg.get_sia_config()); + mount_sia(); + } break; + + case provider_type::remote: { + switch (provider_t::type2) { + case provider_type::s3: { + mount_s3(); + } break; + + case provider_type::sia: { + mount_sia(); + } break; + + default: + throw std::runtime_error("remote provider type is not implemented"); + return; } - drive_args = std::vector({ - "-na", - "sia", - }); + mount_remote(); } break; - // case 0U: { - // config = - // std::make_unique(provider_type::encrypt, - // cfg_directory); - // { - // app_config src_cfg( - // provider_type::s3, - // utils::path::combine(test::get_test_input_dir(), {"encrypt"})); - // config->set_enable_drive_events(true); - // config->set_event_level(event_level::trace); - // config->set_s3_config(src_cfg.get_s3_config()); - // } - // } break; default: throw std::runtime_error("provider type is not implemented"); return; } - - drive_args.push_back(mount_location); - execute_mount(); } static void TearDownTestCase() { - execute_unmount(); + if (provider_t::type == provider_type::remote) { + execute_unmount(drive_args2, mount_location); + execute_unmount(drive_args, mount_location2); + } else { + execute_unmount(drive_args, mount_location); + } std::filesystem::current_path(current_directory); } -public: - [[nodiscard]] static auto create_directory_and_test(std::string &dir_name) - -> std::string { - dir_name += std::to_string(++idx); - auto api_path = utils::path::create_api_path(dir_name); - auto dir_path = utils::path::combine(mount_location, {dir_name}); - - EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str())); - EXPECT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr)); - EXPECT_TRUE(::PathIsDirectoryA(dir_path.c_str())); - return dir_path; - } - - [[nodiscard]] static auto create_file_and_test(std::string &file_name) - -> std::string { - file_name += std::to_string(++idx); - auto api_path = utils::path::create_api_path(file_name); - auto file_path = utils::path::combine(mount_location, {file_name}); - - auto handle = - ::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)); - - EXPECT_TRUE(utils::file::file(file_path).exists()); - - auto opt_size = utils::file::file(file_path).size(); - EXPECT_TRUE(opt_size.has_value()); - EXPECT_EQ(0, opt_size.value()); - - std::string attr; - EXPECT_EQ(api_error::success, - provider->get_item_meta(api_path, META_ATTRIBUTES, attr)); - EXPECT_EQ(FILE_ATTRIBUTE_ARCHIVE, utils::string::to_uint32(attr)); - - return file_path; - } - - static void delete_directory_and_test(const std::string &dir_path) { - EXPECT_TRUE(::PathIsDirectoryA(dir_path.c_str())); - EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str())); - EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str())); - } - - static void delete_file_and_test(std::string_view file_path) { - EXPECT_TRUE(utils::file::file(file_path).remove()); - EXPECT_FALSE(utils::file::file(file_path).exists()); - EXPECT_FALSE(utils::file::directory(file_path).exists()); - EXPECT_FALSE(utils::file::file(file_path).exists()); - } - - static void execute_mount() { - auto mount_cmd = "start .\\repertory.exe -f -dd \"" + - config->get_data_directory() + "\"" + " " + - utils::string::join(drive_args, ' '); + static void execute_mount(auto args, auto location) { + auto mount_cmd = + "start .\\repertory.exe -f " + utils::string::join(args, ' '); std::cout << "mount command: " << mount_cmd << std::endl; ASSERT_EQ(0, system(mount_cmd.c_str())); std::this_thread::sleep_for(5s); - ASSERT_TRUE(utils::file::directory{mount_location}.exists()); + ASSERT_TRUE(utils::file::directory{location}.exists()); } - static void execute_unmount() { + static void execute_unmount(auto args, auto location) { auto unmounted{false}; - auto unmount_cmd = ".\\repertory.exe -dd \"" + - config->get_data_directory() + "\"" + " " + - utils::string::join(drive_args, ' ') + " -unmount"; - for (int i = 0; not unmounted && (i < 50); i++) { + auto unmount_cmd = + ".\\repertory.exe " + utils::string::join(args, ' ') + " -unmount"; + for (int i = 0; not unmounted && (i < 6); i++) { std::cout << "unmount command: " << unmount_cmd << std::endl; system(unmount_cmd.c_str()); - unmounted = not utils::file::directory{mount_location}.exists(); + unmounted = not utils::file::directory{location}.exists(); if (not unmounted) { std::this_thread::sleep_for(5s); } } - EXPECT_TRUE(unmounted); + ASSERT_TRUE(unmounted); } }; -template -std::string winfsp_test::cfg_directory; - -template -std::unique_ptr winfsp_test::comm; - -template -std::unique_ptr winfsp_test::config; - template std::filesystem::path winfsp_test::current_directory; template -provider_type winfsp_test::current_provider{provider_t::type}; - -template -std::unique_ptr winfsp_test::drive; +provider_type winfsp_test::current_provider{provider_t::type2}; template std::vector winfsp_test::drive_args; +template +std::vector winfsp_test::drive_args2; + template std::string winfsp_test::mount_location; template -std::unique_ptr winfsp_test::provider; - -template -std::string winfsp_test::test_directory; - -using winfsp_provider_types = ::testing::Types; -// using winfsp_provider_types = ::testing::Types; +std::string winfsp_test::mount_location2; +// 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_info_test.cpp b/repertory/repertory_test/src/winfsp_drive_info_test.cpp index 9f968bca..b55f197d 100644 --- a/repertory/repertory_test/src/winfsp_drive_info_test.cpp +++ b/repertory/repertory_test/src/winfsp_drive_info_test.cpp @@ -138,6 +138,9 @@ TYPED_TEST(winfsp_test, info_can_get_file_name_info) { } TYPED_TEST(winfsp_test, info_can_get_file_info) { + FILETIME file_time{}; + ::GetSystemTimeAsFileTime(&file_time); + auto time_low = ((PLARGE_INTEGER)&file_time)->QuadPart; auto time_high = time_low + 10000 * 10000 /* 10 seconds */; @@ -153,14 +156,14 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) { BY_HANDLE_FILE_INFORMATION file_info{}; EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); - EXPECT_LE(time_low, file_info.ftCreationTime.QuadPart); - EXPECT_GT(time_high, file_info.ftCreationTime.QuadPart); + EXPECT_LE(time_low, file_info.ftCreationTime.dwLowDateTime); + EXPECT_GT(time_high, file_info.ftCreationTime.dwHighDateTime); - EXPECT_LE(time_low, file_info.ftLastAccessTime.QuadPart); - EXPECT_GT(time_high, file_info.ftLastAccessTime.QuadPart); + EXPECT_LE(time_low, file_info.ftLastAccessTime.dwLowDateTime); + EXPECT_GT(time_high, file_info.ftLastAccessTime.dwHighDateTime); - EXPECT_LE(time_low, file_info.ftLastWriteTime.QuadPart); - EXPECT_GT(time_high, file_info.ftLastWriteTime.QuadPart); + EXPECT_LE(time_low, file_info.ftLastWriteTime.dwLowDateTime); + EXPECT_GT(time_high, file_info.ftLastWriteTime.dwHighDateTime); EXPECT_EQ(0U, file_info.nFileSizeHigh); EXPECT_EQ(0U, file_info.nFileSizeLow); @@ -169,7 +172,7 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) { EXPECT_EQ(FILE_ATTRIBUTE_ARCHIVE, file_info.dwFileAttributes); - EXPECT_EQ(0U, file_info.dwVolumeSerialNumber) + EXPECT_EQ(0U, file_info.dwVolumeSerialNumber); ::CloseHandle(handle); }