summaryrefslogtreecommitdiffstats
path: root/src/validation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/validation.c')
-rw-r--r--src/validation.c649
1 files changed, 399 insertions, 250 deletions
diff --git a/src/validation.c b/src/validation.c
index 6db020a..35136ad 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -3,7 +3,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Validation
*
- * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -40,6 +40,22 @@
#include "tree_schema_internal.h"
#include "xpath.h"
+/**
+ * @brief Check validation error taking into account multi-error validation.
+ *
+ * @param[in] r Local return value.
+ * @param[in] err_cmd Command to perform on any error.
+ * @param[in] val_opts Validation options.
+ * @param[in] label Label to go to on fatal error.
+ */
+#define LY_VAL_ERR_GOTO(r, err_cmd, val_opts, label) \
+ if (r) { \
+ err_cmd; \
+ if ((r != LY_EVALID) || !(val_opts & LYD_VALIDATE_MULTI_ERROR)) { \
+ goto label; \
+ } \
+ }
+
LY_ERR
lyd_val_diff_add(const struct lyd_node *node, enum lyd_diff_op op, struct lyd_node **diff)
{
@@ -126,7 +142,7 @@ static LY_ERR
lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node, const struct lysc_node *schema,
uint32_t xpath_options, const struct lysc_when **disabled)
{
- LY_ERR ret;
+ LY_ERR r;
const struct lyd_node *ctx_node;
struct lyxp_set xp_set;
LY_ARRAY_COUNT_TYPE u;
@@ -152,12 +168,12 @@ lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node,
/* evaluate when */
memset(&xp_set, 0, sizeof xp_set);
- ret = lyxp_eval(LYD_CTX(node), when->cond, schema->module, LY_VALUE_SCHEMA_RESOLVED, when->prefixes,
+ r = lyxp_eval(LYD_CTX(node), when->cond, schema->module, LY_VALUE_SCHEMA_RESOLVED, when->prefixes,
ctx_node, ctx_node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_options);
lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
/* return error or LY_EINCOMPLETE for dependant unresolved when */
- LY_CHECK_RET(ret);
+ LY_CHECK_RET(r);
if (!xp_set.val.bln) {
/* false when */
@@ -173,6 +189,62 @@ lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node,
}
/**
+ * @brief Properly delete a node as part of auto-delete validation tasks.
+ *
+ * @param[in,out] first First sibling, is updated if needed.
+ * @param[in] del Node instance to delete.
+ * @param[in] mod Module of the siblings, NULL for nested siblings.
+ * @param[in] np_cont_diff Whether to put NP container into diff or only its children.
+ * @param[in,out] node Optional current iteration node, update it if it is deleted.
+ * @param[in,out] node_when Optional set with nodes with "when" conditions, may be removed from.
+ * @param[in,out] diff Validation diff.
+ * @return 1 if @p node auto-deleted and updated to its next sibling.
+ * @return 0 if @p node was not auto-deleted.
+ */
+static ly_bool
+lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, const struct lys_module *mod,
+ int np_cont_diff, struct lyd_node **node, struct ly_set *node_types, struct lyd_node **diff)
+{
+ struct lyd_node *iter;
+ ly_bool node_autodel = 0;
+ uint32_t idx;
+
+ /* update pointers */
+ lyd_del_move_root(first, del, mod);
+ if (node && (del == *node)) {
+ *node = (*node)->next;
+ node_autodel = 1;
+ }
+
+ if (diff) {
+ /* add into diff */
+ if (!np_cont_diff && (del->schema->nodetype == LYS_CONTAINER) && !(del->schema->flags & LYS_PRESENCE)) {
+ /* we do not want to track NP container changes, but remember any removed children */
+ LY_LIST_FOR(lyd_child(del), iter) {
+ lyd_val_diff_add(iter, LYD_DIFF_OP_DELETE, diff);
+ }
+ } else {
+ lyd_val_diff_add(del, LYD_DIFF_OP_DELETE, diff);
+ }
+ }
+
+ if (node_types && node_types->count) {
+ /* remove from node_types set */
+ LYD_TREE_DFS_BEGIN(del, iter) {
+ if (ly_set_contains(node_types, iter, &idx)) {
+ ly_set_rm_index(node_types, idx, NULL);
+ }
+ LYD_TREE_DFS_END(del, iter);
+ }
+ }
+
+ /* free */
+ lyd_free_tree(del);
+
+ return node_autodel;
+}
+
+/**
* @brief Evaluate when conditions of collected unres nodes.
*
* @param[in,out] tree Data tree, is updated if some nodes are autodeleted.
@@ -180,6 +252,7 @@ lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node,
* If set, it is expected @p tree should point to the first node of @p mod. Otherwise it will simply be
* the first top-level sibling.
* @param[in] node_when Set with nodes with "when" conditions.
+ * @param[in] val_opts Validation options.
* @param[in] xpath_options Additional XPath options to use.
* @param[in,out] node_types Set with nodes with unresolved types, remove any with false "when" parents.
* @param[in,out] diff Validation diff.
@@ -187,13 +260,13 @@ lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node,
* @return LY_ERR value on error.
*/
static LY_ERR
-lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when,
+lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, uint32_t val_opts,
uint32_t xpath_options, struct ly_set *node_types, struct lyd_node **diff)
{
- LY_ERR rc, r;
- uint32_t i, idx;
+ LY_ERR rc = LY_SUCCESS, r;
+ uint32_t i;
const struct lysc_when *disabled;
- struct lyd_node *node = NULL, *elem;
+ struct lyd_node *node = NULL;
if (!node_when->count) {
return LY_SUCCESS;
@@ -212,32 +285,15 @@ lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, st
/* when false */
if (node->flags & LYD_WHEN_TRUE) {
/* autodelete */
- lyd_del_move_root(tree, node, mod);
- if (diff) {
- /* add into diff */
- LY_CHECK_GOTO(rc = lyd_val_diff_add(node, LYD_DIFF_OP_DELETE, diff), error);
- }
-
- /* remove from node types set, if present */
- if (node_types && node_types->count) {
- LYD_TREE_DFS_BEGIN(node, elem) {
- /* only term nodes with a validation callback can be in node_types */
- if ((elem->schema->nodetype & LYD_NODE_TERM) &&
- ((struct lysc_node_leaf *)elem->schema)->type->plugin->validate &&
- ly_set_contains(node_types, elem, &idx)) {
- LY_CHECK_GOTO(rc = ly_set_rm_index(node_types, idx, NULL), error);
- }
- LYD_TREE_DFS_END(node, elem);
- }
- }
-
- /* free */
- lyd_free_tree(node);
+ lyd_validate_autodel_node_del(tree, node, mod, 1, NULL, node_types, diff);
+ } else if (val_opts & LYD_VALIDATE_OPERATIONAL) {
+ /* only a warning */
+ LOGWRN(LYD_CTX(node), "When condition \"%s\" not satisfied.", disabled->cond->expr);
} else {
/* invalid data */
LOGVAL(LYD_CTX(node), LY_VCODE_NOWHEN, disabled->cond->expr);
- rc = LY_EVALID;
- goto error;
+ r = LY_EVALID;
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, error);
}
} else {
/* when true */
@@ -248,14 +304,13 @@ lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, st
ly_set_rm_index_ordered(node_when, i, NULL);
} else if (r != LY_EINCOMPLETE) {
/* error */
- rc = r;
- goto error;
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, error);
}
LOG_LOCBACK(1, 1, 0, 0);
} while (i);
- return LY_SUCCESS;
+ return rc;
error:
LOG_LOCBACK(1, 1, 0, 0);
@@ -267,7 +322,7 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_node,
struct ly_set *ext_val, uint32_t val_opts, struct lyd_node **diff)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR r, rc = LY_SUCCESS;
uint32_t i;
if (ext_val && ext_val->count) {
@@ -279,8 +334,8 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
struct lyd_ctx_ext_val *ext_v = ext_val->objs[i];
/* validate extension data */
- ret = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, *tree, data_type, val_opts, diff);
- LY_CHECK_RET(ret);
+ r = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, *tree, data_type, val_opts, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* remove this item from the set */
ly_set_rm_index(ext_val, i, free);
@@ -296,8 +351,8 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
struct lyd_ctx_ext_node *ext_n = ext_node->objs[i];
/* validate the node */
- ret = ext_n->ext->def->plugin->node(ext_n->ext, ext_n->node, val_opts);
- LY_CHECK_RET(ret);
+ r = ext_n->ext->def->plugin->node(ext_n->ext, ext_n->node, val_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* remove this item from the set */
ly_set_rm_index(ext_node, i, free);
@@ -310,12 +365,14 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
do {
prev_count = node_when->count;
- LY_CHECK_RET(lyd_validate_unres_when(tree, mod, node_when, when_xp_opts, node_types, diff));
+ r = lyd_validate_unres_when(tree, mod, node_when, val_opts, when_xp_opts, node_types, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
+
/* there must have been some when conditions resolved */
} while (prev_count > node_when->count);
/* there could have been no cyclic when dependencies, checked during compilation */
- assert(!node_when->count);
+ assert(!node_when->count || ((rc == LY_EVALID) && (val_opts & LYD_VALIDATE_MULTI_ERROR)));
}
if (node_types && node_types->count) {
@@ -329,9 +386,9 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
/* resolve the value of the node */
LOG_LOCSET(NULL, &node->node, NULL, NULL);
- ret = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, &node->node, *tree);
+ r = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, &node->node, *tree);
LOG_LOCBACK(0, 1, 0, 0);
- LY_CHECK_RET(ret);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* remove this node from the set */
ly_set_rm_index(node_types, i, NULL);
@@ -349,15 +406,16 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
/* validate and store the value of the metadata */
lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type);
- ret = lyd_value_validate_incomplete(LYD_CTX(meta->parent), type, &meta->value, meta->parent, *tree);
- LY_CHECK_RET(ret);
+ r = lyd_value_validate_incomplete(LYD_CTX(meta->parent), type, &meta->value, meta->parent, *tree);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* remove this attr from the set */
ly_set_rm_index(meta_types, i, NULL);
} while (i);
}
- return ret;
+cleanup:
+ return rc;
}
/**
@@ -365,12 +423,13 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
*
* @param[in] first First sibling to search in.
* @param[in] node Data node instance to check.
+ * @param[in] val_opts Validation options.
* @return LY_ERR value.
*/
static LY_ERR
-lyd_validate_duplicates(const struct lyd_node *first, const struct lyd_node *node)
+lyd_validate_duplicates(const struct lyd_node *first, const struct lyd_node *node, uint32_t val_opts)
{
- struct lyd_node **match_p;
+ struct lyd_node **match_p, *match;
ly_bool fail = 0;
assert(node->flags & LYD_NEW);
@@ -383,7 +442,12 @@ lyd_validate_duplicates(const struct lyd_node *first, const struct lyd_node *nod
/* find exactly the same next instance using hashes if possible */
if (node->parent && node->parent->children_ht) {
- if (!lyht_find_next(node->parent->children_ht, &node, node->hash, (void **)&match_p)) {
+ lyd_find_sibling_first(first, node, &match);
+ assert(match);
+
+ if (match != node) {
+ fail = 1;
+ } else if (!lyht_find_next(node->parent->children_ht, &node, node->hash, (void **)&match_p)) {
fail = 1;
}
} else {
@@ -405,8 +469,17 @@ lyd_validate_duplicates(const struct lyd_node *first, const struct lyd_node *nod
}
if (fail) {
- LOGVAL(node->schema->module->ctx, LY_VCODE_DUP, node->schema->name);
- return LY_EVALID;
+ if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (val_opts & LYD_VALIDATE_OPERATIONAL)) {
+ /* only a warning */
+ LOG_LOCSET(NULL, node, NULL, NULL);
+ LOGWRN(node->schema->module->ctx, "Duplicate instance of \"%s\".", node->schema->name);
+ LOG_LOCBACK(0, 1, 0, 0);
+ } else {
+ LOG_LOCSET(NULL, node, NULL, NULL);
+ LOGVAL(node->schema->module->ctx, LY_VCODE_DUP, node->schema->name);
+ LOG_LOCBACK(0, 1, 0, 0);
+ return LY_EVALID;
+ }
}
return LY_SUCCESS;
}
@@ -530,45 +603,6 @@ lyd_val_has_default(const struct lysc_node *schema)
}
/**
- * @brief Properly delete a node as part of auto-delete validation tasks.
- *
- * @param[in,out] first First sibling, is updated if needed.
- * @param[in] del Node instance to delete.
- * @param[in] mod Module of the siblings, NULL for nested siblings.
- * @param[in,out] node Current iteration node, update it if it is deleted.
- * @param[in,out] diff Validation diff.
- * @return 1 if @p node auto-deleted and updated to its next sibling.
- * @return 0 if @p node was not auto-deleted.
- */
-static ly_bool
-lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, const struct lys_module *mod,
- struct lyd_node **node, struct lyd_node **diff)
-{
- struct lyd_node *iter;
- ly_bool node_autodel = 0;
-
- lyd_del_move_root(first, del, mod);
- if (del == *node) {
- *node = (*node)->next;
- node_autodel = 1;
- }
- if (diff) {
- /* add into diff */
- if ((del->schema->nodetype == LYS_CONTAINER) && !(del->schema->flags & LYS_PRESENCE)) {
- /* we do not want to track NP container changes, but remember any removed children */
- LY_LIST_FOR(lyd_child(del), iter) {
- lyd_val_diff_add(iter, LYD_DIFF_OP_DELETE, diff);
- }
- } else {
- lyd_val_diff_add(del, LYD_DIFF_OP_DELETE, diff);
- }
- }
- lyd_free_tree(del);
-
- return node_autodel;
-}
-
-/**
* @brief Auto-delete leaf-list default instances to prevent validation errors.
*
* @param[in,out] first First sibling to search in, is updated if needed.
@@ -606,7 +640,7 @@ lyd_validate_autodel_leaflist_dflt(struct lyd_node **first, struct lyd_node **no
LYD_LIST_FOR_INST_SAFE(*first, schema, next, iter) {
if (iter->flags & LYD_DEFAULT) {
/* default instance found, remove it */
- if (lyd_validate_autodel_node_del(first, iter, mod, node, diff)) {
+ if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, diff)) {
node_autodel = 1;
}
}
@@ -651,7 +685,7 @@ lyd_validate_autodel_cont_leaf_dflt(struct lyd_node **first, struct lyd_node **n
LYD_LIST_FOR_INST_SAFE(*first, schema, next, iter) {
if (iter->flags & LYD_DEFAULT) {
/* default instance, remove it */
- if (lyd_validate_autodel_node_del(first, iter, mod, node, diff)) {
+ if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, diff)) {
node_autodel = 1;
}
}
@@ -661,7 +695,7 @@ lyd_validate_autodel_cont_leaf_dflt(struct lyd_node **first, struct lyd_node **n
LYD_LIST_FOR_INST(*first, schema, iter) {
if ((iter->flags & LYD_DEFAULT) && !(iter->flags & LYD_NEW)) {
/* old default instance, remove it */
- if (lyd_validate_autodel_node_del(first, iter, mod, node, diff)) {
+ if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, diff)) {
node_autodel = 1;
}
break;
@@ -719,7 +753,7 @@ lyd_validate_autodel_case_dflt(struct lyd_node **first, struct lyd_node **node,
if (!iter) {
/* there are only default nodes of the case meaning it does not exist and neither should any default nodes
* of the case, remove this one default node */
- if (lyd_validate_autodel_node_del(first, *node, mod, node, diff)) {
+ if (lyd_validate_autodel_node_del(first, *node, mod, 0, node, NULL, diff)) {
node_autodel = 1;
}
}
@@ -733,40 +767,46 @@ lyd_validate_autodel_case_dflt(struct lyd_node **first, struct lyd_node **node,
* @param[in,out] first First sibling.
* @param[in] sparent Schema parent of the siblings, NULL for top-level siblings.
* @param[in] mod Module of the siblings, NULL for nested siblings.
+ * @param[in] val_opts Validation options.
* @param[in,out] diff Validation diff.
* @return LY_ERR value.
*/
static LY_ERR
lyd_validate_choice_r(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
- struct lyd_node **diff)
+ uint32_t val_opts, struct lyd_node **diff)
{
+ LY_ERR r, rc = LY_SUCCESS;
const struct lysc_node *snode = NULL;
while (*first && (snode = lys_getnext(snode, sparent, mod ? mod->compiled : NULL, LYS_GETNEXT_WITHCHOICE))) {
/* check case duplicites */
if (snode->nodetype == LYS_CHOICE) {
- LY_CHECK_RET(lyd_validate_cases(first, mod, (struct lysc_node_choice *)snode, diff));
+ r = lyd_validate_cases(first, mod, (struct lysc_node_choice *)snode, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* check for nested choice */
- LY_CHECK_RET(lyd_validate_choice_r(first, snode, mod, diff));
+ r = lyd_validate_choice_r(first, snode, mod, val_opts, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
}
- return LY_SUCCESS;
+cleanup:
+ return rc;
}
LY_ERR
lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
- struct lyd_node **diff)
+ uint32_t val_opts, struct lyd_node **diff)
{
- LY_ERR r;
+ LY_ERR r, rc = LY_SUCCESS;
struct lyd_node *node;
const struct lysc_node *last_dflt_schema = NULL;
assert(first && (sparent || mod));
/* validate choices */
- LY_CHECK_RET(lyd_validate_choice_r(first, sparent, mod, diff));
+ r = lyd_validate_choice_r(first, sparent, mod, val_opts, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
node = *first;
while (node) {
@@ -797,10 +837,8 @@ lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const
if (node->flags & LYD_NEW) {
/* then check new node instance duplicities */
- LOG_LOCSET(NULL, node, NULL, NULL);
- r = lyd_validate_duplicates(*first, node);
- LOG_LOCBACK(0, 1, 0, 0);
- LY_CHECK_RET(r);
+ r = lyd_validate_duplicates(*first, node, val_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* this node is valid */
node->flags &= ~LYD_NEW;
@@ -817,7 +855,8 @@ lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const
node = node->next;
}
- return LY_SUCCESS;
+cleanup:
+ return rc;
}
/**
@@ -833,7 +872,7 @@ static LY_ERR
lyd_validate_dummy_when(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
const struct lysc_when **disabled)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
struct lyd_node *tree, *dummy = NULL;
uint32_t xp_opts;
@@ -850,8 +889,8 @@ lyd_validate_dummy_when(const struct lyd_node *first, const struct lyd_node *par
}
/* create dummy opaque node */
- ret = lyd_new_opaq((struct lyd_node *)parent, snode->module->ctx, snode->name, NULL, NULL, snode->module->name, &dummy);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lyd_new_opaq((struct lyd_node *)parent, snode->module->ctx, snode->name, NULL, NULL, snode->module->name, &dummy);
+ LY_CHECK_GOTO(rc, cleanup);
/* connect it if needed */
if (!parent) {
@@ -871,20 +910,20 @@ lyd_validate_dummy_when(const struct lyd_node *first, const struct lyd_node *par
}
/* evaluate all when */
- ret = lyd_validate_node_when(tree, dummy, snode, xp_opts, disabled);
- if (ret == LY_EINCOMPLETE) {
+ rc = lyd_validate_node_when(tree, dummy, snode, xp_opts, disabled);
+ if (rc == LY_EINCOMPLETE) {
/* all other when must be resolved by now */
LOGINT(snode->module->ctx);
- ret = LY_EINT;
+ rc = LY_EINT;
goto cleanup;
- } else if (ret) {
+ } else if (rc) {
/* error */
goto cleanup;
}
cleanup:
lyd_free_tree(dummy);
- return ret;
+ return rc;
}
/**
@@ -893,10 +932,12 @@ cleanup:
* @param[in] first First sibling to search in.
* @param[in] parent Data parent.
* @param[in] snode Schema node to validate.
+ * @param[in] val_opts Validation options.
* @return LY_ERR value.
*/
static LY_ERR
-lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode)
+lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
+ uint32_t val_opts)
{
const struct lysc_when *disabled;
@@ -921,13 +962,26 @@ lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *pare
}
if (!disabled) {
- /* node instance not found */
- if (snode->nodetype == LYS_CHOICE) {
- LOGVAL_APPTAG(snode->module->ctx, "missing-choice", LY_VCODE_NOMAND_CHOIC, snode->name);
+ if (val_opts & LYD_VALIDATE_OPERATIONAL) {
+ /* only a warning */
+ LOG_LOCSET(parent ? NULL : snode, parent, NULL, NULL);
+ if (snode->nodetype == LYS_CHOICE) {
+ LOGWRN(snode->module->ctx, "Mandatory choice \"%s\" data do not exist.", snode->name);
+ } else {
+ LOGWRN(snode->module->ctx, "Mandatory node \"%s\" instance does not exist.", snode->name);
+ }
+ LOG_LOCBACK(parent ? 0 : 1, parent ? 1 : 0, 0, 0);
} else {
- LOGVAL(snode->module->ctx, LY_VCODE_NOMAND, snode->name);
+ /* node instance not found */
+ LOG_LOCSET(parent ? NULL : snode, parent, NULL, NULL);
+ if (snode->nodetype == LYS_CHOICE) {
+ LOGVAL_APPTAG(snode->module->ctx, "missing-choice", LY_VCODE_NOMAND_CHOIC, snode->name);
+ } else {
+ LOGVAL(snode->module->ctx, LY_VCODE_NOMAND, snode->name);
+ }
+ LOG_LOCBACK(parent ? 0 : 1, parent ? 1 : 0, 0, 0);
+ return LY_EVALID;
}
- return LY_EVALID;
}
return LY_SUCCESS;
@@ -941,16 +995,16 @@ lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *pare
* @param[in] snode Schema node to validate.
* @param[in] min Minimum number of elements, 0 for no restriction.
* @param[in] max Max number of elements, 0 for no restriction.
+ * @param[in] val_opts Validation options.
* @return LY_ERR value.
*/
static LY_ERR
lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
- uint32_t min, uint32_t max)
+ uint32_t min, uint32_t max, uint32_t val_opts)
{
uint32_t count = 0;
struct lyd_node *iter;
const struct lysc_when *disabled;
- ly_bool invalid_instance = 0;
assert(min || max);
@@ -967,8 +1021,6 @@ lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent,
}
if (max && (count > max)) {
/* not satisifed */
- LOG_LOCSET(NULL, iter, NULL, NULL);
- invalid_instance = 1;
break;
}
}
@@ -982,20 +1034,42 @@ lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent,
LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, &disabled));
}
- if (!disabled) {
- LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name);
- goto failure;
+ if (disabled) {
+ /* satisfied */
+ min = 0;
}
- } else if (max && (count > max)) {
- LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name);
- goto failure;
+ }
+ if (max && (count <= max)) {
+ /* satisfied */
+ max = 0;
}
+ if (min) {
+ if (val_opts & LYD_VALIDATE_OPERATIONAL) {
+ /* only a warning */
+ LOG_LOCSET(snode, NULL, NULL, NULL);
+ LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name);
+ LOG_LOCBACK(1, 0, 0, 0);
+ } else {
+ LOG_LOCSET(snode, NULL, NULL, NULL);
+ LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name);
+ LOG_LOCBACK(1, 0, 0, 0);
+ return LY_EVALID;
+ }
+ } else if (max) {
+ if (val_opts & LYD_VALIDATE_OPERATIONAL) {
+ /* only a warning */
+ LOG_LOCSET(NULL, iter, NULL, NULL);
+ LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name);
+ LOG_LOCBACK(0, 1, 0, 0);
+ } else {
+ LOG_LOCSET(NULL, iter, NULL, NULL);
+ LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name);
+ LOG_LOCBACK(0, 1, 0, 0);
+ return LY_EVALID;
+ }
+ }
return LY_SUCCESS;
-
-failure:
- LOG_LOCBACK(0, invalid_instance, 0, 0);
- return LY_EVALID;
}
/**
@@ -1035,11 +1109,17 @@ lyd_val_uniq_find_leaf(const struct lysc_node_leaf *uniq_leaf, const struct lyd_
}
/**
+ * @brief Unique list validation callback argument.
+ */
+struct lyd_val_uniq_arg {
+ LY_ARRAY_COUNT_TYPE action; /**< Action to perform - 0 to compare all uniques, n to compare only n-th unique. */
+ uint32_t val_opts; /**< Validation options. */
+};
+
+/**
* @brief Callback for comparing 2 list unique leaf values.
*
* Implementation of ::lyht_value_equal_cb.
- *
- * @param[in] cb_data 0 to compare all uniques, n to compare only n-th unique.
*/
static ly_bool
lyd_val_uniq_list_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *cb_data)
@@ -1049,13 +1129,14 @@ lyd_val_uniq_list_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *c
struct lyd_node *diter, *first, *second;
struct lyd_value *val1, *val2;
char *path1, *path2, *uniq_str, *ptr;
- LY_ARRAY_COUNT_TYPE u, v, action;
+ LY_ARRAY_COUNT_TYPE u, v;
+ struct lyd_val_uniq_arg *arg = cb_data;
+ const uint32_t uniq_err_msg_size = 1024;
assert(val1_p && val2_p);
first = *((struct lyd_node **)val1_p);
second = *((struct lyd_node **)val2_p);
- action = (uintptr_t)cb_data;
assert(first && (first->schema->nodetype == LYS_LIST));
assert(second && (second->schema == first->schema));
@@ -1065,8 +1146,8 @@ lyd_val_uniq_list_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *c
slist = (struct lysc_node_list *)first->schema;
/* compare unique leaves */
- if (action > 0) {
- u = action - 1;
+ if (arg->action > 0) {
+ u = arg->action - 1;
if (u < LY_ARRAY_COUNT(slist->uniques)) {
goto uniquecheck;
}
@@ -1098,13 +1179,12 @@ uniquecheck:
}
}
if (v && (v == LY_ARRAY_COUNT(slist->uniques[u]))) {
- /* all unique leafs are the same in this set, create this nice error */
+ /* all unique leaves are the same in this set, create this nice error */
path1 = lyd_path(first, LYD_PATH_STD, NULL, 0);
path2 = lyd_path(second, LYD_PATH_STD, NULL, 0);
/* use buffer to rebuild the unique string */
-#define UNIQ_BUF_SIZE 1024
- uniq_str = malloc(UNIQ_BUF_SIZE);
+ uniq_str = malloc(uniq_err_msg_size);
uniq_str[0] = '\0';
ptr = uniq_str;
LY_ARRAY_FOR(slist->uniques[u], v) {
@@ -1113,7 +1193,7 @@ uniquecheck:
++ptr;
}
ptr = lysc_path_until((struct lysc_node *)slist->uniques[u][v], &slist->node, LYSC_PATH_LOG,
- ptr, UNIQ_BUF_SIZE - (ptr - uniq_str));
+ ptr, uniq_err_msg_size - (ptr - uniq_str));
if (!ptr) {
/* path will be incomplete, whatever */
break;
@@ -1122,18 +1202,24 @@ uniquecheck:
ptr += strlen(ptr);
}
LOG_LOCSET(NULL, second, NULL, NULL);
- LOGVAL_APPTAG(ctx, "data-not-unique", LY_VCODE_NOUNIQ, uniq_str, path1, path2);
+ if (arg->val_opts & LYD_VALIDATE_OPERATIONAL) {
+ /* only a warning */
+ LOGWRN(ctx, "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\".", uniq_str, path1, path2);
+ } else {
+ LOGVAL_APPTAG(ctx, "data-not-unique", LY_VCODE_NOUNIQ, uniq_str, path1, path2);
+ }
LOG_LOCBACK(0, 1, 0, 0);
free(path1);
free(path2);
free(uniq_str);
-#undef UNIQ_BUF_SIZE
- return 1;
+ if (!(arg->val_opts & LYD_VALIDATE_OPERATIONAL)) {
+ return 1;
+ }
}
- if (action > 0) {
+ if (arg->action > 0) {
/* done */
return 0;
}
@@ -1148,10 +1234,12 @@ uniquecheck:
* @param[in] first First sibling to search in.
* @param[in] snode Schema node to validate.
* @param[in] uniques List unique arrays to validate.
+ * @param[in] val_opts Validation options.
* @return LY_ERR value.
*/
static LY_ERR
-lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode, const struct lysc_node_leaf ***uniques)
+lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode, const struct lysc_node_leaf ***uniques,
+ uint32_t val_opts)
{
const struct lyd_node *diter;
struct ly_set *set;
@@ -1161,8 +1249,8 @@ lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode,
size_t key_len;
ly_bool dyn;
const void *hash_key;
- void *cb_data;
- struct hash_table **uniqtables = NULL;
+ struct lyd_val_uniq_arg arg, *args = NULL;
+ struct ly_ht **uniqtables = NULL;
struct lyd_value *val;
struct ly_ctx *ctx = snode->module->ctx;
@@ -1179,7 +1267,9 @@ lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode,
if (set->count == 2) {
/* simple comparison */
- if (lyd_val_uniq_list_equal(&set->objs[0], &set->objs[1], 0, (void *)0)) {
+ arg.action = 0;
+ arg.val_opts = val_opts;
+ if (lyd_val_uniq_list_equal(&set->objs[0], &set->objs[1], 0, &arg)) {
/* instance duplication */
ret = LY_EVALID;
goto cleanup;
@@ -1187,12 +1277,14 @@ lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode,
} else if (set->count > 2) {
/* use hashes for comparison */
uniqtables = malloc(LY_ARRAY_COUNT(uniques) * sizeof *uniqtables);
- LY_CHECK_ERR_GOTO(!uniqtables, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+ args = malloc(LY_ARRAY_COUNT(uniques) * sizeof *args);
+ LY_CHECK_ERR_GOTO(!uniqtables || !args, LOGMEM(ctx); ret = LY_EMEM, cleanup);
x = LY_ARRAY_COUNT(uniques);
for (v = 0; v < x; v++) {
- cb_data = (void *)(uintptr_t)(v + 1L);
+ args[v].action = v + 1;
+ args[v].val_opts = val_opts;
uniqtables[v] = lyht_new(lyht_get_fixed_size(set->count), sizeof(struct lyd_node *),
- lyd_val_uniq_list_equal, cb_data, 0);
+ lyd_val_uniq_list_equal, &args[v], 0);
LY_CHECK_ERR_GOTO(!uniqtables[v], LOGMEM(ctx); ret = LY_EMEM, cleanup);
}
@@ -1215,7 +1307,7 @@ lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode,
/* get hash key */
hash_key = val->realtype->plugin->print(NULL, val, LY_VALUE_LYB, NULL, &dyn, &key_len);
- hash = dict_hash_multi(hash, hash_key, key_len);
+ hash = lyht_hash_multi(hash, hash_key, key_len);
if (dyn) {
free((void *)hash_key);
}
@@ -1226,7 +1318,7 @@ lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode,
}
/* finish the hash value */
- hash = dict_hash_multi(hash, NULL, 0);
+ hash = lyht_hash_multi(hash, NULL, 0);
/* insert into the hashtable */
ret = lyht_insert(uniqtables[u], &set->objs[i], hash, NULL);
@@ -1246,9 +1338,10 @@ cleanup:
/* failed when allocating uniquetables[j], following j are not allocated */
break;
}
- lyht_free(uniqtables[v]);
+ lyht_free(uniqtables[v], NULL);
}
free(uniqtables);
+ free(args);
return ret;
}
@@ -1268,7 +1361,7 @@ static LY_ERR
lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_node *parent,
const struct lysc_node *sparent, const struct lysc_module *mod, uint32_t val_opts, uint32_t int_opts)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR r, rc = LY_SUCCESS;
const struct lysc_node *snode = NULL, *scase;
struct lysc_node_list *slist;
struct lysc_node_leaflist *sllist;
@@ -1282,34 +1375,32 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no
continue;
}
- LOG_LOCSET(snode, NULL, NULL, NULL);
-
/* check min-elements and max-elements */
if (snode->nodetype == LYS_LIST) {
slist = (struct lysc_node_list *)snode;
if (slist->min || slist->max) {
- ret = lyd_validate_minmax(first, parent, snode, slist->min, slist->max);
- LY_CHECK_GOTO(ret, error);
+ r = lyd_validate_minmax(first, parent, snode, slist->min, slist->max, val_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
} else if (snode->nodetype == LYS_LEAFLIST) {
sllist = (struct lysc_node_leaflist *)snode;
if (sllist->min || sllist->max) {
- ret = lyd_validate_minmax(first, parent, snode, sllist->min, sllist->max);
- LY_CHECK_GOTO(ret, error);
+ r = lyd_validate_minmax(first, parent, snode, sllist->min, sllist->max, val_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
} else if (snode->flags & LYS_MAND_TRUE) {
/* check generic mandatory existence */
- ret = lyd_validate_mandatory(first, parent, snode);
- LY_CHECK_GOTO(ret, error);
+ r = lyd_validate_mandatory(first, parent, snode, val_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
/* check unique */
if (snode->nodetype == LYS_LIST) {
slist = (struct lysc_node_list *)snode;
if (slist->uniques) {
- ret = lyd_validate_unique(first, snode, (const struct lysc_node_leaf ***)slist->uniques);
- LY_CHECK_GOTO(ret, error);
+ r = lyd_validate_unique(first, snode, (const struct lysc_node_leaf ***)slist->uniques, val_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
}
@@ -1318,21 +1409,16 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no
LY_LIST_FOR(lysc_node_child(snode), scase) {
if (lys_getnext_data(NULL, first, NULL, scase, NULL)) {
/* validate only this case */
- ret = lyd_validate_siblings_schema_r(first, parent, scase, mod, val_opts, int_opts);
- LY_CHECK_GOTO(ret, error);
+ r = lyd_validate_siblings_schema_r(first, parent, scase, mod, val_opts, int_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
break;
}
}
}
-
- LOG_LOCBACK(1, 0, 0, 0);
}
- return LY_SUCCESS;
-
-error:
- LOG_LOCBACK(1, 0, 0, 0);
- return ret;
+cleanup:
+ return rc;
}
/**
@@ -1348,7 +1434,9 @@ lyd_validate_obsolete(const struct lyd_node *node)
snode = node->schema;
do {
if (snode->flags & LYS_STATUS_OBSLT) {
+ LOG_LOCSET(NULL, node, NULL, NULL);
LOGWRN(snode->module->ctx, "Obsolete schema node \"%s\" instantiated in data.", snode->name);
+ LOG_LOCBACK(0, 1, 0, 0);
break;
}
@@ -1360,14 +1448,15 @@ lyd_validate_obsolete(const struct lyd_node *node)
* @brief Validate must conditions of a data node.
*
* @param[in] node Node to validate.
+ * @param[in] val_opts Validation options.
* @param[in] int_opts Internal parser options.
* @param[in] xpath_options Additional XPath options to use.
* @return LY_ERR value.
*/
static LY_ERR
-lyd_validate_must(const struct lyd_node *node, uint32_t int_opts, uint32_t xpath_options)
+lyd_validate_must(const struct lyd_node *node, uint32_t val_opts, uint32_t int_opts, uint32_t xpath_options)
{
- LY_ERR ret;
+ LY_ERR r, rc = LY_SUCCESS;
struct lyxp_set xp_set;
struct lysc_must *musts;
const struct lyd_node *tree;
@@ -1403,30 +1492,46 @@ lyd_validate_must(const struct lyd_node *node, uint32_t int_opts, uint32_t xpath
memset(&xp_set, 0, sizeof xp_set);
/* evaluate must */
- ret = lyxp_eval(LYD_CTX(node), musts[u].cond, node->schema->module, LY_VALUE_SCHEMA_RESOLVED,
+ r = lyxp_eval(LYD_CTX(node), musts[u].cond, node->schema->module, LY_VALUE_SCHEMA_RESOLVED,
musts[u].prefixes, node, node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_options);
- if (ret == LY_EINCOMPLETE) {
- LOGINT_RET(LYD_CTX(node));
- } else if (ret) {
- return ret;
+ if (r == LY_EINCOMPLETE) {
+ LOGERR(LYD_CTX(node), LY_EINCOMPLETE,
+ "Must \"%s\" depends on a node with a when condition, which has not been evaluated.", musts[u].cond->expr);
}
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
/* check the result */
lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
if (!xp_set.val.bln) {
- /* use specific error information */
- emsg = musts[u].emsg;
- eapptag = musts[u].eapptag ? musts[u].eapptag : "must-violation";
- if (emsg) {
- LOGVAL_APPTAG(LYD_CTX(node), eapptag, LYVE_DATA, "%s", emsg);
+ if (val_opts & LYD_VALIDATE_OPERATIONAL) {
+ /* only a warning */
+ emsg = musts[u].emsg;
+ LOG_LOCSET(NULL, node, NULL, NULL);
+ if (emsg) {
+ LOGWRN(LYD_CTX(node), "%s", emsg);
+ } else {
+ LOGWRN(LYD_CTX(node), "Must condition \"%s\" not satisfied.", musts[u].cond->expr);
+ }
+ LOG_LOCBACK(0, 1, 0, 0);
} else {
- LOGVAL_APPTAG(LYD_CTX(node), eapptag, LY_VCODE_NOMUST, musts[u].cond->expr);
+ /* use specific error information */
+ emsg = musts[u].emsg;
+ eapptag = musts[u].eapptag ? musts[u].eapptag : "must-violation";
+ LOG_LOCSET(NULL, node, NULL, NULL);
+ if (emsg) {
+ LOGVAL_APPTAG(LYD_CTX(node), eapptag, LYVE_DATA, "%s", emsg);
+ } else {
+ LOGVAL_APPTAG(LYD_CTX(node), eapptag, LY_VCODE_NOMUST, musts[u].cond->expr);
+ }
+ LOG_LOCBACK(0, 1, 0, 0);
+ r = LY_EVALID;
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
- return LY_EVALID;
}
}
- return LY_SUCCESS;
+cleanup:
+ return rc;
}
/**
@@ -1445,29 +1550,25 @@ static LY_ERR
lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *sparent,
const struct lys_module *mod, uint32_t val_opts, uint32_t int_opts, uint32_t must_xp_opts)
{
- LY_ERR r;
+ LY_ERR r, rc = LY_SUCCESS;
const char *innode;
- struct lyd_node *next = NULL, *node;
+ struct lyd_node *node;
/* validate all restrictions of nodes themselves */
- LY_LIST_FOR_SAFE(first, next, node) {
+ LY_LIST_FOR(first, node) {
if (node->flags & LYD_EXT) {
/* ext instance data should have already been validated */
continue;
}
- LOG_LOCSET(node->schema, node, NULL, NULL);
-
/* opaque data */
if (!node->schema) {
r = lyd_parse_opaq_error(node);
- LOG_LOCBACK(0, 1, 0, 0);
- return r;
+ goto next_iter;
}
if (!node->parent && mod && (lyd_owner_module(node) != mod)) {
/* all top-level data from this module checked */
- LOG_LOCBACK(1, 1, 0, 0);
break;
}
@@ -1487,43 +1588,47 @@ lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, cons
innode = "notification";
}
if (innode) {
+ LOG_LOCSET(NULL, node, NULL, NULL);
LOGVAL(LYD_CTX(node), LY_VCODE_UNEXPNODE, innode, node->schema->name);
- LOG_LOCBACK(1, 1, 0, 0);
- return LY_EVALID;
+ LOG_LOCBACK(0, 1, 0, 0);
+ r = LY_EVALID;
+ goto next_iter;
}
/* obsolete data */
lyd_validate_obsolete(node);
/* node's musts */
- if ((r = lyd_validate_must(node, int_opts, must_xp_opts))) {
- LOG_LOCBACK(1, 1, 0, 0);
- return r;
+ if ((r = lyd_validate_must(node, val_opts, int_opts, must_xp_opts))) {
+ goto next_iter;
}
/* node value was checked by plugins */
- /* next iter */
- LOG_LOCBACK(1, 1, 0, 0);
+next_iter:
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
/* validate schema-based restrictions */
- LY_CHECK_RET(lyd_validate_siblings_schema_r(first, parent, sparent, mod ? mod->compiled : NULL, val_opts, int_opts));
+ r = lyd_validate_siblings_schema_r(first, parent, sparent, mod ? mod->compiled : NULL, val_opts, int_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
LY_LIST_FOR(first, node) {
- if (!node->parent && mod && (lyd_owner_module(node) != mod)) {
- /* all top-level data from this module checked */
+ if (!node->schema || (!node->parent && mod && (lyd_owner_module(node) != mod))) {
+ /* only opaque data following or all top-level data from this module checked */
break;
}
/* validate all children recursively */
- LY_CHECK_RET(lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, val_opts, int_opts, must_xp_opts));
+ r = lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, val_opts, int_opts, must_xp_opts);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* set default for containers */
lyd_cont_set_dflt(node);
}
- return LY_SUCCESS;
+cleanup:
+ return rc;
}
/**
@@ -1609,18 +1714,20 @@ lyd_validate_node_ext(struct lyd_node *node, struct ly_set *ext_node)
* @param[in,out] meta_types Set for unres metadata types.
* @param[in,out] ext_node Set with nodes with extensions to validate.
* @param[in,out] ext_val Set for parsed extension data to validate.
- * @param[in] impl_opts Implicit options, see @ref implicitoptions.
+ * @param[in] val_opts Validation options.
* @param[in,out] diff Validation diff.
* @return LY_ERR value.
*/
static LY_ERR
lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_set *node_types,
- struct ly_set *meta_types, struct ly_set *ext_node, struct ly_set *ext_val, uint32_t impl_opts,
+ struct ly_set *meta_types, struct ly_set *ext_node, struct ly_set *ext_val, uint32_t val_opts,
struct lyd_node **diff)
{
+ LY_ERR r, rc = LY_SUCCESS;
const struct lyd_meta *meta;
const struct lysc_type *type;
struct lyd_node *node;
+ uint32_t impl_opts;
LYD_TREE_DFS_BEGIN(root, node) {
if (node->flags & LYD_EXT) {
@@ -1637,34 +1744,48 @@ lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_
lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type);
if (type->plugin->validate) {
/* metadata type resolution */
- LY_CHECK_RET(ly_set_add(meta_types, (void *)meta, 1, NULL));
+ r = ly_set_add(meta_types, (void *)meta, 1, NULL);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
}
}
if ((node->schema->nodetype & LYD_NODE_TERM) && ((struct lysc_node_leaf *)node->schema)->type->plugin->validate) {
/* node type resolution */
- LY_CHECK_RET(ly_set_add(node_types, (void *)node, 1, NULL));
+ r = ly_set_add(node_types, (void *)node, 1, NULL);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
} else if (node->schema->nodetype & LYD_NODE_INNER) {
/* new node validation, autodelete */
- LY_CHECK_RET(lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, diff));
+ r = lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, val_opts, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* add nested defaults */
- LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, NULL, impl_opts, diff));
+ impl_opts = 0;
+ if (val_opts & LYD_VALIDATE_NO_STATE) {
+ impl_opts |= LYD_IMPLICIT_NO_STATE;
+ }
+ if (val_opts & LYD_VALIDATE_NO_DEFAULTS) {
+ impl_opts |= LYD_IMPLICIT_NO_DEFAULTS;
+ }
+ r = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, NULL, impl_opts, diff);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
}
if (lysc_has_when(node->schema)) {
/* when evaluation */
- LY_CHECK_RET(ly_set_add(node_when, (void *)node, 1, NULL));
+ r = ly_set_add(node_when, (void *)node, 1, NULL);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
}
/* store for ext instance node validation, if needed */
- LY_CHECK_RET(lyd_validate_node_ext(node, ext_node));
+ r = lyd_validate_node_ext(node, ext_node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
next_node:
LYD_TREE_DFS_END(root, node);
}
- return LY_SUCCESS;
+cleanup:
+ return rc;
}
LY_ERR
@@ -1672,11 +1793,11 @@ lyd_validate(struct lyd_node **tree, const struct lys_module *module, const stru
ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p, struct ly_set *meta_types_p,
struct ly_set *ext_node_p, struct ly_set *ext_val_p, struct lyd_node **diff)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR r, rc = LY_SUCCESS;
struct lyd_node *first, *next, **first2, *iter;
const struct lys_module *mod;
struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_node = {0}, ext_val = {0};
- uint32_t i = 0;
+ uint32_t i = 0, impl_opts;
assert(tree && ctx);
assert((node_when_p && node_types_p && meta_types_p && ext_node_p && ext_val_p) ||
@@ -1708,15 +1829,21 @@ lyd_validate(struct lyd_node **tree, const struct lys_module *module, const stru
}
/* validate new top-level nodes of this module, autodelete */
- ret = lyd_validate_new(first2, NULL, mod, diff);
- LY_CHECK_GOTO(ret, cleanup);
+ r = lyd_validate_new(first2, *first2 ? lysc_data_parent((*first2)->schema) : NULL, mod, val_opts, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* add all top-level defaults for this module, if going to validate subtree, do not add into unres sets
* (lyd_validate_subtree() adds all the nodes in that case) */
- ret = lyd_new_implicit_r(NULL, first2, NULL, mod, validate_subtree ? NULL : node_when_p,
- validate_subtree ? NULL : node_types_p, validate_subtree ? NULL : ext_node_p,
- (val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, diff);
- LY_CHECK_GOTO(ret, cleanup);
+ impl_opts = 0;
+ if (val_opts & LYD_VALIDATE_NO_STATE) {
+ impl_opts |= LYD_IMPLICIT_NO_STATE;
+ }
+ if (val_opts & LYD_VALIDATE_NO_DEFAULTS) {
+ impl_opts |= LYD_IMPLICIT_NO_DEFAULTS;
+ }
+ r = lyd_new_implicit_r(lyd_parent(*first2), first2, NULL, mod, validate_subtree ? NULL : node_when_p,
+ validate_subtree ? NULL : node_types_p, validate_subtree ? NULL : ext_node_p, impl_opts, diff);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
/* our first module node pointer may no longer be the first */
first = *first2;
@@ -1734,20 +1861,22 @@ lyd_validate(struct lyd_node **tree, const struct lys_module *module, const stru
break;
}
- ret = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p,
- (val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, diff);
- LY_CHECK_GOTO(ret, cleanup);
+ r = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p,
+ val_opts, diff);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
}
}
/* finish incompletely validated terminal values/attributes and when conditions */
- ret = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p,
+ r = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p,
ext_node_p, ext_val_p, val_opts, diff);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
- /* perform final validation that assumes the data tree is final */
- ret = lyd_validate_final_r(*first2, NULL, NULL, mod, val_opts, 0, 0);
- LY_CHECK_GOTO(ret, cleanup);
+ if (!(val_opts & LYD_VALIDATE_NOT_FINAL)) {
+ /* perform final validation that assumes the data tree is final */
+ r = lyd_validate_final_r(*first2, NULL, NULL, mod, val_opts, 0, 0);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
+ }
}
cleanup:
@@ -1756,7 +1885,7 @@ cleanup:
ly_set_erase(&meta_types, NULL);
ly_set_erase(&ext_node, free);
ly_set_erase(&ext_val, free);
- return ret;
+ return rc;
}
LIBYANG_API_DEF LY_ERR
@@ -1777,14 +1906,36 @@ lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_
LIBYANG_API_DEF LY_ERR
lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff)
{
- LY_CHECK_ARG_RET(NULL, tree, *tree || module, LY_EINVAL);
- LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, tree, module, !(val_opts & LYD_VALIDATE_PRESENT), LY_EINVAL);
+ LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module->ctx, LY_EINVAL);
if (diff) {
*diff = NULL;
}
- return lyd_validate(tree, module, (*tree) ? LYD_CTX(*tree) : module->ctx, val_opts, 1, NULL, NULL, NULL, NULL, NULL,
- diff);
+ return lyd_validate(tree, module, module->ctx, val_opts, 1, NULL, NULL, NULL, NULL, NULL, diff);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_validate_module_final(struct lyd_node *tree, const struct lys_module *module, uint32_t val_opts)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ struct lyd_node *first;
+ const struct lys_module *mod;
+ uint32_t i = 0;
+
+ LY_CHECK_ARG_RET(NULL, module, !(val_opts & (LYD_VALIDATE_PRESENT | LYD_VALIDATE_NOT_FINAL)), LY_EINVAL);
+ LY_CHECK_CTX_EQUAL_RET(LYD_CTX(tree), module->ctx, LY_EINVAL);
+
+ /* module is unchanged but we need to get the first module data node */
+ mod = lyd_mod_next_module(tree, module, module->ctx, &i, &first);
+ assert(mod);
+
+ /* perform final validation that assumes the data tree is final */
+ r = lyd_validate_final_r(first, NULL, NULL, mod, val_opts, 0, 0);
+ LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
+
+cleanup:
+ return rc;
}
/**
@@ -1895,14 +2046,12 @@ _lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struc
op_sibling_after = op_subtree->next;
op_parent = lyd_parent(op_subtree);
- lyd_unlink_tree(op_subtree);
+ lyd_unlink(op_subtree);
lyd_insert_node(tree_parent, &tree_sibling, op_subtree, 0);
if (!dep_tree) {
dep_tree = tree_sibling;
}
- LOG_LOCSET(NULL, op_node, NULL, NULL);
-
if (int_opts & LYD_INTOPT_REPLY) {
/* add output children defaults */
rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_types_p,
@@ -1931,21 +2080,21 @@ _lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struc
/* perform final validation of the operation/notification */
lyd_validate_obsolete(op_node);
- LY_CHECK_GOTO(rc = lyd_validate_must(op_node, int_opts, LYXP_IGNORE_WHEN), cleanup);
+ LY_CHECK_GOTO(rc = lyd_validate_must(op_node, 0, int_opts, LYXP_IGNORE_WHEN), cleanup);
/* final validation of all the descendants */
rc = lyd_validate_final_r(lyd_child(op_node), op_node, op_node->schema, NULL, 0, int_opts, LYXP_IGNORE_WHEN);
LY_CHECK_GOTO(rc, cleanup);
cleanup:
- LOG_LOCBACK(0, 1, 0, 0);
-
/* restore operation tree */
- lyd_unlink_tree(op_subtree);
+ lyd_unlink(op_subtree);
if (op_sibling_before) {
lyd_insert_after_node(op_sibling_before, op_subtree);
+ lyd_insert_hash(op_subtree);
} else if (op_sibling_after) {
lyd_insert_before_node(op_sibling_after, op_subtree);
+ lyd_insert_hash(op_subtree);
} else if (op_parent) {
lyd_insert_node(op_parent, NULL, op_subtree, 0);
}