blob: a764fa7a943187b36dc725670e1e4306a0d41e4b [file] [log] [blame]
Radek Krejcib1c12512015-08-11 11:22:04 +02001/**
2 * @file validation.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Data tree validation functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcib1c12512015-08-11 11:22:04 +020013 */
14
Radek Krejcieab784a2015-08-27 09:56:53 +020015#include <assert.h>
Radek Krejcib1c12512015-08-11 11:22:04 +020016#include <stdlib.h>
Michal Vaskocf024702015-10-08 15:01:42 +020017#include <string.h>
Radek Krejcib1c12512015-08-11 11:22:04 +020018
Radek Krejcieab784a2015-08-27 09:56:53 +020019#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020020#include "validation.h"
Radek Krejcib1c12512015-08-11 11:22:04 +020021#include "libyang.h"
Michal Vaskocf024702015-10-08 15:01:42 +020022#include "xpath.h"
Radek Krejcicf509982015-12-15 09:22:44 +010023#include "parser.h"
Michal Vaskocf024702015-10-08 15:01:42 +020024#include "resolve.h"
25#include "tree_internal.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020026#include "xml_internal.h"
Radek Krejcib1c12512015-08-11 11:22:04 +020027
Radek Krejcieab784a2015-08-27 09:56:53 +020028static struct lys_node_leaf *
Michal Vasko1e62a092015-12-01 12:27:20 +010029lyv_keys_present(const struct lyd_node *list)
Radek Krejcib1c12512015-08-11 11:22:04 +020030{
31 struct lyd_node *aux;
32 struct lys_node_list *schema;
33 int i;
34
35 schema = (struct lys_node_list *)list->schema;
36
37 for (i = 0; i < schema->keys_size; i++) {
38 for (aux = list->child; aux; aux = aux->next) {
39 if (aux->schema == (struct lys_node *)schema->keys[i]) {
40 break;
41 }
42 }
43 if (!aux) {
44 /* key not found in the data */
Radek Krejci1073cc02015-08-12 20:37:39 +020045 return schema->keys[i];
Radek Krejcib1c12512015-08-11 11:22:04 +020046 }
47 }
48
49 return EXIT_SUCCESS;
50}
Radek Krejcieab784a2015-08-27 09:56:53 +020051
Radek Krejci3e0addb2015-08-27 16:37:59 +020052/**
53 * @brief Compare filter nodes
54 *
55 * @param[in] first The first data node to compare
56 * @param[in] second The second node to compare
57 * @return 0 if both filter nodes selects the same data.
58 */
59static int
Michal Vasko1e62a092015-12-01 12:27:20 +010060filter_compare(const struct lyd_node *first, const struct lyd_node *second)
Radek Krejci3e0addb2015-08-27 16:37:59 +020061{
62 struct lyd_node *diter1, *diter2;
63 int match, c1, c2;
64
65 assert(first);
66 assert(second);
67
68 if (first->schema != second->schema) {
69 return 1;
70 }
71
72
73 switch (first->schema->nodetype) {
74 case LYS_CONTAINER:
75 case LYS_LIST:
76 /* check if all the content match nodes are the same */
77 c1 = 0;
78 LY_TREE_FOR(first->child, diter1) {
79 if (!(diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
80 continue;
Michal Vasko4c183312015-09-25 10:41:47 +020081 } else if (!((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +020082 /* selection node */
83 continue;
84 }
85
86 match = 0;
87 LY_TREE_FOR(second->child, diter2) {
88 if (diter2->schema != diter1->schema) {
89 continue;
Radek Krejcic1ffa4d2016-02-17 13:11:11 +010090 } else if (!ly_strequal(((struct lyd_node_leaf_list *)diter1)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +010091 ((struct lyd_node_leaf_list *)diter2)->value_str, 1)) {
Radek Krejci3e0addb2015-08-27 16:37:59 +020092 continue;
93 }
94 match = 1;
95 c1++;
96 }
97 if (!match) {
98 return 1;
99 }
100 }
101 /* get number of content match nodes in the second to get know if there are some
102 * that are not present in first
103 */
104 c2 = 0;
105 LY_TREE_FOR(second->child, diter2) {
106 if (!(diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
107 continue;
Michal Vasko4c183312015-09-25 10:41:47 +0200108 } else if (!((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200109 /* selection node */
110 continue;
111 }
112 c2++;
113 }
114 if (c1 != c2) {
115 return 1;
116 }
117 break;
118 case LYS_LEAF:
119 case LYS_LEAFLIST:
Radek Krejcic1ffa4d2016-02-17 13:11:11 +0100120 if (!ly_strequal(((struct lyd_node_leaf_list *)first)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +0100121 ((struct lyd_node_leaf_list *)second)->value_str, 1)) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200122 return 1;
123 }
124 break;
125 default:
126 /* no more tests are needed */
127 break;
128 }
129 return 0;
130}
131
132static int
133filter_merge(struct lyd_node *to, struct lyd_node *from)
134{
135 struct lyd_node *diter1, *diter2;
136 unsigned int i, j;
Radek Krejcidc154432016-01-21 11:10:59 +0100137 struct ly_set *s1 = NULL, *s2 = NULL;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200138 int copy;
Radek Krejci488fd542016-01-07 12:54:08 +0100139 int ret = EXIT_FAILURE;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200140
141 if (!to || !from || to->schema != from->schema) {
142 ly_errno = LY_EINVAL;
143 return EXIT_FAILURE;
144 }
145
146 switch(to->schema->nodetype) {
147 case LYS_LIST:
148 case LYS_CONTAINER:
149 if (!from->child) {
150 /* from is selection node, so we want to make the to selection node now */
151 while (to->child) {
152 lyd_free(to->child);
153 }
154 } else if (to->child) {
155 /* both to and from are containment nodes and it was already checked
156 * (by calling filter_compare()) that they selects the same target.
157 * Therefore we can skip the content match nodes (they are the same in
158 * both of them) and merge only the selection and containment nodes */
159
160 /* first, get know if to and from contain some selection or containment
161 * nodes. Because if one of them does not contain any such a node it
162 * selects all the data so it does not make sense to limit it by any
163 * selection/containment node.
164 */
Radek Krejcidc154432016-01-21 11:10:59 +0100165 s1 = ly_set_new();
166 s2 = ly_set_new();
Radek Krejci488fd542016-01-07 12:54:08 +0100167 if (!s1 || !s2) {
168 LOGMEM;
169 goto cleanup;
170 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200171 LY_TREE_FOR(to->child, diter1) {
172 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200173 if ((diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
174 && !((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejcidc154432016-01-21 11:10:59 +0100175 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100176 goto cleanup;
177 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100178 } else if ((diter1->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter1)->value->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100179 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100180 goto cleanup;
181 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200182 } else if (diter1->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
183 /* or containment node */
Radek Krejcidc154432016-01-21 11:10:59 +0100184 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100185 goto cleanup;
186 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200187 }
188 }
189
190 LY_TREE_FOR(from->child, diter2) {
191 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200192 if ((diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
193 && !((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejcidc154432016-01-21 11:10:59 +0100194 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100195 goto cleanup;
196 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100197 } else if ((diter2->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter2)->value->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100198 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100199 goto cleanup;
200 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200201 } else if (diter2->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
202 /* or containment node */
Radek Krejcidc154432016-01-21 11:10:59 +0100203 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100204 goto cleanup;
205 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200206 }
207 }
208
209 if (!s1->number) {
210 /* to already selects all content, so nothing is needed */
211 break;
212 } else if (!s2->number) {
213 /* from selects all content, so make to select it too by
214 * removing all selection and containment nodes
215 */
216 for (i = 0; i < s1->number; i++) {
Radek Krejcidc154432016-01-21 11:10:59 +0100217 lyd_free(s1->dset[i]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200218 }
219 break;
220 } else {
221 /* both contain some selection or containment node(s), so merge them */
222 for (j = 0; j < s2->number; j++) { /* from */
223 copy = 0;
224 for (i = 0; i < s1->number; i++) { /* to */
Radek Krejcidc154432016-01-21 11:10:59 +0100225 if (s1->dset[i]->schema != s2->dset[j]->schema) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200226 continue;
227 }
228
229 /* we have something similar to diter1, explore it more */
Radek Krejcidc154432016-01-21 11:10:59 +0100230 switch (s2->dset[j]->schema->nodetype) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200231 case LYS_LIST:
232 case LYS_CONTAINER:
Radek Krejcidc154432016-01-21 11:10:59 +0100233 if (!filter_compare(s2->dset[j], s1->dset[i])) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200234 /* merge the two containers into the to */
Radek Krejcidc154432016-01-21 11:10:59 +0100235 filter_merge(s1->dset[i], s2->dset[j]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200236 } else {
237 /* check that some of them is not a selection node */
Radek Krejcidc154432016-01-21 11:10:59 +0100238 if (!s2->dset[j]->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200239 /* from is selection node, so keep only it because to selects subset */
Radek Krejcidc154432016-01-21 11:10:59 +0100240 lyd_free(s1->dset[i]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200241 /* set the flag to copy the from child at the end */
242 copy = 1;
243 continue;
Radek Krejcidc154432016-01-21 11:10:59 +0100244 } else if (!s1->dset[i]->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200245 /* to is already selection node, so ignore the from child */
246 } else {
247 /* they are different so keep trying to search for some other matching instance */
248 continue;
249 }
250 }
251
252 break;
253 case LYS_ANYXML:
254 case LYS_LEAFLIST:
255 case LYS_LEAF:
256 /* here it can be only a selection node, so do not duplicate it (keep i < s1->number) */
257 break;
258 default:
259 /* keep compiler silent */
260 break;
261 }
262
263 /* we have a match, so do not duplicate the current from child and go to check next from child */
264 /* i < s1->number */
265 break;
266 }
267
268 if (copy || i == s1->number) {
269 /* the node is not yet present in to, so move it there */
Radek Krejcidc154432016-01-21 11:10:59 +0100270 lyd_unlink(s2->dset[j]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200271 if (to->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100272 to->child->prev->next = s2->dset[j];
273 s2->dset[j]->prev = to->child->prev;
274 to->child->prev = s2->dset[j];
Radek Krejci3e0addb2015-08-27 16:37:59 +0200275 } else {
Radek Krejcidc154432016-01-21 11:10:59 +0100276 to->child = s2->dset[j];
Radek Krejci3e0addb2015-08-27 16:37:59 +0200277 }
Radek Krejcidc154432016-01-21 11:10:59 +0100278 s2->dset[j]->parent = to;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200279 }
280 }
281 }
282 } /* else from is empty, so nothing to do */
283
284 break;
285
286 default:
287 /* no other type needed to cover,
288 * keep the default branch to make compiler silent */
289 break;
290 }
Radek Krejci488fd542016-01-07 12:54:08 +0100291 ret = EXIT_SUCCESS;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200292
Radek Krejci488fd542016-01-07 12:54:08 +0100293cleanup:
Radek Krejcidc154432016-01-21 11:10:59 +0100294 ly_set_free(s1);
295 ly_set_free(s2);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200296
Radek Krejci488fd542016-01-07 12:54:08 +0100297 return ret;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200298}
299
Radek Krejcieab784a2015-08-27 09:56:53 +0200300int
Radek Krejci46c4cd72016-01-21 15:13:52 +0100301lyv_data_value(struct lyd_node *node, int options)
302{
303 int rc;
304
305 assert(node);
306
307 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
308 /* nothing to check */
309 return EXIT_SUCCESS;
310 }
311
312 switch (((struct lys_node_leaf *)node->schema)->type.base) {
313 case LY_TYPE_LEAFREF:
314 if (!((struct lyd_node_leaf_list *)node)->value.leafref) {
Radek Krejciadb57612016-02-16 13:34:34 +0100315 if (!(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci46c4cd72016-01-21 15:13:52 +0100316 /* try to resolve leafref */
317 rc = resolve_unres_data_item(node, UNRES_LEAFREF, 0, 0);
318 if (rc) {
319 return EXIT_FAILURE;
320 }
Radek Krejciadb57612016-02-16 13:34:34 +0100321 } /* in other cases the leafref is always unresolved */
Radek Krejci46c4cd72016-01-21 15:13:52 +0100322 }
323 break;
Radek Krejci4ce42be2016-02-03 13:04:41 +0100324 case LY_TYPE_INST:
325 if (!(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) &&
326 ((struct lys_node_leaf *)node->schema)->type.info.inst.req > -1) {
327 /* try to resolve instance-identifier to get know if the target exists */
328 rc = resolve_unres_data_item(node, UNRES_INSTID, 0, 0);
329 if (rc) {
330 return EXIT_FAILURE;
331 }
332 }
333 break;
Radek Krejci46c4cd72016-01-21 15:13:52 +0100334 default:
335 /* do nothing */
336 break;
337 }
338
339 return EXIT_SUCCESS;
340}
341
342int
Michal Vasko1e62a092015-12-01 12:27:20 +0100343lyv_data_context(const struct lyd_node *node, int options, unsigned int line, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200344{
Radek Krejci6baaa9a2016-02-23 16:07:12 +0100345 const struct lys_node *siter = NULL;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100346
Michal Vaskocf024702015-10-08 15:01:42 +0200347 assert(node);
Radek Krejcieab784a2015-08-27 09:56:53 +0200348
349 /* check if the node instance is enabled by if-feature */
Michal Vaskocf024702015-10-08 15:01:42 +0200350 if (lys_is_disabled(node->schema, 2)) {
Radek Krejciadb57612016-02-16 13:34:34 +0100351 LOGVAL(LYE_INELEM, line, LY_VLOG_LYD, node, node->schema->name);
Michal Vaskocf024702015-10-08 15:01:42 +0200352 return EXIT_FAILURE;
353 }
354
355 /* check all relevant when conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200356 if (unres) {
Michal Vasko1e62a092015-12-01 12:27:20 +0100357 if (unres_data_add(unres, (struct lyd_node *)node, UNRES_WHEN, line) == -1) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200358 return EXIT_FAILURE;
359 }
360 } else {
Michal Vasko1e62a092015-12-01 12:27:20 +0100361 if (resolve_unres_data_item((struct lyd_node *)node, UNRES_WHEN, 0, line)) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200362 return EXIT_FAILURE;
363 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200364 }
365
366 /* check for (non-)presence of status data in edit-config data */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100367 if ((options & (LYD_OPT_EDIT | LYD_OPT_GETCONFIG | LYD_OPT_CONFIG)) && (node->schema->flags & LYS_CONFIG_R)) {
Radek Krejciadb57612016-02-16 13:34:34 +0100368 LOGVAL(LYE_INELEM, line, LY_VLOG_LYD, node, node->schema->name);
Radek Krejcieab784a2015-08-27 09:56:53 +0200369 return EXIT_FAILURE;
370 }
371
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100372 /* check elements order in case of RPC's input and output */
Radek Krejcica7efb72016-01-18 13:06:01 +0100373 if (node->validity && lyp_is_rpc(node->schema)) {
Michal Vasko15e0bab2016-02-24 13:58:21 +0100374 if ((node->prev != node) && node->prev->next) {
Radek Krejci6baaa9a2016-02-23 16:07:12 +0100375 for (siter = lys_getnext(node->schema, node->schema->parent, node->schema->module, 0);
376 siter;
377 siter = lys_getnext(siter, siter->parent, siter->module, 0)) {
378 if (siter == node->prev->schema) {
379 /* data predecessor has the schema node after
380 * the schema node of the data node being checked */
381 LOGVAL(LYE_INORDER, line, LY_VLOG_LYD, node, node->schema->name, siter->name);
382 return EXIT_FAILURE;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100383 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100384 }
385
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100386 }
387 }
388
Radek Krejcieab784a2015-08-27 09:56:53 +0200389 return EXIT_SUCCESS;
390}
Michal Vaskocf024702015-10-08 15:01:42 +0200391
Radek Krejcieab784a2015-08-27 09:56:53 +0200392int
Michal Vaskocf024702015-10-08 15:01:42 +0200393lyv_data_content(struct lyd_node *node, int options, unsigned int line, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200394{
Michal Vasko1e62a092015-12-01 12:27:20 +0100395 const struct lys_node *schema, *siter;
396 const struct lys_node *cs, *ch;
Radek Krejcieab784a2015-08-27 09:56:53 +0200397 struct lyd_node *diter, *start;
Radek Krejcicf509982015-12-15 09:22:44 +0100398 struct lys_ident *ident;
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100399 struct lys_tpdf *tpdf;
Radek Krejcieab784a2015-08-27 09:56:53 +0200400
401 assert(node);
402 assert(node->schema);
403
404 schema = node->schema; /* shortcut */
405
Radek Krejcica7efb72016-01-18 13:06:01 +0100406 if (node->validity) {
407 /* check presence of all keys in case of list */
408 if (schema->nodetype == LYS_LIST && !(options & (LYD_OPT_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
409 siter = (struct lys_node *)lyv_keys_present(node);
410 if (siter) {
411 /* key not found in the data */
Radek Krejciadb57612016-02-16 13:34:34 +0100412 LOGVAL(LYE_MISSELEM, line, LY_VLOG_LYD, node, siter->name, schema->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100413 return EXIT_FAILURE;
Radek Krejcieab784a2015-08-27 09:56:53 +0200414 }
415 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200416
Radek Krejcica7efb72016-01-18 13:06:01 +0100417 /* mandatory children */
418 if ((schema->nodetype & (LYS_CONTAINER | LYS_LIST))
419 && !(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100420 siter = ly_check_mandatory(node, NULL);
Radek Krejcica7efb72016-01-18 13:06:01 +0100421 if (siter) {
422 if (siter->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Radek Krejciadb57612016-02-16 13:34:34 +0100423 LOGVAL(LYE_SPEC, line, LY_VLOG_LYD, node,
424 "Number of \"%s\" instances in \"%s\" does not follow min/max constraints.",
Radek Krejcica7efb72016-01-18 13:06:01 +0100425 siter->name, siter->parent->name);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200426 } else {
Radek Krejciadb57612016-02-16 13:34:34 +0100427 LOGVAL(LYE_MISSELEM, line, LY_VLOG_LYD, node, siter->name, siter->parent->name);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200428 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100429 return EXIT_FAILURE;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200430 }
431 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200432
Radek Krejcica7efb72016-01-18 13:06:01 +0100433 /* get the first sibling */
434 if (node->parent) {
435 start = node->parent->child;
Radek Krejci27aaa732015-09-04 15:24:04 +0200436 } else {
Radek Krejcica7efb72016-01-18 13:06:01 +0100437 for (start = node; start->prev->next; start = start->prev);
438 }
439
440 /* check that there are no data from different choice case */
441 if (!(options & LYD_OPT_FILTER)) {
442 /* init loop condition */
443 ch = schema;
444
445 while (ch->parent && (ch->parent->nodetype & (LYS_CASE | LYS_CHOICE))) {
446 if (ch->parent->nodetype == LYS_CHOICE) {
447 cs = NULL;
448 ch = ch->parent;
449 } else { /* ch->parent->nodetype == LYS_CASE */
450 cs = ch->parent;
451 ch = ch->parent->parent;
Radek Krejci9fdfd792015-11-09 15:41:14 +0100452 }
453
Radek Krejcica7efb72016-01-18 13:06:01 +0100454 for (diter = start; diter; diter = diter->next) {
455 if (diter == node) {
456 continue;
457 }
458
459 /* find correct level to compare */
460 for (siter = diter->schema->parent; siter; siter = siter->parent) {
461 if (siter->nodetype == LYS_CHOICE) {
462 if (siter == ch) {
Radek Krejciadb57612016-02-16 13:34:34 +0100463 LOGVAL(LYE_MCASEDATA, line, LY_VLOG_LYD, node, ch->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100464 return EXIT_FAILURE;
465 } else {
466 continue;
467 }
468 }
469
470 if (siter->nodetype == LYS_CASE) {
471 if (siter->parent != ch) {
472 continue;
473 } else if (!cs || cs != siter) {
Radek Krejciadb57612016-02-16 13:34:34 +0100474 LOGVAL(LYE_MCASEDATA, line, LY_VLOG_LYD, node, ch->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100475 return EXIT_FAILURE;
476 }
477 }
478
479 /* diter is from something else choice (subtree) */
480 break;
481 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200482 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200483 }
484 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200485
Radek Krejcica7efb72016-01-18 13:06:01 +0100486 /* keep this check the last since in case of filter it affects the data and can modify the tree */
487 /* check number of instances (similar to list uniqueness) for non-list nodes */
488 if (schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYXML)) {
489 /* find duplicity */
490 for (diter = start; diter; diter = diter->next) {
491 if (diter->schema == schema && diter != node) {
492 if (options & LYD_OPT_FILTER) {
493 /* normalize the filter if needed */
494 switch (schema->nodetype) {
495 case LYS_CONTAINER:
496 if (!filter_compare(diter, node)) {
497 /* merge the two containers, diter will be kept ... */
498 filter_merge(diter, node);
499 /* ... and node will be removed (ly_errno is not set) */
500 return EXIT_FAILURE;
501 } else {
502 /* check that some of them is not a selection node */
503 if (!diter->child) {
504 /* keep diter since it selects all such containers
505 * and let remove the node since it selects just a subset */
506 return EXIT_FAILURE;
507 } else if (!node->child) {
508 /* keep the node and remove diter since it selects subset
509 * of what is selected by node */
510 lyd_free(diter);
511 }
512 /* keep them as they are */
513 return EXIT_SUCCESS;
514 }
515 break;
516 case LYS_LEAF:
517 if (!((struct lyd_node_leaf_list *)diter)->value_str
518 && ((struct lyd_node_leaf_list *)node)->value_str) {
519 /* the first instance is selection node but the new instance is content match node ->
520 * since content match node also works as selection node. keep only the new instance
521 */
522 lyd_free(diter);
523 /* return success to keep the node in the tree */
524 return EXIT_SUCCESS;
525 } else if (!((struct lyd_node_leaf_list *)node)->value_str
Radek Krejciedaaa082016-02-17 10:21:54 +0100526 || ly_strequal(((struct lyd_node_leaf_list *)diter)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +0100527 ((struct lyd_node_leaf_list *)node)->value_str, 1)) {
Radek Krejcica7efb72016-01-18 13:06:01 +0100528 /* keep the previous instance and remove the current one ->
529 * return failure but do not set ly_errno */
530 return EXIT_FAILURE;
531 }
532 break;
533 case LYS_ANYXML:
534 /* filtering according to the anyxml content is not allowed,
535 * so anyxml is always a selection node with no content.
536 * Therefore multiple instances of anyxml does not make sense
537 */
538 /* failure is returned but no ly_errno is set */
539 return EXIT_FAILURE;
540 default:
541 /* not possible, but necessary to silence compiler warnings */
542 break;
543 }
544 /* we are done */
Radek Krejci27aaa732015-09-04 15:24:04 +0200545 break;
Radek Krejcica7efb72016-01-18 13:06:01 +0100546 } else {
Radek Krejciadb57612016-02-16 13:34:34 +0100547 LOGVAL(LYE_TOOMANY, line, LY_VLOG_LYD, node, schema->name,
548 schema->parent ? schema->parent->name : "data tree");
Radek Krejci27aaa732015-09-04 15:24:04 +0200549 return EXIT_FAILURE;
550 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200551 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200552 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100553 } else if (schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
554 /* uniqueness of list/leaflist instances */
Radek Krejcieab784a2015-08-27 09:56:53 +0200555
Radek Krejcica7efb72016-01-18 13:06:01 +0100556 /* get the first list/leaflist instance sibling */
557 if (options & (LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
558 /* skip key uniqueness check in case of get/get-config data */
559 start = NULL;
560 } else {
561 diter = start;
562 start = NULL;
563 while(diter) {
564 if (diter == node) {
565 diter = diter->next;
566 continue;
567 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100568
Radek Krejcica7efb72016-01-18 13:06:01 +0100569 if (diter->schema == node->schema) {
570 /* the same list instance */
571 start = diter;
572 break;
573 }
574 diter = diter->next;
575 }
576 }
577
578 /* check uniqueness of the list/leaflist instances (compare values) */
579 for (diter = start; diter; diter = diter->next) {
580 if (diter->schema != node->schema || diter == node ||
581 diter->validity) { /* skip comparison that will be done in future when checking diter as node */
582 continue;
583 }
584
585 if (options & LYD_OPT_FILTER) {
586 /* compare content match nodes */
587 if (!filter_compare(diter, node)) {
588 /* merge both nodes */
589 /* add selection and containment nodes from result into the diter,
590 * but only in case the diter already contains some selection nodes,
591 * otherwise it already will return all the data */
592 filter_merge(diter, node);
593
594 /* not the error, just return no data */
595 /* failure is returned but no ly_errno is set */
596 return EXIT_FAILURE;
597 } else if (node->schema->nodetype == LYS_LEAFLIST) {
598 /* in contrast to lists, leaflists can be still safely optimized if one of them
599 * is selection node. In that case wee need to keep the other node, which is content
600 * match node and it somehow limit the data to be filtered.
601 */
602 if (!((struct lyd_node_leaf_list *)diter)->value_str) {
603 /* the other instance is selection node, keep the new one whatever it is */
604 lyd_free(diter);
605 break;
606 } else if (!((struct lyd_node_leaf_list *)node)->value_str) {
607 /* the new instance is selection node, keep the previous instance which is
608 * content match node */
609 /* failure is returned but no ly_errno is set */
610 return EXIT_FAILURE;
611 }
612 }
613 } else if (!lyd_compare(diter, node, 1)) { /* comparing keys and unique combinations */
Radek Krejciadb57612016-02-16 13:34:34 +0100614 LOGVAL(LYE_DUPLIST, line, LY_VLOG_LYD, node, schema->name);
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100615 return EXIT_FAILURE;
616 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100617 }
618 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100619
620 /* status - of the node's schema node itself and all its parents that
621 * cannot have their own instance (like a choice statement) */
622 siter = node->schema;
623 do {
624 if (((siter->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) && (options & LYD_OPT_OBSOLETE)) {
Radek Krejciadb57612016-02-16 13:34:34 +0100625 LOGVAL(LYE_OBSDATA, line, LY_VLOG_LYD, node, schema->name);
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100626 return EXIT_FAILURE;
627 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100628 siter = siter->parent;
629 } while(siter && !(siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST)));
630
631 /* status of the identity value */
632 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
633 if (options & LYD_OPT_OBSOLETE) {
634 /* check that we are not instantiating obsolete type */
635 tpdf = ((struct lys_node_leaf *)node->schema)->type.der;
636 while(tpdf) {
637 if ((tpdf->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) {
Radek Krejciadb57612016-02-16 13:34:34 +0100638 LOGVAL(LYE_OBSTYPE, line, LY_VLOG_LYD, node, schema->name, tpdf->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100639 return EXIT_FAILURE;
640 }
641 tpdf = tpdf->type.der;
642 }
643 }
644 if (((struct lyd_node_leaf_list *)node)->value_type == LY_TYPE_IDENT) {
645 ident = ((struct lyd_node_leaf_list *)node)->value.ident;
Radek Krejcic6556022016-01-27 15:16:45 +0100646 if (lyp_check_status(schema->flags, schema->module, schema->name,
Radek Krejciadb57612016-02-16 13:34:34 +0100647 ident->flags, ident->module, ident->name, line, schema)) {
Radek Krejcica7efb72016-01-18 13:06:01 +0100648 return EXIT_FAILURE;
649 }
650 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100651 }
Radek Krejcicf509982015-12-15 09:22:44 +0100652 }
653
Michal Vaskobf19d252015-10-08 15:39:17 +0200654 /* check must conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200655 if (unres) {
656 if (unres_data_add(unres, node, UNRES_MUST, line) == -1) {
657 return EXIT_FAILURE;
658 }
659 } else {
660 if (resolve_unres_data_item(node, UNRES_MUST, 0, line)) {
661 return EXIT_FAILURE;
662 }
Michal Vaskobf19d252015-10-08 15:39:17 +0200663 }
664
Radek Krejcieab784a2015-08-27 09:56:53 +0200665 return EXIT_SUCCESS;
666}