Coverage Report

Created: 2026-03-11 07:30

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
4.91k
G_DEFINE_TYPE_EXTENDED(FuEfiDevicePathList,
26
4.91k
           fu_efi_device_path_list,
27
4.91k
           FU_TYPE_FIRMWARE,
28
4.91k
           0,
29
4.91k
           G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC,
30
4.91k
               fu_efi_device_path_list_codec_iface_init))
31
4.91k
32
4.91k
#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,
48
         FwupdJsonObject *json_obj,
49
         FwupdCodecFlags flags)
50
0
{
51
0
  FuFirmware *firmware = FU_FIRMWARE(codec);
52
0
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
53
0
  g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
54
55
0
  for (guint i = 0; i < imgs->len; i++) {
56
0
    FuFirmware *img = g_ptr_array_index(imgs, i);
57
0
    g_autoptr(FwupdJsonObject) json_obj_tmp = fwupd_json_object_new();
58
0
    g_autoptr(FwupdJsonObject) json_object_tmp2 = fwupd_json_object_new();
59
0
    fwupd_codec_to_json(FWUPD_CODEC(img), json_object_tmp2, flags);
60
0
    fwupd_json_object_add_object(
61
0
        json_obj_tmp,
62
0
        fu_efi_device_path_list_gtype_to_member_name(G_OBJECT_TYPE(img)),
63
0
        json_object_tmp2);
64
0
    fwupd_json_array_add_object(json_arr, json_obj_tmp);
65
0
  }
66
0
  fwupd_json_object_add_array(json_obj, "DPs", json_arr);
67
0
}
68
69
static gboolean
70
fu_efi_device_path_list_parse(FuFirmware *firmware,
71
            GInputStream *stream,
72
            FuFirmwareParseFlags flags,
73
            GError **error)
74
1.70k
{
75
1.70k
  gsize offset = 0;
76
1.70k
  gsize streamsz = 0;
77
1.70k
  if (!fu_input_stream_size(stream, &streamsz, error))
78
0
    return FALSE;
79
24.8k
  while (offset < streamsz) {
80
24.5k
    g_autoptr(FuEfiDevicePath) efi_dp = NULL;
81
24.5k
    g_autoptr(FuStructEfiDevicePath) st_dp = NULL;
82
83
    /* parse the header so we can work out what GType to create */
84
24.5k
    st_dp = fu_struct_efi_device_path_parse_stream(stream, offset, error);
85
24.5k
    if (st_dp == NULL)
86
44
      return FALSE;
87
24.5k
    if (fu_struct_efi_device_path_get_type(st_dp) == FU_EFI_DEVICE_PATH_TYPE_END)
88
1.14k
      break;
89
23.3k
    if (fu_struct_efi_device_path_get_type(st_dp) == FU_EFI_DEVICE_PATH_TYPE_MEDIA &&
90
19.2k
        fu_struct_efi_device_path_get_subtype(st_dp) ==
91
19.2k
      FU_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE_FILE_PATH) {
92
17.7k
      efi_dp = FU_EFI_DEVICE_PATH(fu_efi_file_path_device_path_new());
93
17.7k
    } else if (fu_struct_efi_device_path_get_type(st_dp) ==
94
5.60k
             FU_EFI_DEVICE_PATH_TYPE_MEDIA &&
95
1.43k
         fu_struct_efi_device_path_get_subtype(st_dp) ==
96
1.43k
             FU_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE_HARD_DRIVE) {
97
652
      efi_dp = FU_EFI_DEVICE_PATH(fu_efi_hard_drive_device_path_new());
98
4.95k
    } else {
99
4.95k
      efi_dp = fu_efi_device_path_new();
100
4.95k
    }
101
23.3k
    fu_firmware_set_offset(FU_FIRMWARE(efi_dp), offset);
102
23.3k
    if (!fu_firmware_parse_stream(FU_FIRMWARE(efi_dp), stream, offset, flags, error))
103
213
      return FALSE;
104
23.1k
    if (!fu_firmware_add_image(firmware, FU_FIRMWARE(efi_dp), error))
105
2
      return FALSE;
106
23.1k
    offset += fu_firmware_get_size(FU_FIRMWARE(efi_dp));
107
23.1k
  }
108
109
  /* success */
110
1.45k
  return TRUE;
111
1.70k
}
112
113
static GByteArray *
114
fu_efi_device_path_list_write(FuFirmware *firmware, GError **error)
115
982
{
116
982
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
117
982
  g_autoptr(GByteArray) buf = g_byte_array_new();
118
982
  g_autoptr(FuStructEfiDevicePath) st_dp_end = NULL;
119
120
  /* add each image */
121
6.16k
  for (guint i = 0; i < imgs->len; i++) {
122
5.43k
    FuFirmware *img = g_ptr_array_index(imgs, i);
123
5.43k
    g_autoptr(GBytes) dp_blob = fu_firmware_write(img, error);
124
5.43k
    if (dp_blob == NULL)
125
245
      return NULL;
126
5.18k
    fu_byte_array_append_bytes(buf, dp_blob);
127
5.18k
  }
128
129
  /* add end marker */
130
737
  st_dp_end = fu_struct_efi_device_path_new();
131
737
  fu_struct_efi_device_path_set_type(st_dp_end, FU_EFI_DEVICE_PATH_TYPE_END);
132
737
  fu_struct_efi_device_path_set_subtype(st_dp_end, 0xFF);
133
737
  fu_byte_array_append_array(buf, st_dp_end->buf);
134
135
  /* success */
136
737
  return g_steal_pointer(&buf);
137
982
}
138
139
static void
140
fu_efi_device_path_list_codec_iface_init(FwupdCodecInterface *iface)
141
1
{
142
1
  iface->add_json = fu_efi_device_path_list_add_json;
143
1
}
144
145
static void
146
fu_efi_device_path_list_class_init(FuEfiDevicePathListClass *klass)
147
1
{
148
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
149
1
  firmware_class->parse = fu_efi_device_path_list_parse;
150
1
  firmware_class->write = fu_efi_device_path_list_write;
151
1
}
152
153
static void
154
fu_efi_device_path_list_init(FuEfiDevicePathList *self)
155
1.96k
{
156
1.96k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_DEVICE_PATH);
157
1.96k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_FILE_PATH_DEVICE_PATH);
158
1.96k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_HARD_DRIVE_DEVICE_PATH);
159
1.96k
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_EFI_DEVICE_PATH_LIST_IMAGES_MAX);
160
1.96k
}
161
162
/**
163
 * fu_efi_device_path_list_new:
164
 *
165
 * Creates a new EFI DEVICE_PATH list.
166
 *
167
 * Returns: (transfer full): a #FuEfiDevicePathList
168
 *
169
 * Since: 1.9.3
170
 **/
171
FuEfiDevicePathList *
172
fu_efi_device_path_list_new(void)
173
1.96k
{
174
1.96k
  return g_object_new(FU_TYPE_EFI_DEVICE_PATH_LIST, NULL);
175
1.96k
}