summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2023-02-27 12:02:00 +0100
committerGitHub <noreply@github.com>2023-02-27 12:02:00 +0100
commitc730ee2de2fa5683209f25b07f312fc23717e2b4 (patch)
tree34b4074900c40d8bb5702844931396e8eeb31ff2 /Source/Core
parent4fb3042944e71213167b0bbc417508b3b1c9467e (diff)
parenta11b9d585f0d4668a8d4f698e0d03d1c79013eac (diff)
Merge pull request #11596 from AdmiralCurtiss/copyany
Common/FileUtil: Migrate CopyDir() to a more clear interface.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/FileUtil.cpp97
-rw-r--r--Source/Core/Common/FileUtil.h19
-rw-r--r--Source/Core/Core/IOS/WFS/WFSI.cpp2
-rw-r--r--Source/Core/Core/WiiRoot.cpp20
-rw-r--r--Source/Core/UICommon/AutoUpdate.cpp2
5 files changed, 114 insertions, 26 deletions
diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp
index 0d4288c609..d456952980 100644
--- a/Source/Core/Common/FileUtil.cpp
+++ b/Source/Core/Common/FileUtil.cpp
@@ -193,7 +193,6 @@ bool Delete(const std::string& filename, IfAbsentBehavior behavior)
return true;
}
-// Returns true if successful, or path already exists.
bool CreateDir(const std::string& path)
{
DEBUG_LOG_FMT(COMMON, "{}: directory {}", __func__, path);
@@ -202,7 +201,24 @@ bool CreateDir(const std::string& path)
auto native_path = StringToPath(path);
bool success = fs::create_directory(native_path, error);
// If the path was not created, check if it was a pre-existing directory
- if (!success && fs::is_directory(native_path))
+ std::error_code error_ignored;
+ if (!success && fs::is_directory(native_path, error_ignored))
+ success = true;
+ if (!success)
+ ERROR_LOG_FMT(COMMON, "{}: failed on {}: {}", __func__, path, error.message());
+ return success;
+}
+
+bool CreateDirs(std::string_view path)
+{
+ DEBUG_LOG_FMT(COMMON, "{}: directory {}", __func__, path);
+
+ std::error_code error;
+ auto native_path = StringToPath(path);
+ bool success = fs::create_directories(native_path, error);
+ // If the path was not created, check if it was a pre-existing directory
+ std::error_code error_ignored;
+ if (!success && fs::is_directory(native_path, error_ignored))
success = true;
if (!success)
ERROR_LOG_FMT(COMMON, "{}: failed on {}: {}", __func__, path, error.message());
@@ -217,7 +233,8 @@ bool CreateFullPath(std::string_view fullPath)
auto native_path = StringToPath(fullPath).parent_path();
bool success = fs::create_directories(native_path, error);
// If the path was not created, check if it was a pre-existing directory
- if (!success && fs::is_directory(native_path))
+ std::error_code error_ignored;
+ if (!success && fs::is_directory(native_path, error_ignored))
success = true;
if (!success)
ERROR_LOG_FMT(COMMON, "{}: failed on {}: {}", __func__, fullPath, error.message());
@@ -516,27 +533,81 @@ bool DeleteDirRecursively(const std::string& directory)
return success;
}
-// Create directory and copy contents (optionally overwrites existing files)
-bool CopyDir(const std::string& source_path, const std::string& dest_path, const bool destructive)
+bool Copy(std::string_view source_path, std::string_view dest_path, bool overwrite_existing)
{
+ DEBUG_LOG_FMT(COMMON, "{}: {} --> {} ({})", __func__, source_path, dest_path,
+ overwrite_existing ? "overwrite" : "preserve");
+
auto src_path = StringToPath(source_path);
auto dst_path = StringToPath(dest_path);
- if (fs::equivalent(src_path, dst_path))
+ std::error_code error;
+ auto options = fs::copy_options::recursive;
+ if (overwrite_existing)
+ options |= fs::copy_options::overwrite_existing;
+ fs::copy(src_path, dst_path, options, error);
+ if (error)
+ {
+ std::error_code error_ignored;
+ if (fs::equivalent(src_path, dst_path, error_ignored))
+ return true;
+
+ ERROR_LOG_FMT(COMMON, "{}: failed {} --> {} ({}): {}", __func__, source_path, dest_path,
+ overwrite_existing ? "overwrite" : "preserve", error.message());
+ return false;
+ }
+ return true;
+}
+
+static bool MoveWithOverwrite(const std::filesystem::path& src, const std::filesystem::path& dst,
+ std::error_code& error)
+{
+ fs::rename(src, dst, error);
+ if (!error)
return true;
- DEBUG_LOG_FMT(COMMON, "{}: {} --> {}", __func__, source_path, dest_path);
+ // rename failed, try fallbacks
- auto options = fs::copy_options::recursive;
- if (destructive)
- options |= fs::copy_options::overwrite_existing;
+ if (!fs::is_directory(src))
+ {
+ // src is not a directory (ie, probably a file), try to copy file + delete
+ if (!fs::copy_file(src, dst, fs::copy_options::overwrite_existing, error))
+ return false;
+ if (!fs::remove(src, error))
+ return false;
+ return true;
+ }
+
+ // src is a directory, recurse into it and try to move all sub-elements one by one
+ // this usually happens because the target is a non-empty directory
+ for (fs::directory_iterator it(src, error); it != fs::directory_iterator(); it.increment(error))
+ {
+ if (error)
+ return false;
+ if (!MoveWithOverwrite(it->path(), dst / it->path().filename(), error))
+ return false;
+ }
+ if (error)
+ return false;
+
+ // all sub-elements moved, remove top directory
+ if (!fs::remove(src, error))
+ return false;
+
+ return true;
+}
+
+bool MoveWithOverwrite(std::string_view source_path, std::string_view dest_path)
+{
+ DEBUG_LOG_FMT(COMMON, "{}: {} --> {}", __func__, source_path, dest_path);
+ auto src_path = StringToPath(source_path);
+ auto dst_path = StringToPath(dest_path);
std::error_code error;
- bool copied = fs::copy_file(src_path, dst_path, options, error);
- if (!copied)
+ if (!MoveWithOverwrite(src_path, dst_path, error))
{
ERROR_LOG_FMT(COMMON, "{}: failed {} --> {}: {}", __func__, source_path, dest_path,
error.message());
}
- return copied;
+ return true;
}
// Returns the current directory
diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h
index ff71d394bc..cadabbd541 100644
--- a/Source/Core/Common/FileUtil.h
+++ b/Source/Core/Common/FileUtil.h
@@ -140,9 +140,12 @@ u64 GetSize(const std::string& path);
// Overloaded GetSize, accepts FILE*
u64 GetSize(FILE* f);
-// Returns true if successful, or path already exists.
+// Creates a single directory. Returns true if successful or if the path already exists.
bool CreateDir(const std::string& filename);
+// Creates directories recursively. Returns true if successful or if the path already exists.
+bool CreateDirs(std::string_view filename);
+
// Creates the full path to the file given in fullPath.
// That is, for path '/a/b/c.bin', creates folders '/a' and '/a/b'.
// Returns true if creation is successful or if the path already exists.
@@ -185,9 +188,17 @@ bool DeleteDirRecursively(const std::string& directory);
// Returns the current directory
std::string GetCurrentDir();
-// Create directory and copy contents (optionally overwrites existing files)
-bool CopyDir(const std::string& source_path, const std::string& dest_path,
- bool destructive = false);
+// Copies source_path to dest_path, as if by std::filesystem::copy(). Returns true on success or if
+// the source and destination are already the same (as determined by std::filesystem::equivalent()).
+bool Copy(std::string_view source_path, std::string_view dest_path,
+ bool overwrite_existing = false);
+
+// Moves source_path to dest_path. On success, the source_path will no longer exist, and the
+// dest_path will contain the data previously in source_path. Files in dest_path will be overwritten
+// if they match files in source_path, but files that only exist in dest_path will be kept. No
+// guarantee on the state is given on failure; the move may have completely failed or partially
+// completed.
+bool MoveWithOverwrite(std::string_view source_path, std::string_view dest_path);
// Set the current directory to given directory
bool SetCurrentDir(const std::string& directory);
diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp
index f1f66e1554..833052ce55 100644
--- a/Source/Core/Core/IOS/WFS/WFSI.cpp
+++ b/Source/Core/Core/IOS/WFS/WFSI.cpp
@@ -121,7 +121,7 @@ void WFSIDevice::FinalizePatchInstall()
const std::string current_title_dir = fmt::format("/vol/{}/title/{}/{}", m_device_name,
m_current_group_id_str, m_current_title_id_str);
const std::string patch_dir = current_title_dir + "/_patch";
- File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true);
+ File::MoveWithOverwrite(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir));
}
std::optional<IPCReply> WFSIDevice::IOCtl(const IOCtlRequest& request)
diff --git a/Source/Core/Core/WiiRoot.cpp b/Source/Core/Core/WiiRoot.cpp
index b6e38be832..7311a6b725 100644
--- a/Source/Core/Core/WiiRoot.cpp
+++ b/Source/Core/Core/WiiRoot.cpp
@@ -186,7 +186,10 @@ static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs,
const auto& netplay_redirect_folder = boot_session_data.GetWiiSyncRedirectFolder();
if (!netplay_redirect_folder.empty())
- File::CopyDir(netplay_redirect_folder, s_temp_redirect_root + "/");
+ {
+ File::CreateDirs(s_temp_redirect_root);
+ File::Copy(netplay_redirect_folder, s_temp_redirect_root);
+ }
}
}
@@ -194,7 +197,7 @@ static void MoveToBackupIfExists(const std::string& path)
{
if (File::Exists(path))
{
- const std::string backup_path = path.substr(0, path.size() - 1) + ".backup" DIR_SEP;
+ const std::string backup_path = path.substr(0, path.size() - 1) + ".backup";
WARN_LOG_FMT(IOS_FS, "Temporary directory at {} exists, moving to backup...", path);
// If backup exists, delete it as we don't want a mess
@@ -204,7 +207,7 @@ static void MoveToBackupIfExists(const std::string& path)
File::DeleteDirRecursively(backup_path);
}
- File::CopyDir(path, backup_path, true);
+ File::MoveWithOverwrite(path, backup_path);
}
}
@@ -359,11 +362,11 @@ void InitializeWiiFileSystemContents(
if (!File::IsDirectory(save_redirect->m_target_path))
{
- File::CreateFullPath(save_redirect->m_target_path + "/");
+ File::CreateDirs(save_redirect->m_target_path);
if (save_redirect->m_clone)
{
- File::CopyDir(Common::GetTitleDataPath(title_id, Common::FROM_SESSION_ROOT),
- save_redirect->m_target_path);
+ File::Copy(Common::GetTitleDataPath(title_id, Common::FROM_SESSION_ROOT),
+ save_redirect->m_target_path);
}
}
s_nand_redirects.emplace_back(IOS::HLE::FS::NandRedirect{
@@ -396,7 +399,10 @@ void CleanUpWiiFileSystemContents(const BootSessionData& boot_session_data)
// copy back the temp nand redirected files to where they should normally be redirected to
for (const auto& redirect : s_temp_nand_redirects)
- File::CopyDir(redirect.temp_path, redirect.real_path + "/", true);
+ {
+ File::CreateFullPath(redirect.real_path);
+ File::MoveWithOverwrite(redirect.temp_path, redirect.real_path);
+ }
IOS::HLE::EmulationKernel* ios = IOS::HLE::GetIOS();
diff --git a/Source/Core/UICommon/AutoUpdate.cpp b/Source/Core/UICommon/AutoUpdate.cpp
index 35b17ed19d..b67c499c14 100644
--- a/Source/Core/UICommon/AutoUpdate.cpp
+++ b/Source/Core/UICommon/AutoUpdate.cpp
@@ -248,7 +248,7 @@ void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInforma
#ifdef __APPLE__
// Copy the updater so it can update itself if needed.
const std::string reloc_updater_path = UpdaterPath(true);
- if (!File::CopyDir(UpdaterPath(), reloc_updater_path))
+ if (!File::Copy(UpdaterPath(), reloc_updater_path))
{
CriticalAlertFmtT("Unable to create updater copy.");
return;