1 /**
2 * @file tree_data.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Manipulation with libyang data structures
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * 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
13 */
14
15 #define _GNU_SOURCE
16
17 #include <assert.h>
18 #include <ctype.h>
19 #include <limits.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/mman.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "libyang.h"
31 #include "common.h"
32 #include "context.h"
33 #include "tree_data.h"
34 #include "parser.h"
35 #include "resolve.h"
36 #include "xml_internal.h"
37 #include "tree_internal.h"
38 #include "validation.h"
39 #include "xpath.h"
40
41 static struct lys_node *lyd_get_schema_inctx(const struct lyd_node *node, struct ly_ctx *ctx);
42
43 static struct lyd_node *lyd_dup_withsiblings_to_ctx(const struct lyd_node *node, int options, struct ly_ctx *ctx);
44
45 static struct lyd_node *lyd_new_dummy(struct lyd_node *root, struct lyd_node *parent, const struct lys_node *schema,
46 const char *value, int dflt);
47
48 static int
lyd_anydata_equal(struct lyd_node * first,struct lyd_node * second)49 lyd_anydata_equal(struct lyd_node *first, struct lyd_node *second)
50 {
51 char *str1 = NULL, *str2 = NULL;
52 struct lyd_node_anydata *anydata;
53
54 assert(first->schema->nodetype & LYS_ANYDATA);
55 assert(first->schema->nodetype == second->schema->nodetype);
56
57 anydata = (struct lyd_node_anydata *)first;
58 if (!anydata->value.str) {
59 lyxml_print_mem(&str1, anydata->value.xml, LYXML_PRINT_SIBLINGS);
60 anydata->value.str = lydict_insert_zc(anydata->schema->module->ctx, str1);
61 }
62 str1 = (char *)anydata->value.str;
63
64 anydata = (struct lyd_node_anydata *)second;
65 if (!anydata->value.str) {
66 lyxml_print_mem(&str2, anydata->value.xml, LYXML_PRINT_SIBLINGS);
67 anydata->value.str = lydict_insert_zc(anydata->schema->module->ctx, str2);
68 }
69 str2 = (char *)anydata->value.str;
70
71 if (first->schema->module->ctx != second->schema->module->ctx) {
72 return ly_strequal(str1, str2, 0);
73 } else {
74 return ly_strequal(str1, str2, 1);
75 }
76 }
77
78 /* used in tests */
79 int
lyd_list_has_keys(struct lyd_node * list)80 lyd_list_has_keys(struct lyd_node *list)
81 {
82 struct lyd_node *iter;
83 struct lys_node_list *slist;
84 int i;
85
86 assert(list->schema->nodetype == LYS_LIST);
87
88 /* even though hash is 0, it may be a valid hash, that is what we are going to check */
89
90 slist = (struct lys_node_list *)list->schema;
91 if (!slist->keys_size) {
92 /* always has keys */
93 return 1;
94 }
95
96 i = 0;
97 iter = list->child;
98 while (iter && (i < slist->keys_size)) {
99 if (iter->schema != (struct lys_node *)slist->keys[i]) {
100 /* missing key */
101 return 0;
102 }
103
104 ++i;
105 iter = iter->next;
106 }
107 if (i < slist->keys_size) {
108 /* missing key */
109 return 0;
110 }
111
112 /* all keys found */
113 return 1;
114 }
115
116 static int
lyd_leaf_val_equal(struct lyd_node * node1,struct lyd_node * node2,int diff_ctx)117 lyd_leaf_val_equal(struct lyd_node *node1, struct lyd_node *node2, int diff_ctx)
118 {
119 assert(node1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST));
120 assert(node1->schema->nodetype == node2->schema->nodetype);
121
122 if (diff_ctx) {
123 return ly_strequal(((struct lyd_node_leaf_list *)node1)->value_str, ((struct lyd_node_leaf_list *)node2)->value_str, 0);
124 } else {
125 return ly_strequal(((struct lyd_node_leaf_list *)node1)->value_str, ((struct lyd_node_leaf_list *)node2)->value_str, 1);
126 }
127 }
128
129 /*
130 * withdefaults (only for leaf-list):
131 * 0 - treat default nodes are normal nodes
132 * 1 - only change is that if 2 nodes have the same value, but one is default, the other not, they are considered non-equal
133 */
134 int
lyd_list_equal(struct lyd_node * node1,struct lyd_node * node2,int with_defaults)135 lyd_list_equal(struct lyd_node *node1, struct lyd_node *node2, int with_defaults)
136 {
137 int i, diff_ctx;
138 struct lyd_node *elem1, *next1, *elem2, *next2;
139 struct lys_node *elem1_sch;
140 struct ly_ctx *ctx = node2->schema->module->ctx;
141
142 diff_ctx = (node1->schema->module->ctx != node2->schema->module->ctx);
143
144 switch (node2->schema->nodetype) {
145 case LYS_LEAFLIST:
146 if (lyd_leaf_val_equal(node1, node2, diff_ctx) && (!with_defaults || (node1->dflt == node2->dflt))) {
147 return 1;
148 }
149 break;
150 case LYS_LIST:
151 if (((struct lys_node_list *)node1->schema)->keys_size) {
152 /* lists with keys, their equivalence is based on their keys */
153 elem1 = node1->child;
154 elem2 = node2->child;
155 elem1_sch = NULL;
156 /* the exact data order is guaranteed */
157 for (i = 0; i < ((struct lys_node_list *)node1->schema)->keys_size; ++i) {
158 if (diff_ctx && elem1) {
159 /* we have different contexts */
160 if (!elem1_sch) {
161 elem1_sch = lyd_get_schema_inctx(elem1, ctx);
162 if (!elem1_sch) {
163 LOGERR(ctx, LY_EINVAL, "Target context does not contain a required schema node (%s:%s).",
164 lyd_node_module(elem1)->name, elem1->schema->name);
165 return -1;
166 }
167 } else {
168 /* just move to the next schema node */
169 elem1_sch = elem1_sch->next;
170 }
171 }
172 if (!elem1 || !elem2 || ((elem1_sch ? elem1_sch : elem1->schema) != elem2->schema)
173 || !lyd_leaf_val_equal(elem1, elem2, diff_ctx)) {
174 break;
175 }
176 elem1 = elem1->next;
177 elem2 = elem2->next;
178 }
179 if (i == ((struct lys_node_list *)node1->schema)->keys_size) {
180 return 1;
181 }
182 } else {
183 /* lists wihtout keys, their equivalence is based on values of all the children (both direct and indirect) */
184 if (!node1->child && !node2->child) {
185 /* no children, nothing to compare */
186 return 1;
187 }
188
189 /* status lists without keys, we need to compare all the children :( */
190
191 /* LY_TREE_DFS_BEGIN for 2 data trees */
192 elem1 = next1 = node1->child;
193 elem2 = next2 = node2->child;
194 while (elem1 && elem2) {
195 /* node comparison */
196 #ifdef LY_ENABLED_CACHE
197 if (elem1->hash != elem2->hash) {
198 break;
199 }
200 #endif
201 if (diff_ctx) {
202 elem1_sch = lyd_get_schema_inctx(elem1, ctx);
203 if (!elem1_sch) {
204 LOGERR(ctx, LY_EINVAL, "Target context does not contain a required schema node (%s:%s).",
205 lyd_node_module(elem1)->name, elem1->schema->name);
206 return -1;
207 }
208 } else {
209 elem1_sch = elem1->schema;
210 }
211 if (elem1_sch != elem2->schema) {
212 break;
213 }
214 if (elem2->schema->nodetype == LYS_LIST) {
215 if (!lyd_list_has_keys(elem1) && !lyd_list_has_keys(elem2)) {
216 /* we encountered lists without keys (but have some defined in schema), ignore them for comparison */
217 next1 = NULL;
218 next2 = NULL;
219 goto next_sibling;
220 }
221 /* we will compare all the children of this list instance, not just keys */
222 } else if (elem2->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) {
223 if (!lyd_leaf_val_equal(elem1, elem2, diff_ctx) && (!with_defaults || (elem1->dflt == elem2->dflt))) {
224 break;
225 }
226 } else if (elem2->schema->nodetype & LYS_ANYDATA) {
227 if (!lyd_anydata_equal(elem1, elem2)) {
228 break;
229 }
230 }
231
232 /* LY_TREE_DFS_END for 2 data trees */
233 if (elem2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
234 next1 = NULL;
235 next2 = NULL;
236 } else {
237 next1 = elem1->child;
238 next2 = elem2->child;
239 }
240
241 next_sibling:
242 if (!next1) {
243 next1 = elem1->next;
244 }
245 if (!next2) {
246 next2 = elem2->next;
247 }
248
249 while (!next1) {
250 elem1 = elem1->parent;
251 if (elem1 == node1) {
252 break;
253 }
254 next1 = elem1->next;
255 }
256 while (!next2) {
257 elem2 = elem2->parent;
258 if (elem2 == node2) {
259 break;
260 }
261 next2 = elem2->next;
262 }
263
264 elem1 = next1;
265 elem2 = next2;
266 }
267
268 if (!elem1 && !elem2) {
269 /* all children were successfully compared */
270 return 1;
271 }
272 }
273 break;
274 default:
275 LOGINT(ctx);
276 return -1;
277 }
278
279 return 0;
280 }
281
282 #ifdef LY_ENABLED_CACHE
283
284 static int
lyd_hash_table_val_equal(void * val1_p,void * val2_p,int mod,void * UNUSED (cb_data))285 lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
286 {
287 struct lyd_node *val1, *val2;
288
289 val1 = *((struct lyd_node **)val1_p);
290 val2 = *((struct lyd_node **)val2_p);
291
292 if (mod) {
293 if (val1 == val2) {
294 return 1;
295 } else {
296 return 0;
297 }
298 }
299
300 if (val1->schema != val2->schema) {
301 return 0;
302 }
303
304 switch (val1->schema->nodetype) {
305 case LYS_CONTAINER:
306 case LYS_LEAF:
307 case LYS_ANYXML:
308 case LYS_ANYDATA:
309 return 1;
310 case LYS_LEAFLIST:
311 case LYS_LIST:
312 return lyd_list_equal(val1, val2, 0);
313 default:
314 break;
315 }
316
317 LOGINT(val1->schema->module->ctx);
318 return 0;
319 }
320
321 static void
lyd_hash_keyless_list_dfs(struct lyd_node * child,uint32_t * hash)322 lyd_hash_keyless_list_dfs(struct lyd_node *child, uint32_t *hash)
323 {
324 LY_TREE_FOR(child, child) {
325 switch (child->schema->nodetype) {
326 case LYS_CONTAINER:
327 lyd_hash_keyless_list_dfs(child->child, hash);
328 break;
329 case LYS_LIST:
330 /* ignore lists with missing keys */
331 if (lyd_list_has_keys(child)) {
332 lyd_hash_keyless_list_dfs(child->child, hash);
333 }
334 break;
335 case LYS_LEAFLIST:
336 case LYS_ANYXML:
337 case LYS_ANYDATA:
338 case LYS_LEAF:
339 *hash = dict_hash_multi(*hash, (char *)&child->hash, sizeof child->hash);
340 break;
341 default:
342 assert(0);
343 }
344 }
345 }
346
347 int
lyd_hash(struct lyd_node * node)348 lyd_hash(struct lyd_node *node)
349 {
350 struct lyd_node *iter;
351 int i;
352
353 if ((node->schema->nodetype != LYS_LIST) || lyd_list_has_keys(node)) {
354 node->hash = dict_hash_multi(0, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name));
355 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
356 if (node->schema->nodetype == LYS_LEAFLIST) {
357 node->hash = dict_hash_multi(node->hash, ((struct lyd_node_leaf_list *)node)->value_str,
358 strlen(((struct lyd_node_leaf_list *)node)->value_str));
359 } else if (node->schema->nodetype == LYS_LIST) {
360 if (((struct lys_node_list *)node->schema)->keys_size) {
361 for (i = 0, iter = node->child; i < ((struct lys_node_list *)node->schema)->keys_size; ++i, iter = iter->next) {
362 assert(iter);
363 node->hash = dict_hash_multi(node->hash, ((struct lyd_node_leaf_list *)iter)->value_str,
364 strlen(((struct lyd_node_leaf_list *)iter)->value_str));
365 }
366 } else {
367 /* no-keys list */
368 lyd_hash_keyless_list_dfs(node->child, &node->hash);
369 }
370 }
371 node->hash = dict_hash_multi(node->hash, NULL, 0);
372 return 0;
373 }
374
375 return 1;
376 }
377
378 static void
lyd_keyless_list_hash_change(struct lyd_node * parent)379 lyd_keyless_list_hash_change(struct lyd_node *parent)
380 {
381 int r;
382
383 while (parent && !(parent->schema->flags & LYS_CONFIG_W)) {
384 if (parent->schema->nodetype == LYS_LIST) {
385 if (parent->hash && !((struct lys_node_list *)parent->schema)->keys_size) {
386 if (parent->parent && parent->parent->ht) {
387 /* remove the list from the parent */
388 r = lyht_remove(parent->parent->ht, &parent, parent->hash);
389 assert(!r);
390 (void)r;
391 }
392 /* recalculate the hash */
393 lyd_hash(parent);
394 if (parent->parent && parent->parent->ht) {
395 /* re-add the list again */
396 r = lyht_insert(parent->parent->ht, &parent, parent->hash, NULL);
397 assert(!r);
398 (void)r;
399 }
400 } else if (!lyd_list_has_keys(parent)) {
401 /* a parent is a list without keys so it cannot be a part of any parent hash */
402 break;
403 }
404 }
405
406 parent = parent->parent;
407 }
408 }
409
410 static void
_lyd_insert_hash(struct lyd_node * node,int keyless_list_check)411 _lyd_insert_hash(struct lyd_node *node, int keyless_list_check)
412 {
413 struct lyd_node *iter;
414 int i;
415
416 if (node->parent) {
417 if ((node->schema->nodetype != LYS_LIST) || lyd_list_has_keys(node)) {
418 if ((node->schema->nodetype == LYS_LEAF) && lys_is_key((struct lys_node_leaf *)node->schema, NULL)) {
419 /* we are adding a key which means that it may be the last missing key for our parent's hash */
420 if (!lyd_hash(node->parent)) {
421 /* yep, we successfully hashed node->parent so it is technically now added to its parent (hash-wise) */
422 _lyd_insert_hash(node->parent, 0);
423 }
424 }
425
426 /* create parent hash table if required, otherwise just add the new child */
427 if (!node->parent->ht) {
428 for (i = 0, iter = node->parent->child; iter; ++i, iter = iter->next) {
429 if ((iter->schema->nodetype == LYS_LIST) && !lyd_list_has_keys(iter)) {
430 /* it will either never have keys and will never be hashed or has not all keys created yet */
431 --i;
432 }
433 }
434 assert(i <= LY_CACHE_HT_MIN_CHILDREN);
435 if (i == LY_CACHE_HT_MIN_CHILDREN) {
436 /* create hash table, insert all the children */
437 node->parent->ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
438 LY_TREE_FOR(node->parent->child, iter) {
439 if ((iter->schema->nodetype == LYS_LIST) && !lyd_list_has_keys(iter)) {
440 /* skip lists without keys */
441 continue;
442 }
443
444 if (lyht_insert(node->parent->ht, &iter, iter->hash, NULL)) {
445 assert(0);
446 }
447 }
448 }
449 } else {
450 if (lyht_insert(node->parent->ht, &node, node->hash, NULL)) {
451 assert(0);
452 }
453 }
454
455 /* if node was in a state data subtree, wasn't it a part of a key-less list hash? */
456 if (keyless_list_check) {
457 lyd_keyless_list_hash_change(node->parent);
458 }
459 }
460 }
461 }
462
463 /* we have inserted node into a parent */
464 void
lyd_insert_hash(struct lyd_node * node)465 lyd_insert_hash(struct lyd_node *node)
466 {
467 _lyd_insert_hash(node, 1);
468 }
469
470 static void
_lyd_unlink_hash(struct lyd_node * node,struct lyd_node * orig_parent,int keyless_list_check)471 _lyd_unlink_hash(struct lyd_node *node, struct lyd_node *orig_parent, int keyless_list_check)
472 {
473 #ifndef NDEBUG
474 struct lyd_node *iter;
475
476 /* it must already be unlinked otherwise keyless lists would get wrong hash */
477 if (keyless_list_check && orig_parent) {
478 LY_TREE_FOR(orig_parent->child, iter) {
479 assert(iter != node);
480 }
481 }
482 #endif
483
484 if (orig_parent && node->hash && ((node->schema->nodetype != LYS_LIST) || lyd_list_has_keys(node))) {
485 if (orig_parent->ht) {
486 if (lyht_remove(orig_parent->ht, &node, node->hash)) {
487 assert(0);
488 }
489
490 /* if no longer enough children, free the whole hash table */
491 if (orig_parent->ht->used < LY_CACHE_HT_MIN_CHILDREN) {
492 lyht_free(orig_parent->ht);
493 orig_parent->ht = NULL;
494 }
495 }
496
497 /* if the parent is missing a key now, remove hash, also from parent */
498 if (lys_is_key((struct lys_node_leaf *)node->schema, NULL) && orig_parent->hash) {
499 _lyd_unlink_hash(orig_parent, orig_parent->parent, 0);
500 orig_parent->hash = 0;
501 }
502
503 /* if node was in a state data subtree, shouldn't it be a part of a key-less list hash? */
504 if (keyless_list_check) {
505 lyd_keyless_list_hash_change(orig_parent);
506 }
507 }
508 }
509
510 /* we are unlinking a child from a parent */
511 void
lyd_unlink_hash(struct lyd_node * node,struct lyd_node * orig_parent)512 lyd_unlink_hash(struct lyd_node *node, struct lyd_node *orig_parent)
513 {
514 _lyd_unlink_hash(node, orig_parent, 1);
515 }
516
517 #endif
518
519 /**
520 * @brief get the list of \p data's siblings of the given schema
521 */
522 static int
lyd_get_node_siblings(const struct lyd_node * data,const struct lys_node * schema,struct ly_set * set)523 lyd_get_node_siblings(const struct lyd_node *data, const struct lys_node *schema, struct ly_set *set)
524 {
525 const struct lyd_node *iter;
526
527 assert(set && !set->number);
528 assert(schema);
529 assert(schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC |
530 LYS_ACTION));
531
532 if (!data) {
533 return 0;
534 }
535
536 LY_TREE_FOR(data, iter) {
537 if (iter->schema == schema) {
538 ly_set_add(set, (void*)iter, LY_SET_OPT_USEASLIST);
539 }
540 }
541
542 return set->number;
543 }
544
545 /**
546 * Check whether there are any "when" statements on a \p schema node and evaluate them.
547 *
548 * @return -1 on error, 0 on no when or evaluated to true, 1 on when evaluated to false
549 */
550 static int
lyd_is_when_false(struct lyd_node * root,struct lyd_node * last_parent,struct lys_node * schema,int options)551 lyd_is_when_false(struct lyd_node *root, struct lyd_node *last_parent, struct lys_node *schema, int options)
552 {
553 enum int_log_opts prev_ilo;
554 struct lyd_node *current, *dummy;
555
556 if ((!(options & LYD_OPT_TYPEMASK) || (options & (LYD_OPT_CONFIG | LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF | LYD_OPT_DATA_TEMPLATE)))
557 && resolve_applies_when(schema, 1, last_parent ? last_parent->schema : NULL)) {
558 /* evaluate when statements on a dummy data node */
559 if (schema->nodetype == LYS_CHOICE) {
560 schema = (struct lys_node *)lys_getnext(NULL, schema, NULL, LYS_GETNEXT_NOSTATECHECK);
561 }
562 if (!schema) {
563 /* choice has no descendant data nodes */
564 return 0;
565 }
566 dummy = lyd_new_dummy(root, last_parent, schema, NULL, 0);
567 if (!dummy) {
568 return -1;
569 }
570 if (!dummy->parent && root) {
571 /* connect dummy nodes into the data tree, insert it before the root
572 * to optimize later unlinking (lyd_free()) */
573 lyd_insert_before(root, dummy);
574 }
575 for (current = dummy; current; current = current->child) {
576 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
577 resolve_when(current, 0, NULL);
578 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
579
580 if (current->when_status & LYD_WHEN_FALSE) {
581 /* when evaluates to false */
582 lyd_free(dummy);
583 return 1;
584 }
585
586 if (current->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
587 /* termination node without a child */
588 break;
589 }
590 }
591 lyd_free(dummy);
592 }
593
594 return 0;
595 }
596
597 /**
598 * @param[in] root Root node to be able search the data tree in case of no instance
599 * @return
600 * 0 - all restrictions met
601 * 1 - restrictions not met
602 * 2 - schema node not enabled
603 */
604 static int
lyd_check_mandatory_data(struct lyd_node * root,struct lyd_node * last_parent,struct ly_set * instances,struct lys_node * schema,int options)605 lyd_check_mandatory_data(struct lyd_node *root, struct lyd_node *last_parent,
606 struct ly_set *instances, struct lys_node *schema, int options)
607 {
608 struct ly_ctx *ctx = schema->module->ctx;
609 uint32_t limit;
610 uint16_t status;
611
612 if (!instances->number) {
613 /* no instance in the data tree - check if the instantiating is enabled
614 * (check: if-feature, when, status data in non-status data tree)
615 */
616 status = (schema->flags & LYS_STATUS_MASK);
617 if (lys_is_disabled(schema, 2) || (status && status != LYS_STATUS_CURR)) {
618 /* disabled by if-feature */
619 return EXIT_SUCCESS;
620 } else if ((options & LYD_OPT_TRUSTED) || ((options & LYD_OPT_TYPEMASK) && (schema->flags & LYS_CONFIG_R))) {
621 /* status schema node in non-status data tree */
622 return EXIT_SUCCESS;
623 } else if (lyd_is_when_false(root, last_parent, schema, options)) {
624 return EXIT_SUCCESS;
625 }
626 /* the schema instance is not disabled by anything, continue with checking */
627 }
628
629 /* checking various mandatory conditions */
630 switch (schema->nodetype) {
631 case LYS_LEAF:
632 case LYS_ANYXML:
633 case LYS_ANYDATA:
634 /* mandatory */
635 if ((schema->flags & LYS_MAND_TRUE) && !instances->number) {
636 LOGVAL(ctx, LYE_MISSELEM, LY_VLOG_LYD, last_parent, schema->name,
637 last_parent ? last_parent->schema->name : lys_node_module(schema)->name);
638 return EXIT_FAILURE;
639 }
640 break;
641 case LYS_LIST:
642 /* min-elements */
643 limit = ((struct lys_node_list *)schema)->min;
644 if (limit && limit > instances->number) {
645 LOGVAL(ctx, LYE_NOMIN, LY_VLOG_LYD, last_parent, schema->name);
646 return EXIT_FAILURE;
647 }
648 /* max elements */
649 limit = ((struct lys_node_list *)schema)->max;
650 if (limit && limit < instances->number) {
651 LOGVAL(ctx, LYE_NOMAX, LY_VLOG_LYD, instances->set.d[limit], schema->name);
652 return EXIT_FAILURE;
653 }
654
655 break;
656
657 case LYS_LEAFLIST:
658 /* min-elements */
659 limit = ((struct lys_node_leaflist *)schema)->min;
660 if (limit && limit > instances->number) {
661 LOGVAL(ctx, LYE_NOMIN, LY_VLOG_LYD, last_parent, schema->name);
662 return EXIT_FAILURE;
663 }
664 /* max elements */
665 limit = ((struct lys_node_leaflist *)schema)->max;
666 if (limit && limit < instances->number) {
667 LOGVAL(ctx, LYE_NOMAX, LY_VLOG_LYD, instances->set.d[limit], schema->name);
668 return EXIT_FAILURE;
669 }
670 break;
671 default:
672 /* we cannot get here */
673 assert(0);
674 break;
675 }
676
677 return EXIT_SUCCESS;
678 }
679
680 /**
681 * @brief Check the specific subtree, specified by \p schema node, for presence of mandatory nodes. Function goes
682 * recursively into the subtree.
683 *
684 * What is being checked:
685 * - mandatory statement in leaf, choice, anyxml and anydata
686 * - min-elements and max-elements in list and leaf-list
687 *
688 * @param[in] tree Data tree, needed for case that subtree is NULL (in case of not existing data nodes to explore)
689 * @param[in] subtree Depend ons \p toplevel flag:
690 * toplevel = 1, then subtree is ignored, instead the tree is taken to search in top level data elements (if any)
691 * toplevel = 0, subtree is the parent data node of the possible instances of the schema node being checked
692 * @param[in] last_parent The last present parent data node (so it does not need to be a direct parent) of the possible
693 * instances of the schema node being checked
694 * @param[in] schema The schema node being checked for mandatory nodes
695 * @param[in] toplevel, see the \p root parameter description
696 * @param[in] options @ref parseroptions to specify the type of the data tree.
697 * @return EXIT_SUCCESS or EXIT_FAILURE if there are missing mandatory nodes
698 */
699 static int
lyd_check_mandatory_subtree(struct lyd_node * tree,struct lyd_node * subtree,struct lyd_node * last_parent,struct lys_node * schema,int toplevel,int options)700 lyd_check_mandatory_subtree(struct lyd_node *tree, struct lyd_node *subtree, struct lyd_node *last_parent,
701 struct lys_node *schema, int toplevel, int options)
702 {
703 struct lys_node *siter, *siter_prev;
704 struct lyd_node *iter;
705 struct ly_set *present = NULL;
706 unsigned int u;
707 int ret = EXIT_FAILURE;
708
709 assert(schema);
710
711 if (lys_is_disabled(schema, 0)) {
712 return EXIT_SUCCESS;
713 }
714
715 if (schema->nodetype & (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_CONTAINER)) {
716 /* data node */
717 present = ly_set_new();
718 if (!present) {
719 goto error;
720 }
721 if ((toplevel && tree) || (!toplevel && subtree)) {
722 if (toplevel) {
723 lyd_get_node_siblings(tree, schema, present);
724 } else {
725 lyd_get_node_siblings(subtree->child, schema, present);
726 }
727 }
728 }
729
730 switch (schema->nodetype) {
731 case LYS_LEAF:
732 case LYS_LEAFLIST:
733 case LYS_ANYXML:
734 case LYS_ANYDATA:
735 /* check the schema item */
736 if (lyd_check_mandatory_data(tree, last_parent, present, schema, options)) {
737 goto error;
738 }
739 break;
740 case LYS_LIST:
741 /* check the schema item */
742 if (lyd_check_mandatory_data(tree, last_parent, present, schema, options)) {
743 goto error;
744 }
745
746 /* go recursively */
747 for (u = 0; u < present->number; u++) {
748 LY_TREE_FOR(schema->child, siter) {
749 if (lyd_check_mandatory_subtree(tree, present->set.d[u], present->set.d[u], siter, 0, options)) {
750 goto error;
751 }
752 }
753 }
754 break;
755
756 case LYS_CONTAINER:
757 if (present->number || !((struct lys_node_container *)schema)->presence) {
758 /* if we have existing or non-presence container, go recursively */
759 LY_TREE_FOR(schema->child, siter) {
760 if (lyd_check_mandatory_subtree(tree, present->number ? present->set.d[0] : NULL,
761 present->number ? present->set.d[0] : last_parent,
762 siter, 0, options)) {
763 goto error;
764 }
765 }
766 }
767 break;
768 case LYS_CHOICE:
769 /* get existing node in the data tree from the choice */
770 iter = NULL;
771 if ((toplevel && tree) || (!toplevel && subtree)) {
772 LY_TREE_FOR(toplevel ? tree : subtree->child, iter) {
773 for (siter = lys_parent(iter->schema), siter_prev = iter->schema;
774 siter && (siter->nodetype & (LYS_CASE | LYS_USES | LYS_CHOICE));
775 siter_prev = siter, siter = lys_parent(siter)) {
776 if (siter == schema) {
777 /* we have the choice instance */
778 break;
779 }
780 }
781 if (siter == schema) {
782 /* we have the choice instance;
783 * the condition must be the same as in the loop because of
784 * choice's sibling nodes that break the loop, so siter is not NULL,
785 * but it is not the same as schema */
786 break;
787 }
788 }
789 }
790 if (!iter) {
791 if (lyd_is_when_false(tree, last_parent, schema, options)) {
792 /* nothing to check */
793 break;
794 }
795 if (((struct lys_node_choice *)schema)->dflt) {
796 /* there is a default case */
797 if (lyd_check_mandatory_subtree(tree, subtree, last_parent, ((struct lys_node_choice *)schema)->dflt,
798 toplevel, options)) {
799 goto error;
800 }
801 } else if (schema->flags & LYS_MAND_TRUE) {
802 /* choice requires some data to be instantiated */
803 LOGVAL(schema->module->ctx, LYE_NOMANDCHOICE, LY_VLOG_LYD, last_parent, schema->name);
804 goto error;
805 }
806 } else {
807 /* one of the choice's cases is instantiated, continue into this case */
808 /* since iter != NULL, siter must be also != NULL and we also know siter_prev
809 * which points to the child of schema leading towards the instantiated data */
810 assert(siter && siter_prev);
811 if (lyd_check_mandatory_subtree(tree, subtree, last_parent, siter_prev, toplevel, options)) {
812 goto error;
813 }
814 }
815 break;
816 case LYS_NOTIF:
817 /* skip if validating a notification */
818 if (!(options & LYD_OPT_NOTIF)) {
819 break;
820 }
821 /* fallthrough */
822 case LYS_CASE:
823 case LYS_USES:
824 case LYS_INPUT:
825 case LYS_OUTPUT:
826 /* go recursively */
827 LY_TREE_FOR(schema->child, siter) {
828 if (lyd_check_mandatory_subtree(tree, subtree, last_parent, siter, toplevel, options)) {
829 goto error;
830 }
831 }
832 break;
833 default:
834 /* stop */
835 break;
836 }
837
838 ret = EXIT_SUCCESS;
839
840 error:
841 ly_set_free(present);
842 return ret;
843 }
844
845 int
lyd_check_mandatory_tree(struct lyd_node * root,struct ly_ctx * ctx,const struct lys_module ** modules,int mod_count,int options)846 lyd_check_mandatory_tree(struct lyd_node *root, struct ly_ctx *ctx, const struct lys_module **modules, int mod_count,
847 int options)
848 {
849 struct lys_node *siter;
850 int i;
851
852 assert(root || ctx);
853 assert(!(options & LYD_OPT_ACT_NOTIF));
854
855 if (options & (LYD_OPT_TRUSTED | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
856 /* no check is needed */
857 return EXIT_SUCCESS;
858 }
859
860 if (!ctx) {
861 /* get context */
862 ctx = root->schema->module->ctx;
863 }
864
865 if (!(options & LYD_OPT_TYPEMASK) || (options & LYD_OPT_CONFIG)) {
866 if (options & LYD_OPT_NOSIBLINGS) {
867 if (root && lyd_check_mandatory_subtree(root, NULL, NULL, root->schema, 1, options)) {
868 return EXIT_FAILURE;
869 }
870 } else if (modules && mod_count) {
871 for (i = 0; i < mod_count; ++i) {
872 LY_TREE_FOR(modules[i]->data, siter) {
873 if (!(siter->nodetype & (LYS_RPC | LYS_NOTIF)) &&
874 lyd_check_mandatory_subtree(root, NULL, NULL, siter, 1, options)) {
875 return EXIT_FAILURE;
876 }
877 }
878 }
879 } else {
880 for (i = 0; i < ctx->models.used; i++) {
881 /* skip not implemented and disabled modules */
882 if (!ctx->models.list[i]->implemented || ctx->models.list[i]->disabled) {
883 continue;
884 }
885 if ((options & LYD_OPT_DATA_NO_YANGLIB) && !strcmp(ctx->models.list[i]->name, "ietf-yang-library")) {
886 /* skip ietf-yang-library */
887 continue;
888 }
889 LY_TREE_FOR(ctx->models.list[i]->data, siter) {
890 if (!(siter->nodetype & (LYS_RPC | LYS_NOTIF)) &&
891 lyd_check_mandatory_subtree(root, NULL, NULL, siter, 1, options)) {
892 return EXIT_FAILURE;
893 }
894 }
895 }
896 }
897 } else if (options & LYD_OPT_NOTIF) {
898 if (!root || (root->schema->nodetype != LYS_NOTIF)) {
899 LOGERR(ctx, LY_EINVAL, "Subtree is not a single notification.");
900 return EXIT_FAILURE;
901 }
902 if (root->schema->child && lyd_check_mandatory_subtree(root, root, root, root->schema, 0, options)) {
903 return EXIT_FAILURE;
904 }
905 } else if (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY)) {
906 if (!root || !(root->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
907 LOGERR(ctx, LY_EINVAL, "Subtree is not a single RPC/action/reply.");
908 return EXIT_FAILURE;
909 }
910 if (options & LYD_OPT_RPC) {
911 for (siter = root->schema->child; siter && siter->nodetype != LYS_INPUT; siter = siter->next);
912 } else { /* LYD_OPT_RPCREPLY */
913 for (siter = root->schema->child; siter && siter->nodetype != LYS_OUTPUT; siter = siter->next);
914 }
915 if (siter && lyd_check_mandatory_subtree(root, root, root, siter, 0, options)) {
916 return EXIT_FAILURE;
917 }
918 } else if (options & LYD_OPT_DATA_TEMPLATE) {
919 if (root && lyd_check_mandatory_subtree(root, NULL, NULL, root->schema, 1, options)) {
920 return EXIT_FAILURE;
921 }
922 } else {
923 LOGINT(ctx);
924 return EXIT_FAILURE;
925 }
926
927 return EXIT_SUCCESS;
928 }
929
930 static struct lyd_node *
lyd_parse_(struct ly_ctx * ctx,const struct lyd_node * rpc_act,const char * data,LYD_FORMAT format,int options,const struct lyd_node * data_tree,const char * yang_data_name)931 lyd_parse_(struct ly_ctx *ctx, const struct lyd_node *rpc_act, const char *data, LYD_FORMAT format, int options,
932 const struct lyd_node *data_tree, const char *yang_data_name)
933 {
934 struct lyxml_elem *xml;
935 struct lyd_node *result = NULL;
936 int xmlopt = LYXML_PARSE_MULTIROOT;
937
938 if (!ctx) {
939 LOGARG;
940 return NULL;
941 }
942
943 if (options & LYD_OPT_NOSIBLINGS) {
944 xmlopt = 0;
945 }
946
947 /* we must free all the errors, otherwise we are unable to properly check returned ly_errno :-/ */
948 ly_errno = LY_SUCCESS;
949 switch (format) {
950 case LYD_XML:
951 xml = lyxml_parse_mem(ctx, data, xmlopt);
952 if (ly_errno) {
953 break;
954 }
955 if (options & LYD_OPT_RPCREPLY) {
956 result = lyd_parse_xml(ctx, &xml, options, rpc_act, data_tree);
957 } else if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
958 result = lyd_parse_xml(ctx, &xml, options, data_tree);
959 } else if (options & LYD_OPT_DATA_TEMPLATE) {
960 result = lyd_parse_xml(ctx, &xml, options, yang_data_name);
961 } else {
962 result = lyd_parse_xml(ctx, &xml, options);
963 }
964 lyxml_free_withsiblings(ctx, xml);
965 break;
966 case LYD_JSON:
967 result = lyd_parse_json(ctx, data, options, rpc_act, data_tree, yang_data_name);
968 break;
969 case LYD_LYB:
970 result = lyd_parse_lyb(ctx, data, options, data_tree, yang_data_name, NULL);
971 break;
972 default:
973 /* error */
974 break;
975 }
976
977 if (ly_errno) {
978 lyd_free_withsiblings(result);
979 return NULL;
980 }
981
982 if ((options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY)) && lyd_schema_sort(result, 1)) {
983 /* rpc and rpc-reply must be sorted */
984 lyd_free_withsiblings(result);
985 return NULL;
986 }
987
988 return result;
989 }
990
991 static struct lyd_node *
lyd_parse_data_(struct ly_ctx * ctx,const char * data,LYD_FORMAT format,int options,va_list ap)992 lyd_parse_data_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
993 {
994 const struct lyd_node *rpc_act = NULL, *data_tree = NULL, *iter;
995 const char *yang_data_name = NULL;
996
997 if (lyp_data_check_options(ctx, options, __func__)) {
998 return NULL;
999 }
1000
1001 if (options & LYD_OPT_RPCREPLY) {
1002 rpc_act = va_arg(ap, const struct lyd_node *);
1003 if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_RPC | LYS_LIST | LYS_CONTAINER))) {
1004 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
1005 return NULL;
1006 }
1007 }
1008 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
1009 data_tree = va_arg(ap, const struct lyd_node *);
1010 if (data_tree) {
1011 if (options & LYD_OPT_NOEXTDEPS) {
1012 LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree and LYD_OPT_NOEXTDEPS set).",
1013 __func__);
1014 return NULL;
1015 }
1016
1017 LY_TREE_FOR(data_tree, iter) {
1018 if (iter->parent) {
1019 /* a sibling is not top-level */
1020 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
1021 return NULL;
1022 }
1023 }
1024
1025 /* move it to the beginning */
1026 for (; data_tree->prev->next; data_tree = data_tree->prev);
1027
1028 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
1029 if (options & LYD_OPT_NOSIBLINGS) {
1030 LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
1031 return NULL;
1032 }
1033 }
1034 }
1035 if (options & LYD_OPT_DATA_TEMPLATE) {
1036 yang_data_name = va_arg(ap, const char *);
1037 }
1038
1039 return lyd_parse_(ctx, rpc_act, data, format, options, data_tree, yang_data_name);
1040 }
1041
1042 API struct lyd_node *
lyd_parse_mem(struct ly_ctx * ctx,const char * data,LYD_FORMAT format,int options,...)1043 lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...)
1044 {
1045 FUN_IN;
1046
1047 va_list ap;
1048 struct lyd_node *result;
1049
1050 va_start(ap, options);
1051 result = lyd_parse_data_(ctx, data, format, options, ap);
1052 va_end(ap);
1053
1054 return result;
1055 }
1056
1057 static struct lyd_node *
lyd_parse_fd_(struct ly_ctx * ctx,int fd,LYD_FORMAT format,int options,va_list ap)1058 lyd_parse_fd_(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, va_list ap)
1059 {
1060 struct lyd_node *ret;
1061 size_t length;
1062 char *data;
1063
1064 if (!ctx || (fd == -1)) {
1065 LOGARG;
1066 return NULL;
1067 }
1068
1069 if (lyp_mmap(ctx, fd, 0, &length, (void **)&data)) {
1070 LOGERR(ctx, LY_ESYS, "Mapping file descriptor into memory failed (%s()).", __func__);
1071 return NULL;
1072 }
1073
1074 ret = lyd_parse_data_(ctx, data, format, options, ap);
1075
1076 lyp_munmap(data, length);
1077
1078 return ret;
1079 }
1080
1081 API struct lyd_node *
lyd_parse_fd(struct ly_ctx * ctx,int fd,LYD_FORMAT format,int options,...)1082 lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...)
1083 {
1084 FUN_IN;
1085
1086 struct lyd_node *ret;
1087 va_list ap;
1088
1089 va_start(ap, options);
1090 ret = lyd_parse_fd_(ctx, fd, format, options, ap);
1091 va_end(ap);
1092
1093 return ret;
1094 }
1095
1096 API struct lyd_node *
lyd_parse_path(struct ly_ctx * ctx,const char * path,LYD_FORMAT format,int options,...)1097 lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...)
1098 {
1099 FUN_IN;
1100
1101 int fd;
1102 struct lyd_node *ret;
1103 va_list ap;
1104
1105 if (!ctx || !path) {
1106 LOGARG;
1107 return NULL;
1108 }
1109
1110 fd = open(path, O_RDONLY);
1111 if (fd == -1) {
1112 LOGERR(ctx, LY_ESYS, "Failed to open data file \"%s\" (%s).", path, strerror(errno));
1113 return NULL;
1114 }
1115
1116 va_start(ap, options);
1117 ret = lyd_parse_fd_(ctx, fd, format, options, ap);
1118
1119 va_end(ap);
1120 close(fd);
1121
1122 return ret;
1123 }
1124
1125 static struct lys_node *
lyd_new_find_schema(struct lyd_node * parent,const struct lys_module * module,int rpc_output)1126 lyd_new_find_schema(struct lyd_node *parent, const struct lys_module *module, int rpc_output)
1127 {
1128 struct lys_node *siblings;
1129
1130 if (!parent) {
1131 siblings = module->data;
1132 } else {
1133 if (!parent->schema) {
1134 return NULL;
1135 }
1136 siblings = parent->schema->child;
1137 if (siblings && (siblings->nodetype == (rpc_output ? LYS_INPUT : LYS_OUTPUT))) {
1138 siblings = siblings->next;
1139 }
1140 if (siblings && (siblings->nodetype == (rpc_output ? LYS_OUTPUT : LYS_INPUT))) {
1141 siblings = siblings->child;
1142 }
1143 }
1144
1145 return siblings;
1146 }
1147
1148 struct lyd_node *
_lyd_new(struct lyd_node * parent,const struct lys_node * schema,int dflt)1149 _lyd_new(struct lyd_node *parent, const struct lys_node *schema, int dflt)
1150 {
1151 struct lyd_node *ret;
1152
1153 ret = calloc(1, sizeof *ret);
1154 LY_CHECK_ERR_RETURN(!ret, LOGMEM(schema->module->ctx), NULL);
1155
1156 ret->schema = (struct lys_node *)schema;
1157 ret->validity = ly_new_node_validity(schema);
1158 if (resolve_applies_when(schema, 0, NULL)) {
1159 ret->when_status = LYD_WHEN;
1160 }
1161 ret->prev = ret;
1162 ret->dflt = dflt;
1163
1164 #ifdef LY_ENABLED_CACHE
1165 lyd_hash(ret);
1166 #endif
1167
1168 if (parent) {
1169 if (lyd_insert(parent, ret)) {
1170 lyd_free(ret);
1171 return NULL;
1172 }
1173 }
1174 return ret;
1175 }
1176
1177 API struct lyd_node *
lyd_new(struct lyd_node * parent,const struct lys_module * module,const char * name)1178 lyd_new(struct lyd_node *parent, const struct lys_module *module, const char *name)
1179 {
1180 FUN_IN;
1181
1182 const struct lys_node *snode = NULL, *siblings;
1183
1184 if ((!parent && !module) || !name) {
1185 LOGARG;
1186 return NULL;
1187 }
1188
1189 if (module) {
1190 module = lys_main_module(module);
1191 }
1192
1193 siblings = lyd_new_find_schema(parent, module, 0);
1194 if (!siblings) {
1195 LOGARG;
1196 return NULL;
1197 }
1198
1199 if (lys_getnext_data(module, lys_parent(siblings), name, strlen(name), LYS_CONTAINER | LYS_LIST | LYS_NOTIF
1200 | LYS_RPC | LYS_ACTION, 0, &snode) || !snode) {
1201 LOGERR(siblings->module->ctx, LY_EINVAL, "Failed to find \"%s\" as a sibling to \"%s:%s\".",
1202 name, lys_node_module(siblings)->name, siblings->name);
1203 return NULL;
1204 }
1205
1206 return _lyd_new(parent, snode, 0);
1207 }
1208
1209 static struct lyd_node *
lyd_create_leaf(const struct lys_node * schema,const char * val_str,int dflt,int edit_leaf)1210 lyd_create_leaf(const struct lys_node *schema, const char *val_str, int dflt, int edit_leaf)
1211 {
1212 struct lyd_node_leaf_list *ret;
1213
1214 ret = calloc(1, sizeof *ret);
1215 LY_CHECK_ERR_RETURN(!ret, LOGMEM(schema->module->ctx), NULL);
1216
1217 ret->schema = (struct lys_node *)schema;
1218 ret->validity = ly_new_node_validity(schema);
1219 if (resolve_applies_when(schema, 0, NULL)) {
1220 ret->when_status = LYD_WHEN;
1221 }
1222 ret->prev = (struct lyd_node *)ret;
1223 ret->value_type = ((struct lys_node_leaf *)schema)->type.base;
1224 ret->value_str = lydict_insert(schema->module->ctx, val_str ? val_str : "", 0);
1225 ret->dflt = dflt;
1226
1227 if (edit_leaf && !val_str) {
1228 /* empty edit leaf, it is fine */
1229 ((struct lyd_node_leaf_list *)ret)->value_type = LY_TYPE_UNKNOWN;
1230 } else if (!lyp_parse_value(&((struct lys_node_leaf *)schema)->type, &ret->value_str, NULL, ret, NULL, NULL, 1, dflt)) {
1231 lyd_free((struct lyd_node *)ret);
1232 return NULL;
1233 }
1234
1235 #ifdef LY_ENABLED_CACHE
1236 lyd_hash((struct lyd_node *)ret);
1237 #endif
1238
1239 return (struct lyd_node *)ret;
1240 }
1241
1242 static struct lyd_node *
_lyd_new_leaf(struct lyd_node * parent,const struct lys_node * schema,const char * val_str,int dflt,int edit_leaf)1243 _lyd_new_leaf(struct lyd_node *parent, const struct lys_node *schema, const char *val_str, int dflt, int edit_leaf)
1244 {
1245 struct lyd_node *ret;
1246
1247 ret = lyd_create_leaf(schema, val_str, dflt, edit_leaf);
1248 if (!ret) {
1249 return NULL;
1250 }
1251
1252 /* connect to parent */
1253 if (parent) {
1254 if (lyd_insert(parent, ret)) {
1255 lyd_free(ret);
1256 return NULL;
1257 }
1258 }
1259
1260 if ((ret->schema->nodetype == LYS_LEAF) && (ret->schema->flags & LYS_UNIQUE)) {
1261 for (; parent && (parent->schema->nodetype != LYS_LIST); parent = parent->parent);
1262 if (parent) {
1263 parent->validity |= LYD_VAL_UNIQUE;
1264 } else {
1265 LOGINT(schema->module->ctx);
1266 }
1267 }
1268
1269 return ret;
1270 }
1271
1272 API struct lyd_node *
lyd_new_leaf(struct lyd_node * parent,const struct lys_module * module,const char * name,const char * val_str)1273 lyd_new_leaf(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
1274 {
1275 FUN_IN;
1276
1277 const struct lys_node *snode = NULL, *siblings;
1278
1279 if ((!parent && !module) || !name) {
1280 LOGARG;
1281 return NULL;
1282 }
1283
1284 if (module) {
1285 module = lys_main_module(module);
1286 }
1287
1288 siblings = lyd_new_find_schema(parent, module, 0);
1289 if (!siblings) {
1290 LOGARG;
1291 return NULL;
1292 }
1293
1294 if (lys_getnext_data(module, lys_parent(siblings), name, strlen(name), LYS_LEAFLIST | LYS_LEAF, 0, &snode) || !snode) {
1295 LOGERR(siblings->module->ctx, LY_EINVAL, "Failed to find \"%s\" as a sibling to \"%s:%s\".",
1296 name, lys_node_module(siblings)->name, siblings->name);
1297 return NULL;
1298 }
1299
1300 return _lyd_new_leaf(parent, snode, val_str, 0, 0);
1301 }
1302
1303 /**
1304 * @brief Update (add) default flag of the parents of the added node.
1305 *
1306 * @param[in] node Added node
1307 */
1308 static void
lyd_wd_update_parents(struct lyd_node * node)1309 lyd_wd_update_parents(struct lyd_node *node)
1310 {
1311 struct lyd_node *parent = node->parent, *iter;
1312
1313 for (parent = node->parent; parent; parent = node->parent) {
1314 if (parent->dflt || parent->schema->nodetype != LYS_CONTAINER ||
1315 ((struct lys_node_container *)parent->schema)->presence) {
1316 /* parent is already default and there is nothing to update or
1317 * it is not a non-presence container -> stop the loop */
1318 break;
1319 }
1320 /* check that there is still some non default sibling */
1321 for (iter = node->prev; iter != node; iter = iter->prev) {
1322 if (!iter->dflt) {
1323 break;
1324 }
1325 }
1326 if (iter == node && node->prev != node) {
1327 /* all siblings are implicit default nodes, propagate it to the parent */
1328 node = node->parent;
1329 node->dflt = 1;
1330 continue;
1331 } else {
1332 /* stop the loop */
1333 break;
1334 }
1335 }
1336 }
1337
1338 API int
lyd_change_leaf(struct lyd_node_leaf_list * leaf,const char * val_str)1339 lyd_change_leaf(struct lyd_node_leaf_list *leaf, const char *val_str)
1340 {
1341 FUN_IN;
1342
1343 const char *backup, *new_val;
1344 int val_change, dflt_change;
1345 struct lyd_node *parent;
1346
1347 if (!leaf || (leaf->schema->nodetype != LYS_LEAF)) {
1348 LOGARG;
1349 return -1;
1350 }
1351
1352 backup = leaf->value_str;
1353 new_val = lydict_insert(leaf->schema->module->ctx, val_str ? val_str : "", 0);
1354
1355 /* parse the type correctly, makes the value canonical if needed */
1356 if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &new_val, NULL, leaf, NULL, NULL, 1, 0)) {
1357 lydict_remove(leaf->schema->module->ctx, new_val);
1358 return -1;
1359 }
1360
1361 if (!strcmp(backup, new_val)) {
1362 /* the value remains the same */
1363 val_change = 0;
1364 } else {
1365 val_change = 1;
1366 }
1367
1368 /* value is correct, replace it */
1369 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
1370 leaf->value_str = new_val;
1371
1372 /* clear the default flag, the value is different */
1373 if (leaf->dflt) {
1374 for (parent = (struct lyd_node *)leaf; parent; parent = parent->parent) {
1375 parent->dflt = 0;
1376 }
1377 dflt_change = 1;
1378 } else {
1379 dflt_change = 0;
1380 }
1381
1382 if (val_change) {
1383 /* make the node non-validated */
1384 leaf->validity = ly_new_node_validity(leaf->schema);
1385
1386 /* set unique validation flag for parent list */
1387 if (leaf->schema->flags & LYS_UNIQUE) {
1388 for (parent = leaf->parent; parent && (parent->schema->nodetype != LYS_LIST); parent = parent->parent);
1389 if (parent) {
1390 parent->validity |= LYD_VAL_UNIQUE;
1391 }
1392 }
1393
1394 #ifdef LY_ENABLED_CACHE
1395 /* rehash list if it's key was changed */
1396 if (lys_is_key((struct lys_node_leaf *)leaf->schema, NULL)) {
1397 _lyd_unlink_hash((struct lyd_node *)leaf, leaf->parent, 0);
1398 if (leaf->parent) {
1399 lyd_hash(leaf->parent);
1400 }
1401 lyd_insert_hash((struct lyd_node *)leaf);
1402 }
1403 #endif
1404 }
1405
1406 return (val_change || dflt_change ? 0 : 1);
1407 }
1408
1409 static struct lyd_node *
lyd_create_anydata(struct lyd_node * parent,const struct lys_node * schema,void * value,LYD_ANYDATA_VALUETYPE value_type)1410 lyd_create_anydata(struct lyd_node *parent, const struct lys_node *schema, void *value,
1411 LYD_ANYDATA_VALUETYPE value_type)
1412 {
1413 struct lyd_node *iter;
1414 struct lyd_node_anydata *ret;
1415 int len;
1416
1417 ret = calloc(1, sizeof *ret);
1418 LY_CHECK_ERR_RETURN(!ret, LOGMEM(schema->module->ctx), NULL);
1419
1420 ret->schema = (struct lys_node *)schema;
1421 ret->validity = ly_new_node_validity(schema);
1422 if (resolve_applies_when(schema, 0, NULL)) {
1423 ret->when_status = LYD_WHEN;
1424 }
1425 ret->prev = (struct lyd_node *)ret;
1426
1427 /* set the value */
1428 switch (value_type) {
1429 case LYD_ANYDATA_CONSTSTRING:
1430 case LYD_ANYDATA_SXML:
1431 case LYD_ANYDATA_JSON:
1432 ret->value.str = lydict_insert(schema->module->ctx, (const char *)value, 0);
1433 break;
1434 case LYD_ANYDATA_STRING:
1435 case LYD_ANYDATA_SXMLD:
1436 case LYD_ANYDATA_JSOND:
1437 ret->value.str = lydict_insert_zc(schema->module->ctx, (char *)value);
1438 value_type &= ~LYD_ANYDATA_STRING; /* make const string from string */
1439 break;
1440 case LYD_ANYDATA_DATATREE:
1441 ret->value.tree = (struct lyd_node *)value;
1442 break;
1443 case LYD_ANYDATA_XML:
1444 ret->value.xml = (struct lyxml_elem *)value;
1445 break;
1446 case LYD_ANYDATA_LYB:
1447 len = lyd_lyb_data_length(value);
1448 if (len == -1) {
1449 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid LYB data.");
1450 return NULL;
1451 }
1452 ret->value.mem = malloc(len);
1453 LY_CHECK_ERR_RETURN(!ret->value.mem, LOGMEM(schema->module->ctx); free(ret), NULL);
1454 memcpy(ret->value.mem, value, len);
1455 break;
1456 case LYD_ANYDATA_LYBD:
1457 ret->value.mem = value;
1458 value_type &= ~LYD_ANYDATA_STRING; /* make const string from string */
1459 break;
1460 }
1461 ret->value_type = value_type;
1462
1463 #ifdef LY_ENABLED_CACHE
1464 lyd_hash((struct lyd_node *)ret);
1465 #endif
1466
1467 /* connect to parent */
1468 if (parent) {
1469 if (lyd_insert(parent, (struct lyd_node*)ret)) {
1470 lyd_free((struct lyd_node*)ret);
1471 return NULL;
1472 }
1473
1474 /* remove the flag from parents */
1475 for (iter = parent; iter && iter->dflt; iter = iter->parent) {
1476 iter->dflt = 0;
1477 }
1478 }
1479
1480 return (struct lyd_node*)ret;
1481 }
1482
1483 API struct lyd_node *
lyd_new_anydata(struct lyd_node * parent,const struct lys_module * module,const char * name,void * value,LYD_ANYDATA_VALUETYPE value_type)1484 lyd_new_anydata(struct lyd_node *parent, const struct lys_module *module, const char *name,
1485 void *value, LYD_ANYDATA_VALUETYPE value_type)
1486 {
1487 FUN_IN;
1488
1489 const struct lys_node *siblings, *snode;
1490
1491 if ((!parent && !module) || !name) {
1492 LOGARG;
1493 return NULL;
1494 }
1495
1496 if (module) {
1497 module = lys_main_module(module);
1498 }
1499
1500 siblings = lyd_new_find_schema(parent, module, 0);
1501 if (!siblings) {
1502 LOGARG;
1503 return NULL;
1504 }
1505
1506 if (lys_getnext_data(module, lys_parent(siblings), name, strlen(name), LYS_ANYDATA, 0, &snode) || !snode) {
1507 LOGERR(siblings->module->ctx, LY_EINVAL, "Failed to find \"%s\" as a sibling to \"%s:%s\".",
1508 name, lys_node_module(siblings)->name, siblings->name);
1509 return NULL;
1510 }
1511
1512 return lyd_create_anydata(parent, snode, value, value_type);
1513 }
1514
1515 API struct lyd_node *
lyd_new_yangdata(const struct lys_module * module,const char * name_template,const char * name)1516 lyd_new_yangdata(const struct lys_module *module, const char *name_template, const char *name)
1517 {
1518 FUN_IN;
1519
1520 const struct lys_node *schema = NULL, *snode;
1521
1522 if (!module || !name_template || !name) {
1523 LOGARG;
1524 return NULL;
1525 }
1526
1527 module = lys_main_module(module);
1528
1529 schema = lyp_get_yang_data_template(module, name_template, strlen(name_template));
1530 if (!schema) {
1531 LOGERR(module->ctx, LY_EINVAL, "Failed to find yang-data template \"%s\".", name_template);
1532 return NULL;
1533 }
1534
1535 if (lys_getnext_data(module, schema, name, strlen(name), LYS_CONTAINER, 0, &snode) || !snode) {
1536 LOGERR(module->ctx, LY_EINVAL, "Failed to find \"%s\" as a container child of \"%s:%s\".",
1537 name, module->name, schema->name);
1538 return NULL;
1539 }
1540
1541 return _lyd_new(NULL, snode, 0);
1542 }
1543
1544 API struct lyd_node *
lyd_new_output(struct lyd_node * parent,const struct lys_module * module,const char * name)1545 lyd_new_output(struct lyd_node *parent, const struct lys_module *module, const char *name)
1546 {
1547 FUN_IN;
1548
1549 const struct lys_node *snode = NULL, *siblings;
1550
1551 if ((!parent && !module) || !name) {
1552 LOGARG;
1553 return NULL;
1554 }
1555
1556 if (module) {
1557 module = lys_main_module(module);
1558 }
1559
1560 siblings = lyd_new_find_schema(parent, module, 1);
1561 if (!siblings) {
1562 LOGARG;
1563 return NULL;
1564 }
1565
1566 if (lys_getnext_data(module, lys_parent(siblings), name, strlen(name), LYS_CONTAINER | LYS_LIST | LYS_NOTIF
1567 | LYS_RPC | LYS_ACTION, 0, &snode) || !snode) {
1568 LOGERR(siblings->module->ctx, LY_EINVAL, "Failed to find \"%s\" as a sibling to \"%s:%s\".",
1569 name, lys_node_module(siblings)->name, siblings->name);
1570 return NULL;
1571 }
1572
1573 return _lyd_new(parent, snode, 0);
1574 }
1575
1576 API struct lyd_node *
lyd_new_output_leaf(struct lyd_node * parent,const struct lys_module * module,const char * name,const char * val_str)1577 lyd_new_output_leaf(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
1578 {
1579 FUN_IN;
1580
1581 const struct lys_node *snode = NULL, *siblings;
1582
1583 if ((!parent && !module) || !name) {
1584 LOGARG;
1585 return NULL;
1586 }
1587
1588 if (module) {
1589 module = lys_main_module(module);
1590 }
1591
1592 siblings = lyd_new_find_schema(parent, module, 1);
1593 if (!siblings) {
1594 LOGARG;
1595 return NULL;
1596 }
1597
1598 if (lys_getnext_data(module, lys_parent(siblings), name, strlen(name), LYS_LEAFLIST | LYS_LEAF, 0, &snode) || !snode) {
1599 LOGERR(siblings->module->ctx, LY_EINVAL, "Failed to find \"%s\" as a sibling to \"%s:%s\".",
1600 name, lys_node_module(siblings)->name, siblings->name);
1601 return NULL;
1602 }
1603
1604 return _lyd_new_leaf(parent, snode, val_str, 0, 0);
1605 }
1606
1607 API struct lyd_node *
lyd_new_output_anydata(struct lyd_node * parent,const struct lys_module * module,const char * name,void * value,LYD_ANYDATA_VALUETYPE value_type)1608 lyd_new_output_anydata(struct lyd_node *parent, const struct lys_module *module, const char *name,
1609 void *value, LYD_ANYDATA_VALUETYPE value_type)
1610 {
1611 FUN_IN;
1612
1613 const struct lys_node *siblings, *snode;
1614
1615 if ((!parent && !module) || !name) {
1616 LOGARG;
1617 return NULL;
1618 }
1619
1620 if (module) {
1621 module = lys_main_module(module);
1622 }
1623
1624 siblings = lyd_new_find_schema(parent, module, 1);
1625 if (!siblings) {
1626 LOGARG;
1627 return NULL;
1628 }
1629
1630 if (lys_getnext_data(module, lys_parent(siblings), name, strlen(name), LYS_ANYDATA, 0, &snode) || !snode) {
1631 LOGERR(siblings->module->ctx, LY_EINVAL, "Failed to find \"%s\" as a sibling to \"%s:%s\".",
1632 name, lys_node_module(siblings)->name, siblings->name);
1633 return NULL;
1634 }
1635
1636 return lyd_create_anydata(parent, snode, value, value_type);
1637 }
1638
1639 char *
lyd_make_canonical(const struct lys_node * schema,const char * val_str,int val_str_len)1640 lyd_make_canonical(const struct lys_node *schema, const char *val_str, int val_str_len)
1641 {
1642 struct lyd_node *node;
1643 char *str;
1644
1645 assert(schema->nodetype & (LYS_LEAF | LYS_LEAFLIST));
1646
1647 /* parse the value into a fake leaf */
1648 struct lyd_node_leaf_list *node_leaf_list;
1649
1650 node_leaf_list = calloc(1, sizeof *node_leaf_list);
1651 LY_CHECK_ERR_RETURN(!node_leaf_list, LOGMEM(schema->module->ctx), NULL);
1652
1653 node_leaf_list->schema = (struct lys_node *)schema;
1654 node_leaf_list->prev = (struct lyd_node *)node_leaf_list;
1655 node_leaf_list->value_type = ((struct lys_node_leaf *)schema)->type.base;
1656 node_leaf_list->value_str = lydict_insert(schema->module->ctx, val_str ? val_str : "", val_str_len);
1657 node_leaf_list->dflt = 0;
1658
1659 if (!lyp_parse_value(&((struct lys_node_leaf *)schema)->type, &node_leaf_list->value_str, NULL, node_leaf_list,
1660 NULL, NULL, 1, 0)) {
1661 lyd_free((struct lyd_node *)node_leaf_list);
1662 return NULL;
1663 }
1664
1665 node = (struct lyd_node *)node_leaf_list;
1666
1667 if (!node) {
1668 return NULL;
1669 }
1670
1671 str = strdup(((struct lyd_node_leaf_list *)node)->value_str);
1672 lyd_free(node);
1673 if (!str) {
1674 LOGMEM(schema->module->ctx);
1675 return NULL;
1676 }
1677
1678 return str;
1679 }
1680
1681 static int
lyd_new_path_list_predicate(struct lyd_node * list,const char * list_name,const char * predicate,int * parsed)1682 lyd_new_path_list_predicate(struct lyd_node *list, const char *list_name, const char *predicate, int *parsed)
1683 {
1684 const char *mod_name, *name, *value;
1685 char *key_val;
1686 int r, i, mod_name_len, nam_len, val_len, has_predicate;
1687 struct lys_node_list *slist;
1688 struct lys_node *key;
1689
1690 slist = (struct lys_node_list *)list->schema;
1691
1692 /* is the predicate a number? */
1693 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
1694 || !strncmp(name, ".", nam_len)) {
1695 LOGVAL(slist->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
1696 return -1;
1697 }
1698
1699 if (isdigit(name[0])) {
1700 /* position index - creating without keys */
1701 *parsed += r;
1702 return 0;
1703 }
1704
1705 /* it's not a number, so there must be some keys */
1706 if (!slist->keys_size) {
1707 /* there are none, so pretend we did not parse anything to get invalid char error later */
1708 return 0;
1709 }
1710
1711 /* go through all the keys */
1712 i = 0;
1713 goto check_parsed_values;
1714
1715 for (; i < slist->keys_size; ++i) {
1716 if (!has_predicate) {
1717 LOGVAL(slist->module->ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, list_name);
1718 return -1;
1719 }
1720
1721 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
1722 || !strncmp(name, ".", nam_len)) {
1723 LOGVAL(slist->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
1724 return -1;
1725 }
1726
1727 check_parsed_values:
1728 key = (struct lys_node *)slist->keys[i];
1729 *parsed += r;
1730 predicate += r;
1731
1732 if (!value || (!mod_name && (lys_node_module(key) != lys_node_module((struct lys_node *)slist)))
1733 || (mod_name && (strncmp(lys_node_module(key)->name, mod_name, mod_name_len) || lys_node_module(key)->name[mod_name_len]))
1734 || strncmp(key->name, name, nam_len) || key->name[nam_len]) {
1735 LOGVAL(slist->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1736 return -1;
1737 }
1738
1739 key_val = malloc((val_len + 1) * sizeof(char));
1740 LY_CHECK_ERR_RETURN(!key_val, LOGMEM(slist->module->ctx), -1);
1741 strncpy(key_val, value, val_len);
1742 key_val[val_len] = '\0';
1743
1744 if (!_lyd_new_leaf(list, key, key_val, 0, 0)) {
1745 free(key_val);
1746 return -1;
1747 }
1748 free(key_val);
1749 }
1750
1751 return 0;
1752 }
1753
1754 static struct lyd_node *
lyd_new_path_update(struct lyd_node * node,void * value,LYD_ANYDATA_VALUETYPE value_type,int dflt)1755 lyd_new_path_update(struct lyd_node *node, void *value, LYD_ANYDATA_VALUETYPE value_type, int dflt)
1756 {
1757 struct ly_ctx *ctx = node->schema->module->ctx;
1758 struct lyd_node_anydata *any;
1759 int len;
1760
1761 switch (node->schema->nodetype) {
1762 case LYS_LEAF:
1763 if (value_type > LYD_ANYDATA_STRING) {
1764 LOGARG;
1765 return NULL;
1766 }
1767
1768 if (lyd_change_leaf((struct lyd_node_leaf_list *)node, value) == 0) {
1769 /* there was an actual change */
1770 if (dflt) {
1771 node->dflt = 1;
1772 }
1773 return node;
1774 }
1775
1776 if (dflt) {
1777 /* maybe the value is the same, but the node is default now */
1778 node->dflt = 1;
1779 return node;
1780 }
1781
1782 break;
1783 case LYS_ANYXML:
1784 case LYS_ANYDATA:
1785 /* the nodes are the same if:
1786 * 1) the value types are strings (LYD_ANYDATA_STRING and LYD_ANYDATA_CONSTSTRING equals)
1787 * and the strings equals
1788 * 2) the value types are the same, but not strings and the pointers (not the content) are the
1789 * same
1790 */
1791 any = (struct lyd_node_anydata *)node;
1792 if (any->value_type <= LYD_ANYDATA_STRING && value_type <= LYD_ANYDATA_STRING) {
1793 if (ly_strequal(any->value.str, (char *)value, 0)) {
1794 /* values are the same */
1795 return NULL;
1796 }
1797 } else if (any->value_type == value_type) {
1798 /* compare pointers */
1799 if ((void *)any->value.tree == value) {
1800 /* values are the same */
1801 return NULL;
1802 }
1803 }
1804
1805 /* values are not the same - 1) remove the old one ... */
1806 switch (any->value_type) {
1807 case LYD_ANYDATA_CONSTSTRING:
1808 case LYD_ANYDATA_SXML:
1809 case LYD_ANYDATA_JSON:
1810 lydict_remove(ctx, any->value.str);
1811 break;
1812 case LYD_ANYDATA_DATATREE:
1813 lyd_free_withsiblings(any->value.tree);
1814 break;
1815 case LYD_ANYDATA_XML:
1816 lyxml_free_withsiblings(ctx, any->value.xml);
1817 break;
1818 case LYD_ANYDATA_LYB:
1819 free(any->value.mem);
1820 break;
1821 case LYD_ANYDATA_STRING:
1822 case LYD_ANYDATA_SXMLD:
1823 case LYD_ANYDATA_JSOND:
1824 case LYD_ANYDATA_LYBD:
1825 /* dynamic strings are used only as input parameters */
1826 assert(0);
1827 break;
1828 }
1829 /* ... and 2) store the new one */
1830 switch (value_type) {
1831 case LYD_ANYDATA_CONSTSTRING:
1832 case LYD_ANYDATA_SXML:
1833 case LYD_ANYDATA_JSON:
1834 any->value.str = lydict_insert(ctx, (const char *)value, 0);
1835 break;
1836 case LYD_ANYDATA_STRING:
1837 case LYD_ANYDATA_SXMLD:
1838 case LYD_ANYDATA_JSOND:
1839 any->value.str = lydict_insert_zc(ctx, (char *)value);
1840 value_type &= ~LYD_ANYDATA_STRING; /* make const string from string */
1841 break;
1842 case LYD_ANYDATA_DATATREE:
1843 any->value.tree = value;
1844 break;
1845 case LYD_ANYDATA_XML:
1846 any->value.xml = value;
1847 break;
1848 case LYD_ANYDATA_LYB:
1849 len = lyd_lyb_data_length(value);
1850 if (len == -1) {
1851 LOGERR(ctx, LY_EINVAL, "Invalid LYB data.");
1852 return NULL;
1853 }
1854 any->value.mem = malloc(len);
1855 LY_CHECK_ERR_RETURN(!any->value.mem, LOGMEM(ctx), NULL);
1856 memcpy(any->value.mem, value, len);
1857 break;
1858 case LYD_ANYDATA_LYBD:
1859 any->value.mem = value;
1860 value_type &= ~LYD_ANYDATA_STRING; /* make const string from string */
1861 break;
1862 }
1863 return node;
1864 default:
1865 /* nothing needed - containers, lists and leaf-lists do not have value or it cannot be changed */
1866 break;
1867 }
1868
1869 /* not updated */
1870 return NULL;
1871 }
1872
1873 API struct lyd_node *
lyd_new_path(struct lyd_node * data_tree,const struct ly_ctx * ctx,const char * path,void * value,LYD_ANYDATA_VALUETYPE value_type,int options)1874 lyd_new_path(struct lyd_node *data_tree, const struct ly_ctx *ctx, const char *path, void *value,
1875 LYD_ANYDATA_VALUETYPE value_type, int options)
1876 {
1877 FUN_IN;
1878
1879 char *str;
1880 const char *mod_name, *name, *val_name, *val, *node_mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
1881 struct lyd_node *ret = NULL, *node, *parent = NULL;
1882 const struct lys_node *schild, *sparent, *tmp;
1883 const struct lys_node_list *slist;
1884 const struct lys_module *module, *prev_mod;
1885 int r, i, parsed = 0, mod_name_len, nam_len, val_name_len, val_len;
1886 int is_relative = -1, has_predicate, first_iter = 1;
1887 int backup_is_relative, backup_mod_name_len, yang_data_name_len = 0;
1888
1889 if (!path || (!data_tree && !ctx)
1890 || (!data_tree && (path[0] != '/'))) {
1891 LOGARG;
1892 return NULL;
1893 }
1894
1895 if (!ctx) {
1896 ctx = data_tree->schema->module->ctx;
1897 }
1898
1899 id = path;
1900
1901 if (data_tree) {
1902 if (path[0] == '/') {
1903 /* absolute path, go through all the siblings and try to find the right parent, if exists,
1904 * first go through all the next siblings keeping the original order, for positional predicates */
1905 for (node = data_tree; !parsed && node; node = node->next) {
1906 parent = resolve_partial_json_data_nodeid(id, value_type > LYD_ANYDATA_STRING ? NULL : value, node,
1907 options, &parsed);
1908 }
1909 if (!parsed) {
1910 for (node = data_tree->prev; !parsed && node->next; node = node->prev) {
1911 parent = resolve_partial_json_data_nodeid(id, value_type > LYD_ANYDATA_STRING ? NULL : value, node,
1912 options, &parsed);
1913 }
1914 }
1915 } else {
1916 /* relative path, use only the provided data tree root */
1917 parent = resolve_partial_json_data_nodeid(id, value_type > LYD_ANYDATA_STRING ? NULL : value, data_tree,
1918 options, &parsed);
1919 }
1920 if (parsed == -1) {
1921 return NULL;
1922 }
1923 if (parsed) {
1924 assert(parent);
1925 /* if we parsed something we have a relative path now for sure, otherwise we don't know */
1926 is_relative = 1;
1927
1928 id += parsed;
1929
1930 if (!id[0]) {
1931 /* the node exists, are we supposed to update it or is it default? */
1932 if (!(options & LYD_PATH_OPT_UPDATE) && (!parent->dflt || (options & LYD_PATH_OPT_DFLT))) {
1933 LOGVAL(ctx, LYE_PATH_EXISTS, LY_VLOG_STR, path);
1934 return NULL;
1935 }
1936
1937 /* no change, the default node already exists */
1938 if (parent->dflt && (options & LYD_PATH_OPT_DFLT)) {
1939 return NULL;
1940 }
1941
1942 return lyd_new_path_update(parent, value, value_type, options & LYD_PATH_OPT_DFLT);
1943 }
1944 }
1945 }
1946
1947 backup_is_relative = is_relative;
1948 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
1949 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1950 return NULL;
1951 }
1952
1953 if (name[0] == '#') {
1954 if (is_relative) {
1955 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1956 return NULL;
1957 }
1958 yang_data_name = name + 1;
1959 yang_data_name_len = nam_len - 1;
1960 backup_mod_name = mod_name;
1961 backup_mod_name_len = mod_name_len;
1962 /* move to the next node in the path */
1963 id += r;
1964 } else {
1965 is_relative = backup_is_relative;
1966 }
1967
1968 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
1969 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1970 return NULL;
1971 }
1972 /* move to the next node in the path */
1973 id += r;
1974
1975 if (backup_mod_name) {
1976 mod_name = backup_mod_name;
1977 mod_name_len = backup_mod_name_len;
1978 }
1979
1980 /* prepare everything for the schema search loop */
1981 if (is_relative) {
1982 /* we are relative to data_tree or parent if some part of the path already exists */
1983 if (!data_tree) {
1984 LOGERR(ctx, LY_EINVAL, "%s: provided relative path (%s) without context node.", __func__, path);
1985 return NULL;
1986 } else if (!parent) {
1987 parent = data_tree;
1988 }
1989 sparent = parent->schema;
1990 module = prev_mod = lys_node_module(sparent);
1991 } else {
1992 /* we are starting from scratch, absolute path */
1993 assert(!parent);
1994 if (!mod_name) {
1995 str = strndup(path, (name + nam_len) - path);
1996 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, str);
1997 free(str);
1998 return NULL;
1999 }
2000
2001 module = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
2002
2003 if (!module) {
2004 str = strndup(path, (mod_name + mod_name_len) - path);
2005 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
2006 free(str);
2007 return NULL;
2008 }
2009 mod_name = NULL;
2010 mod_name_len = 0;
2011 prev_mod = module;
2012
2013 sparent = NULL;
2014 if (yang_data_name) {
2015 sparent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2016 if (!sparent) {
2017 str = strndup(path, (yang_data_name + yang_data_name_len) - path);
2018 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2019 free(str);
2020 return NULL;
2021 }
2022 }
2023 }
2024
2025 /* create nodes in a loop */
2026 while (1) {
2027 /* find the schema node */
2028 schild = NULL;
2029 while ((schild = lys_getnext(schild, sparent, module, 0))) {
2030 if (schild->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST
2031 | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
2032 /* module comparison */
2033 if (mod_name) {
2034 node_mod_name = lys_node_module(schild)->name;
2035 if (strncmp(node_mod_name, mod_name, mod_name_len) || node_mod_name[mod_name_len]) {
2036 continue;
2037 }
2038 } else if (lys_node_module(schild) != prev_mod) {
2039 continue;
2040 }
2041
2042 /* name check */
2043 if (strncmp(schild->name, name, nam_len) || schild->name[nam_len]) {
2044 continue;
2045 }
2046
2047 /* RPC/action in/out check */
2048 for (tmp = lys_parent(schild); tmp && (tmp->nodetype == LYS_USES); tmp = lys_parent(tmp));
2049 if (tmp) {
2050 if (options & LYD_PATH_OPT_OUTPUT) {
2051 if (tmp->nodetype == LYS_INPUT) {
2052 continue;
2053 }
2054 } else {
2055 if (tmp->nodetype == LYS_OUTPUT) {
2056 continue;
2057 }
2058 }
2059 }
2060
2061 break;
2062 }
2063 }
2064
2065 if (!schild) {
2066 str = strndup(path, (name + nam_len) - path);
2067 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2068 free(str);
2069 lyd_free(ret);
2070 return NULL;
2071 }
2072
2073 /* we have the right schema node */
2074 switch (schild->nodetype) {
2075 case LYS_CONTAINER:
2076 case LYS_LIST:
2077 case LYS_NOTIF:
2078 case LYS_RPC:
2079 case LYS_ACTION:
2080 if (options & LYD_PATH_OPT_NOPARENT) {
2081 /* these were supposed to exist */
2082 str = strndup(path, (name + nam_len) - path);
2083 LOGVAL(ctx, LYE_PATH_MISSPAR, LY_VLOG_STR, str);
2084 free(str);
2085 lyd_free(ret);
2086 return NULL;
2087 }
2088 node = _lyd_new(is_relative ? parent : NULL, schild, (options & LYD_PATH_OPT_DFLT) ? 1 : 0);
2089 break;
2090 case LYS_LEAF:
2091 case LYS_LEAFLIST:
2092 str = NULL;
2093 if (has_predicate) {
2094 if ((r = parse_schema_json_predicate(id, NULL, NULL, &val_name, &val_name_len, &val, &val_len, &has_predicate)) < 1) {
2095 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2096 lyd_free(ret);
2097 return NULL;
2098 }
2099 id += r;
2100
2101 if ((val_name[0] != '.') || (val_name_len != 1)) {
2102 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, val_name[0], val_name);
2103 lyd_free(ret);
2104 return NULL;
2105 }
2106
2107 str = strndup(val, val_len);
2108 if (!str) {
2109 LOGMEM(ctx);
2110 lyd_free(ret);
2111 return NULL;
2112 }
2113 }
2114 if (id[0]) {
2115 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2116 free(str);
2117 lyd_free(ret);
2118 return NULL;
2119 }
2120
2121 node = _lyd_new_leaf(is_relative ? parent : NULL, schild, (str ? str : value),
2122 (options & LYD_PATH_OPT_DFLT) ? 1 : 0, options & LYD_PATH_OPT_EDIT);
2123 free(str);
2124 break;
2125 case LYS_ANYXML:
2126 case LYS_ANYDATA:
2127 if (id[0]) {
2128 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2129 lyd_free(ret);
2130 return NULL;
2131 }
2132 if (value_type <= LYD_ANYDATA_STRING && !value) {
2133 value_type = LYD_ANYDATA_CONSTSTRING;
2134 value = "";
2135 }
2136 node = lyd_create_anydata(is_relative ? parent : NULL, schild, value, value_type);
2137 break;
2138 default:
2139 LOGINT(ctx);
2140 node = NULL;
2141 break;
2142 }
2143
2144 if (!node) {
2145 str = strndup(path, id - path);
2146 if (is_relative) {
2147 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, str, "Failed to create node \"%s\" as a child of \"%s\".",
2148 schild->name, parent->schema->name);
2149 } else {
2150 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, str, "Failed to create node \"%s\".", schild->name);
2151 }
2152 free(str);
2153 lyd_free(ret);
2154 return NULL;
2155 }
2156 /* special case when we are creating a sibling of a top-level data node */
2157 if (!is_relative) {
2158 if (data_tree) {
2159 for (; data_tree->next; data_tree = data_tree->next);
2160 if (lyd_insert_after(data_tree, node)) {
2161 lyd_free(ret);
2162 return NULL;
2163 }
2164 }
2165 is_relative = 1;
2166 }
2167
2168 if (first_iter) {
2169 /* sort if needed, but only when inserted somewhere */
2170 sparent = node->schema;
2171 do {
2172 sparent = lys_parent(sparent);
2173 } while (sparent && (sparent->nodetype != ((options & LYD_PATH_OPT_OUTPUT) ? LYS_OUTPUT : LYS_INPUT)));
2174 if (sparent && lyd_schema_sort(node, 0)) {
2175 lyd_free(ret);
2176 return NULL;
2177 }
2178
2179 /* set first created node */
2180 ret = node;
2181 first_iter = 0;
2182 }
2183
2184 parsed = 0;
2185 if ((schild->nodetype == LYS_LIST) && has_predicate && lyd_new_path_list_predicate(node, name, id, &parsed)) {
2186 lyd_free(ret);
2187 return NULL;
2188 }
2189 id += parsed;
2190
2191 if (!id[0]) {
2192 /* we are done */
2193 if (options & LYD_PATH_OPT_NOPARENTRET) {
2194 /* last created node */
2195 return node;
2196 }
2197 return ret;
2198 }
2199
2200 /* prepare for another iteration */
2201 parent = node;
2202 sparent = schild;
2203 prev_mod = lys_node_module(schild);
2204
2205 /* parse another node */
2206 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2207 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2208 lyd_free(ret);
2209 return NULL;
2210 }
2211 id += r;
2212
2213 /* if a key of a list was supposed to be created, it is created as a part of the list instance creation */
2214 if ((schild->nodetype == LYS_LIST) && !mod_name) {
2215 slist = (const struct lys_node_list *)schild;
2216 for (i = 0; i < slist->keys_size; ++i) {
2217 if (!strncmp(slist->keys[i]->name, name, nam_len) && !slist->keys[i]->name[nam_len]) {
2218 /* the path continues? there cannot be anything after a key (leaf) */
2219 if (id[0]) {
2220 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2221 lyd_free(ret);
2222 return NULL;
2223 }
2224 return ret;
2225 }
2226 }
2227 }
2228 }
2229
2230 LOGINT(ctx);
2231 return NULL;
2232 }
2233
2234 API unsigned int
lyd_list_pos(const struct lyd_node * node)2235 lyd_list_pos(const struct lyd_node *node)
2236 {
2237 FUN_IN;
2238
2239 unsigned int pos;
2240 struct lys_node *schema;
2241
2242 if (!node || ((node->schema->nodetype != LYS_LIST) && (node->schema->nodetype != LYS_LEAFLIST))) {
2243 return 0;
2244 }
2245
2246 schema = node->schema;
2247 pos = 0;
2248 do {
2249 if (node->schema == schema) {
2250 ++pos;
2251 }
2252 node = node->prev;
2253 } while (node->next);
2254
2255 return pos;
2256 }
2257
2258 static struct lyd_node *
lyd_new_dummy(struct lyd_node * root,struct lyd_node * parent,const struct lys_node * schema,const char * value,int dflt)2259 lyd_new_dummy(struct lyd_node *root, struct lyd_node *parent, const struct lys_node *schema, const char *value, int dflt)
2260 {
2261 unsigned int index;
2262 struct ly_set *spath;
2263 const struct lys_node *siter;
2264 struct lyd_node *iter, *dummy = NULL;
2265
2266 assert(schema);
2267 assert(schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF |
2268 LYS_RPC | LYS_ACTION));
2269
2270 spath = ly_set_new();
2271 if (!spath) {
2272 LOGMEM(schema->module->ctx);
2273 return NULL;
2274 }
2275
2276 if (!parent && root) {
2277 /* find data root */
2278 for (; root->parent; root = root->parent); /* vertical move (up) */
2279 for (; root->prev->next; root = root->prev); /* horizontal move (left) */
2280 }
2281
2282 /* build schema path */
2283 for (siter = schema; siter; siter = lys_parent(siter)) {
2284 /* stop if we know some of the parents */
2285 if (parent && parent->schema == siter) {
2286 break;
2287 }
2288
2289 if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF |
2290 LYS_RPC | LYS_ACTION)) {
2291 /* we have a node that can appear in data tree */
2292 ly_set_add(spath, (void*)siter, LY_SET_OPT_USEASLIST);
2293 } /* else skip the rest node types */
2294 }
2295
2296 assert(spath->number > 0);
2297 index = spath->number;
2298 if (!parent && !(spath->set.s[index - 1]->nodetype & LYS_LEAFLIST)) {
2299 /* start by searching for the top-level parent */
2300 LY_TREE_FOR(root, iter) {
2301 if (iter->schema == spath->set.s[index - 1]) {
2302 parent = iter;
2303 index--;
2304 break;
2305 }
2306 }
2307 }
2308
2309 iter = parent;
2310 while (iter && index && !(spath->set.s[index - 1]->nodetype & LYS_LEAFLIST)) {
2311 /* search for closer parent on the path */
2312 LY_TREE_FOR(parent->child, iter) {
2313 if (iter->schema == spath->set.s[index - 1]) {
2314 index--;
2315 parent = iter;
2316 break;
2317 }
2318 }
2319 }
2320 while (index) {
2321 /* create the missing part of the path */
2322 switch (spath->set.s[index - 1]->nodetype) {
2323 case LYS_LEAF:
2324 case LYS_LEAFLIST:
2325 iter = _lyd_new_leaf(parent, spath->set.s[index - 1], value, dflt, 1);
2326 break;
2327 case LYS_CONTAINER:
2328 case LYS_LIST:
2329 iter = _lyd_new(parent, spath->set.s[index - 1], dflt);
2330 break;
2331 case LYS_ANYXML:
2332 case LYS_ANYDATA:
2333 iter = lyd_create_anydata(parent, spath->set.s[index - 1], "", LYD_ANYDATA_CONSTSTRING);
2334 break;
2335 default:
2336 goto error;
2337 }
2338 if (!iter) {
2339 LOGINT(schema->module->ctx);
2340 goto error;
2341 }
2342
2343 /* we say it is valid and it is dummy */
2344 iter->validity = LYD_VAL_INUSE;
2345
2346 if (!dummy) {
2347 dummy = iter;
2348 }
2349
2350 /* continue */
2351 parent = iter;
2352 index--;
2353 }
2354
2355 ly_set_free(spath);
2356
2357 return dummy;
2358
2359 error:
2360 ly_set_free(spath);
2361 lyd_free(dummy);
2362 return NULL;
2363 }
2364
2365 static struct lys_node *
lys_get_schema_inctx(struct lys_node * schema,struct ly_ctx * ctx)2366 lys_get_schema_inctx(struct lys_node *schema, struct ly_ctx *ctx)
2367 {
2368 const struct lys_module *mod, *trg_mod = NULL;
2369 struct lys_node *parent, *first_sibling = NULL, *iter = NULL;
2370 struct ly_set *parents;
2371 unsigned int index;
2372 uint32_t idx;
2373 void **ptr;
2374
2375 if (!ctx || schema->module->ctx == ctx) {
2376 /* we have the same context */
2377 return schema;
2378 }
2379
2380 /* store the parents chain */
2381 parents = ly_set_new();
2382 for (parent = schema; parent; parent = lys_parent(parent)) {
2383 /* note - augments are skipped so we will work only with the implemented modules
2384 * (where the augments are applied) */
2385 if (parent->nodetype != LYS_USES) {
2386 ly_set_add(parents, parent, LY_SET_OPT_USEASLIST);
2387 }
2388 }
2389 assert(parents->number);
2390 index = parents->number - 1;
2391
2392 /* process the parents from the top level */
2393 /* for the top-level node, we have to locate the module first */
2394 parent = parents->set.s[index];
2395 if (parent->nodetype == LYS_EXT) {
2396 ptr = lys_ext_complex_get_substmt(LY_STMT_NODE, (struct lys_ext_instance_complex *)parent, NULL);
2397 if (!ptr) {
2398 ly_set_free(parents);
2399 return NULL;
2400 }
2401 first_sibling = *(struct lys_node **)ptr;
2402 parent = parents->set.s[--index];
2403 }
2404 idx = 0;
2405 while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
2406 trg_mod = lys_node_module(parent);
2407 /* check module name */
2408 if (strcmp(mod->name, trg_mod->name)) {
2409 continue;
2410 }
2411
2412 /* check revision */
2413 if ((!mod->rev_size && !trg_mod->rev_size) ||
2414 (mod->rev_size && trg_mod->rev_size && !strcmp(mod->rev[0].date, trg_mod->rev[0].date))) {
2415 /* we have match */
2416 break;
2417 }
2418 }
2419 /* try data callback */
2420 if (!mod && trg_mod && ctx->data_clb) {
2421 LOGDBG(LY_LDGYANG, "Attempting to load '%s' into context using callback ...", trg_mod->name);
2422 mod = ctx->data_clb(ctx, trg_mod->name, NULL, 0, ctx->data_clb_data);
2423 }
2424 if (!mod) {
2425 ly_set_free(parents);
2426 return NULL;
2427 }
2428 if (!first_sibling) {
2429 first_sibling = mod->data;
2430 }
2431
2432 /* now search in the schema tree for the matching node */
2433 while (1) {
2434 lys_get_sibling(first_sibling, trg_mod->name, 0, parent->name, 0, parent->nodetype,
2435 (const struct lys_node **)&iter);
2436 if (!iter) {
2437 /* not found, iter will be used as NULL result */
2438 break;
2439 }
2440
2441 if (index == 0) {
2442 /* we are done, iter is the result */
2443 break;
2444 } else {
2445 /* we are going to continue, so update variables for the next loop */
2446 first_sibling = iter->child;
2447 parent = parents->set.s[--index];
2448 iter = NULL;
2449 }
2450 }
2451
2452 ly_set_free(parents);
2453 return iter;
2454 }
2455
2456 static struct lys_node *
lyd_get_schema_inctx(const struct lyd_node * node,struct ly_ctx * ctx)2457 lyd_get_schema_inctx(const struct lyd_node *node, struct ly_ctx *ctx)
2458 {
2459 assert(node);
2460
2461 return lys_get_schema_inctx(node->schema, ctx);
2462 }
2463
2464 /* both target and source were validated */
2465 static void
lyd_merge_node_update(struct lyd_node * target,struct lyd_node * source,int options)2466 lyd_merge_node_update(struct lyd_node *target, struct lyd_node *source, int options)
2467 {
2468 struct ly_ctx *ctx;
2469 struct lyd_node_leaf_list *trg_leaf, *src_leaf;
2470 struct lyd_node_anydata *trg_any, *src_any;
2471 int len;
2472
2473 assert(target->schema->nodetype & (LYS_LEAF | LYS_ANYDATA));
2474 ctx = target->schema->module->ctx;
2475
2476 if (source->dflt && (options & LYD_OPT_EXPLICIT)) {
2477 /* keep the target node whatever it is */
2478 return;
2479 }
2480
2481 if (ctx == source->schema->module->ctx) {
2482 /* source and targets are in the same context */
2483 if (target->schema->nodetype == LYS_LEAF) {
2484 trg_leaf = (struct lyd_node_leaf_list *)target;
2485 src_leaf = (struct lyd_node_leaf_list *)source;
2486
2487 lydict_remove(ctx, trg_leaf->value_str);
2488 trg_leaf->value_str = lydict_insert(ctx, src_leaf->value_str, 0);
2489 trg_leaf->value_type = src_leaf->value_type;
2490 if (trg_leaf->value_type == LY_TYPE_LEAFREF) {
2491 lyp_parse_value(&((struct lys_node_leaf *)trg_leaf->schema)->type, &trg_leaf->value_str,
2492 NULL, trg_leaf, NULL, NULL, 1, src_leaf->dflt);
2493 } else {
2494 lyd_free_value(trg_leaf->value, trg_leaf->value_type, trg_leaf->value_flags,
2495 &((struct lys_node_leaf *)trg_leaf->schema)->type, trg_leaf->value_str, NULL, NULL, NULL);
2496 trg_leaf->value = src_leaf->value;
2497 /* so that it is not freed */
2498 src_leaf->value.uint64 = 0;
2499 }
2500 trg_leaf->dflt = src_leaf->dflt;
2501 } else { /* ANYDATA */
2502 trg_any = (struct lyd_node_anydata *)target;
2503 src_any = (struct lyd_node_anydata *)source;
2504
2505 switch(trg_any->value_type) {
2506 case LYD_ANYDATA_CONSTSTRING:
2507 case LYD_ANYDATA_SXML:
2508 case LYD_ANYDATA_JSON:
2509 lydict_remove(ctx, trg_any->value.str);
2510 break;
2511 case LYD_ANYDATA_DATATREE:
2512 lyd_free_withsiblings(trg_any->value.tree);
2513 break;
2514 case LYD_ANYDATA_XML:
2515 lyxml_free_withsiblings(ctx, trg_any->value.xml);
2516 break;
2517 case LYD_ANYDATA_LYB:
2518 free(trg_any->value.mem);
2519 break;
2520 case LYD_ANYDATA_STRING:
2521 case LYD_ANYDATA_SXMLD:
2522 case LYD_ANYDATA_JSOND:
2523 case LYD_ANYDATA_LYBD:
2524 /* dynamic strings are used only as input parameters */
2525 assert(0);
2526 break;
2527 }
2528
2529 trg_any->value_type = src_any->value_type;
2530 trg_any->value = src_any->value;
2531
2532 src_any->value_type = LYD_ANYDATA_DATATREE;
2533 src_any->value.tree = NULL;
2534 }
2535 } else {
2536 /* we have different contexts for the target and source */
2537 if (target->schema->nodetype == LYS_LEAF) {
2538 trg_leaf = (struct lyd_node_leaf_list *)target;
2539 src_leaf = (struct lyd_node_leaf_list *)source;
2540
2541 lydict_remove(ctx, trg_leaf->value_str);
2542 trg_leaf->value_str = lydict_insert(ctx, src_leaf->value_str, 0);
2543 lyd_free_value(trg_leaf->value, trg_leaf->value_type, trg_leaf->value_flags,
2544 &((struct lys_node_leaf *)trg_leaf->schema)->type, trg_leaf->value_str, NULL, NULL, NULL);
2545 trg_leaf->value_type = src_leaf->value_type;
2546 trg_leaf->dflt = src_leaf->dflt;
2547
2548 switch (trg_leaf->value_type) {
2549 case LY_TYPE_BINARY:
2550 case LY_TYPE_STRING:
2551 /* value_str pointer is shared in these cases */
2552 trg_leaf->value.string = trg_leaf->value_str;
2553 break;
2554 case LY_TYPE_LEAFREF:
2555 lyp_parse_value(&((struct lys_node_leaf *)trg_leaf->schema)->type, &trg_leaf->value_str,
2556 NULL, trg_leaf, NULL, NULL, 1, trg_leaf->dflt);
2557 break;
2558 case LY_TYPE_INST:
2559 trg_leaf->value.instance = NULL;
2560 break;
2561 case LY_TYPE_UNION:
2562 /* unresolved union (this must be non-validated tree), duplicate the stored string (duplicated
2563 * because of possible change of the value in case of instance-identifier) */
2564 trg_leaf->value.string = lydict_insert(ctx, src_leaf->value.string, 0);
2565 break;
2566 case LY_TYPE_BITS:
2567 case LY_TYPE_ENUM:
2568 case LY_TYPE_IDENT:
2569 /* in case of duplicating bits (no matter if in the same context or not) or enum and identityref into
2570 * a different context, searching for the type and duplicating the data is almost as same as resolving
2571 * the string value, so due to a simplicity, parse the value for the duplicated leaf */
2572 lyp_parse_value(&((struct lys_node_leaf *)trg_leaf->schema)->type, &trg_leaf->value_str, NULL,
2573 trg_leaf, NULL, NULL, 1, trg_leaf->dflt);
2574 break;
2575 default:
2576 trg_leaf->value = src_leaf->value;
2577 break;
2578 }
2579 } else { /* ANYDATA */
2580 trg_any = (struct lyd_node_anydata *)target;
2581 src_any = (struct lyd_node_anydata *)source;
2582
2583 switch(trg_any->value_type) {
2584 case LYD_ANYDATA_CONSTSTRING:
2585 case LYD_ANYDATA_SXML:
2586 case LYD_ANYDATA_JSON:
2587 lydict_remove(ctx, trg_any->value.str);
2588 break;
2589 case LYD_ANYDATA_DATATREE:
2590 lyd_free_withsiblings(trg_any->value.tree);
2591 break;
2592 case LYD_ANYDATA_XML:
2593 lyxml_free_withsiblings(ctx, trg_any->value.xml);
2594 break;
2595 case LYD_ANYDATA_LYB:
2596 free(trg_any->value.mem);
2597 break;
2598 case LYD_ANYDATA_STRING:
2599 case LYD_ANYDATA_SXMLD:
2600 case LYD_ANYDATA_JSOND:
2601 case LYD_ANYDATA_LYBD:
2602 /* dynamic strings are used only as input parameters */
2603 assert(0);
2604 break;
2605 }
2606
2607 trg_any->value_type = src_any->value_type;
2608 if ((void*)src_any->value.tree) {
2609 /* there is a value to duplicate */
2610 switch (trg_any->value_type) {
2611 case LYD_ANYDATA_CONSTSTRING:
2612 case LYD_ANYDATA_SXML:
2613 case LYD_ANYDATA_JSON:
2614 trg_any->value.str = lydict_insert(ctx, src_any->value.str, 0);
2615 break;
2616 case LYD_ANYDATA_DATATREE:
2617 trg_any->value.tree = lyd_dup_withsiblings_to_ctx(src_any->value.tree, 1, ctx);
2618 break;
2619 case LYD_ANYDATA_XML:
2620 trg_any->value.xml = lyxml_dup_elem(ctx, src_any->value.xml, NULL, 1, 1);
2621 break;
2622 case LYD_ANYDATA_LYB:
2623 len = lyd_lyb_data_length(src_any->value.mem);
2624 if (len == -1) {
2625 LOGERR(ctx, LY_EINVAL, "Invalid LYB data.");
2626 return;
2627 }
2628 trg_any->value.mem = malloc(len);
2629 LY_CHECK_ERR_RETURN(!trg_any->value.mem, LOGMEM(ctx), );
2630 memcpy(trg_any->value.mem, src_any->value.mem, len);
2631 break;
2632 case LYD_ANYDATA_STRING:
2633 case LYD_ANYDATA_SXMLD:
2634 case LYD_ANYDATA_JSOND:
2635 case LYD_ANYDATA_LYBD:
2636 /* dynamic strings are used only as input parameters */
2637 assert(0);
2638 break;
2639 }
2640 }
2641 }
2642 }
2643 }
2644
2645 /* return: 0 (not equal), 1 (equal), -1 (error) */
2646 static int
lyd_merge_node_schema_equal(struct lyd_node * node1,struct lyd_node * node2)2647 lyd_merge_node_schema_equal(struct lyd_node *node1, struct lyd_node *node2)
2648 {
2649 struct lys_node *sch1;
2650
2651 if (node1->schema->module->ctx == node2->schema->module->ctx) {
2652 if (node1->schema != node2->schema) {
2653 return 0;
2654 }
2655 } else {
2656 /* the nodes are in different contexts, get the appropriate schema nodes from the
2657 * same context */
2658 sch1 = lyd_get_schema_inctx(node1, node2->schema->module->ctx);
2659 if (!sch1) {
2660 LOGERR(node2->schema->module->ctx, LY_EINVAL, "Target context does not contain a required schema node (%s:%s).",
2661 lyd_node_module(node1)->name, node1->schema->name);
2662 return -1;
2663 } else if (sch1 != node2->schema) {
2664 /* not matching nodes */
2665 return 0;
2666 }
2667 }
2668
2669 return 1;
2670 }
2671
2672 /* return: 0 (not equal), 1 (equal), 2 (equal and state leaf-/list marked), -1 (error) */
2673 static int
lyd_merge_node_equal(struct lyd_node * node1,struct lyd_node * node2)2674 lyd_merge_node_equal(struct lyd_node *node1, struct lyd_node *node2)
2675 {
2676 int ret;
2677
2678 switch (node1->schema->nodetype) {
2679 case LYS_CONTAINER:
2680 case LYS_LEAF:
2681 case LYS_ANYXML:
2682 case LYS_ANYDATA:
2683 case LYS_RPC:
2684 case LYS_ACTION:
2685 case LYS_NOTIF:
2686 return 1;
2687 case LYS_LEAFLIST:
2688 if (node1->validity & LYD_VAL_INUSE) {
2689 /* this instance was already matched, we want to find another so that the number of the istances matches */
2690 assert(node1->schema->flags & LYS_CONFIG_R);
2691 return 0;
2692 }
2693
2694 ret = lyd_list_equal(node1, node2, 1);
2695 if ((ret == 1) && (node1->schema->flags & LYS_CONFIG_R)) {
2696 /* mark it as matched */
2697 node1->validity |= LYD_VAL_INUSE;
2698 ret = 2;
2699 }
2700 return ret;
2701 case LYS_LIST:
2702 if (node1->validity & LYD_VAL_INUSE) {
2703 /* this instance was already matched, we want to find another so that the number of the istances matches */
2704 assert(!((struct lys_node_list *)node1->schema)->keys_size);
2705 return 0;
2706 }
2707
2708 ret = lyd_list_equal(node1, node2, 1);
2709 if ((ret == 1) && !((struct lys_node_list *)node1->schema)->keys_size) {
2710 /* mark it as matched */
2711 node1->validity |= LYD_VAL_INUSE;
2712 ret = 2;
2713 }
2714 return ret;
2715 default:
2716 break;
2717 }
2718
2719 LOGINT(node2->schema->module->ctx);
2720 return -1;
2721 }
2722
2723 /* spends source */
2724 static int
lyd_merge_parent_children(struct lyd_node * target,struct lyd_node * source,int options)2725 lyd_merge_parent_children(struct lyd_node *target, struct lyd_node *source, int options)
2726 {
2727 struct lyd_node *trg_parent, *src, *src_backup, *src_elem, *src_elem_backup, *src_next, *trg_child, *trg_parent_backup;
2728 int ret, clear_flag = 0;
2729 struct ly_ctx *ctx = target->schema->module->ctx; /* shortcut */
2730
2731 LY_TREE_FOR_SAFE(source, src_backup, src) {
2732 for (src_elem = src_next = src, trg_parent = target;
2733 src_elem;
2734 src_elem = src_next) {
2735
2736 ret = 0;
2737
2738 #ifdef LY_ENABLED_CACHE
2739 struct lyd_node **trg_child_p;
2740
2741 /* trees are supposed to be validated so all nodes must have their hash, but lets not be that strict */
2742 if (!src_elem->hash) {
2743 lyd_hash(src_elem);
2744 }
2745
2746 if (trg_parent->ht) {
2747 trg_child = NULL;
2748 if (!lyht_find(trg_parent->ht, &src_elem, src_elem->hash, (void **)&trg_child_p)) {
2749 trg_child = *trg_child_p;
2750 ret = 1;
2751
2752 /* it is a bit more difficult with keyless state lists and leaf-lists */
2753 if (((trg_child->schema->nodetype == LYS_LIST) && !((struct lys_node_list *)trg_child->schema)->keys_size)
2754 || ((trg_child->schema->nodetype == LYS_LEAFLIST) && (trg_child->schema->flags & LYS_CONFIG_R))) {
2755 assert(trg_child->schema->flags & LYS_CONFIG_R);
2756
2757 while (trg_child && (trg_child->validity & LYD_VAL_INUSE)) {
2758 /* state lists, find one not-already-found */
2759 if (lyht_find_next(trg_parent->ht, &trg_child, trg_child->hash, (void **)&trg_child_p)) {
2760 trg_child = NULL;
2761 } else {
2762 trg_child = *trg_child_p;
2763 }
2764 }
2765 if (trg_child) {
2766 /* mark it as matched */
2767 trg_child->validity |= LYD_VAL_INUSE;
2768 ret = 2;
2769 } else {
2770 /* actually, it was matched already and no other instance found, so now not a match */
2771 ret = 0;
2772 }
2773 }
2774 }
2775 } else
2776 #endif
2777 {
2778 LY_TREE_FOR(trg_parent->child, trg_child) {
2779 /* schema match, data match? */
2780 ret = lyd_merge_node_schema_equal(trg_child, src_elem);
2781 if (ret == 1) {
2782 ret = lyd_merge_node_equal(trg_child, src_elem);
2783 }
2784 if (ret != 0) {
2785 /* even data match */
2786 break;
2787 }
2788 }
2789 }
2790
2791 if (ret > 0) {
2792 if (trg_child->schema->nodetype & (LYS_LEAF | LYS_ANYDATA)) {
2793 lyd_merge_node_update(trg_child, src_elem, options);
2794 } else if (ret == 2) {
2795 clear_flag = 1;
2796 }
2797 } else if (ret == -1) {
2798 /* error */
2799 lyd_free_withsiblings(source);
2800 return 1;
2801 }
2802
2803 /* first prepare for the next iteration */
2804 src_elem_backup = src_elem;
2805 trg_parent_backup = trg_parent;
2806 if (((src_elem->schema->nodetype == LYS_CONTAINER) || ((src_elem->schema->nodetype == LYS_LIST)
2807 && ((struct lys_node_list *)src_elem->schema)->keys_size)) && src_elem->child && trg_child) {
2808 /* go into children */
2809 src_next = src_elem->child;
2810 trg_parent = trg_child;
2811 } else {
2812 /* no children (or the whole subtree will be inserted), try siblings */
2813 if (src_elem == src) {
2814 /* we are done with this subtree */
2815 if (trg_child) {
2816 /* it's an empty container, list without keys, or an already-updated leaf/anydata, nothing else to do */
2817 break;
2818 } else {
2819 /* ... but we still need to insert it */
2820 src_next = NULL;
2821 goto src_insert;
2822 }
2823 } else {
2824 src_next = src_elem->next;
2825 /* trg_parent does not change */
2826 }
2827 }
2828 while (!src_next) {
2829 src_elem = src_elem->parent;
2830 if (src_elem->parent == src->parent) {
2831 /* we are done, no next element to process */
2832 break;
2833 }
2834
2835 /* parent is already processed, go to its sibling */
2836 src_next = src_elem->next;
2837 trg_parent = trg_parent->parent;
2838 }
2839
2840 if (!trg_child) {
2841 src_insert:
2842 /* we need to insert the whole subtree */
2843 if (ctx == src_elem_backup->schema->module->ctx) {
2844 /* same context - unlink the subtree and insert it into the target */
2845 lyd_unlink(src_elem_backup);
2846 } else {
2847 /* different contexts - before inserting subtree, instead of unlinking, duplicate it into the
2848 * target context */
2849 src_elem_backup = lyd_dup_to_ctx(src_elem_backup, 1, ctx);
2850 }
2851
2852 if (src_elem == source) {
2853 /* it will be linked into another data tree and the pointers changed */
2854 source = source->next;
2855 }
2856
2857 /* insert subtree into the target */
2858 if (lyd_insert(trg_parent_backup, src_elem_backup)) {
2859 LOGINT(ctx);
2860 lyd_free_withsiblings(source);
2861 return 1;
2862 }
2863 if (src_elem == src) {
2864 /* we are finished for this src */
2865 break;
2866 }
2867 }
2868 }
2869 }
2870
2871 lyd_free_withsiblings(source);
2872 if (clear_flag) {
2873 return 2;
2874 }
2875 return 0;
2876 }
2877
2878 /* spends source */
2879 static int
lyd_merge_siblings(struct lyd_node * target,struct lyd_node * source,int options)2880 lyd_merge_siblings(struct lyd_node *target, struct lyd_node *source, int options)
2881 {
2882 struct lyd_node *trg, *src, *src_backup, *ins;
2883 int ret, clear_flag = 0;
2884 struct ly_ctx *ctx = target->schema->module->ctx; /* shortcut */
2885
2886 while (target->prev->next) {
2887 target = target->prev;
2888 }
2889
2890 LY_TREE_FOR_SAFE(source, src_backup, src) {
2891 LY_TREE_FOR(target, trg) {
2892 /* sibling found, merge it */
2893 ret = lyd_merge_node_schema_equal(trg, src);
2894 if (ret == 1) {
2895 ret = lyd_merge_node_equal(trg, src);
2896 }
2897 if (ret > 0) {
2898 if (ret == 2) {
2899 clear_flag = 1;
2900 }
2901
2902 switch (trg->schema->nodetype) {
2903 case LYS_LEAF:
2904 case LYS_ANYXML:
2905 case LYS_ANYDATA:
2906 lyd_merge_node_update(trg, src, options);
2907 break;
2908 case LYS_LEAFLIST:
2909 /* it's already there, nothing to do */
2910 break;
2911 case LYS_LIST:
2912 case LYS_CONTAINER:
2913 case LYS_NOTIF:
2914 case LYS_RPC:
2915 case LYS_INPUT:
2916 case LYS_OUTPUT:
2917 ret = lyd_merge_parent_children(trg, src->child, options);
2918 if (ret == 2) {
2919 clear_flag = 1;
2920 } else if (ret) {
2921 lyd_free_withsiblings(source);
2922 return 1;
2923 }
2924 break;
2925 default:
2926 LOGINT(ctx);
2927 lyd_free_withsiblings(source);
2928 return 1;
2929 }
2930 break;
2931 } else if (ret == -1) {
2932 lyd_free_withsiblings(source);
2933 return 1;
2934 } /* else not equal, nothing to do */
2935 }
2936
2937 /* sibling not found, insert it */
2938 if (!trg) {
2939 if (ctx != src->schema->module->ctx) {
2940 ins = lyd_dup_to_ctx(src, 1, ctx);
2941 } else {
2942 lyd_unlink(src);
2943 if (src == source) {
2944 /* just so source is not freed, we inserted it and need it further */
2945 source = src_backup;
2946 }
2947 ins = src;
2948 }
2949 lyd_insert_after(target->prev, ins);
2950 }
2951 }
2952
2953 lyd_free_withsiblings(source);
2954 if (clear_flag) {
2955 return 2;
2956 }
2957 return 0;
2958 }
2959
2960 API int
lyd_merge_to_ctx(struct lyd_node ** trg,const struct lyd_node * src,int options,struct ly_ctx * ctx)2961 lyd_merge_to_ctx(struct lyd_node **trg, const struct lyd_node *src, int options, struct ly_ctx *ctx)
2962 {
2963 FUN_IN;
2964
2965 struct lyd_node *node = NULL, *node2, *target, *trg_merge_start, *src_merge_start = NULL;
2966 const struct lyd_node *iter;
2967 struct lys_node *src_snode, *sch = NULL;
2968 int i, src_depth, depth, first_iter, ret, dflt = 1;
2969 const struct lys_node *parent = NULL;
2970
2971 if (!trg || !(*trg) || !src) {
2972 LOGARG;
2973 return -1;
2974 }
2975 target = *trg;
2976
2977 parent = lys_parent(target->schema);
2978
2979 /* go up all uses */
2980 while (parent && (parent->nodetype == LYS_USES)) {
2981 parent = lys_parent(parent);
2982 }
2983
2984 if (parent && !lyp_get_yang_data_template_name(target)) {
2985 LOGERR(parent->module->ctx, LY_EINVAL, "Target not a top-level data tree.");
2986 return -1;
2987 }
2988
2989 /* get know if we are converting data into a different context */
2990 if (ctx && target->schema->module->ctx != ctx) {
2991 /* target's data tree context differs from the target context, move the target
2992 * data tree into the target context */
2993
2994 /* get the first target's top-level and store it as the result */
2995 for (; target->prev->next; target = target->prev);
2996 *trg = target;
2997
2998 for (node = NULL, trg_merge_start = target; target; target = target->next) {
2999 node2 = lyd_dup_to_ctx(target, 1, ctx);
3000 if (!node2) {
3001 goto error;
3002 }
3003 if (node) {
3004 if (lyd_insert_after(node->prev, node2)) {
3005 goto error;
3006 }
3007 } else {
3008 node = node2;
3009 }
3010 }
3011 target = node;
3012 node = NULL;
3013 } else if (src->schema->module->ctx != target->schema->module->ctx) {
3014 /* the source data will be converted into the target's context during the merge */
3015 ctx = target->schema->module->ctx;
3016 } else if (ctx == src->schema->module->ctx) {
3017 /* no conversion is needed */
3018 ctx = NULL;
3019 }
3020
3021 /* find source top-level schema node */
3022 for (src_snode = src->schema, src_depth = 0;
3023 (src_snode = lys_parent(src_snode)) && src_snode->nodetype != LYS_EXT;
3024 ++src_depth);
3025
3026 /* find first shared missing schema parent of the subtrees */
3027 trg_merge_start = target;
3028 depth = 0;
3029 first_iter = 1;
3030 if (src_depth) {
3031 /* we are going to create missing parents in the following loop,
3032 * but we will need to know a dflt flag for them. In case the newly
3033 * created parent is going to have at least one non-default child,
3034 * it will be also non-default, otherwise it will be the default node */
3035 if (options & LYD_OPT_NOSIBLINGS) {
3036 dflt = src->dflt;
3037 } else {
3038 LY_TREE_FOR(src, iter) {
3039 if (!iter->dflt) {
3040 /* non default sibling -> parent is going to be
3041 * created also as non-default */
3042 dflt = 0;
3043 break;
3044 }
3045 }
3046 }
3047 }
3048 while (1) {
3049 /* going from down (source root) to up (top-level or the common node with target */
3050 do {
3051 for (src_snode = src->schema, i = 0; i < src_depth - depth; src_snode = lys_parent(src_snode), ++i);
3052 ++depth;
3053 } while (src_snode != src->schema && (src_snode->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)));
3054
3055 if (src_snode == src->schema) {
3056 break;
3057 }
3058
3059 if (src_snode->nodetype != LYS_CONTAINER) {
3060 /* we would have to create a list (the only data node with children except container), impossible */
3061 LOGERR(ctx, LY_EINVAL, "Cannot create %s \"%s\" for the merge.", strnodetype(src_snode->nodetype), src_snode->name);
3062 goto error;
3063 }
3064
3065 /* have we created any missing containers already? if we did,
3066 * it is totally useless to search for match, there won't ever be */
3067 if (!src_merge_start) {
3068 if (first_iter) {
3069 node = trg_merge_start;
3070 first_iter = 0;
3071 } else {
3072 node = trg_merge_start->child;
3073 }
3074
3075 /* find it in target data nodes */
3076 LY_TREE_FOR(node, node) {
3077 if (ctx) {
3078 /* we have the schema nodes in the different context */
3079 sch = lys_get_schema_inctx(src_snode, ctx);
3080 if (!sch) {
3081 LOGERR(ctx, LY_EINVAL, "Target context does not contain schema node for the data node being "
3082 "merged (%s:%s).", lys_node_module(src_snode)->name, src_snode->name);
3083 goto error;
3084 }
3085 } else {
3086 /* the context is same and comparison of the schema nodes will works fine */
3087 sch = src_snode;
3088 }
3089
3090 if (node->schema == sch) {
3091 trg_merge_start = node;
3092 break;
3093 }
3094 }
3095
3096 if (!(options & LYD_OPT_DESTRUCT)) {
3097 /* the source tree will be duplicated, so to save some work in case
3098 * of different target context, create also the parents nodes in the
3099 * correct context */
3100 src_snode = sch;
3101 }
3102 } else if (ctx && !(options & LYD_OPT_DESTRUCT)) {
3103 /* get the schema node in the correct (target) context, same as above,
3104 * this is done to save some work and have the source in the same context
3105 * when the provided source tree is below duplicated in the target context
3106 * and connected into the parents created here */
3107 src_snode = lys_get_schema_inctx(src_snode, ctx);
3108 if (!src_snode) {
3109 LOGERR(ctx, LY_EINVAL, "Target context does not contain schema node for the data node being "
3110 "merged (%s:%s).", lys_node_module(src_snode)->name, src_snode->name);
3111 goto error;
3112 }
3113 }
3114
3115 if (!node) {
3116 /* it is not there, create it */
3117 node2 = _lyd_new(NULL, src_snode, dflt);
3118 if (!src_merge_start) {
3119 src_merge_start = node2;
3120 } else {
3121 if (lyd_insert(node2, src_merge_start)) {
3122 goto error;
3123 }
3124 src_merge_start = node2;
3125 }
3126 }
3127 }
3128
3129 /* process source according to options */
3130 if (options & LYD_OPT_DESTRUCT) {
3131 node = (struct lyd_node *)src;
3132 if ((node->prev != node) && (options & LYD_OPT_NOSIBLINGS)) {
3133 node2 = node->prev;
3134 lyd_unlink(node);
3135 lyd_free_withsiblings(node2);
3136 }
3137 } else {
3138 node = NULL;
3139 for (; src; src = src->next) {
3140 /* because we already have to duplicate it, do it in the correct context */
3141 node2 = lyd_dup_to_ctx(src, 1, ctx);
3142 if (!node2) {
3143 lyd_free_withsiblings(node);
3144 goto error;
3145 }
3146 if (node) {
3147 if (lyd_insert_after(node->prev, node2)) {
3148 lyd_free_withsiblings(node);
3149 goto error;
3150 }
3151 } else {
3152 node = node2;
3153 }
3154
3155 if (options & LYD_OPT_NOSIBLINGS) {
3156 break;
3157 }
3158 }
3159 }
3160
3161 if (src_merge_start) {
3162 /* insert data into the created parents */
3163 /* first, get the lowest created parent, we don't have to check the nodetype since we are
3164 * creating only a simple chain of containers */
3165 for (node2 = src_merge_start; node2->child; node2 = node2->child);
3166 node2->child = node;
3167 LY_TREE_FOR(node, node) {
3168 node->parent = node2;
3169 }
3170 } else {
3171 src_merge_start = node;
3172 }
3173
3174 if (!first_iter) {
3175 /* !! src_merge start is a child(ren) of trg_merge_start */
3176 ret = lyd_merge_parent_children(trg_merge_start, src_merge_start, options);
3177 } else {
3178 /* !! src_merge start is a (top-level) sibling(s) of trg_merge_start */
3179 ret = lyd_merge_siblings(trg_merge_start, src_merge_start, options);
3180 }
3181 /* it was freed whatever the return value */
3182 src_merge_start = NULL;
3183 if (ret == 2) {
3184 /* clear remporary LYD_VAL_INUSE validation flags */
3185 LY_TREE_DFS_BEGIN(target, node2, node) {
3186 node->validity &= ~LYD_VAL_INUSE;
3187 LY_TREE_DFS_END(target, node2, node);
3188 }
3189 ret = 0;
3190 } else if (ret) {
3191 goto error;
3192 }
3193
3194 if (target->schema->nodetype == LYS_RPC) {
3195 lyd_schema_sort(target, 1);
3196 }
3197
3198 /* update the pointer to the target tree if needed */
3199 if (*trg != target) {
3200 lyd_free_withsiblings(*trg);
3201 (*trg) = target;
3202 }
3203 return ret;
3204
3205 error:
3206 if (*trg != target) {
3207 /* target is duplication of the original target in different context,
3208 * free it due to the error */
3209 lyd_free_withsiblings(target);
3210 }
3211 lyd_free_withsiblings(src_merge_start);
3212 return -1;
3213 }
3214
3215 API int
lyd_merge(struct lyd_node * target,const struct lyd_node * source,int options)3216 lyd_merge(struct lyd_node *target, const struct lyd_node *source, int options)
3217 {
3218 FUN_IN;
3219
3220 if (!target || !source) {
3221 LOGARG;
3222 return -1;
3223 }
3224
3225 return lyd_merge_to_ctx(&target, source, options, target->schema->module->ctx);
3226 }
3227
3228 API void
lyd_free_diff(struct lyd_difflist * diff)3229 lyd_free_diff(struct lyd_difflist *diff)
3230 {
3231 FUN_IN;
3232
3233 if (diff) {
3234 free(diff->type);
3235 free(diff->first);
3236 free(diff->second);
3237 free(diff);
3238 }
3239 }
3240
3241 static int
lyd_difflist_add(struct lyd_difflist * diff,unsigned int * size,unsigned int index,LYD_DIFFTYPE type,struct lyd_node * first,struct lyd_node * second)3242 lyd_difflist_add(struct lyd_difflist *diff, unsigned int *size, unsigned int index,
3243 LYD_DIFFTYPE type, struct lyd_node *first, struct lyd_node *second)
3244 {
3245 void *new;
3246 struct ly_ctx *ctx;
3247
3248 assert(diff);
3249 assert(size && *size);
3250 assert(first || second);
3251
3252 ctx = (first ? first->schema->module->ctx : (second ? second->schema->module->ctx : NULL));
3253
3254 if (index + 1 == *size) {
3255 /* it's time to enlarge */
3256 *size = *size + 16;
3257 new = realloc(diff->type, *size * sizeof *diff->type);
3258 LY_CHECK_ERR_RETURN(!new, LOGMEM(ctx), EXIT_FAILURE);
3259 diff->type = new;
3260
3261 new = realloc(diff->first, *size * sizeof *diff->first);
3262 LY_CHECK_ERR_RETURN(!new, LOGMEM(ctx), EXIT_FAILURE);
3263 diff->first = new;
3264
3265 new = realloc(diff->second, *size * sizeof *diff->second);
3266 LY_CHECK_ERR_RETURN(!new, LOGMEM(ctx), EXIT_FAILURE);
3267 diff->second = new;
3268 }
3269
3270 /* insert the item */
3271 diff->type[index] = type;
3272 diff->first[index] = first;
3273 diff->second[index] = second;
3274
3275 /* terminate the arrays */
3276 index++;
3277 diff->type[index] = LYD_DIFF_END;
3278 diff->first[index] = NULL;
3279 diff->second[index] = NULL;
3280
3281 return EXIT_SUCCESS;
3282 }
3283
3284 struct diff_ordered_dist {
3285 struct diff_ordered_dist *next;
3286 int dist;
3287 };
3288 struct diff_ordered_item {
3289 struct lyd_node *first;
3290 struct lyd_node *second;
3291 struct diff_ordered_dist *dist;
3292 };
3293 struct diff_ordered {
3294 struct lys_node *schema;
3295 struct lyd_node *parent;
3296 unsigned int count;
3297 struct diff_ordered_item *items; /* array */
3298 struct diff_ordered_dist *dist; /* linked list (1-way, ring) */
3299 struct diff_ordered_dist *dist_last; /* aux pointer for faster insertion sort */
3300 };
3301
3302 static int
diff_ordset_insert(struct lyd_node * node,struct ly_set * ordset)3303 diff_ordset_insert(struct lyd_node *node, struct ly_set *ordset)
3304 {
3305 unsigned int i;
3306 struct diff_ordered *new_ordered, *iter;
3307
3308 for (i = 0; i < ordset->number; i++) {
3309 iter = (struct diff_ordered *)ordset->set.g[i];
3310 if (iter->schema == node->schema && iter->parent == node->parent) {
3311 break;
3312 }
3313 }
3314 if (i == ordset->number) {
3315 /* not seen user-ordered list */
3316 new_ordered = calloc(1, sizeof *new_ordered);
3317 LY_CHECK_ERR_RETURN(!new_ordered, LOGMEM(node->schema->module->ctx), EXIT_FAILURE);
3318 new_ordered->schema = node->schema;
3319 new_ordered->parent = node->parent;
3320
3321 ly_set_add(ordset, new_ordered, LY_SET_OPT_USEASLIST);
3322 }
3323 ((struct diff_ordered *)ordset->set.g[i])->count++;
3324
3325 return EXIT_SUCCESS;
3326 }
3327
3328 static void
diff_ordset_free(struct ly_set * set)3329 diff_ordset_free(struct ly_set *set)
3330 {
3331 unsigned int i, j;
3332 struct diff_ordered *ord;
3333
3334 if (!set) {
3335 return;
3336 }
3337
3338 for (i = 0; i < set->number; i++) {
3339 ord = (struct diff_ordered *)set->set.g[i];
3340 for (j = 0; j < ord->count; j++) {
3341 free(ord->items[j].dist);
3342 }
3343 free(ord->items);
3344 free(ord);
3345 }
3346
3347 ly_set_free(set);
3348 }
3349
3350 /*
3351 * -1 - error
3352 * 0 - ok
3353 * 1 - first and second not the same
3354 */
3355 static int
lyd_diff_compare(struct lyd_node * first,struct lyd_node * second,int options)3356 lyd_diff_compare(struct lyd_node *first, struct lyd_node *second, int options)
3357 {
3358 int rc;
3359
3360 if (first->dflt && !(options & LYD_DIFFOPT_WITHDEFAULTS)) {
3361 /* the second one cannot be default (see lyd_diff()),
3362 * so the nodes differs (first one is default node) */
3363 return 1;
3364 }
3365
3366 if (first->schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) {
3367 if (first->validity & LYD_VAL_INUSE) {
3368 /* this node was already matched, it cannot be matched twice (except for state leaf-/lists,
3369 * which we want to keep the count on this way) */
3370 return 1;
3371 }
3372
3373 rc = lyd_list_equal(first, second, (options & LYD_DIFFOPT_WITHDEFAULTS ? 1 : 0));
3374 if (rc == -1) {
3375 return -1;
3376 } else if (!rc) {
3377 /* list instances differs */
3378 return 1;
3379 }
3380 /* matches */
3381 }
3382
3383 return 0;
3384 }
3385
3386 /*
3387 * -1 - error
3388 * 0 - ok
3389 */
3390 static int
lyd_diff_match(struct lyd_node * first,struct lyd_node * second,struct lyd_difflist * diff,unsigned int * size,unsigned int * i,struct ly_set * matchset,struct ly_set * ordset,int options)3391 lyd_diff_match(struct lyd_node *first, struct lyd_node *second, struct lyd_difflist *diff, unsigned int *size,
3392 unsigned int *i, struct ly_set *matchset, struct ly_set *ordset, int options)
3393 {
3394 switch (first->schema->nodetype) {
3395 case LYS_LEAFLIST:
3396 case LYS_LIST:
3397 /* additional work for future move matching in case of user ordered lists */
3398 if (first->schema->flags & LYS_USERORDERED) {
3399 diff_ordset_insert(first, ordset);
3400 }
3401
3402 /* falls through */
3403 case LYS_CONTAINER:
3404 case LYS_RPC:
3405 case LYS_ACTION:
3406 case LYS_NOTIF:
3407 assert(!(second->validity & LYD_VAL_INUSE));
3408 second->validity |= LYD_VAL_INUSE;
3409 /* remember the matching node in first for keeping correct pointer in first
3410 * for comparing when passing through the second tree in lyd_diff().
3411 * Duplicities are not allowed actually, but they cannot happen since single
3412 * node can match only one node in the other tree */
3413 ly_set_add(matchset, first, LY_SET_OPT_USEASLIST);
3414 break;
3415 case LYS_LEAF:
3416 /* check for leaf's modification */
3417 if (!lyd_leaf_val_equal(first, second, 0) || ((options & LYD_DIFFOPT_WITHDEFAULTS) && (first->dflt != second->dflt))) {
3418 if (lyd_difflist_add(diff, size, (*i)++, LYD_DIFF_CHANGED, first, second)) {
3419 return -1;
3420 }
3421 }
3422 break;
3423 case LYS_ANYXML:
3424 case LYS_ANYDATA:
3425 /* check for anydata/anyxml's modification */
3426 if (!lyd_anydata_equal(first, second) && lyd_difflist_add(diff, size, (*i)++, LYD_DIFF_CHANGED, first, second)) {
3427 return -1;
3428 }
3429 break;
3430 default:
3431 LOGINT(first->schema->module->ctx);
3432 return -1;
3433 }
3434
3435 /* mark both that they have matching instance in the other tree */
3436 assert(!(first->validity & LYD_VAL_INUSE));
3437 first->validity |= LYD_VAL_INUSE;
3438
3439 return 0;
3440 }
3441
3442 /* @brief compare if the nodes are equivalent including checking the list's keys
3443 * Go through the nodes and their parents and in the case of list, compare its keys.
3444 *
3445 * @return 0 different, 1 equivalent
3446 */
3447 static int
lyd_diff_equivnode(struct lyd_node * first,struct lyd_node * second)3448 lyd_diff_equivnode(struct lyd_node *first, struct lyd_node *second)
3449 {
3450 struct lyd_node *iter1, *iter2;
3451
3452 for (iter1 = first, iter2 = second; iter1 && iter2; iter1 = iter1->parent, iter2 = iter2->parent) {
3453 if (iter1->schema->module->ctx == iter2->schema->module->ctx) {
3454 if (iter1->schema != iter2->schema) {
3455 return 0;
3456 }
3457 } else {
3458 if (!ly_strequal(iter1->schema->name, iter2->schema->name, 0)) {
3459 /* comparing the names is fine, even if they are, in fact, 2 different nodes
3460 * with equal names, some of their parents will differ */
3461 return 0;
3462 }
3463 }
3464 if (iter1->schema->nodetype == LYS_LIST) {
3465 /* compare keys */
3466 if (lyd_list_equal(iter1, iter2, 0) != 1) {
3467 return 0;
3468 }
3469 }
3470 }
3471
3472 if (iter1 != iter2) {
3473 /* we are supposed to be in root (NULL) in both trees */
3474 return 0;
3475 }
3476
3477 return 1;
3478 }
3479
3480 static int
lyd_diff_move_preprocess(struct diff_ordered * ordered,struct lyd_node * first,struct lyd_node * second)3481 lyd_diff_move_preprocess(struct diff_ordered *ordered, struct lyd_node *first, struct lyd_node *second)
3482 {
3483 struct ly_ctx *ctx = first->schema->module->ctx;
3484 struct lyd_node *iter;
3485 unsigned int pos = 0;
3486 int abs_dist;
3487 struct diff_ordered_dist *dist_aux;
3488 struct diff_ordered_dist *dist_iter, *dist_last;
3489 char *str = NULL;
3490
3491 /* ordered->count was zeroed and now it is incremented with each added
3492 * item's information, so it is actually position of the second node
3493 */
3494
3495 /* get the position of the first node */
3496 for (iter = first->prev; iter->next; iter = iter->prev) {
3497 if (!(iter->validity & LYD_VAL_INUSE)) {
3498 /* skip deleted nodes */
3499 continue;
3500 }
3501 if (iter->schema == first->schema) {
3502 pos++;
3503 }
3504 }
3505 if (pos != ordered->count) {
3506 LOGDBG(LY_LDGDIFF, "detected moved element \"%s\" from %d to %d (distance %d)",
3507 str = lyd_path(first), pos, ordered->count, ordered->count - pos);
3508 free(str);
3509 }
3510
3511 /* store information, count distance */
3512 ordered->items[pos].dist = dist_aux = calloc(1, sizeof *dist_aux);
3513 LY_CHECK_ERR_RETURN(!dist_aux, LOGMEM(ctx), EXIT_FAILURE);
3514 ordered->items[pos].dist->dist = ordered->count - pos;
3515 abs_dist = abs(ordered->items[pos].dist->dist);
3516 ordered->items[pos].first = first;
3517 ordered->items[pos].second = second;
3518 ordered->count++;
3519
3520 /* insert sort of distances, higher first */
3521 for (dist_iter = ordered->dist, dist_last = NULL;
3522 dist_iter;
3523 dist_last = dist_iter, dist_iter = dist_iter->next) {
3524 if (abs_dist >= abs(dist_iter->dist)) {
3525 /* found correct place */
3526 dist_aux->next = dist_iter;
3527 if (dist_last) {
3528 dist_last->next = dist_aux;
3529 }
3530 break;
3531 } else if (dist_iter->next == ordered->dist) {
3532 /* last item */
3533 dist_aux->next = ordered->dist; /* ring list */
3534 ordered->dist_last = dist_aux;
3535 dist_iter->next = dist_aux;
3536 break;
3537 }
3538 }
3539 if (dist_aux->next == ordered->dist) {
3540 if (ordered->dist_last == dist_aux) {
3541 /* last item */
3542 if (!ordered->dist) {
3543 /* the only item */
3544 dist_aux->next = dist_aux;
3545 ordered->dist = ordered->dist_last = dist_aux;
3546 }
3547 } else {
3548 /* first item */
3549 ordered->dist = dist_aux;
3550 if (dist_aux->next) {
3551 /* more than one item, update the last one's next */
3552 ordered->dist_last->next = dist_aux;
3553 } else {
3554 /* the only item */
3555 ordered->dist_last = dist_aux;
3556 dist_aux->next = dist_aux; /* ring list */
3557 }
3558 }
3559 }
3560
3561 return 0;
3562 }
3563
3564 static struct lyd_difflist *
lyd_diff_init_difflist(struct ly_ctx * ctx,unsigned int * size)3565 lyd_diff_init_difflist(struct ly_ctx *ctx, unsigned int *size)
3566 {
3567 struct lyd_difflist *result;
3568
3569 result = malloc(sizeof *result);
3570 LY_CHECK_ERR_RETURN(!result, LOGMEM(ctx); *size = 0, NULL);
3571
3572 *size = 1;
3573 result->type = calloc(*size, sizeof *result->type);
3574 result->first = calloc(*size, sizeof *result->first);
3575 result->second = calloc(*size, sizeof *result->second);
3576 if (!result->type || !result->first || !result->second) {
3577 LOGMEM(ctx);
3578 free(result->second);
3579 free(result->first);
3580 free(result->type);
3581 free(result);
3582 *size = 0;
3583 return NULL;
3584 }
3585
3586 return result;
3587 }
3588
3589 API struct lyd_difflist *
lyd_diff(struct lyd_node * first,struct lyd_node * second,int options)3590 lyd_diff(struct lyd_node *first, struct lyd_node *second, int options)
3591 {
3592 FUN_IN;
3593
3594 struct ly_ctx *ctx;
3595 int rc;
3596 struct lyd_node *elem1, *elem2, *iter, *aux, *parent = NULL, *next1, *next2;
3597 struct lyd_difflist *result, *result2 = NULL;
3598 void *new;
3599 unsigned int size, size2, index = 0, index2 = 0, i, j, k;
3600 struct matchlist_s {
3601 struct matchlist_s *prev;
3602 struct ly_set *match;
3603 unsigned int i;
3604 } *matchlist = NULL, *mlaux;
3605 struct ly_set *ordset = NULL;
3606 struct diff_ordered *ordered;
3607 struct diff_ordered_dist *dist_aux, *dist_iter;
3608 struct diff_ordered_item item_aux;
3609
3610 if (!first) {
3611 /* all nodes in second were created,
3612 * but the second must be top level */
3613 if (second && second->parent) {
3614 LOGERR(second->schema->module->ctx, LY_EINVAL, "%s: \"first\" parameter is NULL and \"second\" is not top level.", __func__);
3615 return NULL;
3616 }
3617 result = lyd_diff_init_difflist(NULL, &size);
3618 LY_TREE_FOR(second, iter) {
3619 if (!iter->dflt || (options & LYD_DIFFOPT_WITHDEFAULTS)) { /* skip the implicit nodes */
3620 if (lyd_difflist_add(result, &size, index++, LYD_DIFF_CREATED, NULL, iter)) {
3621 goto error;
3622 }
3623 }
3624 if (options & LYD_DIFFOPT_NOSIBLINGS) {
3625 break;
3626 }
3627 }
3628 return result;
3629 } else if (!second) {
3630 /* all nodes from first were deleted */
3631 result = lyd_diff_init_difflist(first->schema->module->ctx, &size);
3632 LY_TREE_FOR(first, iter) {
3633 if (!iter->dflt || (options & LYD_DIFFOPT_WITHDEFAULTS)) { /* skip the implicit nodes */
3634 if (lyd_difflist_add(result, &size, index++, LYD_DIFF_DELETED, iter, NULL)) {
3635 goto error;
3636 }
3637 }
3638 if (options & LYD_DIFFOPT_NOSIBLINGS) {
3639 break;
3640 }
3641 }
3642 return result;
3643 }
3644
3645 ctx = first->schema->module->ctx;
3646
3647 if (options & LYD_DIFFOPT_NOSIBLINGS) {
3648 /* both trees must start at the same (schema) node */
3649 if (first->schema != second->schema) {
3650 LOGERR(ctx, LY_EINVAL, "%s: incompatible trees to compare with LYD_OPT_NOSIBLINGS option.", __func__);
3651 return NULL;
3652 }
3653 /* use first's and second's child to make comparison the same as without LYD_OPT_NOSIBLINGS */
3654 first = first->child;
3655 second = second->child;
3656 } else {
3657 /* go to the first sibling in both trees */
3658 if (first->parent) {
3659 first = first->parent->child;
3660 } else {
3661 while (first->prev->next) {
3662 first = first->prev;
3663 }
3664 }
3665
3666 if (second->parent) {
3667 second = second->parent->child;
3668 } else {
3669 for (; second->prev->next; second = second->prev);
3670 }
3671
3672 /* check that both has the same (schema) parent or that they are top-level nodes */
3673 if ((first->parent && second->parent && first->parent->schema != second->parent->schema) ||
3674 (!first->parent && first->parent != second->parent)) {
3675 LOGERR(ctx, LY_EINVAL, "%s: incompatible trees with different parents.", __func__);
3676 return NULL;
3677 }
3678 }
3679 if (first == second) {
3680 LOGERR(ctx, LY_EINVAL, "%s: comparing the same tree does not make sense.", __func__);
3681 return NULL;
3682 }
3683
3684 /* initiate resulting structure */
3685 result = lyd_diff_init_difflist(ctx, &size);
3686 LY_CHECK_ERR_GOTO(!result, , error);
3687
3688 /* the records about created and moved items are created in
3689 * bad order, so the records about created nodes (and their
3690 * possible moving) is stored separately and added to the
3691 * main result at the end.
3692 */
3693 result2 = lyd_diff_init_difflist(ctx, &size2);
3694 LY_CHECK_ERR_GOTO(!result2, , error);
3695
3696 matchlist = malloc(sizeof *matchlist);
3697 LY_CHECK_ERR_GOTO(!matchlist, LOGMEM(ctx), error);
3698
3699 matchlist->i = 0;
3700 matchlist->match = ly_set_new();
3701 matchlist->prev = NULL;
3702
3703 ordset = ly_set_new();
3704 LY_CHECK_ERR_GOTO(!ordset, , error);
3705
3706 /*
3707 * compare trees
3708 */
3709 /* 1) newly created nodes + changed leafs/anyxmls */
3710 next1 = first;
3711 for (elem2 = next2 = second; elem2; elem2 = next2) {
3712 /* keep right pointer for searching in the first tree */
3713 elem1 = next1;
3714
3715 if (elem2->dflt && !(options & LYD_DIFFOPT_WITHDEFAULTS)) {
3716 /* skip default elements, they could not be created or changed, just deleted */
3717 goto cmp_continue;
3718 }
3719
3720 #ifdef LY_ENABLED_CACHE
3721 struct lyd_node **iter_p;
3722
3723 if (elem1 && elem1->parent && elem1->parent->ht) {
3724 iter = NULL;
3725 if (!lyht_find(elem1->parent->ht, &elem2, elem2->hash, (void **)&iter_p)) {
3726 iter = *iter_p;
3727 /* we found a match */
3728 if (iter->dflt && !(options & LYD_DIFFOPT_WITHDEFAULTS)) {
3729 /* the second one cannot be default (see lyd_diff()),
3730 * so the nodes differs (first one is default node) */
3731 iter = NULL;
3732 }
3733 while (iter && (iter->validity & LYD_VAL_INUSE)) {
3734 /* state lists, find one not-already-found */
3735 assert((iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (iter->schema->flags & LYS_CONFIG_R));
3736 if (lyht_find_next(elem1->parent->ht, &iter, iter->hash, (void **)&iter_p)) {
3737 iter = NULL;
3738 } else {
3739 iter = *iter_p;
3740 }
3741 }
3742 }
3743 } else
3744 #endif
3745 {
3746 /* search for elem2 instance in the first */
3747 LY_TREE_FOR(elem1, iter) {
3748 if (iter->schema != elem2->schema) {
3749 continue;
3750 }
3751
3752 /* elem2 instance found */
3753 rc = lyd_diff_compare(iter, elem2, options);
3754 if (rc == -1) {
3755 goto error;
3756 } else if (rc == 0) {
3757 /* match */
3758 break;
3759 } /* else, continue */
3760 }
3761 }
3762 /* we have a match */
3763 if (iter && lyd_diff_match(iter, elem2, result, &size, &index, matchlist->match, ordset, options)) {
3764 goto error;
3765 }
3766
3767 if (!iter) {
3768 /* elem2 not found in the first tree */
3769 if (lyd_difflist_add(result2, &size2, index2++, LYD_DIFF_CREATED, elem1 ? elem1->parent : parent, elem2)) {
3770 goto error;
3771 }
3772
3773 if (elem1 && (elem2->schema->flags & LYS_USERORDERED)) {
3774 /* store the correct place where the node is supposed to be moved after creation */
3775 /* if elem1 does not exist, all nodes were created and they will be created in
3776 * correct order, so it is not needed to detect moves */
3777 for (aux = elem2->prev; aux->next; aux = aux->prev) {
3778 if (aux->schema == elem2->schema) {
3779 /* predecessor found */
3780 break;
3781 }
3782 }
3783 if (!aux->next) {
3784 /* predecessor not found */
3785 aux = NULL;
3786 }
3787 if (lyd_difflist_add(result2, &size2, index2++, LYD_DIFF_MOVEDAFTER2, aux, elem2)) {
3788 goto error;
3789 }
3790 }
3791 }
3792
3793 cmp_continue:
3794 /* select element for the next run 1 2
3795 * - first, process all siblings of a single parent / \ / \
3796 * - then, go to children (deep) 3 4 7 8
3797 * - return to the parent's next sibling children / \
3798 * 5 6
3799 */
3800 /* siblings first */
3801 next1 = elem1;
3802 next2 = elem2->next;
3803
3804 if (!next2) {
3805 /* children */
3806
3807 /* first pass of the siblings done, some additional work for future
3808 * detection of move may be needed */
3809 for (i = ordset->number; i > 0; i--) {
3810 ordered = (struct diff_ordered *)ordset->set.g[i - 1];
3811 if (ordered->items) {
3812 /* already preprocessed ordered structure */
3813 break;
3814 }
3815 ordered->items = calloc(ordered->count, sizeof *ordered->items);
3816 LY_CHECK_ERR_GOTO(!ordered->items, LOGMEM(ctx), error);
3817 ordered->dist = NULL;
3818 /* zero the count to be used as a node position in lyd_diff_move_preprocess() */
3819 ordered->count = 0;
3820 }
3821
3822 /* first, get the first sibling */
3823 if (elem2->parent == second->parent) {
3824 elem2 = second;
3825 } else {
3826 elem2 = elem2->parent->child;
3827 }
3828
3829 /* and then find the first child */
3830 LY_TREE_FOR(elem2, iter) {
3831 if (!(iter->validity & LYD_VAL_INUSE)) {
3832 /* the iter is not present in both trees */
3833 continue;
3834 } else if (matchlist->i == matchlist->match->number) {
3835 if (iter == elem2) {
3836 /* we already went through all the matching nodes and now we are just supposed to stop
3837 * the loop with no iter */
3838 iter = NULL;
3839 break;
3840 } else {
3841 /* we have started with some not processed data in matchlist, but now we have
3842 * the INUSE iter and no nodes in matchlist to find its equivalent,
3843 * so something went wrong somewhere */
3844 LOGINT(ctx);
3845 goto error;
3846 }
3847 }
3848
3849 iter->validity &= ~LYD_VAL_INUSE;
3850 if ((iter->schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && (iter->schema->flags & LYS_USERORDERED)) {
3851 for (j = ordset->number; j > 0; j--) {
3852 ordered = (struct diff_ordered *)ordset->set.g[j - 1];
3853 if (ordered->schema != iter->schema || !lyd_diff_equivnode(ordered->parent, iter->parent)) {
3854 continue;
3855 }
3856
3857 /* store necessary information for move detection */
3858 lyd_diff_move_preprocess(ordered, matchlist->match->set.d[matchlist->i], iter);
3859 break;
3860 }
3861 }
3862
3863 if (((iter->schema->nodetype == LYS_CONTAINER) || ((iter->schema->nodetype == LYS_LIST)
3864 && ((struct lys_node_list *)iter->schema)->keys_size)) && iter->child) {
3865 while (matchlist->i < matchlist->match->number && matchlist->match->set.d[matchlist->i]->schema != iter->schema) {
3866 matchlist->i++;
3867 }
3868 if (matchlist->i == matchlist->match->number) {
3869 /* we have the INUSE iter, so we have to find its equivalent in match list */
3870 LOGINT(ctx);
3871 goto error;
3872 }
3873 next1 = matchlist->match->set.d[matchlist->i]->child;
3874 if (!next1) {
3875 parent = matchlist->match->set.d[matchlist->i];
3876 }
3877 matchlist->i++;
3878 next2 = iter->child;
3879 break;
3880 }
3881 matchlist->i++;
3882 }
3883
3884 if (!iter) {
3885 /* no child/data on next level */
3886 if (elem2 == second) {
3887 /* done */
3888 break;
3889 }
3890 } else {
3891 /* create new matchlist item */
3892 mlaux = malloc(sizeof *mlaux);
3893 LY_CHECK_ERR_GOTO(!mlaux, LOGMEM(ctx), error);
3894 mlaux->i = 0;
3895 mlaux->match = ly_set_new();
3896 mlaux->prev = matchlist;
3897 matchlist = mlaux;
3898 }
3899 }
3900
3901 while (!next2) {
3902 /* parent */
3903
3904 /* clean the last match set */
3905 ly_set_clean(matchlist->match);
3906 matchlist->i = 0;
3907
3908 /* try to go to a cousin - child of the next parent's sibling */
3909 mlaux = matchlist->prev;
3910 LY_TREE_FOR(elem2->parent->next, iter) {
3911 if (!(iter->validity & LYD_VAL_INUSE)) {
3912 continue;
3913 } else if (mlaux->i == mlaux->match->number) {
3914 if (iter == elem2->parent->next) {
3915 /* we already went through all the matching nodes and now we are just supposed to stop
3916 * the loop with no iter */
3917 iter = NULL;
3918 break;
3919 } else {
3920 /* we have started with some not processed data in matchlist, but now we have
3921 * the INUSE iter and no nodes in matchlist to find its equivalent,
3922 * so something went wrong somewhere */
3923 LOGINT(ctx);
3924 goto error;
3925 }
3926 }
3927
3928 iter->validity &= ~LYD_VAL_INUSE;
3929 if ((iter->schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && (iter->schema->flags & LYS_USERORDERED)) {
3930 for (j = ordset->number ; j > 0; j--) {
3931 ordered = (struct diff_ordered *)ordset->set.g[j - 1];
3932 if (ordered->schema != iter->schema || !lyd_diff_equivnode(ordered->parent, iter->parent)) {
3933 continue;
3934 }
3935
3936 /* store necessary information for move detection */
3937 lyd_diff_move_preprocess(ordered, mlaux->match->set.d[mlaux->i], iter);
3938 break;
3939 }
3940 }
3941
3942 if (((iter->schema->nodetype == LYS_CONTAINER) || ((iter->schema->nodetype == LYS_LIST)
3943 && ((struct lys_node_list *)iter->schema)->keys_size)) && iter->child) {
3944 while (mlaux->i < mlaux->match->number && mlaux->match->set.d[mlaux->i]->schema != iter->schema) {
3945 mlaux->i++;
3946 }
3947 if (mlaux->i == mlaux->match->number) {
3948 /* we have the INUSE iter, so we have to find its equivalent in match list */
3949 LOGINT(ctx);
3950 goto error;
3951 }
3952 next1 = mlaux->match->set.d[mlaux->i]->child;
3953 if (!next1) {
3954 parent = mlaux->match->set.d[mlaux->i];
3955 }
3956 mlaux->i++;
3957 next2 = iter->child;
3958 break;
3959 }
3960 mlaux->i++;
3961 }
3962
3963 /* if no cousin exists, continue next loop on higher level */
3964 if (!iter) {
3965 elem2 = elem2->parent;
3966
3967 /* remove matchlist item */
3968 ly_set_free(matchlist->match);
3969 mlaux = matchlist;
3970 matchlist = matchlist->prev;
3971 free(mlaux);
3972
3973 if (!matchlist->prev) { /* elem2->parent == second->parent */
3974 /* done */
3975 break;
3976 }
3977 }
3978 }
3979 }
3980
3981 ly_set_free(matchlist->match);
3982 free(matchlist);
3983 matchlist = NULL;
3984
3985 /* 2) deleted nodes */
3986 LY_TREE_DFS_BEGIN(first, next1, elem1) {
3987 /* search for elem1s deleted in the second */
3988 if (elem1->validity & LYD_VAL_INUSE) {
3989 /* erase temporary LYD_VAL_INUSE flag and continue into children */
3990 elem1->validity &= ~LYD_VAL_INUSE;
3991 } else if (!elem1->dflt || (options & LYD_DIFFOPT_WITHDEFAULTS)) {
3992 /* elem1 has no matching node in second, add it into result */
3993 if (lyd_difflist_add(result, &size, index++, LYD_DIFF_DELETED, elem1, NULL)) {
3994 goto error;
3995 }
3996
3997 /* skip subtree processing of data missing in the second tree */
3998 goto dfs_nextsibling;
3999 }
4000
4001 /* modified LY_TREE_DFS_END() */
4002 /* select element for the next run - children first */
4003 if ((elem1->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) || ((elem1->schema->nodetype == LYS_LIST)
4004 && !((struct lys_node_list *)elem1->schema)->keys_size)) {
4005 next1 = NULL;
4006 } else {
4007 next1 = elem1->child;
4008 }
4009 if (!next1) {
4010 dfs_nextsibling:
4011 /* try siblings */
4012 next1 = elem1->next;
4013 }
4014 while (!next1) {
4015 /* parent is already processed, go to its sibling */
4016
4017 elem1 = elem1->parent;
4018 if (elem1 == first->parent) {
4019 /* we are done, no next element to process */
4020 break;
4021 }
4022
4023 next1 = elem1->next;
4024 }
4025 }
4026
4027 /* 3) moved nodes (when user-ordered) */
4028 for (i = 0; i < ordset->number; i++) {
4029 ordered = (struct diff_ordered *)ordset->set.g[i];
4030 if (!ordered->dist->dist) {
4031 /* the dist list is sorted here, but the biggest dist is 0,
4032 * so nothing changed in order of these items between first
4033 * and second. We can continue with another user-ordered list.
4034 */
4035 continue;
4036 }
4037
4038 /* get needed movements
4039 * - from the biggest distances try to apply node movements
4040 * on first tree node until they will be ordered as in the
4041 * second tree - i.e. until there will be no position difference
4042 */
4043
4044 for (dist_iter = ordered->dist; ; dist_iter = dist_iter->next) {
4045 /* dist list is sorted at the beginning, since applying a move causes
4046 * just a small change in other distances, we assume that the biggest
4047 * dist is the next one (note that dist list is implemented as ring
4048 * list). This way we avoid sorting distances after each move. The loop
4049 * stops when all distances are zero.
4050 */
4051 dist_aux = dist_iter;
4052 while (!dist_iter->dist) {
4053 /* no dist, so no move. Try another, but when
4054 * there is no dist at all, stop the loop
4055 */
4056 dist_iter = dist_iter->next;
4057 if (dist_iter == dist_aux) {
4058 /* all dist we zeroed */
4059 goto movedone;
4060 }
4061 }
4062 /* something to move */
4063
4064 /* get the item to move */
4065 for (k = 0; k < ordered->count; k++) {
4066 if (ordered->items[k].dist == dist_iter) {
4067 break;
4068 }
4069 }
4070
4071 /* apply the move (distance) */
4072 memcpy(&item_aux, &ordered->items[k], sizeof item_aux);
4073 if (dist_iter->dist > 0) {
4074 /* move to right (other move to left) */
4075 while (dist_iter->dist) {
4076 memcpy(&ordered->items[k], &ordered->items[k + 1], sizeof *ordered->items);
4077 ordered->items[k].dist->dist++; /* update moved item distance */
4078 dist_iter->dist--;
4079 k++;
4080 }
4081 } else {
4082 /* move to left (other move to right) */
4083 while (dist_iter->dist) {
4084 memcpy(&ordered->items[k], &ordered->items[k - 1], sizeof *ordered->items);
4085 ordered->items[k].dist->dist--; /* update moved item distance */
4086 dist_iter->dist++;
4087 k--;
4088 }
4089 }
4090 memcpy(&ordered->items[k], &item_aux, sizeof *ordered->items);
4091
4092 /* store the transaction into the difflist */
4093 if (lyd_difflist_add(result, &size, index++, LYD_DIFF_MOVEDAFTER1, item_aux.first,
4094 (k > 0) ? ordered->items[k - 1].first : NULL)) {
4095 goto error;
4096 }
4097 continue;
4098
4099 movedone:
4100 break;
4101 }
4102 }
4103
4104 diff_ordset_free(ordset);
4105 ordset = NULL;
4106
4107 if (index2) {
4108 /* append result2 with newly created
4109 * (and possibly moved) nodes */
4110 if (index + index2 + 1 >= size) {
4111 /* result must be enlarged */
4112 size = index + index2 + 1;
4113 new = realloc(result->type, size * sizeof *result->type);
4114 LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx), error);
4115 result->type = new;
4116
4117 new = realloc(result->first, size * sizeof *result->first);
4118 LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx), error);
4119 result->first = new;
4120
4121 new = realloc(result->second, size * sizeof *result->second);
4122 LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx), error);
4123 result->second = new;
4124 }
4125
4126 /* append */
4127 memcpy(&result->type[index], result2->type, (index2 + 1) * sizeof *result->type);
4128 memcpy(&result->first[index], result2->first, (index2 + 1) * sizeof *result->first);
4129 memcpy(&result->second[index], result2->second, (index2 + 1) * sizeof *result->second);
4130 }
4131 lyd_free_diff(result2);
4132
4133 return result;
4134
4135 error:
4136 while (matchlist) {
4137 mlaux = matchlist;
4138 matchlist = mlaux->prev;
4139 ly_set_free(mlaux->match);
4140 free(mlaux);
4141
4142 }
4143 diff_ordset_free(ordset);
4144
4145 lyd_free_diff(result);
4146 lyd_free_diff(result2);
4147
4148 return NULL;
4149 }
4150
4151 static void
lyd_insert_setinvalid(struct lyd_node * node)4152 lyd_insert_setinvalid(struct lyd_node *node)
4153 {
4154 struct lyd_node *next, *elem, *parent_list;
4155
4156 assert(node);
4157
4158 /* overall validity of the node itself */
4159 node->validity = ly_new_node_validity(node->schema);
4160
4161 /* explore changed unique leaves */
4162 /* first, get know if there is a list in parents chain */
4163 for (parent_list = node->parent;
4164 parent_list && parent_list->schema->nodetype != LYS_LIST;
4165 parent_list = parent_list->parent);
4166 if (parent_list && !(parent_list->validity & LYD_VAL_UNIQUE)) {
4167 /* there is a list, so check if we inserted a leaf supposed to be unique */
4168 LY_TREE_DFS_BEGIN(node, next, elem) {
4169 if (elem->schema->nodetype == LYS_LIST) {
4170 /* stop searching to the depth, children would be unique to a list in subtree */
4171 goto nextsibling;
4172 }
4173
4174 if (elem->schema->nodetype == LYS_LEAF && (elem->schema->flags & LYS_UNIQUE)) {
4175 /* set flag to list for future validation */
4176 parent_list->validity |= LYD_VAL_UNIQUE;
4177 break;
4178 }
4179
4180 /* LY_TREE_DFS_END */
4181 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4182 next = NULL;
4183 } else {
4184 next = elem->child;
4185 }
4186
4187 if (!next) {
4188 nextsibling:
4189 /* no children */
4190 if (elem == node) {
4191 /* we are done, (START) has no children */
4192 break;
4193 }
4194 /* try siblings */
4195 next = elem->next;
4196 }
4197 while (!next) {
4198 /* parent is already processed, go to its sibling */
4199 elem = elem->parent;
4200
4201 /* no siblings, go back through parents */
4202 if (elem->parent == node->parent) {
4203 /* we are done, no next element to process */
4204 break;
4205 }
4206 next = elem->next;
4207 }
4208 }
4209 }
4210
4211 if (node->parent) {
4212 /* if the inserted node is list/leaflist with constraint on max instances or extension validation callback,
4213 * invalidate the parent to make it validate this */
4214 if ((node->schema->nodetype & LYS_LEAFLIST) && ((struct lys_node_leaflist *)node->schema)->max) {
4215 node->parent->validity |= LYD_VAL_MAND;
4216 } else if ((node->schema->nodetype & LYS_LIST) && ((struct lys_node_list *)node->schema)->max) {
4217 node->parent->validity |= LYD_VAL_MAND;
4218 } else {
4219 /* invalidate all parents that have an extension with a validation
4220 * callback for their whole subtree */
4221 next = node->parent;
4222 while (next) {
4223 if ((next->schema->flags & LYS_VALID_EXT) && (next->schema->flags & LYS_VALID_EXT_SUBTREE))
4224 next->validity |= LYD_VAL_MAND;
4225 next = next->parent;
4226 }
4227 }
4228 }
4229 }
4230
4231 static void
lyd_replace(struct lyd_node * orig,struct lyd_node * repl)4232 lyd_replace(struct lyd_node *orig, struct lyd_node *repl)
4233 {
4234 struct lyd_node *iter, *last;
4235
4236 if (!repl) {
4237 /* remove the old one */
4238 goto finish;
4239 }
4240
4241 if (repl->parent || repl->prev->next) {
4242 /* isolate the new node */
4243 repl->next = NULL;
4244 repl->prev = repl;
4245 last = repl;
4246 } else {
4247 /* get the last node of a possible list of nodes to be inserted */
4248 for (last = repl; last->next; last = last->next) {
4249 /* part of the parent changes */
4250 last->parent = orig->parent;
4251 }
4252 }
4253
4254 /* parent */
4255 if (orig->parent && (orig->parent->child == orig)) {
4256 orig->parent->child = repl;
4257 }
4258
4259 orig->parent = NULL;
4260
4261 /* predecessor */
4262 if (orig->prev == orig) {
4263 /* the old was alone */
4264 goto finish;
4265 }
4266 if (orig->prev->next) {
4267 orig->prev->next = repl;
4268 }
4269 repl->prev = orig->prev;
4270 orig->prev = orig;
4271
4272 /* successor */
4273 if (orig->next) {
4274 orig->next->prev = last;
4275 last->next = orig->next;
4276 orig->next = NULL;
4277 } else {
4278 /* fix the last pointer */
4279 if (repl->parent) {
4280 repl->parent->child->prev = last;
4281 } else {
4282 /* get the first sibling */
4283 for (iter = repl; iter->prev != orig; iter = iter->prev);
4284 iter->prev = last;
4285 }
4286 }
4287
4288 /* the node is already unlinked, remove it from parent's hash table. */
4289 #ifdef LY_ENABLED_CACHE
4290 lyd_unlink_hash(orig, repl->parent);
4291 #endif
4292
4293 finish:
4294 lyd_free(orig);
4295 }
4296
4297 int
lyd_insert_common(struct lyd_node * parent,struct lyd_node ** sibling,struct lyd_node * node,int invalidate)4298 lyd_insert_common(struct lyd_node *parent, struct lyd_node **sibling, struct lyd_node *node, int invalidate)
4299 {
4300 struct lys_node *par1, *par2;
4301 const struct lys_node *siter;
4302 struct lyd_node *start, *iter, *ins, *next1, *next2;
4303 int invalid = 0, isrpc = 0, clrdflt = 0;
4304 struct ly_set *llists = NULL;
4305 int i;
4306 uint8_t pos;
4307 int stype = LYS_INPUT | LYS_OUTPUT;
4308
4309 assert(parent || sibling);
4310
4311 /* get first sibling */
4312 if (parent) {
4313 start = parent->child;
4314 } else {
4315 for (start = *sibling; start->prev->next; start = start->prev);
4316 }
4317
4318 /* check placing the node to the appropriate place according to the schema */
4319 if (!start) {
4320 if (!parent) {
4321 /* empty tree to insert */
4322 if (node->parent || node->prev->next) {
4323 /* unlink the node first */
4324 lyd_unlink_internal(node, 1);
4325 } /* else insert also node's siblings */
4326 *sibling = node;
4327 return EXIT_SUCCESS;
4328 }
4329 par1 = parent->schema;
4330 if (par1->nodetype & (LYS_RPC | LYS_ACTION)) {
4331 /* it is not clear if the tree being created is going to
4332 * be rpc (LYS_INPUT) or rpc-reply (LYS_OUTPUT) so we have to
4333 * compare against LYS_RPC or LYS_ACTION in par2
4334 */
4335 stype = LYS_RPC | LYS_ACTION;
4336 }
4337 } else if (parent && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
4338 par1 = parent->schema;
4339 stype = LYS_RPC | LYS_ACTION;
4340 } else {
4341 for (par1 = lys_parent(start->schema);
4342 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
4343 par1 = lys_parent(par1));
4344 }
4345 for (par2 = lys_parent(node->schema);
4346 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | stype | LYS_NOTIF));
4347 par2 = lys_parent(par2));
4348 if (par1 != par2) {
4349 LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert, different parents (\"%s\" and \"%s\").",
4350 (par1 ? par1->name : "<top-lvl>"), (par2 ? par2->name : "<top-lvl>"));
4351 return EXIT_FAILURE;
4352 }
4353
4354 if (invalidate) {
4355 invalid = isrpc = lyp_is_rpc_action(node->schema);
4356 if (!parent || node->parent != parent || isrpc) {
4357 /* it is not just moving under a parent node or it is in an RPC where
4358 * nodes order matters, so the validation will be necessary */
4359 invalid++;
4360 }
4361 }
4362
4363 /* unlink only if it is not a list of siblings without a parent and node is not the first sibling */
4364 if (node->parent || node->prev->next) {
4365 /* do it permanent if the parents are not exact same or if it is top-level */
4366 lyd_unlink_internal(node, invalid);
4367 }
4368
4369 llists = ly_set_new();
4370
4371 /* process the nodes to insert one by one */
4372 LY_TREE_FOR_SAFE(node, next1, ins) {
4373 if (invalid == 1) {
4374 /* auto delete nodes from other cases, if any;
4375 * this is done only if node->parent != parent */
4376 if (lyv_multicases(ins, NULL, &start, 1, NULL)) {
4377 goto error;
4378 }
4379 }
4380
4381 /* isolate the node to be handled separately */
4382 ins->prev = ins;
4383 ins->next = NULL;
4384
4385 iter = NULL;
4386 if (!ins->dflt) {
4387 clrdflt = 1;
4388 }
4389
4390 /* are we inserting list key? */
4391 if (!ins->dflt && ins->schema->nodetype == LYS_LEAF && lys_is_key((struct lys_node_leaf *)ins->schema, &pos)) {
4392 /* yes, we have a key, get know its position */
4393 for (i = 0, iter = parent->child;
4394 iter && i < pos && iter->schema->nodetype == LYS_LEAF;
4395 i++, iter = iter->next);
4396 if (iter) {
4397 /* insert list's key to the correct position - before the iter */
4398 if (parent->child == iter) {
4399 parent->child = ins;
4400 }
4401 if (iter->prev->next) {
4402 iter->prev->next = ins;
4403 }
4404 ins->prev = iter->prev;
4405 iter->prev = ins;
4406 ins->next = iter;
4407
4408 /* update start element */
4409 if (parent->child != start) {
4410 start = parent->child;
4411 }
4412 }
4413
4414 /* try to find previously present default instance to replace */
4415 } else if (ins->schema->nodetype == LYS_LEAFLIST) {
4416 i = (int)llists->number;
4417 if ((ly_set_add(llists, ins->schema, 0) != i) || ins->dflt) {
4418 /* each leaf-list must be cleared only once (except when looking for exact same existing dflt nodes) */
4419 LY_TREE_FOR_SAFE(start, next2, iter) {
4420 if (iter->schema == ins->schema) {
4421 if ((ins->dflt && (!iter->dflt || ((iter->schema->flags & LYS_CONFIG_W) &&
4422 !strcmp(((struct lyd_node_leaf_list *)iter)->value_str,
4423 ((struct lyd_node_leaf_list *)ins)->value_str))))
4424 || (!ins->dflt && iter->dflt)) {
4425 if (iter == start) {
4426 start = next2;
4427 }
4428 lyd_free(iter);
4429 }
4430 }
4431 }
4432 }
4433 } else if (ins->schema->nodetype == LYS_LEAF || (ins->schema->nodetype == LYS_CONTAINER
4434 && !((struct lys_node_container *)ins->schema)->presence)) {
4435 LY_TREE_FOR(start, iter) {
4436 if (iter->schema == ins->schema) {
4437 if (ins->dflt || iter->dflt) {
4438 /* replace existing (either explicit or default) node with the new (either explicit or default) node */
4439 lyd_replace(iter, ins);
4440 } else {
4441 /* keep both explicit nodes, let the caller solve it later */
4442 iter = NULL;
4443 }
4444 break;
4445 }
4446 }
4447 }
4448
4449 if (!iter) {
4450 if (!start) {
4451 /* add as the only child of the parent */
4452 start = ins;
4453 if (parent) {
4454 parent->child = ins;
4455 }
4456 } else if (isrpc) {
4457 /* add to the specific position in rpc/rpc-reply/action */
4458 for (par1 = lys_parent(ins->schema); !(par1->nodetype & (LYS_INPUT | LYS_OUTPUT)); par1 = lys_parent(par1));
4459 siter = NULL;
4460 LY_TREE_FOR(start, iter) {
4461 while ((siter = lys_getnext(siter, par1, lys_node_module(par1), 0))) {
4462 if (iter->schema == siter || ins->schema == siter) {
4463 break;
4464 }
4465 }
4466 if (ins->schema == siter) {
4467 if ((siter->nodetype & (LYS_LEAFLIST | LYS_LIST)) && iter->schema == siter) {
4468 /* we are inserting leaflist/list instance, but since there are already
4469 * some instances of the same leaflist/list, we want to insert the new one
4470 * as the last instance, so here we have to move on */
4471 while (iter && iter->schema == siter) {
4472 iter = iter->next;
4473 }
4474 if (!iter) {
4475 break;
4476 }
4477 }
4478 /* we have the correct place for new node (before the iter) */
4479 if (iter == start) {
4480 start = ins;
4481 if (parent) {
4482 parent->child = ins;
4483 }
4484 } else {
4485 iter->prev->next = ins;
4486 }
4487 ins->prev = iter->prev;
4488 iter->prev = ins;
4489 ins->next = iter;
4490
4491 /* we are done */
4492 break;
4493 }
4494 }
4495 if (!iter) {
4496 /* add as the last child of the parent */
4497 start->prev->next = ins;
4498 ins->prev = start->prev;
4499 start->prev = ins;
4500 }
4501 } else {
4502 /* add as the last child of the parent */
4503 start->prev->next = ins;
4504 ins->prev = start->prev;
4505 start->prev = ins;
4506 }
4507 }
4508
4509 #ifdef LY_ENABLED_CACHE
4510 lyd_unlink_hash(ins, ins->parent);
4511 #endif
4512
4513 ins->parent = parent;
4514
4515 #ifdef LY_ENABLED_CACHE
4516 lyd_insert_hash(ins);
4517 #endif
4518
4519 if (invalid) {
4520 lyd_insert_setinvalid(ins);
4521 }
4522 }
4523 ly_set_free(llists);
4524
4525 if (clrdflt) {
4526 /* remove the dflt flag from parents */
4527 for (iter = parent; iter && iter->dflt; iter = iter->parent) {
4528 iter->dflt = 0;
4529 }
4530 }
4531
4532 if (sibling) {
4533 *sibling = start;
4534 }
4535 return EXIT_SUCCESS;
4536
4537 error:
4538 ly_set_free(llists);
4539 return EXIT_FAILURE;
4540 }
4541
4542 API int
lyd_insert(struct lyd_node * parent,struct lyd_node * node)4543 lyd_insert(struct lyd_node *parent, struct lyd_node *node)
4544 {
4545 FUN_IN;
4546
4547 if (!node || !parent || (parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
4548 LOGARG;
4549 return EXIT_FAILURE;
4550 }
4551
4552 return lyd_insert_common(parent, NULL, node, 1);
4553 }
4554
4555 API int
lyd_insert_sibling(struct lyd_node ** sibling,struct lyd_node * node)4556 lyd_insert_sibling(struct lyd_node **sibling, struct lyd_node *node)
4557 {
4558 FUN_IN;
4559
4560 if (!sibling || !node) {
4561 LOGARG;
4562 return EXIT_FAILURE;
4563 }
4564
4565 return lyd_insert_common((*sibling) ? (*sibling)->parent : NULL, sibling, node, 1);
4566
4567 }
4568
4569 int
lyd_insert_nextto(struct lyd_node * sibling,struct lyd_node * node,int before,int invalidate)4570 lyd_insert_nextto(struct lyd_node *sibling, struct lyd_node *node, int before, int invalidate)
4571 {
4572 struct ly_ctx *ctx;
4573 struct lys_node *par1, *par2;
4574 struct lyd_node *iter, *start = NULL, *ins, *next1, *next2, *last = NULL;
4575 struct lyd_node *orig_parent = NULL, *orig_prev = NULL, *orig_next = NULL;
4576 int invalid = 0;
4577 char *str;
4578
4579 assert(sibling);
4580 assert(node);
4581
4582 ctx = sibling->schema->module->ctx;
4583
4584 if (sibling == node) {
4585 return EXIT_SUCCESS;
4586 }
4587
4588 /* check placing the node to the appropriate place according to the schema */
4589 for (par1 = lys_parent(sibling->schema);
4590 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_ACTION | LYS_NOTIF));
4591 par1 = lys_parent(par1));
4592 for (par2 = lys_parent(node->schema);
4593 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_ACTION | LYS_NOTIF));
4594 par2 = lys_parent(par2));
4595 if (par1 != par2) {
4596 LOGERR(ctx, LY_EINVAL, "Cannot insert, different parents (\"%s\" and \"%s\").",
4597 (par1 ? par1->name : "<top-lvl>"), (par2 ? par2->name : "<top-lvl>"));
4598 return EXIT_FAILURE;
4599 }
4600
4601 if (invalidate && ((node->parent != sibling->parent) || (invalid = lyp_is_rpc_action(node->schema)) || !node->parent)) {
4602 /* a) it is not just moving under a parent node (invalid = 1) or
4603 * b) it is in an RPC where nodes order matters (invalid = 2) or
4604 * c) it is top-level where we don't know if it is the same tree (invalid = 1),
4605 * so the validation will be necessary */
4606 if (!node->parent && !invalid) {
4607 /* c) search in siblings */
4608 for (iter = node->prev; iter != node; iter = iter->prev) {
4609 if (iter == sibling) {
4610 break;
4611 }
4612 }
4613 if (iter == node) {
4614 /* node and siblings are not currently in the same data tree */
4615 invalid++;
4616 }
4617 } else { /* a) and b) */
4618 invalid++;
4619 }
4620 }
4621
4622 /* unlink only if it is not a list of siblings without a parent or node is not the first sibling,
4623 * always unlink if just moving a node */
4624 if ((!invalid) || node->parent || node->prev->next) {
4625 /* remember the original position to be able to revert
4626 * unlink in case of error */
4627 orig_parent = node->parent;
4628 if (node->prev != node) {
4629 orig_prev = node->prev;
4630 }
4631 orig_next = node->next;
4632 lyd_unlink_internal(node, invalid);
4633 }
4634
4635 /* find first sibling node */
4636 if (sibling->parent) {
4637 start = sibling->parent->child;
4638 } else {
4639 for (start = sibling; start->prev->next; start = start->prev);
4640 }
4641
4642 /* process the nodes one by one to clean the current tree */
4643 if (!invalid) {
4644 /* just moving one sibling */
4645 last = node;
4646 node->parent = sibling->parent;
4647 } else {
4648 LY_TREE_FOR_SAFE(node, next1, ins) {
4649 lyd_insert_setinvalid(ins);
4650
4651 if (invalid == 1) {
4652 /* auto delete nodes from other cases */
4653 if (lyv_multicases(ins, NULL, &start, 1, sibling) == 2) {
4654 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, sibling, "Insert request refers node (%s) that is going to be auto-deleted.",
4655 ly_errpath(ctx));
4656 goto error;
4657 }
4658 }
4659
4660 /* try to find previously present default instance to remove because of
4661 * inserting the specified node */
4662 if (ins->schema->nodetype == LYS_LEAFLIST) {
4663 LY_TREE_FOR_SAFE(start, next2, iter) {
4664 if (iter->schema == ins->schema) {
4665 if ((ins->dflt && (!iter->dflt || ((iter->schema->flags & LYS_CONFIG_W) &&
4666 !strcmp(((struct lyd_node_leaf_list *)iter)->value_str,
4667 ((struct lyd_node_leaf_list *)ins)->value_str))))
4668 || (!ins->dflt && iter->dflt)) {
4669 /* iter will get deleted */
4670 if (iter == sibling) {
4671 LOGERR(ctx, LY_EINVAL, "Insert request refers node (%s) that is going to be auto-deleted.",
4672 str = lyd_path(sibling));
4673 free(str);
4674 goto error;
4675 }
4676 if (iter == start) {
4677 start = next2;
4678 }
4679 lyd_free(iter);
4680 }
4681 }
4682 }
4683 } else if (ins->schema->nodetype == LYS_LEAF ||
4684 (ins->schema->nodetype == LYS_CONTAINER && !((struct lys_node_container *)ins->schema)->presence)) {
4685 LY_TREE_FOR(start, iter) {
4686 if (iter->schema == ins->schema) {
4687 if (iter->dflt || ins->dflt) {
4688 /* iter gets deleted */
4689 if (iter == sibling) {
4690 LOGERR(ctx, LY_EINVAL, "Insert request refers node (%s) that is going to be auto-deleted.",
4691 str = lyd_path(sibling));
4692 free(str);
4693 goto error;
4694 }
4695 if (iter == start) {
4696 start = iter->next;
4697 }
4698 lyd_free(iter);
4699 }
4700 break;
4701 }
4702 }
4703 }
4704
4705 ins->parent = sibling->parent;
4706 last = ins;
4707 }
4708 }
4709
4710 /* insert the (list of) node(s) to the specified position */
4711 if (before) {
4712 if (sibling->prev->next) {
4713 /* adding into the middle */
4714 sibling->prev->next = node;
4715 } else if (sibling->parent) {
4716 /* at the beginning */
4717 sibling->parent->child = node;
4718 }
4719 node->prev = sibling->prev;
4720 sibling->prev = last;
4721 last->next = sibling;
4722 } else { /* after */
4723 if (sibling->next) {
4724 /* adding into the middle - fix the prev pointer of the node after inserted nodes */
4725 last->next = sibling->next;
4726 sibling->next->prev = last;
4727 } else {
4728 /* at the end - fix the prev pointer of the first node */
4729 start->prev = last;
4730 }
4731 sibling->next = node;
4732 node->prev = sibling;
4733 }
4734
4735 #ifdef LY_ENABLED_CACHE
4736 /* now that all the nodes are correctly inserted, fix hashes (node was already unlinked) */
4737 lyd_insert_hash(node);
4738
4739 /* relink all following nodes */
4740 iter = node;
4741 for (iter = node; iter != last; iter = iter->next) {
4742 lyd_unlink_hash(iter, iter->parent);
4743 lyd_insert_hash(iter);
4744 }
4745 #endif
4746
4747 return EXIT_SUCCESS;
4748
4749 error:
4750 /* insert back to the original position */
4751 if (orig_prev) {
4752 lyd_insert_after(orig_prev, node);
4753 } else if (orig_next) {
4754 lyd_insert_before(orig_next, node);
4755 } else if (orig_parent) {
4756 /* there were no siblings */
4757 orig_parent->child = node;
4758 node->parent = orig_parent;
4759 }
4760 return EXIT_FAILURE;
4761 }
4762
4763 API int
lyd_insert_before(struct lyd_node * sibling,struct lyd_node * node)4764 lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
4765 {
4766 FUN_IN;
4767
4768 if (!node || !sibling) {
4769 LOGARG;
4770 return EXIT_FAILURE;
4771 }
4772
4773 return lyd_insert_nextto(sibling, node, 1, 1);
4774 }
4775
4776 API int
lyd_insert_after(struct lyd_node * sibling,struct lyd_node * node)4777 lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
4778 {
4779 FUN_IN;
4780
4781 if (!node || !sibling) {
4782 LOGARG;
4783 return EXIT_FAILURE;
4784 }
4785
4786 return lyd_insert_nextto(sibling, node, 0, 1);
4787 }
4788
4789 static uint32_t
lys_module_pos(struct lys_module * module)4790 lys_module_pos(struct lys_module *module)
4791 {
4792 int i;
4793 uint32_t pos = 1;
4794
4795 for (i = 0; i < module->ctx->models.used; ++i) {
4796 if (module->ctx->models.list[i] == module) {
4797 return pos;
4798 }
4799 ++pos;
4800 }
4801
4802 LOGINT(module->ctx);
4803 return 0;
4804 }
4805
4806 static int
lys_module_node_pos_r(struct lys_node * first_sibling,struct lys_node * target,uint32_t * pos)4807 lys_module_node_pos_r(struct lys_node *first_sibling, struct lys_node *target, uint32_t *pos)
4808 {
4809 const struct lys_node *next = NULL;
4810
4811 /* the schema nodes are actually from data, lys_getnext skips non-data schema nodes for us (we know the parent will not be uses) */
4812 while ((next = lys_getnext(next, lys_parent(first_sibling), lys_node_module(first_sibling), LYS_GETNEXT_NOSTATECHECK))) {
4813 ++(*pos);
4814 if (target == next) {
4815 return 0;
4816 }
4817 }
4818
4819 LOGINT(first_sibling->module->ctx);
4820 return 1;
4821 }
4822
4823 static int
lyd_node_pos_cmp(const void * item1,const void * item2)4824 lyd_node_pos_cmp(const void *item1, const void *item2)
4825 {
4826 uint32_t mpos1, mpos2;
4827 struct lyd_node_pos *np1, *np2;
4828
4829 np1 = (struct lyd_node_pos *)item1;
4830 np2 = (struct lyd_node_pos *)item2;
4831
4832 /* different modules? */
4833 if (lys_node_module(np1->node->schema) != lys_node_module(np2->node->schema)) {
4834 mpos1 = lys_module_pos(lys_node_module(np1->node->schema));
4835 mpos2 = lys_module_pos(lys_node_module(np2->node->schema));
4836 /* if lys_module_pos failed, there is nothing we can do anyway,
4837 * at least internal error will be printed */
4838
4839 if (mpos1 > mpos2) {
4840 return 1;
4841 } else {
4842 return -1;
4843 }
4844 }
4845
4846 if (np1->pos > np2->pos) {
4847 return 1;
4848 } else if (np1->pos < np2->pos) {
4849 return -1;
4850 }
4851 return 0;
4852 }
4853
4854 API int
lyd_schema_sort(struct lyd_node * sibling,int recursive)4855 lyd_schema_sort(struct lyd_node *sibling, int recursive)
4856 {
4857 FUN_IN;
4858
4859 uint32_t len, i;
4860 struct lyd_node *node;
4861 struct lys_node *first_ssibling = NULL;
4862 struct lyd_node_pos *array;
4863
4864 if (!sibling) {
4865 LOGARG;
4866 return -1;
4867 }
4868
4869 /* something actually to sort */
4870 if (sibling->prev != sibling) {
4871
4872 /* find the beginning */
4873 sibling = lyd_first_sibling(sibling);
4874
4875 /* count siblings */
4876 len = 0;
4877 for (node = sibling; node; node = node->next) {
4878 ++len;
4879 }
4880
4881 array = malloc(len * sizeof *array);
4882 LY_CHECK_ERR_RETURN(!array, LOGMEM(sibling->schema->module->ctx), -1);
4883
4884 /* fill arrays with positions and corresponding nodes */
4885 for (i = 0, node = sibling; i < len; ++i, node = node->next) {
4886 array[i].pos = 0;
4887
4888 /* we need to repeat this for every module */
4889 if (!first_ssibling || (lyd_node_module(node) != lys_node_module(first_ssibling))) {
4890 /* find the data node schema parent */
4891 first_ssibling = node->schema;
4892 while (lys_parent(first_ssibling)
4893 && (lys_parent(first_ssibling)->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
4894 first_ssibling = lys_parent(first_ssibling);
4895 }
4896
4897 /* find the beginning */
4898 if (lys_parent(first_ssibling)) {
4899 first_ssibling = lys_parent(first_ssibling)->child;
4900 } else {
4901 while (first_ssibling->prev->next) {
4902 first_ssibling = first_ssibling->prev;
4903 }
4904 }
4905 }
4906
4907 if (lys_module_node_pos_r(first_ssibling, node->schema, &array[i].pos)) {
4908 free(array);
4909 return -1;
4910 }
4911
4912 array[i].node = node;
4913 }
4914
4915 /* sort the arrays */
4916 qsort(array, len, sizeof *array, lyd_node_pos_cmp);
4917
4918 /* adjust siblings based on the sorted array */
4919 for (i = 0; i < len; ++i) {
4920 /* parent child */
4921 if (i == 0) {
4922 /* adjust sibling so that it still points to the beginning */
4923 sibling = array[i].node;
4924 if (array[i].node->parent) {
4925 array[i].node->parent->child = array[i].node;
4926 }
4927 }
4928
4929 /* prev */
4930 if (i > 0) {
4931 array[i].node->prev = array[i - 1].node;
4932 } else {
4933 array[i].node->prev = array[len - 1].node;
4934 }
4935
4936 /* next */
4937 if (i < len - 1) {
4938 array[i].node->next = array[i + 1].node;
4939 } else {
4940 array[i].node->next = NULL;
4941 }
4942 }
4943 free(array);
4944 }
4945
4946 /* sort all the children recursively */
4947 if (recursive) {
4948 LY_TREE_FOR(sibling, node) {
4949 if ((node->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF))
4950 && node->child && lyd_schema_sort(node->child, recursive)) {
4951 return -1;
4952 }
4953 }
4954 }
4955
4956 return EXIT_SUCCESS;
4957 }
4958
4959 static int
_lyd_validate(struct lyd_node ** node,struct lyd_node * data_tree,struct ly_ctx * ctx,const struct lys_module ** modules,int mod_count,struct lyd_difflist ** diff,int options)4960 _lyd_validate(struct lyd_node **node, struct lyd_node *data_tree, struct ly_ctx *ctx, const struct lys_module **modules,
4961 int mod_count, struct lyd_difflist **diff, int options)
4962 {
4963 struct lyd_node *root, *next1, *next2, *iter, *act_notif = NULL;
4964 int ret = EXIT_FAILURE;
4965 unsigned int i;
4966 struct unres_data *unres = NULL;
4967 const struct lys_module *yanglib_mod;
4968
4969 unres = calloc(1, sizeof *unres);
4970 LY_CHECK_ERR_RETURN(!unres, LOGMEM(NULL), EXIT_FAILURE);
4971
4972 if (diff) {
4973 unres->store_diff = 1;
4974 unres->diff = lyd_diff_init_difflist(ctx, &unres->diff_size);
4975 }
4976
4977 if ((options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY)) && *node && ((*node)->schema->nodetype != LYS_RPC)) {
4978 options |= LYD_OPT_ACT_NOTIF;
4979 }
4980 if ((options & (LYD_OPT_NOTIF | LYD_OPT_NOTIF_FILTER)) && *node && ((*node)->schema->nodetype != LYS_NOTIF)) {
4981 options |= LYD_OPT_ACT_NOTIF;
4982 }
4983
4984 LY_TREE_FOR_SAFE(*node, next1, root) {
4985 if (modules) {
4986 for (i = 0; i < (unsigned)mod_count; ++i) {
4987 if (lyd_node_module(root) == modules[i]) {
4988 break;
4989 }
4990 }
4991 if (i == (unsigned)mod_count) {
4992 /* skip data that should not be validated */
4993 continue;
4994 }
4995 }
4996
4997 LY_TREE_DFS_BEGIN(root, next2, iter) {
4998 if (iter->parent && (iter->schema->nodetype & (LYS_ACTION | LYS_NOTIF))) {
4999 if (!(options & LYD_OPT_ACT_NOTIF) || act_notif) {
5000 LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, iter, iter->schema->name);
5001 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected %s node \"%s\".",
5002 (options & LYD_OPT_RPC ? "action" : "notification"), iter->schema->name);
5003 goto cleanup;
5004 }
5005 act_notif = iter;
5006 }
5007
5008 if (lyv_data_context(iter, options, 1, unres) || lyv_data_content(iter, options, unres)) {
5009 goto cleanup;
5010 }
5011
5012 /* empty non-default, non-presence container without attributes, make it default */
5013 if (!iter->dflt && (iter->schema->nodetype == LYS_CONTAINER) && !iter->child
5014 && !((struct lys_node_container *)iter->schema)->presence && !iter->attr) {
5015 iter->dflt = 1;
5016 }
5017
5018 LY_TREE_DFS_END(root, next2, iter);
5019 }
5020
5021 if (options & LYD_OPT_NOSIBLINGS) {
5022 break;
5023 }
5024
5025 }
5026
5027 if (options & LYD_OPT_ACT_NOTIF) {
5028 if (!act_notif) {
5029 LOGVAL(ctx, LYE_MISSELEM, LY_VLOG_LYD, *node, (options & LYD_OPT_RPC ? "action" : "notification"), (*node)->schema->name);
5030 goto cleanup;
5031 }
5032 options &= ~LYD_OPT_ACT_NOTIF;
5033 }
5034
5035 if (*node) {
5036 /* check for uniqueness of top-level lists/leaflists because
5037 * only the inner instances were tested in lyv_data_content() */
5038 yanglib_mod = ly_ctx_get_module(ctx ? ctx : (*node)->schema->module->ctx, "ietf-yang-library", NULL, 1);
5039 LY_TREE_FOR(*node, root) {
5040 if ((options & LYD_OPT_DATA_ADD_YANGLIB) && yanglib_mod && (root->schema->module == yanglib_mod)) {
5041 /* ietf-yang-library data present, so ignore the option to add them */
5042 options &= ~LYD_OPT_DATA_ADD_YANGLIB;
5043 }
5044
5045 if (!(root->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(root->validity & LYD_VAL_DUP)) {
5046 continue;
5047 }
5048
5049 if (options & LYD_OPT_TRUSTED) {
5050 /* just clear the flag */
5051 root->validity &= ~LYD_VAL_DUP;
5052 continue;
5053 }
5054
5055 if (lyv_data_dup(root, *node)) {
5056 goto cleanup;
5057 }
5058 }
5059 }
5060
5061 /* add missing ietf-yang-library if requested */
5062 if (options & LYD_OPT_DATA_ADD_YANGLIB) {
5063 if (!(*node)) {
5064 (*node) = ly_ctx_info(ctx);
5065 } else if (lyd_merge((*node), ly_ctx_info(ctx), LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
5066 LOGERR(ctx, LY_EINT, "Adding ietf-yang-library data failed.");
5067 goto cleanup;
5068 }
5069 }
5070
5071 /* add default values, resolve unres and check for mandatory nodes in final tree */
5072 if (lyd_defaults_add_unres(node, options, ctx, modules, mod_count, data_tree, act_notif, unres, 1)) {
5073 goto cleanup;
5074 }
5075 if (act_notif) {
5076 if (lyd_check_mandatory_tree(act_notif, ctx, modules, mod_count, options)) {
5077 goto cleanup;
5078 }
5079 } else {
5080 if (lyd_check_mandatory_tree(*node, ctx, modules, mod_count, options)) {
5081 goto cleanup;
5082 }
5083 }
5084
5085 if ((options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY)) && *node && lyd_schema_sort(*node, 1)) {
5086 /* rpc and rpc-reply must be sorted */
5087 goto cleanup;
5088 }
5089
5090 /* consolidate diff if created */
5091 if (diff) {
5092 assert(unres->store_diff);
5093
5094 for (i = 0; i < unres->diff_idx; ++i) {
5095 if (unres->diff->type[i] == LYD_DIFF_CREATED) {
5096 if (unres->diff->second[i]->parent) {
5097 unres->diff->first[i] = (struct lyd_node *)lyd_path(unres->diff->second[i]->parent);
5098 }
5099 unres->diff->second[i] = lyd_dup(unres->diff->second[i], LYD_DUP_OPT_RECURSIVE);
5100 }
5101 }
5102
5103 *diff = unres->diff;
5104 unres->diff = 0;
5105 unres->diff_idx = 0;
5106 }
5107
5108 ret = EXIT_SUCCESS;
5109
5110 cleanup:
5111 if (unres) {
5112 free(unres->node);
5113 free(unres->type);
5114 for (i = 0; i < unres->diff_idx; ++i) {
5115 if (unres->diff->type[i] == LYD_DIFF_DELETED) {
5116 lyd_free_withsiblings(unres->diff->first[i]);
5117 free(unres->diff->second[i]);
5118 }
5119 }
5120 lyd_free_diff(unres->diff);
5121 free(unres);
5122 }
5123
5124 return ret;
5125 }
5126
5127 API int
lyd_validate(struct lyd_node ** node,int options,void * var_arg,...)5128 lyd_validate(struct lyd_node **node, int options, void *var_arg, ...)
5129 {
5130 FUN_IN;
5131
5132 struct lyd_node *iter, *data_tree = NULL;
5133 struct lyd_difflist **diff = NULL;
5134 struct ly_ctx *ctx = NULL;
5135 va_list ap;
5136
5137 if (!node) {
5138 LOGARG;
5139 return EXIT_FAILURE;
5140 }
5141
5142 if (lyp_data_check_options(NULL, options, __func__)) {
5143 return EXIT_FAILURE;
5144 }
5145
5146 data_tree = *node;
5147
5148 if ((!(options & LYD_OPT_TYPEMASK)
5149 || (options & (LYD_OPT_CONFIG | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT))) && !(*node)) {
5150 /* get context with schemas from the var_arg */
5151 ctx = (struct ly_ctx *)var_arg;
5152 if (!ctx) {
5153 LOGERR(NULL, LY_EINVAL, "%s: invalid variable parameter (struct ly_ctx *ctx).", __func__);
5154 return EXIT_FAILURE;
5155 }
5156
5157 /* LYD_OPT_NOSIBLINGS has no meaning here */
5158 options &= ~LYD_OPT_NOSIBLINGS;
5159 } else if (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)) {
5160 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
5161 if (options & LYD_OPT_NOSIBLINGS) {
5162 LOGERR(NULL, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
5163 return EXIT_FAILURE;
5164 } else if (!(*node)) {
5165 LOGARG;
5166 return EXIT_FAILURE;
5167 }
5168
5169 /* get the additional data tree if given */
5170 data_tree = (struct lyd_node *)var_arg;
5171 if (data_tree) {
5172 if (options & LYD_OPT_NOEXTDEPS) {
5173 LOGERR(NULL, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree and LYD_OPT_NOEXTDEPS set).",
5174 __func__);
5175 return EXIT_FAILURE;
5176 }
5177
5178 LY_TREE_FOR(data_tree, iter) {
5179 if (iter->parent) {
5180 /* a sibling is not top-level */
5181 LOGERR(NULL, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
5182 return EXIT_FAILURE;
5183 }
5184 }
5185
5186 /* move it to the beginning */
5187 for (; data_tree->prev->next; data_tree = data_tree->prev);
5188 }
5189 } else if (options & LYD_OPT_DATA_TEMPLATE) {
5190 /* get context with schemas from the var_arg */
5191 if (*node && ((*node)->prev->next || (*node)->next)) {
5192 /* not allow sibling in top-level */
5193 LOGERR(NULL, LY_EINVAL, "%s: invalid variable parameter (struct lyd_node *node).", __func__);
5194 return EXIT_FAILURE;
5195 }
5196 }
5197
5198 if (options & LYD_OPT_VAL_DIFF) {
5199 va_start(ap, var_arg);
5200 diff = va_arg(ap, struct lyd_difflist **);
5201 va_end(ap);
5202 if (!diff) {
5203 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (struct lyd_difflist **).", __func__);
5204 return EXIT_FAILURE;
5205 }
5206 }
5207
5208 if (*node) {
5209 if (!ctx) {
5210 ctx = (*node)->schema->module->ctx;
5211 }
5212 if (!(options & LYD_OPT_NOSIBLINGS)) {
5213 /* check that the node is the first sibling */
5214 while ((*node)->prev->next) {
5215 *node = (*node)->prev;
5216 }
5217 }
5218 }
5219
5220 return _lyd_validate(node, data_tree, ctx, NULL, 0, diff, options);
5221 }
5222
5223 API int
lyd_validate_modules(struct lyd_node ** node,const struct lys_module ** modules,int mod_count,int options,...)5224 lyd_validate_modules(struct lyd_node **node, const struct lys_module **modules, int mod_count, int options, ...)
5225 {
5226 FUN_IN;
5227
5228 struct ly_ctx *ctx;
5229 struct lyd_difflist **diff = NULL;
5230 va_list ap;
5231
5232 if (!node || !modules || !mod_count) {
5233 LOGARG;
5234 return EXIT_FAILURE;
5235 }
5236
5237 ctx = modules[0]->ctx;
5238
5239 if (*node && !(options & LYD_OPT_NOSIBLINGS)) {
5240 /* check that the node is the first sibling */
5241 while ((*node)->prev->next) {
5242 *node = (*node)->prev;
5243 }
5244 }
5245
5246 if (lyp_data_check_options(ctx, options, __func__)) {
5247 return EXIT_FAILURE;
5248 }
5249
5250 if ((options & LYD_OPT_TYPEMASK) && !(options & (LYD_OPT_CONFIG | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT))) {
5251 LOGERR(NULL, LY_EINVAL, "%s: options include a forbidden data type.", __func__);
5252 return EXIT_FAILURE;
5253 }
5254
5255 if (options & LYD_OPT_VAL_DIFF) {
5256 va_start(ap, options);
5257 diff = va_arg(ap, struct lyd_difflist **);
5258 va_end(ap);
5259 if (!diff) {
5260 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (struct lyd_difflist **).", __func__);
5261 return EXIT_FAILURE;
5262 }
5263 }
5264
5265 return _lyd_validate(node, *node, ctx, modules, mod_count, diff, options);
5266 }
5267
5268 API int
lyd_validate_value(struct lys_node * node,const char * value)5269 lyd_validate_value(struct lys_node *node, const char *value)
5270 {
5271 return lyd_value_type(node, value, NULL);
5272 }
5273
5274 int
lyd_value_type_internal(struct lys_node * node,const char * value,const struct lys_module * local_mod,struct lys_type ** type)5275 lyd_value_type_internal(struct lys_node *node, const char *value, const struct lys_module *local_mod,
5276 struct lys_type **type)
5277 {
5278 FUN_IN;
5279
5280 struct lyd_node_leaf_list leaf;
5281 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
5282 struct lys_type *t = NULL;
5283
5284 if (!node || !(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5285 LOGARG;
5286 return EXIT_FAILURE;
5287 }
5288
5289 if (!value) {
5290 value = "";
5291 }
5292
5293 /* dummy leaf */
5294 memset(&leaf, 0, sizeof leaf);
5295 leaf.value_str = lydict_insert(node->module->ctx, value, 0);
5296
5297 repeat:
5298 leaf.value_type = sleaf->type.base;
5299 leaf.schema = node;
5300
5301 if (leaf.value_type == LY_TYPE_LEAFREF) {
5302 if (!sleaf->type.info.lref.target) {
5303 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
5304 LOGINT(node->module->ctx);
5305 goto cleanup;
5306 }
5307 sleaf = sleaf->type.info.lref.target;
5308 goto repeat;
5309 } else {
5310 t = lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, (struct lys_module *)local_mod, 0,
5311 local_mod ? 1 : 0);
5312 }
5313
5314 cleanup:
5315 lydict_remove(node->module->ctx, leaf.value_str);
5316 if (type) {
5317 *type = t;
5318 }
5319 return t ? EXIT_SUCCESS : EXIT_FAILURE;
5320 }
5321
5322 API int
lyd_value_type(struct lys_node * node,const char * value,struct lys_type ** type)5323 lyd_value_type(struct lys_node *node, const char *value, struct lys_type **type)
5324 {
5325 return lyd_value_type_internal(node, value, NULL, type);
5326 }
5327
5328 /* create an attribute copy */
5329 static struct lyd_attr *
lyd_dup_attr(struct ly_ctx * ctx,struct lyd_node * parent,struct lyd_attr * attr)5330 lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
5331 {
5332 struct lyd_attr *ret;
5333
5334 /* allocate new attr */
5335 if (!parent->attr) {
5336 parent->attr = calloc(1, sizeof *ret);
5337 ret = parent->attr;
5338 } else {
5339 for (ret = parent->attr; ret->next; ret = ret->next);
5340 ret->next = calloc(1, sizeof *ret);
5341 ret = ret->next;
5342 }
5343 LY_CHECK_ERR_RETURN(!ret, LOGMEM(ctx), NULL);
5344
5345 /* fill new attr except */
5346 ret->parent = parent;
5347 ret->annotation = attr->annotation;
5348 ret->name = lydict_insert(ctx, attr->name, 0);
5349 ret->value_str = lydict_insert(ctx, attr->value_str, 0);
5350 ret->value_type = attr->value_type;
5351 ret->value_flags = attr->value_flags;
5352 switch (ret->value_type) {
5353 case LY_TYPE_BINARY:
5354 case LY_TYPE_STRING:
5355 /* value_str pointer is shared in these cases */
5356 ret->value.string = ret->value_str;
5357 break;
5358 case LY_TYPE_LEAFREF:
5359 lyp_parse_value(*((struct lys_type **)lys_ext_complex_get_substmt(LY_STMT_TYPE, ret->annotation, NULL)),
5360 &ret->value_str, NULL, NULL, ret, NULL, 1, 0);
5361 break;
5362 case LY_TYPE_INST:
5363 ret->value.instance = NULL;
5364 break;
5365 case LY_TYPE_UNION:
5366 /* unresolved union (this must be non-validated tree), duplicate the stored string (duplicated
5367 * because of possible change of the value in case of instance-identifier) */
5368 ret->value.string = lydict_insert(ctx, attr->value.string, 0);
5369 break;
5370 case LY_TYPE_ENUM:
5371 case LY_TYPE_IDENT:
5372 case LY_TYPE_BITS:
5373 /* in case of duplicating bits (no matter if in the same context or not) or enum and identityref into
5374 * a different context, searching for the type and duplicating the data is almost as same as resolving
5375 * the string value, so due to a simplicity, parse the value for the duplicated leaf */
5376 lyp_parse_value(*((struct lys_type **)lys_ext_complex_get_substmt(LY_STMT_TYPE, ret->annotation, NULL)),
5377 &ret->value_str, NULL, NULL, ret, NULL, 1, 0);
5378 break;
5379 default:
5380 ret->value = attr->value;
5381 break;
5382 }
5383 return ret;
5384 }
5385
5386 int
lyd_unlink_internal(struct lyd_node * node,int permanent)5387 lyd_unlink_internal(struct lyd_node *node, int permanent)
5388 {
5389 struct lyd_node *iter;
5390 (void)permanent;
5391
5392 if (!node) {
5393 LOGARG;
5394 return EXIT_FAILURE;
5395 }
5396
5397 /* unlink from siblings */
5398 if (node->prev->next) {
5399 node->prev->next = node->next;
5400 }
5401 if (node->next) {
5402 node->next->prev = node->prev;
5403 } else {
5404 /* unlinking the last node */
5405 if (node->parent) {
5406 iter = node->parent->child;
5407 } else {
5408 iter = node->prev;
5409 while (iter->prev != node) {
5410 iter = iter->prev;
5411 }
5412 }
5413 /* update the "last" pointer from the first node */
5414 iter->prev = node->prev;
5415 }
5416
5417 /* unlink from parent */
5418 if (node->parent) {
5419 if (node->parent->child == node) {
5420 /* the node is the first child */
5421 node->parent->child = node->next;
5422 }
5423
5424 #ifdef LY_ENABLED_CACHE
5425 /* do not remove from parent hash table if freeing the whole subtree */
5426 if (permanent != 2) {
5427 lyd_unlink_hash(node, node->parent);
5428 }
5429 #endif
5430
5431 node->parent = NULL;
5432 }
5433
5434 node->next = NULL;
5435 node->prev = node;
5436
5437 return EXIT_SUCCESS;
5438 }
5439
5440 API int
lyd_unlink(struct lyd_node * node)5441 lyd_unlink(struct lyd_node *node)
5442 {
5443 FUN_IN;
5444
5445 return lyd_unlink_internal(node, 1);
5446 }
5447
5448 /*
5449 * - in leaflist it must be added with value_str
5450 */
5451 static int
_lyd_dup_node_common(struct lyd_node * new_node,const struct lyd_node * orig,struct ly_ctx * ctx,int options)5452 _lyd_dup_node_common(struct lyd_node *new_node, const struct lyd_node *orig, struct ly_ctx *ctx, int options)
5453 {
5454 struct lyd_attr *attr;
5455
5456 new_node->attr = NULL;
5457 if (!(options & LYD_DUP_OPT_NO_ATTR)) {
5458 LY_TREE_FOR(orig->attr, attr) {
5459 lyd_dup_attr(ctx, new_node, attr);
5460 }
5461 }
5462 new_node->next = NULL;
5463 new_node->prev = new_node;
5464 new_node->parent = NULL;
5465 new_node->validity = ly_new_node_validity(new_node->schema);
5466 new_node->dflt = orig->dflt;
5467 if (options & LYD_DUP_OPT_WITH_WHEN) {
5468 new_node->when_status = orig->when_status;
5469 } else {
5470 new_node->when_status = orig->when_status & LYD_WHEN;
5471 }
5472 #ifdef LY_ENABLED_CACHE
5473 /* just copy the hash, it will not change */
5474 if ((new_node->schema->nodetype != LYS_LIST) || lyd_list_has_keys(new_node)) {
5475 new_node->hash = orig->hash;
5476 }
5477 #endif
5478
5479 #ifdef LY_ENABLED_LYD_PRIV
5480 if (ctx->priv_dup_clb) {
5481 new_node->priv = ctx->priv_dup_clb(orig->priv);
5482 }
5483 #endif
5484
5485 return EXIT_SUCCESS;
5486 }
5487
5488 static struct lyd_node *
_lyd_dup_node(const struct lyd_node * node,const struct lys_node * schema,struct ly_ctx * ctx,int options)5489 _lyd_dup_node(const struct lyd_node *node, const struct lys_node *schema, struct ly_ctx *ctx, int options)
5490 {
5491 struct lyd_node *new_node = NULL;
5492 struct lys_node_leaf *sleaf;
5493 struct lyd_node_leaf_list *new_leaf;
5494 struct lyd_node_anydata *new_any, *old_any;
5495 const struct lys_type *type;
5496 int r;
5497
5498 /* fill specific part */
5499 switch (node->schema->nodetype) {
5500 case LYS_LEAF:
5501 case LYS_LEAFLIST:
5502 new_leaf = calloc(1, sizeof *new_leaf);
5503 new_node = (struct lyd_node *)new_leaf;
5504 LY_CHECK_ERR_GOTO(!new_node, LOGMEM(ctx), error);
5505 new_leaf->schema = (struct lys_node *)schema;
5506
5507 new_leaf->value_str = lydict_insert(ctx, ((struct lyd_node_leaf_list *)node)->value_str, 0);
5508 new_leaf->value_type = ((struct lyd_node_leaf_list *)node)->value_type;
5509 new_leaf->value_flags = ((struct lyd_node_leaf_list *)node)->value_flags;
5510 if (_lyd_dup_node_common(new_node, node, ctx, options)) {
5511 goto error;
5512 }
5513
5514 /* get schema from the correct context */
5515 sleaf = (struct lys_node_leaf *)new_leaf->schema;
5516
5517 switch (new_leaf->value_type) {
5518 case LY_TYPE_BINARY:
5519 case LY_TYPE_STRING:
5520 /* value_str pointer is shared in these cases */
5521 new_leaf->value.string = new_leaf->value_str;
5522 break;
5523 case LY_TYPE_LEAFREF:
5524 lyp_parse_value(&sleaf->type, &new_leaf->value_str, NULL, new_leaf, NULL, NULL, 1, node->dflt);
5525 break;
5526 case LY_TYPE_INST:
5527 new_leaf->value.instance = NULL;
5528 break;
5529 case LY_TYPE_UNION:
5530 /* unresolved union (this must be non-validated tree), duplicate the stored string (duplicated
5531 * because of possible change of the value in case of instance-identifier) */
5532 new_leaf->value.string = lydict_insert(ctx, ((struct lyd_node_leaf_list *)node)->value.string, 0);
5533 break;
5534 case LY_TYPE_ENUM:
5535 case LY_TYPE_IDENT:
5536 case LY_TYPE_BITS:
5537 /* in case of duplicating bits (no matter if in the same context or not) or enum and identityref into
5538 * a different context, searching for the type and duplicating the data is almost as same as resolving
5539 * the string value, so due to a simplicity, parse the value for the duplicated leaf */
5540 if (!lyp_parse_value(&sleaf->type, &new_leaf->value_str, NULL, new_leaf, NULL, NULL, 1, node->dflt)) {
5541 goto error;
5542 }
5543 break;
5544 default:
5545 new_leaf->value = ((struct lyd_node_leaf_list *)node)->value;
5546 break;
5547 }
5548
5549 if (new_leaf->value_flags & LY_VALUE_USER) {
5550 /* get the real type */
5551 type = lyd_leaf_type(new_leaf);
5552 if (!type || !type->der || !type->der->module) {
5553 LOGINT(ctx);
5554 goto error;
5555 }
5556
5557 r = lytype_store(type->der->module, type->der->name, &new_leaf->value_str, &new_leaf->value);
5558 if (r == -1) {
5559 goto error;
5560 } else if (r) {
5561 LOGINT(ctx);
5562 goto error;
5563 }
5564 }
5565 break;
5566 case LYS_ANYXML:
5567 case LYS_ANYDATA:
5568 old_any = (struct lyd_node_anydata *)node;
5569 new_any = calloc(1, sizeof *new_any);
5570 new_node = (struct lyd_node *)new_any;
5571 LY_CHECK_ERR_GOTO(!new_node, LOGMEM(ctx), error);
5572 new_any->schema = (struct lys_node *)schema;
5573
5574 if (_lyd_dup_node_common(new_node, node, ctx, options)) {
5575 goto error;
5576 }
5577
5578 new_any->value_type = old_any->value_type;
5579 if (!(void*)old_any->value.tree) {
5580 /* no value to duplicate */
5581 break;
5582 }
5583 /* duplicate the value */
5584 switch (old_any->value_type) {
5585 case LYD_ANYDATA_CONSTSTRING:
5586 case LYD_ANYDATA_SXML:
5587 case LYD_ANYDATA_JSON:
5588 new_any->value.str = lydict_insert(ctx, old_any->value.str, 0);
5589 break;
5590 case LYD_ANYDATA_DATATREE:
5591 new_any->value.tree = lyd_dup_withsiblings_to_ctx(old_any->value.tree, 1, ctx);
5592 break;
5593 case LYD_ANYDATA_XML:
5594 new_any->value.xml = lyxml_dup_elem(ctx, old_any->value.xml, NULL, 1, 1);
5595 break;
5596 case LYD_ANYDATA_LYB:
5597 r = lyd_lyb_data_length(old_any->value.mem);
5598 if (r == -1) {
5599 LOGERR(ctx, LY_EINVAL, "Invalid LYB data.");
5600 goto error;
5601 }
5602 new_any->value.mem = malloc(r);
5603 LY_CHECK_ERR_GOTO(!new_any->value.mem, LOGMEM(ctx), error);
5604 memcpy(new_any->value.mem, old_any->value.mem, r);
5605 break;
5606 case LYD_ANYDATA_STRING:
5607 case LYD_ANYDATA_SXMLD:
5608 case LYD_ANYDATA_JSOND:
5609 case LYD_ANYDATA_LYBD:
5610 /* dynamic strings are used only as input parameters */
5611 assert(0);
5612 break;
5613 }
5614 break;
5615 case LYS_CONTAINER:
5616 case LYS_LIST:
5617 case LYS_NOTIF:
5618 case LYS_RPC:
5619 case LYS_ACTION:
5620 new_node = calloc(1, sizeof *new_node);
5621 LY_CHECK_ERR_GOTO(!new_node, LOGMEM(ctx), error);
5622 new_node->schema = (struct lys_node *)schema;
5623
5624 if (_lyd_dup_node_common(new_node, node, ctx, options)) {
5625 goto error;
5626 }
5627 break;
5628 default:
5629 LOGINT(ctx);
5630 goto error;
5631 }
5632
5633 return new_node;
5634
5635 error:
5636 lyd_free(new_node);
5637 return NULL;
5638 }
5639
5640 static int
lyd_dup_keys(struct lyd_node * new_list,const struct lyd_node * old_list,struct lys_node * skip_key,struct ly_ctx * log_ctx,int options)5641 lyd_dup_keys(struct lyd_node *new_list, const struct lyd_node *old_list, struct lys_node *skip_key,
5642 struct ly_ctx *log_ctx, int options)
5643 {
5644 struct lys_node_list *slist;
5645 struct lyd_node *key, *key_dup;
5646 uint16_t i;
5647
5648 if (new_list->schema->nodetype != LYS_LIST) {
5649 return 0;
5650 }
5651
5652 slist = (struct lys_node_list *)new_list->schema;
5653 for (key = old_list->child, i = 0; key && (i < slist->keys_size); ++i, key = key->next) {
5654 if (key->schema != (struct lys_node *)slist->keys[i]) {
5655 LOGVAL(log_ctx, LYE_PATH_INKEY, LY_VLOG_LYD, new_list, slist->keys[i]->name);
5656 return -1;
5657 }
5658 if (key->schema == skip_key) {
5659 continue;
5660 }
5661
5662 key_dup = lyd_dup(key, options & LYD_DUP_OPT_NO_ATTR);
5663 LY_CHECK_ERR_RETURN(!key_dup, LOGMEM(log_ctx), -1);
5664
5665 if (lyd_insert(new_list, key_dup)) {
5666 lyd_free(key_dup);
5667 return -1;
5668 }
5669 }
5670 if (!key && (i < slist->keys_size)) {
5671 LOGVAL(log_ctx, LYE_PATH_INKEY, LY_VLOG_LYD, new_list, slist->keys[i]->name);
5672 return -1;
5673 }
5674
5675 return 0;
5676 }
5677
5678 API struct lyd_node *
lyd_dup_to_ctx(const struct lyd_node * node,int options,struct ly_ctx * ctx)5679 lyd_dup_to_ctx(const struct lyd_node *node, int options, struct ly_ctx *ctx)
5680 {
5681 FUN_IN;
5682
5683 struct ly_ctx *log_ctx;
5684 struct lys_node *schema;
5685 const char *yang_data_name;
5686 const struct lys_module *trg_mod;
5687 const struct lyd_node *next, *elem;
5688 struct lyd_node *ret, *parent, *new_node = NULL;
5689
5690 if (!node) {
5691 LOGARG;
5692 return NULL;
5693 }
5694
5695 /* fix options */
5696 if ((options & LYD_DUP_OPT_RECURSIVE) && (options & LYD_DUP_OPT_WITH_KEYS)) {
5697 options &= ~LYD_DUP_OPT_WITH_KEYS;
5698 }
5699
5700 log_ctx = (ctx ? ctx : node->schema->module->ctx);
5701 if (ctx == node->schema->module->ctx) {
5702 /* target context is actually the same as the source context,
5703 * ignore the target context */
5704 ctx = NULL;
5705 }
5706
5707 ret = NULL;
5708 parent = NULL;
5709
5710 /* LY_TREE_DFS */
5711 for (elem = next = node; elem; elem = next) {
5712
5713 /* find the correct schema */
5714 if (ctx) {
5715 schema = NULL;
5716 if (parent) {
5717 trg_mod = lyp_get_module(parent->schema->module, NULL, 0, lyd_node_module(elem)->name,
5718 strlen(lyd_node_module(elem)->name), 1);
5719 if (!trg_mod) {
5720 LOGERR(log_ctx, LY_EINVAL, "Target context does not contain model for the data node being duplicated (%s).",
5721 lyd_node_module(elem)->name);
5722 goto error;
5723 }
5724 /* we know its parent, so we can start with it */
5725 lys_getnext_data(trg_mod, parent->schema, elem->schema->name, strlen(elem->schema->name),
5726 elem->schema->nodetype, 0, (const struct lys_node **)&schema);
5727 } else {
5728 /* we have to search in complete context */
5729 schema = lyd_get_schema_inctx(elem, ctx);
5730 }
5731
5732 if (!schema) {
5733 yang_data_name = lyp_get_yang_data_template_name(elem);
5734 if (yang_data_name) {
5735 LOGERR(log_ctx, LY_EINVAL, "Target context does not contain schema node for the data node being duplicated "
5736 "(%s:#%s/%s).", lyd_node_module(elem)->name, yang_data_name, elem->schema->name);
5737 } else {
5738 LOGERR(log_ctx, LY_EINVAL, "Target context does not contain schema node for the data node being duplicated "
5739 "(%s:%s).", lyd_node_module(elem)->name, elem->schema->name);
5740 }
5741 goto error;
5742 }
5743 } else {
5744 schema = elem->schema;
5745 }
5746
5747 /* make node copy */
5748 new_node = _lyd_dup_node(elem, schema, log_ctx, options);
5749 if (!new_node) {
5750 goto error;
5751 }
5752
5753 if (parent && lyd_insert(parent, new_node)) {
5754 goto error;
5755 }
5756
5757 if (!ret) {
5758 ret = new_node;
5759 }
5760
5761 if (!(options & (LYD_DUP_OPT_RECURSIVE | LYD_DUP_OPT_WITH_KEYS))) {
5762 /* no more descendants copied */
5763 break;
5764 }
5765
5766 if (options & LYD_DUP_OPT_WITH_KEYS) {
5767 /* copy only descendant keys */
5768 if (lyd_dup_keys(new_node, elem, NULL, log_ctx, options)) {
5769 goto error;
5770 }
5771 break;
5772 }
5773
5774 /* LY_TREE_DFS_END */
5775 /* select element for the next run - children first,
5776 * child exception for lyd_node_leaf and lyd_node_leaflist */
5777 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5778 next = NULL;
5779 } else {
5780 next = elem->child;
5781 }
5782 if (!next) {
5783 if (elem->parent == node->parent) {
5784 break;
5785 }
5786 /* no children, so try siblings */
5787 next = elem->next;
5788 } else {
5789 parent = new_node;
5790 }
5791 new_node = NULL;
5792
5793 while (!next) {
5794 /* no siblings, go back through parents */
5795 elem = elem->parent;
5796 if (elem->parent == node->parent) {
5797 break;
5798 }
5799 if (!parent) {
5800 LOGINT(log_ctx);
5801 goto error;
5802 }
5803 parent = parent->parent;
5804 /* parent is already processed, go to its sibling */
5805 next = elem->next;
5806 }
5807 }
5808
5809 /* dup all the parents */
5810 if (options & LYD_DUP_OPT_WITH_PARENTS) {
5811 parent = ret;
5812 if (lys_is_key((struct lys_node_leaf *)ret->schema, NULL)) {
5813 /* this key was being duplicated so do not add it twice */
5814 schema = ret->schema;
5815 } else {
5816 schema = NULL;
5817 }
5818 for (elem = node->parent; elem; elem = elem->parent) {
5819 new_node = lyd_dup(elem, options & LYD_DUP_OPT_NO_ATTR);
5820 LY_CHECK_ERR_GOTO(!new_node, LOGMEM(log_ctx), error);
5821
5822 /* dup all list keys */
5823 if (lyd_dup_keys(new_node, elem, schema, log_ctx, options)) {
5824 goto error;
5825 }
5826
5827 /* link together */
5828 if (lyd_insert(new_node, parent)) {
5829 ret = parent;
5830 goto error;
5831 }
5832 parent = new_node;
5833 }
5834 }
5835
5836 return ret;
5837
5838 error:
5839 lyd_free(ret);
5840 return NULL;
5841 }
5842
5843 API struct lyd_node *
lyd_dup(const struct lyd_node * node,int options)5844 lyd_dup(const struct lyd_node *node, int options)
5845 {
5846 FUN_IN;
5847
5848 return lyd_dup_to_ctx(node, options, NULL);
5849 }
5850
5851 static struct lyd_node *
lyd_dup_withsiblings_r(const struct lyd_node * first,struct lyd_node * parent_dup,int options,struct ly_ctx * ctx)5852 lyd_dup_withsiblings_r(const struct lyd_node *first, struct lyd_node *parent_dup, int options, struct ly_ctx *ctx)
5853 {
5854 struct lyd_node *first_dup = NULL, *prev_dup = NULL, *last_dup;
5855 const struct lyd_node *next;
5856
5857 assert(first);
5858
5859 /* duplicate and connect all siblings */
5860 LY_TREE_FOR(first, next) {
5861 last_dup = _lyd_dup_node(next, next->schema, ctx, options);
5862 if (!last_dup) {
5863 goto error;
5864 }
5865
5866 /* the whole data tree is exactly the same so we can safely copy the validation flags */
5867 last_dup->validity = next->validity;
5868 last_dup->when_status = next->when_status;
5869
5870 last_dup->parent = parent_dup;
5871 /* connect to the parent or the siblings */
5872 if (!first_dup) {
5873 first_dup = last_dup;
5874 if (parent_dup) {
5875 parent_dup->child = first_dup;
5876 }
5877 } else {
5878 assert(prev_dup);
5879 prev_dup->next = last_dup;
5880 last_dup->prev = prev_dup;
5881 }
5882
5883 #ifdef LY_ENABLED_CACHE
5884 /* copy hash */
5885 if ((last_dup->schema->nodetype != LYS_LIST) || lyd_list_has_keys(last_dup)) {
5886 last_dup->hash = next->hash;
5887 }
5888
5889 /* insert into parent */
5890 lyd_insert_hash(last_dup);
5891 #endif
5892
5893 if ((next->schema->nodetype & (LYS_LIST | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF)) && next->child) {
5894 /* recursively duplicate all children */
5895 if (!lyd_dup_withsiblings_r(next->child, last_dup, options, ctx)) {
5896 goto error;
5897 }
5898 }
5899
5900 prev_dup = last_dup;
5901 }
5902
5903 /* correctly set last sibling */
5904 assert(!prev_dup->next);
5905 first_dup->prev = prev_dup;
5906
5907 return first_dup;
5908
5909 error:
5910 /* disconnect and free */
5911 if (first_dup) {
5912 first_dup->parent = NULL;
5913 lyd_free_withsiblings(first_dup);
5914 }
5915 return NULL;
5916 }
5917
5918 static struct lyd_node *
lyd_dup_withsiblings_to_ctx(const struct lyd_node * node,int options,struct ly_ctx * ctx)5919 lyd_dup_withsiblings_to_ctx(const struct lyd_node *node, int options, struct ly_ctx *ctx)
5920 {
5921 const struct lyd_node *iter;
5922 struct lyd_node *ret, *ret_iter, *tmp;
5923
5924 if (!node) {
5925 return NULL;
5926 }
5927
5928 /* find first sibling */
5929 while (node->prev->next) {
5930 node = node->prev;
5931 }
5932
5933 if (node->parent) {
5934 ret = lyd_dup_to_ctx(node, options, ctx);
5935 if (!ret) {
5936 return NULL;
5937 }
5938
5939 /* copy following siblings */
5940 ret_iter = ret;
5941 LY_TREE_FOR(node->next, iter) {
5942 tmp = lyd_dup_to_ctx(iter, options, ctx);
5943 if (!tmp) {
5944 lyd_free_withsiblings(ret);
5945 return NULL;
5946 }
5947
5948 if (lyd_insert_after(ret_iter, tmp)) {
5949 lyd_free_withsiblings(ret);
5950 return NULL;
5951 }
5952 ret_iter = ret_iter->next;
5953 assert(ret_iter == tmp);
5954 }
5955 } else {
5956 /* duplicating top-level siblings, we can duplicate much more efficiently */
5957 ret = lyd_dup_withsiblings_r(node, NULL, options, ctx);
5958 }
5959
5960 return ret;
5961 }
5962
5963 API struct lyd_node *
lyd_dup_withsiblings(const struct lyd_node * node,int options)5964 lyd_dup_withsiblings(const struct lyd_node *node, int options)
5965 {
5966 FUN_IN;
5967
5968 if (!node) {
5969 return NULL;
5970 }
5971
5972 return lyd_dup_withsiblings_to_ctx(node, options, lyd_node_module(node)->ctx);
5973 }
5974
5975 API void
lyd_free_attr(struct ly_ctx * ctx,struct lyd_node * parent,struct lyd_attr * attr,int recursive)5976 lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
5977 {
5978 FUN_IN;
5979
5980 struct lyd_attr *iter;
5981 struct lys_type **type;
5982
5983 if (!ctx || !attr) {
5984 return;
5985 }
5986
5987 if (parent) {
5988 if (parent->attr == attr) {
5989 if (recursive) {
5990 parent->attr = NULL;
5991 } else {
5992 parent->attr = attr->next;
5993 }
5994 } else {
5995 for (iter = parent->attr; iter->next != attr; iter = iter->next);
5996 if (iter->next) {
5997 if (recursive) {
5998 iter->next = NULL;
5999 } else {
6000 iter->next = attr->next;
6001 }
6002 }
6003 }
6004 }
6005
6006 if (!recursive) {
6007 attr->next = NULL;
6008 }
6009
6010 for(iter = attr; iter; ) {
6011 attr = iter;
6012 iter = iter->next;
6013
6014 lydict_remove(ctx, attr->name);
6015 type = lys_ext_complex_get_substmt(LY_STMT_TYPE, attr->annotation, NULL);
6016 assert(type);
6017 lyd_free_value(attr->value, attr->value_type, attr->value_flags, *type, attr->value_str, NULL, NULL, NULL);
6018 lydict_remove(ctx, attr->value_str);
6019 free(attr);
6020 }
6021 }
6022
6023 const struct lyd_node *
lyd_attr_parent(const struct lyd_node * root,struct lyd_attr * attr)6024 lyd_attr_parent(const struct lyd_node *root, struct lyd_attr *attr)
6025 {
6026 const struct lyd_node *next, *elem;
6027 struct lyd_attr *node_attr;
6028
6029 LY_TREE_DFS_BEGIN(root, next, elem) {
6030 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
6031 if (node_attr == attr) {
6032 return elem;
6033 }
6034 }
6035 LY_TREE_DFS_END(root, next, elem)
6036 }
6037
6038 return NULL;
6039 }
6040
6041 API struct lyd_attr *
lyd_insert_attr(struct lyd_node * parent,const struct lys_module * mod,const char * name,const char * value)6042 lyd_insert_attr(struct lyd_node *parent, const struct lys_module *mod, const char *name, const char *value)
6043 {
6044 FUN_IN;
6045
6046 struct lyd_attr *a, *iter;
6047 struct ly_ctx *ctx;
6048 const struct lys_module *module;
6049 const char *p;
6050 char *aux;
6051 int pos, i;
6052
6053 if (!parent || !name || !value) {
6054 LOGARG;
6055 return NULL;
6056 }
6057 ctx = parent->schema->module->ctx;
6058
6059 if ((p = strchr(name, ':'))) {
6060 /* search for the namespace */
6061 aux = strndup(name, p - name);
6062 if (!aux) {
6063 LOGMEM(ctx);
6064 return NULL;
6065 }
6066 module = ly_ctx_get_module(ctx, aux, NULL, 1);
6067 free(aux);
6068 name = p + 1;
6069
6070 if (!module) {
6071 /* module not found */
6072 LOGERR(ctx, LY_EINVAL, "Attribute prefix does not match any implemented schema in the context.");
6073 return NULL;
6074 }
6075 } else if (mod) {
6076 module = mod;
6077 } else if (!mod && (!strcmp(name, "type") || !strcmp(name, "select")) && !strcmp(parent->schema->name, "filter")) {
6078 /* special case of inserting unqualified filter attributes "type" and "select" */
6079 module = ly_ctx_get_module(ctx, "ietf-netconf", NULL, 1);
6080 if (!module) {
6081 LOGERR(ctx, LY_EINVAL, "Attribute prefix does not match any implemented schema in the context.");
6082 return NULL;
6083 }
6084 } else {
6085 /* no prefix -> module is the same as for the parent */
6086 module = lyd_node_module(parent);
6087 }
6088
6089 pos = -1;
6090 do {
6091 if ((unsigned int)(pos + 1) < module->ext_size) {
6092 i = lys_ext_instance_presence(&ctx->models.list[0]->extensions[0],
6093 &module->ext[pos + 1], module->ext_size - (pos + 1));
6094 pos = (i == -1) ? -1 : pos + 1 + i;
6095 } else {
6096 pos = -1;
6097 }
6098 if (pos == -1) {
6099 LOGERR(ctx, LY_EINVAL, "Attribute does not match any annotation instance definition.");
6100 return NULL;
6101 }
6102 } while (!ly_strequal(module->ext[pos]->arg_value, name, 0));
6103
6104 a = calloc(1, sizeof *a);
6105 LY_CHECK_ERR_RETURN(!a, LOGMEM(ctx), NULL);
6106 a->parent = parent;
6107 a->next = NULL;
6108 a->annotation = (struct lys_ext_instance_complex *)module->ext[pos];
6109 a->name = lydict_insert(ctx, name, 0);
6110 a->value_str = lydict_insert(ctx, value, 0);
6111 if (!lyp_parse_value(*((struct lys_type **)lys_ext_complex_get_substmt(LY_STMT_TYPE, a->annotation, NULL)),
6112 &a->value_str, NULL, NULL, a, NULL, 1, 0)) {
6113 lyd_free_attr(ctx, NULL, a, 0);
6114 return NULL;
6115 }
6116
6117 if (!parent->attr) {
6118 parent->attr = a;
6119 } else {
6120 for (iter = parent->attr; iter->next; iter = iter->next);
6121 iter->next = a;
6122 }
6123
6124 return a;
6125 }
6126
6127 void
lyd_free_value(lyd_val value,LY_DATA_TYPE value_type,uint8_t value_flags,struct lys_type * type,const char * value_str,lyd_val * old_val,LY_DATA_TYPE * old_val_type,uint8_t * old_val_flags)6128 lyd_free_value(lyd_val value, LY_DATA_TYPE value_type, uint8_t value_flags, struct lys_type *type, const char *value_str,
6129 lyd_val *old_val, LY_DATA_TYPE *old_val_type, uint8_t *old_val_flags)
6130 {
6131 if (old_val) {
6132 *old_val = value;
6133 *old_val_type = value_type;
6134 *old_val_flags = value_flags;
6135 /* we only backup the values for now */
6136 return;
6137 }
6138
6139 /* otherwise the value is correctly freed */
6140 if (value_flags & LY_VALUE_USER) {
6141 lytype_free(type, value, value_str);
6142 } else {
6143 switch (value_type) {
6144 case LY_TYPE_BITS:
6145 if (value.bit) {
6146 free(value.bit);
6147 }
6148 break;
6149 case LY_TYPE_INST:
6150 if (!(value_flags & LY_VALUE_UNRES)) {
6151 break;
6152 }
6153 /* fallthrough */
6154 case LY_TYPE_UNION:
6155 /* unresolved union leaf */
6156 lydict_remove(type->parent->module->ctx, value.string);
6157 break;
6158 default:
6159 break;
6160 }
6161 }
6162 }
6163
6164 static void
_lyd_free_node(struct lyd_node * node)6165 _lyd_free_node(struct lyd_node *node)
6166 {
6167 struct lyd_node_leaf_list *leaf;
6168
6169 if (!node) {
6170 return;
6171 }
6172
6173 switch (node->schema->nodetype) {
6174 case LYS_CONTAINER:
6175 case LYS_LIST:
6176 case LYS_RPC:
6177 case LYS_ACTION:
6178 case LYS_NOTIF:
6179 #ifdef LY_ENABLED_CACHE
6180 /* it should be empty because all the children are freed already (only if in debug mode) */
6181 lyht_free(node->ht);
6182 #endif
6183 break;
6184 case LYS_ANYDATA:
6185 case LYS_ANYXML:
6186 switch (((struct lyd_node_anydata *)node)->value_type) {
6187 case LYD_ANYDATA_CONSTSTRING:
6188 case LYD_ANYDATA_SXML:
6189 case LYD_ANYDATA_JSON:
6190 lydict_remove(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.str);
6191 break;
6192 case LYD_ANYDATA_DATATREE:
6193 lyd_free_withsiblings(((struct lyd_node_anydata *)node)->value.tree);
6194 break;
6195 case LYD_ANYDATA_XML:
6196 lyxml_free_withsiblings(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.xml);
6197 break;
6198 case LYD_ANYDATA_LYB:
6199 free(((struct lyd_node_anydata *)node)->value.mem);
6200 break;
6201 case LYD_ANYDATA_STRING:
6202 case LYD_ANYDATA_SXMLD:
6203 case LYD_ANYDATA_JSOND:
6204 case LYD_ANYDATA_LYBD:
6205 /* dynamic strings are used only as input parameters */
6206 assert(0);
6207 break;
6208 }
6209 break;
6210 case LYS_LEAF:
6211 case LYS_LEAFLIST:
6212 leaf = (struct lyd_node_leaf_list *)node;
6213 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type,
6214 leaf->value_str, NULL, NULL, NULL);
6215 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
6216 break;
6217 default:
6218 assert(0);
6219 }
6220
6221 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
6222 free(node);
6223 }
6224
6225 static void
lyd_free_internal_r(struct lyd_node * node,int top)6226 lyd_free_internal_r(struct lyd_node *node, int top)
6227 {
6228 struct lyd_node *next, *iter;
6229
6230 if (!node) {
6231 return;
6232 }
6233
6234 /* if freeing top-level, always remove it from the parent hash table */
6235 lyd_unlink_internal(node, (top ? 1 : 2));
6236
6237 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6238 /* free children */
6239 LY_TREE_FOR_SAFE(node->child, next, iter) {
6240 lyd_free_internal_r(iter, 0);
6241 }
6242 }
6243
6244 _lyd_free_node(node);
6245 }
6246
6247 API void
lyd_free(struct lyd_node * node)6248 lyd_free(struct lyd_node *node)
6249 {
6250 FUN_IN;
6251
6252 lyd_free_internal_r(node, 1);
6253 }
6254
6255 static void
lyd_free_withsiblings_r(struct lyd_node * first)6256 lyd_free_withsiblings_r(struct lyd_node *first)
6257 {
6258 struct lyd_node *next, *node;
6259
6260 LY_TREE_FOR_SAFE(first, next, node) {
6261 if (node->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
6262 lyd_free_withsiblings_r(node->child);
6263 }
6264 _lyd_free_node(node);
6265 }
6266 }
6267
6268 API void
lyd_free_withsiblings(struct lyd_node * node)6269 lyd_free_withsiblings(struct lyd_node *node)
6270 {
6271 FUN_IN;
6272
6273 struct lyd_node *iter, *aux;
6274
6275 if (!node) {
6276 return;
6277 }
6278
6279 if (node->parent) {
6280 /* optimization - avoid freeing (unlinking) the last node of the siblings list */
6281 /* so, first, free the node's predecessors to the beginning of the list ... */
6282 for(iter = node->prev; iter->next; iter = aux) {
6283 aux = iter->prev;
6284 lyd_free(iter);
6285 }
6286 /* ... then, the node is the first in the siblings list, so free them all */
6287 LY_TREE_FOR_SAFE(node, aux, iter) {
6288 lyd_free(iter);
6289 }
6290 } else {
6291 /* node is top-level so we are freeing the whole data tree, we can just free nodes without any unlinking */
6292 while (node->prev->next) {
6293 /* find the first sibling */
6294 node = node->prev;
6295 }
6296
6297 /* free it all */
6298 lyd_free_withsiblings_r(node);
6299 }
6300 }
6301
6302 /**
6303 * Expectations:
6304 * - list exists in data tree
6305 * - the leaf (defined by the unique_expr) is not instantiated under the list
6306 */
6307 int
lyd_get_unique_default(const char * unique_expr,struct lyd_node * list,const char ** dflt)6308 lyd_get_unique_default(const char* unique_expr, struct lyd_node *list, const char **dflt)
6309 {
6310 struct ly_ctx *ctx = list->schema->module->ctx;
6311 const struct lys_node *parent;
6312 const struct lys_node_leaf *sleaf = NULL;
6313 struct lys_tpdf *tpdf;
6314 struct lyd_node *last, *node;
6315 struct ly_set *s, *r;
6316 unsigned int i;
6317 enum int_log_opts prev_ilo;
6318
6319 assert(unique_expr && list && dflt);
6320 *dflt = NULL;
6321
6322 if (resolve_descendant_schema_nodeid(unique_expr, list->schema->child, LYS_LEAF, 1, &parent) || !parent) {
6323 /* error, but unique expression was checked when the schema was parsed so this should not happened */
6324 LOGINT(ctx);
6325 return -1;
6326 }
6327
6328 sleaf = (struct lys_node_leaf *)parent;
6329 if (sleaf->dflt) {
6330 /* leaf has a default value */
6331 *dflt = sleaf->dflt;
6332 } else if (!(sleaf->flags & LYS_MAND_TRUE)) {
6333 /* get the default value from the type */
6334 for (tpdf = sleaf->type.der; tpdf && !(*dflt); tpdf = tpdf->type.der) {
6335 *dflt = tpdf->dflt;
6336 }
6337 }
6338
6339 if (!(*dflt)) {
6340 return 0;
6341 }
6342
6343 /* it has default value, but check if it can appear in the data tree under the list */
6344 s = ly_set_new();
6345 for (parent = lys_parent((struct lys_node *)sleaf); parent != list->schema; parent = lys_parent(parent)) {
6346 if (!(parent->nodetype & (LYS_CONTAINER | LYS_CASE | LYS_CHOICE | LYS_USES))) {
6347 /* This should be already detected when parsing schema */
6348 LOGINT(ctx);
6349 ly_set_free(s);
6350 return -1;
6351 }
6352 ly_set_add(s, (void *)parent, LY_SET_OPT_USEASLIST);
6353 }
6354
6355 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
6356 for (i = 0, last = list; i < s->number; i++) {
6357 parent = s->set.s[i]; /* shortcut */
6358
6359 switch (parent->nodetype) {
6360 case LYS_CONTAINER:
6361 if (last) {
6362 /* find instance in the data */
6363 r = lyd_find_path(last, parent->name);
6364 if (!r || r->number > 1) {
6365 ly_set_free(r);
6366 *dflt = NULL;
6367 goto end;
6368 }
6369 if (r->number) {
6370 last = r->set.d[0];
6371 } else {
6372 last = NULL;
6373 }
6374 ly_set_free(r);
6375 }
6376 if (((struct lys_node_container *)parent)->presence) {
6377 /* not-instantiated presence container on path */
6378 *dflt = NULL;
6379 goto end;
6380 }
6381 break;
6382 case LYS_CHOICE :
6383 /* check presence of another case */
6384 if (!last) {
6385 continue;
6386 }
6387
6388 /* remember the case to be searched in choice by lyv_multicases() */
6389 if (i + 1 == s->number) {
6390 parent = (struct lys_node *)sleaf;
6391 } else if (s->set.s[i + 1]->nodetype == LYS_CASE && (i + 2 < s->number) &&
6392 s->set.s[i + 2]->nodetype == LYS_CHOICE) {
6393 /* nested choices are covered by lyv_multicases, we just have to pass
6394 * the lowest choice */
6395 i++;
6396 continue;
6397 } else {
6398 parent = s->set.s[i + 1];
6399 }
6400 node = last->child;
6401 if (lyv_multicases(NULL, (struct lys_node *)parent, &node, 0, NULL)) {
6402 /* another case is present */
6403 *dflt = NULL;
6404 goto end;
6405 }
6406 break;
6407 default:
6408 /* LYS_CASE, LYS_USES */
6409 continue;
6410 }
6411 }
6412
6413 end:
6414 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
6415 ly_set_free(s);
6416 return 0;
6417 }
6418
6419 API char *
lyd_path(const struct lyd_node * node)6420 lyd_path(const struct lyd_node *node)
6421 {
6422 FUN_IN;
6423
6424 char *buf = NULL;
6425
6426 if (!node) {
6427 LOGARG;
6428 return NULL;
6429 }
6430
6431 if (ly_vlog_build_path(LY_VLOG_LYD, node, &buf, 0, 0)) {
6432 return NULL;
6433 }
6434
6435 return buf;
6436 }
6437
6438 int
lyd_build_relative_data_path(const struct lys_module * module,const struct lyd_node * node,const char * schema_id,char * buf)6439 lyd_build_relative_data_path(const struct lys_module *module, const struct lyd_node *node, const char *schema_id,
6440 char *buf)
6441 {
6442 const struct lys_node *snode, *schema;
6443 const char *mod_name, *name;
6444 int mod_name_len, name_len, len = 0;
6445 int r, is_relative = -1;
6446
6447 assert(schema_id && buf);
6448 schema = node->schema;
6449
6450 while (*schema_id) {
6451 if ((r = parse_schema_nodeid(schema_id, &mod_name, &mod_name_len, &name, &name_len, &is_relative, NULL, NULL, 0)) < 1) {
6452 LOGINT(module->ctx);
6453 return -1;
6454 }
6455 schema_id += r;
6456
6457 snode = NULL;
6458 while ((snode = lys_getnext(snode, schema, NULL, LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_NOSTATECHECK))) {
6459 r = schema_nodeid_siblingcheck(snode, module, mod_name, mod_name_len, name, name_len);
6460 if (r == 0) {
6461 schema = snode;
6462 break;
6463 } else if (r == 1) {
6464 continue;
6465 } else {
6466 return -1;
6467 }
6468 }
6469 /* no match */
6470 if (!snode || (!schema_id[0] && snode->nodetype != LYS_LEAF)) {
6471 LOGINT(module->ctx);
6472 return -1;
6473 }
6474
6475 if (!(snode->nodetype & (LYS_CHOICE | LYS_CASE))) {
6476 len += sprintf(&buf[len], "%s%s", (len ? "/" : ""), snode->name);
6477 }
6478 }
6479
6480 return len;
6481 }
6482
6483 API struct ly_set *
lyd_find_path(const struct lyd_node * ctx_node,const char * path)6484 lyd_find_path(const struct lyd_node *ctx_node, const char *path)
6485 {
6486 FUN_IN;
6487
6488 struct lyxp_set xp_set;
6489 struct ly_set *set;
6490 char *yang_xpath;
6491 const char * node_mod_name, *mod_name, *name;
6492 int mod_name_len, name_len, is_relative = -1;
6493 uint32_t i;
6494
6495 if (!ctx_node || !path) {
6496 LOGARG;
6497 return NULL;
6498 }
6499
6500 if (parse_schema_nodeid(path, &mod_name, &mod_name_len, &name, &name_len, &is_relative, NULL, NULL, 1) > 0) {
6501 if (name[0] == '#' && !is_relative) {
6502 node_mod_name = lyd_node_module(ctx_node)->name;
6503 if (strncmp(mod_name, node_mod_name, mod_name_len) || node_mod_name[mod_name_len]) {
6504 return NULL;
6505 }
6506 path = name + name_len;
6507 }
6508 }
6509
6510 /* transform JSON into YANG XPATH */
6511 yang_xpath = transform_json2xpath(lyd_node_module(ctx_node), path);
6512 if (!yang_xpath) {
6513 return NULL;
6514 }
6515
6516 memset(&xp_set, 0, sizeof xp_set);
6517
6518 if (lyxp_eval(yang_xpath, ctx_node, LYXP_NODE_ELEM, lyd_node_module(ctx_node), &xp_set, 0) != EXIT_SUCCESS) {
6519 free(yang_xpath);
6520 return NULL;
6521 }
6522 free(yang_xpath);
6523
6524 set = ly_set_new();
6525 LY_CHECK_ERR_RETURN(!set, LOGMEM(ctx_node->schema->module->ctx), NULL);
6526
6527 if (xp_set.type == LYXP_SET_NODE_SET) {
6528 for (i = 0; i < xp_set.used; ++i) {
6529 if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
6530 if (ly_set_add(set, xp_set.val.nodes[i].node, LY_SET_OPT_USEASLIST) < 0) {
6531 ly_set_free(set);
6532 set = NULL;
6533 break;
6534 }
6535 }
6536 }
6537 }
6538 /* free xp_set content */
6539 lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, ctx_node, NULL, 0);
6540
6541 return set;
6542 }
6543
6544 API struct ly_set *
lyd_find_instance(const struct lyd_node * data,const struct lys_node * schema)6545 lyd_find_instance(const struct lyd_node *data, const struct lys_node *schema)
6546 {
6547 FUN_IN;
6548
6549 struct ly_set *ret, *ret_aux, *spath;
6550 const struct lys_node *siter;
6551 struct lyd_node *iter;
6552 unsigned int i, j;
6553
6554 if (!data || !schema ||
6555 !(schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION))) {
6556 LOGARG;
6557 return NULL;
6558 }
6559
6560 ret = ly_set_new();
6561 spath = ly_set_new();
6562 if (!ret || !spath) {
6563 LOGMEM(schema->module->ctx);
6564 goto error;
6565 }
6566
6567 /* find data root */
6568 while (data->parent) {
6569 /* vertical move (up) */
6570 data = data->parent;
6571 }
6572 while (data->prev->next) {
6573 /* horizontal move (left) */
6574 data = data->prev;
6575 }
6576
6577 /* build schema path */
6578 for (siter = schema; siter; ) {
6579 if (siter->nodetype == LYS_AUGMENT) {
6580 siter = ((struct lys_node_augment *)siter)->target;
6581 continue;
6582 } else if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
6583 /* standard data node */
6584 ly_set_add(spath, (void*)siter, LY_SET_OPT_USEASLIST);
6585
6586 } /* else skip the rest node types */
6587 siter = siter->parent;
6588 }
6589 if (!spath->number) {
6590 /* no valid path */
6591 goto error;
6592 }
6593
6594 /* start searching */
6595 LY_TREE_FOR((struct lyd_node *)data, iter) {
6596 if (iter->schema == spath->set.s[spath->number - 1]) {
6597 ly_set_add(ret, iter, LY_SET_OPT_USEASLIST);
6598 }
6599 }
6600 for (i = spath->number - 1; i; i--) {
6601 if (!ret->number) {
6602 /* nothing found */
6603 break;
6604 }
6605
6606 ret_aux = ly_set_new();
6607 if (!ret_aux) {
6608 LOGMEM(schema->module->ctx);
6609 goto error;
6610 }
6611 for (j = 0; j < ret->number; j++) {
6612 LY_TREE_FOR(ret->set.d[j]->child, iter) {
6613 if (iter->schema == spath->set.s[i - 1]) {
6614 ly_set_add(ret_aux, iter, LY_SET_OPT_USEASLIST);
6615 }
6616 }
6617 }
6618 ly_set_free(ret);
6619 ret = ret_aux;
6620 }
6621
6622 ly_set_free(spath);
6623 return ret;
6624
6625 error:
6626 ly_set_free(ret);
6627 ly_set_free(spath);
6628
6629 return NULL;
6630 }
6631
6632 API int
lyd_find_sibling(const struct lyd_node * siblings,const struct lyd_node * target,struct lyd_node ** match)6633 lyd_find_sibling(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
6634 {
6635 /* argument checks */
6636 if (!target || !match) {
6637 LOGARG;
6638 return -1;
6639 }
6640 if (target->schema->nodetype == LYS_LIST) {
6641 if (!((struct lys_node_list *)target->schema)->keys_size) {
6642 LOGERR(lyd_node_module(target)->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
6643 return -1;
6644 } else if (!lyd_list_has_keys((struct lyd_node *)target)) {
6645 LOGERR(lyd_node_module(target)->ctx, LY_EINVAL, "Invalid arguments - list without keys (%s()).", __func__);
6646 return -1;
6647 }
6648 }
6649 if ((target->schema->nodetype == LYS_LEAFLIST) && !(target->schema->flags & LYS_CONFIG_W)) {
6650 LOGERR(lyd_node_module(target)->ctx, LY_EINVAL, "Invalid arguments - non-configuration leaf-list (%s()).", __func__);
6651 return -1;
6652 }
6653
6654 if (!siblings) {
6655 /* no data */
6656 *match = NULL;
6657 return 0;
6658 }
6659
6660 /* find first sibling */
6661 if (siblings->parent) {
6662 siblings = siblings->parent->child;
6663 } else {
6664 while (siblings->prev->next) {
6665 siblings = siblings->prev;
6666 }
6667 }
6668
6669 #ifdef LY_ENABLED_CACHE
6670 struct lyd_node **match_p;
6671
6672 if (siblings->parent && siblings->parent->ht) {
6673 assert(target->hash);
6674
6675 /* find by hash */
6676 if (!lyht_find(siblings->parent->ht, &target, target->hash, (void **)&match_p)) {
6677 siblings = *match_p;
6678 } else {
6679 /* not found */
6680 siblings = NULL;
6681 }
6682 } else
6683 #endif
6684 {
6685 /* no hashes or no hash table */
6686 for (; siblings; siblings = siblings->next) {
6687 if (siblings->schema != target->schema) {
6688 continue;
6689 }
6690
6691 if (target->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
6692 if (lyd_list_equal((struct lyd_node *)target, (struct lyd_node *)siblings, 0)) {
6693 /* a match */
6694 break;
6695 }
6696 } else {
6697 /* schema match is enough for other nodes */
6698 break;
6699 }
6700 }
6701 }
6702
6703 *match = (struct lyd_node *)siblings;
6704 return 0;
6705 }
6706
6707 API int
lyd_find_sibling_set(const struct lyd_node * siblings,const struct lyd_node * target,struct ly_set ** set)6708 lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
6709 {
6710 struct lyd_node *match;
6711
6712 /* argument checks */
6713 if (!target || !set) {
6714 LOGARG;
6715 return -1;
6716 }
6717
6718 *set = ly_set_new();
6719 LY_CHECK_ERR_RETURN(!*set, LOGMEM(lyd_node_module(target)->ctx), -1);
6720
6721 if (!siblings) {
6722 /* no data */
6723 return 0;
6724 }
6725
6726 /* find first sibling */
6727 if (siblings->parent) {
6728 siblings = siblings->parent->child;
6729 } else {
6730 while (siblings->prev->next) {
6731 siblings = siblings->prev;
6732 }
6733 }
6734
6735 if (((target->schema->nodetype == LYS_LIST) && !((struct lys_node_list *)target->schema)->keys_size)
6736 || ((target->schema->nodetype == LYS_LEAFLIST) && !(target->schema->flags & LYS_CONFIG_W))) {
6737
6738 /* handle key-less lists and state leaf-lists ourselves because there can be more matching instances */
6739 #ifdef LY_ENABLED_CACHE
6740 struct lyd_node **match_p;
6741
6742 if (siblings->parent && siblings->parent->ht) {
6743 assert(target->hash);
6744
6745 /* find by hash */
6746 if (!lyht_find(siblings->parent->ht, &target, target->hash, (void **)&match_p)) {
6747 match = *match_p;
6748 } else {
6749 /* not found */
6750 match = NULL;
6751 }
6752 while (match) {
6753 /* add all found nodes into the set */
6754 if (ly_set_add(*set, match, LY_SET_OPT_USEASLIST) == -1) {
6755 goto error;
6756 }
6757
6758 /* find next instance */
6759 if (lyht_find_next(siblings->parent->ht, &match, match->hash, (void **)&match_p)) {
6760 match = NULL;
6761 } else {
6762 match = *match_p;
6763 }
6764 }
6765 } else
6766 #endif
6767 {
6768 /* no hashes or no hash table */
6769 for (; siblings; siblings = siblings->next) {
6770 if (siblings->schema != target->schema) {
6771 continue;
6772 }
6773
6774 if (lyd_list_equal((struct lyd_node *)target, (struct lyd_node *)siblings, 0)) {
6775 /* a match */
6776 if (ly_set_add(*set, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
6777 goto error;
6778 }
6779 }
6780 }
6781 }
6782 } else {
6783 /* use another function */
6784 if (lyd_find_sibling(siblings, target, &match)) {
6785 goto error;
6786 }
6787 if (match && (ly_set_add(*set, match, LY_SET_OPT_USEASLIST) == -1)) {
6788 goto error;
6789 }
6790 }
6791
6792 return 0;
6793
6794 error:
6795 ly_set_free(*set);
6796 return -1;
6797 }
6798
6799 static char *
lyd_find_sibling_val_key_value(char ** next_key,struct lys_node * key)6800 lyd_find_sibling_val_key_value(char **next_key, struct lys_node *key)
6801 {
6802 char *ptr, *ptr2, *val, quot;
6803
6804 ptr = *next_key;
6805
6806 /* "[" */
6807 if (ptr[0] != '[') {
6808 goto error;
6809 }
6810 ++ptr;
6811
6812 /* optional module name, we are not checking it */
6813 for (ptr2 = ptr; ptr2[0] && (ptr2[0] != '=') && (ptr2[0] != ':'); ++ptr2);
6814 if (!ptr2[0]) {
6815 goto error;
6816 } else if (ptr2[0] == ':') {
6817 ptr = ptr2 + 1;
6818 }
6819
6820 /* key name */
6821 if (strncmp(ptr, key->name, strlen(key->name))) {
6822 goto error;
6823 }
6824 ptr += strlen(key->name);
6825
6826 /* "=" */
6827 if (ptr[0] != '=') {
6828 goto error;
6829 }
6830 ++ptr;
6831
6832 /* quote */
6833 if ((ptr[0] != '\'') && (ptr[0] != '\"')) {
6834 goto error;
6835 }
6836 quot = ptr[0];
6837 ++ptr;
6838
6839 /* value, terminate it */
6840 val = ptr;
6841 if (!(ptr2 = strchr(ptr, quot))) {
6842 goto error;
6843 }
6844 ptr2[0] = '\0';
6845
6846 /* \0, was quote */
6847 ptr = ptr2 + 1;
6848
6849 /* "]" */
6850 if (ptr[0] != ']') {
6851 goto error;
6852 }
6853 ++ptr;
6854
6855 *next_key = ptr;
6856 return val;
6857
6858 error:
6859 LOGERR(lys_node_module(key)->ctx, LY_EINVAL, "Invalid arguments - keys at \"%s\" (%s()).",
6860 ptr, __func__);
6861 return NULL;
6862 }
6863
6864 API int
lyd_find_sibling_val(const struct lyd_node * siblings,const struct lys_node * schema,const char * key_or_value,struct lyd_node ** match)6865 lyd_find_sibling_val(const struct lyd_node *siblings, const struct lys_node *schema, const char *key_or_value,
6866 struct lyd_node **match)
6867 {
6868 struct lyd_node *target = NULL, *node;
6869 struct lys_node *key;
6870 uint8_t i;
6871 char *keys = NULL, *val, *next_key;
6872
6873 /* argument checks */
6874 if (!schema) {
6875 LOGARG;
6876 return -1;
6877 }
6878 switch (schema->nodetype) {
6879 case LYS_CONTAINER:
6880 case LYS_LEAF:
6881 case LYS_ANYXML:
6882 case LYS_ANYDATA:
6883 case LYS_NOTIF:
6884 case LYS_RPC:
6885 case LYS_ACTION:
6886 /* no argument check necessary */
6887 break;
6888 case LYS_LEAFLIST:
6889 if (!(schema->flags & LYS_CONFIG_W)) {
6890 LOGERR(lys_node_module(schema)->ctx, LY_EINVAL, "Invalid arguments - non-configuration leaf-list (%s()).", __func__);
6891 return -1;
6892 } else if (!key_or_value) {
6893 LOGERR(lys_node_module(schema)->ctx, LY_EINVAL, "Invalid arguments - no value for a leaf-list (%s()).", __func__);
6894 return -1;
6895 }
6896 break;
6897 case LYS_LIST:
6898 if (!((struct lys_node_list *)schema)->keys_size) {
6899 LOGERR(lys_node_module(schema)->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
6900 return -1;
6901 } else if (!key_or_value) {
6902 LOGERR(lys_node_module(schema)->ctx, LY_EINVAL, "Invalid arguments - no keys for a list (%s()).", __func__);
6903 return -1;
6904 }
6905 break;
6906 default:
6907 LOGERR(lys_node_module(schema)->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
6908 strnodetype(schema->nodetype), __func__);
6909 return -1;
6910 }
6911
6912 if (!siblings) {
6913 /* no data */
6914 *match = NULL;
6915 return 0;
6916 }
6917
6918 /* create data node */
6919 switch (schema->nodetype) {
6920 case LYS_CONTAINER:
6921 case LYS_ANYXML:
6922 case LYS_ANYDATA:
6923 case LYS_NOTIF:
6924 case LYS_RPC:
6925 case LYS_ACTION:
6926 /* used attributes: schema, hash */
6927 target = _lyd_new(NULL, schema, 0);
6928 LY_CHECK_RETURN(!target, -1);
6929 break;
6930 case LYS_LEAF:
6931 /* used attributes: schema, hash */
6932 target = lyd_create_leaf(schema, NULL, 0, 1);
6933 LY_CHECK_RETURN(!target, -1);
6934 break;
6935 case LYS_LEAFLIST:
6936 /* used attributes: schema, hash, value_str */
6937 target = lyd_create_leaf(schema, key_or_value, 0, 0);
6938 LY_CHECK_RETURN(!target, -1);
6939 break;
6940 case LYS_LIST:
6941 /* used attributes: schema, hash, child (all keys) */
6942 target = _lyd_new(NULL, schema, 0);
6943 LY_CHECK_RETURN(!target, -1);
6944
6945 /* create all keys */
6946 keys = strdup(key_or_value);
6947 LY_CHECK_ERR_GOTO(!keys, LOGMEM(lys_node_module(schema)->ctx), error);
6948 next_key = keys;
6949 for (i = 0; i < ((struct lys_node_list *)schema)->keys_size; ++i) {
6950 /* find key schema */
6951 key = (struct lys_node *)((struct lys_node_list *)schema)->keys[i];
6952
6953 /* find key value */
6954 val = lyd_find_sibling_val_key_value(&next_key, key);
6955 LY_CHECK_GOTO(!val, error);
6956
6957 /* create and insert key */
6958 node = lyd_create_leaf(key, val, 0, 0);
6959 if (!node || lyd_insert(target, node)) {
6960 lyd_free(node);
6961 goto error;
6962 }
6963 }
6964 break;
6965 default:
6966 /* unreachable */
6967 LOGARG;
6968 goto error;
6969 }
6970
6971 /* find it */
6972 if (lyd_find_sibling(siblings, target, match)) {
6973 goto error;
6974 }
6975
6976 free(keys);
6977 lyd_free(target);
6978 return 0;
6979
6980 error:
6981 free(keys);
6982 lyd_free(target);
6983 return -1;
6984 }
6985
6986 API struct lyd_node *
lyd_first_sibling(struct lyd_node * node)6987 lyd_first_sibling(struct lyd_node *node)
6988 {
6989 FUN_IN;
6990
6991 struct lyd_node *start;
6992
6993 if (!node) {
6994 return NULL;
6995 }
6996
6997 /* get the first sibling */
6998 if (node->parent) {
6999 start = node->parent->child;
7000 } else {
7001 for (start = node; start->prev->next; start = start->prev);
7002 }
7003
7004 return start;
7005 }
7006
7007 API struct ly_set *
ly_set_new(void)7008 ly_set_new(void)
7009 {
7010 FUN_IN;
7011
7012 struct ly_set *new;
7013
7014 new = calloc(1, sizeof(struct ly_set));
7015 LY_CHECK_ERR_RETURN(!new, LOGMEM(NULL), NULL);
7016 return new;
7017 }
7018
7019 API void
ly_set_free(struct ly_set * set)7020 ly_set_free(struct ly_set *set)
7021 {
7022 FUN_IN;
7023
7024 if (!set) {
7025 return;
7026 }
7027
7028 free(set->set.g);
7029 free(set);
7030 }
7031
7032 API int
ly_set_contains(const struct ly_set * set,void * node)7033 ly_set_contains(const struct ly_set *set, void *node)
7034 {
7035 FUN_IN;
7036
7037 unsigned int i;
7038
7039 if (!set) {
7040 return -1;
7041 }
7042
7043 for (i = 0; i < set->number; i++) {
7044 if (set->set.g[i] == node) {
7045 /* object found */
7046 return i;
7047 }
7048 }
7049
7050 /* object not found */
7051 return -1;
7052 }
7053
7054 API struct ly_set *
ly_set_dup(const struct ly_set * set)7055 ly_set_dup(const struct ly_set *set)
7056 {
7057 FUN_IN;
7058
7059 struct ly_set *new;
7060
7061 if (!set) {
7062 return NULL;
7063 }
7064
7065 new = calloc(1, sizeof *new);
7066 LY_CHECK_ERR_RETURN(!new, LOGMEM(NULL), NULL);
7067 new->number = set->number;
7068 new->size = set->size;
7069
7070 /* is there anything to copy? */
7071 if (set->size) {
7072 new->set.g = malloc(new->size * sizeof *(new->set.g));
7073 LY_CHECK_ERR_RETURN(!new->set.g, LOGMEM(NULL); free(new), NULL);
7074 assert(set->set.g);
7075 memcpy(new->set.g, set->set.g, new->size * sizeof *(new->set.g));
7076 }
7077
7078 return new;
7079 }
7080
7081 API int
ly_set_add(struct ly_set * set,void * node,int options)7082 ly_set_add(struct ly_set *set, void *node, int options)
7083 {
7084 FUN_IN;
7085
7086 unsigned int i;
7087 void **new;
7088
7089 if (!set) {
7090 LOGARG;
7091 return -1;
7092 }
7093
7094 if (!(options & LY_SET_OPT_USEASLIST)) {
7095 /* search for duplication */
7096 for (i = 0; i < set->number; i++) {
7097 if (set->set.g[i] == node) {
7098 /* already in set */
7099 return i;
7100 }
7101 }
7102 }
7103
7104 if (set->size == set->number) {
7105 new = realloc(set->set.g, (set->size + 8) * sizeof *(set->set.g));
7106 LY_CHECK_ERR_RETURN(!new, LOGMEM(NULL), -1);
7107 set->size += 8;
7108 set->set.g = new;
7109 }
7110
7111 set->set.g[set->number++] = node;
7112
7113 return set->number - 1;
7114 }
7115
7116 API int
ly_set_merge(struct ly_set * trg,struct ly_set * src,int options)7117 ly_set_merge(struct ly_set *trg, struct ly_set *src, int options)
7118 {
7119 FUN_IN;
7120
7121 unsigned int i, ret;
7122 void **new;
7123
7124 if (!trg) {
7125 LOGARG;
7126 return -1;
7127 }
7128
7129 if (!src) {
7130 return 0;
7131 }
7132
7133 if (!(options & LY_SET_OPT_USEASLIST)) {
7134 /* remove duplicates */
7135 i = 0;
7136 while (i < src->number) {
7137 if (ly_set_contains(trg, src->set.g[i]) > -1) {
7138 ly_set_rm_index(src, i);
7139 } else {
7140 ++i;
7141 }
7142 }
7143 }
7144
7145 /* allocate more memory if needed */
7146 if (trg->size < trg->number + src->number) {
7147 new = realloc(trg->set.g, (trg->number + src->number) * sizeof *(trg->set.g));
7148 LY_CHECK_ERR_RETURN(!new, LOGMEM(NULL), -1);
7149 trg->size = trg->number + src->number;
7150 trg->set.g = new;
7151 }
7152
7153 /*
7154 * copy contents from src into trg
7155 * don't copy anything if there's nothing to copy, memcpy doesn't want NULL as second argument
7156 */
7157 if (src->number > 0) {
7158 memcpy(trg->set.g + trg->number, src->set.g, src->number * sizeof *(src->set.g));
7159 }
7160 ret = src->number;
7161 trg->number += ret;
7162
7163 /* cleanup */
7164 ly_set_free(src);
7165 return ret;
7166 }
7167
7168 API int
ly_set_rm_index(struct ly_set * set,unsigned int index)7169 ly_set_rm_index(struct ly_set *set, unsigned int index)
7170 {
7171 FUN_IN;
7172
7173 if (!set || (index + 1) > set->number) {
7174 LOGARG;
7175 return EXIT_FAILURE;
7176 }
7177
7178 if (index == set->number - 1) {
7179 /* removing last item in set */
7180 set->set.g[index] = NULL;
7181 } else {
7182 /* removing item somewhere in a middle, so put there the last item */
7183 set->set.g[index] = set->set.g[set->number - 1];
7184 set->set.g[set->number - 1] = NULL;
7185 }
7186 set->number--;
7187
7188 return EXIT_SUCCESS;
7189 }
7190
7191 API int
ly_set_rm(struct ly_set * set,void * node)7192 ly_set_rm(struct ly_set *set, void *node)
7193 {
7194 FUN_IN;
7195
7196 unsigned int i;
7197
7198 if (!set || !node) {
7199 LOGARG;
7200 return EXIT_FAILURE;
7201 }
7202
7203 /* get index */
7204 for (i = 0; i < set->number; i++) {
7205 if (set->set.g[i] == node) {
7206 break;
7207 }
7208 }
7209 if (i == set->number) {
7210 /* node is not in set */
7211 LOGARG;
7212 return EXIT_FAILURE;
7213 }
7214
7215 return ly_set_rm_index(set, i);
7216 }
7217
7218 API int
ly_set_clean(struct ly_set * set)7219 ly_set_clean(struct ly_set *set)
7220 {
7221 FUN_IN;
7222
7223 if (!set) {
7224 return EXIT_FAILURE;
7225 }
7226
7227 free(set->set.g);
7228 set->set.g = NULL;
7229 set->size = 0;
7230 set->number = 0;
7231 return EXIT_SUCCESS;
7232 }
7233
7234 API int
lyd_wd_default(struct lyd_node_leaf_list * node)7235 lyd_wd_default(struct lyd_node_leaf_list *node)
7236 {
7237 FUN_IN;
7238
7239 struct lys_node_leaf *leaf;
7240 struct lys_node_leaflist *llist;
7241 struct lyd_node *iter;
7242 struct lys_tpdf *tpdf;
7243 const char *dflt = NULL, **dflts = NULL;
7244 uint8_t dflts_size = 0, c, i;
7245
7246 if (!node || !(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7247 return 0;
7248 }
7249
7250 if (node->dflt) {
7251 return 1;
7252 }
7253
7254 if (node->schema->nodetype == LYS_LEAF) {
7255 leaf = (struct lys_node_leaf *)node->schema;
7256
7257 /* get know if there is a default value */
7258 if (leaf->dflt) {
7259 /* leaf has a default value */
7260 dflt = leaf->dflt;
7261 } else if (!(leaf->flags & LYS_MAND_TRUE)) {
7262 /* get the default value from the type */
7263 for (tpdf = leaf->type.der; tpdf && !dflt; tpdf = tpdf->type.der) {
7264 dflt = tpdf->dflt;
7265 }
7266 }
7267 if (!dflt) {
7268 /* no default value */
7269 return 0;
7270 }
7271
7272 /* compare the default value with the value of the leaf */
7273 if (!ly_strequal(dflt, node->value_str, 1)) {
7274 return 0;
7275 }
7276 } else if (node->schema->module->version >= LYS_VERSION_1_1) { /* LYS_LEAFLIST */
7277 llist = (struct lys_node_leaflist *)node->schema;
7278
7279 /* get know if there is a default value */
7280 if (llist->dflt_size) {
7281 /* there are default values */
7282 dflts_size = llist->dflt_size;
7283 dflts = llist->dflt;
7284 } else if (!llist->min) {
7285 /* get the default value from the type */
7286 for (tpdf = llist->type.der; tpdf && !dflts; tpdf = tpdf->type.der) {
7287 if (tpdf->dflt) {
7288 dflts = &tpdf->dflt;
7289 dflts_size = 1;
7290 break;
7291 }
7292 }
7293 }
7294
7295 if (!dflts_size) {
7296 /* no default values to use */
7297 return 0;
7298 }
7299
7300 /* compare the default value with the value of the leaf */
7301 /* first, find the first leaf-list's sibling */
7302 iter = (struct lyd_node *)node;
7303 if (iter->parent) {
7304 iter = iter->parent->child;
7305 } else {
7306 for (; iter->prev->next; iter = iter->prev);
7307 }
7308 for (c = 0; iter; iter = iter->next) {
7309 if (iter->schema != node->schema) {
7310 continue;
7311 }
7312 if (c == dflts_size) {
7313 /* to many leaf-list instances */
7314 return 0;
7315 }
7316
7317 if (llist->flags & LYS_USERORDERED) {
7318 /* we have strict order */
7319 if (!ly_strequal(dflts[c], ((struct lyd_node_leaf_list *)iter)->value_str, 1)) {
7320 return 0;
7321 }
7322 } else {
7323 /* node's value is supposed to match with one of the default values */
7324 for (i = 0; i < dflts_size; i++) {
7325 if (ly_strequal(dflts[i], ((struct lyd_node_leaf_list *)iter)->value_str, 1)) {
7326 break;
7327 }
7328 }
7329 if (i == dflts_size) {
7330 /* values do not match */
7331 return 0;
7332 }
7333 }
7334 c++;
7335 }
7336 if (c != dflts_size) {
7337 /* different sets of leaf-list instances */
7338 return 0;
7339 }
7340 } else {
7341 return 0;
7342 }
7343
7344 /* all checks ok */
7345 return 1;
7346 }
7347
7348 int
unres_data_diff_new(struct unres_data * unres,struct lyd_node * subtree,struct lyd_node * parent,int created)7349 unres_data_diff_new(struct unres_data *unres, struct lyd_node *subtree, struct lyd_node *parent, int created)
7350 {
7351 char *parent_xpath = NULL;
7352
7353 if (created) {
7354 return lyd_difflist_add(unres->diff, &unres->diff_size, unres->diff_idx++, LYD_DIFF_CREATED, NULL, subtree);
7355 } else {
7356 if (parent) {
7357 parent_xpath = lyd_path(parent);
7358 LY_CHECK_ERR_RETURN(!parent_xpath, LOGMEM(lyd_node_module(subtree)->ctx), -1);
7359 }
7360 return lyd_difflist_add(unres->diff, &unres->diff_size, unres->diff_idx++, LYD_DIFF_DELETED,
7361 subtree, (struct lyd_node *)parent_xpath);
7362 }
7363 }
7364
7365 void
unres_data_diff_rem(struct unres_data * unres,unsigned int idx)7366 unres_data_diff_rem(struct unres_data *unres, unsigned int idx)
7367 {
7368 if (unres->diff->type[idx] == LYD_DIFF_DELETED) {
7369 lyd_free_withsiblings(unres->diff->first[idx]);
7370 free(unres->diff->second[idx]);
7371 }
7372
7373 /* replace by last real value */
7374 if (idx < unres->diff_idx - 1) {
7375 unres->diff->type[idx] = unres->diff->type[unres->diff_idx - 1];
7376 unres->diff->first[idx] = unres->diff->first[unres->diff_idx - 1];
7377 unres->diff->second[idx] = unres->diff->second[unres->diff_idx - 1];
7378 }
7379
7380 /* move the end */
7381 assert(unres->diff->type[unres->diff_idx] == LYD_DIFF_END);
7382 unres->diff->type[unres->diff_idx - 1] = unres->diff->type[unres->diff_idx];
7383 --unres->diff_idx;
7384 }
7385
7386 API void
lyd_free_val_diff(struct lyd_difflist * diff)7387 lyd_free_val_diff(struct lyd_difflist *diff)
7388 {
7389 FUN_IN;
7390
7391 uint32_t i;
7392
7393 if (!diff) {
7394 return;
7395 }
7396
7397 for (i = 0; diff->type[i] != LYD_DIFF_END; ++i) {
7398 switch (diff->type[i]) {
7399 case LYD_DIFF_CREATED:
7400 free(diff->first[i]);
7401 lyd_free_withsiblings(diff->second[i]);
7402 break;
7403 case LYD_DIFF_DELETED:
7404 lyd_free_withsiblings(diff->first[i]);
7405 free(diff->second[i]);
7406 break;
7407 default:
7408 /* what to do? */
7409 break;
7410 }
7411 }
7412
7413 lyd_free_diff(diff);
7414 }
7415
7416 static int
lyd_wd_add_leaf(struct lyd_node ** tree,struct lyd_node * last_parent,struct lys_node_leaf * leaf,struct unres_data * unres,int check_when_must)7417 lyd_wd_add_leaf(struct lyd_node **tree, struct lyd_node *last_parent, struct lys_node_leaf *leaf, struct unres_data *unres,
7418 int check_when_must)
7419 {
7420 struct lyd_node *dummy = NULL, *current;
7421 struct lys_tpdf *tpdf;
7422 const char *dflt = NULL;
7423 int ret;
7424
7425 /* get know if there is a default value */
7426 if (leaf->dflt) {
7427 /* leaf has a default value */
7428 dflt = leaf->dflt;
7429 } else if (!(leaf->flags & LYS_MAND_TRUE)) {
7430 /* get the default value from the type */
7431 for (tpdf = leaf->type.der; tpdf && !dflt; tpdf = tpdf->type.der) {
7432 dflt = tpdf->dflt;
7433 }
7434 }
7435 if (!dflt) {
7436 /* no default value */
7437 return EXIT_SUCCESS;
7438 }
7439
7440 /* create the node */
7441 if (!(dummy = lyd_new_dummy(*tree, last_parent, (struct lys_node*)leaf, dflt, 1))) {
7442 goto error;
7443 }
7444
7445 if (unres->store_diff) {
7446 /* remember this subtree in the diff */
7447 if (unres_data_diff_new(unres, dummy, NULL, 1)) {
7448 goto error;
7449 }
7450 }
7451
7452 if (!dummy->parent && (*tree)) {
7453 /* connect dummy nodes into the data tree (at the end of top level nodes) */
7454 if (lyd_insert_sibling(tree, dummy)) {
7455 goto error;
7456 }
7457 }
7458 for (current = dummy; ; current = current->child) {
7459 /* remember the created data in unres */
7460 if (check_when_must) {
7461 if ((current->when_status & LYD_WHEN) && unres_data_add(unres, current, UNRES_WHEN) == -1) {
7462 goto error;
7463 }
7464 if (check_when_must == 2) {
7465 ret = resolve_applies_must(current);
7466 if ((ret & 0x1) && (unres_data_add(unres, current, UNRES_MUST) == -1)) {
7467 goto error;
7468 }
7469 if ((ret & 0x2) && (unres_data_add(unres, current, UNRES_MUST_INOUT) == -1)) {
7470 goto error;
7471 }
7472 }
7473 }
7474
7475 /* clear dummy-node flag */
7476 current->validity &= ~LYD_VAL_INUSE;
7477
7478 if (current->schema == (struct lys_node *)leaf) {
7479 break;
7480 }
7481 }
7482 /* update parent's default flag if needed */
7483 lyd_wd_update_parents(dummy);
7484
7485 /* if necessary, remember the created data value in unres */
7486 if (((struct lyd_node_leaf_list *)current)->value_type == LY_TYPE_LEAFREF) {
7487 if (unres_data_add(unres, current, UNRES_LEAFREF)) {
7488 goto error;
7489 }
7490 } else if (((struct lyd_node_leaf_list *)current)->value_type == LY_TYPE_INST) {
7491 if (unres_data_add(unres, current, UNRES_INSTID)) {
7492 goto error;
7493 }
7494 }
7495
7496 if (!(*tree)) {
7497 *tree = dummy;
7498 }
7499 return EXIT_SUCCESS;
7500
7501 error:
7502 lyd_free(dummy);
7503 return EXIT_FAILURE;
7504 }
7505
7506 static int
lyd_wd_add_leaflist(struct lyd_node ** tree,struct lyd_node * last_parent,struct lys_node_leaflist * llist,struct unres_data * unres,int check_when_must)7507 lyd_wd_add_leaflist(struct lyd_node **tree, struct lyd_node *last_parent, struct lys_node_leaflist *llist,
7508 struct unres_data *unres, int check_when_must)
7509 {
7510 struct lyd_node *dummy, *current, *first = NULL;
7511 struct lys_tpdf *tpdf;
7512 const char **dflt = NULL;
7513 uint8_t dflt_size = 0;
7514 int i, ret;
7515
7516 if (llist->module->version < LYS_VERSION_1_1) {
7517 /* default values on leaf-lists are allowed from YANG 1.1 */
7518 return EXIT_SUCCESS;
7519 }
7520
7521 /* get know if there is a default value */
7522 if (llist->dflt_size) {
7523 /* there are default values */
7524 dflt_size = llist->dflt_size;
7525 dflt = llist->dflt;
7526 } else if (!llist->min) {
7527 /* get the default value from the type */
7528 for (tpdf = llist->type.der; tpdf && !dflt; tpdf = tpdf->type.der) {
7529 if (tpdf->dflt) {
7530 dflt = &tpdf->dflt;
7531 dflt_size = 1;
7532 break;
7533 }
7534 }
7535 }
7536
7537 if (!dflt_size) {
7538 /* no default values to use */
7539 return EXIT_SUCCESS;
7540 }
7541
7542 for (i = 0; i < dflt_size; i++) {
7543 /* create the node */
7544 if (!(dummy = lyd_new_dummy(*tree, last_parent, (struct lys_node*)llist, dflt[i], 1))) {
7545 goto error;
7546 }
7547
7548 if (unres->store_diff) {
7549 /* remember this subtree in the diff */
7550 if (unres_data_diff_new(unres, dummy, NULL, 1)) {
7551 goto error;
7552 }
7553 }
7554
7555 if (!first) {
7556 first = dummy;
7557 } else if (!dummy->parent) {
7558 /* interconnect with the rest of leaf-lists */
7559 first->prev->next = dummy;
7560 dummy->prev = first->prev;
7561 first->prev = dummy;
7562 }
7563
7564 for (current = dummy; ; current = current->child) {
7565 /* remember the created data in unres */
7566 if (check_when_must) {
7567 if ((current->when_status & LYD_WHEN) && unres_data_add(unres, current, UNRES_WHEN) == -1) {
7568 goto error;
7569 }
7570 if (check_when_must == 2) {
7571 ret = resolve_applies_must(current);
7572 if ((ret & 0x1) && (unres_data_add(unres, current, UNRES_MUST) == -1)) {
7573 goto error;
7574 }
7575 if ((ret & 0x2) && (unres_data_add(unres, current, UNRES_MUST_INOUT) == -1)) {
7576 goto error;
7577 }
7578 }
7579 }
7580
7581 /* clear dummy-node flag */
7582 current->validity &= ~LYD_VAL_INUSE;
7583
7584 if (current->schema == (struct lys_node *)llist) {
7585 break;
7586 }
7587 }
7588
7589 /* if necessary, remember the created data value in unres */
7590 if (((struct lyd_node_leaf_list *)current)->value_type == LY_TYPE_LEAFREF) {
7591 if (unres_data_add(unres, current, UNRES_LEAFREF)) {
7592 goto error;
7593 }
7594 } else if (((struct lyd_node_leaf_list *)current)->value_type == LY_TYPE_INST) {
7595 if (unres_data_add(unres, current, UNRES_INSTID)) {
7596 goto error;
7597 }
7598 }
7599 }
7600
7601 /* insert into the tree */
7602 if (first && !first->parent && (*tree)) {
7603 /* connect dummy nodes into the data tree (at the end of top level nodes) */
7604 if (lyd_insert_sibling(tree, first)) {
7605 goto error;
7606 }
7607 } else if (!(*tree)) {
7608 *tree = first;
7609 }
7610
7611 /* update parent's default flag if needed */
7612 lyd_wd_update_parents(first);
7613
7614 return EXIT_SUCCESS;
7615
7616 error:
7617 lyd_free_withsiblings(first);
7618 return EXIT_FAILURE;
7619 }
7620
7621 static void
lyd_wd_leaflist_cleanup(struct ly_set * set,struct unres_data * unres)7622 lyd_wd_leaflist_cleanup(struct ly_set *set, struct unres_data *unres)
7623 {
7624 unsigned int i;
7625
7626 assert(set);
7627
7628 /* if there is an instance without the dflt flag, we have to
7629 * remove all instances with the flag - an instance could be
7630 * explicitely added, so the default leaflists were invalidated */
7631 for (i = 0; i < set->number; i++) {
7632 if (!set->set.d[i]->dflt) {
7633 break;
7634 }
7635 }
7636 if (i < set->number) {
7637 for (i = 0; i < set->number; i++) {
7638 if (set->set.d[i]->dflt) {
7639 /* remove this default instance */
7640 if (unres->store_diff) {
7641 /* just move it to diff if is being generated */
7642 unres_data_diff_new(unres, set->set.d[i], set->set.d[i]->parent, 0);
7643 lyd_unlink(set->set.d[i]);
7644 } else {
7645 lyd_free(set->set.d[i]);
7646 }
7647 }
7648 }
7649 }
7650 }
7651
7652 /**
7653 * @brief Process (add/clean flags) default nodes in the schema subtree
7654 *
7655 * @param[in,out] root Pointer to the root node of the complete data tree, the root node can be NULL if the data tree
7656 * is empty
7657 * @param[in] last_parent The closest parent in the data tree to the currently processed \p schema node
7658 * @param[in] subroot The root node of a data subtree, the node is instance of the \p schema node, NULL in case the
7659 * schema node is not instantiated in the data tree
7660 * @param[in] schema The schema node to be processed
7661 * @param[in] toplevel Flag for processing top level schema nodes when \p last_parent and \p subroot are consider as
7662 * unknown
7663 * @param[in] options Parser options to know the data tree type, see @ref parseroptions.
7664 * @param[in] unres Unresolved data list, the newly added default nodes may need to add some unresolved items
7665 * @return EXIT_SUCCESS or EXIT_FAILURE
7666 */
7667 static int
lyd_wd_add_subtree(struct lyd_node ** root,struct lyd_node * last_parent,struct lyd_node * subroot,struct lys_node * schema,int toplevel,int options,struct unres_data * unres)7668 lyd_wd_add_subtree(struct lyd_node **root, struct lyd_node *last_parent, struct lyd_node *subroot,
7669 struct lys_node *schema, int toplevel, int options, struct unres_data *unres)
7670 {
7671 struct ly_set *present = NULL;
7672 struct lys_node *siter, *siter_prev;
7673 struct lyd_node *iter;
7674 int i, check_when_must, storing_diff = 0;
7675
7676 assert(root);
7677
7678 if ((options & LYD_OPT_TYPEMASK) && (schema->flags & LYS_CONFIG_R)) {
7679 /* non LYD_OPT_DATA tree, status data are not expected here */
7680 return EXIT_SUCCESS;
7681 }
7682
7683 if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
7684 check_when_must = 0; /* check neither */
7685 } else if (options & LYD_OPT_TRUSTED) {
7686 check_when_must = 1; /* check only when */
7687 } else {
7688 check_when_must = 2; /* check both when and must */
7689 }
7690
7691 if (toplevel && (schema->nodetype & (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER))) {
7692 /* search for the schema node instance */
7693 present = ly_set_new();
7694 if (!present) {
7695 goto error;
7696 }
7697 if ((*root) && lyd_get_node_siblings(*root, schema, present)) {
7698 /* there are some instances */
7699 for (i = 0; i < (signed)present->number; i++) {
7700 if (schema->nodetype & LYS_LEAFLIST) {
7701 lyd_wd_leaflist_cleanup(present, unres);
7702 } else if (schema->nodetype != LYS_LEAF) {
7703 if (lyd_wd_add_subtree(root, present->set.d[i], present->set.d[i], schema, 0, options, unres)) {
7704 goto error;
7705 }
7706 } /* else LYS_LEAF - nothing to do */
7707 }
7708 } else {
7709 /* no instance */
7710 if (lyd_wd_add_subtree(root, last_parent, NULL, schema, 0, options, unres)) {
7711 goto error;
7712 }
7713 }
7714
7715 ly_set_free(present);
7716 return EXIT_SUCCESS;
7717 }
7718
7719 /* skip disabled parts of schema */
7720 if (!subroot) {
7721 /* go through all the uses and check whether they are enabled */
7722 for (siter = schema->parent; siter && (siter->nodetype & (LYS_USES | LYS_CHOICE)); siter = siter->parent) {
7723 if (lys_is_disabled(siter, 0)) {
7724 /* ignore disabled uses nodes */
7725 return EXIT_SUCCESS;
7726 }
7727 }
7728
7729 /* check augment state */
7730 if (siter && siter->nodetype == LYS_AUGMENT) {
7731 if (lys_is_disabled(siter, 0)) {
7732 /* ignore disabled augment */
7733 return EXIT_SUCCESS;
7734 }
7735 }
7736
7737 /* check the node itself */
7738 if (lys_is_disabled(schema, 0)) {
7739 /* ignore disabled data */
7740 return EXIT_SUCCESS;
7741 }
7742 }
7743
7744 /* go recursively */
7745 switch (schema->nodetype) {
7746 case LYS_LIST:
7747 if (!subroot) {
7748 /* stop recursion */
7749 break;
7750 }
7751 /* falls through */
7752 case LYS_CONTAINER:
7753 if (!subroot) {
7754 /* container does not exists, continue only in case of non presence container */
7755 if (((struct lys_node_container *)schema)->presence) {
7756 /* stop recursion */
7757 break;
7758 }
7759 /* always create empty NP container even if there is no default node,
7760 * because accroding to RFC, the empty NP container is always part of
7761 * accessible tree (e.g. for evaluating when and must conditions) */
7762 subroot = _lyd_new(last_parent, schema, 1);
7763 /* useless to set mand flag */
7764 subroot->validity &= ~LYD_VAL_MAND;
7765
7766 if (unres->store_diff) {
7767 /* remember this container in the diff */
7768 if (unres_data_diff_new(unres, subroot, NULL, 1)) {
7769 goto error;
7770 }
7771
7772 /* do not store diff for recursive calls, created values will be connected to this one */
7773 storing_diff = 1;
7774 unres->store_diff = 0;
7775 }
7776
7777 if (!last_parent) {
7778 if (*root) {
7779 lyd_insert_common((*root)->parent, root, subroot, 0);
7780 } else {
7781 *root = subroot;
7782 }
7783 }
7784 last_parent = subroot;
7785
7786 /* remember the created container in unres */
7787 if (check_when_must) {
7788 if ((subroot->when_status & LYD_WHEN) && unres_data_add(unres, subroot, UNRES_WHEN) == -1) {
7789 goto error;
7790 }
7791 if (check_when_must == 2) {
7792 i = resolve_applies_must(subroot);
7793 if ((i & 0x1) && (unres_data_add(unres, subroot, UNRES_MUST) == -1)) {
7794 goto error;
7795 }
7796 if ((i & 0x2) && (unres_data_add(unres, subroot, UNRES_MUST_INOUT) == -1)) {
7797 goto error;
7798 }
7799 }
7800 }
7801 } else if (!((struct lys_node_container *)schema)->presence) {
7802 /* fix default flag on existing containers - set it on all non-presence containers and in case we will
7803 * have in recursion function some non-default node, it will unset it */
7804 subroot->dflt = 1;
7805 }
7806 /* falls through */
7807 case LYS_CASE:
7808 case LYS_USES:
7809 case LYS_INPUT:
7810 case LYS_OUTPUT:
7811 case LYS_NOTIF:
7812
7813 /* recursion */
7814 present = ly_set_new();
7815 if (!present) {
7816 goto error;
7817 }
7818 LY_TREE_FOR(schema->child, siter) {
7819 if (siter->nodetype & (LYS_CHOICE | LYS_USES)) {
7820 /* go into without searching for data instance */
7821 if (lyd_wd_add_subtree(root, last_parent, subroot, siter, toplevel, options, unres)) {
7822 goto error;
7823 }
7824 } else if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA)) {
7825 /* search for the schema node instance */
7826 if (subroot && lyd_get_node_siblings(subroot->child, siter, present)) {
7827 /* there are some instances in the data root */
7828 if (siter->nodetype & LYS_LEAFLIST) {
7829 /* already have some leaflists, check that they are all
7830 * default, if not, remove the default leaflists */
7831 lyd_wd_leaflist_cleanup(present, unres);
7832 } else if (siter->nodetype != LYS_LEAF) {
7833 /* recursion */
7834 for (i = 0; i < (signed)present->number; i++) {
7835 if (lyd_wd_add_subtree(root, present->set.d[i], present->set.d[i], siter, toplevel, options,
7836 unres)) {
7837 goto error;
7838 }
7839 }
7840 } /* else LYS_LEAF - nothing to do */
7841
7842 /* fix default flag (2nd part) - for non-default node with default parent, unset the default flag
7843 * from the parents (starting from subroot node) */
7844 if (subroot->dflt) {
7845 for (i = 0; i < (signed)present->number; i++) {
7846 if (!present->set.d[i]->dflt) {
7847 for (iter = subroot; iter && iter->dflt; iter = iter->parent) {
7848 iter->dflt = 0;
7849 }
7850 break;
7851 }
7852 }
7853 }
7854 ly_set_clean(present);
7855 } else {
7856 /* no instance */
7857 if (lyd_wd_add_subtree(root, last_parent, NULL, siter, toplevel, options, unres)) {
7858 goto error;
7859 }
7860 }
7861 }
7862 }
7863
7864 if (storing_diff) {
7865 /* continue generating the diff in functions above this one */
7866 unres->store_diff = 1;
7867 }
7868 break;
7869 case LYS_LEAF:
7870 case LYS_LEAFLIST:
7871 if (subroot) {
7872 /* default shortcase of a choice */
7873 present = ly_set_new();
7874 if (!present) {
7875 goto error;
7876 }
7877 lyd_get_node_siblings(subroot->child, schema, present);
7878 if (present->number) {
7879 /* the shortcase leaf(-list) exists, stop the processing and fix default flags */
7880 if (subroot->dflt) {
7881 for (i = 0; i < (signed)present->number; i++) {
7882 if (!present->set.d[i]->dflt) {
7883 for (iter = subroot; iter && iter->dflt; iter = iter->parent) {
7884 iter->dflt = 0;
7885 }
7886 break;
7887 }
7888 }
7889 }
7890 break;
7891 }
7892 }
7893 if (schema->nodetype == LYS_LEAF) {
7894 if (lyd_wd_add_leaf(root, last_parent, (struct lys_node_leaf*)schema, unres, check_when_must)) {
7895 return EXIT_FAILURE;
7896 }
7897 } else { /* LYS_LEAFLIST */
7898 if (lyd_wd_add_leaflist(root, last_parent, (struct lys_node_leaflist*)schema, unres, check_when_must)) {
7899 goto error;
7900 }
7901 }
7902 break;
7903 case LYS_CHOICE:
7904 /* get existing node in the data root from the choice */
7905 iter = NULL;
7906 if ((toplevel && (*root)) || (!toplevel && subroot)) {
7907 LY_TREE_FOR(toplevel ? (*root) : subroot->child, iter) {
7908 for (siter = lys_parent(iter->schema), siter_prev = iter->schema;
7909 siter && (siter->nodetype & (LYS_CASE | LYS_USES | LYS_CHOICE));
7910 siter_prev = siter, siter = lys_parent(siter)) {
7911 if (siter == schema) {
7912 /* we have the choice instance */
7913 break;
7914 }
7915 }
7916 if (siter == schema) {
7917 /* we have the choice instance;
7918 * the condition must be the same as in the loop because of
7919 * choice's sibling nodes that break the loop, so siter is not NULL,
7920 * but it is not the same as schema */
7921 break;
7922 }
7923 }
7924 }
7925 if (!iter) {
7926 if (((struct lys_node_choice *)schema)->dflt) {
7927 /* there is a default case */
7928 if (lyd_wd_add_subtree(root, last_parent, subroot, ((struct lys_node_choice *)schema)->dflt,
7929 toplevel, options, unres)) {
7930 goto error;
7931 }
7932 }
7933 } else {
7934 /* one of the choice's cases is instantiated, continue into this case */
7935 /* since iter != NULL, siter must be also != NULL and we also know siter_prev
7936 * which points to the child of schema leading towards the instantiated data */
7937 assert(siter && siter_prev);
7938 if (lyd_wd_add_subtree(root, last_parent, subroot, siter_prev, toplevel, options, unres)) {
7939 goto error;
7940 }
7941 }
7942 break;
7943 default:
7944 /* LYS_ANYXML, LYS_ANYDATA, LYS_USES, LYS_GROUPING - do nothing */
7945 break;
7946 }
7947
7948 ly_set_free(present);
7949 return EXIT_SUCCESS;
7950
7951 error:
7952 ly_set_free(present);
7953 return EXIT_FAILURE;
7954 }
7955
7956 /**
7957 * @brief Covering function to process (add/clean) default nodes in the data tree
7958 * @param[in,out] root Pointer to the root node of the complete data tree, the root node can be NULL if the data tree
7959 * is empty
7960 * @param[in] ctx Context for the case the data tree is empty (in that case \p ctx must not be NULL)
7961 * @param[in] options Parser options to know the data tree type, see @ref parseroptions.
7962 * @param[in] unres Unresolved data list, the newly added default nodes may need to add some unresolved items
7963 * @return EXIT_SUCCESS or EXIT_FAILURE
7964 */
7965 static int
lyd_wd_add(struct lyd_node ** root,struct ly_ctx * ctx,const struct lys_module ** modules,int mod_count,struct unres_data * unres,int options)7966 lyd_wd_add(struct lyd_node **root, struct ly_ctx *ctx, const struct lys_module **modules, int mod_count,
7967 struct unres_data *unres, int options)
7968 {
7969 struct lys_node *siter;
7970 int i;
7971
7972 assert(root && !(options & LYD_OPT_ACT_NOTIF));
7973 assert(*root || ctx);
7974 assert(!(options & LYD_OPT_NOSIBLINGS) || *root);
7975
7976 if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
7977 /* no change supposed */
7978 return EXIT_SUCCESS;
7979 }
7980
7981 if (!ctx) {
7982 ctx = (*root)->schema->module->ctx;
7983 }
7984
7985 if (!(options & LYD_OPT_TYPEMASK) || (options & LYD_OPT_CONFIG)) {
7986 if (options & LYD_OPT_NOSIBLINGS) {
7987 if (lyd_wd_add_subtree(root, NULL, NULL, (*root)->schema, 1, options, unres)) {
7988 return EXIT_FAILURE;
7989 }
7990 } else if (modules && mod_count) {
7991 for (i = 0; i < mod_count; ++i) {
7992 LY_TREE_FOR(modules[i]->data, siter) {
7993 if (!(siter->nodetype & (LYS_CONTAINER | LYS_CHOICE | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA |
7994 LYS_USES))) {
7995 continue;
7996 }
7997 if (lyd_wd_add_subtree(root, NULL, NULL, siter, 1, options, unres)) {
7998 return EXIT_FAILURE;
7999 }
8000 }
8001 }
8002 } else {
8003 for (i = 0; i < ctx->models.used; i++) {
8004 /* skip not implemented and disabled modules */
8005 if (!ctx->models.list[i]->implemented || ctx->models.list[i]->disabled) {
8006 continue;
8007 }
8008 LY_TREE_FOR(ctx->models.list[i]->data, siter) {
8009 if (!(siter->nodetype & (LYS_CONTAINER | LYS_CHOICE | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA |
8010 LYS_USES))) {
8011 continue;
8012 }
8013 if (lyd_wd_add_subtree(root, NULL, NULL, siter, 1, options, unres)) {
8014 return EXIT_FAILURE;
8015 }
8016 }
8017 }
8018 }
8019 } else if (options & (LYD_OPT_NOTIF | LYD_OPT_NOTIF_FILTER)) {
8020 if (!(*root) || ((*root)->schema->nodetype != LYS_NOTIF)) {
8021 LOGERR(ctx, LY_EINVAL, "Subtree is not a single notification.");
8022 return EXIT_FAILURE;
8023 }
8024 if (lyd_wd_add_subtree(root, *root, *root, (*root)->schema, 0, options, unres)) {
8025 return EXIT_FAILURE;
8026 }
8027 } else if (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY)) {
8028 if (!(*root) || !((*root)->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
8029 LOGERR(ctx, LY_EINVAL, "Subtree is not a single RPC/action/reply.");
8030 return EXIT_FAILURE;
8031 }
8032 if (options & LYD_OPT_RPC) {
8033 for (siter = (*root)->schema->child; siter && siter->nodetype != LYS_INPUT; siter = siter->next);
8034 } else { /* LYD_OPT_RPCREPLY */
8035 for (siter = (*root)->schema->child; siter && siter->nodetype != LYS_OUTPUT; siter = siter->next);
8036 }
8037 if (siter) {
8038 if (lyd_wd_add_subtree(root, *root, *root, siter, 0, options, unres)) {
8039 return EXIT_FAILURE;
8040 }
8041 }
8042 } else if (options & LYD_OPT_DATA_TEMPLATE) {
8043 if (lyd_wd_add_subtree(root, NULL, NULL, (*root)->schema, 1, options, unres)) {
8044 return EXIT_FAILURE;
8045 }
8046 } else {
8047 LOGINT(ctx);
8048 return EXIT_FAILURE;
8049 }
8050
8051 return EXIT_SUCCESS;
8052 }
8053
8054 int
lyd_defaults_add_unres(struct lyd_node ** root,int options,struct ly_ctx * ctx,const struct lys_module ** modules,int mod_count,const struct lyd_node * data_tree,struct lyd_node * act_notif,struct unres_data * unres,int wd)8055 lyd_defaults_add_unres(struct lyd_node **root, int options, struct ly_ctx *ctx, const struct lys_module **modules,
8056 int mod_count, const struct lyd_node *data_tree, struct lyd_node *act_notif,
8057 struct unres_data *unres, int wd)
8058 {
8059 struct lyd_node *msg_sibling = NULL, *msg_parent = NULL, *data_tree_sibling = NULL, *data_tree_parent = NULL;
8060 struct lys_node *msg_op = NULL;
8061 struct ly_set *set;
8062 int ret = EXIT_FAILURE;
8063
8064 assert(root && (*root || ctx) && unres && !(options & LYD_OPT_ACT_NOTIF));
8065
8066 if (!ctx) {
8067 ctx = (*root)->schema->module->ctx;
8068 }
8069
8070 if ((options & LYD_OPT_NOSIBLINGS) && !(*root)) {
8071 LOGERR(ctx, LY_EINVAL, "Cannot add default values for one module (LYD_OPT_NOSIBLINGS) without any data.");
8072 return EXIT_FAILURE;
8073 }
8074
8075 if (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)) {
8076 if (!(*root)) {
8077 LOGERR(ctx, LY_EINVAL, "Cannot add default values to RPC, RPC reply, and notification without at least the empty container.");
8078 return EXIT_FAILURE;
8079 }
8080 if ((options & LYD_OPT_RPC) && !act_notif && ((*root)->schema->nodetype != LYS_RPC)) {
8081 LOGERR(ctx, LY_EINVAL, "Not valid RPC/action data.");
8082 return EXIT_FAILURE;
8083 }
8084 if ((options & LYD_OPT_RPCREPLY) && !act_notif && ((*root)->schema->nodetype != LYS_RPC)) {
8085 LOGERR(ctx, LY_EINVAL, "Not valid reply data.");
8086 return EXIT_FAILURE;
8087 }
8088 if ((options & LYD_OPT_NOTIF) && !act_notif && ((*root)->schema->nodetype != LYS_NOTIF)) {
8089 LOGERR(ctx, LY_EINVAL, "Not valid notification data.");
8090 return EXIT_FAILURE;
8091 }
8092
8093 /* remember the operation/notification schema */
8094 msg_op = act_notif ? act_notif->schema : (*root)->schema;
8095 } else if (*root && (*root)->parent) {
8096 /* we have inner node, so it will be considered as
8097 * a root of subtree where to add default nodes and
8098 * no of its siblings will be affected */
8099 options |= LYD_OPT_NOSIBLINGS;
8100 }
8101
8102 /* add missing default nodes */
8103 if (wd && lyd_wd_add((act_notif ? &act_notif : root), ctx, modules, mod_count, unres, options)) {
8104 return EXIT_FAILURE;
8105 }
8106
8107 /* check leafrefs and/or instids if any */
8108 if (unres && unres->count) {
8109 if (!(*root)) {
8110 LOGINT(ctx);
8111 return EXIT_FAILURE;
8112 }
8113
8114 /* temporarily link the additional data tree to the RPC/action/notification */
8115 if (data_tree && (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF))) {
8116 /* duplicate the message tree - if it gets deleted we would not be able to positively identify it */
8117 msg_parent = NULL;
8118 msg_sibling = *root;
8119
8120 if (act_notif) {
8121 /* fun case */
8122 data_tree_parent = NULL;
8123 data_tree_sibling = (struct lyd_node *)data_tree;
8124 while (data_tree_sibling) {
8125 while (data_tree_sibling) {
8126 if ((data_tree_sibling->schema == msg_sibling->schema)
8127 && ((msg_sibling->schema->nodetype != LYS_LIST)
8128 || lyd_list_equal(data_tree_sibling, msg_sibling, 0))) {
8129 /* match */
8130 break;
8131 }
8132
8133 data_tree_sibling = data_tree_sibling->next;
8134 }
8135
8136 if (data_tree_sibling) {
8137 /* prepare for the new data_tree iteration */
8138 data_tree_parent = data_tree_sibling;
8139 data_tree_sibling = data_tree_sibling->child;
8140
8141 /* find new action sibling to search for later (skip list keys) */
8142 msg_parent = msg_sibling;
8143 assert(msg_sibling->child);
8144 for (msg_sibling = msg_sibling->child;
8145 msg_sibling->schema->nodetype == LYS_LEAF;
8146 msg_sibling = msg_sibling->next) {
8147 assert(msg_sibling->next);
8148 }
8149 if (msg_sibling->schema->nodetype & (LYS_ACTION | LYS_NOTIF)) {
8150 /* we are done */
8151 assert(act_notif->parent);
8152 assert(act_notif->parent->schema == data_tree_parent->schema);
8153 assert(msg_sibling == act_notif);
8154 break;
8155 }
8156 }
8157 }
8158
8159 /* loop ended after the first iteration, set the values correctly */
8160 if (!data_tree_parent) {
8161 data_tree_sibling = (struct lyd_node *)data_tree;
8162 }
8163
8164 } else {
8165 /* easy case */
8166 data_tree_parent = NULL;
8167 data_tree_sibling = (struct lyd_node *)data_tree;
8168 }
8169
8170 /* unlink msg_sibling if needed (won't do anything otherwise) */
8171 lyd_unlink_internal(msg_sibling, 0);
8172
8173 /* now we can insert msg_sibling into data_tree_parent or next to data_tree_sibling */
8174 assert(data_tree_parent || data_tree_sibling);
8175 if (data_tree_parent) {
8176 if (lyd_insert_common(data_tree_parent, NULL, msg_sibling, 0)) {
8177 goto unlink_datatree;
8178 }
8179 } else {
8180 assert(!data_tree_sibling->parent);
8181 if (lyd_insert_nextto(data_tree_sibling->prev, msg_sibling, 0, 0)) {
8182 goto unlink_datatree;
8183 }
8184 }
8185 }
8186
8187 if (resolve_unres_data(ctx, unres, root, options)) {
8188 goto unlink_datatree;
8189 }
8190
8191 /* we are done */
8192 ret = EXIT_SUCCESS;
8193
8194 /* check that the operation/notification tree was not removed */
8195 if (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)) {
8196 set = NULL;
8197 if (data_tree) {
8198 set = lyd_find_instance(data_tree_parent ? data_tree_parent : data_tree_sibling, msg_op);
8199 assert(set && ((set->number == 0) || (set->number == 1)));
8200 } else if (*root) {
8201 set = lyd_find_instance(*root, msg_op);
8202 assert(set && ((set->number == 0) || (set->number == 1)));
8203 }
8204 if (!set || !set->number) {
8205 /* it was removed, handle specially */
8206 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, msg_op, "Operation/notification not supported because of the current configuration.");
8207 ret = EXIT_FAILURE;
8208 }
8209 ly_set_free(set);
8210 }
8211
8212 unlink_datatree:
8213 /* put the trees back in order */
8214 if (data_tree && (options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF))) {
8215 /* unlink and insert it back, if there is a parent */
8216 lyd_unlink_internal(msg_sibling, 0);
8217 if (msg_parent) {
8218 lyd_insert_common(msg_parent, NULL, msg_sibling, 0);
8219 }
8220 }
8221 } else {
8222 /* we are done */
8223 ret = EXIT_SUCCESS;
8224 }
8225
8226 return ret;
8227 }
8228
8229 API struct lys_module *
lyd_node_module(const struct lyd_node * node)8230 lyd_node_module(const struct lyd_node *node)
8231 {
8232 FUN_IN;
8233
8234 if (!node) {
8235 return NULL;
8236 }
8237
8238 return node->schema->module->type ? ((struct lys_submodule *)node->schema->module)->belongsto : node->schema->module;
8239 }
8240
8241 API double
lyd_dec64_to_double(const struct lyd_node * node)8242 lyd_dec64_to_double(const struct lyd_node *node)
8243 {
8244 FUN_IN;
8245
8246 if (!node || !(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
8247 || (((struct lys_node_leaf *)node->schema)->type.base != LY_TYPE_DEC64)) {
8248 LOGARG;
8249 return 0;
8250 }
8251
8252 return atof(((struct lyd_node_leaf_list *)node)->value_str);
8253 }
8254
8255 API const struct lys_type *
lyd_leaf_type(const struct lyd_node_leaf_list * leaf)8256 lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
8257 {
8258 FUN_IN;
8259
8260 struct lys_type *type;
8261
8262 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
8263 return NULL;
8264 }
8265
8266 type = &((struct lys_node_leaf *)leaf->schema)->type;
8267
8268 do {
8269 if (type->base == LY_TYPE_LEAFREF) {
8270 type = &type->info.lref.target->type;
8271 } else if (type->base == LY_TYPE_UNION) {
8272 if (type->info.uni.has_ptr_type && leaf->validity) {
8273 /* we don't know what it will be after resolution (validation) */
8274 LOGVAL(leaf->schema->module->ctx, LYE_SPEC, LY_VLOG_LYD, leaf,
8275 "Unable to determine the type of value \"%s\" from union type \"%s\" prior to validation.",
8276 leaf->value_str, type->der->name);
8277 return NULL;
8278 }
8279
8280 if (resolve_union((struct lyd_node_leaf_list *)leaf, type, 0, 0, &type)) {
8281 /* resolve union failed */
8282 return NULL;
8283 }
8284 }
8285 } while (type->base == LY_TYPE_LEAFREF);
8286
8287 return type;
8288 }
8289
8290 #ifdef LY_ENABLED_LYD_PRIV
8291
8292 API void *
lyd_set_private(const struct lyd_node * node,void * priv)8293 lyd_set_private(const struct lyd_node *node, void *priv)
8294 {
8295 FUN_IN;
8296
8297 void *prev;
8298
8299 if (!node) {
8300 LOGARG;
8301 return NULL;
8302 }
8303
8304 prev = node->priv;
8305 ((struct lyd_node *)node)->priv = priv;
8306
8307 return prev;
8308 }
8309
8310 #endif
8311
8312 API struct lyd_node *
lyd_find_path_hash_based(struct lyd_node * data_tree,const struct ly_ctx * ctx,const char * path,int output)8313 lyd_find_path_hash_based(struct lyd_node *data_tree, const struct ly_ctx *ctx, const char *path, int output)
8314 {
8315 FUN_IN;
8316
8317 const char *id;
8318 struct lyd_node *node, *parent = NULL;
8319 int parsed = 0;
8320 int options = 0;
8321
8322 if (!path || (!data_tree && !ctx)
8323 || (!data_tree && (path[0] != '/'))) {
8324 LOGARG;
8325 return NULL;
8326 }
8327
8328 /* The only relevant option is LYD_PATH_OPT_OUTPUT */
8329 if (output)
8330 options = LYD_PATH_OPT_OUTPUT;
8331
8332
8333 if (!ctx) {
8334 ctx = data_tree->schema->module->ctx;
8335 }
8336
8337 id = path;
8338
8339 if (data_tree) {
8340 if (path[0] == '/') {
8341 /* absolute path, go through all the siblings and try to find the right parent, if exists,
8342 * first go through all the next siblings keeping the original order, for positional predicates */
8343 for (node = data_tree; !parsed && node; node = node->next) {
8344 parent = resolve_partial_json_data_nodeid(id, NULL, node, options, &parsed);
8345 }
8346 if (!parsed) {
8347 for (node = data_tree->prev; !parsed && node->next; node = node->prev) {
8348 parent = resolve_partial_json_data_nodeid(id, NULL, node, options, &parsed);
8349 }
8350 }
8351 } else {
8352 /* relative path, use only the provided data tree root */
8353 parent = resolve_partial_json_data_nodeid(id, NULL, data_tree, options, &parsed);
8354 }
8355 if (parsed == -1) {
8356 return NULL;
8357 }
8358 }
8359
8360 return parent;
8361 }
8362