validation BUGFIX autodelete leftover defaults of cases
diff --git a/src/validation.c b/src/validation.c
index 29f376a..f8ec013 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -255,6 +255,8 @@
struct lyd_node **match_p;
ly_bool fail = 0;
+ assert(node->flags & LYD_NEW);
+
if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (node->schema->flags & LYS_CONFIG_R)) {
/* duplicate instances allowed */
return LY_SUCCESS;
@@ -404,41 +406,60 @@
}
/**
+ * @brief Properly delete a node as part of autodelete validation tasks.
+ *
+ * @param[in,out] first First sibling, is updated if needed.
+ * @param[in] node Node instance to delete.
+ * @param[in,out] next_p Temporary LY_LIST_FOR_SAFE next pointer, is updated if needed.
+ * @param[in,out] diff Validation diff.
+ */
+static void
+lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *node, struct lyd_node **next_p,
+ struct lyd_node **diff)
+{
+ struct lyd_node *iter;
+
+ if (LYD_DEL_IS_ROOT(*first, node)) {
+ *first = (*first)->next;
+ }
+ if (node == *next_p) {
+ *next_p = (*next_p)->next;
+ }
+ if (diff) {
+ /* add into diff */
+ if ((node->schema->nodetype == LYS_CONTAINER) && !(node->schema->flags & LYS_PRESENCE)) {
+ /* we do not want to track NP container changes, but remember any removed children */
+ LY_LIST_FOR(lyd_child(node), iter) {
+ lyd_val_diff_add(iter, LYD_DIFF_OP_DELETE, diff);
+ }
+ } else {
+ lyd_val_diff_add(node, LYD_DIFF_OP_DELETE, diff);
+ }
+ }
+ lyd_free_tree(node);
+}
+
+/**
* @brief Autodelete old instances to prevent validation errors.
*
* @param[in,out] first First sibling to search in, is updated if needed.
- * @param[in] node Data node instance to check.
+ * @param[in] node New data node instance to check.
* @param[in,out] next_p Temporary LY_LIST_FOR_SAFE next pointer, is updated if needed.
* @param[in,out] diff Validation diff.
*/
static void
lyd_validate_autodel_dup(struct lyd_node **first, struct lyd_node *node, struct lyd_node **next_p, struct lyd_node **diff)
{
- struct lyd_node *match, *next, *iter;
+ struct lyd_node *match, *next;
+
+ assert(node->flags & LYD_NEW);
if (lyd_val_has_default(node->schema)) {
assert(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER));
LYD_LIST_FOR_INST_SAFE(*first, node->schema, next, match) {
if ((match->flags & LYD_DEFAULT) && !(match->flags & LYD_NEW)) {
/* default instance found, remove it */
- if (LYD_DEL_IS_ROOT(*first, match)) {
- *first = (*first)->next;
- }
- if (match == *next_p) {
- *next_p = (*next_p)->next;
- }
- if (diff) {
- /* add into diff */
- if ((match->schema->nodetype == LYS_CONTAINER) && !(match->schema->flags & LYS_PRESENCE)) {
- /* we do not want to track NP container changes, but remember any removed children */
- LY_LIST_FOR(lyd_child(match), iter) {
- lyd_val_diff_add(iter, LYD_DIFF_OP_DELETE, diff);
- }
- } else {
- lyd_val_diff_add(match, LYD_DIFF_OP_DELETE, diff);
- }
- }
- lyd_free_tree(match);
+ lyd_validate_autodel_node_del(first, match, next_p, diff);
/* remove only a single container/leaf default instance, if there are more, it is an error */
if (node->schema->nodetype & (LYS_LEAF | LYS_CONTAINER)) {
@@ -449,6 +470,51 @@
}
}
+/**
+ * @brief Autodelete leftover default nodes of deleted cases (that have no existing explicit data).
+ *
+ * @param[in,out] first First sibling to search in, is updated if needed.
+ * @param[in] node Default data node instance to check.
+ * @param[in,out] next_p Temporary LY_LIST_FOR_SAFE next pointer, is updated if needed.
+ * @param[in,out] diff Validation diff.
+ */
+static void
+lyd_validate_autodel_case_dflt(struct lyd_node **first, struct lyd_node *node, struct lyd_node **next_p,
+ struct lyd_node **diff)
+{
+ struct lysc_node_choice *choic;
+ struct lyd_node *iter = NULL;
+ const struct lysc_node *slast = NULL;
+
+ assert(node->flags & LYD_DEFAULT);
+
+ if (!node->schema->parent || (node->schema->parent->nodetype != LYS_CASE)) {
+ /* the default node is not a descendant of a case */
+ return;
+ }
+
+ choic = (struct lysc_node_choice *)node->schema->parent->parent;
+ assert(choic->nodetype == LYS_CHOICE);
+
+ if (choic->dflt && (choic->dflt == (struct lysc_node_case *)node->schema->parent)) {
+ /* data of a default case, keep them */
+ return;
+ }
+
+ /* try to find an explicit node of the case */
+ while ((iter = lys_getnext_data(iter, *first, &slast, node->schema->parent, NULL))) {
+ if (!(iter->flags & LYD_DEFAULT)) {
+ break;
+ }
+ }
+
+ 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 */
+ lyd_validate_autodel_node_del(first, node, next_p, diff);
+ }
+}
+
LY_ERR
lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
struct lyd_node **diff)
@@ -471,19 +537,26 @@
break;
}
- if (!(node->flags & LYD_NEW)) {
- /* check only new nodes */
+ if (!(node->flags & (LYD_NEW | LYD_DEFAULT))) {
+ /* check only new and default nodes */
continue;
}
- /* remove old default(s) if it exists */
- lyd_validate_autodel_dup(first, node, &next, diff);
+ if (node->flags & LYD_NEW) {
+ /* remove old default(s) of the new node if it exists */
+ lyd_validate_autodel_dup(first, node, &next, diff);
- /* then check new node instance duplicities */
- LY_CHECK_RET(lyd_validate_duplicates(*first, node));
+ /* then check new node instance duplicities */
+ LY_CHECK_RET(lyd_validate_duplicates(*first, node));
- /* this node is valid */
- node->flags &= ~LYD_NEW;
+ /* this node is valid */
+ node->flags &= ~LYD_NEW;
+ }
+
+ if (node->flags & LYD_DEFAULT) {
+ /* remove leftover default nodes from a no-longer existing case */
+ lyd_validate_autodel_case_dflt(first, node, &next, diff);
+ }
}
return LY_SUCCESS;