diff --git a/Source/Android/jni/WiiUtils.cpp b/Source/Android/jni/WiiUtils.cpp index 5939816b8e..b6f494e405 100644 --- a/Source/Android/jni/WiiUtils.cpp +++ b/Source/Android/jni/WiiUtils.cpp @@ -191,12 +191,12 @@ Java_org_dolphinemu_dolphinemu_utils_WiiUtils_getSystemMenuVersion(JNIEnv* env, JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_utils_WiiUtils_syncSdFolderToSdImage(JNIEnv* env, jclass) { - return static_cast(Common::SyncSDFolderToSDImage(false)); + return static_cast(Common::SyncSDFolderToSDImage([]() { return false; }, false)); } JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_utils_WiiUtils_syncSdImageToSdFolder(JNIEnv* env, jclass) { - return static_cast(Common::SyncSDImageToSDFolder()); + return static_cast(Common::SyncSDImageToSDFolder([]() { return false; })); } } diff --git a/Source/Core/Common/FatFsUtil.cpp b/Source/Core/Common/FatFsUtil.cpp index 2c88b56101..f194dc22a3 100644 --- a/Source/Core/Common/FatFsUtil.cpp +++ b/Source/Core/Common/FatFsUtil.cpp @@ -353,8 +353,12 @@ static u64 GetSize(const File::FSTEntry& entry) return size; } -static bool Pack(const File::FSTEntry& entry, bool is_root, std::vector& tmp_buffer) +static bool Pack(const std::function& cancelled, const File::FSTEntry& entry, bool is_root, + std::vector& tmp_buffer) { + if (cancelled()) + return false; + if (!entry.isDirectory) { File::IOFile src(entry.physicalName, "rb"); @@ -392,6 +396,9 @@ static bool Pack(const File::FSTEntry& entry, bool is_root, std::vector& tmp u64 size = entry.size; while (size > 0) { + if (cancelled()) + return false; + u32 chunk_size = static_cast(std::min(size, static_cast(tmp_buffer.size()))); if (!src.ReadBytes(tmp_buffer.data(), chunk_size)) { @@ -456,7 +463,7 @@ static bool Pack(const File::FSTEntry& entry, bool is_root, std::vector& tmp for (const File::FSTEntry& child : entry.children) { - if (!Pack(child, false, tmp_buffer)) + if (!Pack(cancelled, child, false, tmp_buffer)) return false; } @@ -484,7 +491,7 @@ static void SortFST(File::FSTEntry* root) SortFST(&child); } -bool SyncSDFolderToSDImage(bool deterministic) +bool SyncSDFolderToSDImage(const std::function& cancelled, bool deterministic) { const std::string source_dir = File::GetUserPath(D_WIISDCARDSYNCFOLDER_IDX); const std::string image_path = File::GetUserPath(F_WIISDCARDIMAGE_IDX); @@ -528,7 +535,10 @@ bool SyncSDFolderToSDImage(bool deterministic) } // delete temp file in failure case - Common::ScopeGuard image_delete_guard{[&] { File::Delete(temp_image_path); }}; + Common::ScopeGuard image_delete_guard{[&] { + image.Close(); + File::Delete(temp_image_path); + }}; if (!image.Resize(size)) { @@ -563,7 +573,7 @@ bool SyncSDFolderToSDImage(bool deterministic) } Common::ScopeGuard unmount_guard{[] { f_unmount(""); }}; - if (!Pack(root, true, tmp_buffer)) + if (!Pack(cancelled, root, true, tmp_buffer)) { ERROR_LOG_FMT(COMMON, "Failed to pack folder {} to SD image at {}", source_dir, temp_image_path); @@ -590,9 +600,12 @@ bool SyncSDFolderToSDImage(bool deterministic) return true; } -static bool Unpack(const std::string path, bool is_directory, const char* name, - std::vector& tmp_buffer) +static bool Unpack(const std::function& cancelled, const std::string path, + bool is_directory, const char* name, std::vector& tmp_buffer) { + if (cancelled()) + return false; + if (!is_directory) { FIL src{}; @@ -614,6 +627,9 @@ static bool Unpack(const std::string path, bool is_directory, const char* name, u32 size = f_size(&src); while (size > 0) { + if (cancelled()) + return false; + u32 chunk_size = std::min(size, static_cast(tmp_buffer.size())); u32 read_size; const auto read_error_code = f_read(&src, tmp_buffer.data(), chunk_size, &read_size); @@ -717,8 +733,8 @@ static bool Unpack(const std::string path, bool is_directory, const char* name, return false; } - if (!Unpack(fmt::format("{}/{}", path, childname), entry.fattrib & AM_DIR, entry.fname, - tmp_buffer)) + if (!Unpack(cancelled, fmt::format("{}/{}", path, childname), entry.fattrib & AM_DIR, + entry.fname, tmp_buffer)) { return false; } @@ -743,7 +759,7 @@ static bool Unpack(const std::string path, bool is_directory, const char* name, return true; } -bool SyncSDImageToSDFolder() +bool SyncSDImageToSDFolder(const std::function& cancelled) { const std::string image_path = File::GetUserPath(F_WIISDCARDIMAGE_IDX); const std::string target_dir = File::GetUserPath(D_WIISDCARDSYNCFOLDER_IDX); @@ -800,7 +816,7 @@ bool SyncSDImageToSDFolder() } std::vector tmp_buffer(MAX_CLUSTER_SIZE); - if (!Unpack(target_dir_without_slash, true, "", tmp_buffer)) + if (!Unpack(cancelled, target_dir_without_slash, true, "", tmp_buffer)) { ERROR_LOG_FMT(COMMON, "Failed to unpack SD image {} to {}", image_path, target_dir); File::DeleteDirRecursively(target_dir_without_slash); diff --git a/Source/Core/Common/FatFsUtil.h b/Source/Core/Common/FatFsUtil.h index 2cefc1db1f..df0ef58984 100644 --- a/Source/Core/Common/FatFsUtil.h +++ b/Source/Core/Common/FatFsUtil.h @@ -9,8 +9,8 @@ namespace Common { -bool SyncSDFolderToSDImage(bool deterministic); -bool SyncSDImageToSDFolder(); +bool SyncSDFolderToSDImage(const std::function& cancelled, bool deterministic); +bool SyncSDImageToSDFolder(const std::function& cancelled); class FatFsCallbacks { diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 3bc9457003..8fa83e21fa 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -503,11 +503,14 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi bool sync_sd_folder = core_parameter.bWii && Config::Get(Config::MAIN_WII_SD_CARD) && Config::Get(Config::MAIN_WII_SD_CARD_ENABLE_FOLDER_SYNC); if (sync_sd_folder) - sync_sd_folder = Common::SyncSDFolderToSDImage(Core::WantsDeterminism()); + { + sync_sd_folder = + Common::SyncSDFolderToSDImage([]() { return false; }, Core::WantsDeterminism()); + } Common::ScopeGuard sd_folder_sync_guard{[sync_sd_folder] { if (sync_sd_folder && Config::Get(Config::MAIN_ALLOW_SD_WRITES)) - Common::SyncSDImageToSDFolder(); + Common::SyncSDImageToSDFolder([]() { return false; }); }}; // Load Wiimotes - only if we are booting in Wii mode diff --git a/Source/Core/DolphinQt/Settings/WiiPane.cpp b/Source/Core/DolphinQt/Settings/WiiPane.cpp index 4003597daf..40674ece3a 100644 --- a/Source/Core/DolphinQt/Settings/WiiPane.cpp +++ b/Source/Core/DolphinQt/Settings/WiiPane.cpp @@ -3,6 +3,8 @@ #include "DolphinQt/Settings/WiiPane.h" +#include + #include #include #include @@ -30,6 +32,7 @@ #include "DolphinQt/QtUtils/DolphinFileDialog.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h" +#include "DolphinQt/QtUtils/ParallelProgressDialog.h" #include "DolphinQt/QtUtils/SignalBlocking.h" #include "DolphinQt/Settings.h" #include "DolphinQt/Settings/USBDeviceAddToWhitelistDialog.h" @@ -228,7 +231,17 @@ void WiiPane::CreateSDCard() QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::Yes) { - if (!Common::SyncSDFolderToSDImage(false)) + ParallelProgressDialog progress_dialog(tr("Converting..."), tr("Cancel"), 0, 0, this); + progress_dialog.GetRaw()->setWindowModality(Qt::WindowModal); + progress_dialog.GetRaw()->setWindowTitle(tr("Progress")); + auto success = std::async(std::launch::async, [&] { + const bool good = Common::SyncSDFolderToSDImage( + [&progress_dialog]() { return progress_dialog.WasCanceled(); }, false); + progress_dialog.Reset(); + return good; + }); + progress_dialog.GetRaw()->exec(); + if (!success.get()) ModalMessageBox::warning(this, tr("Convert Folder to File Now"), tr("Conversion failed.")); } }); @@ -242,7 +255,17 @@ void WiiPane::CreateSDCard() QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::Yes) { - if (!Common::SyncSDImageToSDFolder()) + ParallelProgressDialog progress_dialog(tr("Converting..."), tr("Cancel"), 0, 0, this); + progress_dialog.GetRaw()->setWindowModality(Qt::WindowModal); + progress_dialog.GetRaw()->setWindowTitle(tr("Progress")); + auto success = std::async(std::launch::async, [&] { + const bool good = Common::SyncSDImageToSDFolder( + [&progress_dialog]() { return progress_dialog.WasCanceled(); }); + progress_dialog.Reset(); + return good; + }); + progress_dialog.GetRaw()->exec(); + if (!success.get()) ModalMessageBox::warning(this, tr("Convert File to Folder Now"), tr("Conversion failed.")); } });