+/*
+ * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <lttng/action/path-internal.h>
+
+struct lttng_action_path_comm {
+ uint32_t index_count;
+ uint64_t indexes[];
+} LTTNG_PACKED;
+
+struct lttng_action_path *lttng_action_path_create(
+ const uint64_t *indexes, size_t index_count)
+{
+ int ret;
+ size_t i;
+ struct lttng_action_path *path = NULL;
+
+ if (!indexes && index_count > 0) {
+ goto error;
+ }
+
+ path = zmalloc(sizeof(*path));
+ if (!path) {
+ goto error;
+ }
+
+ lttng_dynamic_array_init(&path->indexes, sizeof(uint64_t), NULL);
+ ret = lttng_dynamic_array_set_count(&path->indexes, index_count);
+ if (ret) {
+ goto error;
+ }
+
+ for (i = 0; i < index_count; i++) {
+ ret = lttng_dynamic_array_add_element(
+ &path->indexes, &indexes[i]);
+ if (ret) {
+ goto error;
+ }
+ }
+
+ goto end;
+error:
+ lttng_action_path_destroy(path);
+ path = NULL;
+end:
+ return path;
+}
+
+enum lttng_action_path_status lttng_action_path_get_index_count(
+ const struct lttng_action_path *path, size_t *index_count)
+{
+ enum lttng_action_path_status status;
+
+ if (!path || !index_count) {
+ status = LTTNG_ACTION_PATH_STATUS_INVALID;
+ goto end;
+ }
+
+ *index_count = lttng_dynamic_array_get_count(&path->indexes);
+ status = LTTNG_ACTION_PATH_STATUS_OK;
+end:
+ return status;
+}
+
+enum lttng_action_path_status lttng_action_path_get_index_at_index(
+ const struct lttng_action_path *path,
+ size_t path_index,
+ uint64_t *out_index)
+{
+ enum lttng_action_path_status status;
+
+ if (!path || !out_index ||
+ path_index >= lttng_dynamic_array_get_count(
+ &path->indexes)) {
+ status = LTTNG_ACTION_PATH_STATUS_INVALID;
+ goto end;
+ }
+
+ *out_index = *((typeof(out_index)) lttng_dynamic_array_get_element(
+ &path->indexes, path_index));
+ status = LTTNG_ACTION_PATH_STATUS_OK;
+end:
+ return status;
+}
+
+void lttng_action_path_destroy(struct lttng_action_path *action_path)
+{
+ if (!action_path) {
+ goto end;
+ }
+
+ lttng_dynamic_array_reset(&action_path->indexes);
+ free(action_path);
+end:
+ return;
+}
+
+LTTNG_HIDDEN
+int lttng_action_path_copy(const struct lttng_action_path *src,
+ struct lttng_action_path *dst)
+{
+ int ret;
+ size_t i, src_count;
+
+ assert(src);
+ assert(dst);
+
+ lttng_dynamic_array_init(&dst->indexes, sizeof(uint64_t), NULL);
+ src_count = lttng_dynamic_array_get_count(&src->indexes);
+
+ ret = lttng_dynamic_array_set_count(&dst->indexes, src_count);
+ if (ret) {
+ goto error;
+ }
+
+ for (i = 0; i < src_count; i++) {
+ const void *index = lttng_dynamic_array_get_element(
+ &src->indexes, i);
+
+ ret = lttng_dynamic_array_add_element(&dst->indexes, index);
+ if (ret) {
+ goto error;
+ }
+ }
+
+ ret = 0;
+ goto end;
+error:
+ lttng_dynamic_array_reset(&dst->indexes);
+end:
+ return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_action_path_create_from_payload(
+ struct lttng_payload_view *view,
+ struct lttng_action_path **_action_path)
+{
+ ssize_t consumed_size = 0, ret = -1;
+ const struct lttng_action_path_comm *header;
+ struct lttng_action_path *action_path = NULL;
+ const struct lttng_payload_view header_view =
+ lttng_payload_view_from_view(view, 0, sizeof(*header));
+
+ if (!lttng_payload_view_is_valid(&header_view)) {
+ goto end;
+ }
+
+ header = (typeof(header)) header_view.buffer.data;
+ consumed_size += header_view.buffer.size;
+ {
+ const struct lttng_payload_view indexes_view =
+ lttng_payload_view_from_view(view,
+ consumed_size,
+ header->index_count *
+ sizeof(uint64_t));
+
+ if (!lttng_payload_view_is_valid(&indexes_view)) {
+ goto end;
+ }
+
+ consumed_size += indexes_view.buffer.size;
+ action_path = lttng_action_path_create(
+ (const uint64_t *) indexes_view.buffer.data,
+ header->index_count);
+ if (!action_path) {
+ goto end;
+ }
+ }
+
+ ret = consumed_size;
+end:
+ return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_action_path_serialize(const struct lttng_action_path *action_path,
+ struct lttng_payload *payload)
+{
+ int ret;
+ size_t index_count, i;
+ enum lttng_action_path_status status;
+
+ status = lttng_action_path_get_index_count(action_path, &index_count);
+ if (status != LTTNG_ACTION_PATH_STATUS_OK) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = lttng_dynamic_buffer_append(&payload->buffer,
+ &((struct lttng_action_path_comm) {
+ .index_count = index_count
+ }),
+ sizeof(struct lttng_action_path_comm));
+
+ for (i = 0; i < index_count; i++) {
+ uint64_t path_index;
+
+ status = lttng_action_path_get_index_at_index(
+ action_path, i, &path_index);
+ if (status != LTTNG_ACTION_PATH_STATUS_OK) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = lttng_dynamic_buffer_append(&payload->buffer, &path_index,
+ sizeof(path_index));
+ if (ret) {
+ goto end;
+ }
+ }
+
+ ret = 0;
+end:
+ return ret;
+}