Merge pull request #10862 from jdgleaver/core-auto-backup

Add option to automatically backup cores when updating
This commit is contained in:
Autechre 2020-06-16 22:20:37 +02:00 committed by GitHub
commit 43a65ec65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 580 additions and 159 deletions

View File

@ -965,6 +965,14 @@ static const uint16_t network_remote_base_port = 55400;
#define DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE true #define DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE true
#define DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES false #define DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES false
/* Automatically create a backup whenever a core is
* updated via the online updater */
#define DEFAULT_CORE_UPDATER_AUTO_BACKUP false
/* Number of automatic core backups to retain
* (oldest backup will be deleted when creating
* a new one) */
#define DEFAULT_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE 1
#if defined(ANDROID) || defined(IOS) #if defined(ANDROID) || defined(IOS)
#define DEFAULT_NETWORK_ON_DEMAND_THUMBNAILS true #define DEFAULT_NETWORK_ON_DEMAND_THUMBNAILS true
#else #else

View File

@ -1438,6 +1438,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("video_font_enable", &settings->bools.video_font_enable, true, DEFAULT_FONT_ENABLE, false); SETTING_BOOL("video_font_enable", &settings->bools.video_font_enable, true, DEFAULT_FONT_ENABLE, false);
SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE, false); SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE, false);
SETTING_BOOL("core_updater_show_experimental_cores", &settings->bools.network_buildbot_show_experimental_cores, true, DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES, false); SETTING_BOOL("core_updater_show_experimental_cores", &settings->bools.network_buildbot_show_experimental_cores, true, DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES, false);
SETTING_BOOL("core_updater_auto_backup", &settings->bools.core_updater_auto_backup, true, DEFAULT_CORE_UPDATER_AUTO_BACKUP, false);
SETTING_BOOL("camera_allow", &settings->bools.camera_allow, true, false, false); SETTING_BOOL("camera_allow", &settings->bools.camera_allow, true, false, false);
SETTING_BOOL("discord_allow", &settings->bools.discord_enable, true, false, false); SETTING_BOOL("discord_allow", &settings->bools.discord_enable, true, false, false);
#if defined(VITA) #if defined(VITA)
@ -1914,6 +1915,8 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("playlist_sublabel_last_played_style", &settings->uints.playlist_sublabel_last_played_style, true, DEFAULT_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, false); SETTING_UINT("playlist_sublabel_last_played_style", &settings->uints.playlist_sublabel_last_played_style, true, DEFAULT_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, false);
#endif #endif
SETTING_UINT("core_updater_auto_backup_history_size", &settings->uints.core_updater_auto_backup_history_size, true, DEFAULT_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, false);
*size = count; *size = count;
return tmp; return tmp;

View File

@ -286,6 +286,7 @@ typedef struct settings
bool network_buildbot_auto_extract_archive; bool network_buildbot_auto_extract_archive;
bool network_buildbot_show_experimental_cores; bool network_buildbot_show_experimental_cores;
bool network_on_demand_thumbnails; bool network_on_demand_thumbnails;
bool core_updater_auto_backup;
/* UI */ /* UI */
bool ui_menubar_enable; bool ui_menubar_enable;
@ -621,6 +622,8 @@ typedef struct settings
unsigned ai_service_mode; unsigned ai_service_mode;
unsigned ai_service_target_lang; unsigned ai_service_target_lang;
unsigned ai_service_source_lang; unsigned ai_service_source_lang;
unsigned core_updater_auto_backup_history_size;
} uints; } uints;
struct struct

View File

@ -27,7 +27,6 @@
#include "frontend/frontend_driver.h" #include "frontend/frontend_driver.h"
#include "file_path_special.h" #include "file_path_special.h"
#include "core_info.h"
#include "verbosity.h" #include "verbosity.h"
#include "core_backup.h" #include "core_backup.h"
@ -532,7 +531,8 @@ core_backup_list_t *core_backup_list_init(
if (dir_list->size < 1) if (dir_list->size < 1)
goto error; goto error;
/* Ensure list is sorted in alphabetical order */ /* Ensure list is sorted in alphabetical order
* > This corresponds to 'timestamp' order */
dir_list_sort(dir_list, true); dir_list_sort(dir_list, true);
/* Create core backup list */ /* Create core backup list */
@ -622,6 +622,30 @@ size_t core_backup_list_size(core_backup_list_t *backup_list)
return backup_list->size; return backup_list->size;
} }
/* Returns number of entries of specified 'backup mode'
* (manual or automatic) in core backup list */
size_t core_backup_list_get_num_backups(
core_backup_list_t *backup_list,
enum core_backup_mode backup_mode)
{
size_t i;
size_t num_backups = 0;
if (!backup_list || !backup_list->entries)
return 0;
for (i = 0; i < backup_list->size; i++)
{
core_backup_list_entry_t *current_entry = &backup_list->entries[i];
if (current_entry &&
(current_entry->backup_mode == backup_mode))
num_backups++;
}
return num_backups;
}
/* Fetches core backup list entry corresponding /* Fetches core backup list entry corresponding
* to the specified entry index. * to the specified entry index.
* Returns false if index is invalid. */ * Returns false if index is invalid. */

View File

@ -132,6 +132,12 @@ void core_backup_list_free(core_backup_list_t *backup_list);
/* Returns number of entries in core backup list */ /* Returns number of entries in core backup list */
size_t core_backup_list_size(core_backup_list_t *backup_list); size_t core_backup_list_size(core_backup_list_t *backup_list);
/* Returns number of entries of specified 'backup mode'
* (manual or automatic) in core backup list */
size_t core_backup_list_get_num_backups(
core_backup_list_t *backup_list,
enum core_backup_mode backup_mode);
/* Fetches core backup list entry corresponding /* Fetches core backup list entry corresponding
* to the specified entry index. * to the specified entry index.
* Returns false if index is invalid. */ * Returns false if index is invalid. */

View File

@ -516,6 +516,14 @@ MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
"core_updater_show_experimental_cores" "core_updater_show_experimental_cores"
) )
MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP,
"core_updater_auto_backup"
)
MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE,
"core_updater_auto_backup_history_size"
)
MSG_HASH( MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL, MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL,
"core_updater_buildbot_url" "core_updater_buildbot_url"

View File

@ -481,6 +481,10 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_DELETE_BACKUP_LIST, MENU_ENUM_SUBLABEL_CORE_DELETE_BACKUP_LIST,
"Remove a file from the list of archived backups." "Remove a file from the list of archived backups."
) )
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_BACKUP_MODE_AUTO,
"[Auto]"
)
MSG_HASH( MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_BACKUP_CRC, MENU_ENUM_LABEL_VALUE_CORE_BACKUP_CRC,
"CRC32: " "CRC32: "
@ -4598,6 +4602,22 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
"Include 'experimental' cores in the Core Downloader list. These are typically for development/testing purposes only, and are not recommended for general use." "Include 'experimental' cores in the Core Downloader list. These are typically for development/testing purposes only, and are not recommended for general use."
) )
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP,
"Backup Cores When Updating"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_BACKUP,
"Automatically create a backup of any installed cores when performing an online update. Enables easy rollback to a working core if an update introduces a regression."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE,
"Core Backup History Size"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE,
"Specifies how many automatically generated backups to keep for each installed core. When this limit is reached, creating a new backup via an online update will delete the oldest backup. Note: Manual core backups are unaffected by this setting."
)
/* Settings > Playlists */ /* Settings > Playlists */
@ -10862,6 +10882,10 @@ MSG_HASH(
MSG_BACKING_UP_CORE, MSG_BACKING_UP_CORE,
"Backing up core: " "Backing up core: "
) )
MSG_HASH(
MSG_PRUNING_CORE_BACKUP_HISTORY,
"Removing obsolete backups: "
)
MSG_HASH( MSG_HASH(
MSG_CORE_BACKUP_COMPLETE, MSG_CORE_BACKUP_COMPLETE,
"Core backup complete: " "Core backup complete: "

View File

@ -4338,16 +4338,20 @@ static int action_ok_core_updater_download(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx) const char *label, unsigned type, size_t idx, size_t entry_idx)
{ {
#ifdef HAVE_NETWORKING #ifdef HAVE_NETWORKING
core_updater_list_t *core_list = core_updater_list_get_cached(); core_updater_list_t *core_list = core_updater_list_get_cached();
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
const char *path_dir_libretro = settings->paths.directory_libretro; bool auto_backup = settings->bools.core_updater_auto_backup;
unsigned auto_backup_history_size = settings->uints.core_updater_auto_backup_history_size;
const char *path_dir_libretro = settings->paths.directory_libretro;
const char *path_dir_core_assets = settings->paths.directory_core_assets;
if (!core_list) if (!core_list)
return menu_cbs_exit(); return menu_cbs_exit();
task_push_core_updater_download( task_push_core_updater_download(
core_list, path, false, true, core_list, path, 0, false,
path_dir_libretro); auto_backup, (size_t)auto_backup_history_size,
path_dir_libretro, path_dir_core_assets);
#endif #endif
return 0; return 0;
@ -4357,14 +4361,19 @@ static int action_ok_core_updater_download(const char *path,
static int action_ok_update_installed_cores(const char *path, static int action_ok_update_installed_cores(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx) const char *label, unsigned type, size_t idx, size_t entry_idx)
{ {
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
const char *path_dir_libretro = settings->paths.directory_libretro; bool auto_backup = settings->bools.core_updater_auto_backup;
unsigned auto_backup_history_size = settings->uints.core_updater_auto_backup_history_size;
const char *path_dir_libretro = settings->paths.directory_libretro;
const char *path_dir_core_assets = settings->paths.directory_core_assets;
/* Ensure networking is initialised */ /* Ensure networking is initialised */
generic_action_ok_command(CMD_EVENT_NETWORK_INIT); generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
/* Push update task */ /* Push update task */
task_push_update_installed_cores(path_dir_libretro); task_push_update_installed_cores(
auto_backup, auto_backup_history_size,
path_dir_libretro, path_dir_core_assets);
return 0; return 0;
} }
@ -6253,15 +6262,16 @@ static int action_ok_netplay_disconnect(const char *path,
static int action_ok_core_create_backup(const char *path, static int action_ok_core_create_backup(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx) const char *label, unsigned type, size_t idx, size_t entry_idx)
{ {
const char *core_path = label; const char *core_path = label;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
const char *dir_core_assets = settings->paths.directory_core_assets; unsigned auto_backup_history_size = settings->uints.core_updater_auto_backup_history_size;
const char *dir_core_assets = settings->paths.directory_core_assets;
if (string_is_empty(core_path)) if (string_is_empty(core_path))
return -1; return -1;
task_push_core_backup(core_path, 0, CORE_BACKUP_MODE_MANUAL, task_push_core_backup(core_path, NULL, 0, CORE_BACKUP_MODE_MANUAL,
dir_core_assets, false); (size_t)auto_backup_history_size, dir_core_assets, false);
return 0; return 0;
} }

View File

@ -525,6 +525,8 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_show_physical_inputs_p
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_buildbot_assets_url, MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_buildbot_assets_url, MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_auto_extract_archive, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_auto_extract_archive, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_show_experimental_cores, MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_show_experimental_cores, MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_auto_backup, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_BACKUP)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_updater_auto_backup_history_size, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_refresh_rooms, MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_refresh_rooms, MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_rename_entry, MENU_ENUM_SUBLABEL_RENAME_ENTRY) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_rename_entry, MENU_ENUM_SUBLABEL_RENAME_ENTRY)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_delete_entry, MENU_ENUM_SUBLABEL_DELETE_ENTRY) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_delete_entry, MENU_ENUM_SUBLABEL_DELETE_ENTRY)
@ -2375,6 +2377,12 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES: case MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_show_experimental_cores); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_show_experimental_cores);
break; break;
case MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_auto_backup);
break;
case MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_auto_backup_history_size);
break;
case MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL: case MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_url); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_url);
break; break;

View File

@ -453,7 +453,7 @@ static unsigned menu_displaylist_parse_core_backup_list(
if (core_backup_list_get_index(backup_list, i, &entry) && if (core_backup_list_get_index(backup_list, i, &entry) &&
entry && !string_is_empty(entry->backup_path)) entry && !string_is_empty(entry->backup_path))
{ {
char timestamp[32]; char timestamp[128];
char crc[16]; char crc[16];
timestamp[0] = '\0'; timestamp[0] = '\0';
@ -465,6 +465,14 @@ static unsigned menu_displaylist_parse_core_backup_list(
core_backup_list_get_entry_crc_str( core_backup_list_get_entry_crc_str(
entry, crc, sizeof(crc)); entry, crc, sizeof(crc));
/* Append 'auto backup' tag to timestamp, if required */
if (entry->backup_mode == CORE_BACKUP_MODE_AUTO)
{
strlcat(timestamp, " ", sizeof(timestamp));
strlcat(timestamp, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_BACKUP_MODE_AUTO),
sizeof(timestamp));
}
/* Add menu entry */ /* Add menu entry */
if (menu_entries_append_enum(info->list, if (menu_entries_append_enum(info->list,
timestamp, timestamp,
@ -7323,6 +7331,8 @@ unsigned menu_displaylist_build_list(
{MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, PARSE_ONLY_STRING}, {MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, PARSE_ONLY_UINT},
}; };
for (i = 0; i < ARRAY_SIZE(build_list); i++) for (i = 0; i < ARRAY_SIZE(build_list); i++)

View File

@ -16162,6 +16162,38 @@ static bool setting_append_list(
general_read_handler, general_read_handler,
SD_FLAG_NONE SD_FLAG_NONE
); );
CONFIG_BOOL(
list, list_info,
&settings->bools.core_updater_auto_backup,
MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP,
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP,
DEFAULT_CORE_UPDATER_AUTO_BACKUP,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE
);
CONFIG_UINT(
list, list_info,
&settings->uints.core_updater_auto_backup_history_size,
MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE,
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE,
DEFAULT_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
(*list)[list_info->index - 1].offset_by = 1;
menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, 500, 1, true, true);
#endif #endif
END_SUB_GROUP(list, list_info, parent_group); END_SUB_GROUP(list, list_info, parent_group);
END_GROUP(list, list_info, parent_group); END_GROUP(list, list_info, parent_group);

View File

@ -1955,6 +1955,8 @@ enum msg_hash_enums
MENU_LABEL(CORE_MANAGER_LIST), MENU_LABEL(CORE_MANAGER_LIST),
MENU_LABEL(CORE_UPDATER_AUTO_EXTRACT_ARCHIVE), MENU_LABEL(CORE_UPDATER_AUTO_EXTRACT_ARCHIVE),
MENU_LABEL(CORE_UPDATER_SHOW_EXPERIMENTAL_CORES), MENU_LABEL(CORE_UPDATER_SHOW_EXPERIMENTAL_CORES),
MENU_LABEL(CORE_UPDATER_AUTO_BACKUP),
MENU_LABEL(CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE),
MENU_LABEL(CORE_UPDATER_BUILDBOT_URL), MENU_LABEL(CORE_UPDATER_BUILDBOT_URL),
MENU_LABEL(BUILDBOT_ASSETS_URL), MENU_LABEL(BUILDBOT_ASSETS_URL),
MENU_LABEL(CORE_SET_SUPPORTS_NO_CONTENT_ENABLE), MENU_LABEL(CORE_SET_SUPPORTS_NO_CONTENT_ENABLE),
@ -2014,11 +2016,13 @@ enum msg_hash_enums
MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_ENTRY, MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_ENTRY,
MENU_ENUM_LABEL_CORE_DELETE_BACKUP_ENTRY, MENU_ENUM_LABEL_CORE_DELETE_BACKUP_ENTRY,
MENU_ENUM_LABEL_VALUE_CORE_BACKUP_MODE_AUTO,
MENU_ENUM_LABEL_VALUE_CORE_BACKUP_CRC, MENU_ENUM_LABEL_VALUE_CORE_BACKUP_CRC,
MSG_CORE_BACKUP_SCANNING_CORE, MSG_CORE_BACKUP_SCANNING_CORE,
MSG_CORE_BACKUP_ALREADY_EXISTS, MSG_CORE_BACKUP_ALREADY_EXISTS,
MSG_BACKING_UP_CORE, MSG_BACKING_UP_CORE,
MSG_PRUNING_CORE_BACKUP_HISTORY,
MSG_CORE_BACKUP_COMPLETE, MSG_CORE_BACKUP_COMPLETE,
MSG_CORE_RESTORATION_ALREADY_INSTALLED, MSG_CORE_RESTORATION_ALREADY_INSTALLED,
MSG_RESTORING_CORE, MSG_RESTORING_CORE,

View File

@ -44,6 +44,8 @@ enum core_backup_status
CORE_BACKUP_CHECK_CRC, CORE_BACKUP_CHECK_CRC,
CORE_BACKUP_PRE_ITERATE, CORE_BACKUP_PRE_ITERATE,
CORE_BACKUP_ITERATE, CORE_BACKUP_ITERATE,
CORE_BACKUP_CHECK_HISTORY,
CORE_BACKUP_PRUNE_HISTORY,
CORE_BACKUP_END, CORE_BACKUP_END,
CORE_RESTORE_GET_CORE_CRC, CORE_RESTORE_GET_CORE_CRC,
CORE_RESTORE_GET_BACKUP_CRC, CORE_RESTORE_GET_BACKUP_CRC,
@ -61,6 +63,9 @@ typedef struct core_backup_handle
char *backup_path; char *backup_path;
enum core_backup_type backup_type; enum core_backup_type backup_type;
enum core_backup_mode backup_mode; enum core_backup_mode backup_mode;
size_t auto_backup_history_size;
size_t num_auto_backups_to_remove;
size_t backup_index;
int64_t core_file_size; int64_t core_file_size;
int64_t backup_file_size; int64_t backup_file_size;
int64_t file_data_read; int64_t file_data_read;
@ -348,7 +353,13 @@ static void task_core_backup_handler(retro_task_t *task)
backup_handle->backup_file = NULL; backup_handle->backup_file = NULL;
backup_handle->success = true; backup_handle->success = true;
backup_handle->status = CORE_BACKUP_END;
/* If this is an automatic backup, check whether
* any old backup files should be deleted.
* In all other cases, backup is complete */
backup_handle->status = (backup_handle->backup_mode ==
CORE_BACKUP_MODE_AUTO) ?
CORE_BACKUP_CHECK_HISTORY : CORE_BACKUP_END;
break; break;
} }
@ -368,6 +379,103 @@ static void task_core_backup_handler(retro_task_t *task)
(backup_handle->file_data_read * 100) / backup_handle->core_file_size); (backup_handle->file_data_read * 100) / backup_handle->core_file_size);
} }
break; break;
case CORE_BACKUP_CHECK_HISTORY:
{
size_t num_backups;
/* Sanity check: We can only reach this stage
* when performing automatic backups, but verify
* that this is true (i.e. don't inadvertently
* delete backups of the wrong type if someone
* edits the CORE_BACKUP_ITERATE case statement...) */
if (backup_handle->backup_mode != CORE_BACKUP_MODE_AUTO)
{
backup_handle->status = CORE_BACKUP_END;
break;
}
/* This is an automated backup
* > Fetch number of existing auto backups
* in the list
* > If we reach this stage then a new backup
* has been created successfully -> increment
* count by one */
num_backups = core_backup_list_get_num_backups(
backup_handle->backup_list,
CORE_BACKUP_MODE_AUTO);
num_backups++;
/* Check whether we have exceeded the backup
* history size limit */
if (num_backups > backup_handle->auto_backup_history_size)
{
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* Get number of old backups to remove */
backup_handle->num_auto_backups_to_remove = num_backups -
backup_handle->auto_backup_history_size;
/* Update task title */
task_free_title(task);
strlcpy(task_title, msg_hash_to_str(MSG_PRUNING_CORE_BACKUP_HISTORY),
sizeof(task_title));
strlcat(task_title, backup_handle->core_name, sizeof(task_title));
task_set_title(task, strdup(task_title));
/* Go to history clean-up phase */
backup_handle->status = CORE_BACKUP_PRUNE_HISTORY;
}
/* No backups to remove - task is complete */
else
backup_handle->status = CORE_BACKUP_END;
}
break;
case CORE_BACKUP_PRUNE_HISTORY:
{
size_t list_size = core_backup_list_size(backup_handle->backup_list);
/* The core backup list is automatically sorted
* by timestamp - simply loop from start to end
* and delete automatic backups until the required
* number have been removed */
while ((backup_handle->backup_index < list_size) &&
(backup_handle->num_auto_backups_to_remove > 0))
{
const core_backup_list_entry_t *entry = NULL;
if (core_backup_list_get_index(
backup_handle->backup_list,
backup_handle->backup_index,
&entry) &&
entry &&
(entry->backup_mode == CORE_BACKUP_MODE_AUTO))
{
/* Delete backup file (if it exists) */
if (path_is_valid(entry->backup_path))
filestream_delete(entry->backup_path);
backup_handle->num_auto_backups_to_remove--;
backup_handle->backup_index++;
/* Break here - only remove one file per
* iteration of the task */
break;
}
backup_handle->backup_index++;
}
/* Check whether all old backups have been
* removed (also handle error conditions by
* ensuring we quit if end of backup list is
* reached...) */
if ((backup_handle->num_auto_backups_to_remove < 1) ||
(backup_handle->backup_index >= list_size))
backup_handle->status = CORE_BACKUP_END;
}
break;
case CORE_BACKUP_END: case CORE_BACKUP_END:
{ {
char task_title[PATH_MAX_LENGTH]; char task_title[PATH_MAX_LENGTH];
@ -409,14 +517,20 @@ task_finished:
free_core_backup_handle(backup_handle); free_core_backup_handle(backup_handle);
} }
/* Note: If crc is set to 0, crc of core_path file will /* Note 1: If crc is set to 0, crc of core_path file will
* be calculated automatically */ * be calculated automatically
void *task_push_core_backup(const char *core_path, * Note 2: If core_display_name is set to NULL, display
* name will be determined automatically
* > core_display_name *must* be set to a non-empty
* string if task_push_core_backup() is *not* called
* on the main thread */
void *task_push_core_backup(
const char *core_path, const char *core_display_name,
uint32_t crc, enum core_backup_mode backup_mode, uint32_t crc, enum core_backup_mode backup_mode,
size_t auto_backup_history_size,
const char *dir_core_assets, bool mute) const char *dir_core_assets, bool mute)
{ {
task_finder_data_t find_data; task_finder_data_t find_data;
core_info_ctx_find_t core_info;
const char *core_name = NULL; const char *core_name = NULL;
retro_task_t *task = NULL; retro_task_t *task = NULL;
core_backup_handle_t *backup_handle = NULL; core_backup_handle_t *backup_handle = NULL;
@ -438,20 +552,27 @@ void *task_push_core_backup(const char *core_path,
goto error; goto error;
/* Get core name */ /* Get core name */
core_info.inf = NULL; if (!string_is_empty(core_display_name))
core_info.path = core_path; core_name = core_display_name;
/* If core is found, use display name */
if (core_info_find(&core_info) &&
core_info.inf->display_name)
core_name = core_info.inf->display_name;
else else
{ {
/* If not, use core file name */ core_info_ctx_find_t core_info;
core_name = path_basename(core_path);
if (string_is_empty(core_name)) core_info.inf = NULL;
goto error; core_info.path = core_path;
/* If core is found, use display name */
if (core_info_find(&core_info) &&
core_info.inf->display_name)
core_name = core_info.inf->display_name;
else
{
/* If not, use core file name */
core_name = path_basename(core_path);
if (string_is_empty(core_name))
goto error;
}
} }
/* Configure handle */ /* Configure handle */
@ -460,23 +581,26 @@ void *task_push_core_backup(const char *core_path,
if (!backup_handle) if (!backup_handle)
goto error; goto error;
backup_handle->dir_core_assets = string_is_empty(dir_core_assets) ? NULL : strdup(dir_core_assets); backup_handle->dir_core_assets = string_is_empty(dir_core_assets) ? NULL : strdup(dir_core_assets);
backup_handle->core_path = strdup(core_path); backup_handle->core_path = strdup(core_path);
backup_handle->core_name = strdup(core_name); backup_handle->core_name = strdup(core_name);
backup_handle->backup_path = NULL; backup_handle->backup_path = NULL;
backup_handle->backup_type = CORE_BACKUP_TYPE_ARCHIVE; backup_handle->backup_type = CORE_BACKUP_TYPE_ARCHIVE;
backup_handle->backup_mode = backup_mode; backup_handle->backup_mode = backup_mode;
backup_handle->core_file_size = 0; backup_handle->auto_backup_history_size = auto_backup_history_size;
backup_handle->backup_file_size = 0; backup_handle->num_auto_backups_to_remove = 0;
backup_handle->file_data_read = 0; backup_handle->backup_index = 0;
backup_handle->core_crc = crc; backup_handle->core_file_size = 0;
backup_handle->backup_crc = 0; backup_handle->backup_file_size = 0;
backup_handle->crc_match = false; backup_handle->file_data_read = 0;
backup_handle->success = false; backup_handle->core_crc = crc;
backup_handle->core_file = NULL; backup_handle->backup_crc = 0;
backup_handle->backup_file = NULL; backup_handle->crc_match = false;
backup_handle->backup_list = NULL; backup_handle->success = false;
backup_handle->status = CORE_BACKUP_BEGIN; backup_handle->core_file = NULL;
backup_handle->backup_file = NULL;
backup_handle->backup_list = NULL;
backup_handle->status = CORE_BACKUP_BEGIN;
/* Create task */ /* Create task */
task = task_init(); task = task_init();
@ -899,23 +1023,26 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
if (!backup_handle) if (!backup_handle)
goto error; goto error;
backup_handle->dir_core_assets = NULL; backup_handle->dir_core_assets = NULL;
backup_handle->core_path = strdup(core_path); backup_handle->core_path = strdup(core_path);
backup_handle->core_name = strdup(core_name); backup_handle->core_name = strdup(core_name);
backup_handle->backup_path = strdup(backup_path); backup_handle->backup_path = strdup(backup_path);
backup_handle->backup_type = backup_type; backup_handle->backup_type = backup_type;
backup_handle->backup_mode = CORE_BACKUP_MODE_MANUAL; backup_handle->backup_mode = CORE_BACKUP_MODE_MANUAL;
backup_handle->core_file_size = 0; backup_handle->auto_backup_history_size = 0;
backup_handle->backup_file_size = 0; backup_handle->num_auto_backups_to_remove = 0;
backup_handle->file_data_read = 0; backup_handle->backup_index = 0;
backup_handle->core_crc = 0; backup_handle->core_file_size = 0;
backup_handle->backup_crc = 0; backup_handle->backup_file_size = 0;
backup_handle->crc_match = false; backup_handle->file_data_read = 0;
backup_handle->success = false; backup_handle->core_crc = 0;
backup_handle->core_file = NULL; backup_handle->backup_crc = 0;
backup_handle->backup_file = NULL; backup_handle->crc_match = false;
backup_handle->backup_list = NULL; backup_handle->success = false;
backup_handle->status = CORE_RESTORE_GET_CORE_CRC; backup_handle->core_file = NULL;
backup_handle->backup_file = NULL;
backup_handle->backup_list = NULL;
backup_handle->status = CORE_RESTORE_GET_CORE_CRC;
/* Create task */ /* Create task */
task = task_init(); task = task_init();

View File

@ -66,6 +66,9 @@ typedef struct core_updater_list_handle
enum core_updater_download_status enum core_updater_download_status
{ {
CORE_UPDATER_DOWNLOAD_BEGIN = 0, CORE_UPDATER_DOWNLOAD_BEGIN = 0,
CORE_UPDATER_DOWNLOAD_START_BACKUP,
CORE_UPDATER_DOWNLOAD_WAIT_BACKUP,
CORE_UPDATER_DOWNLOAD_START_TRANSFER,
CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER, CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER,
CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS, CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS,
CORE_UPDATER_DOWNLOAD_END CORE_UPDATER_DOWNLOAD_END
@ -73,14 +76,17 @@ enum core_updater_download_status
typedef struct core_updater_download_handle typedef struct core_updater_download_handle
{ {
bool auto_backup;
size_t auto_backup_history_size;
char *path_dir_libretro; char *path_dir_libretro;
char *path_dir_core_assets;
char *remote_filename; char *remote_filename;
char *remote_core_path; char *remote_core_path;
char *local_download_path; char *local_download_path;
char *local_core_path; char *local_core_path;
char *display_name; char *display_name;
uint32_t local_crc;
uint32_t remote_crc; uint32_t remote_crc;
bool check_crc;
bool crc_match; bool crc_match;
retro_task_t *http_task; retro_task_t *http_task;
bool http_task_finished; bool http_task_finished;
@ -88,6 +94,8 @@ typedef struct core_updater_download_handle
retro_task_t *decompress_task; retro_task_t *decompress_task;
bool decompress_task_finished; bool decompress_task_finished;
bool decompress_task_complete; bool decompress_task_complete;
bool backup_enabled;
retro_task_t *backup_task;
enum core_updater_download_status status; enum core_updater_download_status status;
} core_updater_download_handle_t; } core_updater_download_handle_t;
@ -104,7 +112,10 @@ enum update_installed_cores_status
typedef struct update_installed_cores_handle typedef struct update_installed_cores_handle
{ {
bool auto_backup;
size_t auto_backup_history_size;
char *path_dir_libretro; char *path_dir_libretro;
char *path_dir_core_assets;
core_updater_list_t* core_list; core_updater_list_t* core_list;
retro_task_t *list_task; retro_task_t *list_task;
retro_task_t *download_task; retro_task_t *download_task;
@ -119,40 +130,37 @@ typedef struct update_installed_cores_handle
/* Utility functions */ /* Utility functions */
/*********************/ /*********************/
/* Returns true if local core has the same crc /* Returns CRC32 of specified core file */
* value as core on buildbot */ static uint32_t task_core_updater_get_core_crc(const char *core_path)
static bool local_core_matches_remote_crc(
const char *local_core_path, uint32_t remote_crc)
{ {
/* Sanity check */ if (string_is_empty(core_path))
if (string_is_empty(local_core_path) || (remote_crc == 0)) return 0;
return false;
if (path_is_valid(local_core_path)) if (path_is_valid(core_path))
{ {
/* Open core file */ /* Open core file */
intfstream_t *local_core_file = intfstream_open_file( intfstream_t *core_file = intfstream_open_file(
local_core_path, RETRO_VFS_FILE_ACCESS_READ, core_path, RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE); RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (local_core_file) if (core_file)
{ {
uint32_t crc = 0; uint32_t crc = 0;
/* Get crc value */ /* Get crc value */
bool success = intfstream_get_crc(local_core_file, &crc); bool success = intfstream_get_crc(core_file, &crc);
/* Close core file */ /* Close core file */
intfstream_close(local_core_file); intfstream_close(core_file);
free(local_core_file); free(core_file);
local_core_file = NULL; core_file = NULL;
/* Check whether crc matches remote file */ if (success)
if (success && (crc != 0) && (crc == remote_crc)) return crc;
return true;
} }
} }
return false; return 0;
} }
/*************************/ /*************************/
@ -184,7 +192,7 @@ finish:
/* Log any error messages */ /* Log any error messages */
if (!success) if (!success)
RARCH_ERR("Download of core list '%s' failed: %s\n", RARCH_ERR("[core updater] Download of core list '%s' failed: %s\n",
(transf ? transf->path: "unknown"), (transf ? transf->path: "unknown"),
(err ? err : "unknown")); (err ? err : "unknown"));
@ -482,7 +490,7 @@ static void cb_decompress_task_core_updater_download(
/* Log any error messages */ /* Log any error messages */
if (!string_is_empty(err)) if (!string_is_empty(err))
RARCH_ERR("%s", err); RARCH_ERR("[core updater] %s", err);
} }
void cb_http_task_core_updater_download( void cb_http_task_core_updater_download(
@ -576,7 +584,7 @@ finish:
/* Log any error messages */ /* Log any error messages */
if (!string_is_empty(err)) if (!string_is_empty(err))
RARCH_ERR("Download of '%s' failed: %s\n", RARCH_ERR("[core updater] Download of '%s' failed: %s\n",
(transf ? transf->path: "unknown"), err); (transf ? transf->path: "unknown"), err);
if (data) if (data)
@ -598,6 +606,9 @@ static void free_core_updater_download_handle(core_updater_download_handle_t *do
if (download_handle->path_dir_libretro) if (download_handle->path_dir_libretro)
free(download_handle->path_dir_libretro); free(download_handle->path_dir_libretro);
if (download_handle->path_dir_core_assets)
free(download_handle->path_dir_core_assets);
if (download_handle->remote_filename) if (download_handle->remote_filename)
free(download_handle->remote_filename); free(download_handle->remote_filename);
@ -636,13 +647,15 @@ static void task_core_updater_download_handler(retro_task_t *task)
{ {
case CORE_UPDATER_DOWNLOAD_BEGIN: case CORE_UPDATER_DOWNLOAD_BEGIN:
{ {
file_transfer_t *transf = NULL; /* Get CRC of existing core, if required */
if (download_handle->local_crc == 0)
download_handle->local_crc = task_core_updater_get_core_crc(
download_handle->local_core_path);
/* Check CRC of existing core, if required */ /* Check whether existing core and remote core
if (download_handle->check_crc) * have the same CRC */
download_handle->crc_match = local_core_matches_remote_crc( download_handle->crc_match = (download_handle->local_crc != 0) &&
download_handle->local_core_path, (download_handle->local_crc == download_handle->remote_crc);
download_handle->remote_crc);
/* If CRC matches, end task immediately */ /* If CRC matches, end task immediately */
if (download_handle->crc_match) if (download_handle->crc_match)
@ -651,6 +664,99 @@ static void task_core_updater_download_handler(retro_task_t *task)
break; break;
} }
/* If automatic backups are enabled and core is
* already installed, trigger a backup - otherwise,
* initialise download */
download_handle->backup_enabled = download_handle->auto_backup &&
path_is_valid(download_handle->local_core_path);
download_handle->status = download_handle->backup_enabled ?
CORE_UPDATER_DOWNLOAD_START_BACKUP :
CORE_UPDATER_DOWNLOAD_START_TRANSFER;
}
break;
case CORE_UPDATER_DOWNLOAD_START_BACKUP:
{
/* Request core backup */
download_handle->backup_task = (retro_task_t*)task_push_core_backup(
download_handle->local_core_path,
download_handle->display_name,
download_handle->local_crc, CORE_BACKUP_MODE_AUTO,
download_handle->auto_backup_history_size,
download_handle->path_dir_core_assets, true);
if (download_handle->backup_task)
{
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* Update task title */
task_free_title(task);
strlcpy(
task_title, msg_hash_to_str(MSG_BACKING_UP_CORE),
sizeof(task_title));
strlcat(task_title, download_handle->display_name, sizeof(task_title));
task_set_title(task, strdup(task_title));
/* Start waiting for backup to complete */
download_handle->status = CORE_UPDATER_DOWNLOAD_WAIT_BACKUP;
}
else
{
/* This cannot realistically happen...
* > If it does, just log an error and initialise
* download */
RARCH_ERR("[core updater] Failed to backup core: %s\n",
download_handle->local_core_path);
download_handle->backup_enabled = false;
download_handle->status = CORE_UPDATER_DOWNLOAD_START_TRANSFER;
}
}
break;
case CORE_UPDATER_DOWNLOAD_WAIT_BACKUP:
{
bool backup_complete = false;
/* > If task is running, check 'is finished'
* status
* > If task is NULL, then it is finished
* by definition */
if (download_handle->backup_task)
{
backup_complete = task_get_finished(download_handle->backup_task);
/* If backup task is running, copy current
* progress value to *this* task */
if (!backup_complete)
{
/* Backup accounts for first third of
* task progress */
int8_t progress = task_get_progress(download_handle->backup_task);
task_set_progress(task, (int8_t)(((float)progress * (1.0f / 3.0f)) + 0.5f));
}
}
else
backup_complete = true;
/* If backup is complete, initialise download */
if (backup_complete)
{
download_handle->backup_task = NULL;
download_handle->status = CORE_UPDATER_DOWNLOAD_START_TRANSFER;
}
}
break;
case CORE_UPDATER_DOWNLOAD_START_TRANSFER:
{
file_transfer_t *transf = NULL;
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* Configure file transfer object */ /* Configure file transfer object */
transf = (file_transfer_t*)calloc(1, sizeof(file_transfer_t)); transf = (file_transfer_t*)calloc(1, sizeof(file_transfer_t));
@ -668,16 +774,6 @@ static void task_core_updater_download_handler(retro_task_t *task)
download_handle->remote_core_path, true, NULL, download_handle->remote_core_path, true, NULL,
cb_http_task_core_updater_download, transf); cb_http_task_core_updater_download, transf);
/* Start waiting for HTTP transfer to complete */
download_handle->status = CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER;
}
break;
case CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER:
{
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* Update task title */ /* Update task title */
task_free_title(task); task_free_title(task);
@ -688,6 +784,12 @@ static void task_core_updater_download_handler(retro_task_t *task)
task_set_title(task, strdup(task_title)); task_set_title(task, strdup(task_title));
/* Start waiting for HTTP transfer to complete */
download_handle->status = CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER;
}
break;
case CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER:
{
/* If HTTP task is NULL, then it either finished /* If HTTP task is NULL, then it either finished
* or an error occurred - in either case, * or an error occurred - in either case,
* just move on to the next state */ * just move on to the next state */
@ -703,36 +805,46 @@ static void task_core_updater_download_handler(retro_task_t *task)
* progress value to *this* task */ * progress value to *this* task */
if (!download_handle->http_task_finished) if (!download_handle->http_task_finished)
{ {
/* Download accounts for first half of /* > If backups are enabled, download accounts
* task progress */ * for second third of task progress
* > Otherwise, download accounts for first half
* of task progress */
int8_t progress = task_get_progress(download_handle->http_task); int8_t progress = task_get_progress(download_handle->http_task);
task_set_progress(task, progress >> 1); if (download_handle->backup_enabled)
progress = (int8_t)(((float)progress * (1.0f / 3.0f)) + (100.0f / 3.0f) + 0.5f);
else
progress = progress >> 1;
task_set_progress(task, progress);
} }
} }
/* Wait for task_push_http_transfer_file() /* Wait for task_push_http_transfer_file()
* callback to trigger */ * callback to trigger */
if (download_handle->http_task_complete) if (download_handle->http_task_complete)
{
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* Update task title */
task_free_title(task);
strlcpy(
task_title, msg_hash_to_str(MSG_EXTRACTING_CORE),
sizeof(task_title));
strlcat(task_title, download_handle->display_name, sizeof(task_title));
task_set_title(task, strdup(task_title));
/* Start waiting for file to be extracted */
download_handle->status = CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS; download_handle->status = CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS;
}
} }
break; break;
case CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS: case CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS:
{ {
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* Update task title */
task_free_title(task);
strlcpy(
task_title, msg_hash_to_str(MSG_EXTRACTING_CORE),
sizeof(task_title));
strlcat(task_title, download_handle->display_name, sizeof(task_title));
task_set_title(task, strdup(task_title));
/* If decompression task is NULL, then it either /* If decompression task is NULL, then it either
* finished or an error occurred - in either case, * finished or an error occurred - in either case,
* just move on to the next state */ * just move on to the next state */
@ -749,11 +861,18 @@ static void task_core_updater_download_handler(retro_task_t *task)
* current progress value to *this* task */ * current progress value to *this* task */
if (!download_handle->decompress_task_finished) if (!download_handle->decompress_task_finished)
{ {
/* Download accounts for second half /* > If backups are enabled, decompression accounts
* of task progress */ * for last third of task progress
* > Otherwise, decompression accounts for second
* half of task progress */
int8_t progress = task_get_progress(download_handle->decompress_task); int8_t progress = task_get_progress(download_handle->decompress_task);
task_set_progress(task, 50 + (progress >> 1)); if (download_handle->backup_enabled)
progress = (int8_t)(((float)progress * (1.0f / 3.0f)) + (200.0f / 3.0f) + 0.5f);
else
progress = 50 + (progress >> 1);
task_set_progress(task, progress);
} }
} }
@ -816,8 +935,10 @@ static bool task_core_updater_download_finder(retro_task_t *task, void *user_dat
void *task_push_core_updater_download( void *task_push_core_updater_download(
core_updater_list_t* core_list, core_updater_list_t* core_list,
const char *filename, bool mute, bool check_crc, const char *filename, uint32_t crc, bool mute,
const char *path_dir_libretro) bool auto_backup, size_t auto_backup_history_size,
const char *path_dir_libretro,
const char *path_dir_core_assets)
{ {
task_finder_data_t find_data; task_finder_data_t find_data;
char task_title[PATH_MAX_LENGTH]; char task_title[PATH_MAX_LENGTH];
@ -861,14 +982,17 @@ void *task_push_core_updater_download(
sizeof(local_download_path)); sizeof(local_download_path));
/* Configure handle */ /* Configure handle */
download_handle->auto_backup = auto_backup;
download_handle->auto_backup_history_size = auto_backup_history_size;
download_handle->path_dir_libretro = strdup(path_dir_libretro); download_handle->path_dir_libretro = strdup(path_dir_libretro);
download_handle->path_dir_core_assets = string_is_empty(path_dir_core_assets) ? NULL : strdup(path_dir_core_assets);
download_handle->remote_filename = strdup(list_entry->remote_filename); download_handle->remote_filename = strdup(list_entry->remote_filename);
download_handle->remote_core_path = strdup(list_entry->remote_core_path); download_handle->remote_core_path = strdup(list_entry->remote_core_path);
download_handle->local_download_path = strdup(local_download_path); download_handle->local_download_path = strdup(local_download_path);
download_handle->local_core_path = strdup(list_entry->local_core_path); download_handle->local_core_path = strdup(list_entry->local_core_path);
download_handle->display_name = strdup(list_entry->display_name); download_handle->display_name = strdup(list_entry->display_name);
download_handle->local_crc = crc;
download_handle->remote_crc = list_entry->crc; download_handle->remote_crc = list_entry->crc;
download_handle->check_crc = check_crc;
download_handle->crc_match = false; download_handle->crc_match = false;
download_handle->http_task = NULL; download_handle->http_task = NULL;
download_handle->http_task_finished = false; download_handle->http_task_finished = false;
@ -876,6 +1000,8 @@ void *task_push_core_updater_download(
download_handle->decompress_task = NULL; download_handle->decompress_task = NULL;
download_handle->decompress_task_finished = false; download_handle->decompress_task_finished = false;
download_handle->decompress_task_complete = false; download_handle->decompress_task_complete = false;
download_handle->backup_enabled = false;
download_handle->backup_task = NULL;
download_handle->status = CORE_UPDATER_DOWNLOAD_BEGIN; download_handle->status = CORE_UPDATER_DOWNLOAD_BEGIN;
/* Concurrent downloads of the same file are not allowed */ /* Concurrent downloads of the same file are not allowed */
@ -938,6 +1064,9 @@ static void free_update_installed_cores_handle(
if (update_installed_handle->path_dir_libretro) if (update_installed_handle->path_dir_libretro)
free(update_installed_handle->path_dir_libretro); free(update_installed_handle->path_dir_libretro);
if (update_installed_handle->path_dir_core_assets)
free(update_installed_handle->path_dir_core_assets);
core_updater_list_free(update_installed_handle->core_list); core_updater_list_free(update_installed_handle->core_list);
free(update_installed_handle); free(update_installed_handle);
@ -1063,7 +1192,7 @@ static void task_update_installed_cores_handler(retro_task_t *task)
case UPDATE_INSTALLED_CORES_UPDATE_CORE: case UPDATE_INSTALLED_CORES_UPDATE_CORE:
{ {
const core_updater_list_entry_t *list_entry = NULL; const core_updater_list_entry_t *list_entry = NULL;
bool crc_match; uint32_t local_crc;
/* Get list entry /* Get list entry
* > In the event of an error, just return * > In the event of an error, just return
@ -1077,15 +1206,16 @@ static void task_update_installed_cores_handler(retro_task_t *task)
break; break;
} }
/* Check CRC of existing core */ /* Get CRC of existing core */
crc_match = local_core_matches_remote_crc( local_crc = task_core_updater_get_core_crc(
list_entry->local_core_path, list_entry->local_core_path);
list_entry->crc);
/* If CRC matches, then core is already the most /* Check whether existing core and remote core
* recent version - just return to * have the same CRC
* UPDATE_INSTALLED_CORES_ITERATE state */ * > If CRC matches, then core is already the most
if (crc_match) * recent version - just return to
* UPDATE_INSTALLED_CORES_ITERATE state */
if ((local_crc != 0) && (local_crc == list_entry->crc))
{ {
update_installed_handle->status = UPDATE_INSTALLED_CORES_ITERATE; update_installed_handle->status = UPDATE_INSTALLED_CORES_ITERATE;
break; break;
@ -1097,8 +1227,11 @@ static void task_update_installed_cores_handler(retro_task_t *task)
task_push_core_updater_download( task_push_core_updater_download(
update_installed_handle->core_list, update_installed_handle->core_list,
list_entry->remote_filename, list_entry->remote_filename,
true, false, local_crc, true,
update_installed_handle->path_dir_libretro); update_installed_handle->auto_backup,
update_installed_handle->auto_backup_history_size,
update_installed_handle->path_dir_libretro,
update_installed_handle->path_dir_core_assets);
/* Again, if an error occurred, just return to /* Again, if an error occurred, just return to
* UPDATE_INSTALLED_CORES_ITERATE state */ * UPDATE_INSTALLED_CORES_ITERATE state */
@ -1208,7 +1341,10 @@ static bool task_update_installed_cores_finder(retro_task_t *task, void *user_da
return false; return false;
} }
void task_push_update_installed_cores(const char *path_dir_libretro) void task_push_update_installed_cores(
bool auto_backup, size_t auto_backup_history_size,
const char *path_dir_libretro,
const char *path_dir_core_assets)
{ {
task_finder_data_t find_data; task_finder_data_t find_data;
retro_task_t *task = NULL; retro_task_t *task = NULL;
@ -1217,20 +1353,24 @@ void task_push_update_installed_cores(const char *path_dir_libretro)
calloc(1, sizeof(update_installed_cores_handle_t)); calloc(1, sizeof(update_installed_cores_handle_t));
/* Sanity check */ /* Sanity check */
if (!update_installed_handle) if (!update_installed_handle ||
string_is_empty(path_dir_libretro))
goto error; goto error;
/* Configure handle */ /* Configure handle */
update_installed_handle->core_list = core_updater_list_init( update_installed_handle->auto_backup = auto_backup;
CORE_UPDATER_LIST_SIZE); update_installed_handle->auto_backup_history_size = auto_backup_history_size;
update_installed_handle->list_task = NULL; update_installed_handle->path_dir_libretro = strdup(path_dir_libretro);
update_installed_handle->download_task = NULL; update_installed_handle->path_dir_core_assets = string_is_empty(path_dir_core_assets) ?
update_installed_handle->list_size = 0; NULL : strdup(path_dir_core_assets);
update_installed_handle->list_index = 0; update_installed_handle->core_list = core_updater_list_init(CORE_UPDATER_LIST_SIZE);
update_installed_handle->installed_index = 0; update_installed_handle->list_task = NULL;
update_installed_handle->num_updated = 0; update_installed_handle->download_task = NULL;
update_installed_handle->path_dir_libretro = strdup(path_dir_libretro); update_installed_handle->list_size = 0;
update_installed_handle->status = UPDATE_INSTALLED_CORES_BEGIN; update_installed_handle->list_index = 0;
update_installed_handle->installed_index = 0;
update_installed_handle->num_updated = 0;
update_installed_handle->status = UPDATE_INSTALLED_CORES_BEGIN;
if (!update_installed_handle->core_list) if (!update_installed_handle->core_list)
goto error; goto error;

View File

@ -96,13 +96,21 @@ bool task_push_netplay_lan_scan_rooms(retro_task_callback_t cb);
bool task_push_netplay_nat_traversal(void *nat_traversal_state, uint16_t port); bool task_push_netplay_nat_traversal(void *nat_traversal_state, uint16_t port);
/* Core updater tasks */ /* Core updater tasks */
void *task_push_get_core_updater_list( void *task_push_get_core_updater_list(
core_updater_list_t* core_list, bool mute, bool refresh_menu); core_updater_list_t* core_list, bool mute, bool refresh_menu);
/* Note: If crc is set to 0, crc of local core file
* will be calculated automatically */
void *task_push_core_updater_download( void *task_push_core_updater_download(
core_updater_list_t* core_list, const char *filename, core_updater_list_t* core_list,
bool mute, bool check_crc, const char *path_dir_libretro); const char *filename, uint32_t crc, bool mute,
void task_push_update_installed_cores(const char *path_dir_libretro); bool auto_backup, size_t auto_backup_history_size,
const char *path_dir_libretro,
const char *path_dir_core_assets);
void task_push_update_installed_cores(
bool auto_backup, size_t auto_backup_history_size,
const char *path_dir_libretro,
const char *path_dir_core_assets);
bool task_push_pl_entry_thumbnail_download( bool task_push_pl_entry_thumbnail_download(
const char *system, const char *system,
@ -121,12 +129,18 @@ bool task_push_pl_thumbnail_download(
/* Core backup/restore tasks */ /* Core backup/restore tasks */
/* Note: If crc is set to 0, crc of core_path file will /* Note 1: If crc is set to 0, crc of core_path file will
* be calculated automatically */ * be calculated automatically
void *task_push_core_backup(const char *core_path, * Note 2: If core_display_name is set to NULL, display
* name will be determined automatically
* > core_display_name *must* be set to a non-empty
* string if task_push_core_backup() is *not* called
* on the main thread */
void *task_push_core_backup(
const char *core_path, const char *core_display_name,
uint32_t crc, enum core_backup_mode backup_mode, uint32_t crc, enum core_backup_mode backup_mode,
size_t auto_backup_history_size,
const char *dir_core_assets, bool mute); const char *dir_core_assets, bool mute);
/* Note: If 'core_loaded' is true, menu stack should be /* Note: If 'core_loaded' is true, menu stack should be
* flushed if task_push_core_restore() returns true */ * flushed if task_push_core_restore() returns true */
bool task_push_core_restore(const char *backup_path, bool task_push_core_restore(const char *backup_path,