Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions _codeql_detected_source_root
134 changes: 111 additions & 23 deletions src/ut_kvp.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <unistd.h>
#include <assert.h>
#include <curl/curl.h>
#include <libgen.h>
#include <stdlib.h>

/* Application Includes */
#include <ut_kvp.h>
Expand Down Expand Up @@ -57,9 +59,9 @@ static bool str_to_bool(const char *string);
static ut_kvp_status_t ut_kvp_getField(ut_kvp_instance_t *pInstance, const char *pszKey, char *pszResult);
static void convert_dot_to_slash(const char *key, char *output);
static size_t write_memory_callback(void *contents, size_t size, size_t nmemb, void *userp);
static struct fy_node* process_include(const char *filename, int depth, struct fy_document *doc);
static struct fy_node* process_include(const char *filename, int depth, struct fy_document *doc, const char *parent_dir);
static void merge_nodes(struct fy_node *mainNode, struct fy_node *includeNode);
static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_document *dstDoc, int depth);
static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_document *dstDoc, int depth, const char *parent_dir);
static const void *find_pattern_from_buffer(const void *buffer, size_t bufferLength, const void *pattern, size_t patternLength);

ut_kvp_instance_t *ut_kvp_createInstance(void)
Expand Down Expand Up @@ -115,15 +117,33 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName)
return UT_KVP_STATUS_FILE_OPEN_ERROR;
}

// Resolve to absolute path
char resolved_path[PATH_MAX];
if (realpath(fileName, resolved_path) == NULL)
{
UT_LOG_ERROR("Failed to resolve path [%s]", fileName);
return UT_KVP_STATUS_FILE_OPEN_ERROR;
}

// Extract parent directory from the resolved path
char *resolved_copy = strdup(resolved_path);
if (resolved_copy == NULL)
{
UT_LOG_ERROR("Memory allocation failure");
return UT_KVP_STATUS_PARSING_ERROR;
}
char *parent_dir = dirname(resolved_copy);

// Load the new document
struct fy_document *newDoc = fy_document_build_from_file(NULL, fileName);
struct fy_document *newDoc = fy_document_build_from_file(NULL, resolved_path);
if (newDoc == NULL || fy_document_resolve(newDoc) != 0)
{
if (newDoc)
{
UT_LOG_ERROR("Error resolving document for anchors, aliases and merge keys");
fy_document_destroy(newDoc);
}
free(resolved_copy);
ut_kvp_close(pInstance);
return UT_KVP_STATUS_PARSING_ERROR;
}
Expand All @@ -134,6 +154,7 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName)
{
UT_LOG_ERROR("Unable to get root node from document");
fy_document_destroy(newDoc);
free(resolved_copy);
ut_kvp_close(pInstance);
return UT_KVP_STATUS_PARSING_ERROR;
}
Expand All @@ -147,17 +168,19 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName)
{
UT_LOG_ERROR("Unable to create doc");
fy_document_destroy(newDoc);
free(resolved_copy);
ut_kvp_close(pInstance);
return UT_KVP_STATUS_PARSING_ERROR;
}
}

// Always process includes via process_node_copy
struct fy_node *copiedRoot = process_node_copy(newRoot, pInternal->fy_handle, 0);
struct fy_node *copiedRoot = process_node_copy(newRoot, pInternal->fy_handle, 0, parent_dir);
if (copiedRoot == NULL)
{
UT_LOG_ERROR("Unable to process node");
fy_document_destroy(newDoc);
free(resolved_copy);
ut_kvp_close(pInstance);
return UT_KVP_STATUS_PARSING_ERROR;
}
Expand All @@ -177,6 +200,7 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName)
}

fy_document_destroy(newDoc);
free(resolved_copy);

return UT_KVP_STATUS_SUCCESS;
}
Expand Down Expand Up @@ -232,7 +256,7 @@ ut_kvp_status_t ut_kvp_openMemory(ut_kvp_instance_t *pInstance, char *pData, uin
}

struct fy_node *srcNode = fy_document_root(srcDoc);
node = process_node_copy(srcNode, pInternal->fy_handle, 0);
node = process_node_copy(srcNode, pInternal->fy_handle, 0, NULL);

if (node == NULL)
{
Expand Down Expand Up @@ -910,7 +934,7 @@ static size_t write_memory_callback(void *contents, size_t size, size_t nmemb, v
return realsize;
}

static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_document *dstDoc, int depth)
static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_document *dstDoc, int depth, const char *parent_dir)
{
if (srcNode == NULL || dstDoc == NULL)
{
Expand All @@ -932,10 +956,10 @@ static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_docu
const char *filepath = fy_node_get_scalar(srcNode, NULL);
if (filepath)
{
struct fy_node *included = process_include(filepath, depth, dstDoc);
struct fy_node *included = process_include(filepath, depth, dstDoc, parent_dir);
if (included)
{
return process_node_copy(included, dstDoc, depth + 1);
return process_node_copy(included, dstDoc, depth + 1, parent_dir);
}
}
return NULL;
Expand Down Expand Up @@ -971,16 +995,16 @@ static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_docu
const char *filepath = fy_node_get_scalar(incl, NULL);
if (filepath)
{
struct fy_node *included = process_include(filepath, depth, dstDoc);
struct fy_node *included = process_include(filepath, depth, dstDoc, parent_dir);
if (included)
copied_entry = process_node_copy(included, dstDoc, depth + 1);
copied_entry = process_node_copy(included, dstDoc, depth + 1, parent_dir);
}
}
}

if (copied_entry == NULL)
{
copied_entry = process_node_copy(entry, dstDoc, depth);
copied_entry = process_node_copy(entry, dstDoc, depth, parent_dir);
}

if (copied_entry)
Expand Down Expand Up @@ -1023,7 +1047,7 @@ static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_docu
const char *filepath = fy_node_get_scalar(val_node, NULL);
if (filepath)
{
struct fy_node *included = process_include(filepath, depth, dstDoc);
struct fy_node *included = process_include(filepath, depth, dstDoc, parent_dir);
if (included)
{
// If the included node is a mapping, merge it into the new_map
Expand All @@ -1035,7 +1059,7 @@ static struct fy_node* process_node_copy(struct fy_node *srcNode, struct fy_docu

// Regular case: recursive copy
struct fy_node *copied_key = fy_node_copy(dstDoc, key_node);
struct fy_node *copied_val = process_node_copy(val_node, dstDoc, depth);
struct fy_node *copied_val = process_node_copy(val_node, dstDoc, depth, parent_dir);

if (copied_key && copied_val)
{
Expand Down Expand Up @@ -1099,7 +1123,7 @@ static void merge_nodes(struct fy_node *mainNode, struct fy_node *includeNode)
}
}

static struct fy_node* process_include(const char *filename, int depth, struct fy_document *doc)
static struct fy_node* process_include(const char *filename, int depth, struct fy_document *doc, const char *parent_dir)
{
ut_kvp_download_memory_internal_t mChunk;

Expand Down Expand Up @@ -1185,7 +1209,7 @@ static struct fy_node* process_include(const char *filename, int depth, struct f
}

struct fy_node *srcNode = fy_document_root(srcDoc);
struct fy_node *root = process_node_copy(srcNode, doc, depth + 1);
struct fy_node *root = process_node_copy(srcNode, doc, depth + 1, parent_dir);

fy_document_destroy(srcDoc);
fclose(tmp);
Expand All @@ -1195,28 +1219,92 @@ static struct fy_node* process_include(const char *filename, int depth, struct f
}
else
{
// Local file include
FILE *file = fopen(filename, "r");
// Local file include - resolve relative paths
char resolved_path[PATH_MAX];
char *final_path = NULL;

// Check if the path is absolute
if (filename[0] == '/')
{
// Absolute path - use realpath to normalize it
if (realpath(filename, resolved_path) != NULL)
{
final_path = resolved_path;
}
else
{
UT_LOG_ERROR("Failed to resolve absolute path '%s'", filename);
return NULL;
}
}
else
{
// Relative path - resolve relative to parent directory
if (parent_dir != NULL)
{
// Construct full path: parent_dir/filename
char temp_path[PATH_MAX];
snprintf(temp_path, sizeof(temp_path), "%s/%s", parent_dir, filename);

// Resolve to absolute path
if (realpath(temp_path, resolved_path) != NULL)
{
final_path = resolved_path;
}
else
{
UT_LOG_ERROR("Failed to resolve relative path '%s' from parent '%s'", filename, parent_dir);
return NULL;
}
}
else
{
// No parent directory - try resolving relative to CWD as fallback
if (realpath(filename, resolved_path) != NULL)
{
final_path = resolved_path;
}
else
{
UT_LOG_ERROR("Failed to resolve path '%s'", filename);
return NULL;
}
}
}

FILE *file = fopen(final_path, "r");
if (!file)
{
UT_LOG_ERROR("Error: Cannot open include file '%s'.\n", filename);
UT_LOG_ERROR("Cannot open include file '%s'", final_path);
return NULL;
}

// struct fy_document *doc;
struct fy_document *srcDoc = fy_document_build_from_file(NULL, filename);
struct fy_document *srcDoc = fy_document_build_from_file(NULL, final_path);
if (srcDoc == NULL)
{
UT_LOG_ERROR("Error: Cannot parse include file '%s'.\n", filename);
UT_LOG_ERROR("Cannot parse include file '%s'", final_path);
fclose(file);
return NULL;
}

// Extract parent directory from the resolved include file path
char *resolved_copy = strdup(final_path);
if (resolved_copy == NULL)
{
UT_LOG_ERROR("Memory allocation failure");
fclose(file);
fy_document_destroy(srcDoc);
return NULL;
}
char *include_parent_dir = dirname(resolved_copy);

struct fy_node *root;
struct fy_node *srcNode = fy_document_root(srcDoc);
root = process_node_copy(srcNode, doc, depth + 1);
struct fy_node *root = process_node_copy(srcNode, doc, depth + 1, include_parent_dir);

fclose(file);
fy_document_destroy(srcDoc);
free(resolved_copy);

return root;
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/src/assets/include/2d.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
"2":
value: true
include: assets/include/3d.yaml
include: 3d.yaml
2 changes: 1 addition & 1 deletion tests/src/assets/include/3d.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
"3":
value: true
include: assets/include/4d.yaml
include: 4d.yaml
2 changes: 1 addition & 1 deletion tests/src/assets/include/4d.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
"4":
value: true
include: assets/include/5d.yaml
include: 5d.yaml
2 changes: 1 addition & 1 deletion tests/src/assets/include/depth_check.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
"1":
value: true
include: assets/include/2d.yaml
include: 2d.yaml
4 changes: 2 additions & 2 deletions tests/src/assets/include/sequence-include.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"1":
value: true
plugin:
- include: assets/include/2s.yaml
- include: 2s.yaml
- include: https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/3s.yaml
include_0: assets/include/4s.yaml
include_0: 4s.yaml
include_1: https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/5s.yaml
40 changes: 20 additions & 20 deletions tests/src/assets/include/single-include-file.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
---
"1":
value: true
include_0: assets/include/2s.yaml
include_1: assets/include/3s.yaml
include_2: assets/include/4s.yaml
include_3: assets/include/5s.yaml
include_4: assets/include/6s.yaml
include_5: assets/include/7s.yaml
include_6: assets/include/8s.yaml
include_7: assets/include/9s.yaml
include_8: assets/include/10s.yaml
include_9: assets/include/11s.yaml
include_10: assets/include/12s.yaml
include_11: assets/include/13s.yaml
include_12: assets/include/14s.yaml
include_13: assets/include/15s.yaml
include_14: assets/include/16s.yaml
include_15: assets/include/17s.yaml
include_16: assets/include/18s.yaml
include_17: assets/include/19s.yaml
include_18: assets/include/20s.yaml
include_19: assets/include/21s.yaml
include_0: 2s.yaml
include_1: 3s.yaml
include_2: 4s.yaml
include_3: 5s.yaml
include_4: 6s.yaml
include_5: 7s.yaml
include_6: 8s.yaml
include_7: 9s.yaml
include_8: 10s.yaml
include_9: 11s.yaml
include_10: 12s.yaml
include_11: 13s.yaml
include_12: 14s.yaml
include_13: 15s.yaml
include_14: 16s.yaml
include_15: 17s.yaml
include_16: 18s.yaml
include_17: 19s.yaml
include_18: 20s.yaml
include_19: 21s.yaml
8 changes: 4 additions & 4 deletions tests/src/assets/yaml_tags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"1":
value: true
plugin:
- !include assets/include/2s.yaml
- !include assets/include/3s.yaml
"10": !include assets/include/4s.yaml
"11": !include assets/include/5s.yaml
- !include include/2s.yaml
Copy link
Contributor

@kanjoe24 kanjoe24 Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is include directory added here? @copilot

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please check this review comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The include directory is added because with the new relative path resolution, paths are resolved relative to the parent YAML file's location. Since yaml_tags.yaml is in tests/src/assets/, and the included files are in the subdirectory tests/src/assets/include/, the correct relative path is include/2s.yaml. The old path assets/include/2s.yaml was relative to CWD, which is now deprecated.

- !include include/3s.yaml
"10": !include include/4s.yaml
"11": !include include/5s.yaml
6 changes: 3 additions & 3 deletions tests/src/assets/yaml_tags_in_sequence.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# A single scalar value included from an external source
configItem:
value: !include assets/include/2s.yaml
value: !include include/2s.yaml

# A list of values, each included from a separate external source
listConfig:
valueList:
- !include assets/include/3s.yaml
- !include assets/include/4s.yaml
- !include include/3s.yaml
- !include include/4s.yaml
Loading