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