summaryrefslogtreecommitdiff
path: root/Source/Core/Common
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/Common
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/Common')
-rw-r--r--Source/Core/Common/FileUtil.cpp97
-rw-r--r--Source/Core/Common/FileUtil.h19
2 files changed, 99 insertions, 17 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);