ctf.fs source: use last path parameter's element as base for trace names
[babeltrace.git] / plugins / ctf / fs-src / fs.c
CommitLineData
7a278c8e 1/*
ea0b4b9e 2 * fs.c
7a278c8e 3 *
ea0b4b9e 4 * Babeltrace CTF file system Reader Component
7a278c8e 5 *
1a9f7075 6 * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
f3bc2010 7 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7a278c8e 8 *
7a278c8e
JG
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
4bd72b60 28#include <babeltrace/common-internal.h>
5b29e799 29#include <babeltrace/ctf-ir/packet.h>
ac0c6bdd 30#include <babeltrace/ctf-ir/clock-class.h>
94cf822e
PP
31#include <babeltrace/ctf-ir/stream.h>
32#include <babeltrace/ctf-ir/fields.h>
4f1f88a6 33#include <babeltrace/graph/private-port.h>
b2e0c907 34#include <babeltrace/graph/private-component.h>
4f1f88a6
PP
35#include <babeltrace/graph/private-component-source.h>
36#include <babeltrace/graph/private-notification-iterator.h>
b2e0c907
PP
37#include <babeltrace/graph/component.h>
38#include <babeltrace/graph/notification-iterator.h>
599faa1c 39#include <babeltrace/graph/clock-class-priority-map.h>
7d61fa8e 40#include <plugins-common.h>
ea0b4b9e
JG
41#include <glib.h>
42#include <assert.h>
94cf822e 43#include <inttypes.h>
c55a9f58 44#include <stdbool.h>
56a1cced
JG
45#include <unistd.h>
46#include "fs.h"
413bc2c4 47#include "metadata.h"
94cf822e 48#include "data-stream-file.h"
e7a4393b 49#include "file.h"
1e649dff 50#include "../common/metadata/decoder.h"
e7a4393b
JG
51
52#define PRINT_ERR_STREAM ctf_fs->error_fp
53#define PRINT_PREFIX "ctf-fs"
cd00e1d3
MD
54#define PRINT_DBG_CHECK ctf_fs_debug
55#include "../print.h"
33f93973 56#define METADATA_TEXT_SIG "/* CTF 1.8"
ea0b4b9e 57
78bb6992
MD
58BT_HIDDEN
59bool ctf_fs_debug;
ea0b4b9e 60
94cf822e
PP
61static
62int notif_iter_data_set_current_ds_file(struct ctf_fs_notif_iter_data *notif_iter_data)
63{
64 struct ctf_fs_ds_file_info *ds_file_info;
65 int ret = 0;
66
67 assert(notif_iter_data->ds_file_info_index <
68 notif_iter_data->ds_file_group->ds_file_infos->len);
69 ds_file_info = g_ptr_array_index(
70 notif_iter_data->ds_file_group->ds_file_infos,
71 notif_iter_data->ds_file_info_index);
72
73 ctf_fs_ds_file_destroy(notif_iter_data->ds_file);
74 notif_iter_data->ds_file = ctf_fs_ds_file_create(
75 notif_iter_data->ds_file_group->ctf_fs_trace,
76 notif_iter_data->ds_file_group->stream,
77 ds_file_info->path->str, true);
78 if (!notif_iter_data->ds_file) {
79 ret = -1;
80 }
81
82 return ret;
83}
84
85static
86void ctf_fs_notif_iter_data_destroy(
87 struct ctf_fs_notif_iter_data *notif_iter_data)
88{
89 if (!notif_iter_data) {
90 return;
91 }
92
93 ctf_fs_ds_file_destroy(notif_iter_data->ds_file);
94 g_free(notif_iter_data);
95}
96
41a2b7ae 97struct bt_notification_iterator_next_return ctf_fs_iterator_next(
4f1f88a6 98 struct bt_private_notification_iterator *iterator)
ea0b4b9e 99{
94cf822e
PP
100 struct bt_notification_iterator_next_return next_ret;
101 struct ctf_fs_notif_iter_data *notif_iter_data =
4f1f88a6 102 bt_private_notification_iterator_get_user_data(iterator);
94cf822e
PP
103 int ret;
104
105 assert(notif_iter_data->ds_file);
106 next_ret = ctf_fs_ds_file_next(notif_iter_data->ds_file);
107 if (next_ret.status == BT_NOTIFICATION_ITERATOR_STATUS_END) {
108 assert(!next_ret.notification);
109 notif_iter_data->ds_file_info_index++;
110
111 if (notif_iter_data->ds_file_info_index ==
112 notif_iter_data->ds_file_group->ds_file_infos->len) {
113 /*
114 * No more stream files to read: we reached the
115 * real end.
116 */
117 goto end;
118 }
119
120 /*
121 * Open and start reading the next stream file within
122 * our stream file group.
123 */
124 ret = notif_iter_data_set_current_ds_file(notif_iter_data);
125 if (ret) {
126 next_ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
127 goto end;
128 }
129
130 next_ret = ctf_fs_ds_file_next(notif_iter_data->ds_file);
131
132 /*
133 * We should not get BT_NOTIFICATION_ITERATOR_STATUS_END
134 * with a brand new stream file because empty stream
135 * files are not even part of stream file groups, which
136 * means we're sure to get at least one pair of "packet
137 * begin" and "packet end" notifications in the case of
138 * a single, empty packet.
139 */
140 assert(next_ret.status != BT_NOTIFICATION_ITERATOR_STATUS_END);
141 }
d01e0f33 142
94cf822e
PP
143end:
144 return next_ret;
ea0b4b9e 145}
bfd20a42 146
4f1f88a6 147void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it)
760051fa 148{
94cf822e 149 void *notif_iter_data =
4f1f88a6 150 bt_private_notification_iterator_get_user_data(it);
760051fa 151
94cf822e 152 ctf_fs_notif_iter_data_destroy(notif_iter_data);
760051fa
JG
153}
154
4f1f88a6
PP
155enum bt_notification_iterator_status ctf_fs_iterator_init(
156 struct bt_private_notification_iterator *it,
157 struct bt_private_port *port)
4c1456f0 158{
4f1f88a6 159 struct ctf_fs_port_data *port_data;
94cf822e 160 struct ctf_fs_notif_iter_data *notif_iter_data = NULL;
4f1f88a6
PP
161 enum bt_notification_iterator_status ret =
162 BT_NOTIFICATION_ITERATOR_STATUS_OK;
94cf822e 163 int iret;
760051fa 164
4f1f88a6
PP
165 port_data = bt_private_port_get_user_data(port);
166 if (!port_data) {
fe8ad2b6 167 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
4f1f88a6
PP
168 goto error;
169 }
5b29e799 170
94cf822e
PP
171 notif_iter_data = g_new0(struct ctf_fs_notif_iter_data, 1);
172 if (!notif_iter_data) {
173 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
174 goto error;
175 }
176
177 notif_iter_data->ds_file_group = port_data->ds_file_group;
178 iret = notif_iter_data_set_current_ds_file(notif_iter_data);
179 if (iret) {
180 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
4f1f88a6 181 goto error;
760051fa
JG
182 }
183
94cf822e 184 ret = bt_private_notification_iterator_set_user_data(it, notif_iter_data);
4f1f88a6
PP
185 if (ret) {
186 goto error;
760051fa
JG
187 }
188
94cf822e 189 notif_iter_data = NULL;
4f1f88a6 190 goto end;
5b29e799 191
4f1f88a6
PP
192error:
193 (void) bt_private_notification_iterator_set_user_data(it, NULL);
194
195 if (ret == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
196 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
760051fa 197 }
5b29e799 198
760051fa 199end:
94cf822e 200 ctf_fs_notif_iter_data_destroy(notif_iter_data);
760051fa
JG
201 return ret;
202}
203
760051fa 204static
1a9f7075 205void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
760051fa 206{
4f1f88a6 207 if (!ctf_fs) {
8fa760ba
JG
208 return;
209 }
4f1f88a6 210
1a9f7075
PP
211 if (ctf_fs->traces) {
212 g_ptr_array_free(ctf_fs->traces, TRUE);
56a1cced 213 }
4f1f88a6
PP
214
215 if (ctf_fs->port_data) {
216 g_ptr_array_free(ctf_fs->port_data, TRUE);
c14d7e26 217 }
760051fa 218
1a9f7075
PP
219 g_free(ctf_fs);
220}
221
222static
223void ctf_fs_trace_destroy(void *data)
224{
225 struct ctf_fs_trace *ctf_fs_trace = data;
226
227 if (!ctf_fs_trace) {
228 return;
229 }
230
94cf822e
PP
231 if (ctf_fs_trace->ds_file_groups) {
232 g_ptr_array_free(ctf_fs_trace->ds_file_groups, TRUE);
233 }
234
1a9f7075
PP
235 if (ctf_fs_trace->path) {
236 g_string_free(ctf_fs_trace->path, TRUE);
4f1f88a6 237 }
760051fa 238
1a9f7075
PP
239 if (ctf_fs_trace->name) {
240 g_string_free(ctf_fs_trace->name, TRUE);
241 }
242
243 if (ctf_fs_trace->metadata) {
244 ctf_fs_metadata_fini(ctf_fs_trace->metadata);
245 g_free(ctf_fs_trace->metadata);
246 }
247
248 bt_put(ctf_fs_trace->cc_prio_map);
249 g_free(ctf_fs_trace);
4c1456f0
JG
250}
251
4f1f88a6 252void ctf_fs_finalize(struct bt_private_component *component)
a4792757 253{
4f1f88a6
PP
254 void *data = bt_private_component_get_user_data(component);
255
1a9f7075 256 ctf_fs_destroy(data);
a4792757
JG
257}
258
e7a4393b 259static
4f1f88a6
PP
260void port_data_destroy(void *data) {
261 struct ctf_fs_port_data *port_data = data;
262
263 if (!port_data) {
264 return;
265 }
266
4f1f88a6 267 g_free(port_data);
5b29e799
JG
268}
269
270static
1a9f7075 271int create_one_port_for_trace(struct ctf_fs_trace *ctf_fs_trace,
94cf822e 272 struct ctf_fs_ds_file_group *ds_file_group)
5b29e799 273{
4f1f88a6
PP
274 int ret = 0;
275 struct bt_private_port *port = NULL;
276 struct ctf_fs_port_data *port_data = NULL;
277 GString *port_name = NULL;
1a9f7075 278 struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
94cf822e
PP
279 struct ctf_fs_ds_file_info *ds_file_info =
280 g_ptr_array_index(ds_file_group->ds_file_infos, 0);
4f1f88a6
PP
281
282 port_name = g_string_new(NULL);
283 if (!port_name) {
284 goto error;
285 }
286
94cf822e
PP
287 /*
288 * Assign the name for the new output port. If there's more than
289 * one stream file in the stream file group, the first
290 * (earliest) stream file's path is used.
291 */
292 assert(ds_file_group->ds_file_infos->len > 0);
293 ds_file_info = g_ptr_array_index(ds_file_group->ds_file_infos, 0);
294 g_string_assign(port_name, ds_file_info->path->str);
1a9f7075 295 PDBG("Creating one port named `%s`\n", port_name->str);
4f1f88a6
PP
296
297 /* Create output port for this file */
4f1f88a6
PP
298 port_data = g_new0(struct ctf_fs_port_data, 1);
299 if (!port_data) {
300 goto error;
301 }
302
94cf822e 303 port_data->ds_file_group = ds_file_group;
3e9b0023
PP
304 port = bt_private_component_source_add_output_private_port(
305 ctf_fs->priv_comp, port_name->str, port_data);
306 if (!port) {
4f1f88a6
PP
307 goto error;
308 }
309
310 g_ptr_array_add(ctf_fs->port_data, port_data);
311 port_data = NULL;
312 goto end;
313
314error:
315 ret = -1;
316
317end:
318 if (port_name) {
319 g_string_free(port_name, TRUE);
320 }
321
322 bt_put(port);
323 port_data_destroy(port_data);
324 return ret;
5b29e799
JG
325}
326
327static
1a9f7075 328int create_ports_for_trace(struct ctf_fs_trace *ctf_fs_trace)
94cf822e
PP
329{
330 int ret = 0;
331 struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
332 size_t i;
333
334 /* Create one output port for each stream file group */
335 for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
336 struct ctf_fs_ds_file_group *ds_file_group =
337 g_ptr_array_index(ctf_fs_trace->ds_file_groups, i);
338
339 ret = create_one_port_for_trace(ctf_fs_trace, ds_file_group);
340 if (ret) {
341 PERR("Cannot create output port.\n");
342 goto end;
343 }
344 }
345
346end:
347 return ret;
348}
349
350uint64_t get_packet_header_stream_instance_id(struct ctf_fs_trace *ctf_fs_trace,
351 struct bt_ctf_field *packet_header_field)
352{
353 struct bt_ctf_field *stream_instance_id_field = NULL;
354 uint64_t stream_instance_id = -1ULL;
355 int ret;
356
357 if (!packet_header_field) {
358 goto end;
359 }
360
361 stream_instance_id_field = bt_ctf_field_structure_get_field_by_name(
362 packet_header_field, "stream_instance_id");
363 if (!stream_instance_id_field) {
364 goto end;
365 }
366
367 ret = bt_ctf_field_unsigned_integer_get_value(stream_instance_id_field,
368 &stream_instance_id);
369 if (ret) {
370 stream_instance_id = -1ULL;
371 goto end;
372 }
373
374end:
375 bt_put(stream_instance_id_field);
376 return stream_instance_id;
377}
378
379struct bt_ctf_stream_class *stream_class_from_packet_header(
380 struct ctf_fs_trace *ctf_fs_trace,
381 struct bt_ctf_field *packet_header_field)
382{
383 struct bt_ctf_field *stream_id_field = NULL;
384 struct bt_ctf_stream_class *stream_class = NULL;
385 uint64_t stream_id = -1ULL;
386 int ret;
387
388 if (!packet_header_field) {
389 goto single_stream_class;
390 }
391
392 stream_id_field = bt_ctf_field_structure_get_field_by_name(
393 packet_header_field, "stream_id");
394 if (!stream_id_field) {
395 goto end;
396 }
397
398 ret = bt_ctf_field_unsigned_integer_get_value(stream_id_field,
399 &stream_id);
400 if (ret) {
401 stream_id = -1ULL;
402 }
403
404 if (stream_id == -1ULL) {
405single_stream_class:
406 /* Single stream class */
407 if (bt_ctf_trace_get_stream_class_count(
408 ctf_fs_trace->metadata->trace) == 0) {
409 goto end;
410 }
411
412 stream_class = bt_ctf_trace_get_stream_class_by_index(
413 ctf_fs_trace->metadata->trace, 0);
414 } else {
415 stream_class = bt_ctf_trace_get_stream_class_by_id(
416 ctf_fs_trace->metadata->trace, stream_id);
417 }
418
419end:
420 bt_put(stream_id_field);
421 return stream_class;
422}
423
424uint64_t get_packet_context_timestamp_begin_ns(
425 struct ctf_fs_trace *ctf_fs_trace,
426 struct bt_ctf_field *packet_context_field)
427{
428 int ret;
429 struct bt_ctf_field *timestamp_begin_field = NULL;
430 struct bt_ctf_field_type *timestamp_begin_ft = NULL;
431 uint64_t timestamp_begin_raw_value = -1ULL;
432 uint64_t timestamp_begin_ns = -1ULL;
433 int64_t timestamp_begin_ns_signed;
434 struct bt_ctf_clock_class *timestamp_begin_clock_class = NULL;
435 struct bt_ctf_clock_value *clock_value = NULL;
436
437 if (!packet_context_field) {
438 goto end;
439 }
440
441 timestamp_begin_field = bt_ctf_field_structure_get_field_by_name(
442 packet_context_field, "timestamp_begin");
443 if (!timestamp_begin_field) {
444 goto end;
445 }
446
447 timestamp_begin_ft = bt_ctf_field_get_type(timestamp_begin_field);
448 assert(timestamp_begin_ft);
449 timestamp_begin_clock_class =
450 bt_ctf_field_type_integer_get_mapped_clock_class(timestamp_begin_ft);
451 if (!timestamp_begin_clock_class) {
452 goto end;
453 }
454
455 ret = bt_ctf_field_unsigned_integer_get_value(timestamp_begin_field,
456 &timestamp_begin_raw_value);
457 if (ret) {
458 goto end;
459 }
460
461 clock_value = bt_ctf_clock_value_create(timestamp_begin_clock_class,
462 timestamp_begin_raw_value);
463 if (!clock_value) {
464 goto end;
465 }
466
467 ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value,
468 &timestamp_begin_ns_signed);
469 if (ret) {
470 goto end;
471 }
472
473 timestamp_begin_ns = (uint64_t) timestamp_begin_ns_signed;
474
475end:
476 bt_put(timestamp_begin_field);
477 bt_put(timestamp_begin_ft);
478 bt_put(timestamp_begin_clock_class);
479 bt_put(clock_value);
480 return timestamp_begin_ns;
481}
482
483static
484void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
485{
486 if (!ds_file_info) {
487 return;
488 }
489
490 if (ds_file_info->path) {
491 g_string_free(ds_file_info->path, TRUE);
492 }
493
494 g_free(ds_file_info);
495}
496
497static
498struct ctf_fs_ds_file_info *ctf_fs_ds_file_info_create(const char *path,
499 uint64_t begin_ns)
500{
501 struct ctf_fs_ds_file_info *ds_file_info;
502
503 ds_file_info = g_new0(struct ctf_fs_ds_file_info, 1);
504 if (!ds_file_info) {
505 goto end;
506 }
507
508 ds_file_info->path = g_string_new(path);
509 if (!ds_file_info->path) {
510 ctf_fs_ds_file_info_destroy(ds_file_info);
511 ds_file_info = NULL;
512 goto end;
513 }
514
515 ds_file_info->begin_ns = begin_ns;
516
517end:
518 return ds_file_info;
519}
520
521static
522void ctf_fs_ds_file_group_destroy(struct ctf_fs_ds_file_group *ds_file_group)
523{
524 if (!ds_file_group) {
525 return;
526 }
527
528 if (ds_file_group->ds_file_infos) {
529 g_ptr_array_free(ds_file_group->ds_file_infos, TRUE);
530 }
531
532 bt_put(ds_file_group->stream);
533 g_free(ds_file_group);
534}
535
536static
537struct ctf_fs_ds_file_group *ctf_fs_ds_file_group_create(
538 struct ctf_fs_trace *ctf_fs_trace,
539 struct bt_ctf_stream_class *stream_class,
540 uint64_t stream_instance_id)
541{
542 struct ctf_fs_ds_file_group *ds_file_group;
543
544 assert(stream_class);
545 ds_file_group = g_new0(struct ctf_fs_ds_file_group, 1);
546 if (!ds_file_group) {
547 goto error;
548 }
549
550 ds_file_group->ds_file_infos = g_ptr_array_new_with_free_func(
551 (GDestroyNotify) ctf_fs_ds_file_info_destroy);
552 if (!ds_file_group->ds_file_infos) {
553 goto error;
554 }
555
556 if (stream_instance_id == -1ULL) {
557 ds_file_group->stream = bt_ctf_stream_create(
558 stream_class, NULL);
559 } else {
560 ds_file_group->stream = bt_ctf_stream_create_with_id(
561 stream_class, NULL, stream_instance_id);
562 }
563
564 if (!ds_file_group->stream) {
565 goto error;
566 }
567
568 ds_file_group->ctf_fs_trace = ctf_fs_trace;
569
570 goto end;
571
572error:
573 ctf_fs_ds_file_group_destroy(ds_file_group);
574 ds_file_group = NULL;
575
576end:
577 return ds_file_group;
578}
579
580static
581int ctf_fs_ds_file_group_add_ds_file_info(
582 struct ctf_fs_ds_file_group *ds_file_group,
583 const char *path, uint64_t begin_ns)
584{
585 struct ctf_fs_ds_file_info *ds_file_info;
586 gint i = 0;
587 int ret = 0;
588
589 ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
590 if (!ds_file_info) {
591 goto error;
592 }
593
594 /* Find a spot to insert this one */
595 for (i = 0; i < ds_file_group->ds_file_infos->len; i++) {
596 struct ctf_fs_ds_file_info *other_ds_file_info =
597 g_ptr_array_index(ds_file_group->ds_file_infos, i);
598
599 if (begin_ns < other_ds_file_info->begin_ns) {
600 break;
601 }
602 }
603
604 if (i == ds_file_group->ds_file_infos->len) {
605 /* Append instead */
606 i = -1;
607 }
608
609 g_ptr_array_insert(ds_file_group->ds_file_infos, i, ds_file_info);
610 ds_file_info = NULL;
611 goto end;
612
613error:
614 ctf_fs_ds_file_info_destroy(ds_file_info);
615 ret = -1;
616
617end:
618 return ret;
619}
620
621static
622int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
623 const char *path)
624{
625 struct bt_ctf_field *packet_header_field = NULL;
626 struct bt_ctf_field *packet_context_field = NULL;
627 struct bt_ctf_stream_class *stream_class = NULL;
628 struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
629 uint64_t stream_instance_id = -1ULL;
630 uint64_t begin_ns = -1ULL;
631 struct ctf_fs_ds_file_group *ds_file_group = NULL;
632 bool add_group = false;
633 int ret;
634 size_t i;
635
636 ret = ctf_fs_ds_file_get_packet_header_context_fields(
637 ctf_fs_trace, path, &packet_header_field,
638 &packet_context_field);
639 if (ret) {
640 PERR("Cannot get stream file's first packet's header and context fields (`%s`).\n",
641 path);
642 goto error;
643 }
644
645 stream_instance_id = get_packet_header_stream_instance_id(ctf_fs_trace,
646 packet_header_field);
647 begin_ns = get_packet_context_timestamp_begin_ns(ctf_fs_trace,
648 packet_context_field);
649 stream_class = stream_class_from_packet_header(ctf_fs_trace,
650 packet_header_field);
651 if (!stream_class) {
652 goto error;
653 }
654
655 if (begin_ns == -1ULL) {
656 /*
657 * No beggining timestamp to sort the stream files
658 * within a stream file group, so consider that this
659 * file must be the only one within its group.
660 */
661 stream_instance_id = -1ULL;
662 }
663
664 if (stream_instance_id == -1ULL) {
665 /*
666 * No stream instance ID or no beginning timestamp:
667 * create a unique stream file group for this stream
668 * file because, even if there's a stream instance ID,
669 * there's no timestamp to order the file within its
670 * group.
671 */
672
673 ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace,
674 stream_class, stream_instance_id);
675 if (!ds_file_group) {
676 goto error;
677 }
678
679 ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group,
680 path, begin_ns);
681 if (ret) {
682 goto error;
683 }
684
685 add_group = true;
686 goto end;
687 }
688
689 assert(stream_instance_id != -1ULL);
690 assert(begin_ns != -1ULL);
691
692 /* Find an existing stream file group with this ID */
693 for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
694 int64_t id;
695 struct bt_ctf_stream_class *cand_stream_class;
696
697 ds_file_group = g_ptr_array_index(
698 ctf_fs_trace->ds_file_groups, i);
699 id = bt_ctf_stream_get_id(ds_file_group->stream);
700 cand_stream_class = bt_ctf_stream_get_class(
701 ds_file_group->stream);
702
703 assert(cand_stream_class);
704 bt_put(cand_stream_class);
705
706 if (cand_stream_class == stream_class &&
707 (uint64_t) id == stream_instance_id) {
708 break;
709 }
710
711 ds_file_group = NULL;
712 }
713
714 if (!ds_file_group) {
715 ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace,
716 stream_class, stream_instance_id);
717 if (!ds_file_group) {
718 goto error;
719 }
720
721 add_group = true;
722 }
723
724 ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group,
725 path, begin_ns);
726 if (ret) {
727 goto error;
728 }
729
730 goto end;
731
732error:
733 ctf_fs_ds_file_group_destroy(ds_file_group);
734 ret = -1;
735
736end:
737 if (add_group && ds_file_group) {
738 g_ptr_array_add(ctf_fs_trace->ds_file_groups, ds_file_group);
739 }
740
741 bt_put(packet_header_field);
742 bt_put(packet_context_field);
743 bt_put(stream_class);
744 return ret;
745}
746
747static
748int create_ds_file_groups(struct ctf_fs_trace *ctf_fs_trace)
e7a4393b
JG
749{
750 int ret = 0;
4f1f88a6 751 const char *basename;
e7a4393b 752 GError *error = NULL;
4f1f88a6 753 GDir *dir = NULL;
1a9f7075 754 struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
e7a4393b 755
94cf822e 756 /* Check each file in the path directory, except specific ones */
1a9f7075 757 dir = g_dir_open(ctf_fs_trace->path->str, 0, &error);
e7a4393b 758 if (!dir) {
4f1f88a6 759 PERR("Cannot open directory `%s`: %s (code %d)\n",
1a9f7075 760 ctf_fs_trace->path->str, error->message,
4f1f88a6 761 error->code);
e7a4393b
JG
762 goto error;
763 }
764
4f1f88a6 765 while ((basename = g_dir_read_name(dir))) {
94cf822e
PP
766 struct ctf_fs_file *file;
767
4f1f88a6 768 if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) {
e7a4393b 769 /* Ignore the metadata stream. */
1a9f7075
PP
770 PDBG("Ignoring metadata file `%s/%s`\n",
771 ctf_fs_trace->path->str, basename);
e7a4393b
JG
772 continue;
773 }
774
4f1f88a6 775 if (basename[0] == '.') {
1a9f7075
PP
776 PDBG("Ignoring hidden file `%s/%s`\n",
777 ctf_fs_trace->path->str, basename);
e7a4393b
JG
778 continue;
779 }
780
781 /* Create the file. */
782 file = ctf_fs_file_create(ctf_fs);
783 if (!file) {
1a9f7075
PP
784 PERR("Cannot create stream file object for file `%s/%s`\n",
785 ctf_fs_trace->path->str, basename);
e7a4393b
JG
786 goto error;
787 }
788
789 /* Create full path string. */
790 g_string_append_printf(file->path, "%s/%s",
1a9f7075 791 ctf_fs_trace->path->str, basename);
e7a4393b 792 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
1a9f7075
PP
793 PDBG("Ignoring non-regular file `%s`\n",
794 file->path->str);
e7a4393b 795 ctf_fs_file_destroy(file);
4f1f88a6 796 file = NULL;
e7a4393b
JG
797 continue;
798 }
799
4f1f88a6
PP
800 ret = ctf_fs_file_open(ctf_fs, file, "rb");
801 if (ret) {
1a9f7075 802 PERR("Cannot open stream file `%s`\n", file->path->str);
e7a4393b
JG
803 goto error;
804 }
805
9fa0891a
JG
806 if (file->size == 0) {
807 /* Skip empty stream. */
1a9f7075 808 PDBG("Ignoring empty file `%s`\n", file->path->str);
9fa0891a
JG
809 ctf_fs_file_destroy(file);
810 continue;
811 }
812
94cf822e
PP
813 ret = add_ds_file_to_ds_file_group(ctf_fs_trace,
814 file->path->str);
4f1f88a6 815 if (ret) {
94cf822e 816 PDBG("Cannot add stream file `%s` to stream file group\n",
1a9f7075 817 file->path->str);
94cf822e 818 ctf_fs_file_destroy(file);
e7a4393b
JG
819 goto error;
820 }
821
4f1f88a6 822 ctf_fs_file_destroy(file);
e7a4393b
JG
823 }
824
825 goto end;
4f1f88a6 826
e7a4393b
JG
827error:
828 ret = -1;
4f1f88a6 829
e7a4393b
JG
830end:
831 if (dir) {
832 g_dir_close(dir);
833 dir = NULL;
834 }
4f1f88a6 835
e7a4393b
JG
836 if (error) {
837 g_error_free(error);
838 }
5b29e799 839
91457551 840 return ret;
5b29e799
JG
841}
842
599faa1c 843static
1a9f7075 844int create_cc_prio_map(struct ctf_fs_trace *ctf_fs_trace)
599faa1c
PP
845{
846 int ret = 0;
847 size_t i;
848 int count;
849
1a9f7075
PP
850 assert(ctf_fs_trace);
851 ctf_fs_trace->cc_prio_map = bt_clock_class_priority_map_create();
852 if (!ctf_fs_trace->cc_prio_map) {
599faa1c
PP
853 ret = -1;
854 goto end;
855 }
856
1a9f7075
PP
857 count = bt_ctf_trace_get_clock_class_count(
858 ctf_fs_trace->metadata->trace);
599faa1c
PP
859 assert(count >= 0);
860
861 for (i = 0; i < count; i++) {
862 struct bt_ctf_clock_class *clock_class =
9ac68eb1 863 bt_ctf_trace_get_clock_class_by_index(
1a9f7075 864 ctf_fs_trace->metadata->trace, i);
599faa1c
PP
865
866 assert(clock_class);
867 ret = bt_clock_class_priority_map_add_clock_class(
1a9f7075 868 ctf_fs_trace->cc_prio_map, clock_class, 0);
599faa1c
PP
869 BT_PUT(clock_class);
870
871 if (ret) {
872 goto end;
873 }
874 }
875
876end:
877 return ret;
878}
879
1a9f7075
PP
880static
881struct ctf_fs_trace *ctf_fs_trace_create(struct ctf_fs_component *ctf_fs,
882 const char *path, const char *name)
883{
884 struct ctf_fs_trace *ctf_fs_trace;
885 int ret;
886
887 ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
888 if (!ctf_fs_trace) {
889 goto end;
890 }
891
892 ctf_fs_trace->ctf_fs = ctf_fs;
893 ctf_fs_trace->path = g_string_new(path);
894 if (!ctf_fs_trace->path) {
895 goto error;
896 }
897
898 ctf_fs_trace->name = g_string_new(name);
899 if (!ctf_fs_trace->name) {
900 goto error;
901 }
902
903 ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1);
904 if (!ctf_fs_trace->metadata) {
905 goto error;
906 }
907
94cf822e
PP
908 ctf_fs_trace->ds_file_groups = g_ptr_array_new_with_free_func(
909 (GDestroyNotify) ctf_fs_ds_file_group_destroy);
910 if (!ctf_fs_trace->ds_file_groups) {
911 goto error;
912 }
913
1a9f7075
PP
914 ret = ctf_fs_metadata_set_trace(ctf_fs_trace);
915 if (ret) {
916 goto error;
917 }
918
94cf822e
PP
919 ret = create_ds_file_groups(ctf_fs_trace);
920 if (ret) {
921 goto error;
922 }
923
1a9f7075
PP
924 ret = create_cc_prio_map(ctf_fs_trace);
925 if (ret) {
926 goto error;
927 }
928
929 ret = create_ports_for_trace(ctf_fs_trace);
930 if (ret) {
931 goto error;
932 }
933
27d1a78b
PP
934 /*
935 * create_ds_file_groups() created all the streams that this
936 * trace needs. There won't be any more. Therefore it is safe to
937 * make this trace static.
938 */
939 (void) bt_ctf_trace_set_is_static(ctf_fs_trace->metadata->trace);
940
1a9f7075
PP
941 goto end;
942
943error:
944 ctf_fs_trace_destroy(ctf_fs_trace);
945 ctf_fs_trace = NULL;
946end:
947 return ctf_fs_trace;
948}
949
950static
951int path_is_ctf_trace(const char *path)
952{
953 GString *metadata_path = g_string_new(NULL);
954 int ret = 0;
955
956 if (!metadata_path) {
957 ret = -1;
958 goto end;
959 }
960
961 g_string_printf(metadata_path, "%s/%s", path, CTF_FS_METADATA_FILENAME);
962
963 if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) {
964 ret = 1;
965 goto end;
966 }
967
968end:
969 g_string_free(metadata_path, TRUE);
970 return ret;
971}
972
973static
974int add_trace_path(struct ctf_fs_component *ctf_fs, GList **trace_paths,
975 const char *path)
976{
4bd72b60 977 GString *norm_path = NULL;
1a9f7075 978 int ret = 0;
1a9f7075 979
4bd72b60
PP
980 norm_path = bt_common_normalize_path(path, NULL);
981 if (!norm_path) {
982 PERR("Failed to normalize path `%s`.\n", path);
1a9f7075
PP
983 ret = -1;
984 goto end;
985 }
986
4bd72b60 987 if (strcmp(norm_path->str, "/") == 0) {
1a9f7075
PP
988 PERR("Opening a trace in `/` is not supported.\n");
989 ret = -1;
990 goto end;
991 }
992
4bd72b60 993 *trace_paths = g_list_prepend(*trace_paths, norm_path);
1a9f7075 994 assert(*trace_paths);
4bd72b60 995 norm_path = NULL;
1a9f7075
PP
996
997end:
4bd72b60
PP
998 if (norm_path) {
999 g_string_free(norm_path, TRUE);
1000 }
1001
1a9f7075
PP
1002 return ret;
1003}
1004
1005static
1006int find_ctf_traces(struct ctf_fs_component *ctf_fs,
1007 GList **trace_paths, const char *start_path)
1008{
1009 int ret;
1010 GError *error = NULL;
1011 GDir *dir = NULL;
1012 const char *basename = NULL;
1013
1014 /* Check if the starting path is a CTF trace itself */
1015 ret = path_is_ctf_trace(start_path);
1016 if (ret < 0) {
1017 goto end;
1018 }
1019
1020 if (ret) {
1021 /*
4bd72b60
PP
1022 * Stop recursion: a CTF trace cannot contain another
1023 * CTF trace.
1a9f7075
PP
1024 */
1025 ret = add_trace_path(ctf_fs, trace_paths, start_path);
1026 goto end;
1027 }
1028
1029 /* Look for subdirectories */
1030 if (!g_file_test(start_path, G_FILE_TEST_IS_DIR)) {
1031 /* Starting path is not a directory: end of recursion */
1032 goto end;
1033 }
1034
1035 dir = g_dir_open(start_path, 0, &error);
1036 if (!dir) {
1037 if (error->code == G_FILE_ERROR_ACCES) {
1038 PDBG("Cannot open directory `%s`: %s (code %d): continuing\n",
1039 start_path, error->message, error->code);
1040 goto end;
1041 }
1042
1043 PERR("Cannot open directory `%s`: %s (code %d)\n",
1044 start_path, error->message, error->code);
1045 ret = -1;
1046 goto end;
1047 }
1048
1049 while ((basename = g_dir_read_name(dir))) {
1050 GString *sub_path = g_string_new(NULL);
1051
1052 if (!sub_path) {
1053 ret = -1;
1054 goto end;
1055 }
1056
1057 g_string_printf(sub_path, "%s/%s", start_path, basename);
1058 ret = find_ctf_traces(ctf_fs, trace_paths, sub_path->str);
1059 g_string_free(sub_path, TRUE);
1060 if (ret) {
1061 goto end;
1062 }
1063 }
1064
1065end:
1066 if (dir) {
1067 g_dir_close(dir);
1068 }
1069
1070 if (error) {
1071 g_error_free(error);
1072 }
1073
1074 return ret;
1075}
1076
1077static
4bd72b60 1078GList *create_trace_names(GList *trace_paths, const char *base_path) {
1a9f7075 1079 GList *trace_names = NULL;
1a9f7075 1080 GList *node;
4bd72b60
PP
1081 const char *last_sep;
1082 size_t base_dist;
1a9f7075
PP
1083
1084 /*
4bd72b60
PP
1085 * At this point we know that all the trace paths are
1086 * normalized, and so is the base path. This means that
1087 * they are absolute and they don't end with a separator.
1088 * We can simply find the location of the last separator
1089 * in the base path, which gives us the name of the actual
1090 * directory to look into, and use this location as the
1091 * start of each trace name within each trace path.
1092 *
1093 * For example:
1094 *
1095 * Base path: /home/user/my-traces/some-trace
1096 * Trace paths:
1097 * - /home/user/my-traces/some-trace/host1/trace1
1098 * - /home/user/my-traces/some-trace/host1/trace2
1099 * - /home/user/my-traces/some-trace/host2/trace
1100 * - /home/user/my-traces/some-trace/other-trace
1101 *
1102 * In this case the trace names are:
1103 *
1104 * - some-trace/host1/trace1
1105 * - some-trace/host1/trace2
1106 * - some-trace/host2/trace
1107 * - some-trace/other-trace
1a9f7075 1108 */
4bd72b60 1109 last_sep = strrchr(base_path, G_DIR_SEPARATOR);
1a9f7075 1110
4bd72b60
PP
1111 /* We know there's at least one separator */
1112 assert(last_sep);
1a9f7075 1113
4bd72b60
PP
1114 /* Distance to base */
1115 base_dist = last_sep - base_path + 1;
1a9f7075
PP
1116
1117 /* Create the trace names */
1118 for (node = trace_paths; node; node = g_list_next(node)) {
1119 GString *trace_name = g_string_new(NULL);
1120 GString *trace_path = node->data;
1121
4bd72b60
PP
1122 assert(trace_name);
1123 g_string_assign(trace_name, &trace_path->str[base_dist]);
1a9f7075
PP
1124 trace_names = g_list_append(trace_names, trace_name);
1125 }
1126
1127 return trace_names;
1128}
1129
1130static
1131int create_ctf_fs_traces(struct ctf_fs_component *ctf_fs,
1132 const char *path_param)
1133{
1134 struct ctf_fs_trace *ctf_fs_trace = NULL;
1135 int ret = 0;
4bd72b60 1136 GString *norm_path = NULL;
1a9f7075
PP
1137 GList *trace_paths = NULL;
1138 GList *trace_names = NULL;
1139 GList *tp_node;
1140 GList *tn_node;
1141
4bd72b60
PP
1142 norm_path = bt_common_normalize_path(path_param, NULL);
1143 if (!norm_path) {
1144 PERR("Failed to normalize path: `%s`.\n",
1145 path_param);
1146 goto error;
1147 }
1148
1149 ret = find_ctf_traces(ctf_fs, &trace_paths, norm_path->str);
1a9f7075
PP
1150 if (ret) {
1151 goto error;
1152 }
1153
1154 if (!trace_paths) {
1155 PERR("No CTF traces recursively found in `%s`.\n",
1156 path_param);
1157 goto error;
1158 }
1159
4bd72b60 1160 trace_names = create_trace_names(trace_paths, norm_path->str);
1a9f7075
PP
1161 if (!trace_names) {
1162 PERR("Cannot create trace names from trace paths.\n");
1163 goto error;
1164 }
1165
1166 for (tp_node = trace_paths, tn_node = trace_names; tp_node;
1167 tp_node = g_list_next(tp_node),
1168 tn_node = g_list_next(tn_node)) {
1169 GString *trace_path = tp_node->data;
1170 GString *trace_name = tn_node->data;
1171
1172 ctf_fs_trace = ctf_fs_trace_create(ctf_fs, trace_path->str,
1173 trace_name->str);
1174 if (!ctf_fs_trace) {
1175 PERR("Cannot create trace for `%s`.\n",
1176 trace_path->str);
1177 goto error;
1178 }
52c5fe74
PP
1179
1180 g_ptr_array_add(ctf_fs->traces, ctf_fs_trace);
1181 ctf_fs_trace = NULL;
1a9f7075
PP
1182 }
1183
1a9f7075
PP
1184 goto end;
1185
1186error:
1187 ret = -1;
1188 ctf_fs_trace_destroy(ctf_fs_trace);
1189
1190end:
1191 for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) {
1192 if (tp_node->data) {
1193 g_string_free(tp_node->data, TRUE);
1194 }
1195 }
1196
1197 for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) {
1198 if (tn_node->data) {
1199 g_string_free(tn_node->data, TRUE);
1200 }
1201 }
1202
1203 if (trace_paths) {
1204 g_list_free(trace_paths);
1205 }
1206
1207 if (trace_names) {
1208 g_list_free(trace_names);
1209 }
1210
4bd72b60
PP
1211 if (norm_path) {
1212 g_string_free(norm_path, TRUE);
1213 }
1214
1a9f7075
PP
1215 return ret;
1216}
1217
5b29e799 1218static
4f1f88a6
PP
1219struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
1220 struct bt_value *params)
56a1cced
JG
1221{
1222 struct ctf_fs_component *ctf_fs;
1ef09eb5 1223 struct bt_value *value = NULL;
1a9f7075 1224 const char *path_param;
4f1f88a6 1225 int ret;
56a1cced
JG
1226
1227 ctf_fs = g_new0(struct ctf_fs_component, 1);
1228 if (!ctf_fs) {
1229 goto end;
1230 }
1231
1a9f7075
PP
1232 ret = bt_private_component_set_user_data(priv_comp, ctf_fs);
1233 assert(ret == 0);
1234
4f1f88a6
PP
1235 /*
1236 * We don't need to get a new reference here because as long as
1237 * our private ctf_fs_component object exists, the containing
1238 * private component should also exist.
1239 */
1240 ctf_fs->priv_comp = priv_comp;
56a1cced 1241 value = bt_value_map_get(params, "path");
1a9f7075 1242 if (!bt_value_is_string(value)) {
56a1cced
JG
1243 goto error;
1244 }
1245
1a9f7075
PP
1246 ret = bt_value_string_get(value, &path_param);
1247 assert(ret == 0);
1248 BT_PUT(value);
92540773
JD
1249 value = bt_value_map_get(params, "offset-s");
1250 if (value) {
1251 int64_t offset;
1252
1253 if (!bt_value_is_integer(value)) {
1254 fprintf(stderr,
1255 "offset-s should be an integer\n");
1256 goto error;
1257 }
1258 ret = bt_value_integer_get(value, &offset);
1a9f7075 1259 assert(ret == 0);
92540773 1260 ctf_fs->options.clock_offset = offset;
1a9f7075 1261 BT_PUT(value);
92540773
JD
1262 }
1263
1264 value = bt_value_map_get(params, "offset-ns");
1265 if (value) {
1266 int64_t offset;
1267
1268 if (!bt_value_is_integer(value)) {
1269 fprintf(stderr,
1270 "offset-ns should be an integer\n");
1271 goto error;
1272 }
1273 ret = bt_value_integer_get(value, &offset);
1a9f7075 1274 assert(ret == 0);
92540773 1275 ctf_fs->options.clock_offset_ns = offset;
1a9f7075 1276 BT_PUT(value);
92540773
JD
1277 }
1278
56a1cced
JG
1279 ctf_fs->error_fp = stderr;
1280 ctf_fs->page_size = (size_t) getpagesize();
1a9f7075
PP
1281 ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy);
1282 if (!ctf_fs->port_data) {
4f1f88a6
PP
1283 goto error;
1284 }
1285
1a9f7075
PP
1286 ctf_fs->traces = g_ptr_array_new_with_free_func(ctf_fs_trace_destroy);
1287 if (!ctf_fs->traces) {
599faa1c
PP
1288 goto error;
1289 }
1290
1a9f7075 1291 ret = create_ctf_fs_traces(ctf_fs, path_param);
4f1f88a6
PP
1292 if (ret) {
1293 goto error;
1294 }
1295
1ef09eb5
JG
1296 goto end;
1297
56a1cced 1298error:
1a9f7075 1299 ctf_fs_destroy(ctf_fs);
e7a4393b 1300 ctf_fs = NULL;
1a9f7075
PP
1301 ret = bt_private_component_set_user_data(priv_comp, NULL);
1302 assert(ret == 0);
1303
1ef09eb5 1304end:
1a9f7075 1305 bt_put(value);
56a1cced
JG
1306 return ctf_fs;
1307}
1308
ea0b4b9e 1309BT_HIDDEN
4f1f88a6 1310enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp,
7d61fa8e 1311 struct bt_value *params, UNUSED_VAR void *init_method_data)
ea0b4b9e
JG
1312{
1313 struct ctf_fs_component *ctf_fs;
1314 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1315
ea0b4b9e 1316 ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0;
4f1f88a6 1317 ctf_fs = ctf_fs_create(priv_comp, params);
ea0b4b9e 1318 if (!ctf_fs) {
1a9f7075 1319 ret = BT_COMPONENT_STATUS_ERROR;
ea0b4b9e 1320 }
4c1456f0 1321
ea0b4b9e
JG
1322 return ret;
1323}
33f93973
PP
1324
1325BT_HIDDEN
a67681c1
PP
1326struct bt_value *ctf_fs_query(struct bt_component_class *comp_class,
1327 const char *object, struct bt_value *params)
33f93973
PP
1328{
1329 struct bt_value *results = NULL;
1330 struct bt_value *path_value = NULL;
1331 char *metadata_text = NULL;
1332 FILE *metadata_fp = NULL;
1333 GString *g_metadata_text = NULL;
1334
a67681c1 1335 if (strcmp(object, "metadata-info") == 0) {
33f93973
PP
1336 int ret;
1337 int bo;
1338 const char *path;
1339 bool is_packetized;
1340
1341 results = bt_value_map_create();
1342 if (!results) {
1343 goto error;
1344 }
1345
1346 if (!bt_value_is_map(params)) {
1347 fprintf(stderr,
a67681c1 1348 "Query parameters is not a map value object\n");
33f93973
PP
1349 goto error;
1350 }
1351
1352 path_value = bt_value_map_get(params, "path");
1353 ret = bt_value_string_get(path_value, &path);
1354 if (ret) {
1355 fprintf(stderr,
1356 "Cannot get `path` string parameter\n");
1357 goto error;
1358 }
1359
1360 assert(path);
1361 metadata_fp = ctf_fs_metadata_open_file(path);
1362 if (!metadata_fp) {
1363 fprintf(stderr,
1364 "Cannot open trace at path `%s`\n", path);
1365 goto error;
1366 }
1367
1e649dff
PP
1368 is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp,
1369 &bo);
33f93973
PP
1370
1371 if (is_packetized) {
1e649dff
PP
1372 ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
1373 metadata_fp, &metadata_text, bo);
33f93973
PP
1374 if (ret) {
1375 fprintf(stderr,
1376 "Cannot decode packetized metadata file\n");
1377 goto error;
1378 }
1379 } else {
1380 long filesize;
1381
1382 fseek(metadata_fp, 0, SEEK_END);
1383 filesize = ftell(metadata_fp);
1384 rewind(metadata_fp);
1385 metadata_text = malloc(filesize + 1);
1386 if (!metadata_text) {
1387 fprintf(stderr,
1388 "Cannot allocate buffer for metadata text\n");
1389 goto error;
1390 }
1391
1392 if (fread(metadata_text, filesize, 1, metadata_fp) !=
1393 1) {
1394 fprintf(stderr,
1395 "Cannot read metadata file\n");
1396 goto error;
1397 }
1398
1399 metadata_text[filesize] = '\0';
1400 }
1401
1402 g_metadata_text = g_string_new(NULL);
1403 if (!g_metadata_text) {
1404 goto error;
1405 }
1406
1407 if (strncmp(metadata_text, METADATA_TEXT_SIG,
1408 sizeof(METADATA_TEXT_SIG) - 1) != 0) {
1409 g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
1410 g_string_append(g_metadata_text, " */\n\n");
1411 }
1412
1413 g_string_append(g_metadata_text, metadata_text);
1414
1415 ret = bt_value_map_insert_string(results, "text",
1416 g_metadata_text->str);
1417 if (ret) {
1418 fprintf(stderr, "Cannot insert metadata text into results\n");
1419 goto error;
1420 }
1421
1422 ret = bt_value_map_insert_bool(results, "is-packetized",
1423 is_packetized);
1424 if (ret) {
1425 fprintf(stderr, "Cannot insert is packetized into results\n");
1426 goto error;
1427 }
1428 } else {
a67681c1 1429 fprintf(stderr, "Unknown query object `%s`\n", object);
33f93973
PP
1430 goto error;
1431 }
1432
1433 goto end;
1434
1435error:
1436 BT_PUT(results);
1437
1438end:
1439 bt_put(path_value);
1440 free(metadata_text);
1441
1442 if (g_metadata_text) {
1443 g_string_free(g_metadata_text, TRUE);
1444 }
1445
1446 if (metadata_fp) {
1447 fclose(metadata_fp);
1448 }
1449 return results;
1450}
This page took 0.091965 seconds and 4 git commands to generate.