|
| 1 | +From cfc94cc0d66524f453ccd781e9d252e8fc3ae711 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Brad House <brad@brad-house.com> |
| 3 | +Date: Sun, 23 Feb 2025 12:25:04 -0500 |
| 4 | +Subject: [PATCH] validation: Add LYD_VALIDATE_NOEXTDEPS to bypass |
| 5 | + leafref/when/must |
| 6 | + |
| 7 | +In libyang v1, there was an LYD_OPT_NOEXTDEPS flag. This was |
| 8 | +removed, and this patch re-adds a flag with similar functionality. |
| 9 | +--- |
| 10 | + src/parser_data.h | 3 +- |
| 11 | + src/validation.c | 85 ++++++++++++++++++++++++++--------------------- |
| 12 | + 2 files changed, 49 insertions(+), 39 deletions(-) |
| 13 | + |
| 14 | +diff --git a/src/parser_data.h b/src/parser_data.h |
| 15 | +index ddb22781e..292eda86f 100644 |
| 16 | +--- a/src/parser_data.h |
| 17 | ++++ b/src/parser_data.h |
| 18 | +@@ -222,7 +222,8 @@ struct ly_in; |
| 19 | + #define LYD_VALIDATE_NOT_FINAL 0x0020 /**< Skip final validation tasks that require for all the data nodes to |
| 20 | + either exist or not, based on the YANG constraints. Once the data |
| 21 | + satisfy this requirement, the final validation should be performed. */ |
| 22 | +- |
| 23 | ++#define LYD_VALIDATE_NOEXTDEPS 0x0040 /**< Allow external dependencies (external leafrefs, instance-identifiers, |
| 24 | ++ must, and when) to not be resolved/satisfied during validation. */ |
| 25 | + #define LYD_VALIDATE_OPTS_MASK 0x0000FFFF /**< Mask for all the LYD_VALIDATE_* options. */ |
| 26 | + |
| 27 | + /** @} datavalidationoptions */ |
| 28 | +diff --git a/src/validation.c b/src/validation.c |
| 29 | +index a436816fe..ac1822ae9 100644 |
| 30 | +--- a/src/validation.c |
| 31 | ++++ b/src/validation.c |
| 32 | +@@ -41,18 +41,22 @@ |
| 33 | + #include "xpath.h" |
| 34 | + |
| 35 | + /** |
| 36 | +- * @brief Check validation error taking into account multi-error validation. |
| 37 | ++ * @brief Check validation error taking into account multi-error validation and |
| 38 | ++ * possible skipping of external dependency validation. |
| 39 | + * |
| 40 | + * @param[in] r Local return value. |
| 41 | + * @param[in] err_cmd Command to perform on any error. |
| 42 | ++ * @param[in] err_item Optional, may be NULL. Full error to evaluate. |
| 43 | + * @param[in] val_opts Validation options. |
| 44 | + * @param[in] label Label to go to on fatal error. |
| 45 | + */ |
| 46 | +-#define LY_VAL_ERR_GOTO(r, err_cmd, val_opts, label) \ |
| 47 | ++#define LY_VAL_ERR_GOTO(r, err_cmd, err_item, val_opts, label) \ |
| 48 | + if (r) { \ |
| 49 | +- err_cmd; \ |
| 50 | +- if ((r != LY_EVALID) || !(val_opts & LYD_VALIDATE_MULTI_ERROR)) { \ |
| 51 | +- goto label; \ |
| 52 | ++ if (!(val_opts & LYD_VALIDATE_NOEXTDEPS) || (r != LY_EVALID) || ((err_item) == NULL) || ((err_item)->apptag == NULL) || (strcmp((err_item)->apptag, "instance-required") != 0)) { \ |
| 53 | ++ err_cmd; \ |
| 54 | ++ if ((r != LY_EVALID) || !(val_opts & LYD_VALIDATE_MULTI_ERROR)) { \ |
| 55 | ++ goto label; \ |
| 56 | ++ } \ |
| 57 | + } \ |
| 58 | + } |
| 59 | + |
| 60 | +@@ -412,7 +416,7 @@ lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, st |
| 61 | + /* invalid data */ |
| 62 | + LOGVAL(LYD_CTX(node), LY_VCODE_NOWHEN, disabled->cond->expr); |
| 63 | + r = LY_EVALID; |
| 64 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, error); |
| 65 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(node)), val_opts, error); |
| 66 | + } |
| 67 | + } else { |
| 68 | + /* when true */ |
| 69 | +@@ -423,7 +427,7 @@ lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, st |
| 70 | + ly_set_rm_index_ordered(node_when, i, NULL); |
| 71 | + } else if (r != LY_EINCOMPLETE) { |
| 72 | + /* error */ |
| 73 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, error); |
| 74 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(node)), val_opts, error); |
| 75 | + } |
| 76 | + |
| 77 | + LOG_LOCBACK(1, 1); |
| 78 | +@@ -454,7 +458,7 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly |
| 79 | + |
| 80 | + /* validate extension data */ |
| 81 | + r = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, *tree, data_type, val_opts, diff); |
| 82 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 83 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*tree)), val_opts, cleanup); |
| 84 | + |
| 85 | + /* remove this item from the set */ |
| 86 | + ly_set_rm_index(ext_val, i, free); |
| 87 | +@@ -471,21 +475,21 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly |
| 88 | + |
| 89 | + /* validate the node */ |
| 90 | + r = ext_n->ext->def->plugin->node(ext_n->ext, ext_n->node, val_opts); |
| 91 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 92 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*tree)), val_opts, cleanup); |
| 93 | + |
| 94 | + /* remove this item from the set */ |
| 95 | + ly_set_rm_index(ext_node, i, free); |
| 96 | + } while (i); |
| 97 | + } |
| 98 | + |
| 99 | +- if (node_when) { |
| 100 | ++ if (node_when && !(val_opts & LYD_VALIDATE_NOEXTDEPS)) { |
| 101 | + /* evaluate all when conditions */ |
| 102 | + uint32_t prev_count; |
| 103 | + |
| 104 | + do { |
| 105 | + prev_count = node_when->count; |
| 106 | + r = lyd_validate_unres_when(tree, mod, node_when, val_opts, when_xp_opts, node_types, diff); |
| 107 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 108 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*tree)), val_opts, cleanup); |
| 109 | + |
| 110 | + /* there must have been some when conditions resolved */ |
| 111 | + } while (prev_count > node_when->count); |
| 112 | +@@ -513,7 +517,7 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly |
| 113 | + LOG_LOCSET(NULL, &node->node); |
| 114 | + r = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, &node->node, *tree); |
| 115 | + LOG_LOCBACK(0, 1); |
| 116 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 117 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(node)), val_opts, cleanup); |
| 118 | + |
| 119 | + /* remove this node from the set */ |
| 120 | + ly_set_rm_index(node_types, i, NULL); |
| 121 | +@@ -532,7 +536,7 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly |
| 122 | + /* validate and store the value of the metadata */ |
| 123 | + lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type); |
| 124 | + r = lyd_value_validate_incomplete(LYD_CTX(meta->parent), type, &meta->value, meta->parent, *tree); |
| 125 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 126 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(meta->parent)), val_opts, cleanup); |
| 127 | + |
| 128 | + /* remove this attr from the set */ |
| 129 | + ly_set_rm_index(meta_types, i, NULL); |
| 130 | +@@ -926,11 +930,11 @@ lyd_validate_choice_r(struct lyd_node **first, const struct lysc_node *sparent, |
| 131 | + for (i = 0; *first && choices[i]; ++i) { |
| 132 | + /* check case duplicites */ |
| 133 | + r = lyd_validate_cases(first, mod, (struct lysc_node_choice *)choices[i], diff); |
| 134 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 135 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*first)), val_opts, cleanup); |
| 136 | + |
| 137 | + /* check for nested choice */ |
| 138 | + r = lyd_validate_choice_r(first, choices[i], mod, ext, val_opts, int_opts, getnext_ht, diff); |
| 139 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 140 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*first)), val_opts, cleanup); |
| 141 | + } |
| 142 | + |
| 143 | + cleanup: |
| 144 | +@@ -950,7 +954,7 @@ lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const |
| 145 | + |
| 146 | + /* validate choices */ |
| 147 | + r = lyd_validate_choice_r(first, sparent, mod, ext, val_opts, int_opts, getnext_ht, diff); |
| 148 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 149 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*first)), val_opts, cleanup); |
| 150 | + |
| 151 | + node = *first; |
| 152 | + while (node) { |
| 153 | +@@ -982,7 +986,7 @@ lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const |
| 154 | + if (node->flags & LYD_NEW) { |
| 155 | + /* then check new node instance duplicities */ |
| 156 | + r = lyd_validate_duplicates(*first, node, val_opts); |
| 157 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 158 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*first)), val_opts, cleanup); |
| 159 | + |
| 160 | + /* this node is valid */ |
| 161 | + node->flags &= ~LYD_NEW; |
| 162 | +@@ -1100,7 +1104,7 @@ lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *pare |
| 163 | + } |
| 164 | + |
| 165 | + disabled = NULL; |
| 166 | +- if (lysc_has_when(snode)) { |
| 167 | ++ if (lysc_has_when(snode) && !(val_opts & LYD_VALIDATE_NOEXTDEPS)) { |
| 168 | + /* if there are any when conditions, they must be true for a validation error */ |
| 169 | + LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, &disabled)); |
| 170 | + } |
| 171 | +@@ -1177,7 +1181,7 @@ lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, |
| 172 | + assert(count < min); |
| 173 | + |
| 174 | + disabled = NULL; |
| 175 | +- if (lysc_has_when(snode)) { |
| 176 | ++ if (lysc_has_when(snode) && !(val_opts & LYD_VALIDATE_NOEXTDEPS)) { |
| 177 | + /* if there are any when conditions, they must be true for a validation error */ |
| 178 | + LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, &disabled)); |
| 179 | + } |
| 180 | +@@ -1553,7 +1557,7 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no |
| 181 | + if (snode->flags & LYS_MAND_TRUE) { |
| 182 | + /* check generic mandatory existence */ |
| 183 | + r = lyd_validate_mandatory(first, parent, snode, val_opts); |
| 184 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 185 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 186 | + } |
| 187 | + |
| 188 | + /* find the existing case, if any */ |
| 189 | +@@ -1561,7 +1565,7 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no |
| 190 | + if (lys_getnext_data(NULL, first, NULL, scase, NULL)) { |
| 191 | + /* validate only this case */ |
| 192 | + r = lyd_validate_siblings_schema_r(first, parent, scase, mod, ext, val_opts, int_opts, getnext_ht); |
| 193 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 194 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 195 | + break; |
| 196 | + } |
| 197 | + } |
| 198 | +@@ -1580,25 +1584,25 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no |
| 199 | + slist = (struct lysc_node_list *)snode; |
| 200 | + if (slist->min || (slist->max < UINT32_MAX)) { |
| 201 | + r = lyd_validate_minmax(first, parent, snode, slist->min, slist->max, val_opts); |
| 202 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 203 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 204 | + } |
| 205 | + |
| 206 | + /* check unique */ |
| 207 | + if (slist->uniques) { |
| 208 | + r = lyd_validate_unique(first, snode, (const struct lysc_node_leaf ***)slist->uniques, val_opts); |
| 209 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 210 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 211 | + } |
| 212 | + } else if (snode->nodetype == LYS_LEAFLIST) { |
| 213 | + sllist = (struct lysc_node_leaflist *)snode; |
| 214 | + if (sllist->min || (sllist->max < UINT32_MAX)) { |
| 215 | + r = lyd_validate_minmax(first, parent, snode, sllist->min, sllist->max, val_opts); |
| 216 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 217 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 218 | + } |
| 219 | + |
| 220 | + } else if (snode->flags & LYS_MAND_TRUE) { |
| 221 | + /* check generic mandatory existence */ |
| 222 | + r = lyd_validate_mandatory(first, parent, snode, val_opts); |
| 223 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 224 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 225 | + } |
| 226 | + } |
| 227 | + |
| 228 | +@@ -1649,6 +1653,11 @@ lyd_validate_must(const struct lyd_node *node, uint32_t val_opts, uint32_t int_o |
| 229 | + const char *emsg, *eapptag; |
| 230 | + LY_ARRAY_COUNT_TYPE u; |
| 231 | + |
| 232 | ++ /* Must validation has been bypassed */ |
| 233 | ++ if (val_opts & LYD_VALIDATE_NOEXTDEPS) { |
| 234 | ++ return LY_SUCCESS; |
| 235 | ++ } |
| 236 | ++ |
| 237 | + assert((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) != (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)); |
| 238 | + assert((int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) != (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)); |
| 239 | + |
| 240 | +@@ -1710,7 +1719,7 @@ lyd_validate_must(const struct lyd_node *node, uint32_t val_opts, uint32_t int_o |
| 241 | + } |
| 242 | + LOG_LOCBACK(0, 1); |
| 243 | + r = LY_EVALID; |
| 244 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 245 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(node)), val_opts, cleanup); |
| 246 | + } |
| 247 | + } |
| 248 | + } |
| 249 | +@@ -1794,12 +1803,12 @@ lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, cons |
| 250 | + /* node value was checked by plugins */ |
| 251 | + |
| 252 | + next_iter: |
| 253 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 254 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(node)), val_opts, cleanup); |
| 255 | + } |
| 256 | + |
| 257 | + /* validate schema-based restrictions */ |
| 258 | + r = lyd_validate_siblings_schema_r(first, parent, sparent, mod, ext, val_opts, int_opts, getnext_ht); |
| 259 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 260 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(first)), val_opts, cleanup); |
| 261 | + |
| 262 | + LY_LIST_FOR(first, node) { |
| 263 | + if (!node->schema || (!node->parent && mod && (lyd_owner_module(node) != mod))) { |
| 264 | +@@ -1810,7 +1819,7 @@ lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, cons |
| 265 | + /* validate all children recursively */ |
| 266 | + r = lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, NULL, val_opts, int_opts, must_xp_opts, |
| 267 | + getnext_ht); |
| 268 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 269 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(node)), val_opts, cleanup); |
| 270 | + |
| 271 | + /* set default for containers */ |
| 272 | + lyd_np_cont_dflt_set(node); |
| 273 | +@@ -1947,7 +1956,7 @@ lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_ |
| 274 | + } else if (node->schema->nodetype & LYD_NODE_INNER) { |
| 275 | + /* new node validation, autodelete */ |
| 276 | + r = lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, NULL, val_opts, int_opts, getnext_ht, diff); |
| 277 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 278 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(root)), val_opts, cleanup); |
| 279 | + |
| 280 | + /* add nested defaults */ |
| 281 | + impl_opts = 0; |
| 282 | +@@ -2027,7 +2036,7 @@ lyd_validate(struct lyd_node **tree, const struct lys_module *module, const stru |
| 283 | + /* validate new top-level nodes of this module, autodelete */ |
| 284 | + r = lyd_validate_new(first2, *first2 ? lysc_data_parent((*first2)->schema) : NULL, mod, NULL, val_opts, 0, |
| 285 | + getnext_ht, diff); |
| 286 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 287 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(ctx), val_opts, cleanup); |
| 288 | + |
| 289 | + /* add all top-level defaults for this module, if going to validate subtree, do not add into unres sets |
| 290 | + * (lyd_validate_subtree() adds all the nodes in that case) */ |
| 291 | +@@ -2066,19 +2075,19 @@ lyd_validate(struct lyd_node **tree, const struct lys_module *module, const stru |
| 292 | + |
| 293 | + r = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p, |
| 294 | + val_opts, 0, getnext_ht, diff); |
| 295 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 296 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(ctx), val_opts, cleanup); |
| 297 | + } |
| 298 | + } |
| 299 | + |
| 300 | + /* finish incompletely validated terminal values/attributes and when conditions */ |
| 301 | + r = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p, |
| 302 | + ext_node_p, ext_val_p, val_opts, diff); |
| 303 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 304 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(ctx), val_opts, cleanup); |
| 305 | + |
| 306 | + if (!(val_opts & LYD_VALIDATE_NOT_FINAL)) { |
| 307 | + /* perform final validation that assumes the data tree is final */ |
| 308 | + r = lyd_validate_final_r(*first2, NULL, NULL, mod, NULL, val_opts, 0, 0, getnext_ht); |
| 309 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 310 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(ctx), val_opts, cleanup); |
| 311 | + } |
| 312 | + |
| 313 | + /* free the getnext hash table */ |
| 314 | +@@ -2127,19 +2136,19 @@ lyd_validate_ext(struct lyd_node **tree, const struct lysc_ext_instance *ext, ui |
| 315 | + LY_LIST_FOR(*tree, iter) { |
| 316 | + r = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p, |
| 317 | + val_opts, 0, getnext_ht, diff); |
| 318 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 319 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(iter)), val_opts, cleanup); |
| 320 | + } |
| 321 | + } |
| 322 | + |
| 323 | + /* finish incompletely validated terminal values/attributes and when conditions */ |
| 324 | + r = lyd_validate_unres(tree, NULL, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p, |
| 325 | + ext_node_p, ext_val_p, val_opts, diff); |
| 326 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 327 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*tree)), val_opts, cleanup); |
| 328 | + |
| 329 | + if (!(val_opts & LYD_VALIDATE_NOT_FINAL)) { |
| 330 | + /* perform final validation that assumes the data tree is final */ |
| 331 | + r = lyd_validate_final_r(*tree, NULL, NULL, NULL, ext, val_opts, 0, 0, getnext_ht); |
| 332 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 333 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(*tree)), val_opts, cleanup); |
| 334 | + } |
| 335 | + |
| 336 | + cleanup: |
| 337 | +@@ -2201,7 +2210,7 @@ lyd_validate_module_final(struct lyd_node *tree, const struct lys_module *module |
| 338 | + |
| 339 | + /* perform final validation that assumes the data tree is final */ |
| 340 | + r = lyd_validate_final_r(first, NULL, NULL, mod, NULL, val_opts, 0, 0, getnext_ht); |
| 341 | +- LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup); |
| 342 | ++ LY_VAL_ERR_GOTO(r, rc = r, ly_err_last(LYD_CTX(tree)), val_opts, cleanup); |
| 343 | + |
| 344 | + cleanup: |
| 345 | + lyd_val_getnext_ht_free(getnext_ht); |
0 commit comments