Merge pull request #10871 from jdgleaver/core-update-block

Add option to selectively 'lock' (prevent modification of) installed cores
This commit is contained in:
Autechre 2020-06-18 23:02:44 +02:00 committed by GitHub
commit a88bc56ede
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 674 additions and 56 deletions

View File

@ -19,6 +19,7 @@
#include <string/stdstring.h>
#include <file/config_file.h>
#include <file/file_path.h>
#include <streams/file_stream.h>
#include <lists/dir_list.h>
#include <file/archive_file.h>
@ -240,6 +241,36 @@ static config_file_t *core_info_list_iterate(
return conf;
}
/* Returned path must be free()'d */
static char *core_info_get_core_lock_file_path(const char *core_path)
{
char *lock_file_path = NULL;
const char *lock_file_ext = file_path_str(FILE_PATH_LOCK_EXTENSION);
size_t len;
if (string_is_empty(core_path))
return NULL;
/* Note: We follow the common 'core_info' trend of
* allocating all strings dynamically... */
/* Get path length */
len = (strlen(core_path) + strlen(lock_file_ext) + 1) * sizeof(char);
/* Allocate string */
lock_file_path = (char*)malloc(len);
if (!lock_file_path)
return NULL;
lock_file_path[0] = '\0';
/* Lock file is just core path + 'lock' extension */
strlcpy(lock_file_path, core_path, len);
strlcat(lock_file_path, lock_file_ext, len);
return lock_file_path;
}
static core_info_list_t *core_info_list_new(const char *path,
const char *libretro_info_dir,
const char *exts,
@ -523,6 +554,9 @@ static core_info_list_t *core_info_list_new(const char *path,
core_info[i].display_name = strdup(core_filename);
}
}
/* Get core lock status */
core_info[i].is_locked = core_info_get_core_lock(core_info[i].path, false);
}
if (core_info_list)
@ -1505,3 +1539,144 @@ bool core_info_hw_api_supported(core_info_t *info)
return true;
#endif
}
/* Sets 'locked' status of specified core
* > Returns true if successful
* > Like all functions that access the cached
* core info list this is *not* thread safe */
bool core_info_set_core_lock(const char *core_path, bool lock)
{
char *lock_file_path = NULL;
RFILE *lock_file = NULL;
bool lock_file_exists = false;
core_info_ctx_find_t core_info;
if (string_is_empty(core_path))
goto error;
/* Search for specified core */
core_info.inf = NULL;
core_info.path = core_path;
if (!core_info_find(&core_info))
goto error;
/* Get associated lock file path */
lock_file_path = core_info_get_core_lock_file_path(core_info.inf->path);
if (string_is_empty(lock_file_path))
goto error;
/* Check whether lock file exists */
lock_file_exists = path_is_valid(lock_file_path);
/* Create or delete lock file, as required */
if (lock && !lock_file_exists)
{
lock_file = filestream_open(
lock_file_path,
RETRO_VFS_FILE_ACCESS_WRITE,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!lock_file)
goto error;
/* We have to write something - just output
* a single character */
if (filestream_putc(lock_file, 0) != 0)
goto error;
filestream_close(lock_file);
lock_file = NULL;
}
else if (!lock && lock_file_exists)
if (filestream_delete(lock_file_path) != 0)
goto error;
/* Clean up */
free(lock_file_path);
lock_file_path = NULL;
/* File operations were successful - update
* core info entry */
core_info.inf->is_locked = lock;
return true;
error:
if (lock_file_path)
{
free(lock_file_path);
lock_file_path = NULL;
}
if (lock_file)
{
filestream_close(lock_file);
lock_file = NULL;
}
return false;
}
/* Fetches 'locked' status of specified core
* > If 'validate_path' is 'true', will search
* cached core info list for a corresponding
* 'sanitised' core file path. This is *not*
* thread safe
* > If 'validate_path' is 'false', performs a
* direct filesystem check. This *is* thread
* safe, but validity of specified core path
* must be checked externally */
bool core_info_get_core_lock(const char *core_path, bool validate_path)
{
const char *core_file_path = NULL;
char *lock_file_path = NULL;
bool is_locked = false;
core_info_ctx_find_t core_info;
if (string_is_empty(core_path))
goto end;
/* Check whether core path is to be validated */
if (validate_path)
{
core_info.inf = NULL;
core_info.path = core_path;
if (core_info_find(&core_info))
core_file_path = core_info.inf->path;
}
else
core_file_path = core_path;
/* A core cannot be locked if it does not exist... */
if (string_is_empty(core_file_path) ||
!path_is_valid(core_file_path))
goto end;
/* Get lock file path */
lock_file_path = core_info_get_core_lock_file_path(core_file_path);
if (string_is_empty(lock_file_path))
goto end;
/* Check whether lock file exists */
is_locked = path_is_valid(lock_file_path);
/* If core path has been validated (and a
* core info object is available), ensure
* that core info 'is_locked' field is
* up to date */
if (validate_path && core_info.inf)
core_info.inf->is_locked = is_locked;
end:
if (lock_file_path)
{
free(lock_file_path);
lock_file_path = NULL;
}
return is_locked;
}

View File

@ -57,6 +57,7 @@ typedef struct
bool supports_no_game;
bool database_match_archive_member;
bool is_experimental;
bool is_locked;
size_t firmware_count;
char *path;
void *config_data;
@ -201,6 +202,22 @@ bool core_info_list_get_info(core_info_list_t *core_info_list,
bool core_info_hw_api_supported(core_info_t *info);
/* Sets 'locked' status of specified core
* > Returns true if successful
* > Like all functions that access the cached
* core info list this is *not* thread safe */
bool core_info_set_core_lock(const char *core_path, bool lock);
/* Fetches 'locked' status of specified core
* > If 'validate_path' is 'true', will search
* cached core info list for a corresponding
* 'sanitised' core file path. This is *not*
* thread safe
* > If 'validate_path' is 'false', performs a
* direct filesystem check. This *is* thread
* safe, but validity of specified core path
* must be checked externally */
bool core_info_get_core_lock(const char *core_path, bool validate_path);
core_info_state_t *coreinfo_get_ptr(void);
RETRO_END_DECLS

View File

@ -98,7 +98,8 @@ enum file_path_enum
FILE_PATH_EVENT_LOG_EXTENSION,
FILE_PATH_DISK_CONTROL_INDEX_EXTENSION,
FILE_PATH_CORE_BACKUP_EXTENSION,
FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT
FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT,
FILE_PATH_LOCK_EXTENSION
};
enum application_special_type

View File

@ -236,6 +236,9 @@ const char *file_path_str(enum file_path_enum enum_idx)
case FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT:
str = "lcbk";
break;
case FILE_PATH_LOCK_EXTENSION:
str = ".lck";
break;
case FILE_PATH_UNKNOWN:
default:
break;

View File

@ -3540,6 +3540,10 @@ MSG_HASH(
MENU_ENUM_LABEL_MENU_SCROLL_FAST,
"menu_scroll_fast"
)
MSG_HASH(
MENU_ENUM_LABEL_CORE_LOCK,
"core_lock"
)
MSG_HASH(
MENU_ENUM_LABEL_CORE_DELETE,
"core_delete"

View File

@ -449,6 +449,14 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_REQUIRED,
"Required"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_LOCK,
"Lock Installed Core"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_LOCK,
"Prevent modification of the currently installed core. May be used to avoid unwanted updates when content requires a specific core version (e.g. Arcade ROM sets)."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_DELETE,
"Delete Core"
@ -9726,6 +9734,14 @@ MSG_HASH(
MSG_NUM_CORES_UPDATED,
"cores updated: "
)
MSG_HASH(
MSG_NUM_CORES_LOCKED,
"cores skipped: "
)
MSG_HASH(
MSG_CORE_UPDATE_DISABLED,
"Core update disabled - core is locked: "
)
MSG_HASH(
MSG_PLAYLIST_MANAGER_RESETTING_CORES,
"Resetting cores: "
@ -10934,6 +10950,26 @@ MSG_HASH(
MSG_CORE_INSTALLATION_FAILED,
"Core installation failed: "
)
MSG_HASH(
MSG_CORE_RESTORATION_DISABLED,
"Core restoration disabled - core is locked: "
)
MSG_HASH(
MSG_CORE_INSTALLATION_DISABLED,
"Core installation disabled - core is locked: "
)
MSG_HASH(
MSG_CORE_LOCK_FAILED,
"Failed to lock core: "
)
MSG_HASH(
MSG_CORE_UNLOCK_FAILED,
"Failed to unlock core: "
)
MSG_HASH(
MSG_CORE_DELETE_DISABLED,
"Core deletion disabled - core is locked: "
)
/* Lakka */

View File

@ -464,8 +464,17 @@ static void menu_action_setting_disp_set_label_core_updater_entry(
if (core_info_find(&core_info))
{
strlcpy(s, "[#]", len);
*w = (unsigned)STRLEN_CONST("[#]");
/* Highlight locked cores */
if (core_info.inf->is_locked)
{
strlcpy(s, "[#!]", len);
*w = (unsigned)STRLEN_CONST("[#!]");
}
else
{
strlcpy(s, "[#]", len);
*w = (unsigned)STRLEN_CONST("[#]");
}
}
}
}
@ -480,6 +489,7 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
char *s2, size_t len2)
{
const char *alt = NULL;
core_info_ctx_find_t core_info;
*s = '\0';
*w = 0;
@ -490,10 +500,55 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
if (alt)
strlcpy(s2, alt, len2);
/* TODO: Once core-specific 'block online updates'
* settings are implemented, the 'value' string will
* be used to indicate whether updates are enabled
* or disabled */
/* Check whether core is locked
* > Note: We search core_info here instead of
* calling core_info_get_core_lock() since we
* don't want to perform disk access every frame */
core_info.inf = NULL;
core_info.path = path;
if (core_info_find(&core_info) &&
core_info.inf->is_locked)
{
strlcpy(s, "[!]", len);
*w = (unsigned)STRLEN_CONST("[!]");
}
}
static void menu_action_setting_disp_set_label_core_lock(
file_list_t* list,
unsigned *w, unsigned type, unsigned i,
const char *label,
char *s, size_t len,
const char *path,
char *s2, size_t len2)
{
const char *alt = NULL;
core_info_ctx_find_t core_info;
*s = '\0';
*w = 0;
menu_entries_get_at_offset(list, i, NULL,
NULL, NULL, NULL, &alt);
if (alt)
strlcpy(s2, alt, len2);
/* Check whether core is locked
* > Note: We search core_info here instead of
* calling core_info_get_core_lock() since we
* don't want to perform disk access every frame */
core_info.inf = NULL;
core_info.path = path;
if (core_info_find(&core_info) &&
core_info.inf->is_locked)
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON), len);
else
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF), len);
*w = (unsigned)strlen(s);
}
static void menu_action_setting_disp_set_label_input_desc(
@ -1622,7 +1677,7 @@ static int menu_cbs_init_bind_get_string_representation_compare_label(
menu_action_setting_disp_set_label_core_manager_entry);
break;
default:
return - 1;
return -1;
}
}
else
@ -1821,6 +1876,10 @@ static int menu_cbs_init_bind_get_string_representation_compare_type(
case MENU_SETTING_NO_ITEM:
BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_no_items);
break;
case MENU_SETTING_ACTION_CORE_LOCK:
BIND_ACTION_GET_VALUE(cbs,
menu_action_setting_disp_set_label_core_lock);
break;
case 32: /* Recent history entry */
case 65535: /* System info entry */
BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_entry);

View File

@ -46,6 +46,9 @@
#define BIND_ACTION_LEFT(cbs, name) (cbs)->action_left = (name)
#endif
/* Forward declarations */
int action_ok_core_lock(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx);
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
@ -680,6 +683,12 @@ static int core_setting_left(unsigned type, const char *label,
return 0;
}
static int action_left_core_lock(unsigned type, const char *label,
bool wraparound)
{
return action_ok_core_lock(label, label, type, 0, 0);
}
static int disk_options_disk_idx_left(unsigned type, const char *label,
bool wraparound)
{
@ -1066,6 +1075,9 @@ static int menu_cbs_init_bind_left_compare_type(menu_file_list_cbs_t *cbs,
case FILE_TYPE_CONTENTLIST_ENTRY:
BIND_ACTION_LEFT(cbs, action_left_mainmenu);
break;
case MENU_SETTING_ACTION_CORE_LOCK:
BIND_ACTION_LEFT(cbs, action_left_core_lock);
break;
default:
return -1;
}

View File

@ -6360,17 +6360,122 @@ static int action_ok_core_delete_backup(const char *path,
return 0;
}
/* Do not declare this static - it is also used
* in menu_cbs_left.c and menu_cbs_right.c */
int action_ok_core_lock(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = path;
bool lock = false;
bool refresh = false;
int ret = 0;
if (string_is_empty(core_path))
return -1;
/* Simply toggle current lock status */
lock = !core_info_get_core_lock(core_path, true);
if (!core_info_set_core_lock(core_path, lock))
{
const char *core_name = NULL;
core_info_ctx_find_t core_info;
char msg[PATH_MAX_LENGTH];
msg[0] = '\0';
/* Need to fetch core name for error message */
core_info.inf = NULL;
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;
/* If not, use core file name */
else
core_name = path_basename(core_path);
/* Build error message */
strlcpy(
msg,
msg_hash_to_str(lock ?
MSG_CORE_LOCK_FAILED : MSG_CORE_UNLOCK_FAILED),
sizeof(msg));
if (!string_is_empty(core_name))
strlcat(msg, core_name, sizeof(msg));
/* Generate log + notification */
RARCH_ERR("%s\n", msg);
runloop_msg_queue_push(
msg,
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
ret = -1;
}
/* Whenever lock status is changed, menu must be
* refreshed - do this even in the event of an error,
* since we don't want to leave the menu in an
* undefined state */
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
return ret;
}
static int action_ok_core_delete(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = label;
const char *core = NULL;
const char *core_path = label;
const char *core = NULL;
const char *loaded_core_path = NULL;
const char *loaded_core = NULL;
if (string_is_empty(core_path))
return -1;
/* Check whether core is locked */
if (core_info_get_core_lock(core_path, true))
{
const char *core_name = NULL;
core_info_ctx_find_t core_info;
char msg[PATH_MAX_LENGTH];
msg[0] = '\0';
/* Need to fetch core name for notification */
core_info.inf = NULL;
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;
/* If not, use core file name */
else
core_name = path_basename(core_path);
/* Build notification message */
strlcpy(msg, msg_hash_to_str(MSG_CORE_DELETE_DISABLED), sizeof(msg));
if (!string_is_empty(core_name))
strlcat(msg, core_name, sizeof(msg));
runloop_msg_queue_push(
msg,
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* We do not consider this an 'error' - we are
* merely telling the user that this operation
* is not currently supported */
return 0;
}
/* Get core file name */
core = path_basename(core_path);
if (string_is_empty(core))
@ -7409,6 +7514,9 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
case MENU_SETTING_ITEM_CORE_DELETE_BACKUP:
BIND_ACTION_OK(cbs, action_ok_core_delete_backup);
break;
case MENU_SETTING_ACTION_CORE_LOCK:
BIND_ACTION_OK(cbs, action_ok_core_lock);
break;
default:
return -1;
}

View File

@ -47,6 +47,9 @@
#define BIND_ACTION_RIGHT(cbs, name) (cbs)->action_right = (name)
#endif
/* Forward declarations */
int action_ok_core_lock(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx);
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
@ -804,6 +807,12 @@ int core_setting_right(unsigned type, const char *label,
return 0;
}
static int action_right_core_lock(unsigned type, const char *label,
bool wraparound)
{
return action_ok_core_lock(label, label, type, 0, 0);
}
static int disk_options_disk_idx_right(unsigned type, const char *label,
bool wraparound)
{
@ -923,6 +932,9 @@ static int menu_cbs_init_bind_right_compare_type(menu_file_list_cbs_t *cbs,
case FILE_TYPE_CONTENTLIST_ENTRY:
BIND_ACTION_RIGHT(cbs, action_right_mainmenu);
break;
case MENU_SETTING_ACTION_CORE_LOCK:
BIND_ACTION_RIGHT(cbs, action_right_core_lock);
break;
default:
return -1;
}

View File

@ -36,6 +36,7 @@
#include "../../managers/core_option_manager.h"
#include "../../managers/cheat_manager.h"
#include "../../retroarch.h"
#include "../../verbosity.h"
#include "../../performance_counters.h"
#include "../../playlist.h"
#include "../../manual_content_scan.h"
@ -495,6 +496,70 @@ static int action_start_core_updater_entry(
}
#endif
static int action_start_core_lock(
const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = path;
bool refresh = false;
int ret = 0;
if (string_is_empty(core_path))
return -1;
/* Core should be unlocked by default
* > If it is currently unlocked, do nothing */
if (!core_info_get_core_lock(core_path, true))
return ret;
/* ...Otherwise, attempt to unlock it */
if (!core_info_set_core_lock(core_path, false))
{
const char *core_name = NULL;
core_info_ctx_find_t core_info;
char msg[PATH_MAX_LENGTH];
msg[0] = '\0';
/* Need to fetch core name for error message */
core_info.inf = NULL;
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;
/* If not, use core file name */
else
core_name = path_basename(core_path);
/* Build error message */
strlcpy(msg, msg_hash_to_str(MSG_CORE_UNLOCK_FAILED), sizeof(msg));
if (!string_is_empty(core_name))
strlcat(msg, core_name, sizeof(msg));
/* Generate log + notification */
RARCH_ERR("%s\n", msg);
runloop_msg_queue_push(
msg,
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
ret = -1;
}
/* Whenever lock status is changed, menu must be
* refreshed - do this even in the event of an error,
* since we don't want to leave the menu in an
* undefined state */
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
return ret;
}
static int action_start_lookup_setting(
const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
@ -636,6 +701,9 @@ static int menu_cbs_init_bind_start_compare_type(menu_file_list_cbs_t *cbs,
BIND_ACTION_START(cbs, action_start_core_updater_entry);
break;
#endif
case MENU_SETTING_ACTION_CORE_LOCK:
BIND_ACTION_START(cbs, action_start_core_lock);
break;
default:
return -1;
}

View File

@ -753,6 +753,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_x,
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_y, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_use_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_lock, MENU_ENUM_SUBLABEL_CORE_LOCK)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_delete, MENU_ENUM_SUBLABEL_CORE_DELETE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_pause_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_resume_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME)
@ -3468,6 +3469,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_NETPLAY_MITM_SERVER:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_mitm_server);
break;
case MENU_ENUM_LABEL_CORE_LOCK:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_lock);
break;
case MENU_ENUM_LABEL_CORE_DELETE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_delete);
break;

View File

@ -9119,6 +9119,7 @@ static void materialui_list_insert(
case FILE_TYPE_DOWNLOAD_CORE:
case FILE_TYPE_CORE:
case MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS:
case MENU_SETTING_ACTION_CORE_LOCK:
node->icon_texture_index = MUI_TEXTURE_CORES;
node->has_icon = true;
break;

View File

@ -239,6 +239,8 @@ uintptr_t ozone_entries_icon_get_texture(ozone_handle_t *ozone,
case MENU_ENUM_LABEL_DELETE_PLAYLIST:
case MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE];
case MENU_ENUM_LABEL_CORE_LOCK:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE];
case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OSD];
case MENU_ENUM_LABEL_SHOW_WIMP:

View File

@ -2644,6 +2644,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
case MENU_ENUM_LABEL_DELETE_PLAYLIST:
case MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST:
return xmb->textures.list[XMB_TEXTURE_CLOSE];
case MENU_ENUM_LABEL_CORE_LOCK:
return xmb->textures.list[XMB_TEXTURE_CORE];
case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS:
return xmb->textures.list[XMB_TEXTURE_OSD];
case MENU_ENUM_LABEL_SHOW_WIMP:

View File

@ -367,6 +367,26 @@ end:
#if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
if (!string_is_empty(core_path) && !kiosk_mode_enable)
{
/* Check whether core is currently locked */
bool core_locked = core_info_get_core_lock(core_path, true);
/* Lock core
* > Note: Have to set core_path as both the
* 'path' and 'label' parameters (otherwise
* cannot access it in menu_cbs_get_value.c
* or menu_cbs_left/right.c), which means
* entry name must be set as 'alt' text */
if (menu_entries_append_enum(info->list,
core_path,
core_path,
MENU_ENUM_LABEL_CORE_LOCK,
MENU_SETTING_ACTION_CORE_LOCK, 0, 0))
{
file_list_set_alt_at_offset(
info->list, count, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LOCK));
count++;
}
/* Backup core */
if (menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_CREATE_BACKUP),
@ -376,12 +396,13 @@ end:
count++;
/* Restore core from backup */
if (menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_RESTORE_BACKUP_LIST),
core_path,
MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST,
MENU_SETTING_ACTION_CORE_RESTORE_BACKUP, 0, 0))
count++;
if (!core_locked)
if (menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_RESTORE_BACKUP_LIST),
core_path,
MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST,
MENU_SETTING_ACTION_CORE_RESTORE_BACKUP, 0, 0))
count++;
/* Delete core backup */
if (menu_entries_append_enum(info->list,
@ -397,7 +418,7 @@ end:
* up in a situation where a core cannot be
* restored */
#if defined(HAVE_NETWORKING) && defined(HAVE_ONLINE_UPDATER)
if (menu_show_core_updater)
if (menu_show_core_updater && !core_locked)
if (menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE),
core_path,
@ -9641,26 +9662,30 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
break;
case DISPLAYLIST_CORE_INFO:
{
/* There is a (infinitesimally small) chance that
* the number of items in the core info menu will
* change after performing a core restore operation
* (i.e. the core info files are reloaded, and if
* an unknown error occurs then info entries may
* not be available upon popping the stack). We
* therefore have to cache the last set menu size,
* and reset the navigation pointer if the current
* size is different */
static size_t prev_count = 0;
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
count = menu_displaylist_parse_core_info(info);
/* The number of items in the core info menu:
* - *May* (possibly) change after performing a
* core restore operation (i.e. the core info
* files are reloaded, and if an unknown error
* occurs then info entries may not be available
* upon popping the stack)
* - *Will* change when toggling the core lock
* status
* To prevent the menu selection from going out
* of bounds, we therefore have to check that the
* current selection index is less than the current
* number of menu entries - if not, we reset the
* navigation pointer */
size_t selection = menu_navigation_get_selection();
if (count != prev_count)
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
count = menu_displaylist_parse_core_info(info);
if (selection >= count)
{
info->need_refresh = true;
info->need_navigation_clear = true;
prev_count = count;
}
info->need_push = true;
info->need_push = true;
}
break;
case DISPLAYLIST_CORE_RESTORE_BACKUP_LIST:

View File

@ -108,6 +108,7 @@ enum menu_settings_type
MENU_SETTING_ACTION_SCREENSHOT,
MENU_SETTING_ACTION_DELETE_ENTRY,
MENU_SETTING_ACTION_RESET,
MENU_SETTING_ACTION_CORE_LOCK,
MENU_SETTING_ACTION_CORE_DELETE,
MENU_SETTING_STRING_OPTIONS,
MENU_SETTING_GROUP,

View File

@ -1995,8 +1995,13 @@ enum msg_hash_enums
MENU_LABEL(ACHIEVEMENT_RESUME),
MENU_LABEL(CORE_INFORMATION),
MENU_LABEL(DISC_INFORMATION),
MENU_LABEL(CORE_LOCK),
MENU_LABEL(CORE_DELETE),
MSG_CORE_LOCK_FAILED,
MSG_CORE_UNLOCK_FAILED,
MSG_CORE_DELETE_DISABLED,
/* Core updater */
MENU_LABEL(UPDATE_INSTALLED_CORES),
@ -2011,6 +2016,8 @@ enum msg_hash_enums
MSG_CHECKING_CORE,
MSG_ALL_CORES_UPDATED,
MSG_NUM_CORES_UPDATED,
MSG_NUM_CORES_LOCKED,
MSG_CORE_UPDATE_DISABLED,
/* Core backup/restore */
MENU_LABEL(CORE_CREATE_BACKUP),
@ -2037,6 +2044,8 @@ enum msg_hash_enums
MSG_CORE_BACKUP_FAILED,
MSG_CORE_RESTORATION_FAILED,
MSG_CORE_INSTALLATION_FAILED,
MSG_CORE_RESTORATION_DISABLED,
MSG_CORE_INSTALLATION_DISABLED,
MENU_LABEL(VIDEO_SHADER_PARAMETERS),
MENU_LABEL(VIDEO_SHADER_PRESET_PARAMETERS),

View File

@ -992,14 +992,6 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
goto error;
}
/* Concurrent backup/restore tasks for the same core
* are not allowed */
find_data.func = task_core_backup_finder;
find_data.userdata = (void*)core_path;
if (task_queue_find(&find_data))
goto error;
/* Get core name */
core_info.inf = NULL;
core_info.path = core_path;
@ -1017,6 +1009,34 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
goto error;
}
/* Check whether core is locked */
if (core_info_get_core_lock(core_path, true))
{
char msg[PATH_MAX_LENGTH];
msg[0] = '\0';
strlcpy(msg,
(backup_type == CORE_BACKUP_TYPE_ARCHIVE) ?
msg_hash_to_str(MSG_CORE_RESTORATION_DISABLED) :
msg_hash_to_str(MSG_CORE_INSTALLATION_DISABLED),
sizeof(msg));
strlcat(msg, core_name, sizeof(msg));
RARCH_ERR("[core restore] Restoration disabled - core is locked: %s\n", core_path);
runloop_msg_queue_push(msg, 1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
goto error;
}
/* Concurrent backup/restore tasks for the same core
* are not allowed */
find_data.func = task_core_backup_finder;
find_data.userdata = (void*)core_path;
if (task_queue_find(&find_data))
goto error;
/* Configure handle */
backup_handle = (core_backup_handle_t*)calloc(1, sizeof(core_backup_handle_t));

View File

@ -123,6 +123,7 @@ typedef struct update_installed_cores_handle
size_t list_index;
size_t installed_index;
unsigned num_updated;
unsigned num_locked;
enum update_installed_cores_status status;
} update_installed_cores_handle_t;
@ -962,14 +963,37 @@ void *task_push_core_updater_download(
core_list, filename, &list_entry))
goto error;
if (string_is_empty(list_entry->remote_core_path))
if (string_is_empty(list_entry->remote_core_path) ||
string_is_empty(list_entry->local_core_path) ||
string_is_empty(list_entry->display_name))
goto error;
if (string_is_empty(list_entry->local_core_path))
goto error;
/* Check whether core is locked
* > Have to set validate_path to 'false' here,
* since this may not run on the main thread
* > Validation is not required anyway, since core
* updater list provides 'sane' core paths */
if (core_info_get_core_lock(list_entry->local_core_path, false))
{
RARCH_ERR("[core updater] Update disabled - core is locked: %s\n",
list_entry->local_core_path);
/* If task is not muted, generate notification */
if (!mute)
{
char msg[PATH_MAX_LENGTH];
msg[0] = '\0';
strlcpy(msg, msg_hash_to_str(MSG_CORE_UPDATE_DISABLED), sizeof(msg));
strlcat(msg, list_entry->display_name, sizeof(msg));
runloop_msg_queue_push(msg, 1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
if (string_is_empty(list_entry->display_name))
goto error;
}
/* Get local file download path */
if (string_is_empty(path_dir_libretro))
@ -1206,6 +1230,24 @@ static void task_update_installed_cores_handler(retro_task_t *task)
break;
}
/* Check whether core is locked
* > Have to set validate_path to 'false' here,
* since this does not run on the main thread
* > Validation is not required anyway, since core
* updater list provides 'sane' core paths */
if (core_info_get_core_lock(list_entry->local_core_path, false))
{
RARCH_LOG("[core updater] Skipping locked core: %s\n",
list_entry->display_name);
/* Core update is disabled
* > Just increment 'locked cores' counter and
* return to UPDATE_INSTALLED_CORES_ITERATE state */
update_installed_handle->num_locked++;
update_installed_handle->status = UPDATE_INSTALLED_CORES_ITERATE;
break;
}
/* Get CRC of existing core */
local_crc = task_core_updater_get_core_crc(
list_entry->local_core_path);
@ -1292,24 +1334,40 @@ static void task_update_installed_cores_handler(retro_task_t *task)
* successfully */
if (update_installed_handle->list_size > 0)
{
/* > Check whether a non-zero number of cores
* were updated */
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
/* > Generate final status message based on number
* of cores that were updated/locked */
if (update_installed_handle->num_updated > 0)
{
char task_title[PATH_MAX_LENGTH];
task_title[0] = '\0';
if (update_installed_handle->num_locked > 0)
snprintf(
task_title, sizeof(task_title), "%s [%s%u, %s%u]",
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
msg_hash_to_str(MSG_NUM_CORES_UPDATED),
update_installed_handle->num_updated,
msg_hash_to_str(MSG_NUM_CORES_LOCKED),
update_installed_handle->num_locked);
else
snprintf(
task_title, sizeof(task_title), "%s [%s%u]",
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
msg_hash_to_str(MSG_NUM_CORES_UPDATED),
update_installed_handle->num_updated);
}
else if (update_installed_handle->num_locked > 0)
snprintf(
task_title, sizeof(task_title), "%s [%s%u]",
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
msg_hash_to_str(MSG_NUM_CORES_UPDATED),
update_installed_handle->num_updated);
task_set_title(task, strdup(task_title));
}
msg_hash_to_str(MSG_NUM_CORES_LOCKED),
update_installed_handle->num_locked);
else
task_set_title(task, strdup(msg_hash_to_str(MSG_ALL_CORES_UPDATED)));
strlcpy(task_title, msg_hash_to_str(MSG_ALL_CORES_UPDATED),
sizeof(task_title));
task_set_title(task, strdup(task_title));
}
else
task_set_title(task, strdup(msg_hash_to_str(MSG_CORE_LIST_FAILED)));
@ -1370,6 +1428,7 @@ void task_push_update_installed_cores(
update_installed_handle->list_index = 0;
update_installed_handle->installed_index = 0;
update_installed_handle->num_updated = 0;
update_installed_handle->num_locked = 0;
update_installed_handle->status = UPDATE_INSTALLED_CORES_BEGIN;
if (!update_installed_handle->core_list)