diff --git a/Core/Util/MemStick.cpp b/Core/Util/MemStick.cpp index fe79846b19..e081c00a64 100644 --- a/Core/Util/MemStick.cpp +++ b/Core/Util/MemStick.cpp @@ -172,23 +172,43 @@ MemstickFolderCheck CheckNewMemstickFolder(const Path &newFolder, const Path &cu return MemstickFolderCheck::OK; } -bool SwitchMemstickFolderTo(Path newMemstickFolder) { +static bool CanWriteTo(const Path &folder) { + const Path testWriteFile = folder / ".write_verify_file"; + if (!File::WriteDataToFile(true, "1", 1, testWriteFile)) { + return false; + } + File::Delete(testWriteFile); + return true; +} + +bool CanSwitchMemstickFolderTo(const Path &newMemstickFolder) { // Doesn't already exist, create. // Should this ever happen? if (newMemstickFolder.Type() == PathType::NATIVE) { if (!File::Exists(newMemstickFolder)) { File::CreateFullPath(newMemstickFolder); } - Path testWriteFile = newMemstickFolder / ".write_verify_file"; - if (!File::WriteDataToFile(true, "1", 1, testWriteFile)) { + if (!CanWriteTo(newMemstickFolder)) { + ERROR_LOG(Log::System, "Can't write to '%s'", newMemstickFolder.c_str()); return false; } - File::Delete(testWriteFile); } else { // TODO: Do the same but with scoped storage? Not really necessary, right? If it came from a browse // for folder, we can assume it exists and is writable, barring wacky race conditions like the user // being connected by USB and deleting it. } + // Where memstick_dir.txt goes. Not set on desktops, which only get here through a debug start screen. + if (!g_Config.internalDataDirectory.empty() && !CanWriteTo(g_Config.internalDataDirectory)) { + ERROR_LOG(Log::System, "Can't write to '%s'", g_Config.internalDataDirectory.c_str()); + return false; + } + return true; +} + +bool SwitchMemstickFolderTo(Path newMemstickFolder) { + if (!CanSwitchMemstickFolderTo(newMemstickFolder)) { + return false; + } Path memStickDirFile = g_Config.internalDataDirectory / "memstick_dir.txt"; #if PPSSPP_PLATFORM(UWP) diff --git a/Core/Util/MemStick.h b/Core/Util/MemStick.h index 119f78f387..cd813a7f0e 100644 --- a/Core/Util/MemStick.h +++ b/Core/Util/MemStick.h @@ -48,5 +48,7 @@ enum class MemstickFolderCheck { MemstickFolderCheck CheckNewMemstickFolder(const Path &newFolder, const Path ¤tFolder); bool FolderSeemsToBeUsed(const Path &newMemstickFolder); +// The checks SwitchMemstickFolderTo() starts with, to run before moving any data. +bool CanSwitchMemstickFolderTo(const Path &newMemstickFolder); bool SwitchMemstickFolderTo(Path newMemstickFolder); MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressReporter &progressReporter); diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index 5dbf161b01..f2f1315d19 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -551,7 +551,7 @@ void ConfirmMemstickMoveScreen::CreateViews() { } if (!error_.empty()) { - leftColumn->Add(new TextView(error_, ALIGN_LEFT, false)); + leftColumn->Add(new TextView(error_, ALIGN_LEFT | FLAG_WRAP_TEXT, false)); } if (!oldMemstickFolder.empty()) { @@ -566,7 +566,7 @@ void ConfirmMemstickMoveScreen::CreateViews() { } if (!moveDataTask_) { - if (!initialSetup_ && CanMoveData()) { + if (!initialSetup_ && CanMoveData() && !dataMoved_) { leftColumn->Add(new CheckBox(&moveData_, ms->T("Move Data")))->OnClick.Handle(this, &ConfirmMemstickMoveScreen::OnMoveDataClick); } @@ -611,7 +611,9 @@ void ConfirmMemstickMoveScreen::update() { if (result->success) { progressReporter_.SetProgress(T(I18NCat::DIALOG, "Done!")); INFO_LOG(Log::System, "Move data task finished successfully!"); - // Succeeded! + // Succeeded! If the switch below fails, OK only retries the switch. + dataMoved_ = true; + moveData_ = false; FinishFolderMove(); } else { progressReporter_.SetProgress(ms->T("Failed to move some files!")); @@ -639,7 +641,20 @@ void ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) { // Should probably be done on a background thread so we can show some UI. // So we probably need another screen for this with a progress bar.. // If the directory itself is called PSP, don't go below. - if (IsBlocked()) { + if (IsBlocked() || moveDataTask_) { + return; + } + + // Only the switch is left to retry, and its own failure message says the data moved. + if (dataMoved_) { + FinishFolderMove(); + return; + } + + // Find out now if the switch would fail, rather than after moving the data away. + if (!CanSwitchMemstickFolderTo(newMemstickFolder_)) { + error_ = T(I18NCat::MEMSTICK, "That folder doesn't work as a memstick folder."); + RecreateViews(); return; } @@ -667,8 +682,11 @@ void ConfirmMemstickMoveScreen::FinishFolderMove() { // Successful so far, switch the memstick folder. if (!SwitchMemstickFolderTo(newMemstickFolder_)) { - // TODO: More precise errors. - error_ = ms->T("That folder doesn't work as a memstick folder."); + if (dataMoved_) { + error_ = ms->T("DataMovedButNotSwitched", "Your data was moved to the new folder, but PPSSPP couldn't switch to it. Please try again."); + } else { + error_ = ms->T("That folder doesn't work as a memstick folder."); + } RecreateViews(); return; } diff --git a/UI/MemStickScreen.h b/UI/MemStickScreen.h index 6fc3a3e7ae..aceb2dd0f7 100644 --- a/UI/MemStickScreen.h +++ b/UI/MemStickScreen.h @@ -134,6 +134,8 @@ private: bool moveData_ = true; #endif bool initialSetup_; + // The data is already in the new folder. + bool dataMoved_ = false; MoveProgressReporter progressReporter_; UI::TextView *progressView_ = nullptr;