Coverage Report

Created: 2026-01-09 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-cfu-payload.c
Line
Count
Source
1
/*
2
 * Copyright 2021 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#define G_LOG_DOMAIN "FuFirmware"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-cfu-firmware-struct.h"
13
#include "fu-cfu-payload.h"
14
#include "fu-input-stream.h"
15
16
/**
17
 * FuCfuPayload:
18
 *
19
 * A CFU payload. This contains of a variable number of blocks, each containing the address, size
20
 * and the chunk data. The chunks do not have to be the same size, and the address ranges do not
21
 * have to be continuous.
22
 *
23
 * Documented: https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification
24
 *
25
 * See also: [class@FuFirmware]
26
 */
27
28
1.10k
G_DEFINE_TYPE(FuCfuPayload, fu_cfu_payload, FU_TYPE_FIRMWARE)
29
1.10k
30
1.10k
static gboolean
31
1.10k
fu_cfu_payload_parse(FuFirmware *firmware,
32
1.10k
         GInputStream *stream,
33
1.10k
         FuFirmwareParseFlags flags,
34
1.10k
         GError **error)
35
1.10k
{
36
472
  gsize offset = 0;
37
472
  gsize streamsz = 0;
38
39
  /* process into chunks */
40
472
  if (!fu_input_stream_size(stream, &streamsz, error))
41
0
    return FALSE;
42
719k
  while (offset < streamsz) {
43
718k
    guint8 chunk_size = 0;
44
718k
    g_autoptr(FuChunk) chk = NULL;
45
718k
    g_autoptr(GBytes) blob = NULL;
46
718k
    g_autoptr(FuStructCfuPayload) st = NULL;
47
48
718k
    st = fu_struct_cfu_payload_parse_stream(stream, offset, error);
49
718k
    if (st == NULL)
50
31
      return FALSE;
51
718k
    offset += st->buf->len;
52
718k
    chunk_size = fu_struct_cfu_payload_get_size(st);
53
718k
    if (chunk_size == 0) {
54
17
      g_set_error_literal(error,
55
17
              FWUPD_ERROR,
56
17
              FWUPD_ERROR_INVALID_DATA,
57
17
              "payload size was invalid");
58
17
      return FALSE;
59
17
    }
60
718k
    blob = fu_input_stream_read_bytes(stream, offset, chunk_size, NULL, error);
61
718k
    if (blob == NULL)
62
5
      return FALSE;
63
718k
    chk = fu_chunk_bytes_new(blob);
64
718k
    fu_chunk_set_address(chk, fu_struct_cfu_payload_get_addr(st));
65
718k
    fu_firmware_add_chunk(firmware, chk);
66
67
    /* next! */
68
718k
    offset += chunk_size;
69
718k
  }
70
71
  /* success */
72
419
  return TRUE;
73
472
}
74
75
static GByteArray *
76
fu_cfu_payload_write(FuFirmware *firmware, GError **error)
77
390
{
78
390
  g_autoptr(GByteArray) buf = g_byte_array_new();
79
390
  g_autoptr(GPtrArray) chunks = NULL;
80
81
390
  chunks = fu_firmware_get_chunks(firmware, error);
82
390
  if (chunks == NULL)
83
0
    return NULL;
84
771k
  for (guint i = 0; i < chunks->len; i++) {
85
771k
    FuChunk *chk = g_ptr_array_index(chunks, i);
86
771k
    g_autoptr(FuStructCfuPayload) st = fu_struct_cfu_payload_new();
87
771k
    fu_struct_cfu_payload_set_addr(st, fu_chunk_get_address(chk));
88
771k
    fu_struct_cfu_payload_set_size(st, fu_chunk_get_data_sz(chk));
89
771k
    fu_byte_array_append_array(buf, st->buf);
90
771k
    g_byte_array_append(buf, fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk));
91
771k
  }
92
390
  return g_steal_pointer(&buf);
93
390
}
94
95
static void
96
fu_cfu_payload_init(FuCfuPayload *self)
97
504
{
98
504
  fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_NO_AUTO_DETECTION);
99
504
}
100
101
static void
102
fu_cfu_payload_class_init(FuCfuPayloadClass *klass)
103
1
{
104
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
105
1
  firmware_class->parse = fu_cfu_payload_parse;
106
1
  firmware_class->write = fu_cfu_payload_write;
107
1
}
108
109
/**
110
 * fu_cfu_payload_new:
111
 *
112
 * Creates a new #FuFirmware for a CFU payload
113
 *
114
 * Since: 1.7.0
115
 **/
116
FuFirmware *
117
fu_cfu_payload_new(void)
118
504
{
119
504
  return FU_FIRMWARE(g_object_new(FU_TYPE_CFU_PAYLOAD, NULL));
120
504
}