Add replacement table for sanitize_string_for_path

This commit is contained in:
J-D-K
2025-10-02 13:09:27 -04:00
parent 98c00ff858
commit cc5da07eaa
17 changed files with 193 additions and 179 deletions

View File

@@ -39,7 +39,7 @@ INCLUDES := include ./Libraries/FsLib/Switch/FsLib/include ./Libraries/SDLLib/SD
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 09.30.2025
APP_VERSION := 10.02.2025
ROMFS := romfs
ICON := icon.jpg

View File

@@ -18,19 +18,23 @@ class BackupMenuState final : public BaseState
/// @brief Creates a new backup selection state.
/// @param user Pointer to currently selected user.
/// @param titleInfo Pointer to titleInfo of selected title.
/// @param saveType Save data type we're working with.
BackupMenuState(data::User *user, data::TitleInfo *titleInfo);
/// @param saveInfo Pointer to the target save info.
BackupMenuState(data::User *user, data::TitleInfo *titleInfo, const FsSaveDataInfo *saveInfo);
/// @brief Creates and returns a new BackupMenuState.
static inline std::shared_ptr<BackupMenuState> create(data::User *user, data::TitleInfo *titleInfo)
static inline std::shared_ptr<BackupMenuState> create(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo)
{
return std::make_shared<BackupMenuState>(user, titleInfo);
return std::make_shared<BackupMenuState>(user, titleInfo, saveInfo);
}
/// @brief Creates and pushes a new BackupMenuState to the vector.
static inline std::shared_ptr<BackupMenuState> create_and_push(data::User *user, data::TitleInfo *titleInfo)
static inline std::shared_ptr<BackupMenuState> create_and_push(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo)
{
auto newState = BackupMenuState::create(user, titleInfo);
auto newState = BackupMenuState::create(user, titleInfo, saveInfo);
StateManager::push_state(newState);
return newState;
}
@@ -65,6 +69,7 @@ class BackupMenuState final : public BaseState
{
data::User *user{};
data::TitleInfo *titleInfo{};
const FsSaveDataInfo *saveInfo{};
fslib::Path path{}; // This and
std::string remoteName{}; // and this and
remote::Item *remoteItem{}; // this are set when needed.
@@ -82,6 +87,9 @@ class BackupMenuState final : public BaseState
/// @brief Pointer to data for selected title.
data::TitleInfo *m_titleInfo{};
/// @brief Pointer to the save info. This cleans and simplifies code in other places.
const FsSaveDataInfo *m_saveInfo{};
/// @brief Save data type we're working with.
FsSaveDataType m_saveType{};

View File

@@ -13,22 +13,27 @@ class TitleOptionState final : public BaseState
/// @brief Constructs a new title option state.
/// @param user Target user.
/// @param titleInfo Target title.
TitleOptionState(data::User *user, data::TitleInfo *titleInfo, TitleSelectCommon *titleSelect);
TitleOptionState(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo,
TitleSelectCommon *titleSelect);
/// @brief Returns a new TitleOptionState. See constructor.
static inline std::shared_ptr<TitleOptionState> create(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo,
TitleSelectCommon *titleSelect)
{
return std::make_shared<TitleOptionState>(user, titleInfo, titleSelect);
return std::make_shared<TitleOptionState>(user, titleInfo, saveInfo, titleSelect);
}
/// @brief Creates, pushes, and returns a new TitleOptionState
static std::shared_ptr<TitleOptionState> create_and_push(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo,
TitleSelectCommon *titleSelect)
{
auto newState = TitleOptionState::create(user, titleInfo, titleSelect);
auto newState = TitleOptionState::create(user, titleInfo, saveInfo, titleSelect);
StateManager::push_state(newState);
return newState;
}
@@ -53,6 +58,7 @@ class TitleOptionState final : public BaseState
{
data::User *user{};
data::TitleInfo *titleInfo{};
const FsSaveDataInfo *saveInfo{};
TitleOptionState *spawningState{};
TitleSelectCommon *titleSelect{};
};
@@ -65,6 +71,9 @@ class TitleOptionState final : public BaseState
/// @brief This is the target title.
data::TitleInfo *m_titleInfo{};
/// @brief This makes tasks easier to read and understand.
const FsSaveDataInfo *m_saveInfo{};
/// @brief Pointer to the title selection being used for updating.
TitleSelectCommon *m_titleSelect{};

View File

@@ -2,7 +2,7 @@
namespace builddate
{
inline constexpr int MONTH = 9;
inline constexpr int DAY = 30;
inline constexpr int MONTH = 10;
inline constexpr int DAY = 2;
inline constexpr int YEAR = 2025;
}

View File

@@ -21,9 +21,10 @@
#include <cstring>
BackupMenuState::BackupMenuState(data::User *user, data::TitleInfo *titleInfo)
BackupMenuState::BackupMenuState(data::User *user, data::TitleInfo *titleInfo, const FsSaveDataInfo *saveInfo)
: m_user(user)
, m_titleInfo(titleInfo)
, m_saveInfo(saveInfo)
, m_saveType(m_user->get_account_save_type())
, m_directoryPath(config::get_working_directory() / m_titleInfo->get_path_safe_title())
, m_dataStruct(std::make_shared<BackupMenuState::DataStruct>())
@@ -168,6 +169,7 @@ void BackupMenuState::initialize_task_data()
// The other members are set upon actions being taken.
m_dataStruct->user = m_user;
m_dataStruct->titleInfo = m_titleInfo;
m_dataStruct->saveInfo = m_saveInfo;
m_dataStruct->spawningState = this;
}
@@ -183,11 +185,7 @@ void BackupMenuState::initialize_info_string()
void BackupMenuState::save_data_check()
{
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return; }
fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, saveInfo};
fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, m_saveInfo};
fslib::Directory saveRoot{fs::DEFAULT_SAVE_ROOT};
m_saveHasData = saveRoot.is_open() && saveRoot.get_count() > 0;
}

View File

@@ -55,7 +55,7 @@ void BlacklistEditState::refresh_menu()
m_blacklistMenu->reset();
config::get_blacklisted_titles(m_blacklist);
for (const uint64_t &applicationID : m_blacklist)
for (const uint64_t applicationID : m_blacklist)
{
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
if (error::is_null(titleInfo)) { continue; }

View File

@@ -119,13 +119,16 @@ void SettingsState::load_extra_strings()
void SettingsState::update_menu_options()
{
for (int i : {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23})
static constexpr std::array<int, 20> TOGGLE_INDEXES = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 17, 18, 19, 20, 21, 22, 23};
for (const int index : TOGGLE_INDEXES)
{
const char *optionFormat = strings::get_by_name(strings::names::SETTINGS_MENU, i);
const uint8_t value = config::get_by_key(CONFIG_KEY_ARRAY[i]);
const char *optionFormat = strings::get_by_name(strings::names::SETTINGS_MENU, index);
const uint8_t value = config::get_by_key(CONFIG_KEY_ARRAY[index]);
const char *status = SettingsState::get_status_text(value);
const std::string option = stringutil::get_formatted_string(optionFormat, status);
m_settingsMenu->edit_option(i, option);
m_settingsMenu->edit_option(index, option);
}
{
@@ -179,9 +182,7 @@ void SettingsState::change_working_directory()
moved = fs::move_directory_recursively(oldPath, newPath);
error::fslib(fslib::delete_directory_recursively(oldPath));
}
else {
moved = fslib::rename_directory(oldPath, newPath);
}
else { moved = fslib::rename_directory(oldPath, newPath); }
if (!moved)
{
@@ -273,9 +274,7 @@ void SettingsState::toggle_trash_folder()
config::toggle_by_key(config::keys::ENABLE_TRASH_BIN);
if (trashEnabled) { error::fslib(fslib::delete_directory_recursively(trashPath)); }
else {
error::fslib(fslib::create_directory(trashPath));
}
else { error::fslib(fslib::create_directory(trashPath)); }
}
void SettingsState::cycle_anim_scaling()

View File

@@ -81,22 +81,22 @@ void TextTitleSelectState::refresh()
void TextTitleSelectState::create_backup_menu()
{
const int selected = m_titleSelectMenu->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const int selected = m_titleSelectMenu->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const FsSaveDataInfo *saveInfo = m_user->get_save_info_at(selected);
auto backupMenuState = std::make_shared<BackupMenuState>(m_user, titleInfo);
StateManager::push_state(backupMenuState);
BackupMenuState::create_and_push(m_user, titleInfo, saveInfo);
}
void TextTitleSelectState::create_title_option_menu()
{
const int selected = m_titleSelectMenu->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const int selected = m_titleSelectMenu->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const FsSaveDataInfo *saveInfo = m_user->get_save_info_at(selected);
auto titleOptionState = std::make_shared<TitleOptionState>(m_user, titleInfo, this);
StateManager::push_state(titleOptionState);
TitleOptionState::create_and_push(m_user, titleInfo, saveInfo, this);
}
void TextTitleSelectState::add_remove_favorite()

View File

@@ -40,9 +40,13 @@ namespace
};
} // namespace
TitleOptionState::TitleOptionState(data::User *user, data::TitleInfo *titleInfo, TitleSelectCommon *titleSelect)
TitleOptionState::TitleOptionState(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo,
TitleSelectCommon *titleSelect)
: m_user(user)
, m_titleInfo(titleInfo)
, m_saveInfo(saveInfo)
, m_titleSelect(titleSelect)
, m_dataStruct(std::make_shared<TitleOptionState::DataStruct>())
{
@@ -124,6 +128,7 @@ void TitleOptionState::initialize_data_struct()
{
m_dataStruct->user = m_user;
m_dataStruct->titleInfo = m_titleInfo;
m_dataStruct->saveInfo = m_saveInfo;
m_dataStruct->spawningState = this;
m_dataStruct->titleSelect = m_titleSelect;
}

View File

@@ -74,22 +74,23 @@ bool TitleSelectState::title_count_check()
void TitleSelectState::create_backup_menu()
{
const int selected = m_titleView->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const int selected = m_titleView->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const FsSaveDataInfo *saveInfo = m_user->get_save_info_at(selected);
auto backupMenu = std::make_shared<BackupMenuState>(m_user, titleInfo);
auto backupMenu = std::make_shared<BackupMenuState>(m_user, titleInfo, saveInfo);
StateManager::push_state(backupMenu);
}
void TitleSelectState::create_title_option_menu()
{
const int selected = m_titleView->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const int selected = m_titleView->get_selected();
const uint64_t applicationID = m_user->get_application_id_at(selected);
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
const FsSaveDataInfo *saveInfo = m_user->get_save_info_at(selected);
auto titleOptions = std::make_shared<TitleOptionState>(m_user, titleInfo, this);
StateManager::push_state(titleOptions);
TitleOptionState::create_and_push(m_user, titleInfo, saveInfo, this);
}
void TitleSelectState::deactivate_state()

View File

@@ -205,6 +205,7 @@ bool config::ConfigContext::load_config_file()
json_object_iter_next(&configIter);
}
return true;
}
@@ -227,7 +228,7 @@ void config::ConfigContext::save_config_file()
json::add_object(configJSON, config::keys::UI_ANIMATION_SCALE, scaling);
json_object *favoritesArray = json_object_new_array();
for (const uint64_t &applicationID : m_favorites)
for (const uint64_t applicationID : m_favorites)
{
const std::string appIDHex = stringutil::get_formatted_string(APP_ID_HEX_FORMAT, applicationID);
json_object *jsonFavorite = json_object_new_string(appIDHex.c_str());
@@ -237,7 +238,7 @@ void config::ConfigContext::save_config_file()
json::add_object(configJSON, config::keys::FAVORITES, favoritesArray);
json_object *blacklistArray = json_object_new_array();
for (const uint64_t &applicationID : m_blacklist)
for (const uint64_t applicationID : m_blacklist)
{
const std::string appIDHex = stringutil::get_formatted_string(APP_ID_HEX_FORMAT, applicationID);
json_object *jsonBlacklist = json_object_new_string(appIDHex.c_str());
@@ -280,8 +281,7 @@ void config::ConfigContext::load_custom_paths()
const uint64_t applicationID = std::strtoull(appIDString, nullptr, 16);
const char *path = json_object_get_string(pathObject);
m_paths[applicationID] = path;
m_paths.try_emplace(applicationID, path);
json_object_iter_next(&pathsIter);
}
@@ -292,7 +292,7 @@ void config::ConfigContext::save_custom_paths()
json::Object pathsJSON = json::new_object(json_object_new_object);
if (!pathsJSON) { return; }
for (auto &[applicationID, path] : m_paths)
for (const auto &[applicationID, path] : m_paths)
{
const std::string key = stringutil::get_formatted_string(APP_ID_HEX_FORMAT, applicationID);
json_object *pathObject = json_object_new_string(path.c_str());

View File

@@ -135,7 +135,7 @@ void fs::copy_file_commit(const fslib::Path &source,
}
const auto &[buffer, bufferSize] = queuePair;
const bool needsCommit = journalCount + bufferSize >= journalSize;
const bool needsCommit = journalCount + static_cast<int64_t>(bufferSize) >= journalSize;
if (needsCommit)
{
destFile.close();

View File

@@ -208,7 +208,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, in
auto &[buffer, bufferSize] = queuePair;
const bool commitNeeded = needCommits && journalCount + bufferSize >= journalSize;
const bool commitNeeded = needCommits && journalCount + static_cast<int64_t>(bufferSize) >= journalSize;
if (commitNeeded)
{
destFile.close();

View File

@@ -7,14 +7,31 @@
#include <ctime>
#include <string>
#include <switch.h>
#include <unordered_map>
namespace
{
// Size limit for formatted strings.
constexpr size_t VA_BUFFER_SIZE = 0x1000;
// These characters get replaced by spaces when path is sanitized.
constexpr std::array<uint32_t, 13> FORBIDDEN_PATH_CHARACTERS =
{L',', L'/', L'\\', L'<', L'>', L':', L'"', L'|', L'?', L'*', L'', L'©', L'®'};
/// @brief This is a table for replacing accented characters and "look alike" unicode characters.
// Note: extra outer braces required to initialize std::array of non-scalar elements (pairs)
constexpr std::array<std::pair<uint32_t, std::string_view>, 78> REPLACEMENT_TABLE{
{{L'Á', "A"}, {L'À', "A"}, {L'Â', "A"}, {L'Ä', "A"}, {L'Ã', "A"}, {L'Å', "A"}, {L'á', "a"}, {L'à', "a"},
{L'â', "a"}, {L'ä', "a"}, {L'ã', "a"}, {L'å', "a"}, {L'É', "E"}, {L'È', "E"}, {L'Ê', "E"}, {L'Ë', "E"},
{L'é', "e"}, {L'è', "e"}, {L'ê', "e"}, {L'ë', "e"}, {L'Í', "I"}, {L'Ì', "I"}, {L'Î', "I"}, {L'Ï', "I"},
{L'í', "i"}, {L'ì', "i"}, {L'î', "i"}, {L'ï', "i"}, {L'Ó', "O"}, {L'Ò', "O"}, {L'Ô', "O"}, {L'Ö', "O"},
{L'Õ', "O"}, {L'Ø', "O"}, {L'ó', "o"}, {L'ò', "o"}, {L'ô', "o"}, {L'ö', "o"}, {L'õ', "o"}, {L'ø', "o"},
{L'Ú', "U"}, {L'Ù', "U"}, {L'Û', "U"}, {L'Ü', "U"}, {L'ú', "u"}, {L'ù', "u"}, {L'û', "u"}, {L'ü', "u"},
{L'Ñ', "N"}, {L'ñ', "n"}, {L'Ç', "C"}, {L'ç', "c"}, {L'', "Ss"}, {L'ß', "ss"}, {L'Œ', "OE"}, {L'œ', "oe"},
{L'Æ', "AE"}, {L'æ', "ae"}, {L'', "-"}, {L'', "-"}, {L'', "-"}, {L'', "-"}, {L' ', " "}, {L'', " "},
{L'', " "}, {L'', "I"}, {L'', "II"}, {L'', "III"}, {L'', "IV"}, {L'', "V"}, {L'', "*"}, {L'×', "x"},
{L'', "'"}, {L'', "'"}, {L'', "'"}, {L'', ";"}, {L'ʼ', "'"}}};
} // namespace
std::string stringutil::get_formatted_string(const char *format, ...)
@@ -57,18 +74,9 @@ bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut,
{
const uint8_t *point = reinterpret_cast<const uint8_t *>(&stringIn[i]);
const ssize_t count = decode_utf8(&codepoint, point);
if (count <= 0 || i + count >= static_cast<int>(stringOutSize)) { return false; }
if (codepoint == L'é')
{
stringOut[outOffset++] = 'e';
i += count;
continue;
}
const bool asciiCheck = codepoint < 0x1E || codepoint >= 0x7E;
if (asciiCheck) { return false; }
if (count <= 0 || outOffset + count >= static_cast<int>(stringOutSize)) { return false; }
// If it's forbidden, skip.
const bool isForbidden = std::find(FORBIDDEN_PATH_CHARACTERS.begin(), FORBIDDEN_PATH_CHARACTERS.end(), codepoint) !=
FORBIDDEN_PATH_CHARACTERS.end();
if (isForbidden)
@@ -76,12 +84,30 @@ bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut,
i += count;
continue;
}
else
// Check for replacing.
const auto &replace = std::find_if(REPLACEMENT_TABLE.begin(),
REPLACEMENT_TABLE.end(),
[=](const auto &replacePair) { return replacePair.first == codepoint; });
if (replace != REPLACEMENT_TABLE.end())
{
std::memcpy(&stringOut[outOffset], &stringIn[i], static_cast<size_t>(count));
outOffset += count;
const auto &[tablePoint, replacement] = *replace;
const size_t replacementLength = replacement.length();
std::copy(replacement.data(), replacement.data() + replacementLength, &stringOut[outOffset]);
outOffset += replacementLength;
i += count;
continue;
}
// Final valid ASCII check.
const bool asciiCheck = codepoint < 0x20 || codepoint >= 0x7F;
if (asciiCheck) { return false; }
// Just copy it over.
std::copy(&stringIn[i], &stringIn[i] + count, &stringOut[outOffset]);
outOffset += count;
i += count;
}

View File

@@ -32,19 +32,16 @@ void tasks::backup::create_new_backup_local(sys::threadpool::JobData taskData)
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
const fslib::Path &target = castData->path;
BackupMenuState *spawningState = castData->spawningState;
const bool killTask = castData->killTask;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); }
const std::string targetString = target.string();
const bool hasZipExt = std::strstr(targetString.c_str(), STRING_ZIP_EXT);
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); }
if (hasZipExt) // At this point, this should have the zip extension appended if needed.
{
fs::MiniZip zip{target};
@@ -54,7 +51,8 @@ void tasks::backup::create_new_backup_local(sys::threadpool::JobData taskData)
auto scopedMount = create_scoped_mount(saveInfo);
fs::copy_directory_to_zip(fs::DEFAULT_SAVE_ROOT, zip, task);
}
else {
else
{
const bool needsDir = !fslib::directory_exists(target);
const bool createError = needsDir && error::fslib(fslib::create_directory(target));
if (needsDir && createError) { TASK_FINISH_RETURN(task); }
@@ -77,20 +75,19 @@ void tasks::backup::create_new_backup_remote(sys::threadpool::JobData taskData)
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
const fslib::Path &path = castData->path;
const std::string &remoteName = castData->remoteName;
BackupMenuState *spawningState = castData->spawningState;
const bool &killTask = castData->killTask;
const bool keepLocal = config::get_by_key(config::keys::KEEP_LOCAL_BACKUPS);
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(task)) { return; }
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(remote)) { 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); }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(remote) || error::is_null(saveInfo))
{
TASK_FINISH_RETURN(task);
}
const fslib::Path zipPath{keepLocal ? path : PATH_JKSV_TEMP};
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
@@ -132,14 +129,9 @@ void tasks::backup::overwrite_backup_local(sys::threadpool::JobData taskData)
{
auto castData = std::static_pointer_cast<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const fslib::Path &target = castData->path;
BackupMenuState *spawningState = castData->spawningState;
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
const fslib::Path &target = castData->path;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const bool isDirectory = fslib::directory_exists(target);
@@ -160,19 +152,13 @@ void tasks::backup::overwrite_backup_remote(sys::threadpool::JobData taskData)
{
auto castData = std::static_pointer_cast<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
const FsSaveDataInfo *saveInfo = castData->saveInfo;
remote::Item *target = castData->remoteItem;
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(task)) { return; }
remote::Item *target = castData->remoteItem;
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(remote) || error::is_null(target)) { 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); }
else if (error::is_null(remote) || error::is_null(target)) { TASK_FINISH_RETURN(task); }
const fslib::Path tempPath{PATH_JKSV_TEMP};
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
@@ -212,18 +198,18 @@ void tasks::backup::restore_backup_local(sys::threadpool::JobData taskData)
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
const fslib::Path &target = castData->path;
BackupMenuState *spawningState = castData->spawningState;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(titleInfo) || 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);
const uint8_t saveType = user->get_account_save_type();
if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(saveInfo) || error::is_null(spawningState))
{
TASK_FINISH_RETURN(task);
}
FsSaveDataExtraData extraData{};
const uint8_t saveType = saveInfo->save_data_type;
const bool readExtra = fs::read_save_extra_data(saveInfo, extraData);
const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType);
@@ -261,7 +247,8 @@ void tasks::backup::restore_backup_local(sys::threadpool::JobData taskData)
auto scopedMount = create_scoped_mount(saveInfo);
fs::copy_directory_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task);
}
else {
else
{
auto scopedMount = create_scoped_mount(saveInfo);
fs::copy_file_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task);
}
@@ -282,17 +269,16 @@ void tasks::backup::restore_backup_remote(sys::threadpool::JobData taskData)
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
BackupMenuState *spawningState = castData->spawningState;
remote::Storage *remote = remote::get_remote_storage();
const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE);
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE);
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); }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(saveInfo) || error::is_null(remote))
{
TASK_FINISH_RETURN(task);
}
if (autoBackup) { auto_backup(task, castData); }
@@ -371,8 +357,7 @@ void tasks::backup::delete_backup_local(sys::threadpool::JobData taskData)
BackupMenuState *spawningState = castData->spawningState;
if (error::is_null(task)) { return; }
if (error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
{
@@ -391,7 +376,8 @@ void tasks::backup::delete_backup_local(sys::threadpool::JobData taskData)
dirError = isDir && error::fslib(fslib::rename_directory(path, newPath));
fileError = !isDir && error::fslib(fslib::rename_file(path, newPath));
}
else {
else
{
dirError = isDir && error::fslib(fslib::delete_directory_recursively(path));
fileError = !isDir && error::fslib(fslib::delete_file(path));
}
@@ -416,8 +402,7 @@ void tasks::backup::delete_backup_remote(sys::threadpool::JobData taskData)
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(task)) { return; }
if (error::is_null(target) || error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(target) || error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
{
@@ -448,8 +433,7 @@ void tasks::backup::upload_backup(sys::threadpool::JobData taskData)
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(task)) { return; }
if (error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
{
const char *filename = path.get_filename();
@@ -474,8 +458,10 @@ void tasks::backup::patch_backup(sys::threadpool::JobData taskData)
BackupMenuState *spawningState = castData->spawningState;
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(task)) { return; }
if (error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(remoteItem) || error::is_null(spawningState) || error::is_null(remote))
{
TASK_FINISH_RETURN(task);
}
{
const char *filename = path.get_filename();
@@ -497,6 +483,7 @@ static void auto_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskD
data::TitleInfo *titleInfo = taskData->titleInfo;
fslib::Path &target = taskData->path;
BackupMenuState *spawningState = taskData->spawningState;
if (error::is_null(user) || error::is_null(titleInfo)) { return; }
const uint64_t applicationID = titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID);
@@ -530,7 +517,8 @@ static void auto_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskD
tasks::backup::create_new_backup_remote(tempData);
}
else {
else
{
// We're going to get the target dir from the path passed.
const size_t lastSlash = target.find_last_of('/');
if (lastSlash == target.NOT_FOUND) { return; }
@@ -545,15 +533,10 @@ static void auto_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskD
static bool read_and_process_meta(const fslib::Path &targetDir, BackupMenuState::TaskData taskData, sys::ProgressTask *task)
{
if (error::is_null(task)) { return false; }
data::User *user = taskData->user;
data::TitleInfo *titleInfo = taskData->titleInfo;
if (error::is_null(user) || error::is_null(titleInfo))
{
task->complete();
return false;
}
if (error::is_null(task)) { return false; }
else if (error::is_null(user) || error::is_null(titleInfo)) { return false; }
const uint64_t applicationID = titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID);
@@ -591,17 +574,10 @@ static bool read_and_process_meta(fs::MiniUnzip &unzip, BackupMenuState::TaskDat
{
if (error::is_null(task)) { return false; }
data::User *user = taskData->user;
data::TitleInfo *titleInfo = taskData->titleInfo;
if (error::is_null(user) || error::is_null(titleInfo))
{
task->complete();
return false;
}
const uint64_t applicationID = titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return false; }
data::User *user = taskData->user;
data::TitleInfo *titleInfo = taskData->titleInfo;
const FsSaveDataInfo *saveInfo = taskData->saveInfo;
if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(saveInfo)) { return false; }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
{

View File

@@ -70,7 +70,8 @@ void tasks::titleoptions::delete_all_local_backups_for_title(sys::threadpool::Jo
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 {
else
{
const char *title = titleInfo->get_title();
std::string popMessage = stringutil::get_formatted_string(popSuccess, title);
ui::PopMessageManager::push_message(popTicks, popMessage);
@@ -140,15 +141,12 @@ void tasks::titleoptions::reset_save_data(sys::threadpool::JobData taskData)
{
auto castData = std::static_pointer_cast<TitleOptionState::DataStruct>(taskData);
sys::Task *task = castData->task;
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
sys::Task *task = castData->task;
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
if (error::is_null(task)) { return; }
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); }
else if (error::is_null(user) || error::is_null(titleInfo) || 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);
@@ -166,9 +164,7 @@ void tasks::titleoptions::reset_save_data(sys::threadpool::JobData taskData)
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);
}
else { ui::PopMessageManager::push_message(popTicks, popSuccess); }
}
task->complete();
@@ -181,18 +177,16 @@ void tasks::titleoptions::delete_save_data_from_system(sys::threadpool::JobData
sys::Task *task = castData->task;
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
TitleSelectCommon *titleSelect = castData->titleSelect;
TitleOptionState *spawningState = castData->spawningState;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(titleSelect) || error::is_null(spawningState))
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(saveInfo) || 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);
@@ -210,6 +204,7 @@ void tasks::titleoptions::delete_save_data_from_system(sys::threadpool::JobData
return;
}
const uint64_t applicationID = titleInfo->get_application_id();
user->erase_save_info_by_id(applicationID);
titleSelect->refresh();
spawningState->close_on_update();
@@ -218,20 +213,15 @@ void tasks::titleoptions::delete_save_data_from_system(sys::threadpool::JobData
void tasks::titleoptions::extend_save_data(sys::threadpool::JobData taskData)
{
static constexpr int SIZE_MB = 0x100000;
auto castData = std::static_pointer_cast<TitleOptionState::DataStruct>(taskData);
sys::Task *task = castData->task;
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); }
static constexpr int SIZE_MB = 0x100000;
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); }
auto castData = std::static_pointer_cast<TitleOptionState::DataStruct>(taskData);
sys::Task *task = castData->task;
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
const FsSaveDataInfo *saveInfo = castData->saveInfo;
if (error::is_null(task)) { return; }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); }
std::array<char, 5> sizeBuffer = {0};
FsSaveDataExtraData extraData{};
@@ -262,9 +252,11 @@ void tasks::titleoptions::extend_save_data(sys::threadpool::JobData taskData)
const char *popSuccess = strings::get_by_name(strings::names::TITLEOPTION_POPS, 10);
ui::PopMessageManager::push_message(popTicks, popSuccess);
}
else {
else
{
const char *popFailed = strings::get_by_name(strings::names::TITLEOPTION_POPS, 11);
ui::PopMessageManager::push_message(popTicks, popFailed);
}
task->complete();
}

View File

@@ -17,7 +17,7 @@ void tasks::useroptions::backup_all_for_user_local(sys::threadpool::JobData task
data::User *user = castData->user;
if (error::is_null(task)) { return; }
if (error::is_null(user)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(user)) { TASK_FINISH_RETURN(task); }
auto backupStruct = std::make_shared<BackupMenuState::DataStruct>();
backupStruct->task = task;
@@ -71,7 +71,7 @@ void tasks::useroptions::backup_all_for_user_remote(sys::threadpool::JobData tas
data::User *user = castData->user;
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(user) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
auto backupStruct = std::make_shared<BackupMenuState::DataStruct>();
backupStruct->task = task;
@@ -120,7 +120,7 @@ void tasks::useroptions::create_all_save_data_for_user(sys::threadpool::JobData
data::User *user = castData->user;
UserOptionState *spawningState = castData->spawningState;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
else if (error::is_null(user) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
data::TitleInfoList infoList{};
data::get_title_info_list(infoList);
@@ -160,7 +160,7 @@ void tasks::useroptions::delete_all_save_data_for_user(sys::threadpool::JobData
data::User *user = castData->user;
UserOptionState *spawningState = castData->spawningState;
if (error::is_null(task)) { return; }
if (error::is_null(user) || error::is_null(spawningState) || user->get_account_save_type() == FsSaveDataType_System)
else if (error::is_null(user) || error::is_null(spawningState) || user->get_account_save_type() == FsSaveDataType_System)
{
TASK_FINISH_RETURN(task);
}
@@ -193,7 +193,7 @@ void tasks::useroptions::delete_all_save_data_for_user(sys::threadpool::JobData
applicationIDs.push_back(applicationID);
}
for (const uint64_t &applicationID : applicationIDs) { user->erase_save_info_by_id(applicationID); }
for (const uint64_t applicationID : applicationIDs) { user->erase_save_info_by_id(applicationID); }
spawningState->refresh_required();
task->complete();
}