#include "tasks/titleoptions.hpp" #include "config/config.hpp" #include "data/data.hpp" #include "error.hpp" #include "fs/fs.hpp" #include "keyboard.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" #include "ui/ui.hpp" #include void tasks::titleoptions::blacklist_title(sys::Task *task, TitleOptionState::TaskData taskData) { if (error::is_null(task)) { return; } data::TitleInfo *titleInfo = taskData->titleInfo; TitleOptionState *spawningState = taskData->spawningState; if (error::is_null(titleInfo) || error::is_null(spawningState)) { task->complete(); return; } const uint64_t applicationID = titleInfo->get_application_id(); config::add_remove_blacklist(applicationID); data::UserList list{}; data::get_users(list); for (data::User *user : list) { user->erase_save_info_by_id(applicationID); } // We need to signal both since the title in question is no longer valid. spawningState->refresh_required(); spawningState->close_on_update(); task->complete(); } void tasks::titleoptions::delete_all_local_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData) { if (error::is_null(task)) { return; } data::TitleInfo *titleInfo = taskData->titleInfo; if (error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const char *popSuccess = strings::get_by_name(strings::names::TITLEOPTION_POPS, 0); const char *popFailure = strings::get_by_name(strings::names::TITLEOPTION_POPS, 1); { const char *title = titleInfo->get_title(); const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 0); const std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } const char *safeTitle = titleInfo->get_path_safe_title(); const fslib::Path workingDir{config::get_working_directory()}; const fslib::Path targetPath{workingDir / safeTitle}; const bool dirExists = fslib::directory_exists(targetPath); const bool deleteFailed = dirExists && error::fslib(fslib::delete_directory_recursively(targetPath)); if (deleteFailed) { ui::PopMessageManager::push_message(popTicks, popFailure); } else { const char *title = titleInfo->get_title(); const std::string popMessage = stringutil::get_formatted_string(popSuccess, title); ui::PopMessageManager::push_message(popTicks, popMessage); } task->complete(); } void tasks::titleoptions::delete_all_remote_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData) { if (error::is_null(task)) { return; } data::TitleInfo *titleInfo = taskData->titleInfo; remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(titleInfo) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } const char *title = titleInfo->get_title(); const std::string_view remoteTitle = remote->supports_utf8() ? titleInfo->get_title() : titleInfo->get_path_safe_title(); const bool exists = remote->directory_exists(remoteTitle); if (!exists) { TASK_FINISH_RETURN(task); } remote::Item *workDir = remote->get_directory_by_name(remoteTitle); remote->change_directory(workDir); remote::Storage::DirectoryListing remoteListing{}; remote->get_directory_listing(remoteListing); { const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 0); const std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const char *popSuccess = strings::get_by_name(strings::names::TITLEOPTION_POPS, 0); const char *popFailure = strings::get_by_name(strings::names::TITLEOPTION_POPS, 1); for (remote::Item *item : remoteListing) { const bool deleted = remote->delete_item(item); if (!deleted) { ui::PopMessageManager::push_message(popTicks, popFailure); } } const std::string popMessage = stringutil::get_formatted_string(popSuccess, title); ui::PopMessageManager::push_message(popTicks, popMessage); task->complete(); } void tasks::titleoptions::reset_save_data(sys::Task *task, TitleOptionState::TaskData taskData) { if (error::is_null(task)) { return; } data::User *user = taskData->user; data::TitleInfo *titleInfo = taskData->titleInfo; if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } const uint64_t applicationID = titleInfo->get_application_id(); const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID); if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const char *popFailed = strings::get_by_name(strings::names::TITLEOPTION_POPS, 2); const char *popSuccess = strings::get_by_name(strings::names::TITLEOPTION_POPS, 3); { const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 1); const char *title = titleInfo->get_title(); const std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } { fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, saveInfo}; const bool resetFailed = error::fslib(fslib::delete_directory_recursively(fs::DEFAULT_SAVE_ROOT)); const bool commitFailed = error::fslib(fslib::commit_data_to_file_system(fs::DEFAULT_SAVE_MOUNT)); if (resetFailed || commitFailed) { ui::PopMessageManager::push_message(popTicks, popFailed); } else { ui::PopMessageManager::push_message(popTicks, popSuccess); } } task->complete(); } void tasks::titleoptions::delete_save_data_from_system(sys::Task *task, TitleOptionState::TaskData taskData) { if (error::is_null(task)) { return; } data::User *user = taskData->user; data::TitleInfo *titleInfo = taskData->titleInfo; TitleSelectCommon *titleSelect = taskData->titleSelect; TitleOptionState *spawningState = taskData->spawningState; if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(titleSelect) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } const uint64_t applicationID = titleInfo->get_application_id(); const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID); if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; { const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 2); const char *nickname = user->get_nickname(); const char *title = titleInfo->get_title(); const std::string status = stringutil::get_formatted_string(statusFormat, nickname, title); task->set_status(status); } const bool saveDeleted = fs::delete_save_data(saveInfo); if (!saveDeleted) { const char *popError = strings::get_by_name(strings::names::SAVECREATE_POPS, 2); ui::PopMessageManager::push_message(popTicks, popError); } else { const char *title = titleInfo->get_title(); const char *popSuccessFormat = strings::get_by_name(strings::names::SAVECREATE_POPS, 0); const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, title); } user->erase_save_info_by_id(applicationID); titleSelect->refresh(); spawningState->close_on_update(); task->complete(); } void tasks::titleoptions::extend_save_data(sys::Task *task, TitleOptionState::TaskData taskData) { static constexpr int SIZE_MB = 0x100000; if (error::is_null(task)) { return; } data::User *user = taskData->user; data::TitleInfo *titleInfo = taskData->titleInfo; if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const uint64_t applicationID = titleInfo->get_application_id(); const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID); if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); } std::array sizeBuffer = {0}; FsSaveDataExtraData extraData{}; const bool readExtra = fs::read_save_extra_data(saveInfo, extraData); const int sizeMB = extraData.data_size / SIZE_MB; const char *keyboardHeader = strings::get_by_name(strings::names::KEYBOARD, 8); const std::string keyboardDefault = stringutil::get_formatted_string("%lli", sizeMB + 1); const bool validInput = keyboard::get_input(SwkbdType_NumPad, keyboardDefault, keyboardHeader, sizeBuffer.data(), 5); if (!validInput) { TASK_FINISH_RETURN(task); } { const char *nickname = user->get_nickname(); const char *title = titleInfo->get_title(); const char *extendingFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 3); const std::string status = stringutil::get_formatted_string(extendingFormat, nickname, title); task->set_status(status); } const uint8_t saveType = saveInfo->save_data_type; const int64_t size = std::strtoll(sizeBuffer.data(), nullptr, 10) * SIZE_MB; const int64_t journal = !readExtra ? titleInfo->get_journal_size(saveType) : extraData.journal_size; const bool saveExtended = fs::extend_save_data(saveInfo, size, journal); if (saveExtended) { const char *popSuccess = strings::get_by_name(strings::names::TITLEOPTION_POPS, 10); ui::PopMessageManager::push_message(popTicks, popSuccess); } else { const char *popFailed = strings::get_by_name(strings::names::TITLEOPTION_POPS, 11); ui::PopMessageManager::push_message(popTicks, popFailed); } task->complete(); }