blob: 27742cbf2afb3cba314bad6d908add74dc3cd653 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_schema.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
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#include "common.h"
16
Radek Krejci084289f2019-07-09 17:35:30 +020017#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020018#include <ctype.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <stdarg.h>
22#include <stdint.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "log.h"
27#include "tree.h"
28#include "tree_data.h"
29#include "tree_data_internal.h"
30#include "tree_schema.h"
31
Radek Krejci576b23f2019-07-12 14:06:32 +020032API void
33lyd_trees_free(const struct lyd_node **trees, int free_data)
34{
35 if (!trees) {
36 return;
37 }
38
39 if (free_data) {
40 unsigned int u;
41 LY_ARRAY_FOR(trees, u) {
42 lyd_free_all((struct lyd_node *)trees[u]);
43 }
44 }
45 LY_ARRAY_FREE(trees);
46}
47
48static const struct lyd_node *
49lyd_trees_getstart(const struct lyd_node *tree)
50{
51 if (!tree) {
52 return NULL;
53 }
54 while (tree->prev->next) {
55 tree = tree->prev;
56 }
57 return tree;
58}
59
60API const struct lyd_node **
61lyd_trees_new(size_t count, const struct lyd_node *tree, ...)
62{
63 LY_ERR ret;
64 const struct lyd_node **trees = NULL;
65 va_list ap;
66
67 LY_CHECK_ARG_RET(NULL, tree, count > 0, NULL);
68
69 va_start(ap, tree);
70
71 LY_ARRAY_CREATE_GOTO(tree->schema->module->ctx, trees, count, ret, error);
72 /* first, mandatory, tree to insert */
73 trees[0] = lyd_trees_getstart(tree);
74 LY_ARRAY_INCREMENT(trees);
75
76 /* variable arguments */
77 for (unsigned int u = 1; u < count; ++u) {
78 trees[u] = lyd_trees_getstart(va_arg(ap, const struct lyd_node *));
79 LY_ARRAY_INCREMENT(trees);
80 }
81
82 va_end(ap);
83 return trees;
84
85error:
86 (void)ret; /* unused */
87 lyd_trees_free(trees, 1);
88 va_end(ap);
89 return NULL;
90}
91
Radek Krejcif3b6fec2019-07-24 15:53:11 +020092API const struct lyd_node **
93lyd_trees_add(const struct lyd_node **trees, const struct lyd_node *tree)
94{
95 const struct lyd_node **t = NULL;
96
97 LY_CHECK_ARG_RET(NULL, tree, trees, trees);
98
99 LY_ARRAY_NEW_RET(tree->schema->module->ctx, trees, t, NULL);
100 *t = lyd_trees_getstart(tree);
101
102 return trees;
103}
104
Radek Krejcie7b95092019-05-15 11:03:07 +0200105static int
Radek Krejci357398c2019-05-27 14:15:01 +0200106cmp_str(const char *refstr, const char *str, size_t str_len)
Radek Krejcie7b95092019-05-15 11:03:07 +0200107{
108
Radek Krejci357398c2019-05-27 14:15:01 +0200109 if (str_len) {
110 int r = strncmp(refstr, str, str_len);
111 if (!r && !refstr[str_len]) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200112 return 0;
113 } else {
114 return 1;
115 }
116 } else {
117 return strcmp(refstr, str);
118 }
119}
120
121API const struct lyd_node *
122lyd_search(const struct lyd_node *first, const struct lys_module *module,
123 const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len)
124{
125 const struct lyd_node *node = NULL;
126 const struct lysc_node *snode;
127
128 LY_CHECK_ARG_RET(NULL, module, name, NULL);
129 if (!nodetype) {
130 nodetype = 0xffff;
131 }
132
133 LY_LIST_FOR(first, node) {
134 snode = node->schema;
135 if (!(snode->nodetype & nodetype)) {
136 continue;
137 }
138 if (snode->module != module) {
139 continue;
140 }
141
142 if (cmp_str(snode->name, name, name_len)) {
143 continue;
144 }
145
146 if (value) {
147 if (snode->nodetype == LYS_LIST) {
148 /* TODO handle value as keys of the list instance */
149 } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
150 if (cmp_str(((struct lyd_node_term*)node)->value.canonized, value, value_len)) {
151 continue;
152 }
153 } else {
154 continue;
155 }
156 }
157
158 /* all criteria passed */
159 return node;
160 }
161 return NULL;
162}
163
Radek Krejci084289f2019-07-09 17:35:30 +0200164LY_ERR
Radek Krejci3c9758d2019-07-11 16:49:10 +0200165lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic, int second,
Radek Krejci576b23f2019-07-12 14:06:32 +0200166 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200167{
168 LY_ERR ret = LY_SUCCESS, rc;
169 struct ly_err_item *err = NULL;
170 struct ly_ctx *ctx;
171 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +0200172 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
173 (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200174 assert(node);
175
176 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +0200177
Radek Krejci73dead22019-07-11 16:46:16 +0200178 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci62903c32019-07-15 14:42:05 +0200179 if (!second) {
180 node->value.realtype = type;
181 }
Radek Krejci73dead22019-07-11 16:46:16 +0200182 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
183 trees ? (void*)node : (void*)node->schema, trees,
184 &node->value, NULL, &err);
185 if (rc == LY_EINCOMPLETE) {
186 ret = rc;
187 /* continue with storing, just remember what to return if storing is ok */
188 } else if (rc) {
189 ret = rc;
190 if (err) {
191 ly_err_print(err);
192 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
193 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200194 }
Radek Krejci73dead22019-07-11 16:46:16 +0200195 goto error;
Radek Krejci084289f2019-07-09 17:35:30 +0200196 }
197
198error:
199 return ret;
200}
201
202API LY_ERR
203lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
204 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
205{
206 LY_ERR rc = LY_SUCCESS;
207 struct ly_err_item *err = NULL;
208 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200209
210 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
211
212 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
213 LOGARG(ctx, node);
214 return LY_EINVAL;
215 }
216
217 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200218 /* just validate, no storing of enything */
219 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
220 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
221 if (rc == LY_EINCOMPLETE) {
222 /* actually success since we do not provide the context tree and call validation with
223 * LY_TYPE_OPTS_INCOMPLETE_DATA */
224 rc = LY_SUCCESS;
225 } else if (rc && err) {
226 if (ctx) {
227 /* log only in case the ctx was provided as input parameter */
228 ly_err_print(err);
229 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200230 }
Radek Krejci73dead22019-07-11 16:46:16 +0200231 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200232 }
233
234 return rc;
235}
236
237API LY_ERR
238lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
Radek Krejci576b23f2019-07-12 14:06:32 +0200239 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200240{
241 LY_ERR rc;
242 struct ly_err_item *err = NULL;
243 struct lysc_type *type;
Radek Krejci73dead22019-07-11 16:46:16 +0200244 int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200245
246 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
247
248 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200249 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
250 get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
251 NULL, NULL, &err);
252 if (rc == LY_EINCOMPLETE) {
253 return rc;
254 } else if (rc) {
255 if (err) {
256 if (ctx) {
257 ly_err_print(err);
258 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200259 }
Radek Krejci73dead22019-07-11 16:46:16 +0200260 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200261 }
Radek Krejci73dead22019-07-11 16:46:16 +0200262 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200263 }
264
265 return LY_SUCCESS;
266}
267
268API LY_ERR
269lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Radek Krejci576b23f2019-07-12 14:06:32 +0200270 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200271{
272 LY_ERR ret = LY_SUCCESS, rc;
273 struct ly_err_item *err = NULL;
274 struct ly_ctx *ctx;
275 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200276 struct lyd_value data = {0};
Radek Krejci73dead22019-07-11 16:46:16 +0200277 int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200278
279 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
280
281 ctx = node->schema->module->ctx;
282 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200283 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
284 trees, &data, NULL, &err);
285 if (rc == LY_EINCOMPLETE) {
286 ret = rc;
287 /* continue with comparing, just remember what to return if storing is ok */
288 } else if (rc) {
289 /* value to compare is invalid */
290 ret = LY_EINVAL;
291 if (err) {
292 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200293 }
Radek Krejci73dead22019-07-11 16:46:16 +0200294 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200295 }
296
297 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200298 if (type->plugin->compare(&node->value, &data)) {
299 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
300 ret = LY_EVALID;
301 }
Radek Krejci084289f2019-07-09 17:35:30 +0200302
303cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200304 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200305
306 return ret;
307}
308
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200309API struct lyd_node *
310lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, const struct lyd_node **trees)
Radek Krejcie7b95092019-05-15 11:03:07 +0200311{
Radek Krejcie7b95092019-05-15 11:03:07 +0200312 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200313#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200314 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200315#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200316
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200317 LY_CHECK_ARG_RET(ctx, ctx, NULL);
318
319 if (lyd_parse_options_check(ctx, options, __func__)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200320 return NULL;
321 }
322
323 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200324 /* first item in trees is mandatory - the RPC/action request */
325 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
326 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
327 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
328 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200329 return NULL;
330 }
331 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200332
Radek Krejcie92210c2019-05-17 15:53:35 +0200333#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200334 if (options & LYD_OPT_DATA_TEMPLATE) {
335 yang_data_name = va_arg(ap, const char *);
336 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200337#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200338
339 if (!format) {
340 /* TODO try to detect format from the content */
341 }
342
343 switch (format) {
344 case LYD_XML:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200345 lyd_parse_xml(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200346 break;
347#if 0
348 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200349 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200350 break;
351 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200352 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200353 break;
354#endif
355 case LYD_UNKNOWN:
356 LOGINT(ctx);
357 break;
358 }
359
Radek Krejcie7b95092019-05-15 11:03:07 +0200360 return result;
361}
362
363API struct lyd_node *
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200364lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, const struct lyd_node **trees)
Radek Krejcie7b95092019-05-15 11:03:07 +0200365{
366 struct lyd_node *result;
367 size_t length;
368 char *addr;
369
370 LY_CHECK_ARG_RET(ctx, ctx, NULL);
371 if (fd < 0) {
372 LOGARG(ctx, fd);
373 return NULL;
374 }
375
376 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200377 result = lyd_parse_mem(ctx, addr ? addr : "", format, options, trees);
Radek Krejcidf3da792019-05-17 10:32:24 +0200378 if (addr) {
379 ly_munmap(addr, length);
380 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200381
382 return result;
383}
384
385API struct lyd_node *
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200386lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, const struct lyd_node **trees)
Radek Krejcie7b95092019-05-15 11:03:07 +0200387{
388 int fd;
389 struct lyd_node *result;
390 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200391
392 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
393
394 fd = open(path, O_RDONLY);
395 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
396
397 if (!format) {
398 /* unknown format - try to detect it from filename's suffix */
399 len = strlen(path);
400
401 /* ignore trailing whitespaces */
402 for (; len > 0 && isspace(path[len - 1]); len--);
403
404 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
405 format = LYD_XML;
406#if 0
407 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
408 format = LYD_JSON;
409 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
410 format = LYD_LYB;
411#endif
412 } /* else still unknown, try later to detect it from the content */
413 }
414
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200415 result = lyd_parse_fd(ctx, fd, format, options, trees);
Radek Krejcie7b95092019-05-15 11:03:07 +0200416 close(fd);
417
418 return result;
419}
Radek Krejci084289f2019-07-09 17:35:30 +0200420
421API const struct lyd_node_term *
Radek Krejci576b23f2019-07-12 14:06:32 +0200422lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200423{
424 unsigned int u, v, x;
425 const struct lyd_node *node = NULL, *parent = NULL, *start_search;
426 uint64_t pos = 1;
427
428 LY_CHECK_ARG_RET(NULL, path, trees, NULL);
429
430 LY_ARRAY_FOR(path, u) {
431 if (parent) {
432 start_search = lyd_node_children(parent);
433search_inner:
434 node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
435 } else {
436 LY_ARRAY_FOR(trees, v) {
437 start_search = trees[v];
438search_toplevel:
439 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
440 node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
441 if (node) {
442 break;
443 }
444 }
445 }
446 if (!node) {
447 return NULL;
448 }
449
450 /* check predicate if any */
451 LY_ARRAY_FOR(path[u].predicates, x) {
452 if (path[u].predicates[x].type == 0) {
453 /* position predicate */
454 if (pos != path[u].predicates[x].position) {
455 pos++;
456 goto search_repeat;
457 }
458 /* done, no more predicates are allowed here */
459 break;
460 } else if (path[u].predicates[x].type == 1) {
461 /* key-predicate */
462 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
463 const struct lyd_node *key = lyd_search(lyd_node_children(node), path[u].predicates[x].key->module,
464 path[u].predicates[x].key->name, strlen(path[u].predicates[x].key->name),
465 LYS_LEAF, NULL, 0);
466 if (!key) {
467 /* probably error and we shouldn't be here due to previous checks when creating path */
468 goto search_repeat;
469 }
470 if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
471 goto search_repeat;
472 }
473 } else if (path[u].predicates[x].type == 2) {
474 /* leaf-list-predicate */
475 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
476 if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
477 goto search_repeat;
478 }
479 } else {
480 LOGINT(NULL);
481 }
482 }
483
484 parent = node;
485 }
486
487 return (const struct lyd_node_term*)node;
488
489search_repeat:
490 start_search = node->next;
491 if (parent) {
492 goto search_inner;
493 } else {
494 goto search_toplevel;
495 }
496}
497
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200498API LY_ERR
499lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
500{
501 const struct lyd_node *iter1, *iter2;
502 struct lyd_node_term *term1, *term2;
503 struct lyd_node_any *any1, *any2;
504 struct lysc_type *type;
505 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +0200506
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200507 if (!node1 || !node2) {
508 if (node1 == node2) {
509 return LY_SUCCESS;
510 } else {
511 return LY_ENOT;
512 }
513 }
514
515 if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2 ->schema) {
516 return LY_ENOT;
517 }
518
519 if (node1->hash != node2->hash) {
520 return LY_ENOT;
521 }
522
523 /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
524
525 switch (node1->schema->nodetype) {
526 case LYS_LEAF:
527 case LYS_LEAFLIST:
528 if (options & LYD_COMPARE_DEFAULTS) {
529 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
530 return LY_ENOT;
531 }
532 }
533
534 term1 = (struct lyd_node_term*)node1;
535 term2 = (struct lyd_node_term*)node2;
536 type = ((struct lysc_node_leaf*)node1->schema)->type;
537
538 return type->plugin->compare(&term1->value, &term2->value);
539 case LYS_CONTAINER:
540 if (options & LYD_COMPARE_DEFAULTS) {
541 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
542 return LY_ENOT;
543 }
544 }
545 if (options & LYD_COMPARE_FULL_RECURSION) {
546 iter1 = ((struct lyd_node_inner*)node1)->child;
547 iter2 = ((struct lyd_node_inner*)node2)->child;
548 goto all_children_compare;
549 }
550 return LY_SUCCESS;
551 case LYS_ACTION:
552 if (options & LYD_COMPARE_FULL_RECURSION) {
553 /* TODO action/RPC
554 goto all_children_compare;
555 */
556 }
557 return LY_SUCCESS;
558 case LYS_NOTIF:
559 if (options & LYD_COMPARE_FULL_RECURSION) {
560 /* TODO Notification
561 goto all_children_compare;
562 */
563 }
564 return LY_SUCCESS;
565 case LYS_LIST:
566 iter1 = ((struct lyd_node_inner*)node1)->child;
567 iter2 = ((struct lyd_node_inner*)node2)->child;
568
Radek Krejcif6aa45c2019-07-23 16:59:14 +0200569 if (((struct lysc_node_list*)node1->schema)->keys && !(options & LYD_COMPARE_FULL_RECURSION)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200570 /* lists with keys, their equivalence is based on their keys */
571 unsigned int u;
572
573 LY_ARRAY_FOR(((struct lysc_node_list*)node1->schema)->keys, u) {
574 if (lyd_compare(iter1, iter2, options)) {
575 return LY_ENOT;
576 }
577 iter1 = iter1->next;
578 iter2 = iter2->next;
579 }
580 } else {
581 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
582
583all_children_compare:
584 if (!iter1 && !iter2) {
585 /* no children, nothing to compare */
586 return LY_SUCCESS;
587 }
588
589 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
590 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
591 return LY_ENOT;
592 }
593 }
594 if (iter1 || iter2) {
595 return LY_ENOT;
596 }
597 }
598 return LY_SUCCESS;
599 case LYS_ANYXML:
600 case LYS_ANYDATA:
601 any1 = (struct lyd_node_any*)node1;
602 any2 = (struct lyd_node_any*)node2;
603
604 if (any1->value_type != any2->value_type) {
605 return LY_ENOT;
606 }
607 switch (any1->value_type) {
608 case LYD_ANYDATA_DATATREE:
609 iter1 = any1->value.tree;
610 iter2 = any2->value.tree;
611 goto all_children_compare;
612 case LYD_ANYDATA_STRING:
613 case LYD_ANYDATA_XML:
614 case LYD_ANYDATA_JSON:
615 len1 = strlen(any1->value.str);
616 len2 = strlen(any2->value.str);
617 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
618 return LY_ENOT;
619 }
620 return LY_SUCCESS;
621#if 0 /* TODO LYB format */
622 case LYD_ANYDATA_LYB:
623 int len1 = lyd_lyb_data_length(any1->value.mem);
624 int len2 = lyd_lyb_data_length(any2->value.mem);
625 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
626 return LY_ENOT;
627 }
628 return LY_SUCCESS;
629#endif
630 }
631 }
632
633 LOGINT(node1->schema->module->ctx);
634 return LY_EINT;
635}
Radek Krejci22ebdba2019-07-25 13:59:43 +0200636
637/**
638 * @brief Duplicates just a single node and interconnect it into a @p parent (if present) and after the @p prev
639 * sibling (if present).
640 *
641 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
642 */
643static struct lyd_node *
644lyd_dup_recursive(const struct lyd_node *node, struct lyd_node_inner *parent, struct lyd_node *prev, int options)
645{
646 struct ly_ctx *ctx;
647 struct lyd_node *dup = NULL;
648
649 LY_CHECK_ARG_RET(NULL, node, NULL);
650 ctx = node->schema->module->ctx;
651
652 switch (node->schema->nodetype) {
653 case LYS_ACTION:
654 case LYS_NOTIF:
655 case LYS_CONTAINER:
656 case LYS_LIST:
657 dup = calloc(1, sizeof(struct lyd_node_inner));
658 break;
659 case LYS_LEAF:
660 case LYS_LEAFLIST:
661 dup = calloc(1, sizeof(struct lyd_node_term));
662 break;
663 case LYS_ANYDATA:
664 case LYS_ANYXML:
665 dup = calloc(1, sizeof(struct lyd_node_any));
666 break;
667 default:
668 LOGINT(ctx);
669 goto error;
670 }
671
672 /* TODO implement LYD_DUP_WITH_WHEN */
673 dup->flags = node->flags;
674 dup->schema = node->schema;
675
676 /* interconnect the node at the end */
677 dup->parent = parent;
678 if (prev) {
679 dup->prev = prev;
680 prev->next = dup;
681 } else {
682 dup->prev = dup;
683 if (parent) {
684 parent->child = dup;
685 }
686 }
687 if (parent) {
688 parent->child->prev = dup;
689 } else if (prev) {
690 struct lyd_node *first;
691 for (first = prev; first->prev != prev; first = first->prev);
692 first->prev = dup;
693 }
694
695 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
696
697 /* nodetype-specific work */
698 if (dup->schema->nodetype & LYD_NODE_TERM) {
699 struct lyd_node_term *term = (struct lyd_node_term*)dup;
700 struct lyd_node_term *orig = (struct lyd_node_term*)node;
701
702 term->hash = orig->hash;
703 term->value.realtype = orig->value.realtype;
704 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(ctx, &orig->value, &term->value),
705 LOGERR(ctx, LY_EINT, "Value duplication failed."), error);
706 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
707 struct lyd_node_inner *inner = (struct lyd_node_inner*)dup;
708 struct lyd_node_inner *orig = (struct lyd_node_inner*)node;
709 struct lyd_node *child, *last = NULL;
710
711 if (options & LYD_DUP_RECURSIVE) {
712 /* duplicate all the children */
713 LY_LIST_FOR(orig->child, child) {
714 last = lyd_dup_recursive(child, inner, last, options);
715 LY_CHECK_GOTO(!last, error);
716 }
717 } else if (dup->schema->nodetype == LYS_LIST && ((struct lysc_node_list*)dup->schema)->keys) {
718 /* always duplicate keys of a list */
719 unsigned int u;
720
721 child = orig->child;
722 LY_ARRAY_FOR(((struct lysc_node_list*)dup->schema)->keys, u) {
723 if (!child) {
724 /* possibly not keys are present in filtered tree */
725 break;
726 }
727 last = lyd_dup_recursive(child, inner, last, options);
728 child = child->next;
729 }
730 }
731 lyd_hash(dup);
732 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
733 struct lyd_node_any *any = (struct lyd_node_any*)dup;
734 struct lyd_node_any *orig = (struct lyd_node_any*)node;
735
736 any->hash = orig->hash;
737 any->value_type = orig->value_type;
738 switch (any->value_type) {
739 case LYD_ANYDATA_DATATREE:
740 if (orig->value.tree) {
741 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
742 LY_CHECK_GOTO(!any->value.tree, error);
743 }
744 break;
745 case LYD_ANYDATA_STRING:
746 case LYD_ANYDATA_XML:
747 case LYD_ANYDATA_JSON:
748 if (orig->value.str) {
749 any->value.str = lydict_insert(ctx, orig->value.str, strlen(orig->value.str));
750 }
751 break;
752 }
753 }
754
755 lyd_insert_hash(dup);
756 return dup;
757
758error:
759 if (!parent && !prev) {
760 lyd_free_tree(dup);
761 }
762 return NULL;
763}
764
765API struct lyd_node *
766lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
767{
768 struct ly_ctx *ctx;
769 const struct lyd_node *orig; /* original node to be duplicated */
770 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
771 struct lyd_node *last = NULL; /* the last sibling of the duplicated nodes */
772 struct lyd_node *top = NULL; /* the most higher created node */
773 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
774 int keyless_parent_list = 0;
775
776 LY_CHECK_ARG_RET(NULL, node, NULL);
777 ctx = node->schema->module->ctx;
778
779 if (options & LYD_DUP_WITH_PARENTS) {
780 struct lyd_node_inner *orig_parent, *iter;
781 int repeat = 1;
782 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
783 if (parent && parent->schema == orig_parent->schema) {
784 /* stop creating parents, connect what we have into the provided parent */
785 iter = parent;
786 repeat = 0;
787 /* get know if there is a keyless list which we will have to rehash */
788 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
789 if (piter->schema->nodetype == LYS_LIST && !((struct lysc_node_list*)piter->schema)->keys) {
790 keyless_parent_list = 1;
791 break;
792 }
793 }
794 } else {
795 iter = (struct lyd_node_inner*)lyd_dup_recursive((struct lyd_node*)orig_parent, NULL, NULL, 0);
796 LY_CHECK_GOTO(!iter, error);
797 }
798 if (!local_parent) {
799 local_parent = iter;
800 }
801 if (iter->child) {
802 /* 1) list - add after keys
803 * 2) provided parent with some children */
804 iter->child->prev->next = top;
805 if (top) {
806 top->prev = iter->child->prev;
807 iter->child->prev = top;
808 }
809 } else {
810 iter->child = top;
811 if (iter->schema->nodetype == LYS_LIST) {
812 /* keyless list - we will need to rehash it since we are going to add nodes into it */
813 keyless_parent_list = 1;
814 }
815 }
816 if (top) {
817 top->parent = iter;
818 }
819 top = (struct lyd_node*)iter;
820 }
821 if (repeat && parent) {
822 /* given parent and created parents chain actually do not interconnect */
823 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
824 goto error;
825 }
826 } else {
827 local_parent = parent;
828 }
829
830 if (local_parent && local_parent->child) {
831 last = local_parent->child->prev;
832 }
833
834 LY_LIST_FOR(node, orig) {
835 last = lyd_dup_recursive(orig, local_parent, last, options);
836 LY_CHECK_GOTO(!last, error);
837 if (!first) {
838 first = last;
839 }
840
841 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
842 break;
843 }
844 }
845 if (keyless_parent_list) {
846 /* rehash */
847 for (; local_parent; local_parent = local_parent->parent) {
848 if (local_parent->schema->nodetype == LYS_LIST && !((struct lysc_node_list*)local_parent->schema)->keys) {
849 lyd_hash((struct lyd_node*)local_parent);
850 }
851 }
852 }
853 return first;
854
855error:
856 if (top) {
857 lyd_free_tree(top);
858 } else {
859 lyd_free_withsiblings(first);
860 }
861 return NULL;
862}