diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index 23538da0b..4837cb1ee 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -284,6 +284,45 @@ fu_firmware_image_get_bytes (FuFirmwareImage *self) return g_bytes_ref (priv->bytes); } +/** + * fu_firmware_image_get_checksum: + * @self: a #FuPlugin + * @csum_kind: a #GChecksumType, e.g. %G_CHECKSUM_SHA256 + * @error: A #GError, or %NULL + * + * Returns a checksum of the data. + * + * Returns: (transfer full): a checksum string, or %NULL if the checksum is not available + * + * Since: 1.5.5 + **/ +gchar * +fu_firmware_image_get_checksum (FuFirmwareImage *self, + GChecksumType csum_kind, + GError **error) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* subclassed */ + if (klass->get_checksum != NULL) + return klass->get_checksum (self, csum_kind, error); + + /* internal data */ + if (priv->bytes == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no bytes found in firmware bytes %s", + priv->id); + return NULL; + } + return g_compute_checksum_for_bytes (csum_kind, priv->bytes); +} + /** * fu_firmware_image_parse: * @self: A #FuFirmwareImage diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index ab082466c..d7f120a85 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -31,8 +31,12 @@ struct _FuFirmwareImageClass XbNode *n, GError **error) G_GNUC_WARN_UNUSED_RESULT; + gchar *(*get_checksum)(FuFirmwareImage *self, + GChecksumType csum_kind, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; /*< private >*/ - gpointer padding[27]; + gpointer padding[26]; }; #define FU_FIRMWARE_IMAGE_ID_PAYLOAD "payload" @@ -63,6 +67,9 @@ void fu_firmware_image_set_idx (FuFirmwareImage *self, GBytes *fu_firmware_image_get_bytes (FuFirmwareImage *self); void fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes); +gchar *fu_firmware_image_get_checksum (FuFirmwareImage *self, + GChecksumType csum_kind, + GError **error); gboolean fu_firmware_image_parse (FuFirmwareImage *self, GBytes *fw, FwupdInstallFlags flags, diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index 428af51e3..bda802b46 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -671,6 +671,51 @@ fu_firmware_get_image_by_idx (FuFirmware *self, guint64 idx, GError **error) return NULL; } +/** + * fu_firmware_get_image_by_checksum: + * @self: a #FuPlugin + * @checksum: checksum string of any format + * @error: A #GError, or %NULL + * + * Gets the firmware image using the image checksum. The checksum type is guessed + * based on the length of the input string. + * + * Returns: (transfer full): a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.5.5 + **/ +FuFirmwareImage * +fu_firmware_get_image_by_checksum (FuFirmware *self, + const gchar *checksum, + GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + GChecksumType csum_kind; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), NULL); + g_return_val_if_fail (checksum != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + csum_kind = fwupd_checksum_guess_kind (checksum); + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (priv->images, i); + g_autofree gchar *checksum_tmp = NULL; + + /* if this expensive then the subclassed FuFirmwareImage can + * cache the result as required */ + checksum_tmp = fu_firmware_image_get_checksum (img, csum_kind, error); + if (checksum_tmp == NULL) + return NULL; + if (g_strcmp0 (checksum_tmp, checksum) == 0) + return g_object_ref (img); + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no image with checksum %s found in firmware", checksum); + return NULL; +} + /** * fu_firmware_get_image_by_idx_bytes: * @self: a #FuPlugin diff --git a/libfwupdplugin/fu-firmware.h b/libfwupdplugin/fu-firmware.h index 5801d7485..518ba19fd 100644 --- a/libfwupdplugin/fu-firmware.h +++ b/libfwupdplugin/fu-firmware.h @@ -128,6 +128,9 @@ FuFirmwareImage *fu_firmware_get_image_by_idx (FuFirmware *self, GBytes *fu_firmware_get_image_by_idx_bytes (FuFirmware *self, guint64 idx, GError **error); +FuFirmwareImage *fu_firmware_get_image_by_checksum (FuFirmware *self, + const gchar *checksum, + GError **error); FuFirmwareImage *fu_firmware_get_image_default (FuFirmware *self, GError **error); GBytes *fu_firmware_get_image_default_bytes (FuFirmware *self, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index e48345fe6..761361ac6 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -703,5 +703,7 @@ LIBFWUPDPLUGIN_1.5.4 { LIBFWUPDPLUGIN_1.5.5 { global: fu_device_retry_full; + fu_firmware_get_image_by_checksum; + fu_firmware_image_get_checksum; local: *; } LIBFWUPDPLUGIN_1.5.4;