Fixed: [Error when changing choice/case with different structure](https://github.com/clicon/clixon/issues/568)

This commit is contained in:
Olof hagsand 2024-10-19 17:05:19 +02:00
parent 098262e2e7
commit 4dd3f9fd34
4 changed files with 260 additions and 11 deletions

View file

@ -109,13 +109,12 @@ struct xmldb_multi_write_arg {
* @param[in] x XML node (where to look for attribute)
* @param[in] name Attribute name
* @param[in] ns (Expected) Namespace of attribute
* @param[in] peek If 0 dont remove attribute
* @param[in] peek If 1 dont remove attribute
* @param[out] cbret Error message (if retval=0)
* @param[out] valp Malloced value (if retval=1)
* @retval 1 OK
* @retval 0 Failed (cbret set)
* @retval -1 Error
* @note as a side.effect the attribute is removed
*/
static int
attr_ns_value(cxobj *x,
@ -384,7 +383,7 @@ check_when_condition(cxobj *x0p,
goto done;
}
/*! Check if x0/y0 is part of other choice/case than y1 recursively , if so purge
/*! Check if y0 is part of other choice/case than y1 recursively
*
* @retval 1 yes, y0 is in other case than y1
* @retval 0 No, y0 it is not in other case than y1
@ -423,6 +422,56 @@ choice_is_other(yang_stmt *y0c,
return 0;
}
/*! Find/peek operation recursively other than NONE
*
* @param[in] x Base tree node
* @param[in] op NETCONF operation
* @param[out] cbret Initialized cligen buffer. Contains return XML if retval is 0.
* @retval 1 OK
* @retval 0 Fail with cbret set
* @retval -1 Error
*/
static int
find_first_op_recurse(cxobj *x,
enum operation_type *op,
cbuf *cbret)
{
int retval = -1;
char *opstr = NULL;
cxobj *xc;
int ret;
if (*op != OP_NONE)
goto ok;
if ((ret = attr_ns_value(x, "operation", NETCONF_BASE_NAMESPACE, 1, cbret, &opstr)) < 0)
goto done;
if (ret == 0)
goto fail;
if (opstr != NULL)
if (xml_operation(opstr, op) < 0)
goto done;
if (*op == OP_NONE){
xc = NULL;
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
if ((ret = find_first_op_recurse(xc, op, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
if (*op != OP_NONE)
break;
}
}
ok:
retval = 1;
done:
if (opstr)
free(opstr);
return retval;
fail:
retval = 0;
goto done;
}
/*! Check if choice nodes and if add implicitly remove all other cases, or fail if delete
*
* Special case is if yc parent (yp) is choice/case
@ -431,6 +480,8 @@ choice_is_other(yang_stmt *y0c,
* @param[in] x0 Base tree node
* @param[in] x1c Tree child
* @param[in] y1c Yang spec of x1c
* @param[in] op NETCONF operation
* @param[out] cbret Initialized cligen buffer. Contains return XML if retval is 0.
* @retval 1 OK
* @retval 0 Fail with cbret set
* @retval -1 Error
@ -441,6 +492,7 @@ choice_is_other(yang_stmt *y0c,
* all nodes from all other cases. If a request creates a node from a
* case, the server will delete any existing nodes that are defined in
* other cases inside the choice.
* XXX just looks for first op, handling could be improved if several
*/
static int
choice_other_match(cxobj *x0,
@ -457,16 +509,14 @@ choice_other_match(cxobj *x0,
yang_stmt *y0choice;
yang_stmt *y1case = NULL;
yang_stmt *y1choice = NULL;
char *opstr = NULL;
int ret;
if ((ret = attr_ns_value(x1c, "operation", NETCONF_BASE_NAMESPACE, 1, cbret, &opstr)) < 0)
if ((ret = find_first_op_recurse(x1c, &op, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
if (opstr != NULL)
if (xml_operation(opstr, &op) < 0)
goto done;
if (op == OP_REMOVE || op == OP_NONE)
goto ok;
if (yang_choice_case_get(y1c, &y1case, &y1choice) == 0)
goto ok;
x0prev = NULL;
@ -507,8 +557,6 @@ choice_other_match(cxobj *x0,
ok:
retval = 1;
done:
if (opstr)
free(opstr);
return retval;
fail:
retval = 0;