Coverage Report

Created: 2025-08-24 07:10

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