Add ctf-reader prototype
[babeltrace.git] / ctf-reader-proto / ctf-fs-metadata.c
1 /*
2 * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
4 *
5 * Some functions are based on older functions written by Mathieu Desnoyers.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include <stdio.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdbool.h>
30 #include <glib.h>
31 #include <babeltrace/compat/uuid.h>
32 #include <babeltrace/compat/memstream.h>
33
34 #define PRINT_ERR_STREAM ctf_fs->error_fp
35 #define PRINT_PREFIX "ctf-fs-metadata"
36 #include "print.h"
37
38 #include "ctf-fs.h"
39 #include "ctf-fs-file.h"
40 #include "metadata-parsing/ctf-ast.h"
41 #include "metadata-parsing/ctf-scanner.h"
42
43 #define TSDL_MAGIC 0x75d11d57
44
45 struct packet_header {
46 uint32_t magic;
47 uint8_t uuid[16];
48 uint32_t checksum;
49 uint32_t content_size;
50 uint32_t packet_size;
51 uint8_t compression_scheme;
52 uint8_t encryption_scheme;
53 uint8_t checksum_scheme;
54 uint8_t major;
55 uint8_t minor;
56 } __attribute__((__packed__));
57
58 static struct ctf_fs_file *get_file(struct ctf_fs *ctf_fs,
59 const char *trace_path)
60 {
61 struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs);
62
63 if (!file) {
64 goto error;
65 }
66
67 g_string_append(file->path, trace_path);
68 g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME);
69
70 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
71 goto error;
72 }
73
74 goto end;
75
76 error:
77 if (file) {
78 ctf_fs_file_destroy(file);
79 file = NULL;
80 }
81
82 end:
83 return file;
84 }
85
86 static
87 bool is_packetized(struct ctf_fs *ctf_fs, struct ctf_fs_file *file)
88 {
89 uint32_t magic;
90 size_t len;
91 int ret = 0;
92
93 len = fread(&magic, sizeof(magic), 1, file->fp);
94 if (len != 1) {
95 goto end;
96 }
97
98 if (magic == TSDL_MAGIC) {
99 ret = 1;
100 ctf_fs->metadata.bo = BYTE_ORDER;
101 } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
102 ret = 1;
103 ctf_fs->metadata.bo = BYTE_ORDER == BIG_ENDIAN ?
104 LITTLE_ENDIAN : BIG_ENDIAN;
105 }
106
107 end:
108 rewind(file->fp);
109
110 return ret;
111 }
112
113 static
114 bool is_version_valid(unsigned int major, unsigned int minor)
115 {
116 return major == 1 && minor == 8;
117 }
118
119 static
120 int decode_packet(struct ctf_fs *ctf_fs, FILE *in_fp, FILE *out_fp)
121 {
122 struct packet_header header;
123 size_t readlen, writelen, toread;
124 uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */
125 int ret = 0;
126
127 readlen = fread(&header, sizeof(header), 1, in_fp);
128 if (feof(in_fp) != 0) {
129 goto end;
130 }
131 if (readlen < 1) {
132 goto error;
133 }
134
135 if (ctf_fs->metadata.bo != BYTE_ORDER) {
136 header.magic = GUINT32_SWAP_LE_BE(header.magic);
137 header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
138 header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
139 header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
140 }
141
142 if (header.compression_scheme) {
143 PERR("Metadata packet compression not supported yet\n");
144 goto error;
145 }
146
147 if (header.encryption_scheme) {
148 PERR("Metadata packet encryption not supported yet\n");
149 goto error;
150 }
151
152 if (header.checksum || header.checksum_scheme) {
153 PERR("Metadata packet checksum verification not supported yet\n");
154 goto error;
155 }
156
157 if (!is_version_valid(header.major, header.minor)) {
158 PERR("Invalid metadata version: %u.%u\n", header.major,
159 header.minor);
160 goto error;
161 }
162
163 /* Set expected trace UUID if not set; otherwise validate it */
164 if (!ctf_fs->metadata.is_uuid_set) {
165 memcpy(ctf_fs->metadata.uuid, header.uuid, sizeof(header.uuid));
166 ctf_fs->metadata.is_uuid_set = true;
167 } else if (bt_uuid_compare(header.uuid, ctf_fs->metadata.uuid)) {
168 PERR("Metadata UUID mismatch between packets of the same file\n");
169 goto error;
170 }
171
172 if ((header.content_size / CHAR_BIT) < sizeof(header)) {
173 PERR("Bad metadata packet content size: %u\n",
174 header.content_size);
175 goto error;
176 }
177
178 toread = header.content_size / CHAR_BIT - sizeof(header);
179
180 for (;;) {
181 readlen = fread(buf, sizeof(uint8_t),
182 MIN(sizeof(buf) - 1, toread), in_fp);
183 if (ferror(in_fp)) {
184 PERR("Cannot read metadata packet buffer (at position %ld)\n",
185 ftell(in_fp));
186 goto error;
187 }
188
189 writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
190 if (writelen < readlen || ferror(out_fp)) {
191 PERR("Cannot write decoded metadata text to buffer\n");
192 goto error;
193 }
194
195 toread -= readlen;
196 if (toread == 0) {
197 int fseek_ret;
198
199 /* Read leftover padding */
200 toread = (header.packet_size - header.content_size) /
201 CHAR_BIT;
202 fseek_ret = fseek(in_fp, toread, SEEK_CUR);
203 if (fseek_ret < 0) {
204 PWARN("Missing padding at the end of the metadata file\n");
205 }
206
207 break;
208 }
209 }
210
211 goto end;
212
213 error:
214 ret = -1;
215
216 end:
217 return ret;
218 }
219
220 static
221 int packetized_file_to_buf(struct ctf_fs *ctf_fs, struct ctf_fs_file *file,
222 uint8_t **buf)
223 {
224 FILE *out_fp;
225 size_t size;
226 int ret = 0;
227 int tret;
228 size_t packet_index = 0;
229
230 out_fp = babeltrace_open_memstream((char **) buf, &size);
231 if (out_fp == NULL) {
232 PERR("Cannot open memory stream: %s\n", strerror(errno));
233 goto error;
234 }
235
236 for (;;) {
237 if (feof(file->fp) != 0) {
238 break;
239 }
240
241 tret = decode_packet(ctf_fs, file->fp, out_fp);
242 if (tret) {
243 PERR("Cannot decode packet #%zu\n", packet_index);
244 goto error;
245 }
246
247 packet_index++;
248 }
249
250 /* Make sure the whole string ends with a null character */
251 tret = fputc('\0', out_fp);
252 if (tret == EOF) {
253 PERR("Cannot append '\\0' to the decoded metadata buffer\n");
254 goto error;
255 }
256
257 /* Close stream, which also flushes the buffer */
258 ret = babeltrace_close_memstream((char **) buf, &size, out_fp);
259 if (ret < 0) {
260 PERR("Cannot close memory stream: %s\n", strerror(errno));
261 goto error;
262 }
263
264 goto end;
265
266 error:
267 ret = -1;
268
269 if (out_fp) {
270 babeltrace_close_memstream((char **) buf, &size, out_fp);
271 }
272
273 if (*buf) {
274 free(*buf);
275 }
276
277 end:
278 return ret;
279 }
280
281 void ctf_fs_metadata_set_trace(struct ctf_fs *ctf_fs)
282 {
283 int ret = 0;
284 struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str);
285 struct ctf_scanner *scanner = NULL;
286 uint8_t *buf = NULL;
287 char *cbuf;
288
289 if (!file) {
290 PERR("Cannot create metadata file object\n");
291 goto error;
292 }
293
294 if (babeltrace_debug) {
295 // yydebug = 1;
296 }
297
298 if (is_packetized(ctf_fs, file)) {
299 PDBG("Metadata file \"%s\" is packetized\n", file->path->str);
300 ret = packetized_file_to_buf(ctf_fs, file, &buf);
301 if (ret) {
302 // log: details
303 goto error;
304 }
305
306 cbuf = (char *) buf;
307 ctf_fs->metadata.text = (char *) cbuf;
308
309 /* Convert the real file pointer to a memory file pointer */
310 ret = fclose(file->fp);
311 file->fp = NULL;
312 if (ret) {
313 PERR("Cannot close file \"%s\": %s\n", file->path->str,
314 strerror(errno));
315 goto error;
316 }
317
318 file->fp = babeltrace_fmemopen(cbuf, strlen(cbuf), "rb");
319 if (!file->fp) {
320 PERR("Cannot memory-open metadata buffer: %s\n",
321 strerror(errno));
322 goto error;
323 }
324 } else {
325 unsigned int major, minor;
326 ssize_t nr_items;
327
328 PDBG("Metadata file \"%s\" is plain text\n", file->path->str);
329
330 /* Check text-only metadata header and version */
331 nr_items = fscanf(file->fp, "/* CTF %10u.%10u", &major, &minor);
332 if (nr_items < 2) {
333 PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file\n");
334 }
335 PDBG("Metadata version: %u.%u\n", major, minor);
336
337 if (!is_version_valid(major, minor)) {
338 PERR("Invalid metadata version: %u.%u\n", major, minor);
339 goto error;
340 }
341
342 rewind(file->fp);
343 }
344
345 /* Allocate a scanner and append the metadata text content */
346 scanner = ctf_scanner_alloc();
347 if (!scanner) {
348 PERR("Cannot allocate a metadata lexical scanner\n");
349 goto error;
350 }
351
352 ret = ctf_scanner_append_ast(scanner, file->fp);
353 if (ret) {
354 PERR("Cannot create the metadata AST\n");
355 goto error;
356 }
357
358 ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
359 if (ret) {
360 PERR("Metadata semantic validation failed\n");
361 goto error;
362 }
363
364 ret = ctf_visitor_generate_ir(ctf_fs->error_fp, &scanner->ast->root,
365 &ctf_fs->metadata.trace);
366 if (ret) {
367 PERR("Cannot create trace object from metadata AST\n");
368 goto error;
369 }
370
371 goto end;
372
373 error:
374 if (ctf_fs->metadata.text) {
375 free(ctf_fs->metadata.text);
376 ctf_fs->metadata.text = NULL;
377 }
378
379 end:
380 if (file) {
381 ctf_fs_file_destroy(file);
382 }
383
384 if (scanner) {
385 ctf_scanner_free(scanner);
386 }
387 }
388
389 int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
390 {
391 /* Nothing to initialize for the moment */
392 return 0;
393 }
394
395 void ctf_fs_metadata_deinit(struct ctf_fs_metadata *metadata)
396 {
397 if (metadata->text) {
398 free(metadata->text);
399 }
400
401 if (metadata->trace) {
402 BT_PUT(metadata->trace);
403 }
404 }
This page took 0.037381 seconds and 4 git commands to generate.