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