-
-static
-int ctf_fs_find_traces(GList **trace_paths, const char *start_path,
- bt_logging_level log_level, bt_self_component *self_comp)
-{
- int ret;
- GError *error = NULL;
- GDir *dir = NULL;
- const char *basename = NULL;
-
- /* Check if the starting path is a CTF trace itself */
- ret = path_is_ctf_trace(start_path);
- if (ret < 0) {
- goto end;
- }
-
- if (ret) {
- /*
- * Stop recursion: a CTF trace cannot contain another
- * CTF trace.
- */
- ret = add_trace_path(trace_paths, start_path, log_level,
- self_comp);
- goto end;
- }
-
- /* Look for subdirectories */
- if (!g_file_test(start_path, G_FILE_TEST_IS_DIR)) {
- /* Starting path is not a directory: end of recursion */
- goto end;
- }
-
- dir = g_dir_open(start_path, 0, &error);
- if (!dir) {
- if (error->code == G_FILE_ERROR_ACCES) {
- BT_COMP_LOGI("Cannot open directory `%s`: %s (code %d): continuing",
- start_path, error->message, error->code);
- goto end;
- }
-
- BT_COMP_LOGE("Cannot open directory `%s`: %s (code %d)",
- start_path, error->message, error->code);
- ret = -1;
- goto end;
- }
-
- while ((basename = g_dir_read_name(dir))) {
- GString *sub_path = g_string_new(NULL);
-
- if (!sub_path) {
- ret = -1;
- goto end;
- }
-
- g_string_printf(sub_path, "%s" G_DIR_SEPARATOR_S "%s", start_path, basename);
- ret = ctf_fs_find_traces(trace_paths, sub_path->str,
- log_level, self_comp);
- g_string_free(sub_path, TRUE);
- if (ret) {
- goto end;
- }
- }
-
-end:
- if (dir) {
- g_dir_close(dir);
- }
-
- if (error) {
- g_error_free(error);
- }
-
- return ret;
-}
-
-static
-GList *ctf_fs_create_trace_names(GList *trace_paths, const char *base_path) {
- GList *trace_names = NULL;
- GList *node;
- const char *last_sep;
- size_t base_dist;
-
- /*
- * At this point we know that all the trace paths are
- * normalized, and so is the base path. This means that
- * they are absolute and they don't end with a separator.
- * We can simply find the location of the last separator
- * in the base path, which gives us the name of the actual
- * directory to look into, and use this location as the
- * start of each trace name within each trace path.
- *
- * For example:
- *
- * Base path: /home/user/my-traces/some-trace
- * Trace paths:
- * - /home/user/my-traces/some-trace/host1/trace1
- * - /home/user/my-traces/some-trace/host1/trace2
- * - /home/user/my-traces/some-trace/host2/trace
- * - /home/user/my-traces/some-trace/other-trace
- *
- * In this case the trace names are:
- *
- * - some-trace/host1/trace1
- * - some-trace/host1/trace2
- * - some-trace/host2/trace
- * - some-trace/other-trace
- */
- last_sep = strrchr(base_path, G_DIR_SEPARATOR);
-
- /* We know there's at least one separator */
- BT_ASSERT(last_sep);
-
- /* Distance to base */
- base_dist = last_sep - base_path + 1;
-
- /* Create the trace names */
- for (node = trace_paths; node; node = g_list_next(node)) {
- GString *trace_name = g_string_new(NULL);
- GString *trace_path = node->data;
-
- BT_ASSERT(trace_name);
- g_string_assign(trace_name, &trace_path->str[base_dist]);
- trace_names = g_list_append(trace_names, trace_name);
- }
-
- return trace_names;
-}
-
-/* Helper for ctf_fs_component_create_ctf_fs_traces, to handle a single path/root. */
-
-static
-int ctf_fs_component_create_ctf_fs_traces_one_root(
- struct ctf_fs_component *ctf_fs,
- const char *path_param)
-{
- struct ctf_fs_trace *ctf_fs_trace = NULL;
- int ret = 0;
- GString *norm_path = NULL;
- GList *trace_paths = NULL;
- GList *trace_names = NULL;
- GList *tp_node;
- GList *tn_node;
- bt_logging_level log_level = ctf_fs->log_level;
- bt_self_component *self_comp = ctf_fs->self_comp;
-
- norm_path = bt_common_normalize_path(path_param, NULL);
- if (!norm_path) {
- BT_COMP_LOGE("Failed to normalize path: `%s`.",
- path_param);
- goto error;
- }
-
- ret = ctf_fs_find_traces(&trace_paths, norm_path->str, log_level,
- self_comp);
- if (ret) {
- goto error;
- }
-
- if (!trace_paths) {
- BT_COMP_LOGE("No CTF traces recursively found in `%s`.",
- path_param);
- (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
- ctf_fs->self_comp,
- "No CTF traces recursively found in `%s`.", path_param);
- goto error;
- }
-
- trace_names = ctf_fs_create_trace_names(trace_paths, norm_path->str);
- if (!trace_names) {
- BT_COMP_LOGE("Cannot create trace names from trace paths.");
- goto error;
- }
-
- for (tp_node = trace_paths, tn_node = trace_names; tp_node;
- tp_node = g_list_next(tp_node),
- tn_node = g_list_next(tn_node)) {
- GString *trace_path = tp_node->data;
- GString *trace_name = tn_node->data;
-
- ctf_fs_trace = ctf_fs_trace_create(self_comp,
- trace_path->str, trace_name->str,
- &ctf_fs->metadata_config,
- log_level);
- if (!ctf_fs_trace) {
- BT_COMP_LOGE("Cannot create trace for `%s`.",
- trace_path->str);
- goto error;
- }
-
- g_ptr_array_add(ctf_fs->traces, ctf_fs_trace);
- ctf_fs_trace = NULL;
- }
-
- goto end;
-
-error:
- ret = -1;
- ctf_fs_trace_destroy(ctf_fs_trace);
-
-end:
- for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) {
- if (tp_node->data) {
- g_string_free(tp_node->data, TRUE);
- }
- }
-
- for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) {
- if (tn_node->data) {
- g_string_free(tn_node->data, TRUE);
- }
- }
-
- if (trace_paths) {
- g_list_free(trace_paths);
- }
-
- if (trace_names) {
- g_list_free(trace_names);
- }
-
- if (norm_path) {
- g_string_free(norm_path, TRUE);
- }
-
- return ret;
-}
-
-/* GCompareFunc to sort traces by UUID. */
-
-static
-gint sort_traces_by_uuid(gconstpointer a, gconstpointer b)
-{
- const struct ctf_fs_trace *trace_a = *((const struct ctf_fs_trace **) a);
- const struct ctf_fs_trace *trace_b = *((const struct ctf_fs_trace **) b);
-
- bool trace_a_has_uuid = trace_a->metadata->tc->is_uuid_set;
- bool trace_b_has_uuid = trace_b->metadata->tc->is_uuid_set;
- gint ret;
-
- /* Order traces without uuid first. */
- if (!trace_a_has_uuid && trace_b_has_uuid) {
- ret = -1;
- } else if (trace_a_has_uuid && !trace_b_has_uuid) {
- ret = 1;
- } else if (!trace_a_has_uuid && !trace_b_has_uuid) {
- ret = 0;
- } else {
- ret = bt_uuid_compare(trace_a->metadata->tc->uuid, trace_b->metadata->tc->uuid);
- }
-
- return ret;
-}
-
-/*
- * Count the number of stream and event classes defined by this trace's metadata.
- *
- * This is used to determine which metadata is the "latest", out of multiple
- * traces sharing the same UUID. It is assumed that amongst all these metadatas,
- * a bigger metadata is a superset of a smaller metadata. Therefore, it is
- * enough to just count the classes.
- */