Coverage Report

Created: 2026-08-15 06:58

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-common.h"
15
#include "fu-input-stream.h"
16
17
/**
18
 * FuCfuPayload:
19
 *
20
 * A CFU payload. This contains of a variable number of blocks, each containing the address, size
21
 * and the chunk data. The chunks do not have to be the same size, and the address ranges do not
22
 * have to be continuous.
23
 *
24
 * Documented: https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification
25
 *
26
 * See also: [class@FuFirmware]
27
 */
28
29
520
G_DEFINE_TYPE(FuCfuPayload, fu_cfu_payload, FU_TYPE_FIRMWARE)
30
520
31
520
static gboolean
32
520
fu_cfu_payload_parse(FuFirmware *firmware,
33
520
         FuInputStream *stream,
34
520
         FuFirmwareParseFlags flags,
35
520
         GError **error)
36
520
{
37
494
  gsize offset = 0;
38
494
  gsize streamsz = 0;
39
40
  /* process into chunks */
41
494
  if (!fu_input_stream_size(stream, &streamsz, error))
42
0
    return FALSE;
43
948k
  while (offset < streamsz) {
44
948k
    guint8 chunk_size = 0;
45
948k
    g_autoptr(FuChunk) chk = NULL;
46
948k
    g_autoptr(GBytes) blob = NULL;
47
948k
    g_autoptr(FuStructCfuPayload) st = NULL;
48
49
948k
    st = fu_struct_cfu_payload_parse_stream(stream, offset, error);
50
948k
    if (st == NULL)
51
37
      return FALSE;
52
53
    /* add payload structure size */
54
948k
    if (!fu_size_checked_inc(&offset, st->buf->len, error)) {
55
0
      g_prefix_error_literal(error, "payload offset overflow: ");
56
0
      return FALSE;
57
0
    }
58
59
948k
    chunk_size = fu_struct_cfu_payload_get_size(st);
60
948k
    if (chunk_size == 0) {
61
20
      g_set_error_literal(error,
62
20
              FWUPD_ERROR,
63
20
              FWUPD_ERROR_INVALID_DATA,
64
20
              "payload size was invalid");
65
20
      return FALSE;
66
20
    }
67
948k
    blob = fu_input_stream_read_bytes(stream, offset, chunk_size, NULL, error);
68
948k
    if (blob == NULL)
69
16
      return FALSE;
70
948k
    chk = fu_chunk_bytes_new(blob);
71
948k
    fu_chunk_set_address(chk, fu_struct_cfu_payload_get_addr(st));
72
948k
    fu_firmware_add_chunk(firmware, chk);
73
74
    /* next! */
75
948k
    if (!fu_size_checked_inc(&offset, chunk_size, error))
76
0
      return FALSE;
77
948k
  }
78
79
  /* success */
80
421
  return TRUE;
81
494
}
82
83
static GByteArray *
84
fu_cfu_payload_write(FuFirmware *firmware, GError **error)
85
362
{
86
362
  g_autoptr(GByteArray) buf = g_byte_array_new();
87
362
  g_autoptr(GPtrArray) chunks = NULL;
88
89
362
  chunks = fu_firmware_get_chunks(firmware, error);
90
362
  if (chunks == NULL)
91
0
    return NULL;
92
1.20M
  for (guint i = 0; i < chunks->len; i++) {
93
1.20M
    FuChunk *chk = g_ptr_array_index(chunks, i);
94
1.20M
    g_autoptr(FuStructCfuPayload) st = fu_struct_cfu_payload_new();
95
1.20M
    fu_struct_cfu_payload_set_addr(st, fu_chunk_get_address(chk));
96
1.20M
    fu_struct_cfu_payload_set_size(st, fu_chunk_get_data_sz(chk));
97
1.20M
    fu_byte_array_append_array(buf, st->buf);
98
1.20M
    g_byte_array_append(buf, fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk));
99
1.20M
  }
100
362
  return g_steal_pointer(&buf);
101
362
}
102
103
static void
104
fu_cfu_payload_init(FuCfuPayload *self)
105
519
{
106
519
  fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_NO_AUTO_DETECTION);
107
519
}
108
109
static void
110
fu_cfu_payload_class_init(FuCfuPayloadClass *klass)
111
1
{
112
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
113
1
  firmware_class->parse = fu_cfu_payload_parse;
114
1
  firmware_class->write = fu_cfu_payload_write;
115
1
  fu_firmware_set_size_max(firmware_class, 128 * FU_MB);
116
1
}
117
118
/**
119
 * fu_cfu_payload_new:
120
 *
121
 * Creates a new #FuFirmware for a CFU payload
122
 *
123
 * Since: 1.7.0
124
 **/
125
FuFirmware *
126
fu_cfu_payload_new(void)
127
519
{
128
519
  return FU_FIRMWARE(g_object_new(FU_TYPE_CFU_PAYLOAD, NULL));
129
519
}