/src/fwupd/libfwupdplugin/fu-sbatlevel-section.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2023 Canonical Ltd. |
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-csv-firmware.h" |
13 | | #include "fu-input-stream.h" |
14 | | #include "fu-partial-input-stream.h" |
15 | | #include "fu-sbatlevel-section-struct.h" |
16 | | #include "fu-sbatlevel-section.h" |
17 | | |
18 | | G_DEFINE_TYPE(FuSbatlevelSection, fu_sbatlevel_section, FU_TYPE_FIRMWARE); |
19 | | |
20 | | static gboolean |
21 | | fu_sbatlevel_section_add_entry(FuFirmware *firmware, |
22 | | GInputStream *stream, |
23 | | gsize offset, |
24 | | const gchar *entry_name, |
25 | | guint64 entry_idx, |
26 | | FuFirmwareParseFlags flags, |
27 | | GError **error) |
28 | 0 | { |
29 | 0 | gsize streamsz = 0; |
30 | 0 | g_autoptr(FuFirmware) entry_fw = NULL; |
31 | 0 | g_autoptr(GInputStream) partial_stream = NULL; |
32 | | |
33 | | /* stop at the null terminator */ |
34 | 0 | if (!fu_input_stream_size(stream, &streamsz, error)) |
35 | 0 | return FALSE; |
36 | 0 | for (guint i = offset; i < streamsz; i++) { |
37 | 0 | guint8 value = 0; |
38 | 0 | if (!fu_input_stream_read_u8(stream, i, &value, error)) |
39 | 0 | return FALSE; |
40 | 0 | if (value == 0x0) { |
41 | 0 | streamsz = i - 1; |
42 | 0 | break; |
43 | 0 | } |
44 | 0 | } |
45 | | |
46 | 0 | entry_fw = fu_csv_firmware_new(); |
47 | 0 | fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "$id"); |
48 | 0 | fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "component_generation"); |
49 | 0 | fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "date_stamp"); |
50 | 0 | fu_csv_firmware_set_write_column_ids(FU_CSV_FIRMWARE(entry_fw), FALSE); |
51 | |
|
52 | 0 | fu_firmware_set_idx(entry_fw, entry_idx); |
53 | 0 | fu_firmware_set_id(entry_fw, entry_name); |
54 | 0 | fu_firmware_set_offset(entry_fw, offset); |
55 | 0 | partial_stream = fu_partial_input_stream_new(stream, offset, streamsz - offset, error); |
56 | 0 | if (partial_stream == NULL) { |
57 | 0 | g_prefix_error(error, "failed to cut CSV section: "); |
58 | 0 | return FALSE; |
59 | 0 | } |
60 | 0 | if (!fu_firmware_parse_stream(entry_fw, partial_stream, 0, flags, error)) { |
61 | 0 | g_prefix_error(error, "failed to parse %s: ", entry_name); |
62 | 0 | return FALSE; |
63 | 0 | } |
64 | 0 | if (!fu_firmware_add_image_full(firmware, entry_fw, error)) |
65 | 0 | return FALSE; |
66 | | |
67 | | /* success */ |
68 | 0 | return TRUE; |
69 | 0 | } |
70 | | |
71 | | static gboolean |
72 | | fu_sbatlevel_section_parse(FuFirmware *firmware, |
73 | | GInputStream *stream, |
74 | | FuFirmwareParseFlags flags, |
75 | | GError **error) |
76 | 0 | { |
77 | 0 | g_autoptr(GByteArray) st = NULL; |
78 | |
|
79 | 0 | st = fu_struct_sbat_level_section_header_parse_stream(stream, 0x0, error); |
80 | 0 | if (st == NULL) |
81 | 0 | return FALSE; |
82 | 0 | if (!fu_sbatlevel_section_add_entry( |
83 | 0 | firmware, |
84 | 0 | stream, |
85 | 0 | sizeof(guint32) + fu_struct_sbat_level_section_header_get_previous(st), |
86 | 0 | "previous", |
87 | 0 | 0, |
88 | 0 | flags, |
89 | 0 | error)) |
90 | 0 | return FALSE; |
91 | 0 | if (!fu_sbatlevel_section_add_entry(firmware, |
92 | 0 | stream, |
93 | 0 | sizeof(guint32) + |
94 | 0 | fu_struct_sbat_level_section_header_get_latest(st), |
95 | 0 | "latest", |
96 | 0 | 1, |
97 | 0 | flags, |
98 | 0 | error)) |
99 | 0 | return FALSE; |
100 | 0 | return TRUE; |
101 | 0 | } |
102 | | |
103 | | static GByteArray * |
104 | | fu_sbatlevel_section_write(FuFirmware *firmware, GError **error) |
105 | 0 | { |
106 | 0 | g_autoptr(FuFirmware) img_ltst = NULL; |
107 | 0 | g_autoptr(FuFirmware) img_prev = NULL; |
108 | 0 | g_autoptr(GByteArray) buf = fu_struct_sbat_level_section_header_new(); |
109 | 0 | g_autoptr(GBytes) blob_ltst = NULL; |
110 | 0 | g_autoptr(GBytes) blob_prev = NULL; |
111 | | |
112 | | /* previous */ |
113 | 0 | fu_struct_sbat_level_section_header_set_previous(buf, sizeof(guint32) * 2); |
114 | 0 | img_prev = fu_firmware_get_image_by_id(firmware, "previous", error); |
115 | 0 | if (img_prev == NULL) |
116 | 0 | return NULL; |
117 | 0 | blob_prev = fu_firmware_write(img_prev, error); |
118 | 0 | if (blob_prev == NULL) |
119 | 0 | return NULL; |
120 | 0 | fu_byte_array_append_bytes(buf, blob_prev); |
121 | 0 | fu_byte_array_append_uint8(buf, 0x0); |
122 | | |
123 | | /* latest */ |
124 | 0 | fu_struct_sbat_level_section_header_set_latest(buf, |
125 | 0 | (sizeof(guint32) * 2) + |
126 | 0 | g_bytes_get_size(blob_prev) + 1); |
127 | 0 | img_ltst = fu_firmware_get_image_by_id(firmware, "latest", error); |
128 | 0 | if (img_ltst == NULL) |
129 | 0 | return NULL; |
130 | 0 | blob_ltst = fu_firmware_write(img_ltst, error); |
131 | 0 | if (blob_ltst == NULL) |
132 | 0 | return NULL; |
133 | 0 | fu_byte_array_append_bytes(buf, blob_ltst); |
134 | 0 | fu_byte_array_append_uint8(buf, 0x0); |
135 | | |
136 | | /* success */ |
137 | 0 | return g_steal_pointer(&buf); |
138 | 0 | } |
139 | | |
140 | | static void |
141 | | fu_sbatlevel_section_init(FuSbatlevelSection *self) |
142 | 0 | { |
143 | 0 | fu_firmware_set_images_max(FU_FIRMWARE(self), 2); |
144 | 0 | } |
145 | | |
146 | | static void |
147 | | fu_sbatlevel_section_class_init(FuSbatlevelSectionClass *klass) |
148 | 0 | { |
149 | 0 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
150 | |
|
151 | 0 | firmware_class->parse = fu_sbatlevel_section_parse; |
152 | 0 | firmware_class->write = fu_sbatlevel_section_write; |
153 | 0 | } |
154 | | |
155 | | FuFirmware * |
156 | | fu_sbatlevel_section_new(void) |
157 | 0 | { |
158 | 0 | return FU_FIRMWARE(g_object_new(FU_TYPE_SBATLEVEL_SECTION, NULL)); |
159 | 0 | } |