File: fu-sbatlevel-section.c

package info (click to toggle)
fwupd 2.0.19-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 32,340 kB
  • sloc: ansic: 274,440; python: 11,468; xml: 9,432; sh: 1,625; makefile: 167; cpp: 19; asm: 11; javascript: 9
file content (169 lines) | stat: -rw-r--r-- 4,730 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
 * Copyright 2023 Canonical Ltd.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#define G_LOG_DOMAIN "FuFirmware"

#include "config.h"

#include "fu-byte-array.h"
#include "fu-csv-firmware.h"
#include "fu-input-stream.h"
#include "fu-partial-input-stream.h"
#include "fu-sbatlevel-section-struct.h"
#include "fu-sbatlevel-section.h"

G_DEFINE_TYPE(FuSbatlevelSection, fu_sbatlevel_section, FU_TYPE_FIRMWARE);

static gboolean
fu_sbatlevel_section_add_entry(FuSbatlevelSection *self,
			       GInputStream *stream,
			       gsize offset,
			       const gchar *entry_name,
			       guint64 entry_idx,
			       FuFirmwareParseFlags flags,
			       GError **error)
{
	gsize streamsz = 0;
	g_autoptr(FuFirmware) entry_fw = NULL;
	g_autoptr(GInputStream) partial_stream = NULL;

	/* stop at the null terminator */
	if (!fu_input_stream_size(stream, &streamsz, error))
		return FALSE;
	if (offset >= streamsz) {
		g_set_error(error,
			    FWUPD_ERROR,
			    FWUPD_ERROR_INVALID_DATA,
			    "offset 0x%x exceeds stream size 0x%x",
			    (guint)offset,
			    (guint)streamsz);
		return FALSE;
	}
	for (guint i = offset; i < streamsz; i++) {
		guint8 value = 0;
		if (!fu_input_stream_read_u8(stream, i, &value, error))
			return FALSE;
		if (value == 0x0) {
			streamsz = i - 1;
			break;
		}
	}

	entry_fw = fu_csv_firmware_new();
	fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "$id");
	fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "component_generation");
	fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "date_stamp");
	fu_csv_firmware_set_write_column_ids(FU_CSV_FIRMWARE(entry_fw), FALSE);

	fu_firmware_set_idx(entry_fw, entry_idx);
	fu_firmware_set_id(entry_fw, entry_name);
	fu_firmware_set_offset(entry_fw, offset);
	partial_stream = fu_partial_input_stream_new(stream, offset, streamsz - offset, error);
	if (partial_stream == NULL) {
		g_prefix_error_literal(error, "failed to cut CSV section: ");
		return FALSE;
	}
	if (!fu_firmware_parse_stream(entry_fw, partial_stream, 0, flags, error)) {
		g_prefix_error(error, "failed to parse %s: ", entry_name);
		return FALSE;
	}
	if (!fu_firmware_add_image(FU_FIRMWARE(self), entry_fw, error))
		return FALSE;

	/* success */
	return TRUE;
}

static gboolean
fu_sbatlevel_section_parse(FuFirmware *firmware,
			   GInputStream *stream,
			   FuFirmwareParseFlags flags,
			   GError **error)
{
	FuSbatlevelSection *self = FU_SBATLEVEL_SECTION(firmware);
	g_autoptr(FuStructSbatLevelSectionHeader) st = NULL;

	st = fu_struct_sbat_level_section_header_parse_stream(stream, 0x0, error);
	if (st == NULL)
		return FALSE;
	if (!fu_sbatlevel_section_add_entry(
		self,
		stream,
		sizeof(guint32) + fu_struct_sbat_level_section_header_get_previous(st),
		"previous",
		0,
		flags,
		error))
		return FALSE;
	if (!fu_sbatlevel_section_add_entry(self,
					    stream,
					    sizeof(guint32) +
						fu_struct_sbat_level_section_header_get_latest(st),
					    "latest",
					    1,
					    flags,
					    error))
		return FALSE;
	return TRUE;
}

static GByteArray *
fu_sbatlevel_section_write(FuFirmware *firmware, GError **error)
{
	g_autoptr(FuFirmware) img_ltst = NULL;
	g_autoptr(FuFirmware) img_prev = NULL;
	g_autoptr(FuStructSbatLevelSectionHeader) st = fu_struct_sbat_level_section_header_new();
	g_autoptr(GBytes) blob_ltst = NULL;
	g_autoptr(GBytes) blob_prev = NULL;

	/* previous */
	fu_struct_sbat_level_section_header_set_previous(st, sizeof(guint32) * 2);
	img_prev = fu_firmware_get_image_by_id(firmware, "previous", error);
	if (img_prev == NULL)
		return NULL;
	blob_prev = fu_firmware_write(img_prev, error);
	if (blob_prev == NULL)
		return NULL;
	fu_byte_array_append_bytes(st->buf, blob_prev);
	fu_byte_array_append_uint8(st->buf, 0x0);

	/* latest */
	fu_struct_sbat_level_section_header_set_latest(st,
						       (sizeof(guint32) * 2) +
							   g_bytes_get_size(blob_prev) + 1);
	img_ltst = fu_firmware_get_image_by_id(firmware, "latest", error);
	if (img_ltst == NULL)
		return NULL;
	blob_ltst = fu_firmware_write(img_ltst, error);
	if (blob_ltst == NULL)
		return NULL;
	fu_byte_array_append_bytes(st->buf, blob_ltst);
	fu_byte_array_append_uint8(st->buf, 0x0);

	/* success */
	return g_steal_pointer(&st->buf);
}

static void
fu_sbatlevel_section_init(FuSbatlevelSection *self)
{
	fu_firmware_set_images_max(FU_FIRMWARE(self), 2);
}

static void
fu_sbatlevel_section_class_init(FuSbatlevelSectionClass *klass)
{
	FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);

	firmware_class->parse = fu_sbatlevel_section_parse;
	firmware_class->write = fu_sbatlevel_section_write;
}

FuFirmware *
fu_sbatlevel_section_new(void)
{
	return FU_FIRMWARE(g_object_new(FU_TYPE_SBATLEVEL_SECTION, NULL));
}