Coverage Report

Created: 2025-11-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-efi-device-path-list.c
Line
Count
Source
1
/*
2
 * Copyright 2023 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#define G_LOG_DOMAIN "FuEfiDevicePath"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-efi-device-path-list.h"
13
#include "fu-efi-file-path-device-path.h"
14
#include "fu-efi-hard-drive-device-path.h"
15
#include "fu-efi-struct.h"
16
#include "fu-input-stream.h"
17
18
struct _FuEfiDevicePathList {
19
  FuFirmware parent_instance;
20
};
21
22
static void
23
fu_efi_device_path_list_codec_iface_init(FwupdCodecInterface *iface);
24
25
5.32k
G_DEFINE_TYPE_EXTENDED(FuEfiDevicePathList,
26
5.32k
           fu_efi_device_path_list,
27
5.32k
           FU_TYPE_FIRMWARE,
28
5.32k
           0,
29
5.32k
           G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC,
30
5.32k
               fu_efi_device_path_list_codec_iface_init))
31
5.32k
32
5.32k
#define FU_EFI_DEVICE_PATH_LIST_IMAGES_MAX 1000u
33
34
static const gchar *
35
fu_efi_device_path_list_gtype_to_member_name(GType gtype)
36
0
{
37
0
  if (gtype == FU_TYPE_EFI_DEVICE_PATH)
38
0
    return "Dp";
39
0
  if (gtype == FU_TYPE_EFI_FILE_PATH_DEVICE_PATH)
40
0
    return "Fp";
41
0
  if (gtype == FU_TYPE_EFI_HARD_DRIVE_DEVICE_PATH)
42
0
    return "Hd";
43
0
  return g_type_name(gtype);
44
0
}
45
46
static void
47
fu_efi_device_path_list_add_json(FwupdCodec *codec, JsonBuilder *builder, FwupdCodecFlags flags)
48
0
{
49
0
  FuFirmware *firmware = FU_FIRMWARE(codec);
50
0
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
51
52
0
  json_builder_set_member_name(builder, "DPs");
53
0
  json_builder_begin_array(builder);
54
0
  for (guint i = 0; i < imgs->len; i++) {
55
0
    FuFirmware *img = g_ptr_array_index(imgs, i);
56
0
    json_builder_begin_object(builder);
57
0
    json_builder_set_member_name(
58
0
        builder,
59
0
        fu_efi_device_path_list_gtype_to_member_name(G_OBJECT_TYPE(img)));
60
0
    json_builder_begin_object(builder);
61
0
    fwupd_codec_to_json(FWUPD_CODEC(img), builder, flags);
62
0
    json_builder_end_object(builder);
63
0
    json_builder_end_object(builder);
64
0
  }
65
0
  json_builder_end_array(builder);
66
0
}
67
68
static gboolean
69
fu_efi_device_path_list_parse(FuFirmware *firmware,
70
            GInputStream *stream,
71
            FuFirmwareParseFlags flags,
72
            GError **error)
73
1.83k
{
74
1.83k
  gsize offset = 0;
75
1.83k
  gsize streamsz = 0;
76
1.83k
  if (!fu_input_stream_size(stream, &streamsz, error))
77
0
    return FALSE;
78
26.1k
  while (offset < streamsz) {
79
25.5k
    g_autoptr(FuEfiDevicePath) efi_dp = NULL;
80
25.5k
    g_autoptr(FuStructEfiDevicePath) st_dp = NULL;
81
82
    /* parse the header so we can work out what GType to create */
83
25.5k
    st_dp = fu_struct_efi_device_path_parse_stream(stream, offset, error);
84
25.5k
    if (st_dp == NULL)
85
41
      return FALSE;
86
25.4k
    if (fu_struct_efi_device_path_get_type(st_dp) == FU_EFI_DEVICE_PATH_TYPE_END)
87
1.00k
      break;
88
24.4k
    if (fu_struct_efi_device_path_get_type(st_dp) == FU_EFI_DEVICE_PATH_TYPE_MEDIA &&
89
12.6k
        fu_struct_efi_device_path_get_subtype(st_dp) ==
90
12.6k
      FU_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE_FILE_PATH) {
91
3.33k
      efi_dp = FU_EFI_DEVICE_PATH(fu_efi_file_path_device_path_new());
92
21.1k
    } else if (fu_struct_efi_device_path_get_type(st_dp) ==
93
21.1k
             FU_EFI_DEVICE_PATH_TYPE_MEDIA &&
94
9.33k
         fu_struct_efi_device_path_get_subtype(st_dp) ==
95
9.33k
             FU_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE_HARD_DRIVE) {
96
654
      efi_dp = FU_EFI_DEVICE_PATH(fu_efi_hard_drive_device_path_new());
97
20.4k
    } else {
98
20.4k
      efi_dp = fu_efi_device_path_new();
99
20.4k
    }
100
24.4k
    fu_firmware_set_offset(FU_FIRMWARE(efi_dp), offset);
101
24.4k
    if (!fu_firmware_parse_stream(FU_FIRMWARE(efi_dp), stream, offset, flags, error))
102
209
      return FALSE;
103
24.2k
    if (!fu_firmware_add_image(firmware, FU_FIRMWARE(efi_dp), error))
104
2
      return FALSE;
105
24.2k
    offset += fu_firmware_get_size(FU_FIRMWARE(efi_dp));
106
24.2k
  }
107
108
  /* success */
109
1.58k
  return TRUE;
110
1.83k
}
111
112
static GByteArray *
113
fu_efi_device_path_list_write(FuFirmware *firmware, GError **error)
114
1.16k
{
115
1.16k
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
116
1.16k
  g_autoptr(GByteArray) buf = g_byte_array_new();
117
1.16k
  g_autoptr(FuStructEfiDevicePath) st_dp_end = NULL;
118
119
  /* add each image */
120
8.33k
  for (guint i = 0; i < imgs->len; i++) {
121
7.55k
    FuFirmware *img = g_ptr_array_index(imgs, i);
122
7.55k
    g_autoptr(GBytes) dp_blob = fu_firmware_write(img, error);
123
7.55k
    if (dp_blob == NULL)
124
389
      return NULL;
125
7.16k
    fu_byte_array_append_bytes(buf, dp_blob);
126
7.16k
  }
127
128
  /* add end marker */
129
778
  st_dp_end = fu_struct_efi_device_path_new();
130
778
  fu_struct_efi_device_path_set_type(st_dp_end, FU_EFI_DEVICE_PATH_TYPE_END);
131
778
  fu_struct_efi_device_path_set_subtype(st_dp_end, 0xFF);
132
778
  fu_byte_array_append_array(buf, st_dp_end->buf);
133
134
  /* success */
135
778
  return g_steal_pointer(&buf);
136
1.16k
}
137
138
static void
139
fu_efi_device_path_list_codec_iface_init(FwupdCodecInterface *iface)
140
1
{
141
1
  iface->add_json = fu_efi_device_path_list_add_json;
142
1
}
143
144
static void
145
fu_efi_device_path_list_class_init(FuEfiDevicePathListClass *klass)
146
1
{
147
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
148
1
  firmware_class->parse = fu_efi_device_path_list_parse;
149
1
  firmware_class->write = fu_efi_device_path_list_write;
150
1
}
151
152
static void
153
fu_efi_device_path_list_init(FuEfiDevicePathList *self)
154
2.07k
{
155
2.07k
  g_type_ensure(FU_TYPE_EFI_FILE_PATH_DEVICE_PATH);
156
2.07k
  g_type_ensure(FU_TYPE_EFI_HARD_DRIVE_DEVICE_PATH);
157
2.07k
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_EFI_DEVICE_PATH_LIST_IMAGES_MAX);
158
2.07k
}
159
160
/**
161
 * fu_efi_device_path_list_new:
162
 *
163
 * Creates a new EFI DEVICE_PATH list.
164
 *
165
 * Returns: (transfer full): a #FuEfiDevicePathList
166
 *
167
 * Since: 1.9.3
168
 **/
169
FuEfiDevicePathList *
170
fu_efi_device_path_list_new(void)
171
2.07k
{
172
2.07k
  return g_object_new(FU_TYPE_EFI_DEVICE_PATH_LIST, NULL);
173
2.07k
}