Merge pull request #11596 from AdmiralCurtiss/copyany
Common/FileUtil: Migrate CopyDir() to a more clear interface.
This commit is contained in:
commit
c730ee2de2
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue