diff --git a/tests/ctest/common/CMakeLists.txt b/tests/ctest/common/CMakeLists.txt index dfe66f89035a9..bb5ceb304bbc5 100644 --- a/tests/ctest/common/CMakeLists.txt +++ b/tests/ctest/common/CMakeLists.txt @@ -1,5 +1,6 @@ add_pcsx2_test(common_test byteswap_tests.cpp + filesystem_tests.cpp path_tests.cpp string_util_tests.cpp ) diff --git a/tests/ctest/common/filesystem_tests.cpp b/tests/ctest/common/filesystem_tests.cpp new file mode 100644 index 0000000000000..89562819bf815 --- /dev/null +++ b/tests/ctest/common/filesystem_tests.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team +// SPDX-License-Identifier: GPL-3.0+ + +#include "common/FileSystem.h" +#include "common/Path.h" +#include + +#ifdef __linux__ + +#include + +static std::optional create_test_directory() +{ + for (u16 i = 0; i < UINT16_MAX; i++) + { + std::string path = std::string("/tmp/pcsx2_filesystem_test_") + std::to_string(i); + if (!FileSystem::DirectoryExists(path.c_str())) + { + if (!FileSystem::CreateDirectoryPath(path.c_str(), false)) + break; + + return path; + } + } + + return std::nullopt; +} + +TEST(FileSystem, RecursiveDeleteDirectoryDontFollowSymbolicLinks) +{ + // Find a suitable location to write some test files. + std::optional test_dir = create_test_directory(); + ASSERT_TRUE(test_dir.has_value()); + + // Create a target directory containing a file that shouldn't be deleted. + std::string target_dir = Path::Combine(*test_dir, "target_dir"); + ASSERT_TRUE(FileSystem::CreateDirectoryPath(target_dir.c_str(), false)); + std::string file_path = Path::Combine(target_dir, "file.txt"); + ASSERT_TRUE(FileSystem::WriteStringToFile(file_path.c_str(), "Lorem ipsum!")); + + // Create a directory containing a symlink to the target directory. + std::string dir_to_delete = Path::Combine(*test_dir, "dir_to_delete"); + ASSERT_TRUE(FileSystem::CreateDirectoryPath(dir_to_delete.c_str(), false)); + std::string symlink_path = Path::Combine(dir_to_delete, "link"); + ASSERT_EQ(symlink(target_dir.c_str(), symlink_path.c_str()), 0); + + // Delete the directory containing the symlink. + ASSERT_TRUE(dir_to_delete.starts_with("/tmp/")); + ASSERT_TRUE(FileSystem::RecursiveDeleteDirectory(dir_to_delete.c_str())); + + // Make sure the target file didn't get deleted. + ASSERT_TRUE(FileSystem::FileExists(file_path.c_str())); + + // Clean up. + ASSERT_TRUE(FileSystem::DeleteFilePath(file_path.c_str())); + ASSERT_TRUE(FileSystem::DeleteDirectory(target_dir.c_str())); + ASSERT_TRUE(FileSystem::DeleteDirectory(test_dir->c_str())); +} + +#endif