mirror of
https://github.com/libretro/RetroArch
synced 2025-02-07 12:39:54 +00:00
Merge pull request #10871 from jdgleaver/core-update-block
Add option to selectively 'lock' (prevent modification of) installed cores
This commit is contained in:
commit
a88bc56ede
175
core_info.c
175
core_info.c
@ -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;
|
||||
}
|
||||
|
17
core_info.h
17
core_info.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user