Commit | Line | Data |
---|---|---|
3c8252a5 | 1 | /* |
0235b0db | 2 | * SPDX-License-Identifier: MIT |
3c8252a5 | 3 | * |
0235b0db | 4 | * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com> |
3c8252a5 PP |
5 | */ |
6 | ||
0f5c5d5c | 7 | #include <stdbool.h> |
c802cacb | 8 | #include <stdint.h> |
c802cacb | 9 | #include <stdlib.h> |
3c8252a5 | 10 | |
6162e6b7 | 11 | #include "common/uuid.h" |
3c8252a5 | 12 | #include "compat/memstream.h" |
3c8252a5 | 13 | |
c802cacb | 14 | #include "decoder-packetized-file-stream-to-buf.hpp" |
087cd0f5 | 15 | #include "decoder.hpp" |
3c8252a5 | 16 | |
4164020e | 17 | #define TSDL_MAGIC 0x75d11d57 |
3c8252a5 | 18 | |
4164020e SM |
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; | |
3c8252a5 PP |
31 | } __attribute__((__packed__)); |
32 | ||
4164020e | 33 | static int decode_packet(FILE *in_fp, FILE *out_fp, int byte_order, bool *is_uuid_set, |
0f5c5d5c | 34 | uint8_t *uuid, const bt2c::Logger& logger) |
3c8252a5 | 35 | { |
4164020e SM |
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) { | |
0f5c5d5c SM |
43 | BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Failed to get current metadata file position", |
44 | "."); | |
4164020e SM |
45 | goto error; |
46 | } | |
0f5c5d5c | 47 | BT_CPPLOGD_SPEC(logger, "Decoding metadata packet: offset={}", offset); |
4164020e SM |
48 | readlen = fread(&header, sizeof(header), 1, in_fp); |
49 | if (feof(in_fp) != 0) { | |
0f5c5d5c | 50 | BT_CPPLOGI_SPEC(logger, "Reached end of file: offset={}", ftell(in_fp)); |
4164020e SM |
51 | goto end; |
52 | } | |
53 | if (readlen < 1) { | |
0f5c5d5c | 54 | BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot decode metadata packet: offset={}", offset); |
4164020e SM |
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) { | |
0f5c5d5c SM |
66 | BT_CPPLOGE_APPEND_CAUSE_SPEC( |
67 | logger, | |
4164020e | 68 | "Metadata packet compression is not supported as of this version: " |
0f5c5d5c | 69 | "compression-scheme={}, offset={}", |
4164020e SM |
70 | (unsigned int) header.compression_scheme, offset); |
71 | goto error; | |
72 | } | |
73 | ||
74 | if (header.encryption_scheme) { | |
0f5c5d5c SM |
75 | BT_CPPLOGE_APPEND_CAUSE_SPEC( |
76 | logger, | |
4164020e | 77 | "Metadata packet encryption is not supported as of this version: " |
0f5c5d5c | 78 | "encryption-scheme={}, offset={}", |
4164020e SM |
79 | (unsigned int) header.encryption_scheme, offset); |
80 | goto error; | |
81 | } | |
82 | ||
83 | if (header.checksum || header.checksum_scheme) { | |
0f5c5d5c SM |
84 | auto checksum = header.checksum; |
85 | ||
86 | BT_CPPLOGE_APPEND_CAUSE_SPEC( | |
87 | logger, | |
4164020e | 88 | "Metadata packet checksum verification is not supported as of this version: " |
0f5c5d5c SM |
89 | "checksum-scheme={}, checksum={}, offset={}", |
90 | (unsigned int) header.checksum_scheme, checksum, offset); | |
4164020e SM |
91 | goto error; |
92 | } | |
93 | ||
94 | if (!ctf_metadata_decoder_is_packet_version_valid(header.major, header.minor)) { | |
0f5c5d5c SM |
95 | BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, |
96 | "Invalid metadata packet version: " | |
97 | "version={}.{}, offset={}", | |
98 | header.major, header.minor, offset); | |
4164020e SM |
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)) { | |
0f5c5d5c SM |
108 | BT_CPPLOGE_APPEND_CAUSE_SPEC( |
109 | logger, | |
4164020e SM |
110 | "Metadata UUID mismatch between packets of the same stream: " |
111 | "packet-uuid=\"" BT_UUID_FMT "\", " | |
112 | "expected-uuid=\"" BT_UUID_FMT "\", " | |
0f5c5d5c | 113 | "offset={}", |
4164020e SM |
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)) { | |
0f5c5d5c SM |
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); | |
4164020e SM |
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)) { | |
0f5c5d5c SM |
137 | BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, |
138 | "Cannot read metadata packet buffer: " | |
139 | "offset={}, read-size={}", | |
140 | ftell(in_fp), loop_read); | |
4164020e SM |
141 | goto error; |
142 | } | |
143 | if (readlen > loop_read) { | |
0f5c5d5c SM |
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); | |
4164020e SM |
148 | goto error; |
149 | } | |
150 | ||
151 | writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp); | |
152 | if (writelen < readlen || ferror(out_fp)) { | |
0f5c5d5c SM |
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); | |
4164020e SM |
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) { | |
e27adb90 | 168 | BT_CPPLOGW_SPEC(logger, "Missing padding at the end of the metadata stream."); |
4164020e SM |
169 | } |
170 | break; | |
171 | } | |
172 | } | |
173 | ||
174 | goto end; | |
3c8252a5 PP |
175 | |
176 | error: | |
4164020e | 177 | ret = -1; |
3c8252a5 PP |
178 | |
179 | end: | |
4164020e | 180 | return ret; |
3c8252a5 PP |
181 | } |
182 | ||
4164020e SM |
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, | |
0f5c5d5c | 185 | const bt2c::Logger& parentLogger) |
3c8252a5 | 186 | { |
4164020e SM |
187 | FILE *out_fp; |
188 | size_t size; | |
189 | int ret = 0; | |
190 | int tret; | |
191 | size_t packet_index = 0; | |
0f5c5d5c | 192 | bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/DECODER-DECODE-PACKET"}; |
4164020e SM |
193 | |
194 | out_fp = bt_open_memstream(buf, &size); | |
195 | if (!out_fp) { | |
0f5c5d5c | 196 | BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot open memory stream: {}.", strerror(errno)); |
4164020e SM |
197 | goto error; |
198 | } | |
199 | ||
200 | for (;;) { | |
201 | if (feof(fp) != 0) { | |
202 | break; | |
203 | } | |
204 | ||
0f5c5d5c | 205 | tret = decode_packet(fp, out_fp, byte_order, is_uuid_set, uuid, logger); |
4164020e | 206 | if (tret) { |
0f5c5d5c | 207 | BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot decode packet: index={}", packet_index); |
4164020e SM |
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) { | |
0f5c5d5c | 217 | BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot append '\\0' to the decoded metadata buffer."); |
4164020e SM |
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) { | |
0f5c5d5c | 231 | BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Cannot close memory stream", "."); |
4164020e SM |
232 | goto error; |
233 | } | |
234 | ||
235 | goto end; | |
3c8252a5 PP |
236 | |
237 | error: | |
4164020e | 238 | ret = -1; |
3c8252a5 | 239 | |
4164020e SM |
240 | if (out_fp) { |
241 | if (bt_close_memstream(buf, &size, out_fp)) { | |
0f5c5d5c | 242 | BT_CPPLOGE_ERRNO_SPEC(logger, "Cannot close memory stream", "."); |
4164020e SM |
243 | } |
244 | } | |
3c8252a5 | 245 | |
4164020e SM |
246 | if (*buf) { |
247 | free(*buf); | |
248 | *buf = NULL; | |
249 | } | |
3c8252a5 PP |
250 | |
251 | end: | |
4164020e | 252 | return ret; |
3c8252a5 | 253 | } |