cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / plugins / ctf / common / src / metadata / tsdl / decoder-packetized-file-stream-to-buf.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
5 */
6
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10
11 #include "common/uuid.h"
12 #include "compat/memstream.h"
13
14 #include "decoder-packetized-file-stream-to-buf.hpp"
15 #include "decoder.hpp"
16
17 #define TSDL_MAGIC 0x75d11d57
18
19 struct packet_header
20 {
21 uint32_t magic;
22 bt_uuid_t uuid;
23 uint32_t checksum;
24 uint32_t content_size;
25 uint32_t packet_size;
26 uint8_t compression_scheme;
27 uint8_t encryption_scheme;
28 uint8_t checksum_scheme;
29 uint8_t major;
30 uint8_t minor;
31 } __attribute__((__packed__));
32
33 static int decode_packet(FILE *in_fp, FILE *out_fp, int byte_order, bool *is_uuid_set,
34 uint8_t *uuid, const bt2c::Logger& logger)
35 {
36 struct packet_header header;
37 size_t readlen, writelen, toread;
38 uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */
39 int ret = 0;
40 const long offset = ftell(in_fp);
41
42 if (offset < 0) {
43 BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Failed to get current metadata file position",
44 ".");
45 goto error;
46 }
47 BT_CPPLOGD_SPEC(logger, "Decoding metadata packet: offset={}", offset);
48 readlen = fread(&header, sizeof(header), 1, in_fp);
49 if (feof(in_fp) != 0) {
50 BT_CPPLOGI_SPEC(logger, "Reached end of file: offset={}", ftell(in_fp));
51 goto end;
52 }
53 if (readlen < 1) {
54 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot decode metadata packet: offset={}", offset);
55 goto error;
56 }
57
58 if (byte_order != BYTE_ORDER) {
59 header.magic = GUINT32_SWAP_LE_BE(header.magic);
60 header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
61 header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
62 header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
63 }
64
65 if (header.compression_scheme) {
66 BT_CPPLOGE_APPEND_CAUSE_SPEC(
67 logger,
68 "Metadata packet compression is not supported as of this version: "
69 "compression-scheme={}, offset={}",
70 (unsigned int) header.compression_scheme, offset);
71 goto error;
72 }
73
74 if (header.encryption_scheme) {
75 BT_CPPLOGE_APPEND_CAUSE_SPEC(
76 logger,
77 "Metadata packet encryption is not supported as of this version: "
78 "encryption-scheme={}, offset={}",
79 (unsigned int) header.encryption_scheme, offset);
80 goto error;
81 }
82
83 if (header.checksum || header.checksum_scheme) {
84 auto checksum = header.checksum;
85
86 BT_CPPLOGE_APPEND_CAUSE_SPEC(
87 logger,
88 "Metadata packet checksum verification is not supported as of this version: "
89 "checksum-scheme={}, checksum={}, offset={}",
90 (unsigned int) header.checksum_scheme, checksum, offset);
91 goto error;
92 }
93
94 if (!ctf_metadata_decoder_is_packet_version_valid(header.major, header.minor)) {
95 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
96 "Invalid metadata packet version: "
97 "version={}.{}, offset={}",
98 header.major, header.minor, offset);
99 goto error;
100 }
101
102 /* Set expected trace UUID if not set; otherwise validate it */
103 if (is_uuid_set) {
104 if (!*is_uuid_set) {
105 bt_uuid_copy(uuid, header.uuid);
106 *is_uuid_set = true;
107 } else if (bt_uuid_compare(header.uuid, uuid)) {
108 BT_CPPLOGE_APPEND_CAUSE_SPEC(
109 logger,
110 "Metadata UUID mismatch between packets of the same stream: "
111 "packet-uuid=\"" BT_UUID_FMT "\", "
112 "expected-uuid=\"" BT_UUID_FMT "\", "
113 "offset={}",
114 BT_UUID_FMT_VALUES(header.uuid), BT_UUID_FMT_VALUES(uuid), offset);
115 goto error;
116 }
117 }
118
119 if ((header.content_size / CHAR_BIT) < sizeof(header)) {
120 auto content_size = header.content_size;
121
122 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
123 "Bad metadata packet content size: content-size={}, "
124 "offset={}",
125 content_size, offset);
126 goto error;
127 }
128
129 toread = header.content_size / CHAR_BIT - sizeof(header);
130
131 for (;;) {
132 size_t loop_read;
133
134 loop_read = MIN(sizeof(buf) - 1, toread);
135 readlen = fread(buf, sizeof(uint8_t), loop_read, in_fp);
136 if (ferror(in_fp)) {
137 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
138 "Cannot read metadata packet buffer: "
139 "offset={}, read-size={}",
140 ftell(in_fp), loop_read);
141 goto error;
142 }
143 if (readlen > loop_read) {
144 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
145 "fread returned more byte than expected: "
146 "read-size-asked={}, read-size-returned={}",
147 loop_read, readlen);
148 goto error;
149 }
150
151 writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
152 if (writelen < readlen || ferror(out_fp)) {
153 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
154 "Cannot write decoded metadata text to buffer: "
155 "read-offset={}, write-size={}",
156 ftell(in_fp), readlen);
157 goto error;
158 }
159
160 toread -= readlen;
161 if (toread == 0) {
162 int fseek_ret;
163
164 /* Read leftover padding */
165 toread = (header.packet_size - header.content_size) / CHAR_BIT;
166 fseek_ret = fseek(in_fp, toread, SEEK_CUR);
167 if (fseek_ret < 0) {
168 BT_CPPLOGW_STR_SPEC(logger, "Missing padding at the end of the metadata stream.");
169 }
170 break;
171 }
172 }
173
174 goto end;
175
176 error:
177 ret = -1;
178
179 end:
180 return ret;
181 }
182
183 int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order,
184 bool *is_uuid_set, uint8_t *uuid,
185 const bt2c::Logger& parentLogger)
186 {
187 FILE *out_fp;
188 size_t size;
189 int ret = 0;
190 int tret;
191 size_t packet_index = 0;
192 bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/DECODER-DECODE-PACKET"};
193
194 out_fp = bt_open_memstream(buf, &size);
195 if (!out_fp) {
196 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot open memory stream: {}.", strerror(errno));
197 goto error;
198 }
199
200 for (;;) {
201 if (feof(fp) != 0) {
202 break;
203 }
204
205 tret = decode_packet(fp, out_fp, byte_order, is_uuid_set, uuid, logger);
206 if (tret) {
207 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot decode packet: index={}", packet_index);
208 goto error;
209 }
210
211 packet_index++;
212 }
213
214 /* Make sure the whole string ends with a null character */
215 tret = fputc('\0', out_fp);
216 if (tret == EOF) {
217 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot append '\\0' to the decoded metadata buffer.");
218 goto error;
219 }
220
221 /* Close stream, which also flushes the buffer */
222 ret = bt_close_memstream(buf, &size, out_fp);
223 /*
224 * See fclose(3). Further access to out_fp after both success
225 * and error, even through another bt_close_memstream(), results
226 * in undefined behavior. Nullify out_fp to ensure we don't
227 * fclose it twice on error.
228 */
229 out_fp = NULL;
230 if (ret < 0) {
231 BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Cannot close memory stream", ".");
232 goto error;
233 }
234
235 goto end;
236
237 error:
238 ret = -1;
239
240 if (out_fp) {
241 if (bt_close_memstream(buf, &size, out_fp)) {
242 BT_CPPLOGE_ERRNO_SPEC(logger, "Cannot close memory stream", ".");
243 }
244 }
245
246 if (*buf) {
247 free(*buf);
248 *buf = NULL;
249 }
250
251 end:
252 return ret;
253 }
This page took 0.034689 seconds and 4 git commands to generate.