mirror of
https://git.proxmox.com/git/fwupd
synced 2025-07-27 12:54:58 +00:00
Use libxmlb bound parameters to speed up te device verification
This means we only parse the complicated xpath query once, rather than for every GUID the device has. The code flow is also simplified and split out into two functions.
This commit is contained in:
parent
664b8aa9ad
commit
35ac0727d3
189
src/fu-engine.c
189
src/fu-engine.c
@ -785,6 +785,115 @@ fu_engine_get_component_by_guids (FuEngine *self, FuDevice *device)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static XbNode *
|
||||
fu_engine_verify_from_local_metadata (FuEngine *self,
|
||||
FuDevice *device,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree gchar *fn = NULL;
|
||||
g_autofree gchar *localstatedir = NULL;
|
||||
g_autofree gchar *xpath = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
g_autoptr(XbBuilder) builder = xb_builder_new ();
|
||||
g_autoptr(XbBuilderSource) source = xb_builder_source_new ();
|
||||
g_autoptr(XbNode) release = NULL;
|
||||
g_autoptr(XbSilo) silo = NULL;
|
||||
|
||||
localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
|
||||
fn = g_strdup_printf ("%s/verify/%s.xml",
|
||||
localstatedir,
|
||||
fu_device_get_id (device));
|
||||
file = g_file_new_for_path (fn);
|
||||
if (!g_file_query_exists (file, NULL)) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_FOUND,
|
||||
"failed to find %s", fn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!xb_builder_source_load_file (source, file,
|
||||
XB_BUILDER_SOURCE_FLAG_NONE,
|
||||
NULL, error))
|
||||
return NULL;
|
||||
xb_builder_import_source (builder, source);
|
||||
silo = xb_builder_compile (builder,
|
||||
XB_BUILDER_COMPILE_FLAG_NONE,
|
||||
NULL, error);
|
||||
if (silo == NULL)
|
||||
return NULL;
|
||||
xpath = g_strdup_printf ("component/releases/release[@version='%s']",
|
||||
fu_device_get_version (device));
|
||||
release = xb_silo_query_first (silo, xpath, error);
|
||||
if (release == NULL)
|
||||
return NULL;
|
||||
|
||||
/* silo has to have same lifecyle as node */
|
||||
g_object_set_data_full (G_OBJECT (release), "XbSilo",
|
||||
g_steal_pointer (&silo),
|
||||
(GDestroyNotify) g_object_unref);
|
||||
return g_steal_pointer (&release);
|
||||
}
|
||||
|
||||
static XbNode *
|
||||
fu_engine_verify_from_system_metadata (FuEngine *self,
|
||||
FuDevice *device,
|
||||
GError **error)
|
||||
{
|
||||
FwupdVersionFormat fmt = fu_device_get_version_format (device);
|
||||
GPtrArray *guids = fu_device_get_guids (device);
|
||||
g_autoptr(XbQuery) query = NULL;
|
||||
|
||||
/* prepare query with bound GUID parameter */
|
||||
query = xb_query_new_full (self->silo,
|
||||
"components/component/"
|
||||
"provides/firmware[@type='flashed'][text()=?]/"
|
||||
"../../releases/release",
|
||||
XB_QUERY_FLAG_OPTIMIZE |
|
||||
XB_QUERY_FLAG_USE_INDEXES,
|
||||
error);
|
||||
if (query == NULL)
|
||||
return NULL;
|
||||
|
||||
/* use prepared query for each GUID */
|
||||
for (guint i = 0; i < guids->len; i++) {
|
||||
const gchar *guid = g_ptr_array_index (guids, i);
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
g_autoptr(GPtrArray) releases = NULL;
|
||||
|
||||
/* bind GUID and then query */
|
||||
if (!xb_query_bind_str (query, 0, guid, error)) {
|
||||
g_prefix_error (error, "failed to bind string: ");
|
||||
return NULL;
|
||||
}
|
||||
releases = xb_silo_query_full (self->silo, query, &error_local);
|
||||
if (releases == NULL) {
|
||||
if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) ||
|
||||
g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
|
||||
g_debug ("could not find %s: %s",
|
||||
guid, error_local->message);
|
||||
continue;
|
||||
}
|
||||
g_propagate_error (error, g_steal_pointer (&error_local));
|
||||
return NULL;
|
||||
}
|
||||
for (guint j = 0; j < releases->len; j++) {
|
||||
XbNode *rel = g_ptr_array_index (releases, j);
|
||||
const gchar *rel_ver = xb_node_get_attr (rel, "version");
|
||||
g_autofree gchar *tmp_ver = fu_common_version_parse_from_format (rel_ver, fmt);
|
||||
if (fu_common_vercmp_full (tmp_ver, fu_device_get_version (device), fmt) == 0)
|
||||
return g_object_ref (rel);
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_FOUND,
|
||||
"failed to find release");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_engine_verify:
|
||||
* @self: A #FuEngine
|
||||
@ -800,15 +909,11 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error)
|
||||
{
|
||||
FuPlugin *plugin;
|
||||
GPtrArray *checksums;
|
||||
const gchar *version;
|
||||
g_autofree gchar *fn = NULL;
|
||||
g_autofree gchar *localstatedir = NULL;
|
||||
g_autoptr(FuDevice) device = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
g_autoptr(GString) xpath_csum = g_string_new (NULL);
|
||||
g_autoptr(XbNode) csum = NULL;
|
||||
g_autoptr(XbNode) release = NULL;
|
||||
g_autoptr(XbSilo) silo = xb_silo_new ();
|
||||
|
||||
g_return_val_if_fail (FU_IS_ENGINE (self), FALSE);
|
||||
g_return_val_if_fail (device_id != NULL, FALSE);
|
||||
@ -833,71 +938,34 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* find component in metadata */
|
||||
version = fu_device_get_version (device);
|
||||
localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
|
||||
fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id);
|
||||
file = g_file_new_for_path (fn);
|
||||
if (g_file_query_exists (file, NULL)) {
|
||||
g_autofree gchar *xpath = NULL;
|
||||
g_autoptr(XbBuilder) builder = xb_builder_new ();
|
||||
g_autoptr(XbBuilderSource) source = xb_builder_source_new ();
|
||||
if (!xb_builder_source_load_file (source, file,
|
||||
XB_BUILDER_SOURCE_FLAG_NONE,
|
||||
NULL, error))
|
||||
/* find component in local metadata */
|
||||
release = fu_engine_verify_from_local_metadata (self, device, &error_local);
|
||||
if (release == NULL) {
|
||||
if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
|
||||
!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
|
||||
g_propagate_error (error, g_steal_pointer (&error_local));
|
||||
return FALSE;
|
||||
xb_builder_import_source (builder, source);
|
||||
silo = xb_builder_compile (builder,
|
||||
XB_BUILDER_COMPILE_FLAG_NONE,
|
||||
NULL, error);
|
||||
if (silo == NULL)
|
||||
return FALSE;
|
||||
xpath = g_strdup_printf ("component/releases/release[@version='%s']", version);
|
||||
release = xb_silo_query_first (silo, xpath, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* try again with the system metadata */
|
||||
if (release == NULL) {
|
||||
GPtrArray *guids = fu_device_get_guids (device);
|
||||
FwupdVersionFormat fmt = fu_device_get_version_format (device);
|
||||
for (guint i = 0; i < guids->len; i++) {
|
||||
const gchar *guid = g_ptr_array_index (guids, i);
|
||||
g_autofree gchar *xpath2 = NULL;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
g_autoptr(GPtrArray) releases = NULL;
|
||||
xpath2 = g_strdup_printf ("components/component/"
|
||||
"provides/firmware[@type='flashed'][text()='%s']/"
|
||||
"../../releases/release",
|
||||
guid);
|
||||
releases = xb_silo_query (self->silo, xpath2, 0, &error_local);
|
||||
if (releases == NULL) {
|
||||
if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) ||
|
||||
g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
|
||||
g_debug ("could not find %s: %s",
|
||||
guid, error_local->message);
|
||||
continue;
|
||||
}
|
||||
g_propagate_error (error, g_steal_pointer (&error_local));
|
||||
g_autoptr(GError) error_system = NULL;
|
||||
release = fu_engine_verify_from_system_metadata (self, device, &error_system);
|
||||
if (release == NULL) {
|
||||
if (!g_error_matches (error_system, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
|
||||
!g_error_matches (error_system, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
|
||||
g_propagate_error (error, g_steal_pointer (&error_system));
|
||||
return FALSE;
|
||||
}
|
||||
for (guint j = 0; j < releases->len; j++) {
|
||||
XbNode *rel = g_ptr_array_index (releases, j);
|
||||
const gchar *rel_ver = xb_node_get_attr (rel, "version");
|
||||
g_autofree gchar *tmp_ver = fu_common_version_parse_from_format (rel_ver, fmt);
|
||||
if (fu_common_vercmp_full (tmp_ver, version, fmt) == 0) {
|
||||
release = g_object_ref (rel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (release != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (release == NULL) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_FOUND,
|
||||
"No release found for version %s", version);
|
||||
"No release found for version %s",
|
||||
fu_device_get_version (device));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -907,7 +975,8 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error)
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_FOUND,
|
||||
"No device checksums for %s", version);
|
||||
"No device checksums for %s",
|
||||
fu_device_get_version (device));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -938,7 +1007,7 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error)
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_FOUND,
|
||||
"No stored checksums for %s",
|
||||
version);
|
||||
fu_device_get_version (device));
|
||||
return FALSE;
|
||||
}
|
||||
for (guint i = 0; i < csums->len; i++) {
|
||||
@ -955,7 +1024,7 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error)
|
||||
FWUPD_ERROR_NOT_FOUND,
|
||||
"For %s %s expected %s, got %s",
|
||||
fu_device_get_name (device),
|
||||
version,
|
||||
fu_device_get_version (device),
|
||||
checksums_metadata->str,
|
||||
checksums_device->str);
|
||||
return FALSE;
|
||||
|
Loading…
Reference in New Issue
Block a user