Commit | Line | Data |
---|---|---|
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> |
4f1f88a6 | 31 | #include <babeltrace/graph/private-port.h> |
b2e0c907 | 32 | #include <babeltrace/graph/private-component.h> |
4f1f88a6 PP |
33 | #include <babeltrace/graph/private-component-source.h> |
34 | #include <babeltrace/graph/private-notification-iterator.h> | |
b2e0c907 PP |
35 | #include <babeltrace/graph/component.h> |
36 | #include <babeltrace/graph/notification-iterator.h> | |
599faa1c | 37 | #include <babeltrace/graph/clock-class-priority-map.h> |
7d61fa8e | 38 | #include <plugins-common.h> |
ea0b4b9e JG |
39 | #include <glib.h> |
40 | #include <assert.h> | |
56a1cced JG |
41 | #include <unistd.h> |
42 | #include "fs.h" | |
413bc2c4 JG |
43 | #include "metadata.h" |
44 | #include "data-stream.h" | |
e7a4393b | 45 | #include "file.h" |
1e649dff | 46 | #include "../common/metadata/decoder.h" |
e7a4393b JG |
47 | |
48 | #define PRINT_ERR_STREAM ctf_fs->error_fp | |
49 | #define PRINT_PREFIX "ctf-fs" | |
50 | #include "print.h" | |
33f93973 | 51 | #define METADATA_TEXT_SIG "/* CTF 1.8" |
ea0b4b9e | 52 | |
78bb6992 MD |
53 | BT_HIDDEN |
54 | bool ctf_fs_debug; | |
ea0b4b9e | 55 | |
41a2b7ae | 56 | struct bt_notification_iterator_next_return ctf_fs_iterator_next( |
4f1f88a6 | 57 | struct bt_private_notification_iterator *iterator) |
ea0b4b9e | 58 | { |
4f1f88a6 PP |
59 | struct ctf_fs_stream *fs_stream = |
60 | bt_private_notification_iterator_get_user_data(iterator); | |
d01e0f33 | 61 | |
4f1f88a6 | 62 | return ctf_fs_stream_next(fs_stream); |
ea0b4b9e | 63 | } |
bfd20a42 | 64 | |
4f1f88a6 | 65 | void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it) |
760051fa | 66 | { |
4f1f88a6 PP |
67 | void *ctf_fs_stream = |
68 | bt_private_notification_iterator_get_user_data(it); | |
760051fa | 69 | |
4f1f88a6 | 70 | ctf_fs_stream_destroy(ctf_fs_stream); |
760051fa JG |
71 | } |
72 | ||
4f1f88a6 PP |
73 | enum bt_notification_iterator_status ctf_fs_iterator_init( |
74 | struct bt_private_notification_iterator *it, | |
75 | struct bt_private_port *port) | |
4c1456f0 | 76 | { |
4f1f88a6 PP |
77 | struct ctf_fs_stream *stream = NULL; |
78 | struct ctf_fs_component *ctf_fs; | |
79 | struct ctf_fs_port_data *port_data; | |
80 | struct bt_private_component *priv_comp = | |
81 | bt_private_notification_iterator_get_private_component(it); | |
82 | enum bt_notification_iterator_status ret = | |
83 | BT_NOTIFICATION_ITERATOR_STATUS_OK; | |
760051fa | 84 | |
4f1f88a6 | 85 | assert(priv_comp); |
5b29e799 | 86 | |
4f1f88a6 PP |
87 | ctf_fs = bt_private_component_get_user_data(priv_comp); |
88 | if (!ctf_fs) { | |
fe8ad2b6 | 89 | ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; |
4f1f88a6 | 90 | goto error; |
760051fa JG |
91 | } |
92 | ||
4f1f88a6 PP |
93 | port_data = bt_private_port_get_user_data(port); |
94 | if (!port_data) { | |
fe8ad2b6 | 95 | ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; |
4f1f88a6 PP |
96 | goto error; |
97 | } | |
5b29e799 | 98 | |
4f1f88a6 | 99 | stream = ctf_fs_stream_create(ctf_fs, port_data->path->str); |
5b29e799 | 100 | if (!stream) { |
4f1f88a6 | 101 | goto error; |
760051fa JG |
102 | } |
103 | ||
4f1f88a6 PP |
104 | ret = bt_private_notification_iterator_set_user_data(it, stream); |
105 | if (ret) { | |
106 | goto error; | |
760051fa JG |
107 | } |
108 | ||
4f1f88a6 PP |
109 | stream = NULL; |
110 | goto end; | |
5b29e799 | 111 | |
4f1f88a6 PP |
112 | error: |
113 | (void) bt_private_notification_iterator_set_user_data(it, NULL); | |
114 | ||
115 | if (ret == BT_NOTIFICATION_ITERATOR_STATUS_OK) { | |
116 | ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; | |
760051fa | 117 | } |
5b29e799 | 118 | |
760051fa | 119 | end: |
4f1f88a6 PP |
120 | ctf_fs_stream_destroy(stream); |
121 | bt_put(priv_comp); | |
760051fa JG |
122 | return ret; |
123 | } | |
124 | ||
760051fa | 125 | static |
4f1f88a6 | 126 | void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs) |
760051fa | 127 | { |
4f1f88a6 | 128 | if (!ctf_fs) { |
8fa760ba JG |
129 | return; |
130 | } | |
4f1f88a6 PP |
131 | |
132 | if (ctf_fs->trace_path) { | |
133 | g_string_free(ctf_fs->trace_path, TRUE); | |
56a1cced | 134 | } |
4f1f88a6 PP |
135 | |
136 | if (ctf_fs->port_data) { | |
137 | g_ptr_array_free(ctf_fs->port_data, TRUE); | |
c14d7e26 | 138 | } |
760051fa | 139 | |
4f1f88a6 PP |
140 | if (ctf_fs->metadata) { |
141 | ctf_fs_metadata_fini(ctf_fs->metadata); | |
142 | g_free(ctf_fs->metadata); | |
143 | } | |
760051fa | 144 | |
599faa1c | 145 | bt_put(ctf_fs->cc_prio_map); |
4f1f88a6 | 146 | g_free(ctf_fs); |
4c1456f0 JG |
147 | } |
148 | ||
4f1f88a6 | 149 | void ctf_fs_finalize(struct bt_private_component *component) |
a4792757 | 150 | { |
4f1f88a6 PP |
151 | void *data = bt_private_component_get_user_data(component); |
152 | ||
153 | ctf_fs_destroy_data(data); | |
a4792757 JG |
154 | } |
155 | ||
e7a4393b | 156 | static |
4f1f88a6 PP |
157 | void port_data_destroy(void *data) { |
158 | struct ctf_fs_port_data *port_data = data; | |
159 | ||
160 | if (!port_data) { | |
161 | return; | |
162 | } | |
163 | ||
164 | if (port_data->path) { | |
165 | g_string_free(port_data->path, TRUE); | |
166 | } | |
167 | ||
168 | g_free(port_data); | |
5b29e799 JG |
169 | } |
170 | ||
171 | static | |
4f1f88a6 PP |
172 | int create_one_port(struct ctf_fs_component *ctf_fs, |
173 | const char *stream_basename, const char *stream_path) | |
5b29e799 | 174 | { |
4f1f88a6 PP |
175 | int ret = 0; |
176 | struct bt_private_port *port = NULL; | |
177 | struct ctf_fs_port_data *port_data = NULL; | |
178 | GString *port_name = NULL; | |
179 | ||
180 | port_name = g_string_new(NULL); | |
181 | if (!port_name) { | |
182 | goto error; | |
183 | } | |
184 | ||
185 | /* Assign the name for the new output port */ | |
186 | g_string_assign(port_name, ""); | |
187 | g_string_printf(port_name, "trace0-stream-%s", stream_basename); | |
188 | PDBG("Creating one port named `%s` associated with path `%s`\n", | |
189 | port_name->str, stream_path); | |
190 | ||
191 | /* Create output port for this file */ | |
4f1f88a6 PP |
192 | port_data = g_new0(struct ctf_fs_port_data, 1); |
193 | if (!port_data) { | |
194 | goto error; | |
195 | } | |
196 | ||
197 | port_data->path = g_string_new(stream_path); | |
198 | if (!port_data->path) { | |
199 | goto error; | |
200 | } | |
201 | ||
3e9b0023 PP |
202 | port = bt_private_component_source_add_output_private_port( |
203 | ctf_fs->priv_comp, port_name->str, port_data); | |
204 | if (!port) { | |
4f1f88a6 PP |
205 | goto error; |
206 | } | |
207 | ||
208 | g_ptr_array_add(ctf_fs->port_data, port_data); | |
209 | port_data = NULL; | |
210 | goto end; | |
211 | ||
212 | error: | |
213 | ret = -1; | |
214 | ||
215 | end: | |
216 | if (port_name) { | |
217 | g_string_free(port_name, TRUE); | |
218 | } | |
219 | ||
220 | bt_put(port); | |
221 | port_data_destroy(port_data); | |
222 | return ret; | |
5b29e799 JG |
223 | } |
224 | ||
225 | static | |
4f1f88a6 | 226 | int create_ports(struct ctf_fs_component *ctf_fs) |
e7a4393b JG |
227 | { |
228 | int ret = 0; | |
4f1f88a6 | 229 | const char *basename; |
e7a4393b | 230 | GError *error = NULL; |
4f1f88a6 PP |
231 | GDir *dir = NULL; |
232 | struct bt_private_port *def_port; | |
233 | struct ctf_fs_file *file = NULL; | |
e7a4393b | 234 | |
4f1f88a6 PP |
235 | /* Remove default port if needed */ |
236 | def_port = bt_private_component_source_get_default_output_private_port( | |
237 | ctf_fs->priv_comp); | |
238 | if (def_port) { | |
239 | bt_private_port_remove_from_component(def_port); | |
240 | bt_put(def_port); | |
241 | } | |
242 | ||
243 | /* Create one output port for each stream file */ | |
244 | dir = g_dir_open(ctf_fs->trace_path->str, 0, &error); | |
e7a4393b | 245 | if (!dir) { |
4f1f88a6 PP |
246 | PERR("Cannot open directory `%s`: %s (code %d)\n", |
247 | ctf_fs->trace_path->str, error->message, | |
248 | error->code); | |
e7a4393b JG |
249 | goto error; |
250 | } | |
251 | ||
4f1f88a6 PP |
252 | while ((basename = g_dir_read_name(dir))) { |
253 | if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) { | |
e7a4393b | 254 | /* Ignore the metadata stream. */ |
4f1f88a6 | 255 | PDBG("Ignoring metadata file `%s`\n", basename); |
e7a4393b JG |
256 | continue; |
257 | } | |
258 | ||
4f1f88a6 PP |
259 | if (basename[0] == '.') { |
260 | PDBG("Ignoring hidden file `%s`\n", basename); | |
e7a4393b JG |
261 | continue; |
262 | } | |
263 | ||
264 | /* Create the file. */ | |
265 | file = ctf_fs_file_create(ctf_fs); | |
266 | if (!file) { | |
4f1f88a6 PP |
267 | PERR("Cannot create stream file object for file `%s`\n", |
268 | basename); | |
e7a4393b JG |
269 | goto error; |
270 | } | |
271 | ||
272 | /* Create full path string. */ | |
273 | g_string_append_printf(file->path, "%s/%s", | |
4f1f88a6 | 274 | ctf_fs->trace_path->str, basename); |
e7a4393b | 275 | if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) { |
4f1f88a6 | 276 | PDBG("Ignoring non-regular file `%s`\n", basename); |
e7a4393b | 277 | ctf_fs_file_destroy(file); |
4f1f88a6 | 278 | file = NULL; |
e7a4393b JG |
279 | continue; |
280 | } | |
281 | ||
4f1f88a6 PP |
282 | ret = ctf_fs_file_open(ctf_fs, file, "rb"); |
283 | if (ret) { | |
284 | PERR("Cannot open stream file `%s`\n", basename); | |
e7a4393b JG |
285 | goto error; |
286 | } | |
287 | ||
9fa0891a JG |
288 | if (file->size == 0) { |
289 | /* Skip empty stream. */ | |
4f1f88a6 | 290 | PDBG("Ignoring empty file `%s`\n", basename); |
9fa0891a | 291 | ctf_fs_file_destroy(file); |
4f1f88a6 | 292 | file = NULL; |
9fa0891a JG |
293 | continue; |
294 | } | |
295 | ||
4f1f88a6 PP |
296 | ret = create_one_port(ctf_fs, basename, file->path->str); |
297 | if (ret) { | |
298 | PERR("Cannot create output port for file `%s`\n", | |
299 | basename); | |
e7a4393b JG |
300 | goto error; |
301 | } | |
302 | ||
4f1f88a6 PP |
303 | ctf_fs_file_destroy(file); |
304 | file = NULL; | |
e7a4393b JG |
305 | } |
306 | ||
307 | goto end; | |
4f1f88a6 | 308 | |
e7a4393b JG |
309 | error: |
310 | ret = -1; | |
4f1f88a6 | 311 | |
e7a4393b JG |
312 | end: |
313 | if (dir) { | |
314 | g_dir_close(dir); | |
315 | dir = NULL; | |
316 | } | |
4f1f88a6 | 317 | |
e7a4393b JG |
318 | if (error) { |
319 | g_error_free(error); | |
320 | } | |
5b29e799 | 321 | |
4f1f88a6 | 322 | ctf_fs_file_destroy(file); |
91457551 | 323 | return ret; |
5b29e799 JG |
324 | } |
325 | ||
599faa1c PP |
326 | static |
327 | int create_cc_prio_map(struct ctf_fs_component *ctf_fs) | |
328 | { | |
329 | int ret = 0; | |
330 | size_t i; | |
331 | int count; | |
332 | ||
333 | assert(ctf_fs); | |
334 | ctf_fs->cc_prio_map = bt_clock_class_priority_map_create(); | |
335 | if (!ctf_fs->cc_prio_map) { | |
336 | ret = -1; | |
337 | goto end; | |
338 | } | |
339 | ||
340 | count = bt_ctf_trace_get_clock_class_count(ctf_fs->metadata->trace); | |
341 | assert(count >= 0); | |
342 | ||
343 | for (i = 0; i < count; i++) { | |
344 | struct bt_ctf_clock_class *clock_class = | |
9ac68eb1 PP |
345 | bt_ctf_trace_get_clock_class_by_index( |
346 | ctf_fs->metadata->trace, i); | |
599faa1c PP |
347 | |
348 | assert(clock_class); | |
349 | ret = bt_clock_class_priority_map_add_clock_class( | |
350 | ctf_fs->cc_prio_map, clock_class, 0); | |
351 | BT_PUT(clock_class); | |
352 | ||
353 | if (ret) { | |
354 | goto end; | |
355 | } | |
356 | } | |
357 | ||
358 | end: | |
359 | return ret; | |
360 | } | |
361 | ||
5b29e799 | 362 | static |
4f1f88a6 PP |
363 | struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, |
364 | struct bt_value *params) | |
56a1cced JG |
365 | { |
366 | struct ctf_fs_component *ctf_fs; | |
1ef09eb5 | 367 | struct bt_value *value = NULL; |
56a1cced | 368 | const char *path; |
4f1f88a6 | 369 | int ret; |
56a1cced JG |
370 | |
371 | ctf_fs = g_new0(struct ctf_fs_component, 1); | |
372 | if (!ctf_fs) { | |
373 | goto end; | |
374 | } | |
375 | ||
4f1f88a6 PP |
376 | /* |
377 | * We don't need to get a new reference here because as long as | |
378 | * our private ctf_fs_component object exists, the containing | |
379 | * private component should also exist. | |
380 | */ | |
381 | ctf_fs->priv_comp = priv_comp; | |
382 | ||
56a1cced JG |
383 | /* FIXME: should probably look for a source URI */ |
384 | value = bt_value_map_get(params, "path"); | |
385 | if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) { | |
386 | goto error; | |
387 | } | |
388 | ||
389 | ret = bt_value_string_get(value, &path); | |
4f1f88a6 PP |
390 | if (ret) { |
391 | goto error; | |
392 | } | |
393 | ||
394 | ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy); | |
395 | if (!ctf_fs->port_data) { | |
56a1cced JG |
396 | goto error; |
397 | } | |
398 | ||
399 | ctf_fs->trace_path = g_string_new(path); | |
400 | if (!ctf_fs->trace_path) { | |
92540773 | 401 | BT_PUT(value); |
56a1cced JG |
402 | goto error; |
403 | } | |
92540773 JD |
404 | bt_put(value); |
405 | ||
406 | value = bt_value_map_get(params, "offset-s"); | |
407 | if (value) { | |
408 | int64_t offset; | |
409 | ||
410 | if (!bt_value_is_integer(value)) { | |
411 | fprintf(stderr, | |
412 | "offset-s should be an integer\n"); | |
413 | goto error; | |
414 | } | |
415 | ret = bt_value_integer_get(value, &offset); | |
416 | if (ret != BT_VALUE_STATUS_OK) { | |
417 | fprintf(stderr, | |
418 | "Failed to get offset-s value\n"); | |
419 | goto error; | |
420 | } | |
421 | ctf_fs->options.clock_offset = offset; | |
422 | bt_put(value); | |
423 | } | |
424 | ||
425 | value = bt_value_map_get(params, "offset-ns"); | |
426 | if (value) { | |
427 | int64_t offset; | |
428 | ||
429 | if (!bt_value_is_integer(value)) { | |
430 | fprintf(stderr, | |
431 | "offset-ns should be an integer\n"); | |
432 | goto error; | |
433 | } | |
434 | ret = bt_value_integer_get(value, &offset); | |
435 | if (ret != BT_VALUE_STATUS_OK) { | |
436 | fprintf(stderr, | |
437 | "Failed to get offset-ns value\n"); | |
438 | goto error; | |
439 | } | |
440 | ctf_fs->options.clock_offset_ns = offset; | |
441 | bt_put(value); | |
442 | } | |
443 | ||
56a1cced JG |
444 | ctf_fs->error_fp = stderr; |
445 | ctf_fs->page_size = (size_t) getpagesize(); | |
e7a4393b JG |
446 | |
447 | // FIXME: check error. | |
5b29e799 JG |
448 | ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1); |
449 | if (!ctf_fs->metadata) { | |
e7a4393b JG |
450 | goto error; |
451 | } | |
4f1f88a6 PP |
452 | |
453 | ret = ctf_fs_metadata_set_trace(ctf_fs); | |
454 | if (ret) { | |
455 | goto error; | |
456 | } | |
457 | ||
599faa1c PP |
458 | ret = create_cc_prio_map(ctf_fs); |
459 | if (ret) { | |
460 | goto error; | |
461 | } | |
462 | ||
4f1f88a6 PP |
463 | ret = create_ports(ctf_fs); |
464 | if (ret) { | |
465 | goto error; | |
466 | } | |
467 | ||
1ef09eb5 JG |
468 | goto end; |
469 | ||
56a1cced JG |
470 | error: |
471 | ctf_fs_destroy_data(ctf_fs); | |
e7a4393b | 472 | ctf_fs = NULL; |
1ef09eb5 | 473 | end: |
56a1cced JG |
474 | return ctf_fs; |
475 | } | |
476 | ||
ea0b4b9e | 477 | BT_HIDDEN |
4f1f88a6 | 478 | enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp, |
7d61fa8e | 479 | struct bt_value *params, UNUSED_VAR void *init_method_data) |
ea0b4b9e JG |
480 | { |
481 | struct ctf_fs_component *ctf_fs; | |
482 | enum bt_component_status ret = BT_COMPONENT_STATUS_OK; | |
483 | ||
4f1f88a6 | 484 | assert(priv_comp); |
ea0b4b9e | 485 | ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0; |
4f1f88a6 | 486 | ctf_fs = ctf_fs_create(priv_comp, params); |
ea0b4b9e JG |
487 | if (!ctf_fs) { |
488 | ret = BT_COMPONENT_STATUS_NOMEM; | |
489 | goto end; | |
490 | } | |
4c1456f0 | 491 | |
4f1f88a6 | 492 | ret = bt_private_component_set_user_data(priv_comp, ctf_fs); |
ea0b4b9e JG |
493 | if (ret != BT_COMPONENT_STATUS_OK) { |
494 | goto error; | |
495 | } | |
ea0b4b9e JG |
496 | end: |
497 | return ret; | |
498 | error: | |
4f1f88a6 | 499 | (void) bt_private_component_set_user_data(priv_comp, NULL); |
760051fa | 500 | ctf_fs_destroy_data(ctf_fs); |
ea0b4b9e JG |
501 | return ret; |
502 | } | |
33f93973 PP |
503 | |
504 | BT_HIDDEN | |
a67681c1 PP |
505 | struct bt_value *ctf_fs_query(struct bt_component_class *comp_class, |
506 | const char *object, struct bt_value *params) | |
33f93973 PP |
507 | { |
508 | struct bt_value *results = NULL; | |
509 | struct bt_value *path_value = NULL; | |
510 | char *metadata_text = NULL; | |
511 | FILE *metadata_fp = NULL; | |
512 | GString *g_metadata_text = NULL; | |
513 | ||
a67681c1 | 514 | if (strcmp(object, "metadata-info") == 0) { |
33f93973 PP |
515 | int ret; |
516 | int bo; | |
517 | const char *path; | |
518 | bool is_packetized; | |
519 | ||
520 | results = bt_value_map_create(); | |
521 | if (!results) { | |
522 | goto error; | |
523 | } | |
524 | ||
525 | if (!bt_value_is_map(params)) { | |
526 | fprintf(stderr, | |
a67681c1 | 527 | "Query parameters is not a map value object\n"); |
33f93973 PP |
528 | goto error; |
529 | } | |
530 | ||
531 | path_value = bt_value_map_get(params, "path"); | |
532 | ret = bt_value_string_get(path_value, &path); | |
533 | if (ret) { | |
534 | fprintf(stderr, | |
535 | "Cannot get `path` string parameter\n"); | |
536 | goto error; | |
537 | } | |
538 | ||
539 | assert(path); | |
540 | metadata_fp = ctf_fs_metadata_open_file(path); | |
541 | if (!metadata_fp) { | |
542 | fprintf(stderr, | |
543 | "Cannot open trace at path `%s`\n", path); | |
544 | goto error; | |
545 | } | |
546 | ||
1e649dff PP |
547 | is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp, |
548 | &bo); | |
33f93973 PP |
549 | |
550 | if (is_packetized) { | |
1e649dff PP |
551 | ret = ctf_metadata_decoder_packetized_file_stream_to_buf( |
552 | metadata_fp, &metadata_text, bo); | |
33f93973 PP |
553 | if (ret) { |
554 | fprintf(stderr, | |
555 | "Cannot decode packetized metadata file\n"); | |
556 | goto error; | |
557 | } | |
558 | } else { | |
559 | long filesize; | |
560 | ||
561 | fseek(metadata_fp, 0, SEEK_END); | |
562 | filesize = ftell(metadata_fp); | |
563 | rewind(metadata_fp); | |
564 | metadata_text = malloc(filesize + 1); | |
565 | if (!metadata_text) { | |
566 | fprintf(stderr, | |
567 | "Cannot allocate buffer for metadata text\n"); | |
568 | goto error; | |
569 | } | |
570 | ||
571 | if (fread(metadata_text, filesize, 1, metadata_fp) != | |
572 | 1) { | |
573 | fprintf(stderr, | |
574 | "Cannot read metadata file\n"); | |
575 | goto error; | |
576 | } | |
577 | ||
578 | metadata_text[filesize] = '\0'; | |
579 | } | |
580 | ||
581 | g_metadata_text = g_string_new(NULL); | |
582 | if (!g_metadata_text) { | |
583 | goto error; | |
584 | } | |
585 | ||
586 | if (strncmp(metadata_text, METADATA_TEXT_SIG, | |
587 | sizeof(METADATA_TEXT_SIG) - 1) != 0) { | |
588 | g_string_assign(g_metadata_text, METADATA_TEXT_SIG); | |
589 | g_string_append(g_metadata_text, " */\n\n"); | |
590 | } | |
591 | ||
592 | g_string_append(g_metadata_text, metadata_text); | |
593 | ||
594 | ret = bt_value_map_insert_string(results, "text", | |
595 | g_metadata_text->str); | |
596 | if (ret) { | |
597 | fprintf(stderr, "Cannot insert metadata text into results\n"); | |
598 | goto error; | |
599 | } | |
600 | ||
601 | ret = bt_value_map_insert_bool(results, "is-packetized", | |
602 | is_packetized); | |
603 | if (ret) { | |
604 | fprintf(stderr, "Cannot insert is packetized into results\n"); | |
605 | goto error; | |
606 | } | |
607 | } else { | |
a67681c1 | 608 | fprintf(stderr, "Unknown query object `%s`\n", object); |
33f93973 PP |
609 | goto error; |
610 | } | |
611 | ||
612 | goto end; | |
613 | ||
614 | error: | |
615 | BT_PUT(results); | |
616 | ||
617 | end: | |
618 | bt_put(path_value); | |
619 | free(metadata_text); | |
620 | ||
621 | if (g_metadata_text) { | |
622 | g_string_free(g_metadata_text, TRUE); | |
623 | } | |
624 | ||
625 | if (metadata_fp) { | |
626 | fclose(metadata_fp); | |
627 | } | |
628 | return results; | |
629 | } |