From 5367bf394c6092bed589bc4cdb06a2f0ab2c0f75 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Fri, 24 Feb 2023 21:39:02 +0100 Subject: [PATCH] Common/FileUtil: Add Move() function. --- Source/Core/Common/FileUtil.cpp | 52 +++++++++++++++++++++++++++++++++ Source/Core/Common/FileUtil.h | 7 +++++ 2 files changed, 59 insertions(+) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 656e74134b..333831d39f 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -558,6 +558,58 @@ bool Copy(std::string_view source_path, std::string_view dest_path, bool overwri 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; + + // rename failed, try fallbacks + + 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; + if (!MoveWithOverwrite(src_path, dst_path, error)) + { + ERROR_LOG_FMT(COMMON, "{}: failed {} --> {}: {}", __func__, source_path, dest_path, + error.message()); + } + return true; +} + // Create directory and copy contents (optionally overwrites existing files) bool CopyDir(const std::string& source_path, const std::string& dest_path, const bool destructive) { diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index f8cd92a880..53d5d46d3f 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -193,6 +193,13 @@ std::string GetCurrentDir(); 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); + // Create directory and copy contents (optionally overwrites existing files) bool CopyDir(const std::string& source_path, const std::string& dest_path, bool destructive = false);