blob: 5ebc9bfb25efcc952aaa1ffa56ba9c7d294cfd05 [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
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * 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 Krejci702deb82016-03-09 12:37:57 +010028static int
Radek Krejci48464ed2016-03-17 15:44:09 +010029lyv_keys(const struct lyd_node *list)
Radek Krejcib1c12512015-08-11 11:22:04 +020030{
Radek Krejci702deb82016-03-09 12:37:57 +010031 struct lyd_node *child;
32 struct lys_node_list *schema = (struct lys_node_list *)list->schema; /* shortcut */
Radek Krejcib1c12512015-08-11 11:22:04 +020033 int i;
34
Radek Krejci702deb82016-03-09 12:37:57 +010035 for (i = 0, child = list->child; i < schema->keys_size; i++, child = child->next) {
36 if (!child || child->schema != (struct lys_node *)schema->keys[i]) {
37 /* key not found on the correct place */
Radek Krejci48464ed2016-03-17 15:44:09 +010038 LOGVAL(LYE_MISSELEM, LY_VLOG_LYD, list, schema->keys[i]->name, schema->name);
Radek Krejci702deb82016-03-09 12:37:57 +010039 for ( ; child; child = child->next) {
40 if (child->schema == (struct lys_node *)schema->keys[i]) {
Radek Krejci48464ed2016-03-17 15:44:09 +010041 LOGVAL(LYE_SPEC, LY_VLOG_LYD, child, "Invalid position of the key element.");
Radek Krejci702deb82016-03-09 12:37:57 +010042 break;
43 }
Radek Krejcib1c12512015-08-11 11:22:04 +020044 }
Radek Krejci702deb82016-03-09 12:37:57 +010045 return EXIT_FAILURE;
Radek Krejcib1c12512015-08-11 11:22:04 +020046 }
47 }
Radek Krejcib1c12512015-08-11 11:22:04 +020048 return EXIT_SUCCESS;
49}
Radek Krejcieab784a2015-08-27 09:56:53 +020050
Radek Krejci3e0addb2015-08-27 16:37:59 +020051/**
52 * @brief Compare filter nodes
53 *
54 * @param[in] first The first data node to compare
55 * @param[in] second The second node to compare
56 * @return 0 if both filter nodes selects the same data.
57 */
58static int
Michal Vasko1e62a092015-12-01 12:27:20 +010059filter_compare(const struct lyd_node *first, const struct lyd_node *second)
Radek Krejci3e0addb2015-08-27 16:37:59 +020060{
61 struct lyd_node *diter1, *diter2;
62 int match, c1, c2;
63
64 assert(first);
65 assert(second);
66
67 if (first->schema != second->schema) {
68 return 1;
69 }
70
71
72 switch (first->schema->nodetype) {
73 case LYS_CONTAINER:
74 case LYS_LIST:
75 /* check if all the content match nodes are the same */
76 c1 = 0;
77 LY_TREE_FOR(first->child, diter1) {
78 if (!(diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
79 continue;
Michal Vasko4c183312015-09-25 10:41:47 +020080 } else if (!((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +020081 /* selection node */
82 continue;
83 }
84
85 match = 0;
86 LY_TREE_FOR(second->child, diter2) {
87 if (diter2->schema != diter1->schema) {
88 continue;
Radek Krejcic1ffa4d2016-02-17 13:11:11 +010089 } else if (!ly_strequal(((struct lyd_node_leaf_list *)diter1)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +010090 ((struct lyd_node_leaf_list *)diter2)->value_str, 1)) {
Radek Krejci3e0addb2015-08-27 16:37:59 +020091 continue;
92 }
93 match = 1;
94 c1++;
95 }
96 if (!match) {
97 return 1;
98 }
99 }
100 /* get number of content match nodes in the second to get know if there are some
101 * that are not present in first
102 */
103 c2 = 0;
104 LY_TREE_FOR(second->child, diter2) {
105 if (!(diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
106 continue;
Michal Vasko4c183312015-09-25 10:41:47 +0200107 } else if (!((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200108 /* selection node */
109 continue;
110 }
111 c2++;
112 }
113 if (c1 != c2) {
114 return 1;
115 }
116 break;
117 case LYS_LEAF:
118 case LYS_LEAFLIST:
Radek Krejcic1ffa4d2016-02-17 13:11:11 +0100119 if (!ly_strequal(((struct lyd_node_leaf_list *)first)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +0100120 ((struct lyd_node_leaf_list *)second)->value_str, 1)) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200121 return 1;
122 }
123 break;
124 default:
125 /* no more tests are needed */
126 break;
127 }
128 return 0;
129}
130
131static int
132filter_merge(struct lyd_node *to, struct lyd_node *from)
133{
134 struct lyd_node *diter1, *diter2;
135 unsigned int i, j;
Radek Krejcidc154432016-01-21 11:10:59 +0100136 struct ly_set *s1 = NULL, *s2 = NULL;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200137 int copy;
Radek Krejci488fd542016-01-07 12:54:08 +0100138 int ret = EXIT_FAILURE;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200139
140 if (!to || !from || to->schema != from->schema) {
141 ly_errno = LY_EINVAL;
142 return EXIT_FAILURE;
143 }
144
145 switch(to->schema->nodetype) {
146 case LYS_LIST:
147 case LYS_CONTAINER:
148 if (!from->child) {
149 /* from is selection node, so we want to make the to selection node now */
150 while (to->child) {
151 lyd_free(to->child);
152 }
153 } else if (to->child) {
154 /* both to and from are containment nodes and it was already checked
155 * (by calling filter_compare()) that they selects the same target.
156 * Therefore we can skip the content match nodes (they are the same in
157 * both of them) and merge only the selection and containment nodes */
158
159 /* first, get know if to and from contain some selection or containment
160 * nodes. Because if one of them does not contain any such a node it
161 * selects all the data so it does not make sense to limit it by any
162 * selection/containment node.
163 */
Radek Krejcidc154432016-01-21 11:10:59 +0100164 s1 = ly_set_new();
165 s2 = ly_set_new();
Radek Krejci488fd542016-01-07 12:54:08 +0100166 if (!s1 || !s2) {
167 LOGMEM;
168 goto cleanup;
169 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200170 LY_TREE_FOR(to->child, diter1) {
171 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200172 if ((diter1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
173 && !((struct lyd_node_leaf_list *)diter1)->value_str) {
Radek Krejcidc154432016-01-21 11:10:59 +0100174 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100175 goto cleanup;
176 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100177 } else if ((diter1->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter1)->value->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100178 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100179 goto cleanup;
180 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200181 } else if (diter1->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
182 /* or containment node */
Radek Krejcidc154432016-01-21 11:10:59 +0100183 if (ly_set_add(s1, diter1)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100184 goto cleanup;
185 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200186 }
187 }
188
189 LY_TREE_FOR(from->child, diter2) {
190 /* is selection node */
Michal Vasko4c183312015-09-25 10:41:47 +0200191 if ((diter2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
192 && !((struct lyd_node_leaf_list *)diter2)->value_str) {
Radek Krejcidc154432016-01-21 11:10:59 +0100193 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100194 goto cleanup;
195 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100196 } else if ((diter2->schema->nodetype == LYS_ANYXML) && !((struct lyd_node_anyxml *)diter2)->value->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100197 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100198 goto cleanup;
199 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200200 } else if (diter2->schema->nodetype & (LYS_CONTAINER | LYS_LIST)) {
201 /* or containment node */
Radek Krejcidc154432016-01-21 11:10:59 +0100202 if (ly_set_add(s2, diter2)) {
Radek Krejci488fd542016-01-07 12:54:08 +0100203 goto cleanup;
204 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200205 }
206 }
207
208 if (!s1->number) {
209 /* to already selects all content, so nothing is needed */
210 break;
211 } else if (!s2->number) {
212 /* from selects all content, so make to select it too by
213 * removing all selection and containment nodes
214 */
215 for (i = 0; i < s1->number; i++) {
Radek Krejcidc154432016-01-21 11:10:59 +0100216 lyd_free(s1->dset[i]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200217 }
218 break;
219 } else {
220 /* both contain some selection or containment node(s), so merge them */
221 for (j = 0; j < s2->number; j++) { /* from */
222 copy = 0;
223 for (i = 0; i < s1->number; i++) { /* to */
Radek Krejcidc154432016-01-21 11:10:59 +0100224 if (s1->dset[i]->schema != s2->dset[j]->schema) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200225 continue;
226 }
227
228 /* we have something similar to diter1, explore it more */
Radek Krejcidc154432016-01-21 11:10:59 +0100229 switch (s2->dset[j]->schema->nodetype) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200230 case LYS_LIST:
231 case LYS_CONTAINER:
Radek Krejcidc154432016-01-21 11:10:59 +0100232 if (!filter_compare(s2->dset[j], s1->dset[i])) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200233 /* merge the two containers into the to */
Radek Krejcidc154432016-01-21 11:10:59 +0100234 filter_merge(s1->dset[i], s2->dset[j]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200235 } else {
236 /* check that some of them is not a selection node */
Radek Krejcidc154432016-01-21 11:10:59 +0100237 if (!s2->dset[j]->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200238 /* from is selection node, so keep only it because to selects subset */
Radek Krejcidc154432016-01-21 11:10:59 +0100239 lyd_free(s1->dset[i]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200240 /* set the flag to copy the from child at the end */
241 copy = 1;
242 continue;
Radek Krejcidc154432016-01-21 11:10:59 +0100243 } else if (!s1->dset[i]->child) {
Radek Krejci3e0addb2015-08-27 16:37:59 +0200244 /* to is already selection node, so ignore the from child */
245 } else {
246 /* they are different so keep trying to search for some other matching instance */
247 continue;
248 }
249 }
250
251 break;
252 case LYS_ANYXML:
253 case LYS_LEAFLIST:
254 case LYS_LEAF:
255 /* here it can be only a selection node, so do not duplicate it (keep i < s1->number) */
256 break;
257 default:
258 /* keep compiler silent */
259 break;
260 }
261
262 /* we have a match, so do not duplicate the current from child and go to check next from child */
263 /* i < s1->number */
264 break;
265 }
266
267 if (copy || i == s1->number) {
268 /* the node is not yet present in to, so move it there */
Radek Krejcidc154432016-01-21 11:10:59 +0100269 lyd_unlink(s2->dset[j]);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200270 if (to->child) {
Radek Krejcidc154432016-01-21 11:10:59 +0100271 to->child->prev->next = s2->dset[j];
272 s2->dset[j]->prev = to->child->prev;
273 to->child->prev = s2->dset[j];
Radek Krejci3e0addb2015-08-27 16:37:59 +0200274 } else {
Radek Krejcidc154432016-01-21 11:10:59 +0100275 to->child = s2->dset[j];
Radek Krejci3e0addb2015-08-27 16:37:59 +0200276 }
Radek Krejcidc154432016-01-21 11:10:59 +0100277 s2->dset[j]->parent = to;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200278 }
279 }
280 }
281 } /* else from is empty, so nothing to do */
282
283 break;
284
285 default:
286 /* no other type needed to cover,
287 * keep the default branch to make compiler silent */
288 break;
289 }
Radek Krejci488fd542016-01-07 12:54:08 +0100290 ret = EXIT_SUCCESS;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200291
Radek Krejci488fd542016-01-07 12:54:08 +0100292cleanup:
Radek Krejcidc154432016-01-21 11:10:59 +0100293 ly_set_free(s1);
294 ly_set_free(s2);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200295
Radek Krejci488fd542016-01-07 12:54:08 +0100296 return ret;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200297}
298
Radek Krejcieab784a2015-08-27 09:56:53 +0200299int
Radek Krejci46c4cd72016-01-21 15:13:52 +0100300lyv_data_value(struct lyd_node *node, int options)
301{
302 int rc;
303
304 assert(node);
305
306 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
307 /* nothing to check */
308 return EXIT_SUCCESS;
309 }
310
311 switch (((struct lys_node_leaf *)node->schema)->type.base) {
312 case LY_TYPE_LEAFREF:
313 if (!((struct lyd_node_leaf_list *)node)->value.leafref) {
Radek Krejciadb57612016-02-16 13:34:34 +0100314 if (!(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci46c4cd72016-01-21 15:13:52 +0100315 /* try to resolve leafref */
Radek Krejci48464ed2016-03-17 15:44:09 +0100316 rc = resolve_unres_data_item(node, UNRES_LEAFREF);
Radek Krejci46c4cd72016-01-21 15:13:52 +0100317 if (rc) {
318 return EXIT_FAILURE;
319 }
Radek Krejciadb57612016-02-16 13:34:34 +0100320 } /* in other cases the leafref is always unresolved */
Radek Krejci46c4cd72016-01-21 15:13:52 +0100321 }
322 break;
Radek Krejci4ce42be2016-02-03 13:04:41 +0100323 case LY_TYPE_INST:
324 if (!(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) &&
325 ((struct lys_node_leaf *)node->schema)->type.info.inst.req > -1) {
326 /* try to resolve instance-identifier to get know if the target exists */
Radek Krejci48464ed2016-03-17 15:44:09 +0100327 rc = resolve_unres_data_item(node, UNRES_INSTID);
Radek Krejci4ce42be2016-02-03 13:04:41 +0100328 if (rc) {
329 return EXIT_FAILURE;
330 }
331 }
332 break;
Radek Krejci46c4cd72016-01-21 15:13:52 +0100333 default:
334 /* do nothing */
335 break;
336 }
337
338 return EXIT_SUCCESS;
339}
340
341int
Radek Krejci48464ed2016-03-17 15:44:09 +0100342lyv_data_context(const struct lyd_node *node, int options, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200343{
Radek Krejci6baaa9a2016-02-23 16:07:12 +0100344 const struct lys_node *siter = NULL;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100345
Michal Vaskocf024702015-10-08 15:01:42 +0200346 assert(node);
Radek Krejci03b71f72016-03-16 11:10:09 +0100347 assert(unres);
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 Krejci48464ed2016-03-17 15:44:09 +0100351 LOGVAL(LYE_INELEM, 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 */
Radek Krejci03b71f72016-03-16 11:10:09 +0100356 if ((!(options & LYD_OPT_TYPEMASK) || (options & LYD_OPT_CONFIG)) && resolve_applies_when(node)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100357 if (unres_data_addonly(unres, (struct lyd_node *)node, UNRES_WHEN)) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200358 return EXIT_FAILURE;
359 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200360 }
361
362 /* check for (non-)presence of status data in edit-config data */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100363 if ((options & (LYD_OPT_EDIT | LYD_OPT_GETCONFIG | LYD_OPT_CONFIG)) && (node->schema->flags & LYS_CONFIG_R)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100364 LOGVAL(LYE_INELEM, LY_VLOG_LYD, node, node->schema->name);
Radek Krejcieab784a2015-08-27 09:56:53 +0200365 return EXIT_FAILURE;
366 }
367
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100368 /* check elements order in case of RPC's input and output */
Radek Krejcica7efb72016-01-18 13:06:01 +0100369 if (node->validity && lyp_is_rpc(node->schema)) {
Michal Vasko15e0bab2016-02-24 13:58:21 +0100370 if ((node->prev != node) && node->prev->next) {
Radek Krejci6baaa9a2016-02-23 16:07:12 +0100371 for (siter = lys_getnext(node->schema, node->schema->parent, node->schema->module, 0);
372 siter;
373 siter = lys_getnext(siter, siter->parent, siter->module, 0)) {
374 if (siter == node->prev->schema) {
375 /* data predecessor has the schema node after
376 * the schema node of the data node being checked */
Radek Krejci48464ed2016-03-17 15:44:09 +0100377 LOGVAL(LYE_INORDER, LY_VLOG_LYD, node, node->schema->name, siter->name);
Radek Krejci6baaa9a2016-02-23 16:07:12 +0100378 return EXIT_FAILURE;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100379 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100380 }
381
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100382 }
383 }
384
Radek Krejcieab784a2015-08-27 09:56:53 +0200385 return EXIT_SUCCESS;
386}
Michal Vaskocf024702015-10-08 15:01:42 +0200387
Radek Krejcieab784a2015-08-27 09:56:53 +0200388int
Radek Krejci48464ed2016-03-17 15:44:09 +0100389lyv_data_content(struct lyd_node *node, int options, struct unres_data *unres)
Radek Krejcieab784a2015-08-27 09:56:53 +0200390{
Michal Vasko1e62a092015-12-01 12:27:20 +0100391 const struct lys_node *schema, *siter;
392 const struct lys_node *cs, *ch;
Radek Krejcieab784a2015-08-27 09:56:53 +0200393 struct lyd_node *diter, *start;
Radek Krejcicf509982015-12-15 09:22:44 +0100394 struct lys_ident *ident;
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100395 struct lys_tpdf *tpdf;
Radek Krejcieab784a2015-08-27 09:56:53 +0200396
397 assert(node);
398 assert(node->schema);
399
400 schema = node->schema; /* shortcut */
401
Radek Krejcica7efb72016-01-18 13:06:01 +0100402 if (node->validity) {
Radek Krejci702deb82016-03-09 12:37:57 +0100403 /* check presence and correct order of all keys in case of list */
Radek Krejcica7efb72016-01-18 13:06:01 +0100404 if (schema->nodetype == LYS_LIST && !(options & (LYD_OPT_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100405 if (lyv_keys(node)) {
Radek Krejcica7efb72016-01-18 13:06:01 +0100406 return EXIT_FAILURE;
Radek Krejcieab784a2015-08-27 09:56:53 +0200407 }
408 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200409
Radek Krejcica7efb72016-01-18 13:06:01 +0100410 /* mandatory children */
411 if ((schema->nodetype & (LYS_CONTAINER | LYS_LIST))
412 && !(options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100413 siter = ly_check_mandatory(node, NULL);
Radek Krejcica7efb72016-01-18 13:06:01 +0100414 if (siter) {
415 if (siter->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100416 LOGVAL(LYE_INCOUNT, LY_VLOG_LYD, node, siter->name, siter->parent->name);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200417 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +0100418 LOGVAL(LYE_MISSELEM, LY_VLOG_LYD, node, siter->name, siter->parent->name);
Radek Krejci3e0addb2015-08-27 16:37:59 +0200419 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100420 return EXIT_FAILURE;
Radek Krejci3e0addb2015-08-27 16:37:59 +0200421 }
422 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200423
Radek Krejcica7efb72016-01-18 13:06:01 +0100424 /* get the first sibling */
425 if (node->parent) {
426 start = node->parent->child;
Radek Krejci27aaa732015-09-04 15:24:04 +0200427 } else {
Radek Krejcica7efb72016-01-18 13:06:01 +0100428 for (start = node; start->prev->next; start = start->prev);
429 }
430
431 /* check that there are no data from different choice case */
432 if (!(options & LYD_OPT_FILTER)) {
433 /* init loop condition */
434 ch = schema;
435
436 while (ch->parent && (ch->parent->nodetype & (LYS_CASE | LYS_CHOICE))) {
437 if (ch->parent->nodetype == LYS_CHOICE) {
438 cs = NULL;
439 ch = ch->parent;
440 } else { /* ch->parent->nodetype == LYS_CASE */
441 cs = ch->parent;
442 ch = ch->parent->parent;
Radek Krejci9fdfd792015-11-09 15:41:14 +0100443 }
444
Radek Krejcica7efb72016-01-18 13:06:01 +0100445 for (diter = start; diter; diter = diter->next) {
446 if (diter == node) {
447 continue;
448 }
449
450 /* find correct level to compare */
451 for (siter = diter->schema->parent; siter; siter = siter->parent) {
452 if (siter->nodetype == LYS_CHOICE) {
453 if (siter == ch) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100454 LOGVAL(LYE_MCASEDATA, LY_VLOG_LYD, node, ch->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100455 return EXIT_FAILURE;
456 } else {
457 continue;
458 }
459 }
460
461 if (siter->nodetype == LYS_CASE) {
462 if (siter->parent != ch) {
463 continue;
464 } else if (!cs || cs != siter) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100465 LOGVAL(LYE_MCASEDATA, LY_VLOG_LYD, node, ch->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100466 return EXIT_FAILURE;
467 }
468 }
469
470 /* diter is from something else choice (subtree) */
471 break;
472 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200473 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200474 }
475 }
Radek Krejci3e0addb2015-08-27 16:37:59 +0200476
Radek Krejcica7efb72016-01-18 13:06:01 +0100477 /* keep this check the last since in case of filter it affects the data and can modify the tree */
478 /* check number of instances (similar to list uniqueness) for non-list nodes */
479 if (schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYXML)) {
480 /* find duplicity */
481 for (diter = start; diter; diter = diter->next) {
482 if (diter->schema == schema && diter != node) {
483 if (options & LYD_OPT_FILTER) {
484 /* normalize the filter if needed */
485 switch (schema->nodetype) {
486 case LYS_CONTAINER:
487 if (!filter_compare(diter, node)) {
488 /* merge the two containers, diter will be kept ... */
489 filter_merge(diter, node);
490 /* ... and node will be removed (ly_errno is not set) */
491 return EXIT_FAILURE;
492 } else {
493 /* check that some of them is not a selection node */
494 if (!diter->child) {
495 /* keep diter since it selects all such containers
496 * and let remove the node since it selects just a subset */
497 return EXIT_FAILURE;
498 } else if (!node->child) {
499 /* keep the node and remove diter since it selects subset
500 * of what is selected by node */
501 lyd_free(diter);
502 }
503 /* keep them as they are */
504 return EXIT_SUCCESS;
505 }
506 break;
507 case LYS_LEAF:
508 if (!((struct lyd_node_leaf_list *)diter)->value_str
509 && ((struct lyd_node_leaf_list *)node)->value_str) {
510 /* the first instance is selection node but the new instance is content match node ->
511 * since content match node also works as selection node. keep only the new instance
512 */
513 lyd_free(diter);
514 /* return success to keep the node in the tree */
515 return EXIT_SUCCESS;
516 } else if (!((struct lyd_node_leaf_list *)node)->value_str
Radek Krejciedaaa082016-02-17 10:21:54 +0100517 || ly_strequal(((struct lyd_node_leaf_list *)diter)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +0100518 ((struct lyd_node_leaf_list *)node)->value_str, 1)) {
Radek Krejcica7efb72016-01-18 13:06:01 +0100519 /* keep the previous instance and remove the current one ->
520 * return failure but do not set ly_errno */
521 return EXIT_FAILURE;
522 }
523 break;
524 case LYS_ANYXML:
525 /* filtering according to the anyxml content is not allowed,
526 * so anyxml is always a selection node with no content.
527 * Therefore multiple instances of anyxml does not make sense
528 */
529 /* failure is returned but no ly_errno is set */
530 return EXIT_FAILURE;
531 default:
532 /* not possible, but necessary to silence compiler warnings */
533 break;
534 }
535 /* we are done */
Radek Krejci27aaa732015-09-04 15:24:04 +0200536 break;
Radek Krejcica7efb72016-01-18 13:06:01 +0100537 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +0100538 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, node, schema->name,
Radek Krejciadb57612016-02-16 13:34:34 +0100539 schema->parent ? schema->parent->name : "data tree");
Radek Krejci27aaa732015-09-04 15:24:04 +0200540 return EXIT_FAILURE;
541 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200542 }
Radek Krejcieab784a2015-08-27 09:56:53 +0200543 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100544 } else if (schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
545 /* uniqueness of list/leaflist instances */
Radek Krejcieab784a2015-08-27 09:56:53 +0200546
Radek Krejcica7efb72016-01-18 13:06:01 +0100547 /* get the first list/leaflist instance sibling */
548 if (options & (LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
549 /* skip key uniqueness check in case of get/get-config data */
550 start = NULL;
551 } else {
552 diter = start;
553 start = NULL;
554 while(diter) {
555 if (diter == node) {
556 diter = diter->next;
557 continue;
558 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100559
Radek Krejcica7efb72016-01-18 13:06:01 +0100560 if (diter->schema == node->schema) {
561 /* the same list instance */
562 start = diter;
563 break;
564 }
565 diter = diter->next;
566 }
567 }
568
569 /* check uniqueness of the list/leaflist instances (compare values) */
570 for (diter = start; diter; diter = diter->next) {
571 if (diter->schema != node->schema || diter == node ||
572 diter->validity) { /* skip comparison that will be done in future when checking diter as node */
573 continue;
574 }
575
576 if (options & LYD_OPT_FILTER) {
577 /* compare content match nodes */
578 if (!filter_compare(diter, node)) {
579 /* merge both nodes */
580 /* add selection and containment nodes from result into the diter,
581 * but only in case the diter already contains some selection nodes,
582 * otherwise it already will return all the data */
583 filter_merge(diter, node);
584
585 /* not the error, just return no data */
586 /* failure is returned but no ly_errno is set */
587 return EXIT_FAILURE;
588 } else if (node->schema->nodetype == LYS_LEAFLIST) {
589 /* in contrast to lists, leaflists can be still safely optimized if one of them
590 * is selection node. In that case wee need to keep the other node, which is content
591 * match node and it somehow limit the data to be filtered.
592 */
593 if (!((struct lyd_node_leaf_list *)diter)->value_str) {
594 /* the other instance is selection node, keep the new one whatever it is */
595 lyd_free(diter);
596 break;
597 } else if (!((struct lyd_node_leaf_list *)node)->value_str) {
598 /* the new instance is selection node, keep the previous instance which is
599 * content match node */
600 /* failure is returned but no ly_errno is set */
601 return EXIT_FAILURE;
602 }
603 }
604 } else if (!lyd_compare(diter, node, 1)) { /* comparing keys and unique combinations */
Radek Krejci48464ed2016-03-17 15:44:09 +0100605 LOGVAL(LYE_DUPLIST, LY_VLOG_LYD, node, schema->name);
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100606 return EXIT_FAILURE;
607 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100608 }
609 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100610
611 /* status - of the node's schema node itself and all its parents that
612 * cannot have their own instance (like a choice statement) */
613 siter = node->schema;
614 do {
615 if (((siter->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) && (options & LYD_OPT_OBSOLETE)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100616 LOGVAL(LYE_OBSDATA, LY_VLOG_LYD, node, schema->name);
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100617 return EXIT_FAILURE;
618 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100619 siter = siter->parent;
620 } while(siter && !(siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST)));
621
622 /* status of the identity value */
623 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
624 if (options & LYD_OPT_OBSOLETE) {
625 /* check that we are not instantiating obsolete type */
626 tpdf = ((struct lys_node_leaf *)node->schema)->type.der;
627 while(tpdf) {
628 if ((tpdf->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100629 LOGVAL(LYE_OBSTYPE, LY_VLOG_LYD, node, schema->name, tpdf->name);
Radek Krejcica7efb72016-01-18 13:06:01 +0100630 return EXIT_FAILURE;
631 }
632 tpdf = tpdf->type.der;
633 }
634 }
635 if (((struct lyd_node_leaf_list *)node)->value_type == LY_TYPE_IDENT) {
636 ident = ((struct lyd_node_leaf_list *)node)->value.ident;
Radek Krejcic6556022016-01-27 15:16:45 +0100637 if (lyp_check_status(schema->flags, schema->module, schema->name,
Radek Krejci48464ed2016-03-17 15:44:09 +0100638 ident->flags, ident->module, ident->name, schema)) {
Radek Krejcica7efb72016-01-18 13:06:01 +0100639 return EXIT_FAILURE;
640 }
641 }
Radek Krejci4eaf5a82015-12-15 15:10:38 +0100642 }
Radek Krejcicf509982015-12-15 09:22:44 +0100643 }
644
Michal Vaskobf19d252015-10-08 15:39:17 +0200645 /* check must conditions */
Michal Vasko0d182ba2015-10-09 09:29:14 +0200646 if (unres) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100647 if (unres_data_add(unres, node, UNRES_MUST) == -1) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200648 return EXIT_FAILURE;
649 }
650 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +0100651 if (resolve_unres_data_item(node, UNRES_MUST)) {
Michal Vasko0d182ba2015-10-09 09:29:14 +0200652 return EXIT_FAILURE;
653 }
Michal Vaskobf19d252015-10-08 15:39:17 +0200654 }
655
Radek Krejcieab784a2015-08-27 09:56:53 +0200656 return EXIT_SUCCESS;
657}