diff --git a/repertory/repertory_test/src/winfsp_drive_info_test.cpp b/repertory/repertory_test/src/winfsp_drive_info_test.cpp index 40396f25..7186af10 100644 --- a/repertory/repertory_test/src/winfsp_drive_info_test.cpp +++ b/repertory/repertory_test/src/winfsp_drive_info_test.cpp @@ -53,7 +53,7 @@ TYPED_TEST(winfsp_test, info_can_get_basic_info) { FILETIME file_time{}; ::GetSystemTimeAsFileTime(&file_time); - auto time_low = ((PLARGE_INTEGER)&file_time)->QuadPart; + auto time_low = reinterpret_cast(&file_time)->QuadPart; auto time_high = time_low + 10000 * 10000 /* 10 seconds */; auto file_path{ @@ -137,11 +137,33 @@ TYPED_TEST(winfsp_test, info_can_get_file_name_info) { ::CloseHandle(handle); } +TYPED_TEST(winfsp_test, info_get_file_name_info_buffer_too_small) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + std::array name_info{}; + EXPECT_FALSE( + ::GetFileInformationByHandleEx(handle, FileNameInfo, name_info.data(), + static_cast(name_info.size()))); + EXPECT_EQ(ERROR_MORE_DATA, ::GetLastError()); + + auto *info = reinterpret_cast(name_info.data()); + EXPECT_EQ('\\', info->FileName[0U]); + + ::CloseHandle(handle); +} + 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_low = reinterpret_cast(&file_time)->QuadPart; auto time_high = time_low + 10000 * 10000 /* 10 seconds */; auto file_path{ @@ -156,14 +178,26 @@ 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, ((PLARGE_INTEGER)&file_info.ftCreationTime)->QuadPart); - EXPECT_GT(time_high, ((PLARGE_INTEGER)&file_info.ftCreationTime)->QuadPart); + EXPECT_LE( + time_low, + reinterpret_cast(&file_info.ftCreationTime)->QuadPart); + EXPECT_GT( + time_high, + reinterpret_cast(&file_info.ftCreationTime)->QuadPart); - EXPECT_LE(time_low, ((PLARGE_INTEGER)&file_info.ftLastAccessTime)->QuadPart); - EXPECT_GT(time_high, ((PLARGE_INTEGER)&file_info.ftLastAccessTime)->QuadPart); + EXPECT_LE( + time_low, + reinterpret_cast(&file_info.ftLastAccessTime)->QuadPart); + EXPECT_GT( + time_high, + reinterpret_cast(&file_info.ftLastAccessTime)->QuadPart); - EXPECT_LE(time_low, ((PLARGE_INTEGER)&file_info.ftLastWriteTime)->QuadPart); - EXPECT_GT(time_high, ((PLARGE_INTEGER)&file_info.ftLastWriteTime)->QuadPart); + EXPECT_LE( + time_low, + reinterpret_cast(&file_info.ftLastWriteTime)->QuadPart); + EXPECT_GT( + time_high, + reinterpret_cast(&file_info.ftLastWriteTime)->QuadPart); EXPECT_EQ(0U, file_info.nFileSizeHigh); EXPECT_EQ(0U, file_info.nFileSizeLow); @@ -176,6 +210,199 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) { ::CloseHandle(handle); } + +TYPED_TEST(winfsp_test, info_can_get_file_path) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + std::string final_path; + final_path.resize(MAX_PATH + 1U); + + auto result = ::GetFinalPathNameByHandleA( + handle, final_path.data(), final_path.size() - 1U, + VOLUME_NAME_NONE | FILE_NAME_OPENED); + + auto expected_name{ + std::string{"\\repertory\\"} + + utils::string::to_lower(this->mount_location).at(0U) + + "\\test_file_2", + }; + EXPECT_EQ(result, static_cast(expected_name.size())); + EXPECT_STREQ(expected_name.c_str(), final_path.c_str()); + + ::CloseHandle(handle); +} + +TYPED_TEST(winfsp_test, info_can_set_file_info_attributes_to_hidden) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + EXPECT_TRUE(::SetFileAttributesA(file_path.c_str(), FILE_ATTRIBUTE_HIDDEN)); + + BY_HANDLE_FILE_INFORMATION file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); + EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN, file_info.dwFileAttributes); + + ::CloseHandle(handle); +} + +TYPED_TEST( + winfsp_test, + info_can_set_file_info_attributes_to_hidden_ignoring_directory_attribute) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + EXPECT_TRUE(::SetFileAttributesA( + file_path.c_str(), FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)); + + BY_HANDLE_FILE_INFORMATION file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); + EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN, file_info.dwFileAttributes); + + ::CloseHandle(handle); +} + +TYPED_TEST(winfsp_test, info_can_set_creation_file_time) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + BY_HANDLE_FILE_INFORMATION orig_file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &orig_file_info)); + + static constexpr const UINT64 file_time{ + 116444736000000000ULL + 0x4200000042ULL, + }; + + EXPECT_TRUE(::SetFileTime(handle, + reinterpret_cast(&file_time), + nullptr, nullptr)); + + BY_HANDLE_FILE_INFORMATION file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); + + EXPECT_EQ(file_time, *reinterpret_cast(&file_info.ftCreationTime)); + + EXPECT_EQ(*reinterpret_cast(&orig_file_info.ftLastAccessTime), + *reinterpret_cast(&file_info.ftLastAccessTime)); + EXPECT_EQ(*reinterpret_cast(&orig_file_info.ftLastWriteTime), + *reinterpret_cast(&file_info.ftLastWriteTime)); + + ::CloseHandle(handle); +} + +TYPED_TEST(winfsp_test, info_can_set_accessed_file_time) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + BY_HANDLE_FILE_INFORMATION orig_file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &orig_file_info)); + + static constexpr const UINT64 file_time{ + 116444736000000000ULL + 0x4200000042ULL, + }; + + EXPECT_TRUE(::SetFileTime(handle, nullptr, + reinterpret_cast(&file_time), + nullptr)); + + BY_HANDLE_FILE_INFORMATION file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); + + EXPECT_EQ(file_time, *reinterpret_cast(&file_info.ftLastAccessTime)); + EXPECT_EQ(*reinterpret_cast(&orig_file_info.ftCreationTime), + *reinterpret_cast(&file_info.ftCreationTime)); + EXPECT_EQ(*reinterpret_cast(&orig_file_info.ftLastWriteTime), + *reinterpret_cast(&file_info.ftLastWriteTime)); + + ::CloseHandle(handle); +} + +TYPED_TEST(winfsp_test, info_can_set_written_file_time) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + BY_HANDLE_FILE_INFORMATION orig_file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &orig_file_info)); + + static constexpr const UINT64 file_time{ + 116444736000000000ULL + 0x4200000042ULL, + }; + + EXPECT_TRUE(::SetFileTime(handle, nullptr, nullptr, + reinterpret_cast(&file_time))); + + BY_HANDLE_FILE_INFORMATION file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); + + EXPECT_EQ(file_time, *reinterpret_cast(&file_info.ftLastWriteTime)); + + EXPECT_EQ(*reinterpret_cast(&orig_file_info.ftLastAccessTime), + *reinterpret_cast(&file_info.ftLastAccessTime)); + EXPECT_EQ(*reinterpret_cast(&orig_file_info.ftCreationTime), + *reinterpret_cast(&file_info.ftCreationTime)); + + ::CloseHandle(handle); +} + +TYPED_TEST(winfsp_test, info_can_set_file_size) { + auto file_path{ + utils::path::combine(this->mount_location, {"test_file_2"}), + }; + auto handle = + ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + auto offset = ::SetFilePointer(handle, 42, nullptr, FILE_BEGIN); + EXPECT_EQ(42U, offset); + + EXPECT_TRUE(::SetEndOfFile(handle)); + + BY_HANDLE_FILE_INFORMATION file_info{}; + EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info)); + + EXPECT_EQ(0U, file_info.nFileSizeHigh); + EXPECT_EQ(42U, file_info.nFileSizeLow); + + ::CloseHandle(handle); +} } // namespace repertory #endif // defined(_WIN32)