diff --git a/plugins/dfu/dfu-patch.c b/plugins/dfu/dfu-patch.c deleted file mode 100644 index d6d172fce..000000000 --- a/plugins/dfu/dfu-patch.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-patch - * @short_description: Object representing a binary patch - * - * This object represents an binary patch that can be applied on a firmware - * image. The patch itself is made up of chunks of data that have an offset - * and that can replace the data to upgrade the firmware. - * - * Note: this is one way operation -- the patch can only be used to go forwards - * and also cannot be used to truncate the existing image. - * - * See also: #DfuImage, #DfuFirmware - */ - -#include "config.h" - -#include -#include - -#include "fu-common.h" - -#include "dfu-common.h" -#include "dfu-patch.h" - -#include "fwupd-error.h" - -static void dfu_patch_finalize (GObject *object); - -typedef struct __attribute__((packed)) { - guint32 off; - guint32 sz; - guint32 flags; -} DfuPatchChunkHeader; - -typedef struct __attribute__((packed)) { - guint8 signature[4]; /* 'DfuP' */ - guint8 reserved[4]; - guint8 checksum_old[20]; /* SHA1 */ - guint8 checksum_new[20]; /* SHA1 */ -} DfuPatchFileHeader; - -typedef struct { - GBytes *checksum_old; - GBytes *checksum_new; - GPtrArray *chunks; /* of DfuPatchChunk */ -} DfuPatchPrivate; - -typedef struct { - guint32 off; - GBytes *blob; -} DfuPatchChunk; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuPatch, dfu_patch, G_TYPE_OBJECT) -#define GET_PRIVATE(o) (dfu_patch_get_instance_private (o)) - -static void -dfu_patch_class_init (DfuPatchClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = dfu_patch_finalize; -} - -static void -dfu_patch_chunk_free (DfuPatchChunk *chunk) -{ - g_bytes_unref (chunk->blob); - g_free (chunk); -} - -static void -dfu_patch_init (DfuPatch *self) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - priv->chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) dfu_patch_chunk_free); -} - -static void -dfu_patch_finalize (GObject *object) -{ - DfuPatch *self = DFU_PATCH (object); - DfuPatchPrivate *priv = GET_PRIVATE (self); - - if (priv->checksum_old != NULL) - g_bytes_unref (priv->checksum_old); - if (priv->checksum_new != NULL) - g_bytes_unref (priv->checksum_new); - g_ptr_array_unref (priv->chunks); - - G_OBJECT_CLASS (dfu_patch_parent_class)->finalize (object); -} - -/** - * dfu_patch_export: - * @self: a #DfuPatch - * @error: a #GError, or %NULL - * - * Converts the patch to a binary blob that can be stored as a file. - * - * Return value: (transfer full): blob - **/ -GBytes * -dfu_patch_export (DfuPatch *self, GError **error) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - gsize addr; - gsize sz; - guint8 *data; - - g_return_val_if_fail (DFU_IS_PATCH (self), NULL); - - /* check we have something to write */ - if (priv->chunks->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no chunks to process"); - return NULL; - } - - /* calculate the size of the new blob */ - sz = sizeof(DfuPatchFileHeader); - for (guint i = 0; i < priv->chunks->len; i++) { - DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i); - sz += sizeof(DfuPatchChunkHeader) + g_bytes_get_size (chunk->blob); - } - g_debug ("blob size is %" G_GSIZE_FORMAT, sz); - - /* actually allocate and fill in the blob */ - data = g_malloc0 (sz); - memcpy (data, "DfuP", 4); - - /* add checksums */ - if (priv->checksum_old != NULL) { - gsize csum_sz = 0; - const guint8 *csum_data = g_bytes_get_data (priv->checksum_old, &csum_sz); - if (!fu_memcpy_safe (data, sz, G_STRUCT_OFFSET(DfuPatchFileHeader,checksum_old), /* dst */ - csum_data, csum_sz, 0x0, /* src */ - csum_sz, error)) - return NULL; - } - if (priv->checksum_new != NULL) { - gsize csum_sz = 0; - const guint8 *csum_data = g_bytes_get_data (priv->checksum_new, &csum_sz); - if (!fu_memcpy_safe (data, sz, G_STRUCT_OFFSET(DfuPatchFileHeader,checksum_new), /* dst */ - csum_data, csum_sz, 0x0, /* src */ - csum_sz, error)) - return NULL; - } - - addr = sizeof(DfuPatchFileHeader); - for (guint i = 0; i < priv->chunks->len; i++) { - DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i); - DfuPatchChunkHeader chunkhdr; - gsize sz_tmp = 0; - const guint8 *data_new = g_bytes_get_data (chunk->blob, &sz_tmp); - - /* build chunk header and append data */ - chunkhdr.off = GUINT32_TO_LE (chunk->off); - chunkhdr.sz = GUINT32_TO_LE (sz_tmp); - chunkhdr.flags = 0; - - if (!fu_memcpy_safe (data, sz, addr, /* dst */ - (const guint8 *) &chunkhdr, sizeof(DfuPatchChunkHeader), 0x0, /* src */ - sizeof(DfuPatchChunkHeader), error)) - return NULL; - if (!fu_memcpy_safe (data, sz, addr + sizeof(DfuPatchChunkHeader), /* dst */ - data_new, sz_tmp, 0x0, /* src */ - sz_tmp, error)) - return NULL; - /* move up after the copied data */ - addr += sizeof(DfuPatchChunkHeader) + sz_tmp; - } - return g_bytes_new_take (data, sz); - -} - -/** - * dfu_patch_import: - * @self: a #DfuPatch - * @blob: patch data - * @error: a #GError, or %NULL - * - * Creates a patch from a serialized patch, possibly from a file. - * - * Return value: %TRUE on success - **/ -gboolean -dfu_patch_import (DfuPatch *self, GBytes *blob, GError **error) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - const guint8 *data; - gsize sz = 0; - guint32 off; - - g_return_val_if_fail (DFU_IS_PATCH (self), FALSE); - g_return_val_if_fail (blob != NULL, FALSE); - - /* cannot reuse object */ - if (priv->chunks->len > 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "patch has already been loaded"); - return FALSE; - } - - /* check minimum size */ - data = g_bytes_get_data (blob, &sz); - if (sz < sizeof(DfuPatchFileHeader) + sizeof(DfuPatchChunkHeader) + 1) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "file is too small"); - return FALSE; - } - - /* check header */ - if (memcmp (data, "DfuP", 4) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "header signature is not correct"); - return FALSE; - } - - /* get checksums */ - priv->checksum_old = g_bytes_new (data + G_STRUCT_OFFSET(DfuPatchFileHeader,checksum_old), 20); - priv->checksum_new = g_bytes_new (data + G_STRUCT_OFFSET(DfuPatchFileHeader,checksum_new), 20); - - /* look for each chunk */ - off = sizeof(DfuPatchFileHeader); - while (off < (guint32) sz) { - DfuPatchChunkHeader *chunkhdr = (DfuPatchChunkHeader *) (data + off); - DfuPatchChunk *chunk; - guint32 chunk_sz = GUINT32_FROM_LE (chunkhdr->sz); - guint32 chunk_off = GUINT32_FROM_LE (chunkhdr->off); - - /* check chunk size, assuming it can overflow */ - if (chunk_sz > sz || off + chunk_sz > sz) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "chunk offset 0x%04x outsize file size 0x%04x", - (guint) (off + chunk_sz), (guint) sz); - return FALSE; - } - chunk = g_new0 (DfuPatchChunk, 1); - chunk->off = chunk_off; - chunk->blob = g_bytes_new_from_bytes (blob, off + sizeof(DfuPatchChunkHeader), chunk_sz); - g_ptr_array_add (priv->chunks, chunk); - off += sizeof(DfuPatchChunkHeader) + chunk_sz; - } - - /* check we finished properly */ - if (off != sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "blob chunk sizes did not sum to total"); - return FALSE; - } - - /* success */ - return TRUE; -} - - -static GBytes * -dfu_patch_calculate_checksum (GBytes *blob) -{ - const guchar *data; - gsize digest_len = 20; - gsize sz = 0; - guint8 *buf = g_malloc0 (digest_len); - g_autoptr(GChecksum) csum = NULL; - csum = g_checksum_new (G_CHECKSUM_SHA1); - data = g_bytes_get_data (blob, &sz); - g_checksum_update (csum, data, (gssize) sz); - g_checksum_get_digest (csum, buf, &digest_len); - return g_bytes_new_take (buf, digest_len); -} - -typedef struct { - guint32 diff_start; - guint32 diff_end; - GBytes *blob; /* no ref */ -} DfuPatchCreateHelper; - -static void -dfu_patch_flush (DfuPatch *self, DfuPatchCreateHelper *helper) -{ - DfuPatchChunk *chunk; - DfuPatchPrivate *priv = GET_PRIVATE (self); - - if (helper->diff_end == 0xffff) - return; - g_debug ("add chunk @0x%04x (len %" G_GUINT32_FORMAT ")", - (guint) helper->diff_start, helper->diff_end - helper->diff_start + 1); - - chunk = g_new0 (DfuPatchChunk, 1); - chunk->off = helper->diff_start; - chunk->blob = g_bytes_new_from_bytes (helper->blob, chunk->off, - helper->diff_end - helper->diff_start + 1); - g_ptr_array_add (priv->chunks, chunk); - helper->diff_end = 0xffff; -} - -/** - * dfu_patch_create: - * @self: a #DfuPatch - * @blob1: a #GBytes, typically the old firmware image - * @blob2: a #GBytes, typically the new firmware image - * @error: a #GError, or %NULL - * - * Creates a patch from two blobs of memory. - * - * The blobs should ideally be the same size. If @blob2 is has grown in size - * the binary diff will still work but the algorithm will probably not perform - * well unless the majority of data has just been appended. - * - * As an additional constrainst, @blob2 cannot be smaller than @blob1, i.e. - * the firmware cannot be truncated by this format. - * - * Return value: %TRUE on success - **/ -gboolean -dfu_patch_create (DfuPatch *self, GBytes *blob1, GBytes *blob2, GError **error) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - DfuPatchCreateHelper helper; - const guint8 *data1; - const guint8 *data2; - gsize sz1 = 0; - gsize sz2 = 0; - guint32 same_sz = 0; - - g_return_val_if_fail (DFU_IS_PATCH (self), FALSE); - g_return_val_if_fail (blob1 != NULL, FALSE); - g_return_val_if_fail (blob2 != NULL, FALSE); - - /* are the blobs the same */ - if (g_bytes_equal (blob1, blob2)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "old and new binaries are the same"); - return FALSE; - } - - /* cannot reuse object */ - if (priv->chunks->len > 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "patch has already been loaded"); - return FALSE; - } - - /* get the hash of the old firmware file */ - priv->checksum_old = dfu_patch_calculate_checksum (blob1); - priv->checksum_new = dfu_patch_calculate_checksum (blob2); - - /* get the raw data, and ensure they are the same size */ - data1 = g_bytes_get_data (blob1, &sz1); - data2 = g_bytes_get_data (blob2, &sz2); - if (sz1 > sz2) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "firmware binary cannot go down, got " - "%" G_GSIZE_FORMAT " and %" G_GSIZE_FORMAT, - sz1, sz2); - return FALSE; - } - if (sz1 == sz2) { - g_debug ("binary staying same size: %" G_GSIZE_FORMAT, sz1); - } else { - g_debug ("binary growing from: %" G_GSIZE_FORMAT - " to %" G_GSIZE_FORMAT, sz1, sz2); - } - - /* start the dumb comparison algorithm */ - helper.diff_start = 0; - helper.diff_end = 0xffff; - helper.blob = blob2; - for (gsize i = 0; i < sz1 || i < sz2; i++) { - if (i < sz1 && i < sz2 && - data1[i] == data2[i]) { - /* if we got enough the same, dump what is pending */ - if (++same_sz > sizeof(DfuPatchChunkHeader) * 2) - dfu_patch_flush (self, &helper); - continue; - } - if (helper.diff_end == 0xffff) - helper.diff_start = (guint32) i; - helper.diff_end = (guint32) i; - same_sz = 0; - } - dfu_patch_flush (self, &helper); - return TRUE; -} - -static gchar * -_g_bytes_to_string (GBytes *blob) -{ - gsize sz = 0; - const guint8 *data = g_bytes_get_data (blob, &sz); - GString *str = g_string_new (NULL); - for (gsize i = 0; i < sz; i++) - g_string_append_printf (str, "%02x", (guint) data[i]); - return g_string_free (str, FALSE); -} - -/** - * dfu_patch_get_checksum_old: - * @self: a #DfuPatch - * - * Get the checksum for the old firmware image. - * - * Return value: A #GBytes, or %NULL if nothing has been loaded. - **/ -GBytes * -dfu_patch_get_checksum_old (DfuPatch *self) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - return priv->checksum_old; -} - -/** - * dfu_patch_get_checksum_new: - * @self: a #DfuPatch - * - * Get the checksum for the new firmware image. - * - * Return value: A #GBytes, or %NULL if nothing has been loaded. - **/ -GBytes * -dfu_patch_get_checksum_new (DfuPatch *self) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - return priv->checksum_new; -} - -/** - * dfu_patch_apply: - * @self: a #DfuPatch - * @blob: a #GBytes, typically the old firmware image - * @flags: a #DfuPatchApplyFlags, e.g. %DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM - * @error: a #GError, or %NULL - * - * Apply the currently loaded patch to a new firmware image. - * - * Return value: A #GBytes, typically saved as the new firmware file - **/ -GBytes * -dfu_patch_apply (DfuPatch *self, GBytes *blob, DfuPatchApplyFlags flags, GError **error) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - const guint8 *data_old; - gsize sz; - gsize sz_max = 0; - g_autofree guint8 *data_new = NULL; - g_autoptr(GBytes) blob_checksum_new = NULL; - g_autoptr(GBytes) blob_checksum = NULL; - g_autoptr(GBytes) blob_new = NULL; - - /* not loaded yet */ - if (priv->chunks->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no patches loaded"); - return NULL; - } - - /* get the hash of the old firmware file */ - blob_checksum = dfu_patch_calculate_checksum (blob); - if ((flags & DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM) == 0 && - !g_bytes_equal (blob_checksum, priv->checksum_old)) { - g_autofree gchar *actual = _g_bytes_to_string (blob_checksum); - g_autofree gchar *expect = _g_bytes_to_string (priv->checksum_old); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "checksum for source did not match, expected %s, got %s", - expect, actual); - return NULL; - } - - /* get the size of the new image size */ - for (guint i = 0; i < priv->chunks->len; i++) { - DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i); - gsize chunk_sz = g_bytes_get_size (chunk->blob); - if (chunk->off + chunk_sz > sz_max) - sz_max = chunk->off + chunk_sz; - } - - /* first, copy the data buffer */ - data_old = g_bytes_get_data (blob, &sz); - if (sz_max < sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "binary patch cannot truncate binary"); - return NULL; - } - if (sz == sz_max) { - g_debug ("binary staying same size: %" G_GSIZE_FORMAT, sz); - } else { - g_debug ("binary growing from: %" G_GSIZE_FORMAT - " to %" G_GSIZE_FORMAT, sz, sz_max); - } - - data_new = g_malloc0 (sz_max); - if (!fu_memcpy_safe (data_new, sz_max, 0x0, /* dst */ - data_old, sz, 0x0, /* src */ - MIN (sz, sz_max), error)) - return NULL; - for (guint i = 0; i < priv->chunks->len; i++) { - DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i); - const guint8 *chunk_data; - gsize chunk_sz; - - /* bigger than the total size */ - chunk_data = g_bytes_get_data (chunk->blob, &chunk_sz); - if (chunk->off + chunk_sz > sz_max) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cannot apply chunk as larger than max size"); - return NULL; - } - - /* apply one chunk */ - g_debug ("applying chunk %u/%u @0x%04x (length %" G_GSIZE_FORMAT ")", - i + 1, priv->chunks->len, chunk->off, chunk_sz); - if (!fu_memcpy_safe (data_new, sz_max, chunk->off, /* dst */ - chunk_data, chunk_sz, 0x0, /* src */ - chunk_sz, error)) - return NULL; - } - - /* check we got the desired hash */ - blob_new = g_bytes_new (data_new, sz_max); - blob_checksum_new = dfu_patch_calculate_checksum (blob_new); - if ((flags & DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM) == 0 && - !g_bytes_equal (blob_checksum_new, priv->checksum_new)) { - g_autofree gchar *actual = _g_bytes_to_string (blob_checksum_new); - g_autofree gchar *expect = _g_bytes_to_string (priv->checksum_new); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "checksum for result did not match, expected %s, got %s", - expect, actual); - return NULL; - } - - /* success */ - return g_steal_pointer (&blob_new); -} - -/** - * dfu_patch_to_string: - * @self: a #DfuPatch - * - * Returns a string representaiton of the object. - * - * Return value: NULL terminated string, or %NULL for invalid - **/ -gchar * -dfu_patch_to_string (DfuPatch *self) -{ - DfuPatchPrivate *priv = GET_PRIVATE (self); - GString *str = g_string_new (NULL); - g_autofree gchar *checksum_old = NULL; - g_autofree gchar *checksum_new = NULL; - - g_return_val_if_fail (DFU_IS_PATCH (self), NULL); - - /* add checksums */ - checksum_old = _g_bytes_to_string (priv->checksum_old); - g_string_append_printf (str, "checksum-old: %s\n", checksum_old); - checksum_new = _g_bytes_to_string (priv->checksum_new); - g_string_append_printf (str, "checksum-new: %s\n", checksum_new); - - /* add chunks */ - for (guint i = 0; i < priv->chunks->len; i++) { - DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i); - g_string_append_printf (str, "chunk #%02u 0x%04x, length %" G_GSIZE_FORMAT "\n", - i, chunk->off, g_bytes_get_size (chunk->blob)); - } - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); -} - -/** - * dfu_patch_new: - * - * Creates a new DFU patch object. - * - * Return value: a new #DfuPatch - **/ -DfuPatch * -dfu_patch_new (void) -{ - DfuPatch *self; - self = g_object_new (DFU_TYPE_PATCH, NULL); - return self; -} diff --git a/plugins/dfu/dfu-patch.h b/plugins/dfu/dfu-patch.h deleted file mode 100644 index 2004d8702..000000000 --- a/plugins/dfu/dfu-patch.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#define DFU_TYPE_PATCH (dfu_patch_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuPatch, dfu_patch, DFU, PATCH, GObject) - -struct _DfuPatchClass -{ - GObjectClass parent_class; -}; - -/** - * DfuPatchApplyFlags: - * @DFU_PATCH_APPLY_FLAG_NONE: No flags set - * @DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM: Do not check the checksum - * - * The optional flags used for applying a patch. - **/ -typedef enum { - DFU_PATCH_APPLY_FLAG_NONE = 0, - DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM = (1 << 0), - /*< private >*/ - DFU_PATCH_APPLY_FLAG_LAST -} DfuPatchApplyFlags; - -DfuPatch *dfu_patch_new (void); - -gchar *dfu_patch_to_string (DfuPatch *self); -GBytes *dfu_patch_export (DfuPatch *self, - GError **error); -gboolean dfu_patch_import (DfuPatch *self, - GBytes *blob, - GError **error); -gboolean dfu_patch_create (DfuPatch *self, - GBytes *blob1, - GBytes *blob2, - GError **error); -GBytes *dfu_patch_apply (DfuPatch *self, - GBytes *blob, - DfuPatchApplyFlags flags, - GError **error); -GBytes *dfu_patch_get_checksum_old (DfuPatch *self); -GBytes *dfu_patch_get_checksum_new (DfuPatch *self); diff --git a/plugins/dfu/dfu-self-test.c b/plugins/dfu/dfu-self-test.c index ddf9576fe..f751bebb3 100644 --- a/plugins/dfu/dfu-self-test.c +++ b/plugins/dfu/dfu-self-test.c @@ -13,7 +13,6 @@ #include "dfu-common.h" #include "dfu-device-private.h" #include "dfu-firmware.h" -#include "dfu-patch.h" #include "dfu-sector-private.h" #include "dfu-target-private.h" @@ -326,156 +325,6 @@ dfu_target_dfuse_func (void) g_assert (!ret); } -static gboolean -dfu_patch_create_from_strings (DfuPatch *patch, - const gchar *dold, - const gchar *dnew, - GError **error) -{ - guint32 sz1 = strlen (dold); - guint32 sz2 = strlen (dnew); - g_autoptr(GBytes) blob1 = g_bytes_new (dold, sz1); - g_autoptr(GBytes) blob2 = g_bytes_new (dnew, sz2); - g_debug ("compare:\n%s\n%s", dold, dnew); - return dfu_patch_create (patch, blob1, blob2, error); -} - -static void -dfu_patch_merges_func (void) -{ - const guint8 *data; - gboolean ret; - gsize sz; - g_autoptr(DfuPatch) patch = dfu_patch_new (); - g_autoptr(GBytes) blob = NULL; - g_autoptr(GError) error = NULL; - - /* check merges happen */ - ret = dfu_patch_create_from_strings (patch, "XXX", "YXY", &error); - g_assert_no_error (error); - g_assert (ret); - blob = dfu_patch_export (patch, &error); - g_assert_no_error (error); - g_assert (ret); - data = g_bytes_get_data (blob, &sz); - g_assert_cmpint (data[0x00], ==, 'D'); - g_assert_cmpint (data[0x01], ==, 'f'); - g_assert_cmpint (data[0x02], ==, 'u'); - g_assert_cmpint (data[0x03], ==, 'P'); - g_assert_cmpint (data[0x04], ==, 0x00); /* reserved */ - g_assert_cmpint (data[0x05], ==, 0x00); - g_assert_cmpint (data[0x06], ==, 0x00); - g_assert_cmpint (data[0x07], ==, 0x00); - g_assert_cmpint (data[0x08 + 0x28], ==, 0x00); /* chunk1, offset */ - g_assert_cmpint (data[0x09 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0a + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0b + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0c + 0x28], ==, 0x03); /* chunk1, size */ - g_assert_cmpint (data[0x0d + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0e + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0f + 0x28], ==, 0x00); - g_assert_cmpint (data[0x10 + 0x28], ==, 0x00); /* reserved */ - g_assert_cmpint (data[0x11 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x12 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x13 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x14 + 0x28], ==, 'Y'); - g_assert_cmpint (data[0x15 + 0x28], ==, 'X'); - g_assert_cmpint (data[0x16 + 0x28], ==, 'Y'); - g_assert_cmpint (sz, ==, 48 /* hdr */ + 12 /* chunk */ + 3 /* data */); -} - -static void -dfu_patch_apply_func (void) -{ - gboolean ret; - g_autoptr(DfuPatch) patch = dfu_patch_new (); - g_autoptr(GBytes) blob_new2 = NULL; - g_autoptr(GBytes) blob_new3 = NULL; - g_autoptr(GBytes) blob_new4 = NULL; - g_autoptr(GBytes) blob_new = NULL; - g_autoptr(GBytes) blob_old = NULL; - g_autoptr(GBytes) blob_wrong = NULL; - g_autoptr(GError) error = NULL; - - /* create a patch */ - blob_old = g_bytes_new_static ("helloworldhelloworldhelloworldhelloworld", 40); - blob_new = g_bytes_new_static ("XelloXorldhelloworldhelloworldhelloworlXXX", 42); - ret = dfu_patch_create (patch, blob_old, blob_new, &error); - g_assert_no_error (error); - g_assert (ret); - - /* apply the patch */ - blob_new2 = dfu_patch_apply (patch, blob_old, DFU_PATCH_APPLY_FLAG_NONE, &error); - g_assert_no_error (error); - g_assert (blob_new2 != NULL); - g_assert_cmpint (g_bytes_compare (blob_new, blob_new2), ==, 0); - - /* check we force the patch to an unrelated blob */ - blob_wrong = g_bytes_new_static ("wrongwrongwrongwrongwrongwrongwrongwrong", 40); - blob_new3 = dfu_patch_apply (patch, blob_wrong, DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM, &error); - g_assert_no_error (error); - g_assert (blob_new3 != NULL); - - /* check we can't apply the patch to an unrelated blob */ - blob_new4 = dfu_patch_apply (patch, blob_wrong, DFU_PATCH_APPLY_FLAG_NONE, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (blob_new4 == NULL); -} - -static void -dfu_patch_func (void) -{ - const guint8 *data; - gboolean ret; - gsize sz; - g_autoptr(DfuPatch) patch = dfu_patch_new (); - g_autoptr(DfuPatch) patch2 = dfu_patch_new (); - g_autoptr(GBytes) blob = NULL; - g_autoptr(GError) error = NULL; - g_autofree gchar *serialized_str = NULL; - - /* create binary diff */ - ret = dfu_patch_create_from_strings (patch, "XXX", "XYY", &error); - g_assert_no_error (error); - g_assert (ret); - - /* check we can serialize this object to a blob */ - blob = dfu_patch_export (patch, &error); - g_assert_no_error (error); - g_assert (ret); - data = g_bytes_get_data (blob, &sz); - g_assert_cmpint (data[0x00], ==, 'D'); - g_assert_cmpint (data[0x01], ==, 'f'); - g_assert_cmpint (data[0x02], ==, 'u'); - g_assert_cmpint (data[0x03], ==, 'P'); - g_assert_cmpint (data[0x04], ==, 0x00); /* reserved */ - g_assert_cmpint (data[0x05], ==, 0x00); - g_assert_cmpint (data[0x06], ==, 0x00); - g_assert_cmpint (data[0x07], ==, 0x00); - g_assert_cmpint (data[0x08 + 0x28], ==, 0x01); /* chunk1, offset */ - g_assert_cmpint (data[0x09 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0a + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0b + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0c + 0x28], ==, 0x02); /* chunk1, size */ - g_assert_cmpint (data[0x0d + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0e + 0x28], ==, 0x00); - g_assert_cmpint (data[0x0f + 0x28], ==, 0x00); - g_assert_cmpint (data[0x10 + 0x28], ==, 0x00); /* reserved */ - g_assert_cmpint (data[0x11 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x12 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x13 + 0x28], ==, 0x00); - g_assert_cmpint (data[0x14 + 0x28], ==, 'Y'); - g_assert_cmpint (data[0x15 + 0x28], ==, 'Y'); - g_assert_cmpint (sz, ==, 48 /* hdr */ + 12 /* chunk */ + 2 /* data */); - - /* try to load it from the serialized blob */ - ret = dfu_patch_import (patch2, blob, &error); - g_assert_no_error (error); - g_assert (ret); - serialized_str = dfu_patch_to_string (patch2); - g_debug ("serialized blob %s", serialized_str); -} - int main (int argc, char **argv) { @@ -488,9 +337,6 @@ main (int argc, char **argv) g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); /* tests go here */ - g_test_add_func ("/dfu/patch", dfu_patch_func); - g_test_add_func ("/dfu/patch{merges}", dfu_patch_merges_func); - g_test_add_func ("/dfu/patch{apply}", dfu_patch_apply_func); g_test_add_func ("/dfu/enums", dfu_enums_func); g_test_add_func ("/dfu/target(DfuSe}", dfu_target_dfuse_func); g_test_add_func ("/dfu/firmware{raw}", dfu_firmware_raw_func); diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index 748e975ae..1ffafd5de 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -13,7 +13,6 @@ #include #include "dfu-device-private.h" -#include "dfu-patch.h" #include "dfu-sector.h" #include "fu-device-locker.h" @@ -491,127 +490,6 @@ dfu_tool_bytes_replace (GBytes *data, GBytes *search, GBytes *replace) return cnt; } -static gboolean -dfu_tool_patch_dump (DfuToolPrivate *priv, gchar **values, GError **error) -{ - gsize sz = 0; - g_autofree gchar *data = NULL; - g_autofree gchar *str = NULL; - g_autoptr(DfuPatch) patch = NULL; - g_autoptr(GBytes) blob = NULL; - - if (g_strv_length (values) != 1) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected FILE.bdiff"); - return FALSE; - } - - /* load file */ - if (!g_file_get_contents (values[0], &data, &sz, error)) - return FALSE; - blob = g_bytes_new (data, sz); - - /* dump the patch to disk */ - patch = dfu_patch_new (); - if (!dfu_patch_import (patch, blob, error)) - return FALSE; - str = dfu_patch_to_string (patch); - g_print ("%s\n", str); - - /* success */ - return TRUE; -} - -static gboolean -dfu_tool_patch_apply (DfuToolPrivate *priv, gchar **values, GError **error) -{ - DfuPatchApplyFlags flags = DFU_PATCH_APPLY_FLAG_NONE; - const gchar *data_new; - gsize sz_diff = 0; - gsize sz_new = 0; - gsize sz_old = 0; - g_autofree gchar *data_diff = NULL; - g_autofree gchar *data_old = NULL; - g_autoptr(DfuPatch) patch = NULL; - g_autoptr(GBytes) blob_diff = NULL; - g_autoptr(GBytes) blob_new = NULL; - g_autoptr(GBytes) blob_old = NULL; - - if (g_strv_length (values) != 3) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected OLD.bin OUT.bdiff NEW.bin"); - return FALSE; - } - - /* allow the user to shoot themselves in the foot */ - if (priv->force) - flags |= DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM; - - if (!g_file_get_contents (values[0], &data_old, &sz_old, error)) - return FALSE; - blob_old = g_bytes_new (data_old, sz_old); - if (!g_file_get_contents (values[1], &data_diff, &sz_diff, error)) - return FALSE; - blob_diff = g_bytes_new (data_diff, sz_diff); - patch = dfu_patch_new (); - if (!dfu_patch_import (patch, blob_diff, error)) - return FALSE; - blob_new = dfu_patch_apply (patch, blob_old, flags, error); - if (blob_new == NULL) - return FALSE; - - /* save to disk */ - data_new = g_bytes_get_data (blob_new, &sz_new); - return g_file_set_contents (values[2], data_new, sz_new, error); -} - -static gboolean -dfu_tool_patch_create (DfuToolPrivate *priv, gchar **values, GError **error) -{ - const gchar *data_diff; - gsize sz_diff = 0; - gsize sz_new = 0; - gsize sz_old = 0; - g_autofree gchar *data_new = NULL; - g_autofree gchar *data_old = NULL; - g_autoptr(DfuPatch) patch = NULL; - g_autoptr(GBytes) blob_diff = NULL; - g_autoptr(GBytes) blob_new = NULL; - g_autoptr(GBytes) blob_old = NULL; - - if (g_strv_length (values) != 3) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected OLD.bin NEW.bin OUT.bdiff"); - return FALSE; - } - - /* read files */ - if (!g_file_get_contents (values[0], &data_old, &sz_old, error)) - return FALSE; - blob_old = g_bytes_new (data_old, sz_old); - if (!g_file_get_contents (values[1], &data_new, &sz_new, error)) - return FALSE; - blob_new = g_bytes_new (data_new, sz_new); - - /* create patch */ - patch = dfu_patch_new (); - if (!dfu_patch_create (patch, blob_old, blob_new, error)) - return FALSE; - blob_diff = dfu_patch_export (patch, error); - if (blob_diff == NULL) - return FALSE; - - /* save to disk */ - data_diff = g_bytes_get_data (blob_diff, &sz_diff); - return g_file_set_contents (values[2], data_diff, sz_diff, error); -} - static gboolean dfu_tool_replace_data (DfuToolPrivate *priv, gchar **values, GError **error) { @@ -2071,24 +1949,6 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Replace data in an existing firmware file"), dfu_tool_replace_data); - dfu_tool_add (priv->cmd_array, - "patch-create", - NULL, - /* TRANSLATORS: command description */ - _("Create a binary patch using two files"), - dfu_tool_patch_create); - dfu_tool_add (priv->cmd_array, - "patch-apply", - NULL, - /* TRANSLATORS: command description */ - _("Apply a binary patch"), - dfu_tool_patch_apply); - dfu_tool_add (priv->cmd_array, - "patch-dump", - NULL, - /* TRANSLATORS: command description */ - _("Dump information about a binary patch to the screen"), - dfu_tool_patch_dump); /* use animated progress bar */ priv->progressbar = fu_progressbar_new (); diff --git a/plugins/dfu/meson.build b/plugins/dfu/meson.build index d84c4c348..c82028f34 100644 --- a/plugins/dfu/meson.build +++ b/plugins/dfu/meson.build @@ -16,7 +16,6 @@ dfu = static_library( 'dfu-format-dfuse.c', 'dfu-format-raw.c', 'dfu-image.c', - 'dfu-patch.c', 'dfu-sector.c', 'dfu-target.c', 'dfu-target-stm.c',