blob: 968dd87b1289702ee57901c4e9231cf19162acfc [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_data_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions for data trees
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 */
Radek Krejcie7b95092019-05-15 11:03:07 +020014
15#include <assert.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020016#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020017#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020018#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
21#include "context.h"
Radek Krejci47fab892020-11-05 17:02:41 +010022#include "dict.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020023#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020025#include "lyb.h"
Radek Krejci7931b192020-06-25 17:05:03 +020026#include "parser_data.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020027#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020028#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020030#include "tree_data_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "tree_schema.h"
32
Michal Vaskoa6669ba2020-08-06 16:14:26 +020033struct lyd_node *
34lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
Radek Krejci0f969882020-08-21 16:56:47 +020035 const struct lysc_node *parent, const struct lysc_module *module)
Michal Vaskoa6669ba2020-08-06 16:14:26 +020036{
37 const struct lysc_node *siter = NULL;
38 struct lyd_node *match = NULL;
39
40 assert(parent || module);
41 assert(!last || (slast && *slast));
42
43 if (slast) {
44 siter = *slast;
45 }
46
47 if (last && last->next && (last->next->schema == siter)) {
48 /* return next data instance */
49 return last->next;
50 }
51
52 /* find next schema node data instance */
53 while ((siter = lys_getnext(siter, parent, module, 0))) {
54 if (!lyd_find_sibling_val(sibling, siter, NULL, 0, &match)) {
55 break;
56 }
57 }
58
59 if (slast) {
60 *slast = siter;
61 }
62 return match;
63}
64
Radek Krejcie7b95092019-05-15 11:03:07 +020065struct lyd_node **
66lyd_node_children_p(struct lyd_node *node)
67{
68 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +010069
70 if (!node->schema) {
71 return &((struct lyd_node_opaq *)node)->child;
72 } else {
73 switch (node->schema->nodetype) {
74 case LYS_CONTAINER:
75 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +010076 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +010077 case LYS_ACTION:
78 case LYS_NOTIF:
79 return &((struct lyd_node_inner *)node)->child;
80 default:
81 return NULL;
82 }
Radek Krejcie7b95092019-05-15 11:03:07 +020083 }
84}
85
Radek Krejcidae0ee82020-05-06 16:53:24 +020086API struct lyd_node *
Radek Krejcia1c1e542020-09-29 16:06:52 +020087lyd_parent(const struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +020088{
Radek Krejcia1c1e542020-09-29 16:06:52 +020089 if (!node) {
90 return NULL;
91 }
92
93 return (struct lyd_node *)(node)->parent;
94}
95
96API struct lyd_node *
97lyd_child(const struct lyd_node *node)
98{
99 struct lyd_node **children;
Radek Krejcie7b95092019-05-15 11:03:07 +0200100
101 if (!node) {
102 return NULL;
103 }
104
Radek Krejcia1c1e542020-09-29 16:06:52 +0200105 if (!node->schema) {
106 /* opaq node */
107 return ((struct lyd_node_opaq *)(node))->child;
108 }
109
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200110 children = lyd_node_children_p((struct lyd_node *)node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200111 if (children) {
Radek Krejcia1c1e542020-09-29 16:06:52 +0200112 return *children;
113 } else {
114 return NULL;
115 }
116}
117
118API struct lyd_node *
119lyd_child_no_keys(const struct lyd_node *node)
120{
121 struct lyd_node **children;
122
123 if (!node) {
124 return NULL;
125 }
126
127 if (!node->schema) {
128 /* opaq node */
129 return ((struct lyd_node_opaq *)(node))->child;
130 }
131
132 children = lyd_node_children_p((struct lyd_node *)node);
133 if (children) {
134 struct lyd_node *child = *children;
135 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
136 child = child->next;
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200137 }
138 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +0200139 } else {
140 return NULL;
141 }
142}
Michal Vasko9b368d32020-02-14 13:53:31 +0100143
Michal Vaskoc193ce92020-03-06 11:04:48 +0100144API const struct lys_module *
145lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +0100146{
147 const struct lysc_node *schema;
148
Michal Vasko52927e22020-03-16 17:26:14 +0100149 if (!node || !node->schema) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100150 return NULL;
151 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100152
Radek Krejci1e008d22020-08-17 11:37:37 +0200153 for (schema = node->schema; schema->parent; schema = schema->parent) {}
Michal Vasko9b368d32020-02-14 13:53:31 +0100154 return schema->module;
155}
Michal Vaskob1b5c262020-03-05 14:29:47 +0100156
Michal Vasko8207e7e2020-11-09 21:03:54 +0100157API const struct lysc_when *
158lyd_has_when(const struct lyd_node *node)
159{
160 const struct lysc_node *schema;
161
162 if (!node || !node->schema) {
163 return NULL;
164 }
165
166 schema = node->schema;
167 do {
168 if (schema->when) {
169 return *schema->when;
170 }
171 schema = schema->parent;
172 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
173
174 return NULL;
175}
176
Michal Vaskob1b5c262020-03-05 14:29:47 +0100177const struct lys_module *
Michal Vasko26e80012020-07-08 10:55:46 +0200178lyd_mod_next_module(struct lyd_node *tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t *i,
Radek Krejci0f969882020-08-21 16:56:47 +0200179 struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100180{
181 struct lyd_node *iter;
182 const struct lys_module *mod;
183
184 /* get the next module */
Michal Vasko26e80012020-07-08 10:55:46 +0200185 if (module) {
186 if (*i) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100187 mod = NULL;
Michal Vasko26e80012020-07-08 10:55:46 +0200188 } else {
189 mod = module;
190 ++(*i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100191 }
192 } else {
193 do {
194 mod = ly_ctx_get_module_iter(ctx, i);
195 } while (mod && !mod->implemented);
196 }
197
198 /* find its data */
199 *first = NULL;
200 if (mod) {
201 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100202 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100203 *first = iter;
204 break;
205 }
206 }
207 }
208
209 return mod;
210}
211
212const struct lys_module *
213lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
214{
215 const struct lys_module *mod;
216
217 if (!*next) {
218 /* all data traversed */
219 *first = NULL;
220 return NULL;
221 }
222
223 *first = *next;
224
225 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100226 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100227 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100228 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100229 break;
230 }
231 }
232
233 return mod;
234}
Michal Vasko9f96a052020-03-10 09:41:45 +0100235
236LY_ERR
237lyd_parse_check_keys(struct lyd_node *node)
238{
239 const struct lysc_node *skey = NULL;
240 const struct lyd_node *key;
241
242 assert(node->schema->nodetype == LYS_LIST);
243
Radek Krejcia1c1e542020-09-29 16:06:52 +0200244 key = lyd_child(node);
Michal Vasko9f96a052020-03-10 09:41:45 +0100245 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
246 if (!key || (key->schema != skey)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200247 LOGVAL(LYD_CTX(node), LY_VLOG_LYD, node, LY_VCODE_NOKEY, skey->name);
Michal Vasko9f96a052020-03-10 09:41:45 +0100248 return LY_EVALID;
249 }
250
251 key = key->next;
252 }
253
254 return LY_SUCCESS;
255}
Michal Vasko60ea6352020-06-29 13:39:39 +0200256
257void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200258lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct lyd_meta **meta, uint32_t options)
Michal Vasko60ea6352020-06-29 13:39:39 +0200259{
260 struct lyd_meta *meta2, *prev_meta = NULL;
261
262 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
Michal Vasko0f3377d2020-11-09 20:56:11 +0100263 if (!(options & LYD_PARSE_ONLY)) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200264 /* remember we need to evaluate this node's when */
Radek Krejci3d92e442020-10-12 12:48:13 +0200265 LY_CHECK_RET(ly_set_add(when_check, node, 1, NULL), );
Michal Vasko60ea6352020-06-29 13:39:39 +0200266 }
267 }
268
Michal Vasko60ea6352020-06-29 13:39:39 +0200269 LY_LIST_FOR(*meta, meta2) {
Michal Vasko69730152020-10-09 16:30:07 +0200270 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
271 meta2->value.boolean) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200272 /* node is default according to the metadata */
273 node->flags |= LYD_DEFAULT;
274
275 /* delete the metadata */
276 if (prev_meta) {
277 prev_meta->next = meta2->next;
278 } else {
279 *meta = (*meta)->next;
280 }
Michal Vasko3a41dff2020-07-15 14:30:28 +0200281 lyd_free_meta_single(meta2);
Michal Vasko60ea6352020-06-29 13:39:39 +0200282 break;
283 }
284
285 prev_meta = meta2;
286 }
287}
288
Michal Vaskoc0004272020-08-06 08:32:34 +0200289API LY_ERR
Michal Vasko61551fa2020-07-09 15:45:45 +0200290lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_ANYDATA_VALUETYPE value_type)
291{
292 struct lyd_node_any *t;
Michal Vasko61551fa2020-07-09 15:45:45 +0200293
294 assert(trg->schema->nodetype & LYS_ANYDATA);
295
296 t = (struct lyd_node_any *)trg;
297
298 /* free trg */
299 switch (t->value_type) {
300 case LYD_ANYDATA_DATATREE:
301 lyd_free_all(t->value.tree);
302 break;
303 case LYD_ANYDATA_STRING:
304 case LYD_ANYDATA_XML:
305 case LYD_ANYDATA_JSON:
Michal Vaskob7be7a82020-08-20 09:09:04 +0200306 FREE_STRING(LYD_CTX(trg), t->value.str);
Michal Vasko61551fa2020-07-09 15:45:45 +0200307 break;
308 case LYD_ANYDATA_LYB:
309 free(t->value.mem);
310 break;
311 }
312 t->value.str = NULL;
313
314 if (!value) {
315 /* only free value in this case */
316 return LY_SUCCESS;
317 }
318
319 /* copy src */
320 t->value_type = value_type;
321 switch (value_type) {
322 case LYD_ANYDATA_DATATREE:
323 if (value->tree) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200324 LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
Michal Vasko61551fa2020-07-09 15:45:45 +0200325 }
326 break;
327 case LYD_ANYDATA_STRING:
328 case LYD_ANYDATA_XML:
329 case LYD_ANYDATA_JSON:
330 if (value->str) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200331 LY_CHECK_RET(lydict_insert(LYD_CTX(trg), value->str, 0, &t->value.str));
Michal Vasko61551fa2020-07-09 15:45:45 +0200332 }
333 break;
334 case LYD_ANYDATA_LYB:
335 if (value->mem) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200336 int len = lyd_lyb_data_length(value->mem);
Radek Krejci82fa8d42020-07-11 22:00:59 +0200337 LY_CHECK_RET(len == -1, LY_EINVAL);
Michal Vasko61551fa2020-07-09 15:45:45 +0200338 t->value.mem = malloc(len);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200339 LY_CHECK_ERR_RET(!t->value.mem, LOGMEM(LYD_CTX(trg)), LY_EMEM);
Michal Vasko61551fa2020-07-09 15:45:45 +0200340 memcpy(t->value.mem, value->mem, len);
341 }
342 break;
343 }
344
345 return LY_SUCCESS;
346}
347
Michal Vasko60ea6352020-06-29 13:39:39 +0200348LYB_HASH
349lyb_hash(struct lysc_node *sibling, uint8_t collision_id)
350{
351 const struct lys_module *mod;
Michal Vasko60ea6352020-06-29 13:39:39 +0200352 uint32_t full_hash;
353 LYB_HASH hash;
354
355 if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
356 return sibling->hash[collision_id];
357 }
358
359 mod = sibling->module;
360
361 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
362 full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
363 if (collision_id) {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200364 size_t ext_len;
365
Michal Vasko60ea6352020-06-29 13:39:39 +0200366 if (collision_id > strlen(mod->name)) {
367 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
368 ext_len = strlen(mod->name);
369 } else {
370 /* use one more byte from the module name than before */
371 ext_len = collision_id;
372 }
373 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
374 }
375 full_hash = dict_hash_multi(full_hash, NULL, 0);
376
377 /* use the shortened hash */
378 hash = full_hash & (LYB_HASH_MASK >> collision_id);
379 /* add colision identificator */
380 hash |= LYB_HASH_COLLISION_ID >> collision_id;
381
382 /* save this hash */
383 if (collision_id < LYS_NODE_HASH_COUNT) {
384 sibling->hash[collision_id] = hash;
385 }
386
387 return hash;
388}
389
Radek Krejci857189e2020-09-01 13:26:36 +0200390ly_bool
Michal Vasko60ea6352020-06-29 13:39:39 +0200391lyb_has_schema_model(const struct lysc_node *sibling, const struct lys_module **models)
392{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200393 LY_ARRAY_COUNT_TYPE u;
Michal Vasko60ea6352020-06-29 13:39:39 +0200394
395 LY_ARRAY_FOR(models, u) {
396 if (sibling->module == models[u]) {
397 return 1;
398 }
399 }
400
401 return 0;
402}