Fix: ctf.fs source: append all ctf_fs_trace objects to component's list
[babeltrace.git] / plugins / ctf / fs-src / fs.c
1 /*
2 * fs.c
3 *
4 * Babeltrace CTF file system Reader Component
5 *
6 * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
7 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
8 *
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
28 #include <babeltrace/ctf-ir/packet.h>
29 #include <babeltrace/ctf-ir/clock-class.h>
30 #include <babeltrace/graph/private-port.h>
31 #include <babeltrace/graph/private-component.h>
32 #include <babeltrace/graph/private-component-source.h>
33 #include <babeltrace/graph/private-notification-iterator.h>
34 #include <babeltrace/graph/component.h>
35 #include <babeltrace/graph/notification-iterator.h>
36 #include <babeltrace/graph/clock-class-priority-map.h>
37 #include <plugins-common.h>
38 #include <glib.h>
39 #include <assert.h>
40 #include <stdbool.h>
41 #include <unistd.h>
42 #include "fs.h"
43 #include "metadata.h"
44 #include "data-stream.h"
45 #include "file.h"
46 #include "../common/metadata/decoder.h"
47
48 #define PRINT_ERR_STREAM ctf_fs->error_fp
49 #define PRINT_PREFIX "ctf-fs"
50 #define PRINT_DBG_CHECK ctf_fs_debug
51 #include "../print.h"
52 #define METADATA_TEXT_SIG "/* CTF 1.8"
53
54 BT_HIDDEN
55 bool ctf_fs_debug;
56
57 struct bt_notification_iterator_next_return ctf_fs_iterator_next(
58 struct bt_private_notification_iterator *iterator)
59 {
60 struct ctf_fs_stream *fs_stream =
61 bt_private_notification_iterator_get_user_data(iterator);
62
63 return ctf_fs_stream_next(fs_stream);
64 }
65
66 void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it)
67 {
68 void *ctf_fs_stream =
69 bt_private_notification_iterator_get_user_data(it);
70
71 ctf_fs_stream_destroy(ctf_fs_stream);
72 }
73
74 enum bt_notification_iterator_status ctf_fs_iterator_init(
75 struct bt_private_notification_iterator *it,
76 struct bt_private_port *port)
77 {
78 struct ctf_fs_stream *ctf_fs_stream = NULL;
79 struct ctf_fs_port_data *port_data;
80 enum bt_notification_iterator_status ret =
81 BT_NOTIFICATION_ITERATOR_STATUS_OK;
82
83 port_data = bt_private_port_get_user_data(port);
84 if (!port_data) {
85 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
86 goto error;
87 }
88
89 ctf_fs_stream = ctf_fs_stream_create(port_data->ctf_fs_trace,
90 port_data->path->str);
91 if (!ctf_fs_stream) {
92 goto error;
93 }
94
95 ret = bt_private_notification_iterator_set_user_data(it, ctf_fs_stream);
96 if (ret) {
97 goto error;
98 }
99
100 ctf_fs_stream = NULL;
101 goto end;
102
103 error:
104 (void) bt_private_notification_iterator_set_user_data(it, NULL);
105
106 if (ret == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
107 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
108 }
109
110 end:
111 ctf_fs_stream_destroy(ctf_fs_stream);
112 return ret;
113 }
114
115 static
116 void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
117 {
118 if (!ctf_fs) {
119 return;
120 }
121
122 if (ctf_fs->traces) {
123 g_ptr_array_free(ctf_fs->traces, TRUE);
124 }
125
126 if (ctf_fs->port_data) {
127 g_ptr_array_free(ctf_fs->port_data, TRUE);
128 }
129
130 g_free(ctf_fs);
131 }
132
133 static
134 void ctf_fs_trace_destroy(void *data)
135 {
136 struct ctf_fs_trace *ctf_fs_trace = data;
137
138 if (!ctf_fs_trace) {
139 return;
140 }
141
142 if (ctf_fs_trace->path) {
143 g_string_free(ctf_fs_trace->path, TRUE);
144 }
145
146 if (ctf_fs_trace->name) {
147 g_string_free(ctf_fs_trace->name, TRUE);
148 }
149
150 if (ctf_fs_trace->metadata) {
151 ctf_fs_metadata_fini(ctf_fs_trace->metadata);
152 g_free(ctf_fs_trace->metadata);
153 }
154
155 bt_put(ctf_fs_trace->cc_prio_map);
156 g_free(ctf_fs_trace);
157 }
158
159 void ctf_fs_finalize(struct bt_private_component *component)
160 {
161 void *data = bt_private_component_get_user_data(component);
162
163 ctf_fs_destroy(data);
164 }
165
166 static
167 void port_data_destroy(void *data) {
168 struct ctf_fs_port_data *port_data = data;
169
170 if (!port_data) {
171 return;
172 }
173
174 if (port_data->path) {
175 g_string_free(port_data->path, TRUE);
176 }
177
178 g_free(port_data);
179 }
180
181 static
182 int create_one_port_for_trace(struct ctf_fs_trace *ctf_fs_trace,
183 const char *stream_path)
184 {
185 int ret = 0;
186 struct bt_private_port *port = NULL;
187 struct ctf_fs_port_data *port_data = NULL;
188 GString *port_name = NULL;
189 struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
190
191 port_name = g_string_new(NULL);
192 if (!port_name) {
193 goto error;
194 }
195
196 /* Assign the name for the new output port */
197 g_string_printf(port_name, "%s", stream_path);
198 PDBG("Creating one port named `%s`\n", port_name->str);
199
200 /* Create output port for this file */
201 port_data = g_new0(struct ctf_fs_port_data, 1);
202 if (!port_data) {
203 goto error;
204 }
205
206 port_data->ctf_fs_trace = ctf_fs_trace;
207 port_data->path = g_string_new(stream_path);
208 if (!port_data->path) {
209 goto error;
210 }
211
212 port = bt_private_component_source_add_output_private_port(
213 ctf_fs->priv_comp, port_name->str, port_data);
214 if (!port) {
215 goto error;
216 }
217
218 g_ptr_array_add(ctf_fs->port_data, port_data);
219 port_data = NULL;
220 goto end;
221
222 error:
223 ret = -1;
224
225 end:
226 if (port_name) {
227 g_string_free(port_name, TRUE);
228 }
229
230 bt_put(port);
231 port_data_destroy(port_data);
232 return ret;
233 }
234
235 static
236 int create_ports_for_trace(struct ctf_fs_trace *ctf_fs_trace)
237 {
238 int ret = 0;
239 const char *basename;
240 GError *error = NULL;
241 GDir *dir = NULL;
242 struct ctf_fs_file *file = NULL;
243 struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
244
245 /* Create one output port for each stream file */
246 dir = g_dir_open(ctf_fs_trace->path->str, 0, &error);
247 if (!dir) {
248 PERR("Cannot open directory `%s`: %s (code %d)\n",
249 ctf_fs_trace->path->str, error->message,
250 error->code);
251 goto error;
252 }
253
254 while ((basename = g_dir_read_name(dir))) {
255 if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) {
256 /* Ignore the metadata stream. */
257 PDBG("Ignoring metadata file `%s/%s`\n",
258 ctf_fs_trace->path->str, basename);
259 continue;
260 }
261
262 if (basename[0] == '.') {
263 PDBG("Ignoring hidden file `%s/%s`\n",
264 ctf_fs_trace->path->str, basename);
265 continue;
266 }
267
268 /* Create the file. */
269 file = ctf_fs_file_create(ctf_fs);
270 if (!file) {
271 PERR("Cannot create stream file object for file `%s/%s`\n",
272 ctf_fs_trace->path->str, basename);
273 goto error;
274 }
275
276 /* Create full path string. */
277 g_string_append_printf(file->path, "%s/%s",
278 ctf_fs_trace->path->str, basename);
279 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
280 PDBG("Ignoring non-regular file `%s`\n",
281 file->path->str);
282 ctf_fs_file_destroy(file);
283 file = NULL;
284 continue;
285 }
286
287 ret = ctf_fs_file_open(ctf_fs, file, "rb");
288 if (ret) {
289 PERR("Cannot open stream file `%s`\n", file->path->str);
290 goto error;
291 }
292
293 if (file->size == 0) {
294 /* Skip empty stream. */
295 PDBG("Ignoring empty file `%s`\n", file->path->str);
296 ctf_fs_file_destroy(file);
297 file = NULL;
298 continue;
299 }
300
301 ret = create_one_port_for_trace(ctf_fs_trace, file->path->str);
302 if (ret) {
303 PERR("Cannot create output port for file `%s`\n",
304 file->path->str);
305 goto error;
306 }
307
308 ctf_fs_file_destroy(file);
309 file = NULL;
310 }
311
312 goto end;
313
314 error:
315 ret = -1;
316
317 end:
318 if (dir) {
319 g_dir_close(dir);
320 dir = NULL;
321 }
322
323 if (error) {
324 g_error_free(error);
325 }
326
327 ctf_fs_file_destroy(file);
328 return ret;
329 }
330
331 static
332 int create_cc_prio_map(struct ctf_fs_trace *ctf_fs_trace)
333 {
334 int ret = 0;
335 size_t i;
336 int count;
337
338 assert(ctf_fs_trace);
339 ctf_fs_trace->cc_prio_map = bt_clock_class_priority_map_create();
340 if (!ctf_fs_trace->cc_prio_map) {
341 ret = -1;
342 goto end;
343 }
344
345 count = bt_ctf_trace_get_clock_class_count(
346 ctf_fs_trace->metadata->trace);
347 assert(count >= 0);
348
349 for (i = 0; i < count; i++) {
350 struct bt_ctf_clock_class *clock_class =
351 bt_ctf_trace_get_clock_class_by_index(
352 ctf_fs_trace->metadata->trace, i);
353
354 assert(clock_class);
355 ret = bt_clock_class_priority_map_add_clock_class(
356 ctf_fs_trace->cc_prio_map, clock_class, 0);
357 BT_PUT(clock_class);
358
359 if (ret) {
360 goto end;
361 }
362 }
363
364 end:
365 return ret;
366 }
367
368 static
369 struct ctf_fs_trace *ctf_fs_trace_create(struct ctf_fs_component *ctf_fs,
370 const char *path, const char *name)
371 {
372 struct ctf_fs_trace *ctf_fs_trace;
373 int ret;
374
375 ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
376 if (!ctf_fs_trace) {
377 goto end;
378 }
379
380 ctf_fs_trace->ctf_fs = ctf_fs;
381 ctf_fs_trace->path = g_string_new(path);
382 if (!ctf_fs_trace->path) {
383 goto error;
384 }
385
386 ctf_fs_trace->name = g_string_new(name);
387 if (!ctf_fs_trace->name) {
388 goto error;
389 }
390
391 ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1);
392 if (!ctf_fs_trace->metadata) {
393 goto error;
394 }
395
396 ret = ctf_fs_metadata_set_trace(ctf_fs_trace);
397 if (ret) {
398 goto error;
399 }
400
401 ret = create_cc_prio_map(ctf_fs_trace);
402 if (ret) {
403 goto error;
404 }
405
406 ret = create_ports_for_trace(ctf_fs_trace);
407 if (ret) {
408 goto error;
409 }
410
411 goto end;
412
413 error:
414 ctf_fs_trace_destroy(ctf_fs_trace);
415 ctf_fs_trace = NULL;
416 end:
417 return ctf_fs_trace;
418 }
419
420 static
421 int path_is_ctf_trace(const char *path)
422 {
423 GString *metadata_path = g_string_new(NULL);
424 int ret = 0;
425
426 if (!metadata_path) {
427 ret = -1;
428 goto end;
429 }
430
431 g_string_printf(metadata_path, "%s/%s", path, CTF_FS_METADATA_FILENAME);
432
433 if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) {
434 ret = 1;
435 goto end;
436 }
437
438 end:
439 g_string_free(metadata_path, TRUE);
440 return ret;
441 }
442
443 static
444 int add_trace_path(struct ctf_fs_component *ctf_fs, GList **trace_paths,
445 const char *path)
446 {
447 GString *path_str = g_string_new(NULL);
448 int ret = 0;
449 char *rp = NULL;
450
451 if (!path_str) {
452 ret = -1;
453 goto end;
454 }
455
456 /*
457 * Find the real path so that we don't have relative components
458 * in the trace name. This also squashes consecutive slashes and
459 * removes any slash at the end.
460 */
461 rp = realpath(path, NULL);
462 if (!rp) {
463 PERR("realpath() failed: %s (%d)\n", strerror(errno), errno);
464 ret = -1;
465 goto end;
466 }
467
468 if (strcmp(rp, "/") == 0) {
469 PERR("Opening a trace in `/` is not supported.\n");
470 ret = -1;
471 goto end;
472 }
473
474 g_string_assign(path_str, rp);
475 *trace_paths = g_list_prepend(*trace_paths, path_str);
476 assert(*trace_paths);
477
478 end:
479 free(rp);
480 return ret;
481 }
482
483 static
484 int find_ctf_traces(struct ctf_fs_component *ctf_fs,
485 GList **trace_paths, const char *start_path)
486 {
487 int ret;
488 GError *error = NULL;
489 GDir *dir = NULL;
490 const char *basename = NULL;
491
492 /* Check if the starting path is a CTF trace itself */
493 ret = path_is_ctf_trace(start_path);
494 if (ret < 0) {
495 goto end;
496 }
497
498 if (ret) {
499 /*
500 * Do not even recurse: a CTF trace cannot contain
501 * another CTF trace.
502 */
503 ret = add_trace_path(ctf_fs, trace_paths, start_path);
504 goto end;
505 }
506
507 /* Look for subdirectories */
508 if (!g_file_test(start_path, G_FILE_TEST_IS_DIR)) {
509 /* Starting path is not a directory: end of recursion */
510 goto end;
511 }
512
513 dir = g_dir_open(start_path, 0, &error);
514 if (!dir) {
515 if (error->code == G_FILE_ERROR_ACCES) {
516 PDBG("Cannot open directory `%s`: %s (code %d): continuing\n",
517 start_path, error->message, error->code);
518 goto end;
519 }
520
521 PERR("Cannot open directory `%s`: %s (code %d)\n",
522 start_path, error->message, error->code);
523 ret = -1;
524 goto end;
525 }
526
527 while ((basename = g_dir_read_name(dir))) {
528 GString *sub_path = g_string_new(NULL);
529
530 if (!sub_path) {
531 ret = -1;
532 goto end;
533 }
534
535 g_string_printf(sub_path, "%s/%s", start_path, basename);
536 ret = find_ctf_traces(ctf_fs, trace_paths, sub_path->str);
537 g_string_free(sub_path, TRUE);
538 if (ret) {
539 goto end;
540 }
541 }
542
543 end:
544 if (dir) {
545 g_dir_close(dir);
546 }
547
548 if (error) {
549 g_error_free(error);
550 }
551
552 return ret;
553 }
554
555 static
556 GList *create_trace_names(GList *trace_paths) {
557 GList *trace_names = NULL;
558 size_t chars_to_strip = 0;
559 size_t at = 0;
560 GList *node;
561 bool done = false;
562
563 /*
564 * Find the number of characters to strip from the beginning,
565 * that is, the longest prefix until a common slash (also
566 * stripped).
567 */
568 while (true) {
569 gchar common_ch = '\0';
570
571 for (node = trace_paths; node; node = g_list_next(node)) {
572 GString *gstr = node->data;
573 gchar this_ch = gstr->str[at];
574
575 if (this_ch == '\0') {
576 done = true;
577 break;
578 }
579
580 if (common_ch == '\0') {
581 /*
582 * Establish the expected common
583 * character at this position.
584 */
585 common_ch = this_ch;
586 continue;
587 }
588
589 if (this_ch != common_ch) {
590 done = true;
591 break;
592 }
593 }
594
595 if (done) {
596 break;
597 }
598
599 if (common_ch == '/') {
600 /*
601 * Common character is a slash: safe to include
602 * this slash in the number of characters to
603 * strip because the paths are guaranteed not to
604 * end with slash.
605 */
606 chars_to_strip = at + 1;
607 }
608
609 at++;
610 }
611
612 /* Create the trace names */
613 for (node = trace_paths; node; node = g_list_next(node)) {
614 GString *trace_name = g_string_new(NULL);
615 GString *trace_path = node->data;
616
617 g_string_assign(trace_name, &trace_path->str[chars_to_strip]);
618 trace_names = g_list_append(trace_names, trace_name);
619 }
620
621 return trace_names;
622 }
623
624 static
625 int create_ctf_fs_traces(struct ctf_fs_component *ctf_fs,
626 const char *path_param)
627 {
628 struct ctf_fs_trace *ctf_fs_trace = NULL;
629 int ret = 0;
630 GList *trace_paths = NULL;
631 GList *trace_names = NULL;
632 GList *tp_node;
633 GList *tn_node;
634
635 ret = find_ctf_traces(ctf_fs, &trace_paths, path_param);
636 if (ret) {
637 goto error;
638 }
639
640 if (!trace_paths) {
641 PERR("No CTF traces recursively found in `%s`.\n",
642 path_param);
643 goto error;
644 }
645
646 trace_names = create_trace_names(trace_paths);
647 if (!trace_names) {
648 PERR("Cannot create trace names from trace paths.\n");
649 goto error;
650 }
651
652 for (tp_node = trace_paths, tn_node = trace_names; tp_node;
653 tp_node = g_list_next(tp_node),
654 tn_node = g_list_next(tn_node)) {
655 GString *trace_path = tp_node->data;
656 GString *trace_name = tn_node->data;
657
658 ctf_fs_trace = ctf_fs_trace_create(ctf_fs, trace_path->str,
659 trace_name->str);
660 if (!ctf_fs_trace) {
661 PERR("Cannot create trace for `%s`.\n",
662 trace_path->str);
663 goto error;
664 }
665
666 g_ptr_array_add(ctf_fs->traces, ctf_fs_trace);
667 ctf_fs_trace = NULL;
668 }
669
670 goto end;
671
672 error:
673 ret = -1;
674 ctf_fs_trace_destroy(ctf_fs_trace);
675
676 end:
677 for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) {
678 if (tp_node->data) {
679 g_string_free(tp_node->data, TRUE);
680 }
681 }
682
683 for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) {
684 if (tn_node->data) {
685 g_string_free(tn_node->data, TRUE);
686 }
687 }
688
689 if (trace_paths) {
690 g_list_free(trace_paths);
691 }
692
693 if (trace_names) {
694 g_list_free(trace_names);
695 }
696
697 return ret;
698 }
699
700 static
701 struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
702 struct bt_value *params)
703 {
704 struct ctf_fs_component *ctf_fs;
705 struct bt_value *value = NULL;
706 const char *path_param;
707 int ret;
708
709 ctf_fs = g_new0(struct ctf_fs_component, 1);
710 if (!ctf_fs) {
711 goto end;
712 }
713
714 ret = bt_private_component_set_user_data(priv_comp, ctf_fs);
715 assert(ret == 0);
716
717 /*
718 * We don't need to get a new reference here because as long as
719 * our private ctf_fs_component object exists, the containing
720 * private component should also exist.
721 */
722 ctf_fs->priv_comp = priv_comp;
723 value = bt_value_map_get(params, "path");
724 if (!bt_value_is_string(value)) {
725 goto error;
726 }
727
728 ret = bt_value_string_get(value, &path_param);
729 assert(ret == 0);
730 BT_PUT(value);
731 value = bt_value_map_get(params, "offset-s");
732 if (value) {
733 int64_t offset;
734
735 if (!bt_value_is_integer(value)) {
736 fprintf(stderr,
737 "offset-s should be an integer\n");
738 goto error;
739 }
740 ret = bt_value_integer_get(value, &offset);
741 assert(ret == 0);
742 ctf_fs->options.clock_offset = offset;
743 BT_PUT(value);
744 }
745
746 value = bt_value_map_get(params, "offset-ns");
747 if (value) {
748 int64_t offset;
749
750 if (!bt_value_is_integer(value)) {
751 fprintf(stderr,
752 "offset-ns should be an integer\n");
753 goto error;
754 }
755 ret = bt_value_integer_get(value, &offset);
756 assert(ret == 0);
757 ctf_fs->options.clock_offset_ns = offset;
758 BT_PUT(value);
759 }
760
761 ctf_fs->error_fp = stderr;
762 ctf_fs->page_size = (size_t) getpagesize();
763 ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy);
764 if (!ctf_fs->port_data) {
765 goto error;
766 }
767
768 ctf_fs->traces = g_ptr_array_new_with_free_func(ctf_fs_trace_destroy);
769 if (!ctf_fs->traces) {
770 goto error;
771 }
772
773 ret = create_ctf_fs_traces(ctf_fs, path_param);
774 if (ret) {
775 goto error;
776 }
777
778 goto end;
779
780 error:
781 ctf_fs_destroy(ctf_fs);
782 ctf_fs = NULL;
783 ret = bt_private_component_set_user_data(priv_comp, NULL);
784 assert(ret == 0);
785
786 end:
787 bt_put(value);
788 return ctf_fs;
789 }
790
791 BT_HIDDEN
792 enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp,
793 struct bt_value *params, UNUSED_VAR void *init_method_data)
794 {
795 struct ctf_fs_component *ctf_fs;
796 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
797
798 ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0;
799 ctf_fs = ctf_fs_create(priv_comp, params);
800 if (!ctf_fs) {
801 ret = BT_COMPONENT_STATUS_ERROR;
802 }
803
804 return ret;
805 }
806
807 BT_HIDDEN
808 struct bt_value *ctf_fs_query(struct bt_component_class *comp_class,
809 const char *object, struct bt_value *params)
810 {
811 struct bt_value *results = NULL;
812 struct bt_value *path_value = NULL;
813 char *metadata_text = NULL;
814 FILE *metadata_fp = NULL;
815 GString *g_metadata_text = NULL;
816
817 if (strcmp(object, "metadata-info") == 0) {
818 int ret;
819 int bo;
820 const char *path;
821 bool is_packetized;
822
823 results = bt_value_map_create();
824 if (!results) {
825 goto error;
826 }
827
828 if (!bt_value_is_map(params)) {
829 fprintf(stderr,
830 "Query parameters is not a map value object\n");
831 goto error;
832 }
833
834 path_value = bt_value_map_get(params, "path");
835 ret = bt_value_string_get(path_value, &path);
836 if (ret) {
837 fprintf(stderr,
838 "Cannot get `path` string parameter\n");
839 goto error;
840 }
841
842 assert(path);
843 metadata_fp = ctf_fs_metadata_open_file(path);
844 if (!metadata_fp) {
845 fprintf(stderr,
846 "Cannot open trace at path `%s`\n", path);
847 goto error;
848 }
849
850 is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp,
851 &bo);
852
853 if (is_packetized) {
854 ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
855 metadata_fp, &metadata_text, bo);
856 if (ret) {
857 fprintf(stderr,
858 "Cannot decode packetized metadata file\n");
859 goto error;
860 }
861 } else {
862 long filesize;
863
864 fseek(metadata_fp, 0, SEEK_END);
865 filesize = ftell(metadata_fp);
866 rewind(metadata_fp);
867 metadata_text = malloc(filesize + 1);
868 if (!metadata_text) {
869 fprintf(stderr,
870 "Cannot allocate buffer for metadata text\n");
871 goto error;
872 }
873
874 if (fread(metadata_text, filesize, 1, metadata_fp) !=
875 1) {
876 fprintf(stderr,
877 "Cannot read metadata file\n");
878 goto error;
879 }
880
881 metadata_text[filesize] = '\0';
882 }
883
884 g_metadata_text = g_string_new(NULL);
885 if (!g_metadata_text) {
886 goto error;
887 }
888
889 if (strncmp(metadata_text, METADATA_TEXT_SIG,
890 sizeof(METADATA_TEXT_SIG) - 1) != 0) {
891 g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
892 g_string_append(g_metadata_text, " */\n\n");
893 }
894
895 g_string_append(g_metadata_text, metadata_text);
896
897 ret = bt_value_map_insert_string(results, "text",
898 g_metadata_text->str);
899 if (ret) {
900 fprintf(stderr, "Cannot insert metadata text into results\n");
901 goto error;
902 }
903
904 ret = bt_value_map_insert_bool(results, "is-packetized",
905 is_packetized);
906 if (ret) {
907 fprintf(stderr, "Cannot insert is packetized into results\n");
908 goto error;
909 }
910 } else {
911 fprintf(stderr, "Unknown query object `%s`\n", object);
912 goto error;
913 }
914
915 goto end;
916
917 error:
918 BT_PUT(results);
919
920 end:
921 bt_put(path_value);
922 free(metadata_text);
923
924 if (g_metadata_text) {
925 g_string_free(g_metadata_text, TRUE);
926 }
927
928 if (metadata_fp) {
929 fclose(metadata_fp);
930 }
931 return results;
932 }
This page took 0.0478 seconds and 5 git commands to generate.