text: mask some internal fields
[babeltrace.git] / plugins / ctf / fs / fs.c
CommitLineData
7a278c8e 1/*
ea0b4b9e 2 * fs.c
7a278c8e 3 *
ea0b4b9e 4 * Babeltrace CTF file system Reader Component
7a278c8e 5 *
f3bc2010 6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7a278c8e
JG
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
5b29e799 29#include <babeltrace/ctf-ir/packet.h>
ac0c6bdd 30#include <babeltrace/ctf-ir/clock-class.h>
33b34c43
PP
31#include <babeltrace/component/notification/iterator.h>
32#include <babeltrace/component/notification/stream.h>
33#include <babeltrace/component/notification/event.h>
34#include <babeltrace/component/notification/packet.h>
35#include <babeltrace/component/notification/heap.h>
7d61fa8e 36#include <plugins-common.h>
ea0b4b9e
JG
37#include <glib.h>
38#include <assert.h>
56a1cced
JG
39#include <unistd.h>
40#include "fs.h"
413bc2c4
JG
41#include "metadata.h"
42#include "data-stream.h"
e7a4393b
JG
43#include "file.h"
44
45#define PRINT_ERR_STREAM ctf_fs->error_fp
46#define PRINT_PREFIX "ctf-fs"
47#include "print.h"
33f93973 48#define METADATA_TEXT_SIG "/* CTF 1.8"
ea0b4b9e 49
78bb6992
MD
50BT_HIDDEN
51bool ctf_fs_debug;
ea0b4b9e 52
f48bc732
JG
53enum bt_notification_iterator_status ctf_fs_iterator_next(
54 struct bt_notification_iterator *iterator);
55
760051fa
JG
56struct bt_notification *ctf_fs_iterator_get(
57 struct bt_notification_iterator *iterator)
ea0b4b9e 58{
5b29e799
JG
59 struct ctf_fs_iterator *ctf_it =
60 bt_notification_iterator_get_private_data(iterator);
d01e0f33 61
f48bc732
JG
62 if (!ctf_it->current_notification) {
63 (void) ctf_fs_iterator_next(iterator);
64 }
65
5b29e799 66 return bt_get(ctf_it->current_notification);
ea0b4b9e
JG
67}
68
69static
5b29e799
JG
70enum bt_notification_iterator_status ctf_fs_iterator_get_next_notification(
71 struct ctf_fs_iterator *it,
72 struct ctf_fs_stream *stream,
73 struct bt_notification **notification)
ea0b4b9e 74{
5b29e799 75 enum bt_ctf_notif_iter_status status;
d01e0f33 76 enum bt_notification_iterator_status ret;
d01e0f33 77
5b29e799
JG
78 if (stream->end_reached) {
79 status = BT_CTF_NOTIF_ITER_STATUS_EOF;
d01e0f33
JG
80 goto end;
81 }
82
5b29e799
JG
83 status = bt_ctf_notif_iter_get_next_notification(stream->notif_iter,
84 notification);
85 if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
86 status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
d01e0f33
JG
87 goto end;
88 }
89
5b29e799
JG
90 /* Should be handled in bt_ctf_notif_iter_get_next_notification. */
91 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
92 *notification = bt_notification_stream_end_create(
93 stream->stream);
94 if (!*notification) {
95 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
96 }
97 status = BT_CTF_NOTIF_ITER_STATUS_OK;
98 stream->end_reached = true;
99 }
d01e0f33 100end:
5b29e799
JG
101 switch (status) {
102 case BT_CTF_NOTIF_ITER_STATUS_EOF:
103 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
104 break;
105 case BT_CTF_NOTIF_ITER_STATUS_OK:
106 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
107 break;
108 case BT_CTF_NOTIF_ITER_STATUS_AGAIN:
109 /*
110 * Should not make it this far as this is medium-specific;
111 * there is nothing for the user to do and it should have been
112 * handled upstream.
113 */
114 assert(0);
115 case BT_CTF_NOTIF_ITER_STATUS_INVAL:
116 /* No argument provided by the user, so don't return INVAL. */
117 case BT_CTF_NOTIF_ITER_STATUS_ERROR:
118 default:
119 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
120 break;
121 }
043e2020 122 return ret;
ea0b4b9e 123}
bfd20a42 124
5b29e799
JG
125/*
126 * Remove me. This is a temporary work-around due to our inhability to use
127 * libbabeltrace-ctf from libbabeltrace-plugin.
128 */
760051fa 129static
5b29e799
JG
130struct bt_ctf_stream *internal_bt_notification_get_stream(
131 struct bt_notification *notification)
760051fa 132{
5b29e799
JG
133 struct bt_ctf_stream *stream = NULL;
134
135 assert(notification);
136 switch (bt_notification_get_type(notification)) {
137 case BT_NOTIFICATION_TYPE_EVENT:
138 {
139 struct bt_ctf_event *event;
140
141 event = bt_notification_event_get_event(notification);
142 stream = bt_ctf_event_get_stream(event);
143 bt_put(event);
144 break;
145 }
ea0e619e 146 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
5b29e799
JG
147 {
148 struct bt_ctf_packet *packet;
149
ea0e619e 150 packet = bt_notification_packet_begin_get_packet(notification);
5b29e799
JG
151 stream = bt_ctf_packet_get_stream(packet);
152 bt_put(packet);
153 break;
154 }
155 case BT_NOTIFICATION_TYPE_PACKET_END:
156 {
157 struct bt_ctf_packet *packet;
158
159 packet = bt_notification_packet_end_get_packet(notification);
160 stream = bt_ctf_packet_get_stream(packet);
161 bt_put(packet);
162 break;
163 }
164 case BT_NOTIFICATION_TYPE_STREAM_END:
165 stream = bt_notification_stream_end_get_stream(notification);
166 break;
167 default:
168 goto end;
169 }
170end:
171 return stream;
760051fa
JG
172}
173
174static
5b29e799 175enum bt_notification_iterator_status populate_heap(struct ctf_fs_iterator *it)
760051fa 176{
5b29e799
JG
177 size_t i, pending_streams_count = it->pending_streams->len;
178 enum bt_notification_iterator_status ret =
179 BT_NOTIFICATION_ITERATOR_STATUS_OK;
180
181 /* Insert one stream-associated notification for each stream. */
182 for (i = 0; i < pending_streams_count; i++) {
183 struct bt_notification *notification;
184 struct ctf_fs_stream *fs_stream;
185 struct bt_ctf_stream *stream;
186 size_t pending_stream_index = pending_streams_count - 1 - i;
187
188 fs_stream = g_ptr_array_index(it->pending_streams,
189 pending_stream_index);
190
191 do {
192 int heap_ret;
193
194 ret = ctf_fs_iterator_get_next_notification(
195 it, fs_stream, &notification);
196 if (ret && ret != BT_NOTIFICATION_ITERATOR_STATUS_END) {
197 printf_debug("Failed to populate heap at stream %zu\n",
198 pending_stream_index);
199 goto end;
200 }
201
202 stream = internal_bt_notification_get_stream(
203 notification);
204 if (stream) {
205 gboolean inserted;
206
207 /*
208 * Associate pending ctf_fs_stream to
209 * bt_ctf_stream. Ownership of stream
210 * is passed to the stream ht.
211 */
212 inserted = g_hash_table_insert(it->stream_ht,
213 stream, fs_stream);
214 if (!inserted) {
215 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
216 printf_debug("Failed to associate fs stream to ctf stream\n");
217 goto end;
218 }
219 }
220
221 heap_ret = bt_notification_heap_insert(
222 it->pending_notifications,
223 notification);
224 bt_put(notification);
225 if (heap_ret) {
226 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
227 printf_debug("Failed to insert notification in heap\n");
228 goto end;
229 }
230 } while (!stream && ret != BT_NOTIFICATION_ITERATOR_STATUS_END);
231 /*
232 * Set NULL so the destruction callback registered with the
233 * array is not invoked on the stream (its ownership was
234 * transferred to the streams hashtable).
235 */
236 g_ptr_array_index(it->pending_streams,
237 pending_stream_index) = NULL;
238 g_ptr_array_remove_index(it->pending_streams,
239 pending_stream_index);
240 }
760051fa 241
5b29e799
JG
242 g_ptr_array_free(it->pending_streams, TRUE);
243 it->pending_streams = NULL;
244end:
245 return ret;
760051fa
JG
246}
247
5b29e799
JG
248enum bt_notification_iterator_status ctf_fs_iterator_next(
249 struct bt_notification_iterator *iterator)
4c1456f0 250{
5b29e799 251 int heap_ret;
a11bd504 252 struct bt_ctf_stream *stream = NULL;
5b29e799
JG
253 struct ctf_fs_stream *fs_stream;
254 struct bt_notification *notification;
255 struct bt_notification *next_stream_notification;
256 enum bt_notification_iterator_status ret =
257 BT_NOTIFICATION_ITERATOR_STATUS_OK;
258 struct ctf_fs_iterator *ctf_it =
259 bt_notification_iterator_get_private_data(iterator);
260
261 notification = bt_notification_heap_pop(ctf_it->pending_notifications);
262 if (!notification && !ctf_it->pending_streams) {
263 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
760051fa
JG
264 goto end;
265 }
266
5b29e799
JG
267 if (!notification && ctf_it->pending_streams) {
268 /*
269 * Insert at one notification per stream in the heap and pop
270 * one.
271 */
272 ret = populate_heap(ctf_it);
273 if (ret) {
274 goto end;
275 }
276
277 notification = bt_notification_heap_pop(
278 ctf_it->pending_notifications);
279 if (!notification) {
280 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
281 goto end;
282 }
760051fa
JG
283 }
284
5b29e799
JG
285 /* notification is set from here. */
286
287 stream = internal_bt_notification_get_stream(notification);
288 if (!stream) {
289 /*
290 * The current notification is not associated to a particular
291 * stream, there is no need to insert a new notification from
292 * a stream in the heap.
293 */
294 goto end;
760051fa
JG
295 }
296
5b29e799
JG
297 fs_stream = g_hash_table_lookup(ctf_it->stream_ht, stream);
298 if (!fs_stream) {
299 /* We have reached this stream's end. */
300 goto end;
760051fa
JG
301 }
302
5b29e799
JG
303 ret = ctf_fs_iterator_get_next_notification(ctf_it, fs_stream,
304 &next_stream_notification);
305 if ((ret && ret != BT_NOTIFICATION_ITERATOR_STATUS_END)) {
306 heap_ret = bt_notification_heap_insert(
307 ctf_it->pending_notifications, notification);
308
309 assert(!next_stream_notification);
310 if (heap_ret) {
311 /*
312 * We're dropping the most recent notification, but at
313 * this point, something is seriously wrong...
314 */
315 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
316 }
317 BT_PUT(notification);
318 goto end;
319 }
320
321 if (ret == BT_NOTIFICATION_ITERATOR_STATUS_END) {
322 gboolean success;
323
324 /* Remove stream. */
325 success = g_hash_table_remove(ctf_it->stream_ht, stream);
326 assert(success);
327 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
328 } else {
329 heap_ret = bt_notification_heap_insert(ctf_it->pending_notifications,
330 next_stream_notification);
331 BT_PUT(next_stream_notification);
332 if (heap_ret) {
333 /*
334 * We're dropping the most recent notification...
335 */
336 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
337 }
760051fa 338 }
5b29e799
JG
339
340 /*
341 * Ensure that the stream is removed from both pending_streams and
342 * the streams hashtable on reception of the "end of stream"
343 * notification.
344 */
760051fa 345end:
5b29e799 346 BT_MOVE(ctf_it->current_notification, notification);
33bf10b7 347 bt_put(stream);
760051fa
JG
348 return ret;
349}
350
760051fa 351static
5b29e799 352void ctf_fs_iterator_destroy_data(struct ctf_fs_iterator *ctf_it)
760051fa 353{
8fa760ba
JG
354 if (!ctf_it) {
355 return;
356 }
5b29e799
JG
357 bt_put(ctf_it->current_notification);
358 bt_put(ctf_it->pending_notifications);
359 if (ctf_it->pending_streams) {
360 g_ptr_array_free(ctf_it->pending_streams, TRUE);
56a1cced 361 }
5b29e799
JG
362 if (ctf_it->stream_ht) {
363 g_hash_table_destroy(ctf_it->stream_ht);
c14d7e26 364 }
5b29e799 365 g_free(ctf_it);
760051fa
JG
366}
367
5b29e799 368void ctf_fs_iterator_destroy(struct bt_notification_iterator *it)
760051fa 369{
5b29e799 370 void *data = bt_notification_iterator_get_private_data(it);
760051fa 371
5b29e799 372 ctf_fs_iterator_destroy_data(data);
4c1456f0
JG
373}
374
a4792757
JG
375static
376bool compare_event_notifications(struct bt_notification *a,
377 struct bt_notification *b)
378{
379 int ret;
ac0c6bdd 380 struct bt_ctf_clock_class *clock_class;
a4792757
JG
381 struct bt_ctf_clock_value *a_clock_value, *b_clock_value;
382 struct bt_ctf_stream_class *a_stream_class;
383 struct bt_ctf_stream *a_stream;
384 struct bt_ctf_event *a_event, *b_event;
385 struct bt_ctf_trace *trace;
386 int64_t a_ts, b_ts;
387
388 // FIXME - assumes only one clock
389 a_event = bt_notification_event_get_event(a);
390 b_event = bt_notification_event_get_event(b);
391 assert(a_event);
392 assert(b_event);
393
394 a_stream = bt_ctf_event_get_stream(a_event);
395 assert(a_stream);
396 a_stream_class = bt_ctf_stream_get_class(a_stream);
397 assert(a_stream_class);
398 trace = bt_ctf_stream_class_get_trace(a_stream_class);
399 assert(trace);
400
ac0c6bdd
PP
401 clock_class = bt_ctf_trace_get_clock_class(trace, 0);
402 a_clock_value = bt_ctf_event_get_clock_value(a_event, clock_class);
403 b_clock_value = bt_ctf_event_get_clock_value(b_event, clock_class);
a4792757
JG
404 assert(a_clock_value);
405 assert(b_clock_value);
406
407 ret = bt_ctf_clock_value_get_value_ns_from_epoch(a_clock_value, &a_ts);
408 assert(!ret);
409 ret = bt_ctf_clock_value_get_value_ns_from_epoch(b_clock_value, &b_ts);
410 assert(!ret);
411
412 bt_put(a_event);
413 bt_put(b_event);
414 bt_put(a_clock_value);
415 bt_put(b_clock_value);
416 bt_put(a_stream);
417 bt_put(a_stream_class);
ac0c6bdd 418 bt_put(clock_class);
a4792757
JG
419 bt_put(trace);
420 return a_ts < b_ts;
421}
422
e7a4393b 423static
5b29e799
JG
424bool compare_notifications(struct bt_notification *a, struct bt_notification *b,
425 void *unused)
426{
a4792757
JG
427 static int notification_priorities[] = {
428 [BT_NOTIFICATION_TYPE_NEW_TRACE] = 0,
429 [BT_NOTIFICATION_TYPE_NEW_STREAM_CLASS] = 1,
430 [BT_NOTIFICATION_TYPE_NEW_EVENT_CLASS] = 2,
ea0e619e 431 [BT_NOTIFICATION_TYPE_PACKET_BEGIN] = 3,
a4792757
JG
432 [BT_NOTIFICATION_TYPE_PACKET_END] = 4,
433 [BT_NOTIFICATION_TYPE_EVENT] = 5,
434 [BT_NOTIFICATION_TYPE_END_OF_TRACE] = 6,
435 };
436 int a_prio, b_prio;
437 enum bt_notification_type a_type, b_type;
438
439 assert(a && b);
440 a_type = bt_notification_get_type(a);
441 b_type = bt_notification_get_type(b);
442 assert(a_type > BT_NOTIFICATION_TYPE_ALL);
443 assert(a_type < BT_NOTIFICATION_TYPE_NR);
444 assert(b_type > BT_NOTIFICATION_TYPE_ALL);
445 assert(b_type < BT_NOTIFICATION_TYPE_NR);
446
447 a_prio = notification_priorities[a_type];
448 b_prio = notification_priorities[b_type];
449
450 if (likely((a_type == b_type) && a_type == BT_NOTIFICATION_TYPE_EVENT)) {
451 return compare_event_notifications(a, b);
452 }
453
454 if (unlikely(a_prio != b_prio)) {
455 return a_prio < b_prio;
456 }
457
458 /* Notification types are equal, but not of type "event". */
459 switch (a_type) {
ea0e619e 460 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
a4792757
JG
461 case BT_NOTIFICATION_TYPE_PACKET_END:
462 case BT_NOTIFICATION_TYPE_STREAM_END:
463 {
464 int64_t a_sc_id, b_sc_id;
465 struct bt_ctf_stream *a_stream, *b_stream;
466 struct bt_ctf_stream_class *a_sc, *b_sc;
467
468 a_stream = internal_bt_notification_get_stream(a);
469 b_stream = internal_bt_notification_get_stream(b);
470 assert(a_stream && b_stream);
471
472 a_sc = bt_ctf_stream_get_class(a_stream);
473 b_sc = bt_ctf_stream_get_class(b_stream);
474 assert(a_sc && b_sc);
475
476 a_sc_id = bt_ctf_stream_class_get_id(a_sc);
477 b_sc_id = bt_ctf_stream_class_get_id(b_sc);
478 assert(a_sc_id >= 0 && b_sc_id >= 0);
479 bt_put(a_sc);
480 bt_put(a_stream);
481 bt_put(b_sc);
482 bt_put(b_stream);
483 return a_sc_id < b_sc_id;
484 }
485 case BT_NOTIFICATION_TYPE_NEW_TRACE:
486 case BT_NOTIFICATION_TYPE_END_OF_TRACE:
487 /* Impossible to have two separate traces. */
488 default:
489 assert(0);
490 }
491
492 assert(0);
5b29e799
JG
493 return a < b;
494}
495
496static
497void stream_destroy(void *stream)
498{
499 ctf_fs_stream_destroy((struct ctf_fs_stream *) stream);
500}
501
502static
503int open_trace_streams(struct ctf_fs_component *ctf_fs,
504 struct ctf_fs_iterator *ctf_it)
e7a4393b
JG
505{
506 int ret = 0;
507 const char *name;
508 GError *error = NULL;
509 GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
510
511 if (!dir) {
512 PERR("Cannot open directory \"%s\": %s (code %d)\n",
513 ctf_fs->trace_path->str, error->message,
514 error->code);
515 goto error;
516 }
517
518 while ((name = g_dir_read_name(dir))) {
519 struct ctf_fs_file *file = NULL;
520 struct ctf_fs_stream *stream = NULL;
521
522 if (!strcmp(name, CTF_FS_METADATA_FILENAME)) {
523 /* Ignore the metadata stream. */
524 PDBG("Ignoring metadata file \"%s\"\n",
525 name);
526 continue;
527 }
528
529 if (name[0] == '.') {
530 PDBG("Ignoring hidden file \"%s\"\n",
531 name);
532 continue;
533 }
534
535 /* Create the file. */
536 file = ctf_fs_file_create(ctf_fs);
537 if (!file) {
538 PERR("Cannot create stream file object\n");
539 goto error;
540 }
541
542 /* Create full path string. */
543 g_string_append_printf(file->path, "%s/%s",
544 ctf_fs->trace_path->str, name);
545 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
546 PDBG("Ignoring non-regular file \"%s\"\n", name);
547 ctf_fs_file_destroy(file);
548 continue;
549 }
550
551 /* Open the file. */
552 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
553 ctf_fs_file_destroy(file);
554 goto error;
555 }
556
9fa0891a
JG
557 if (file->size == 0) {
558 /* Skip empty stream. */
559 ctf_fs_file_destroy(file);
560 continue;
561 }
562
e7a4393b
JG
563 /* Create a private stream; file ownership is passed to it. */
564 stream = ctf_fs_stream_create(ctf_fs, file);
565 if (!stream) {
566 ctf_fs_file_destroy(file);
567 goto error;
568 }
569
5b29e799 570 g_ptr_array_add(ctf_it->pending_streams, stream);
e7a4393b
JG
571 }
572
573 goto end;
574error:
575 ret = -1;
576end:
577 if (dir) {
578 g_dir_close(dir);
579 dir = NULL;
580 }
581 if (error) {
582 g_error_free(error);
583 }
584 return ret;
585}
586
d3eb6e8f 587enum bt_notification_iterator_status ctf_fs_iterator_init(struct bt_component *source,
8b0ce102
PP
588 struct bt_notification_iterator *it,
589 UNUSED_VAR void *init_method_data)
e7a4393b 590{
5b29e799
JG
591 struct ctf_fs_iterator *ctf_it;
592 struct ctf_fs_component *ctf_fs;
d3eb6e8f 593 enum bt_notification_iterator_status ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
5b29e799
JG
594
595 assert(source && it);
596
597 ctf_fs = bt_component_get_private_data(source);
598 if (!ctf_fs) {
d3eb6e8f 599 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVAL;
5b29e799
JG
600 goto end;
601 }
602
603 ctf_it = g_new0(struct ctf_fs_iterator, 1);
604 if (!ctf_it) {
d3eb6e8f 605 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
5b29e799
JG
606 goto end;
607 }
608
609 ctf_it->stream_ht = g_hash_table_new_full(g_direct_hash,
610 g_direct_equal, bt_put, stream_destroy);
611 if (!ctf_it->stream_ht) {
612 goto error;
613 }
614 ctf_it->pending_streams = g_ptr_array_new_with_free_func(
615 stream_destroy);
616 if (!ctf_it->pending_streams) {
617 goto error;
618 }
619 ctf_it->pending_notifications = bt_notification_heap_create(
620 compare_notifications, NULL);
621 if (!ctf_it->pending_notifications) {
622 goto error;
623 }
624
625 ret = open_trace_streams(ctf_fs, ctf_it);
626 if (ret) {
627 goto error;
628 }
629
5b29e799
JG
630 ret = bt_notification_iterator_set_private_data(it, ctf_it);
631 if (ret) {
632 goto error;
633 }
f48bc732 634
5b29e799
JG
635end:
636 return ret;
637error:
638 (void) bt_notification_iterator_set_private_data(it, NULL);
639 ctf_fs_iterator_destroy_data(ctf_it);
640 goto end;
641}
642
643static
644void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs)
645{
fa5a772d
JG
646 if (!ctf_fs) {
647 return;
648 }
5b29e799
JG
649 if (ctf_fs->trace_path) {
650 g_string_free(ctf_fs->trace_path, TRUE);
651 }
652 if (ctf_fs->metadata) {
653 ctf_fs_metadata_fini(ctf_fs->metadata);
654 g_free(ctf_fs->metadata);
655 }
656 g_free(ctf_fs);
657}
658
5b29e799
JG
659void ctf_fs_destroy(struct bt_component *component)
660{
661 void *data = bt_component_get_private_data(component);
662
663 ctf_fs_destroy_data(data);
e7a4393b
JG
664}
665
56a1cced
JG
666static
667struct ctf_fs_component *ctf_fs_create(struct bt_value *params)
668{
669 struct ctf_fs_component *ctf_fs;
1ef09eb5 670 struct bt_value *value = NULL;
56a1cced
JG
671 const char *path;
672 enum bt_value_status ret;
673
674 ctf_fs = g_new0(struct ctf_fs_component, 1);
675 if (!ctf_fs) {
676 goto end;
677 }
678
679 /* FIXME: should probably look for a source URI */
680 value = bt_value_map_get(params, "path");
681 if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) {
682 goto error;
683 }
684
685 ret = bt_value_string_get(value, &path);
686 if (ret != BT_VALUE_STATUS_OK) {
687 goto error;
688 }
689
690 ctf_fs->trace_path = g_string_new(path);
691 if (!ctf_fs->trace_path) {
692 goto error;
693 }
56a1cced
JG
694 ctf_fs->error_fp = stderr;
695 ctf_fs->page_size = (size_t) getpagesize();
e7a4393b
JG
696
697 // FIXME: check error.
5b29e799
JG
698 ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1);
699 if (!ctf_fs->metadata) {
e7a4393b
JG
700 goto error;
701 }
5b29e799 702 ctf_fs_metadata_set_trace(ctf_fs);
1ef09eb5
JG
703 goto end;
704
56a1cced
JG
705error:
706 ctf_fs_destroy_data(ctf_fs);
e7a4393b 707 ctf_fs = NULL;
1ef09eb5
JG
708end:
709 BT_PUT(value);
56a1cced
JG
710 return ctf_fs;
711}
712
ea0b4b9e
JG
713BT_HIDDEN
714enum bt_component_status ctf_fs_init(struct bt_component *source,
7d61fa8e 715 struct bt_value *params, UNUSED_VAR void *init_method_data)
ea0b4b9e
JG
716{
717 struct ctf_fs_component *ctf_fs;
718 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
719
720 assert(source);
721 ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0;
722 ctf_fs = ctf_fs_create(params);
723 if (!ctf_fs) {
724 ret = BT_COMPONENT_STATUS_NOMEM;
725 goto end;
726 }
4c1456f0 727
ea0b4b9e
JG
728 ret = bt_component_set_private_data(source, ctf_fs);
729 if (ret != BT_COMPONENT_STATUS_OK) {
730 goto error;
731 }
ea0b4b9e
JG
732end:
733 return ret;
734error:
735 (void) bt_component_set_private_data(source, NULL);
760051fa 736 ctf_fs_destroy_data(ctf_fs);
ea0b4b9e
JG
737 return ret;
738}
33f93973
PP
739
740BT_HIDDEN
741struct bt_value *ctf_fs_query_info(struct bt_component_class *comp_class,
742 const char *action, struct bt_value *params)
743{
744 struct bt_value *results = NULL;
745 struct bt_value *path_value = NULL;
746 char *metadata_text = NULL;
747 FILE *metadata_fp = NULL;
748 GString *g_metadata_text = NULL;
749
750 if (strcmp(action, "get-metadata-info") == 0) {
751 int ret;
752 int bo;
753 const char *path;
754 bool is_packetized;
755
756 results = bt_value_map_create();
757 if (!results) {
758 goto error;
759 }
760
761 if (!bt_value_is_map(params)) {
762 fprintf(stderr,
763 "Query info parameters is not a map value object\n");
764 goto error;
765 }
766
767 path_value = bt_value_map_get(params, "path");
768 ret = bt_value_string_get(path_value, &path);
769 if (ret) {
770 fprintf(stderr,
771 "Cannot get `path` string parameter\n");
772 goto error;
773 }
774
775 assert(path);
776 metadata_fp = ctf_fs_metadata_open_file(path);
777 if (!metadata_fp) {
778 fprintf(stderr,
779 "Cannot open trace at path `%s`\n", path);
780 goto error;
781 }
782
783 is_packetized = ctf_metadata_is_packetized(metadata_fp, &bo);
784
785 if (is_packetized) {
786 ret = ctf_metadata_packetized_file_to_buf(NULL,
787 metadata_fp, (uint8_t **) &metadata_text, bo);
788 if (ret) {
789 fprintf(stderr,
790 "Cannot decode packetized metadata file\n");
791 goto error;
792 }
793 } else {
794 long filesize;
795
796 fseek(metadata_fp, 0, SEEK_END);
797 filesize = ftell(metadata_fp);
798 rewind(metadata_fp);
799 metadata_text = malloc(filesize + 1);
800 if (!metadata_text) {
801 fprintf(stderr,
802 "Cannot allocate buffer for metadata text\n");
803 goto error;
804 }
805
806 if (fread(metadata_text, filesize, 1, metadata_fp) !=
807 1) {
808 fprintf(stderr,
809 "Cannot read metadata file\n");
810 goto error;
811 }
812
813 metadata_text[filesize] = '\0';
814 }
815
816 g_metadata_text = g_string_new(NULL);
817 if (!g_metadata_text) {
818 goto error;
819 }
820
821 if (strncmp(metadata_text, METADATA_TEXT_SIG,
822 sizeof(METADATA_TEXT_SIG) - 1) != 0) {
823 g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
824 g_string_append(g_metadata_text, " */\n\n");
825 }
826
827 g_string_append(g_metadata_text, metadata_text);
828
829 ret = bt_value_map_insert_string(results, "text",
830 g_metadata_text->str);
831 if (ret) {
832 fprintf(stderr, "Cannot insert metadata text into results\n");
833 goto error;
834 }
835
836 ret = bt_value_map_insert_bool(results, "is-packetized",
837 is_packetized);
838 if (ret) {
839 fprintf(stderr, "Cannot insert is packetized into results\n");
840 goto error;
841 }
842 } else {
843 fprintf(stderr, "Unknown query info action `%s`\n", action);
844 goto error;
845 }
846
847 goto end;
848
849error:
850 BT_PUT(results);
851
852end:
853 bt_put(path_value);
854 free(metadata_text);
855
856 if (g_metadata_text) {
857 g_string_free(g_metadata_text, TRUE);
858 }
859
860 if (metadata_fp) {
861 fclose(metadata_fp);
862 }
863 return results;
864}
This page took 0.063327 seconds and 4 git commands to generate.