blob: 0b1dbcb1f23b9e906c971ee15a9f0bf1ce693baa [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
Michal Vaskob1b5c262020-03-05 14:29:47 +01002 * @file tree_data.c
Radek Krejcie7b95092019-05-15 11:03:07 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01004 * @author Michal Vasko <mvasko@cesnet.cz>
Michal Vasko6cd9b6b2020-06-22 10:05:22 +02005 * @brief Data tree functions
Radek Krejcie7b95092019-05-15 11:03:07 +02006 *
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +01007 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Radek Krejci535ea9f2020-05-29 16:01:05 +020016#define _GNU_SOURCE
17
18#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci084289f2019-07-09 17:35:30 +020020#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include <ctype.h>
Radek Krejci47fab892020-11-05 17:02:41 +010022#include <inttypes.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <stdarg.h>
24#include <stdint.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include <stdio.h>
26#include <stdlib.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020028
Michal Vasko5aa44c02020-06-29 11:47:02 +020029#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "context.h"
31#include "dict.h"
Michal Vaskoa6669ba2020-08-06 16:14:26 +020032#include "diff.h"
Michal Vasko90932a92020-02-12 14:33:03 +010033#include "hash_table.h"
Radek Krejci47fab892020-11-05 17:02:41 +010034#include "in.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020035#include "in_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010037#include "ly_common.h"
Radek Krejci7931b192020-06-25 17:05:03 +020038#include "parser_data.h"
39#include "parser_internal.h"
Michal Vasko004d3152020-06-11 19:59:22 +020040#include "path.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020041#include "plugins.h"
Radek Krejcif1ca0ac2021-04-12 16:00:06 +020042#include "plugins_exts/metadata.h"
Radek Krejci3e6632f2021-03-22 22:08:21 +010043#include "plugins_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020044#include "plugins_types.h"
45#include "set.h"
46#include "tree.h"
47#include "tree_data_internal.h"
aPiecek6cf1d162023-11-08 16:07:00 +010048#include "tree_data_sorted.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010049#include "tree_edit.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020050#include "tree_schema.h"
51#include "tree_schema_internal.h"
Michal Vaskoa6669ba2020-08-06 16:14:26 +020052#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020053#include "xml.h"
54#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020055
Michal Vaskof277d362023-04-24 09:08:31 +020056static LY_ERR lyd_compare_siblings_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
57 ly_bool parental_schemas_checked);
58
Radek Krejci7931b192020-06-25 17:05:03 +020059static LYD_FORMAT
Michal Vasko63f3d842020-07-08 10:10:14 +020060lyd_parse_get_format(const struct ly_in *in, LYD_FORMAT format)
Radek Krejcie7b95092019-05-15 11:03:07 +020061{
Michal Vasko69730152020-10-09 16:30:07 +020062 if (!format && (in->type == LY_IN_FILEPATH)) {
Radek Krejcie7b95092019-05-15 11:03:07 +020063 /* unknown format - try to detect it from filename's suffix */
Radek Krejci7931b192020-06-25 17:05:03 +020064 const char *path = in->method.fpath.filepath;
65 size_t len = strlen(path);
Radek Krejcie7b95092019-05-15 11:03:07 +020066
67 /* ignore trailing whitespaces */
Michal Vaskod989ba02020-08-24 10:59:24 +020068 for ( ; len > 0 && isspace(path[len - 1]); len--) {}
Radek Krejcie7b95092019-05-15 11:03:07 +020069
Radek Krejcif13b87b2020-12-01 22:02:17 +010070 if ((len >= LY_XML_SUFFIX_LEN + 1) &&
71 !strncmp(&path[len - LY_XML_SUFFIX_LEN], LY_XML_SUFFIX, LY_XML_SUFFIX_LEN)) {
Radek Krejcie7b95092019-05-15 11:03:07 +020072 format = LYD_XML;
Radek Krejcif13b87b2020-12-01 22:02:17 +010073 } else if ((len >= LY_JSON_SUFFIX_LEN + 1) &&
74 !strncmp(&path[len - LY_JSON_SUFFIX_LEN], LY_JSON_SUFFIX, LY_JSON_SUFFIX_LEN)) {
Radek Krejcie7b95092019-05-15 11:03:07 +020075 format = LYD_JSON;
Radek Krejcif13b87b2020-12-01 22:02:17 +010076 } else if ((len >= LY_LYB_SUFFIX_LEN + 1) &&
77 !strncmp(&path[len - LY_LYB_SUFFIX_LEN], LY_LYB_SUFFIX, LY_LYB_SUFFIX_LEN)) {
Radek Krejcie7b95092019-05-15 11:03:07 +020078 format = LYD_LYB;
Radek Krejci7931b192020-06-25 17:05:03 +020079 } /* else still unknown */
Radek Krejcie7b95092019-05-15 11:03:07 +020080 }
81
Radek Krejci7931b192020-06-25 17:05:03 +020082 return format;
83}
Radek Krejcie7b95092019-05-15 11:03:07 +020084
Michal Vaskoe0665742021-02-11 11:08:44 +010085/**
86 * @brief Parse YANG data into a data tree.
87 *
88 * @param[in] ctx libyang context.
Radek Krejcif16e2542021-02-17 15:39:23 +010089 * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
Michal Vaskoe0665742021-02-11 11:08:44 +010090 * @param[in] parent Parent to connect the parsed nodes to, if any.
Michal Vaskob36c56f2024-01-31 12:50:07 +010091 * @param[in,out] first_p Pointer to the first parsed node.
Michal Vaskoe0665742021-02-11 11:08:44 +010092 * @param[in] in Input handle to read the input from.
93 * @param[in] format Expected format of the data in @p in.
94 * @param[in] parse_opts Options for parser.
95 * @param[in] val_opts Options for validation.
96 * @param[out] op Optional pointer to the parsed operation, if any.
97 * @return LY_ERR value.
98 */
99static LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +0100100lyd_parse(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent, struct lyd_node **first_p,
101 struct ly_in *in, LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
Radek Krejci7931b192020-06-25 17:05:03 +0200102{
stewegd8e2fc92023-05-31 09:52:56 +0200103 LY_ERR r = LY_SUCCESS, rc = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200104 struct lyd_ctx *lydctx = NULL;
Michal Vaskoe0665742021-02-11 11:08:44 +0100105 struct ly_set parsed = {0};
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100106 uint32_t i, int_opts = 0;
Michal Vasko7a266772024-01-23 11:02:38 +0100107 const struct ly_err_item *eitem;
Michal Vaskoddd76592022-01-17 13:34:48 +0100108 ly_bool subtree_sibling = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +0200109
Michal Vaskoe0665742021-02-11 11:08:44 +0100110 assert(ctx && (parent || first_p));
Radek Krejci7931b192020-06-25 17:05:03 +0200111
112 format = lyd_parse_get_format(in, format);
Michal Vaskoe0665742021-02-11 11:08:44 +0100113 if (first_p) {
114 *first_p = NULL;
115 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200116
Michal Vasko63f3d842020-07-08 10:10:14 +0200117 /* remember input position */
118 in->func_start = in->current;
Radek Krejci7931b192020-06-25 17:05:03 +0200119
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100120 /* set internal options */
121 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
122 int_opts = LYD_INTOPT_WITH_SIBLINGS;
123 }
124
Michal Vaskoe0665742021-02-11 11:08:44 +0100125 /* parse the data */
Radek Krejci7931b192020-06-25 17:05:03 +0200126 switch (format) {
127 case LYD_XML:
Michal Vaskod027f382023-02-10 09:13:25 +0100128 r = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
Michal Vaskoddd76592022-01-17 13:34:48 +0100129 &subtree_sibling, &lydctx);
Radek Krejci1798aae2020-07-14 13:26:06 +0200130 break;
Radek Krejci7931b192020-06-25 17:05:03 +0200131 case LYD_JSON:
Michal Vaskod027f382023-02-10 09:13:25 +0100132 r = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
Michal Vaskoddd76592022-01-17 13:34:48 +0100133 &subtree_sibling, &lydctx);
Radek Krejci1798aae2020-07-14 13:26:06 +0200134 break;
Radek Krejci7931b192020-06-25 17:05:03 +0200135 case LYD_LYB:
Michal Vaskod027f382023-02-10 09:13:25 +0100136 r = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
Michal Vaskoddd76592022-01-17 13:34:48 +0100137 &subtree_sibling, &lydctx);
Radek Krejci1798aae2020-07-14 13:26:06 +0200138 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200139 case LYD_UNKNOWN:
Michal Vaskod74978f2021-02-12 11:59:36 +0100140 LOGARG(ctx, format);
Michal Vaskod027f382023-02-10 09:13:25 +0100141 r = LY_EINVAL;
Michal Vaskoe0665742021-02-11 11:08:44 +0100142 break;
143 }
Michal Vasko50da8cd2023-03-10 08:38:59 +0100144 if (r) {
145 rc = r;
Michal Vasko7a266772024-01-23 11:02:38 +0100146 if ((r != LY_EVALID) || !lydctx || !(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR)) {
147 goto cleanup;
148 }
149
150 eitem = ly_err_last(ctx);
151 assert(eitem);
152 if (eitem->vecode == LYVE_SYNTAX) {
153 /* cannot get more errors on a syntax error */
Michal Vasko50da8cd2023-03-10 08:38:59 +0100154 goto cleanup;
155 }
156 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100157
Michal Vaskoa6139e02023-10-03 14:13:22 +0200158 if (parent && parsed.count) {
159 /* use the first parsed node */
Michal Vaskob36c56f2024-01-31 12:50:07 +0100160 if (first_p) {
161 *first_p = parsed.dnodes[0];
162 } else {
163 first_p = &parsed.dnodes[0];
164 }
Radek Krejci7931b192020-06-25 17:05:03 +0200165 }
166
Michal Vaskoe0665742021-02-11 11:08:44 +0100167 if (!(parse_opts & LYD_PARSE_ONLY)) {
168 /* validate data */
Michal Vasko9f6dd7c2023-04-06 08:46:30 +0200169 r = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
Michal Vasko135719f2022-08-25 12:18:17 +0200170 &lydctx->ext_node, &lydctx->ext_val, NULL);
Michal Vasko9f6dd7c2023-04-06 08:46:30 +0200171 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +0100172 }
Radek Krejci7931b192020-06-25 17:05:03 +0200173
Michal Vaskoe0665742021-02-11 11:08:44 +0100174 /* set the operation node */
175 if (op) {
176 *op = lydctx->op_node;
Radek Krejci1798aae2020-07-14 13:26:06 +0200177 }
178
179cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100180 if (lydctx) {
181 lydctx->free(lydctx);
Radek Krejci1798aae2020-07-14 13:26:06 +0200182 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100183 if (rc) {
184 if (parent) {
185 /* free all the parsed subtrees */
186 for (i = 0; i < parsed.count; ++i) {
187 lyd_free_tree(parsed.dnodes[i]);
188 }
189 } else {
190 /* free everything */
191 lyd_free_all(*first_p);
192 *first_p = NULL;
193 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100194 } else if (subtree_sibling) {
195 rc = LY_ENOT;
Michal Vaskoe0665742021-02-11 11:08:44 +0100196 }
197 ly_set_erase(&parsed, NULL);
198 return rc;
Radek Krejci7931b192020-06-25 17:05:03 +0200199}
200
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100201LIBYANG_API_DEF LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +0100202lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
203 uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
204{
205 const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
206
207 LY_CHECK_ARG_RET(ctx, ext, in, parent || tree, LY_EINVAL);
208 LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
209 LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
210
211 return lyd_parse(ctx, ext, parent, tree, in, format, parse_options, validate_options, NULL);
212}
213
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100214LIBYANG_API_DEF LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100215lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
216 uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
217{
218 LY_CHECK_ARG_RET(ctx, ctx, in, parent || tree, LY_EINVAL);
219 LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
220 LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
221
Radek Krejcif16e2542021-02-17 15:39:23 +0100222 return lyd_parse(ctx, NULL, parent, tree, in, format, parse_options, validate_options, NULL);
Michal Vaskoe0665742021-02-11 11:08:44 +0100223}
224
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100225LIBYANG_API_DEF LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100226lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, uint32_t parse_options,
227 uint32_t validate_options, struct lyd_node **tree)
Radek Krejci7931b192020-06-25 17:05:03 +0200228{
229 LY_ERR ret;
230 struct ly_in *in;
231
232 LY_CHECK_RET(ly_in_new_memory(data, &in));
Michal Vaskoe0665742021-02-11 11:08:44 +0100233 ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
Radek Krejci7931b192020-06-25 17:05:03 +0200234
235 ly_in_free(in, 0);
236 return ret;
237}
238
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100239LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200240lyd_parse_data_fd(const struct ly_ctx *ctx, int fd, LYD_FORMAT format, uint32_t parse_options, uint32_t validate_options,
Radek Krejci0f969882020-08-21 16:56:47 +0200241 struct lyd_node **tree)
Radek Krejci7931b192020-06-25 17:05:03 +0200242{
243 LY_ERR ret;
244 struct ly_in *in;
245
246 LY_CHECK_RET(ly_in_new_fd(fd, &in));
Michal Vaskoe0665742021-02-11 11:08:44 +0100247 ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
Radek Krejci7931b192020-06-25 17:05:03 +0200248
249 ly_in_free(in, 0);
250 return ret;
251}
252
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100253LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200254lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, uint32_t parse_options,
255 uint32_t validate_options, struct lyd_node **tree)
Radek Krejci7931b192020-06-25 17:05:03 +0200256{
257 LY_ERR ret;
258 struct ly_in *in;
259
260 LY_CHECK_RET(ly_in_new_filepath(path, 0, &in));
Michal Vaskoe0665742021-02-11 11:08:44 +0100261 ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
Radek Krejci7931b192020-06-25 17:05:03 +0200262
263 ly_in_free(in, 0);
264 return ret;
265}
266
Radek Krejcif16e2542021-02-17 15:39:23 +0100267/**
268 * @brief Parse YANG data into an operation data tree, in case the extension instance is specified, keep the searching
269 * for schema nodes locked inside the extension instance.
270 *
271 * At least one of @p parent, @p tree, or @p op must always be set.
272 *
Michal Vasko820efe82023-05-12 15:47:43 +0200273 * Specific @p data_type values have different parameter meaning as mentioned for ::lyd_parse_op().
Radek Krejcif16e2542021-02-17 15:39:23 +0100274 *
275 * @param[in] ctx libyang context.
276 * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
277 * @param[in] parent Optional parent to connect the parsed nodes to.
278 * @param[in] in Input handle to read the input from.
279 * @param[in] format Expected format of the data in @p in.
280 * @param[in] data_type Expected operation to parse (@ref datatype).
281 * @param[out] tree Optional full parsed data tree. If @p parent is set, set to NULL.
282 * @param[out] op Optional parsed operation node.
283 * @return LY_ERR value.
284 * @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
285 */
286static LY_ERR
287lyd_parse_op_(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
288 struct ly_in *in, LYD_FORMAT format, enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
Radek Krejci7931b192020-06-25 17:05:03 +0200289{
Michal Vaskoe0665742021-02-11 11:08:44 +0100290 LY_ERR rc = LY_SUCCESS;
291 struct lyd_ctx *lydctx = NULL;
292 struct ly_set parsed = {0};
293 struct lyd_node *first = NULL, *envp = NULL;
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100294 uint32_t i, parse_opts, val_opts, int_opts = 0;
Michal Vasko820efe82023-05-12 15:47:43 +0200295 ly_bool proto_msg = 0;
Radek Krejci7931b192020-06-25 17:05:03 +0200296
Michal Vasko27fb0262021-02-23 09:42:01 +0100297 if (!ctx) {
298 ctx = LYD_CTX(parent);
299 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200300 if (tree) {
301 *tree = NULL;
302 }
303 if (op) {
304 *op = NULL;
305 }
306
Radek Krejci7931b192020-06-25 17:05:03 +0200307 format = lyd_parse_get_format(in, format);
Radek Krejci7931b192020-06-25 17:05:03 +0200308
Michal Vasko63f3d842020-07-08 10:10:14 +0200309 /* remember input position */
310 in->func_start = in->current;
311
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100312 /* set parse and validation opts */
Michal Vasko140ede92022-05-10 09:27:30 +0200313 parse_opts = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoe0665742021-02-11 11:08:44 +0100314 val_opts = 0;
315
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100316 switch (data_type) {
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100317 case LYD_TYPE_RPC_NETCONF:
318 case LYD_TYPE_NOTIF_NETCONF:
319 LY_CHECK_ARG_RET(ctx, format == LYD_XML, !parent, tree, op, LY_EINVAL);
Michal Vasko820efe82023-05-12 15:47:43 +0200320 proto_msg = 1;
321 break;
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100322 case LYD_TYPE_REPLY_NETCONF:
Michal Vasko820efe82023-05-12 15:47:43 +0200323 LY_CHECK_ARG_RET(ctx, format == LYD_XML, parent, parent->schema, parent->schema->nodetype & (LYS_RPC | LYS_ACTION),
324 tree, !op, LY_EINVAL);
325 proto_msg = 1;
326 break;
327 case LYD_TYPE_RPC_RESTCONF:
328 case LYD_TYPE_REPLY_RESTCONF:
329 LY_CHECK_ARG_RET(ctx, parent, parent->schema, parent->schema->nodetype & (LYS_RPC | LYS_ACTION), tree, !op, LY_EINVAL);
330 proto_msg = 1;
331 break;
332 case LYD_TYPE_NOTIF_RESTCONF:
333 LY_CHECK_ARG_RET(ctx, format == LYD_JSON, !parent, tree, op, LY_EINVAL);
334 proto_msg = 1;
335 break;
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100336
Michal Vasko820efe82023-05-12 15:47:43 +0200337 /* set internal opts */
338 case LYD_TYPE_RPC_YANG:
Michal Vasko5df28522023-08-25 08:04:37 +0200339 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
Michal Vasko820efe82023-05-12 15:47:43 +0200340 break;
341 case LYD_TYPE_NOTIF_YANG:
Michal Vasko5df28522023-08-25 08:04:37 +0200342 int_opts = LYD_INTOPT_NOTIF | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
Michal Vasko820efe82023-05-12 15:47:43 +0200343 break;
344 case LYD_TYPE_REPLY_YANG:
Michal Vasko5df28522023-08-25 08:04:37 +0200345 int_opts = LYD_INTOPT_REPLY | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
Michal Vasko820efe82023-05-12 15:47:43 +0200346 break;
347 case LYD_TYPE_DATA_YANG:
348 LOGINT(ctx);
349 rc = LY_EINT;
350 goto cleanup;
351 }
352
353 /* parse a full protocol message */
354 if (proto_msg) {
355 if (format == LYD_XML) {
356 /* parse the NETCONF (or RESTCONF XML) message */
357 rc = lyd_parse_xml_netconf(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
358 } else {
359 /* parse the RESTCONF message */
360 rc = lyd_parse_json_restconf(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
361 }
Michal Vasko3a163bc2023-01-10 14:23:56 +0100362 if (rc) {
363 if (envp) {
364 /* special situation when the envelopes were parsed successfully */
365 *tree = envp;
366 }
Michal Vasko73792a12022-05-10 09:28:45 +0200367 goto cleanup;
Michal Vasko299d5d12021-02-16 16:36:37 +0100368 }
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100369
370 /* set out params correctly */
Michal Vasko472baa82022-12-01 16:17:41 +0100371 if (envp) {
372 /* special out param meaning */
373 *tree = envp;
374 } else {
375 *tree = parent ? NULL : first;
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100376 }
377 if (op) {
378 *op = lydctx->op_node;
379 }
380 goto cleanup;
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100381 }
382
383 /* parse the data */
384 switch (format) {
385 case LYD_XML:
386 rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
Michal Vaskoe0665742021-02-11 11:08:44 +0100387 break;
Radek Krejci7931b192020-06-25 17:05:03 +0200388 case LYD_JSON:
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100389 rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
Michal Vaskoe0665742021-02-11 11:08:44 +0100390 break;
Radek Krejci7931b192020-06-25 17:05:03 +0200391 case LYD_LYB:
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100392 rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
Michal Vaskoe0665742021-02-11 11:08:44 +0100393 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200394 case LYD_UNKNOWN:
Michal Vaskod74978f2021-02-12 11:59:36 +0100395 LOGARG(ctx, format);
396 rc = LY_EINVAL;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200397 break;
Radek Krejci7931b192020-06-25 17:05:03 +0200398 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100399 LY_CHECK_GOTO(rc, cleanup);
Radek Krejci7931b192020-06-25 17:05:03 +0200400
Michal Vaskoe0665742021-02-11 11:08:44 +0100401 /* set out params correctly */
402 if (tree) {
Michal Vaskoe3ed7dc2022-11-30 11:39:44 +0100403 *tree = parent ? NULL : first;
Michal Vaskoe0665742021-02-11 11:08:44 +0100404 }
405 if (op) {
406 *op = lydctx->op_node;
407 }
408
409cleanup:
410 if (lydctx) {
411 lydctx->free(lydctx);
412 }
413 if (rc) {
Michal Vasko73792a12022-05-10 09:28:45 +0200414 /* free all the parsed nodes */
415 if (parsed.count) {
416 i = parsed.count;
417 do {
418 --i;
Michal Vaskoe0665742021-02-11 11:08:44 +0100419 lyd_free_tree(parsed.dnodes[i]);
Michal Vasko73792a12022-05-10 09:28:45 +0200420 } while (i);
421 }
Michal Vasko6fbf07b2023-08-08 13:54:48 +0200422 if (tree && !envp) {
Michal Vasko73792a12022-05-10 09:28:45 +0200423 *tree = NULL;
424 }
425 if (op) {
426 *op = NULL;
Michal Vaskoe0665742021-02-11 11:08:44 +0100427 }
428 }
429 ly_set_erase(&parsed, NULL);
430 return rc;
Radek Krejcie7b95092019-05-15 11:03:07 +0200431}
Radek Krejci084289f2019-07-09 17:35:30 +0200432
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100433LIBYANG_API_DEF LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +0100434lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
435 enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
436{
437 LY_CHECK_ARG_RET(ctx, ctx || parent, in, data_type, parent || tree || op, LY_EINVAL);
438
439 return lyd_parse_op_(ctx, NULL, parent, in, format, data_type, tree, op);
440}
441
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100442LIBYANG_API_DEF LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +0100443lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
444 enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
445{
446 const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
447
448 LY_CHECK_ARG_RET(ctx, ext, in, data_type, parent || tree || op, LY_EINVAL);
449
450 return lyd_parse_op_(ctx, ext, parent, in, format, data_type, tree, op);
451}
452
Michal Vasko90932a92020-02-12 14:33:03 +0100453struct lyd_node *
Michal Vaskob104f112020-07-17 09:54:54 +0200454lyd_insert_get_next_anchor(const struct lyd_node *first_sibling, const struct lyd_node *new_node)
Michal Vasko90932a92020-02-12 14:33:03 +0100455{
Michal Vaskob104f112020-07-17 09:54:54 +0200456 const struct lysc_node *schema, *sparent;
Michal Vasko90932a92020-02-12 14:33:03 +0100457 struct lyd_node *match = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200458 ly_bool found;
Michal Vasko93b16062020-12-09 18:14:18 +0100459 uint32_t getnext_opts;
Michal Vasko90932a92020-02-12 14:33:03 +0100460
Michal Vaskob104f112020-07-17 09:54:54 +0200461 assert(new_node);
462
Michal Vasko9beceb82022-04-05 12:14:15 +0200463 if (!first_sibling || !new_node->schema || (LYD_CTX(first_sibling) != LYD_CTX(new_node))) {
Michal Vaskob104f112020-07-17 09:54:54 +0200464 /* insert at the end, no next anchor */
Michal Vasko90932a92020-02-12 14:33:03 +0100465 return NULL;
466 }
467
Michal Vasko93b16062020-12-09 18:14:18 +0100468 getnext_opts = 0;
Michal Vaskod1e53b92021-01-28 13:11:06 +0100469 if (new_node->schema->flags & LYS_IS_OUTPUT) {
Michal Vasko93b16062020-12-09 18:14:18 +0100470 getnext_opts = LYS_GETNEXT_OUTPUT;
471 }
472
Michal Vaskoa2756f02021-07-09 13:20:28 +0200473 if (first_sibling->parent && first_sibling->parent->schema && first_sibling->parent->children_ht) {
Michal Vaskob104f112020-07-17 09:54:54 +0200474 /* find the anchor using hashes */
475 sparent = first_sibling->parent->schema;
Michal Vasko93b16062020-12-09 18:14:18 +0100476 schema = lys_getnext(new_node->schema, sparent, NULL, getnext_opts);
Michal Vaskob104f112020-07-17 09:54:54 +0200477 while (schema) {
478 /* keep trying to find the first existing instance of the closest following schema sibling,
479 * otherwise return NULL - inserting at the end */
480 if (!lyd_find_sibling_schema(first_sibling, schema, &match)) {
481 break;
482 }
483
Michal Vasko93b16062020-12-09 18:14:18 +0100484 schema = lys_getnext(schema, sparent, NULL, getnext_opts);
Michal Vaskob104f112020-07-17 09:54:54 +0200485 }
486 } else {
487 /* find the anchor without hashes */
488 match = (struct lyd_node *)first_sibling;
Michal Vasko3a708622021-07-15 14:20:10 +0200489 sparent = lysc_data_parent(new_node->schema);
490 if (!sparent) {
Michal Vaskob104f112020-07-17 09:54:54 +0200491 /* we are in top-level, skip all the data from preceding modules */
492 LY_LIST_FOR(match, match) {
493 if (!match->schema || (strcmp(lyd_owner_module(match)->name, lyd_owner_module(new_node)->name) >= 0)) {
494 break;
495 }
496 }
497 }
498
499 /* get the first schema sibling */
Michal Vasko93b16062020-12-09 18:14:18 +0100500 schema = lys_getnext(NULL, sparent, new_node->schema->module->compiled, getnext_opts);
Michal Vasko9a463472023-08-08 09:43:33 +0200501 if (!schema) {
Michal Vasko60d929e2023-08-21 11:54:42 +0200502 /* must be a top-level extension instance data, no anchor */
503 return NULL;
Michal Vasko9a463472023-08-08 09:43:33 +0200504 }
Michal Vaskob104f112020-07-17 09:54:54 +0200505
506 found = 0;
507 LY_LIST_FOR(match, match) {
508 if (!match->schema || (lyd_owner_module(match) != lyd_owner_module(new_node))) {
509 /* we have found an opaque node, which must be at the end, so use it OR
510 * modules do not match, so we must have traversed all the data from new_node module (if any),
511 * we have found the first node of the next module, that is what we want */
512 break;
513 }
514
515 /* skip schema nodes until we find the instantiated one */
516 while (!found) {
517 if (new_node->schema == schema) {
518 /* we have found the schema of the new node, continue search to find the first
519 * data node with a different schema (after our schema) */
520 found = 1;
521 break;
522 }
523 if (match->schema == schema) {
524 /* current node (match) is a data node still before the new node, continue search in data */
525 break;
526 }
Michal Vasko9a463472023-08-08 09:43:33 +0200527
Michal Vasko93b16062020-12-09 18:14:18 +0100528 schema = lys_getnext(schema, sparent, new_node->schema->module->compiled, getnext_opts);
Michal Vasko9a463472023-08-08 09:43:33 +0200529 if (!schema) {
Michal Vasko60d929e2023-08-21 11:54:42 +0200530 /* must be a top-level extension instance data, no anchor */
531 return NULL;
Michal Vasko9a463472023-08-08 09:43:33 +0200532 }
Michal Vaskob104f112020-07-17 09:54:54 +0200533 }
534
535 if (found && (match->schema != new_node->schema)) {
536 /* find the next node after we have found our node schema data instance */
537 break;
538 }
539 }
Michal Vasko90932a92020-02-12 14:33:03 +0100540 }
541
542 return match;
543}
544
Michal Vaskoc61dd062022-06-07 11:01:28 +0200545void
Michal Vaskof03ed032020-03-04 13:31:44 +0100546lyd_insert_after_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100547{
Michal Vasko0249f7c2020-03-05 16:36:40 +0100548 struct lyd_node_inner *par;
549
Michal Vasko90932a92020-02-12 14:33:03 +0100550 assert(!node->next && (node->prev == node));
551
552 node->next = sibling->next;
553 node->prev = sibling;
554 sibling->next = node;
555 if (node->next) {
556 /* sibling had a succeeding node */
557 node->next->prev = node;
558 } else {
559 /* sibling was last, find first sibling and change its prev */
560 if (sibling->parent) {
561 sibling = sibling->parent->child;
562 } else {
Michal Vaskod989ba02020-08-24 10:59:24 +0200563 for ( ; sibling->prev->next != node; sibling = sibling->prev) {}
Michal Vasko90932a92020-02-12 14:33:03 +0100564 }
565 sibling->prev = node;
566 }
567 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100568
Michal Vasko9f96a052020-03-10 09:41:45 +0100569 for (par = node->parent; par; par = par->parent) {
570 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
571 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100572 par->flags &= ~LYD_DEFAULT;
573 }
574 }
Michal Vasko90932a92020-02-12 14:33:03 +0100575}
576
Michal Vaskoc61dd062022-06-07 11:01:28 +0200577void
Michal Vaskof03ed032020-03-04 13:31:44 +0100578lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100579{
Michal Vasko0249f7c2020-03-05 16:36:40 +0100580 struct lyd_node_inner *par;
581
Michal Vasko90932a92020-02-12 14:33:03 +0100582 assert(!node->next && (node->prev == node));
583
584 node->next = sibling;
585 /* covers situation of sibling being first */
586 node->prev = sibling->prev;
587 sibling->prev = node;
588 if (node->prev->next) {
589 /* sibling had a preceding node */
590 node->prev->next = node;
591 } else if (sibling->parent) {
592 /* sibling was first and we must also change parent child pointer */
593 sibling->parent->child = node;
594 }
595 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100596
Michal Vasko9f96a052020-03-10 09:41:45 +0100597 for (par = node->parent; par; par = par->parent) {
598 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
599 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100600 par->flags &= ~LYD_DEFAULT;
601 }
602 }
Michal Vasko90932a92020-02-12 14:33:03 +0100603}
604
605/**
Michal Vaskob104f112020-07-17 09:54:54 +0200606 * @brief Insert node as the first and only child of a parent.
Michal Vasko90932a92020-02-12 14:33:03 +0100607 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100608 * Handles inserting into NP containers and key-less lists.
609 *
Michal Vasko90932a92020-02-12 14:33:03 +0100610 * @param[in] parent Parent to insert into.
611 * @param[in] node Node to insert.
612 */
613static void
Michal Vaskob104f112020-07-17 09:54:54 +0200614lyd_insert_only_child(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100615{
616 struct lyd_node_inner *par;
617
Radek Krejcia1c1e542020-09-29 16:06:52 +0200618 assert(parent && !lyd_child(parent) && !node->next && (node->prev == node));
Michal Vasko52927e22020-03-16 17:26:14 +0100619 assert(!parent->schema || (parent->schema->nodetype & LYD_NODE_INNER));
Michal Vasko90932a92020-02-12 14:33:03 +0100620
621 par = (struct lyd_node_inner *)parent;
622
Michal Vaskob104f112020-07-17 09:54:54 +0200623 par->child = node;
Michal Vasko90932a92020-02-12 14:33:03 +0100624 node->parent = par;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100625
Michal Vaskod989ba02020-08-24 10:59:24 +0200626 for ( ; par; par = par->parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100627 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
628 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100629 par->flags &= ~LYD_DEFAULT;
630 }
631 }
Michal Vasko751cb4d2020-07-14 12:25:28 +0200632}
Michal Vasko0249f7c2020-03-05 16:36:40 +0100633
Michal Vasko751cb4d2020-07-14 12:25:28 +0200634/**
635 * @brief Learn whether a list instance has all the keys.
636 *
637 * @param[in] list List instance to check.
638 * @return non-zero if all the keys were found,
639 * @return 0 otherwise.
640 */
641static int
642lyd_insert_has_keys(const struct lyd_node *list)
643{
644 const struct lyd_node *key;
645 const struct lysc_node *skey = NULL;
646
647 assert(list->schema->nodetype == LYS_LIST);
Radek Krejcia1c1e542020-09-29 16:06:52 +0200648 key = lyd_child(list);
Michal Vasko751cb4d2020-07-14 12:25:28 +0200649 while ((skey = lys_getnext(skey, list->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
650 if (!key || (key->schema != skey)) {
651 /* key missing */
652 return 0;
653 }
654
655 key = key->next;
656 }
657
658 /* all keys found */
659 return 1;
Michal Vasko90932a92020-02-12 14:33:03 +0100660}
661
aPiecek6cf1d162023-11-08 16:07:00 +0100662/**
663 * @brief Get the first subsequent data node that contains a different schema definition.
664 *
665 * @param[in] first_sibling First sibling, NULL if no top-level sibling exist yet.
666 * @param[in] node Node to be inserted.
667 * @return Subsequent data node with a different schema.
668 */
669static struct lyd_node *
670lyd_insert_node_find_anchor(struct lyd_node *first_sibling, struct lyd_node *node)
671{
672 struct lyd_node *anchor;
673
674 if (first_sibling && (first_sibling->flags & LYD_EXT)) {
675 return NULL;
676 }
677
678 /* find the anchor, so we can insert somewhere before it */
679 anchor = lyd_insert_get_next_anchor(first_sibling, node);
680 /* cannot insert data node after opaque nodes */
681 if (!anchor && node->schema && first_sibling && !first_sibling->prev->schema) {
682 anchor = first_sibling->prev;
683 while ((anchor != first_sibling) && !anchor->prev->schema) {
684 anchor = anchor->prev;
685 }
686 }
687
688 return anchor;
689}
690
691/**
aPiecek61880852024-01-11 14:10:29 +0100692 * @brief Insert @p node as the last node.
aPiecek6cf1d162023-11-08 16:07:00 +0100693 *
694 * @param[in] parent Parent to insert into, NULL for top-level sibling.
aPiecek61880852024-01-11 14:10:29 +0100695 * @param[in] first_sibling First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
aPiecek6cf1d162023-11-08 16:07:00 +0100696 * @param[in] node Individual node (without siblings) to insert.
aPiecek6cf1d162023-11-08 16:07:00 +0100697 */
698static void
aPiecek61880852024-01-11 14:10:29 +0100699lyd_insert_node_last(struct lyd_node *parent, struct lyd_node *first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100700{
aPiecek61880852024-01-11 14:10:29 +0100701 if (first_sibling) {
aPiecek2d8ce0b2024-01-15 15:47:23 +0100702#ifndef NDEBUG
703 if (lyds_is_supported(node) && (first_sibling->prev->schema == node->schema) &&
704 (lyds_compare_single(first_sibling->prev, node) > 0)) {
705 LOGWRN(LYD_CTX(node), "Data in \"%s\" are not sorted, inserted node should not be added to the end.",
706 node->schema->name);
707 }
708#endif
Michal Vaskob104f112020-07-17 09:54:54 +0200709 lyd_insert_after_node(first_sibling->prev, node);
710 } else if (parent) {
711 lyd_insert_only_child(parent, node);
Michal Vaskob104f112020-07-17 09:54:54 +0200712 }
aPiecek6cf1d162023-11-08 16:07:00 +0100713}
714
aPieceke6955f42024-01-19 14:01:54 +0100715void
aPiecek61880852024-01-11 14:10:29 +0100716lyd_insert_node_ordby_schema(struct lyd_node *parent, struct lyd_node *first_sibling, struct lyd_node *node)
aPiecek6cf1d162023-11-08 16:07:00 +0100717{
aPiecek61880852024-01-11 14:10:29 +0100718 struct lyd_node *anchor;
aPiecek6cf1d162023-11-08 16:07:00 +0100719
aPiecek61880852024-01-11 14:10:29 +0100720 if ((anchor = lyd_insert_node_find_anchor(first_sibling, node))) {
aPiecek6cf1d162023-11-08 16:07:00 +0100721 lyd_insert_before_node(anchor, node);
722 } else {
aPiecek61880852024-01-11 14:10:29 +0100723 lyd_insert_node_last(parent, first_sibling, node);
aPiecek6cf1d162023-11-08 16:07:00 +0100724 }
aPiecek6cf1d162023-11-08 16:07:00 +0100725}
726
727void
728lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, struct lyd_node *node, ly_bool last)
729{
730 LY_ERR ret = LY_SUCCESS;
aPiecek61880852024-01-11 14:10:29 +0100731 struct lyd_node *first_sibling, *leader;
aPiecek6cf1d162023-11-08 16:07:00 +0100732
733 /* inserting list without its keys is not supported */
734 assert((parent || first_sibling_p) && node && (node->hash || !node->schema));
735 assert(!parent || !parent->schema ||
736 (parent->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF)));
737
aPiecek61880852024-01-11 14:10:29 +0100738 if (!parent && first_sibling_p && (*first_sibling_p)) {
aPiecek6cf1d162023-11-08 16:07:00 +0100739 parent = lyd_parent(*first_sibling_p);
740 }
aPiecek61880852024-01-11 14:10:29 +0100741 first_sibling = parent ? lyd_child(parent) : *first_sibling_p;
aPiecek6cf1d162023-11-08 16:07:00 +0100742
aPiecek61880852024-01-11 14:10:29 +0100743 if (last) {
744 lyd_insert_node_last(parent, first_sibling, node);
745 } else if (lyds_is_supported(node) &&
746 (lyd_find_sibling_schema(first_sibling, node->schema, &leader) == LY_SUCCESS)) {
747 ret = lyds_insert(&leader, node);
aPiecek6cf1d162023-11-08 16:07:00 +0100748 if (ret) {
749 /* The operation on the sorting tree unexpectedly failed due to some internal issue,
750 * but insert the node anyway although the nodes will not be sorted.
751 */
752 LOGWRN(LYD_CTX(node), "Data in \"%s\" are not sorted.", node->schema->name);
aPiecek61880852024-01-11 14:10:29 +0100753 lyd_insert_node_ordby_schema(parent, first_sibling, node);
aPiecek6cf1d162023-11-08 16:07:00 +0100754 }
755 } else {
aPiecek61880852024-01-11 14:10:29 +0100756 lyd_insert_node_ordby_schema(parent, first_sibling, node);
aPiecek6cf1d162023-11-08 16:07:00 +0100757 }
Michal Vaskob104f112020-07-17 09:54:54 +0200758
759 /* insert into parent HT */
760 lyd_insert_hash(node);
761
762 /* finish hashes for our parent, if needed and possible */
Michal Vaskoa878a892023-08-18 12:22:07 +0200763 if (node->schema && (node->schema->flags & LYS_KEY) && parent && parent->schema && lyd_insert_has_keys(parent)) {
Michal Vaskob104f112020-07-17 09:54:54 +0200764 lyd_hash(parent);
765
766 /* now we can insert even the list into its parent HT */
767 lyd_insert_hash(parent);
Michal Vasko90932a92020-02-12 14:33:03 +0100768 }
aPiecek61880852024-01-11 14:10:29 +0100769
770 if (first_sibling_p) {
771 *first_sibling_p = node->prev->next ? first_sibling : node;
772 }
Michal Vasko90932a92020-02-12 14:33:03 +0100773}
774
Michal Vasko717a4c32020-12-07 09:40:10 +0100775/**
aPiecekcada0d72024-01-11 15:04:12 +0100776 * @brief Check that @p node can be unlinked.
777 *
778 * @param[in] node Node to check
779 * @return LY_ERR value.
780 */
781static LY_ERR
782lyd_unlink_check(struct lyd_node *node)
783{
784 if (!node) {
785 return LY_SUCCESS;
786 }
787
788 if (lysc_is_key(node->schema) && node->parent) {
789 LOGERR(LYD_CTX(node), LY_EINVAL, "Cannot unlink a list key \"%s\", unlink the list instance instead.",
790 LYD_NAME(node));
791 return LY_EINVAL;
792 }
793
794 return LY_SUCCESS;
795}
796
797/**
798 * @brief Move schema instances before anchor or as the last.
799 *
800 * The nodes will remain sorted according to the schema.
801 *
802 * @param[in] first_sibling First sibling, destination.
803 * @param[in] node Starting node, all following nodes with the same schema will be moved.
804 * @param[out] next_p Next node that has a different schema or NULL.
805 * @return LY_ERR value.
806 */
807static LY_ERR
808lyd_move_nodes_ordby_schema(struct lyd_node *first_sibling, struct lyd_node *node, struct lyd_node **next_p)
809{
810 struct lyd_node *second, *anchor, *iter, *next, *dst, *src;
811
812 assert(first_sibling && !first_sibling->prev->next && node && next_p);
813
814 if ((anchor = lyd_insert_node_find_anchor(first_sibling, node))) {
815 /* move the first node to the correct place according to the schema */
816 LY_CHECK_RET(lyd_unlink_check(node));
817 second = node->next;
818 lyd_unlink_ignore_lyds(node);
819 lyd_insert_before_node(anchor, node);
820 lyd_insert_hash(node);
821 if (!second || (node->schema != second->schema)) {
822 /* no more nodes to move */
823 *next_p = second;
824 return LY_SUCCESS;
825 }
826 dst = node;
827 src = second;
828 } else {
829 /* just move all instances to the end */
830 dst = first_sibling->prev;
831 src = node;
832 }
833
834 /* move the rest of source instances after @p node */
835 LY_LIST_FOR_SAFE(src, next, iter) {
836 LY_CHECK_RET(lyd_unlink_check(iter));
837 if (iter->schema != src->schema) {
838 break;
839 }
840 lyd_unlink_ignore_lyds(iter);
841 lyd_insert_after_node(dst, iter);
842 lyd_insert_hash(iter);
843 dst = iter;
844 }
845 *next_p = iter;
846
847 return LY_SUCCESS;
848}
849
850/**
851 * @brief Move nodes regardless of schema.
852 *
853 * The destination for the move is NULL, or a childless parent.
854 *
855 * @param[in] parent Parent to insert into, NULL for top-level sibling.
856 * @param[in] first_src First sibling, all following nodes will be moved.
857 * @return LY_ERR value.
858 */
859static LY_ERR
860lyd_move_nodes_at_once(struct lyd_node *parent, struct lyd_node *first_src)
861{
862 struct lyd_node *start, *next, *iter;
863
864 assert(!lyd_child(parent) && first_src && !first_src->prev->next && !first_src->parent);
865
866 LY_CHECK_RET(lyd_unlink_check(first_src));
867
868 /* move the first node */
869 start = first_src->next;
870 if (parent) {
871 lyd_unlink_ignore_lyds(first_src);
872 lyd_insert_only_child(parent, first_src);
873 lyd_insert_hash(first_src);
874 } else {
875 lyd_unlink_ignore_lyds(first_src);
876 }
877
878 /* move the rest of the nodes */
879 LY_LIST_FOR_SAFE(start, next, iter) {
880 LY_CHECK_RET(lyd_unlink_check(iter));
881 lyd_unlink_ignore_lyds(iter);
882 lyd_insert_after_node(first_src->prev, iter);
883 lyd_insert_hash(iter);
884 }
885
886 return LY_SUCCESS;
887}
888
889/**
890 * @brief Move the nodes in parts according to the schema.
891 *
892 * @param[in] first_sibling First sibling, destination.
893 * @param[in] first_src First sibling, all following nodes will be moved.
894 * @return LY_ERR value.
895 */
896static LY_ERR
897lyd_move_nodes_by_schema(struct lyd_node *first_sibling, struct lyd_node *first_src)
898{
899 LY_ERR ret;
900 struct lyd_node *next, *iter, *leader;
901
902 assert(first_sibling && !first_sibling->prev->next && first_src && !first_src->prev->next && !first_src->parent);
903
904 for (iter = first_src; iter; iter = next) {
905 if (lyds_is_supported(iter) &&
906 (lyd_find_sibling_schema(first_sibling, iter->schema, &leader) == LY_SUCCESS)) {
907 ret = lyds_merge(&leader, iter, &next);
908 if (ret) {
909 /* The operation on the sorting tree unexpectedly failed due to some internal issue,
910 * but insert the node anyway although the nodes will not be sorted.
911 */
912 LOGWRN(LYD_CTX(first_src), "Data in \"%s\" are not sorted.", leader->schema->name);
913 LY_CHECK_RET(lyd_move_nodes_ordby_schema(first_sibling, next, &next));
914 }
915 } else {
916 LY_CHECK_RET(lyd_move_nodes_ordby_schema(first_sibling, iter, &next));
917 }
918 first_sibling = iter->prev->next ? first_sibling : iter;
919 }
920
921 return LY_SUCCESS;
922}
923
924/**
925 * @brief Move a nodes into parent/siblings.
926 *
927 * @param[in] parent Parent to insert into, NULL for top-level sibling.
928 * @param[in] first_sibling First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
929 * @param[in] first_src First sibling, all following nodes will be moved.
930 * @return LY_ERR value.
931 */
932static LY_ERR
933lyd_move_nodes(struct lyd_node *parent, struct lyd_node *first_sibling, struct lyd_node *first_src)
934{
935 LY_ERR ret;
936
937 assert(first_src && (!first_sibling || !first_sibling->prev->next) && !first_src->prev->next);
938
939 first_sibling = first_sibling ? first_sibling : lyd_child(parent);
940 if (!first_sibling) {
941 ret = lyd_move_nodes_at_once(parent, first_src);
942 } else {
943 ret = lyd_move_nodes_by_schema(first_sibling, first_src);
944 }
945
946 return ret;
947}
948
949/**
Michal Vasko717a4c32020-12-07 09:40:10 +0100950 * @brief Check schema place of a node to be inserted.
951 *
952 * @param[in] parent Schema node of the parent data node.
953 * @param[in] sibling Schema node of a sibling data node.
954 * @param[in] schema Schema node if the data node to be inserted.
955 * @return LY_SUCCESS on success.
956 * @return LY_EINVAL if the place is invalid.
957 */
Michal Vaskof03ed032020-03-04 13:31:44 +0100958static LY_ERR
Michal Vasko717a4c32020-12-07 09:40:10 +0100959lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *sibling, const struct lysc_node *schema)
Michal Vaskof03ed032020-03-04 13:31:44 +0100960{
961 const struct lysc_node *par2;
962
Michal Vasko62ed12d2020-05-21 10:08:25 +0200963 assert(!parent || !(parent->nodetype & (LYS_CASE | LYS_CHOICE)));
Michal Vasko717a4c32020-12-07 09:40:10 +0100964 assert(!sibling || !(sibling->nodetype & (LYS_CASE | LYS_CHOICE)));
965 assert(!schema || !(schema->nodetype & (LYS_CASE | LYS_CHOICE)));
Michal Vaskof03ed032020-03-04 13:31:44 +0100966
Michal Vasko717a4c32020-12-07 09:40:10 +0100967 if (!schema || (!parent && !sibling)) {
Michal Vasko71e795e2020-12-04 16:27:37 +0100968 /* opaque nodes can be inserted wherever */
969 return LY_SUCCESS;
970 }
971
Michal Vasko717a4c32020-12-07 09:40:10 +0100972 if (!parent) {
973 parent = lysc_data_parent(sibling);
974 }
975
Michal Vaskof03ed032020-03-04 13:31:44 +0100976 /* find schema parent */
Michal Vasko62ed12d2020-05-21 10:08:25 +0200977 par2 = lysc_data_parent(schema);
Michal Vaskof03ed032020-03-04 13:31:44 +0100978
979 if (parent) {
980 /* inner node */
981 if (par2 != parent) {
Michal Vaskob104f112020-07-17 09:54:54 +0200982 LOGERR(schema->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name,
Michal Vasko69730152020-10-09 16:30:07 +0200983 parent->name);
Michal Vaskof03ed032020-03-04 13:31:44 +0100984 return LY_EINVAL;
985 }
986 } else {
987 /* top-level node */
988 if (par2) {
Radek Krejcif6d14cb2020-07-02 16:11:45 +0200989 LOGERR(schema->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
Michal Vaskof03ed032020-03-04 13:31:44 +0100990 return LY_EINVAL;
991 }
992 }
993
994 return LY_SUCCESS;
995}
996
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100997LIBYANG_API_DEF LY_ERR
Michal Vaskob104f112020-07-17 09:54:54 +0200998lyd_insert_child(struct lyd_node *parent, struct lyd_node *node)
Michal Vaskof03ed032020-03-04 13:31:44 +0100999{
Michal Vasko0ab974d2021-02-24 13:18:26 +01001000 LY_CHECK_ARG_RET(NULL, parent, node, !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01001001 LY_CHECK_CTX_EQUAL_RET(LYD_CTX(parent), LYD_CTX(node), LY_EINVAL);
Michal Vaskof03ed032020-03-04 13:31:44 +01001002
Michal Vasko717a4c32020-12-07 09:40:10 +01001003 LY_CHECK_RET(lyd_insert_check_schema(parent->schema, NULL, node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001004
aPiecekcada0d72024-01-11 15:04:12 +01001005 if (node->parent || node->prev->next || !node->next) {
aPiecekdfde77d2024-01-15 15:16:01 +01001006 LY_CHECK_RET(lyd_unlink_tree(node));
Michal Vasko6ee6f432021-07-16 09:49:14 +02001007 lyd_insert_node(parent, NULL, node, 0);
aPiecekcada0d72024-01-11 15:04:12 +01001008 } else {
aPiecekdfde77d2024-01-15 15:16:01 +01001009 LY_CHECK_RET(lyd_move_nodes(parent, NULL, node));
Michal Vaskof03ed032020-03-04 13:31:44 +01001010 }
aPiecekcada0d72024-01-11 15:04:12 +01001011
Michal Vaskof03ed032020-03-04 13:31:44 +01001012 return LY_SUCCESS;
1013}
1014
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001015LIBYANG_API_DEF LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +02001016lyplg_ext_insert(struct lyd_node *parent, struct lyd_node *first)
Michal Vaskoddd76592022-01-17 13:34:48 +01001017{
1018 struct lyd_node *iter;
1019
1020 LY_CHECK_ARG_RET(NULL, parent, first, !first->parent, !first->prev->next,
1021 !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
1022
1023 if (first->schema && (first->schema->flags & LYS_KEY)) {
1024 LOGERR(LYD_CTX(parent), LY_EINVAL, "Cannot insert key \"%s\".", first->schema->name);
1025 return LY_EINVAL;
1026 }
1027
1028 while (first) {
1029 iter = first->next;
Michal Vasko2e784f82024-01-11 09:51:22 +01001030 lyd_unlink(first);
Michal Vasko61ad1ff2022-02-10 15:48:39 +01001031 lyd_insert_node(parent, NULL, first, 1);
Michal Vaskoddd76592022-01-17 13:34:48 +01001032 first = iter;
1033 }
1034 return LY_SUCCESS;
1035}
1036
1037LIBYANG_API_DEF LY_ERR
Michal Vaskob104f112020-07-17 09:54:54 +02001038lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct lyd_node **first)
Michal Vaskob1b5c262020-03-05 14:29:47 +01001039{
aPiecekcada0d72024-01-11 15:04:12 +01001040 struct lyd_node *first_sibling;
Michal Vaskob1b5c262020-03-05 14:29:47 +01001041
Michal Vaskob104f112020-07-17 09:54:54 +02001042 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Michal Vaskob1b5c262020-03-05 14:29:47 +01001043
Michal Vaskob104f112020-07-17 09:54:54 +02001044 if (sibling) {
Michal Vasko717a4c32020-12-07 09:40:10 +01001045 LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
Michal Vaskob1b5c262020-03-05 14:29:47 +01001046 }
1047
aPiecekcada0d72024-01-11 15:04:12 +01001048 first_sibling = lyd_first_sibling(sibling);
1049 if (node->parent || node->prev->next || !node->next) {
aPiecekdfde77d2024-01-15 15:16:01 +01001050 LY_CHECK_RET(lyd_unlink_tree(node));
aPiecekcada0d72024-01-11 15:04:12 +01001051 lyd_insert_node(NULL, &first_sibling, node, 0);
1052 } else {
aPiecekdfde77d2024-01-15 15:16:01 +01001053 LY_CHECK_RET(lyd_move_nodes(NULL, first_sibling, node));
Michal Vaskob1b5c262020-03-05 14:29:47 +01001054 }
Michal Vaskob1b5c262020-03-05 14:29:47 +01001055
Michal Vaskob104f112020-07-17 09:54:54 +02001056 if (first) {
aPiecekcada0d72024-01-11 15:04:12 +01001057 *first = node->prev->next ? first_sibling : node;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001058 }
1059
1060 return LY_SUCCESS;
1061}
1062
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001063LIBYANG_API_DEF LY_ERR
Michal Vaskof03ed032020-03-04 13:31:44 +01001064lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
1065{
Michal Vaskobce230b2022-04-19 09:55:31 +02001066 LY_CHECK_ARG_RET(NULL, sibling, node, sibling != node, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01001067 LY_CHECK_CTX_EQUAL_RET(LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
Michal Vaskof03ed032020-03-04 13:31:44 +01001068
Michal Vasko717a4c32020-12-07 09:40:10 +01001069 LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001070
Michal Vaskoab7a2bf2022-04-01 14:37:54 +02001071 if (node->schema && (!(node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(node->schema->flags & LYS_ORDBY_USER))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +02001072 LOGERR(LYD_CTX(sibling), LY_EINVAL, "Can be used only for user-ordered nodes.");
Michal Vaskof03ed032020-03-04 13:31:44 +01001073 return LY_EINVAL;
1074 }
Michal Vasko5c0b27a2022-04-19 09:56:02 +02001075 if (node->schema && sibling->schema && (node->schema != sibling->schema)) {
1076 LOGERR(LYD_CTX(sibling), LY_EINVAL, "Cannot insert before a different schema node instance.");
Michal Vasko7508ef22022-02-22 14:13:10 +01001077 return LY_EINVAL;
1078 }
Michal Vaskof03ed032020-03-04 13:31:44 +01001079
Michal Vasko2e784f82024-01-11 09:51:22 +01001080 lyd_unlink(node);
Michal Vasko4bc2ce32020-12-08 10:06:16 +01001081 lyd_insert_before_node(sibling, node);
1082 lyd_insert_hash(node);
Michal Vaskof03ed032020-03-04 13:31:44 +01001083
Michal Vaskof03ed032020-03-04 13:31:44 +01001084 return LY_SUCCESS;
1085}
1086
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001087LIBYANG_API_DEF LY_ERR
Michal Vaskof03ed032020-03-04 13:31:44 +01001088lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
1089{
Michal Vaskobce230b2022-04-19 09:55:31 +02001090 LY_CHECK_ARG_RET(NULL, sibling, node, sibling != node, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01001091 LY_CHECK_CTX_EQUAL_RET(LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
Michal Vaskof03ed032020-03-04 13:31:44 +01001092
Michal Vasko717a4c32020-12-07 09:40:10 +01001093 LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001094
Michal Vaskoab7a2bf2022-04-01 14:37:54 +02001095 if (node->schema && (!(node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(node->schema->flags & LYS_ORDBY_USER))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +02001096 LOGERR(LYD_CTX(sibling), LY_EINVAL, "Can be used only for user-ordered nodes.");
Michal Vaskof03ed032020-03-04 13:31:44 +01001097 return LY_EINVAL;
1098 }
Michal Vasko5c0b27a2022-04-19 09:56:02 +02001099 if (node->schema && sibling->schema && (node->schema != sibling->schema)) {
1100 LOGERR(LYD_CTX(sibling), LY_EINVAL, "Cannot insert after a different schema node instance.");
Michal Vasko7508ef22022-02-22 14:13:10 +01001101 return LY_EINVAL;
1102 }
Michal Vaskof03ed032020-03-04 13:31:44 +01001103
Michal Vasko2e784f82024-01-11 09:51:22 +01001104 lyd_unlink(node);
Michal Vasko4bc2ce32020-12-08 10:06:16 +01001105 lyd_insert_after_node(sibling, node);
1106 lyd_insert_hash(node);
Michal Vaskof03ed032020-03-04 13:31:44 +01001107
Michal Vaskof03ed032020-03-04 13:31:44 +01001108 return LY_SUCCESS;
1109}
1110
Michal Vasko2e784f82024-01-11 09:51:22 +01001111void
aPiecekcada0d72024-01-11 15:04:12 +01001112lyd_unlink_ignore_lyds(struct lyd_node *node)
Michal Vaskof03ed032020-03-04 13:31:44 +01001113{
aPiecekcada0d72024-01-11 15:04:12 +01001114 struct lyd_node *iter;
aPiecek6cf1d162023-11-08 16:07:00 +01001115
Michal Vaskob104f112020-07-17 09:54:54 +02001116 /* update hashes while still linked into the tree */
1117 lyd_unlink_hash(node);
1118
stewegf9041a22024-01-18 13:29:12 +01001119 /* unlink leafref nodes */
1120 if (node->schema && (node->schema->nodetype & LYD_NODE_TERM)) {
1121 lyd_free_leafref_nodes((struct lyd_node_term *)node);
1122 }
1123
Michal Vaskof03ed032020-03-04 13:31:44 +01001124 /* unlink from siblings */
1125 if (node->prev->next) {
1126 node->prev->next = node->next;
1127 }
1128 if (node->next) {
1129 node->next->prev = node->prev;
1130 } else {
1131 /* unlinking the last node */
1132 if (node->parent) {
1133 iter = node->parent->child;
1134 } else {
1135 iter = node->prev;
1136 while (iter->prev != node) {
1137 iter = iter->prev;
1138 }
1139 }
1140 /* update the "last" pointer from the first node */
1141 iter->prev = node->prev;
1142 }
1143
1144 /* unlink from parent */
1145 if (node->parent) {
1146 if (node->parent->child == node) {
1147 /* the node is the first child */
1148 node->parent->child = node->next;
1149 }
1150
Michal Vaskoab49dbe2020-07-17 12:32:47 +02001151 /* check for NP container whether its last non-default node is not being unlinked */
Michal Vasko4754d4a2022-12-01 10:11:21 +01001152 lyd_cont_set_dflt(lyd_parent(node));
Michal Vaskoab49dbe2020-07-17 12:32:47 +02001153
Michal Vaskof03ed032020-03-04 13:31:44 +01001154 node->parent = NULL;
1155 }
1156
1157 node->next = NULL;
1158 node->prev = node;
1159}
1160
aPiecekcada0d72024-01-11 15:04:12 +01001161void
1162lyd_unlink(struct lyd_node *node)
1163{
1164 struct lyd_node *leader;
1165
1166 if (!node) {
1167 return;
1168 }
1169
1170 /* unlink from the lyds tree */
1171 if (lyds_is_supported(node)) {
1172 if (!node->prev->next || (node->prev->schema != node->schema)) {
1173 leader = node;
1174 } else {
1175 lyd_find_sibling_val(node, node->schema, NULL, 0, &leader);
1176 assert(leader);
1177 }
1178 lyds_unlink(&leader, node);
1179 }
1180
1181 /* unlink data tree */
1182 lyd_unlink_ignore_lyds(node);
1183}
1184
aPiecekdfde77d2024-01-15 15:16:01 +01001185LIBYANG_API_DEF LY_ERR
Michal Vasko2e784f82024-01-11 09:51:22 +01001186lyd_unlink_siblings(struct lyd_node *node)
1187{
aPiecekcada0d72024-01-11 15:04:12 +01001188 struct lyd_node *next, *iter, *leader, *start;
Michal Vasko2e784f82024-01-11 09:51:22 +01001189
aPiecekcada0d72024-01-11 15:04:12 +01001190 if (lyds_is_supported(node) && node->prev->next && (node->prev->schema == node->schema)) {
1191 /* unlink starts at the non-first item in the (leaf-)list */
1192 lyd_find_sibling_val(node, node->schema, NULL, 0, &leader);
1193 lyds_split(leader, node, &start);
1194 } else {
1195 /* unlink @p node */
aPiecekdfde77d2024-01-15 15:16:01 +01001196 LY_CHECK_RET(lyd_unlink_check(node));
aPiecekcada0d72024-01-11 15:04:12 +01001197 start = node->next;
1198 lyd_unlink_ignore_lyds(node);
1199 }
Michal Vasko2e784f82024-01-11 09:51:22 +01001200
aPiecekcada0d72024-01-11 15:04:12 +01001201 /* continue unlinking the rest */
1202 LY_LIST_FOR_SAFE(start, next, iter) {
aPiecekdfde77d2024-01-15 15:16:01 +01001203 LY_CHECK_RET(lyd_unlink_check(iter));
aPiecekcada0d72024-01-11 15:04:12 +01001204 lyd_unlink_ignore_lyds(iter);
1205 lyd_insert_after_node(node->prev, iter);
1206 lyd_insert_hash(iter);
Michal Vasko2e784f82024-01-11 09:51:22 +01001207 }
aPiecekdfde77d2024-01-15 15:16:01 +01001208
1209 return LY_SUCCESS;
Michal Vasko2e784f82024-01-11 09:51:22 +01001210}
1211
aPiecekdfde77d2024-01-15 15:16:01 +01001212LIBYANG_API_DEF LY_ERR
Michal Vasko2e784f82024-01-11 09:51:22 +01001213lyd_unlink_tree(struct lyd_node *node)
1214{
aPiecekdfde77d2024-01-15 15:16:01 +01001215 LY_CHECK_RET(lyd_unlink_check(node));
Michal Vasko2e784f82024-01-11 09:51:22 +01001216 lyd_unlink(node);
aPiecekdfde77d2024-01-15 15:16:01 +01001217
1218 return LY_SUCCESS;
Michal Vasko2e784f82024-01-11 09:51:22 +01001219}
1220
Michal Vaskoa5da3292020-08-12 13:10:50 +02001221void
Michal Vasko871a0252020-11-11 18:35:24 +01001222lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta, ly_bool clear_dflt)
Radek Krejci1798aae2020-07-14 13:26:06 +02001223{
1224 struct lyd_meta *last, *iter;
1225
1226 assert(parent);
Michal Vaskoa5da3292020-08-12 13:10:50 +02001227
1228 if (!meta) {
1229 return;
1230 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001231
1232 for (iter = meta; iter; iter = iter->next) {
1233 iter->parent = parent;
1234 }
1235
1236 /* insert as the last attribute */
1237 if (parent->meta) {
Radek Krejci1e008d22020-08-17 11:37:37 +02001238 for (last = parent->meta; last->next; last = last->next) {}
Radek Krejci1798aae2020-07-14 13:26:06 +02001239 last->next = meta;
1240 } else {
1241 parent->meta = meta;
1242 }
1243
1244 /* remove default flags from NP containers */
Michal Vasko871a0252020-11-11 18:35:24 +01001245 while (clear_dflt && parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
Radek Krejci1798aae2020-07-14 13:26:06 +02001246 parent->flags &= ~LYD_DEFAULT;
Michal Vasko9e685082021-01-29 14:49:09 +01001247 parent = lyd_parent(parent);
Radek Krejci1798aae2020-07-14 13:26:06 +02001248 }
Radek Krejci1798aae2020-07-14 13:26:06 +02001249}
1250
aPiecek0e92afc2023-11-08 10:48:02 +01001251void
1252lyd_unlink_meta_single(struct lyd_meta *meta)
1253{
1254 struct lyd_meta *iter;
1255
1256 if (!meta) {
1257 return;
1258 }
1259
1260 if (meta->parent && (meta->parent->meta == meta)) {
1261 meta->parent->meta = meta->next;
1262 } else if (meta->parent) {
1263 for (iter = meta->parent->meta; iter->next && (iter->next != meta); iter = iter->next) {}
1264 if (iter->next) {
1265 iter->next = meta->next;
1266 }
1267 }
1268
1269 meta->next = NULL;
1270 meta->parent = NULL;
1271}
1272
aPiecek0b1df642023-11-06 16:15:33 +01001273/**
1274 * @brief Get the annotation definition in the module.
1275 *
1276 * @param[in] mod Metadata module (with the annotation definition).
1277 * @param[in] name Attribute name.
1278 * @param[in] name_len Length of @p name, must be set correctly.
1279 * @return compiled YANG extension instance on success.
1280 */
1281static struct lysc_ext_instance *
1282lyd_get_meta_annotation(const struct lys_module *mod, const char *name, size_t name_len)
1283{
1284 LY_ARRAY_COUNT_TYPE u;
1285 struct lyplg_ext *plugin;
1286
1287 if (!mod) {
1288 return NULL;
1289 }
1290
1291 LY_ARRAY_FOR(mod->compiled->exts, u) {
1292 plugin = mod->compiled->exts[u].def->plugin;
1293 if (plugin && !strncmp(plugin->id, "ly2 metadata", 12) &&
1294 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
1295 return &mod->compiled->exts[u];
1296 }
1297 }
1298
1299 return NULL;
1300}
1301
Radek Krejci1798aae2020-07-14 13:26:06 +02001302LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +01001303lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
Michal Vasko989cdb42023-10-06 15:32:37 +02001304 size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format,
Michal Vaskoddd76592022-01-17 13:34:48 +01001305 void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete)
Michal Vasko90932a92020-02-12 14:33:03 +01001306{
Radek Krejci2efc45b2020-12-22 16:25:44 +01001307 LY_ERR ret = LY_SUCCESS;
Michal Vasko90932a92020-02-12 14:33:03 +01001308 struct lysc_ext_instance *ant = NULL;
Michal Vasko193dacd2022-10-13 08:43:05 +02001309 const struct lysc_type *ant_type;
Michal Vasko9f96a052020-03-10 09:41:45 +01001310 struct lyd_meta *mt, *last;
Michal Vasko90932a92020-02-12 14:33:03 +01001311
Michal Vasko9f96a052020-03-10 09:41:45 +01001312 assert((parent || meta) && mod);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001313
aPiecek0b1df642023-11-06 16:15:33 +01001314 ant = lyd_get_meta_annotation(mod, name, name_len);
Michal Vasko90932a92020-02-12 14:33:03 +01001315 if (!ant) {
1316 /* attribute is not defined as a metadata annotation (RFC 7952) */
Radek Krejci2efc45b2020-12-22 16:25:44 +01001317 LOGVAL(mod->ctx, LYVE_REFERENCE, "Annotation definition for attribute \"%s:%.*s\" not found.",
Radek Krejci422afb12021-03-04 16:38:16 +01001318 mod->name, (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001319 ret = LY_EINVAL;
1320 goto cleanup;
Michal Vasko90932a92020-02-12 14:33:03 +01001321 }
1322
Michal Vasko9f96a052020-03-10 09:41:45 +01001323 mt = calloc(1, sizeof *mt);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001324 LY_CHECK_ERR_GOTO(!mt, LOGMEM(mod->ctx); ret = LY_EMEM, cleanup);
Michal Vasko9f96a052020-03-10 09:41:45 +01001325 mt->parent = parent;
1326 mt->annotation = ant;
Michal Vaskofbd037c2022-11-08 10:34:20 +01001327 lyplg_ext_get_storage(ant, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type);
Michal Vasko989cdb42023-10-06 15:32:37 +02001328 ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, is_utf8, dynamic, format, prefix_data, hints,
Michal Vaskoddd76592022-01-17 13:34:48 +01001329 ctx_node, incomplete);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001330 LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
1331 ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
1332 LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +01001333
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001334 /* insert as the last attribute */
1335 if (parent) {
Michal Vasko871a0252020-11-11 18:35:24 +01001336 lyd_insert_meta(parent, mt, clear_dflt);
Michal Vasko9f96a052020-03-10 09:41:45 +01001337 } else if (*meta) {
Radek Krejci1e008d22020-08-17 11:37:37 +02001338 for (last = *meta; last->next; last = last->next) {}
Michal Vasko9f96a052020-03-10 09:41:45 +01001339 last->next = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001340 }
1341
Michal Vasko9f96a052020-03-10 09:41:45 +01001342 if (meta) {
1343 *meta = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001344 }
Radek Krejci2efc45b2020-12-22 16:25:44 +01001345
1346cleanup:
Radek Krejci2efc45b2020-12-22 16:25:44 +01001347 return ret;
Michal Vasko90932a92020-02-12 14:33:03 +01001348}
1349
Michal Vaskoa5da3292020-08-12 13:10:50 +02001350void
1351lyd_insert_attr(struct lyd_node *parent, struct lyd_attr *attr)
1352{
1353 struct lyd_attr *last, *iter;
1354 struct lyd_node_opaq *opaq;
1355
1356 assert(parent && !parent->schema);
1357
1358 if (!attr) {
1359 return;
1360 }
1361
1362 opaq = (struct lyd_node_opaq *)parent;
1363 for (iter = attr; iter; iter = iter->next) {
1364 iter->parent = opaq;
1365 }
1366
1367 /* insert as the last attribute */
1368 if (opaq->attr) {
Radek Krejci1e008d22020-08-17 11:37:37 +02001369 for (last = opaq->attr; last->next; last = last->next) {}
Michal Vaskoa5da3292020-08-12 13:10:50 +02001370 last->next = attr;
1371 } else {
1372 opaq->attr = attr;
1373 }
1374}
1375
Michal Vasko52927e22020-03-16 17:26:14 +01001376LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001377lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct ly_ctx *ctx, const char *name, size_t name_len,
Michal Vasko501af032020-11-11 20:27:44 +01001378 const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len, const char *value,
Radek Krejci8df109d2021-04-23 12:19:08 +02001379 size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *val_prefix_data, uint32_t hints)
Michal Vasko52927e22020-03-16 17:26:14 +01001380{
Radek Krejci011e4aa2020-09-04 15:22:31 +02001381 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +02001382 struct lyd_attr *at, *last;
Michal Vasko52927e22020-03-16 17:26:14 +01001383
1384 assert(ctx && (parent || attr) && (!parent || !parent->schema));
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001385 assert(name && name_len && format);
Michal Vasko52927e22020-03-16 17:26:14 +01001386
Michal Vasko2a3722d2021-06-16 11:52:39 +02001387 if (!value_len && (!dynamic || !*dynamic)) {
Michal Vasko52927e22020-03-16 17:26:14 +01001388 value = "";
1389 }
1390
1391 at = calloc(1, sizeof *at);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01001392 LY_CHECK_ERR_RET(!at, LOGMEM(ctx); ly_free_prefix_data(format, val_prefix_data), LY_EMEM);
Radek Krejcid46e46a2020-09-15 14:22:42 +02001393
Michal Vaskoad92b672020-11-12 13:11:31 +01001394 LY_CHECK_GOTO(ret = lydict_insert(ctx, name, name_len, &at->name.name), finish);
Michal Vasko501af032020-11-11 20:27:44 +01001395 if (prefix_len) {
Michal Vaskoad92b672020-11-12 13:11:31 +01001396 LY_CHECK_GOTO(ret = lydict_insert(ctx, prefix, prefix_len, &at->name.prefix), finish);
Michal Vasko501af032020-11-11 20:27:44 +01001397 }
1398 if (module_key_len) {
Michal Vaskoad92b672020-11-12 13:11:31 +01001399 LY_CHECK_GOTO(ret = lydict_insert(ctx, module_key, module_key_len, &at->name.module_ns), finish);
Michal Vasko501af032020-11-11 20:27:44 +01001400 }
1401
Michal Vasko52927e22020-03-16 17:26:14 +01001402 if (dynamic && *dynamic) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02001403 ret = lydict_insert_zc(ctx, (char *)value, &at->value);
1404 LY_CHECK_GOTO(ret, finish);
Michal Vasko52927e22020-03-16 17:26:14 +01001405 *dynamic = 0;
1406 } else {
Radek Krejci011e4aa2020-09-04 15:22:31 +02001407 LY_CHECK_GOTO(ret = lydict_insert(ctx, value, value_len, &at->value), finish);
Michal Vasko52927e22020-03-16 17:26:14 +01001408 }
Michal Vasko501af032020-11-11 20:27:44 +01001409 at->format = format;
1410 at->val_prefix_data = val_prefix_data;
1411 at->hints = hints;
Michal Vasko52927e22020-03-16 17:26:14 +01001412
1413 /* insert as the last attribute */
1414 if (parent) {
Michal Vaskoa5da3292020-08-12 13:10:50 +02001415 lyd_insert_attr(parent, at);
Michal Vasko52927e22020-03-16 17:26:14 +01001416 } else if (*attr) {
Radek Krejci1e008d22020-08-17 11:37:37 +02001417 for (last = *attr; last->next; last = last->next) {}
Michal Vasko52927e22020-03-16 17:26:14 +01001418 last->next = at;
1419 }
1420
Radek Krejci011e4aa2020-09-04 15:22:31 +02001421finish:
1422 if (ret) {
1423 lyd_free_attr_single(ctx, at);
1424 } else if (attr) {
Michal Vasko52927e22020-03-16 17:26:14 +01001425 *attr = at;
1426 }
1427 return LY_SUCCESS;
1428}
1429
aPiecek2f63f952021-03-30 12:22:18 +02001430/**
1431 * @brief Check the equality of the two schemas from different contexts.
1432 *
1433 * @param schema1 of first node.
1434 * @param schema2 of second node.
1435 * @return 1 if the schemas are equal otherwise 0.
1436 */
1437static ly_bool
1438lyd_compare_schema_equal(const struct lysc_node *schema1, const struct lysc_node *schema2)
1439{
1440 if (!schema1 && !schema2) {
1441 return 1;
1442 } else if (!schema1 || !schema2) {
1443 return 0;
1444 }
1445
1446 assert(schema1->module->ctx != schema2->module->ctx);
1447
1448 if (schema1->nodetype != schema2->nodetype) {
1449 return 0;
1450 }
1451
1452 if (strcmp(schema1->name, schema2->name)) {
1453 return 0;
1454 }
1455
1456 if (strcmp(schema1->module->name, schema2->module->name)) {
1457 return 0;
1458 }
1459
aPiecek2f63f952021-03-30 12:22:18 +02001460 return 1;
1461}
1462
1463/**
1464 * @brief Check the equality of the schemas for all parent nodes.
1465 *
1466 * Both nodes must be from different contexts.
1467 *
1468 * @param node1 Data of first node.
1469 * @param node2 Data of second node.
1470 * @return 1 if the all related parental schemas are equal otherwise 0.
1471 */
1472static ly_bool
1473lyd_compare_schema_parents_equal(const struct lyd_node *node1, const struct lyd_node *node2)
1474{
1475 const struct lysc_node *parent1, *parent2;
1476
1477 assert(node1 && node2);
1478
1479 for (parent1 = node1->schema->parent, parent2 = node2->schema->parent;
1480 parent1 && parent2;
1481 parent1 = parent1->parent, parent2 = parent2->parent) {
1482 if (!lyd_compare_schema_equal(parent1, parent2)) {
1483 return 0;
1484 }
1485 }
1486
1487 if (parent1 || parent2) {
1488 return 0;
1489 }
1490
1491 return 1;
1492}
1493
1494/**
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001495 * @brief Compare 2 nodes values including opaque node values.
1496 *
1497 * @param[in] node1 First node to compare.
1498 * @param[in] node2 Second node to compare.
1499 * @return LY_SUCCESS if equal.
1500 * @return LY_ENOT if not equal.
1501 * @return LY_ERR on error.
1502 */
1503static LY_ERR
1504lyd_compare_single_value(const struct lyd_node *node1, const struct lyd_node *node2)
1505{
1506 const struct lyd_node_opaq *opaq1 = NULL, *opaq2 = NULL;
1507 const char *val1, *val2, *col;
1508 const struct lys_module *mod;
1509 char *val_dyn = NULL;
1510 LY_ERR rc = LY_SUCCESS;
1511
1512 if (!node1->schema) {
1513 opaq1 = (struct lyd_node_opaq *)node1;
1514 }
1515 if (!node2->schema) {
1516 opaq2 = (struct lyd_node_opaq *)node2;
1517 }
1518
1519 if (opaq1 && opaq2 && (opaq1->format == LY_VALUE_XML) && (opaq2->format == LY_VALUE_XML)) {
1520 /* opaque XML and opaque XML node */
1521 if (lyxml_value_compare(LYD_CTX(node1), opaq1->value, opaq1->val_prefix_data, LYD_CTX(node2), opaq2->value,
1522 opaq2->val_prefix_data)) {
1523 return LY_ENOT;
1524 }
1525 return LY_SUCCESS;
1526 }
1527
1528 /* get their values */
1529 if (opaq1 && ((opaq1->format == LY_VALUE_XML) || (opaq1->format == LY_VALUE_STR_NS)) && (col = strchr(opaq1->value, ':'))) {
1530 /* XML value with a prefix, try to transform it into a JSON (canonical) value */
1531 mod = ly_resolve_prefix(LYD_CTX(node1), opaq1->value, col - opaq1->value, opaq1->format, opaq1->val_prefix_data);
1532 if (!mod) {
1533 /* unable to compare */
1534 return LY_ENOT;
1535 }
1536
1537 if (asprintf(&val_dyn, "%s%s", mod->name, col) == -1) {
1538 LOGMEM(LYD_CTX(node1));
1539 return LY_EMEM;
1540 }
1541 val1 = val_dyn;
1542 } else {
1543 val1 = lyd_get_value(node1);
1544 }
1545 if (opaq2 && ((opaq2->format == LY_VALUE_XML) || (opaq2->format == LY_VALUE_STR_NS)) && (col = strchr(opaq2->value, ':'))) {
1546 mod = ly_resolve_prefix(LYD_CTX(node2), opaq2->value, col - opaq2->value, opaq2->format, opaq2->val_prefix_data);
1547 if (!mod) {
1548 return LY_ENOT;
1549 }
1550
1551 assert(!val_dyn);
1552 if (asprintf(&val_dyn, "%s%s", mod->name, col) == -1) {
1553 LOGMEM(LYD_CTX(node2));
1554 return LY_EMEM;
1555 }
1556 val2 = val_dyn;
1557 } else {
1558 val2 = lyd_get_value(node2);
1559 }
1560
1561 /* compare values */
1562 if (strcmp(val1, val2)) {
1563 rc = LY_ENOT;
1564 }
1565
1566 free(val_dyn);
1567 return rc;
1568}
1569
1570/**
Michal Vaskof277d362023-04-24 09:08:31 +02001571 * @brief Compare 2 data nodes if they are equivalent regarding the schema tree.
1572 *
1573 * Works correctly even if @p node1 and @p node2 have different contexts.
1574 *
1575 * @param[in] node1 The first node to compare.
1576 * @param[in] node2 The second node to compare.
1577 * @param[in] options Various @ref datacompareoptions.
1578 * @param[in] parental_schemas_checked Flag set if parent schemas were checked for match.
1579 * @return LY_SUCCESS if the nodes are equivalent.
1580 * @return LY_ENOT if the nodes are not equivalent.
aPiecek2f63f952021-03-30 12:22:18 +02001581 */
1582static LY_ERR
Michal Vaskof277d362023-04-24 09:08:31 +02001583lyd_compare_single_schema(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001584 ly_bool parental_schemas_checked)
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001585{
aPiecek2f63f952021-03-30 12:22:18 +02001586 if (LYD_CTX(node1) == LYD_CTX(node2)) {
1587 /* same contexts */
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001588 if (options & LYD_COMPARE_OPAQ) {
1589 if (lyd_node_schema(node1) != lyd_node_schema(node2)) {
1590 return LY_ENOT;
1591 }
1592 } else {
1593 if (node1->schema != node2->schema) {
1594 return LY_ENOT;
1595 }
aPiecek2f63f952021-03-30 12:22:18 +02001596 }
1597 } else {
1598 /* different contexts */
1599 if (!lyd_compare_schema_equal(node1->schema, node2->schema)) {
1600 return LY_ENOT;
1601 }
1602 if (!parental_schemas_checked) {
1603 if (!lyd_compare_schema_parents_equal(node1, node2)) {
1604 return LY_ENOT;
1605 }
1606 parental_schemas_checked = 1;
1607 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001608 }
1609
Michal Vaskof277d362023-04-24 09:08:31 +02001610 return LY_SUCCESS;
1611}
1612
1613/**
1614 * @brief Compare 2 data nodes if they are equivalent regarding the data they contain.
1615 *
1616 * Works correctly even if @p node1 and @p node2 have different contexts.
1617 *
1618 * @param[in] node1 The first node to compare.
1619 * @param[in] node2 The second node to compare.
1620 * @param[in] options Various @ref datacompareoptions.
1621 * @return LY_SUCCESS if the nodes are equivalent.
1622 * @return LY_ENOT if the nodes are not equivalent.
1623 */
1624static LY_ERR
1625lyd_compare_single_data(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
1626{
1627 const struct lyd_node *iter1, *iter2;
1628 struct lyd_node_any *any1, *any2;
1629 int len1, len2;
1630 LY_ERR r;
1631
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001632 if (!(options & LYD_COMPARE_OPAQ) && (node1->hash != node2->hash)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001633 return LY_ENOT;
1634 }
aPiecek2f63f952021-03-30 12:22:18 +02001635 /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001636
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001637 if (!node1->schema || !node2->schema) {
1638 if (!(options & LYD_COMPARE_OPAQ) && ((node1->schema && !node2->schema) || (!node1->schema && node2->schema))) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001639 return LY_ENOT;
1640 }
Michal Vasko7b0500d2023-03-20 15:22:46 +01001641 if ((!node1->schema && !node2->schema) || (node1->schema && (node1->schema->nodetype & LYD_NODE_TERM)) ||
1642 (node2->schema && (node2->schema->nodetype & LYD_NODE_TERM))) {
1643 /* compare values only if there are any to compare */
1644 if ((r = lyd_compare_single_value(node1, node2))) {
1645 return r;
1646 }
Michal Vasko52927e22020-03-16 17:26:14 +01001647 }
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001648
Michal Vasko52927e22020-03-16 17:26:14 +01001649 if (options & LYD_COMPARE_FULL_RECURSION) {
Michal Vaskof277d362023-04-24 09:08:31 +02001650 return lyd_compare_siblings_(lyd_child(node1), lyd_child(node2), options, 1);
Michal Vasko52927e22020-03-16 17:26:14 +01001651 }
1652 return LY_SUCCESS;
1653 } else {
1654 switch (node1->schema->nodetype) {
1655 case LYS_LEAF:
1656 case LYS_LEAFLIST:
1657 if (options & LYD_COMPARE_DEFAULTS) {
1658 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1659 return LY_ENOT;
1660 }
1661 }
Michal Vaskodf8ebf62022-11-10 10:33:28 +01001662 if ((r = lyd_compare_single_value(node1, node2))) {
1663 return r;
aPiecek2f63f952021-03-30 12:22:18 +02001664 }
1665
aPiecek2f63f952021-03-30 12:22:18 +02001666 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001667 case LYS_CONTAINER:
Michal Vaskoc8187dc2022-05-13 12:26:40 +02001668 case LYS_RPC:
1669 case LYS_ACTION:
1670 case LYS_NOTIF:
Michal Vaskoa38adc72023-04-25 10:14:28 +02001671 /* implicit container is always equal to a container with non-default descendants */
Michal Vasko52927e22020-03-16 17:26:14 +01001672 if (options & LYD_COMPARE_FULL_RECURSION) {
Michal Vaskof277d362023-04-24 09:08:31 +02001673 return lyd_compare_siblings_(lyd_child(node1), lyd_child(node2), options, 1);
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001674 }
1675 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001676 case LYS_LIST:
Michal Vasko9e685082021-01-29 14:49:09 +01001677 iter1 = lyd_child(node1);
1678 iter2 = lyd_child(node2);
Michal Vasko52927e22020-03-16 17:26:14 +01001679
Michal Vaskoee9b9482023-06-19 13:17:48 +02001680 if (options & LYD_COMPARE_FULL_RECURSION) {
Michal Vaskof277d362023-04-24 09:08:31 +02001681 return lyd_compare_siblings_(iter1, iter2, options, 1);
Michal Vaskoee9b9482023-06-19 13:17:48 +02001682 } else if (node1->schema->flags & LYS_KEYLESS) {
1683 /* always equal */
1684 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001685 }
Michal Vaskoee9b9482023-06-19 13:17:48 +02001686
1687 /* lists with keys, their equivalence is based on their keys */
1688 for (const struct lysc_node *key = lysc_node_child(node1->schema);
1689 key && (key->flags & LYS_KEY);
1690 key = key->next) {
1691 if (!iter1 || !iter2) {
1692 return (iter1 == iter2) ? LY_SUCCESS : LY_ENOT;
1693 }
1694 r = lyd_compare_single_schema(iter1, iter2, options, 1);
1695 LY_CHECK_RET(r);
1696 r = lyd_compare_single_data(iter1, iter2, options);
1697 LY_CHECK_RET(r);
1698
1699 iter1 = iter1->next;
1700 iter2 = iter2->next;
1701 }
1702
1703 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001704 case LYS_ANYXML:
1705 case LYS_ANYDATA:
Michal Vasko22df3f02020-08-24 13:29:22 +02001706 any1 = (struct lyd_node_any *)node1;
1707 any2 = (struct lyd_node_any *)node2;
Michal Vasko52927e22020-03-16 17:26:14 +01001708
1709 if (any1->value_type != any2->value_type) {
1710 return LY_ENOT;
1711 }
1712 switch (any1->value_type) {
1713 case LYD_ANYDATA_DATATREE:
Michal Vaskof277d362023-04-24 09:08:31 +02001714 return lyd_compare_siblings_(any1->value.tree, any2->value.tree, options, 1);
Michal Vasko52927e22020-03-16 17:26:14 +01001715 case LYD_ANYDATA_STRING:
1716 case LYD_ANYDATA_XML:
1717 case LYD_ANYDATA_JSON:
Michal Vasko3b4ec412022-09-22 15:24:14 +02001718 if ((!any1->value.str && any2->value.str) || (any1->value.str && !any2->value.str)) {
1719 return LY_ENOT;
1720 } else if (!any1->value.str && !any2->value.str) {
1721 return LY_SUCCESS;
1722 }
Michal Vasko52927e22020-03-16 17:26:14 +01001723 len1 = strlen(any1->value.str);
1724 len2 = strlen(any2->value.str);
Michal Vasko69730152020-10-09 16:30:07 +02001725 if ((len1 != len2) || strcmp(any1->value.str, any2->value.str)) {
Michal Vasko52927e22020-03-16 17:26:14 +01001726 return LY_ENOT;
1727 }
1728 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001729 case LYD_ANYDATA_LYB:
Michal Vasko60ea6352020-06-29 13:39:39 +02001730 len1 = lyd_lyb_data_length(any1->value.mem);
1731 len2 = lyd_lyb_data_length(any2->value.mem);
Michal Vasko2b97d472022-08-17 09:29:03 +02001732 if ((len1 == -1) || (len2 == -1) || (len1 != len2) || memcmp(any1->value.mem, any2->value.mem, len1)) {
Michal Vasko52927e22020-03-16 17:26:14 +01001733 return LY_ENOT;
1734 }
1735 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001736 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001737 }
1738 }
1739
Michal Vaskob7be7a82020-08-20 09:09:04 +02001740 LOGINT(LYD_CTX(node1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001741 return LY_EINT;
1742}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001743
Michal Vaskof277d362023-04-24 09:08:31 +02001744/**
1745 * @brief Compare all siblings at a node level.
1746 *
1747 * @param[in] node1 First sibling list.
1748 * @param[in] node2 Second sibling list.
1749 * @param[in] options Various @ref datacompareoptions.
1750 * @param[in] parental_schemas_checked Flag set if parent schemas were checked for match.
1751 * @return LY_SUCCESS if equal.
1752 * @return LY_ENOT if not equal.
1753 * @return LY_ERR on error.
1754 */
1755static LY_ERR
1756lyd_compare_siblings_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
1757 ly_bool parental_schemas_checked)
1758{
1759 LY_ERR r;
1760 const struct lyd_node *iter2;
1761
1762 while (node1 && node2) {
1763 /* schema match */
1764 r = lyd_compare_single_schema(node1, node2, options, parental_schemas_checked);
1765 LY_CHECK_RET(r);
1766
1767 if (node1->schema && (((node1->schema->nodetype == LYS_LIST) && !(node1->schema->flags & LYS_KEYLESS)) ||
1768 ((node1->schema->nodetype == LYS_LEAFLIST) && (node1->schema->flags & LYS_CONFIG_W))) &&
1769 (node1->schema->flags & LYS_ORDBY_SYSTEM)) {
1770 /* find a matching instance in case they are ordered differently */
1771 r = lyd_find_sibling_first(node2, node1, (struct lyd_node **)&iter2);
1772 if (r == LY_ENOTFOUND) {
1773 /* no matching instance, data not equal */
1774 r = LY_ENOT;
1775 }
1776 LY_CHECK_RET(r);
1777 } else {
1778 /* compare with the current node */
1779 iter2 = node2;
1780 }
1781
1782 /* data match */
1783 r = lyd_compare_single_data(node1, iter2, options | LYD_COMPARE_FULL_RECURSION);
1784 LY_CHECK_RET(r);
1785
1786 node1 = node1->next;
1787 node2 = node2->next;
1788 }
1789
1790 return (node1 || node2) ? LY_ENOT : LY_SUCCESS;
1791}
1792
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001793LIBYANG_API_DEF LY_ERR
aPiecek2f63f952021-03-30 12:22:18 +02001794lyd_compare_single(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
1795{
Michal Vaskof277d362023-04-24 09:08:31 +02001796 LY_ERR r;
1797
1798 if (!node1 || !node2) {
1799 return (node1 == node2) ? LY_SUCCESS : LY_ENOT;
1800 }
1801
1802 /* schema match */
1803 if ((r = lyd_compare_single_schema(node1, node2, options, 0))) {
1804 return r;
1805 }
1806
1807 /* data match */
1808 return lyd_compare_single_data(node1, node2, options);
aPiecek2f63f952021-03-30 12:22:18 +02001809}
1810
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001811LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001812lyd_compare_siblings(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
Michal Vasko8f359bf2020-07-28 10:41:15 +02001813{
Michal Vaskof277d362023-04-24 09:08:31 +02001814 return lyd_compare_siblings_(node1, node2, options, 0);
Michal Vasko8f359bf2020-07-28 10:41:15 +02001815}
1816
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001817LIBYANG_API_DEF LY_ERR
Michal Vasko21725742020-06-29 11:49:25 +02001818lyd_compare_meta(const struct lyd_meta *meta1, const struct lyd_meta *meta2)
1819{
aPiecek0a6705b2023-11-14 14:20:58 +01001820 const struct ly_ctx *ctx;
1821
Michal Vasko21725742020-06-29 11:49:25 +02001822 if (!meta1 || !meta2) {
1823 if (meta1 == meta2) {
1824 return LY_SUCCESS;
1825 } else {
1826 return LY_ENOT;
1827 }
1828 }
1829
aPiecek0a6705b2023-11-14 14:20:58 +01001830 ctx = meta1->annotation->module->ctx;
1831 if ((ctx != meta2->annotation->module->ctx) || (meta1->annotation != meta2->annotation)) {
Michal Vasko21725742020-06-29 11:49:25 +02001832 return LY_ENOT;
1833 }
1834
aPiecek0a6705b2023-11-14 14:20:58 +01001835 return meta1->value.realtype->plugin->compare(ctx, &meta1->value, &meta2->value);
Michal Vasko21725742020-06-29 11:49:25 +02001836}
1837
Radek Krejci22ebdba2019-07-25 13:59:43 +02001838/**
Michal Vasko9cf62422021-07-01 13:29:32 +02001839 * @brief Create a copy of the attribute.
1840 *
1841 * @param[in] attr Attribute to copy.
1842 * @param[in] node Opaque where to append the new attribute.
1843 * @param[out] dup Optional created attribute copy.
1844 * @return LY_ERR value.
1845 */
1846static LY_ERR
1847lyd_dup_attr_single(const struct lyd_attr *attr, struct lyd_node *node, struct lyd_attr **dup)
1848{
1849 LY_ERR ret = LY_SUCCESS;
1850 struct lyd_attr *a, *last;
1851 struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)node;
1852
1853 LY_CHECK_ARG_RET(NULL, attr, node, !node->schema, LY_EINVAL);
1854
1855 /* create a copy */
1856 a = calloc(1, sizeof *attr);
1857 LY_CHECK_ERR_RET(!a, LOGMEM(LYD_CTX(node)), LY_EMEM);
1858
1859 LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->name.name, 0, &a->name.name), finish);
1860 LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->name.prefix, 0, &a->name.prefix), finish);
1861 LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->name.module_ns, 0, &a->name.module_ns), finish);
1862 LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->value, 0, &a->value), finish);
1863 a->hints = attr->hints;
1864 a->format = attr->format;
1865 if (attr->val_prefix_data) {
1866 ret = ly_dup_prefix_data(LYD_CTX(node), attr->format, attr->val_prefix_data, &a->val_prefix_data);
1867 LY_CHECK_GOTO(ret, finish);
1868 }
1869
1870 /* insert as the last attribute */
1871 a->parent = opaq;
1872 if (opaq->attr) {
1873 for (last = opaq->attr; last->next; last = last->next) {}
1874 last->next = a;
1875 } else {
1876 opaq->attr = a;
1877 }
1878
1879finish:
1880 if (ret) {
1881 lyd_free_attr_single(LYD_CTX(node), a);
1882 } else if (dup) {
1883 *dup = a;
1884 }
1885 return LY_SUCCESS;
1886}
1887
1888/**
Michal Vaskoddd76592022-01-17 13:34:48 +01001889 * @brief Find @p schema equivalent in @p trg_ctx.
1890 *
1891 * @param[in] schema Schema node to find.
1892 * @param[in] trg_ctx Target context to search in.
1893 * @param[in] parent Data parent of @p schema, if any.
Michal Vaskoaf3df492022-12-02 14:03:52 +01001894 * @param[in] log Whether to log directly.
Michal Vaskoddd76592022-01-17 13:34:48 +01001895 * @param[out] trg_schema Found schema from @p trg_ctx to use.
1896 * @return LY_RRR value.
1897 */
1898static LY_ERR
Michal Vaskoaf3df492022-12-02 14:03:52 +01001899lyd_find_schema_ctx(const struct lysc_node *schema, const struct ly_ctx *trg_ctx, const struct lyd_node *parent,
1900 ly_bool log, const struct lysc_node **trg_schema)
Michal Vaskoddd76592022-01-17 13:34:48 +01001901{
Michal Vasko9beceb82022-04-05 12:14:15 +02001902 const struct lysc_node *src_parent = NULL, *trg_parent = NULL, *sp, *tp;
1903 const struct lys_module *trg_mod = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +01001904 char *path;
1905
1906 if (!schema) {
1907 /* opaque node */
1908 *trg_schema = NULL;
1909 return LY_SUCCESS;
1910 }
1911
Michal Vasko9beceb82022-04-05 12:14:15 +02001912 if (lysc_data_parent(schema) && parent && parent->schema) {
Michal Vaskoddd76592022-01-17 13:34:48 +01001913 /* start from schema parent */
Michal Vasko9beceb82022-04-05 12:14:15 +02001914 trg_parent = parent->schema;
1915 src_parent = lysc_data_parent(schema);
1916 }
1917
1918 do {
1919 /* find the next parent */
1920 sp = schema;
Michal Vaskob6808202022-12-02 14:04:23 +01001921 while (lysc_data_parent(sp) != src_parent) {
1922 sp = lysc_data_parent(sp);
Michal Vasko9beceb82022-04-05 12:14:15 +02001923 }
1924 src_parent = sp;
1925
1926 if (!src_parent->parent) {
1927 /* find the module first */
1928 trg_mod = ly_ctx_get_module_implemented(trg_ctx, src_parent->module->name);
1929 if (!trg_mod) {
Michal Vaskoaf3df492022-12-02 14:03:52 +01001930 if (log) {
1931 LOGERR(trg_ctx, LY_ENOTFOUND, "Module \"%s\" not present/implemented in the target context.",
1932 src_parent->module->name);
1933 }
Michal Vasko9beceb82022-04-05 12:14:15 +02001934 return LY_ENOTFOUND;
1935 }
1936 }
1937
1938 /* find the next parent */
1939 assert(trg_parent || trg_mod);
1940 tp = NULL;
1941 while ((tp = lys_getnext(tp, trg_parent, trg_mod ? trg_mod->compiled : NULL, 0))) {
1942 if (!strcmp(tp->name, src_parent->name) && !strcmp(tp->module->name, src_parent->module->name)) {
1943 break;
1944 }
1945 }
1946 if (!tp) {
1947 /* schema node not found */
Michal Vaskoaf3df492022-12-02 14:03:52 +01001948 if (log) {
1949 path = lysc_path(src_parent, LYSC_PATH_LOG, NULL, 0);
1950 LOGERR(trg_ctx, LY_ENOTFOUND, "Schema node \"%s\" not found in the target context.", path);
1951 free(path);
1952 }
Michal Vaskoddd76592022-01-17 13:34:48 +01001953 return LY_ENOTFOUND;
1954 }
Michal Vaskoddd76592022-01-17 13:34:48 +01001955
Michal Vasko9beceb82022-04-05 12:14:15 +02001956 trg_parent = tp;
1957 } while (schema != src_parent);
Michal Vaskoddd76592022-01-17 13:34:48 +01001958
Michal Vasko9beceb82022-04-05 12:14:15 +02001959 /* success */
1960 *trg_schema = trg_parent;
1961 return LY_SUCCESS;
Michal Vaskoddd76592022-01-17 13:34:48 +01001962}
1963
1964/**
Michal Vasko52927e22020-03-16 17:26:14 +01001965 * @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
Radek Krejci22ebdba2019-07-25 13:59:43 +02001966 *
aPiecek55653c92023-11-09 13:43:19 +01001967 * Ignores ::LYD_DUP_WITH_PARENTS which is supposed to be handled by lyd_dup().
Radek Krejcif8b95172020-05-15 14:51:06 +02001968 *
Michal Vaskoddd76592022-01-17 13:34:48 +01001969 * @param[in] node Node to duplicate.
1970 * @param[in] trg_ctx Target context for duplicated nodes.
Radek Krejcif8b95172020-05-15 14:51:06 +02001971 * @param[in] parent Parent to insert into, NULL for top-level sibling.
Michal Vasko67177e52021-08-25 11:15:15 +02001972 * @param[in] insert_last Whether the duplicated node can be inserted as the last child of @p parent. Set for
1973 * recursive duplication as an optimization.
Radek Krejcif8b95172020-05-15 14:51:06 +02001974 * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
1975 * @param[in] options Bitmask of options flags, see @ref dupoptions.
Michal Vaskoddd76592022-01-17 13:34:48 +01001976 * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it to @p parent / @p first).
1977 * @return LY_ERR value.
Radek Krejci22ebdba2019-07-25 13:59:43 +02001978 */
Michal Vasko52927e22020-03-16 17:26:14 +01001979static LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +01001980lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, ly_bool insert_last,
1981 struct lyd_node **first, uint32_t options, struct lyd_node **dup_p)
Radek Krejci22ebdba2019-07-25 13:59:43 +02001982{
Michal Vasko52927e22020-03-16 17:26:14 +01001983 LY_ERR ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001984 struct lyd_node *dup = NULL;
Michal Vasko61551fa2020-07-09 15:45:45 +02001985 struct lyd_meta *meta;
Michal Vasko9cf62422021-07-01 13:29:32 +02001986 struct lyd_attr *attr;
Michal Vasko61551fa2020-07-09 15:45:45 +02001987 struct lyd_node_any *any;
Michal Vaskoddd76592022-01-17 13:34:48 +01001988 const struct lysc_type *type;
1989 const char *val_can;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001990
Michal Vasko52927e22020-03-16 17:26:14 +01001991 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001992
Michal Vasko19175b62022-04-01 09:17:07 +02001993 if (node->flags & LYD_EXT) {
Michal Vasko53ac4dd2022-06-07 10:56:08 +02001994 if (options & LYD_DUP_NO_EXT) {
1995 /* no not duplicate this subtree */
1996 return LY_SUCCESS;
1997 }
1998
Michal Vasko19175b62022-04-01 09:17:07 +02001999 /* we need to use the same context */
2000 trg_ctx = LYD_CTX(node);
2001 }
2002
Michal Vasko52927e22020-03-16 17:26:14 +01002003 if (!node->schema) {
2004 dup = calloc(1, sizeof(struct lyd_node_opaq));
Michal Vaskoddd76592022-01-17 13:34:48 +01002005 ((struct lyd_node_opaq *)dup)->ctx = trg_ctx;
Michal Vasko52927e22020-03-16 17:26:14 +01002006 } else {
2007 switch (node->schema->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +01002008 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01002009 case LYS_ACTION:
2010 case LYS_NOTIF:
2011 case LYS_CONTAINER:
2012 case LYS_LIST:
2013 dup = calloc(1, sizeof(struct lyd_node_inner));
2014 break;
2015 case LYS_LEAF:
2016 case LYS_LEAFLIST:
2017 dup = calloc(1, sizeof(struct lyd_node_term));
2018 break;
2019 case LYS_ANYDATA:
2020 case LYS_ANYXML:
2021 dup = calloc(1, sizeof(struct lyd_node_any));
2022 break;
2023 default:
Michal Vaskoddd76592022-01-17 13:34:48 +01002024 LOGINT(trg_ctx);
Michal Vasko52927e22020-03-16 17:26:14 +01002025 ret = LY_EINT;
2026 goto error;
2027 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02002028 }
Michal Vaskoddd76592022-01-17 13:34:48 +01002029 LY_CHECK_ERR_GOTO(!dup, LOGMEM(trg_ctx); ret = LY_EMEM, error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002030
Michal Vaskof6df0a02020-06-16 13:08:34 +02002031 if (options & LYD_DUP_WITH_FLAGS) {
2032 dup->flags = node->flags;
2033 } else {
Michal Vasko19175b62022-04-01 09:17:07 +02002034 dup->flags = (node->flags & (LYD_DEFAULT | LYD_EXT)) | LYD_NEW;
Michal Vaskof6df0a02020-06-16 13:08:34 +02002035 }
Igor Ryzhov9e7af662023-10-31 13:27:56 +02002036 if (options & LYD_DUP_WITH_PRIV) {
2037 dup->priv = node->priv;
2038 }
Michal Vaskoddd76592022-01-17 13:34:48 +01002039 if (trg_ctx == LYD_CTX(node)) {
2040 dup->schema = node->schema;
2041 } else {
Michal Vaskoaf3df492022-12-02 14:03:52 +01002042 ret = lyd_find_schema_ctx(node->schema, trg_ctx, parent, 1, &dup->schema);
Michal Vasko27f536f2022-04-01 09:17:30 +02002043 if (ret) {
2044 /* has no schema but is not an opaque node */
2045 free(dup);
2046 dup = NULL;
2047 goto error;
2048 }
Michal Vaskoddd76592022-01-17 13:34:48 +01002049 }
Michal Vasko52927e22020-03-16 17:26:14 +01002050 dup->prev = dup;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002051
Michal Vasko9cf62422021-07-01 13:29:32 +02002052 /* duplicate metadata/attributes */
Michal Vasko25a32822020-07-09 15:48:22 +02002053 if (!(options & LYD_DUP_NO_META)) {
Michal Vasko9cf62422021-07-01 13:29:32 +02002054 if (!node->schema) {
2055 LY_LIST_FOR(((struct lyd_node_opaq *)node)->attr, attr) {
2056 LY_CHECK_GOTO(ret = lyd_dup_attr_single(attr, dup, NULL), error);
2057 }
2058 } else {
2059 LY_LIST_FOR(node->meta, meta) {
aPiecek41680342023-11-08 10:19:44 +01002060 LY_CHECK_GOTO(ret = lyd_dup_meta_single_to_ctx(trg_ctx, meta, dup, NULL), error);
Michal Vasko9cf62422021-07-01 13:29:32 +02002061 }
Michal Vasko25a32822020-07-09 15:48:22 +02002062 }
2063 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02002064
2065 /* nodetype-specific work */
Michal Vasko52927e22020-03-16 17:26:14 +01002066 if (!dup->schema) {
2067 struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
2068 struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
2069 struct lyd_node *child;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002070
2071 if (options & LYD_DUP_RECURSIVE) {
2072 /* duplicate all the children */
2073 LY_LIST_FOR(orig->child, child) {
Michal Vaskoddd76592022-01-17 13:34:48 +01002074 LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
Michal Vasko52927e22020-03-16 17:26:14 +01002075 }
2076 }
Michal Vaskoddd76592022-01-17 13:34:48 +01002077 LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.name, 0, &opaq->name.name), error);
2078 LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.prefix, 0, &opaq->name.prefix), error);
2079 LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.module_ns, 0, &opaq->name.module_ns), error);
2080 LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->value, 0, &opaq->value), error);
Michal Vasko9cf62422021-07-01 13:29:32 +02002081 opaq->hints = orig->hints;
2082 opaq->format = orig->format;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01002083 if (orig->val_prefix_data) {
Michal Vaskoddd76592022-01-17 13:34:48 +01002084 ret = ly_dup_prefix_data(trg_ctx, opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
Michal Vasko6b5cb2a2020-11-11 19:11:21 +01002085 LY_CHECK_GOTO(ret, error);
Michal Vasko52927e22020-03-16 17:26:14 +01002086 }
Michal Vasko52927e22020-03-16 17:26:14 +01002087 } else if (dup->schema->nodetype & LYD_NODE_TERM) {
2088 struct lyd_node_term *term = (struct lyd_node_term *)dup;
2089 struct lyd_node_term *orig = (struct lyd_node_term *)node;
2090
2091 term->hash = orig->hash;
Michal Vaskoddd76592022-01-17 13:34:48 +01002092 if (trg_ctx == LYD_CTX(node)) {
2093 ret = orig->value.realtype->plugin->duplicate(trg_ctx, &orig->value, &term->value);
2094 LY_CHECK_ERR_GOTO(ret, LOGERR(trg_ctx, ret, "Value duplication failed."), error);
2095 } else {
2096 /* store canonical value in the target context */
2097 val_can = lyd_get_value(node);
2098 type = ((struct lysc_node_leaf *)term->schema)->type;
Michal Vasko989cdb42023-10-06 15:32:37 +02002099 ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, NULL, LY_VALUE_CANON, NULL,
Michal Vaskoddd76592022-01-17 13:34:48 +01002100 LYD_HINT_DATA, term->schema, NULL);
2101 LY_CHECK_GOTO(ret, error);
2102 }
Michal Vasko52927e22020-03-16 17:26:14 +01002103 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
2104 struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
2105 struct lyd_node *child;
2106
2107 if (options & LYD_DUP_RECURSIVE) {
2108 /* duplicate all the children */
2109 LY_LIST_FOR(orig->child, child) {
Michal Vaskoddd76592022-01-17 13:34:48 +01002110 LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002111 }
Michal Vasko69730152020-10-09 16:30:07 +02002112 } else if ((dup->schema->nodetype == LYS_LIST) && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002113 /* always duplicate keys of a list */
Michal Vasko9beceb82022-04-05 12:14:15 +02002114 for (child = orig->child; child && lysc_is_key(child->schema); child = child->next) {
Michal Vaskoddd76592022-01-17 13:34:48 +01002115 LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002116 }
2117 }
2118 lyd_hash(dup);
2119 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
Michal Vasko61551fa2020-07-09 15:45:45 +02002120 dup->hash = node->hash;
2121 any = (struct lyd_node_any *)node;
2122 LY_CHECK_GOTO(ret = lyd_any_copy_value(dup, &any->value, any->value_type), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002123 }
2124
Michal Vasko52927e22020-03-16 17:26:14 +01002125 /* insert */
Michal Vasko67177e52021-08-25 11:15:15 +02002126 lyd_insert_node(parent, first, dup, insert_last);
Michal Vasko52927e22020-03-16 17:26:14 +01002127
2128 if (dup_p) {
2129 *dup_p = dup;
2130 }
2131 return LY_SUCCESS;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002132
2133error:
Michal Vasko52927e22020-03-16 17:26:14 +01002134 lyd_free_tree(dup);
2135 return ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002136}
2137
Michal Vasko29d674b2021-08-25 11:18:35 +02002138/**
2139 * @brief Get a parent node to connect duplicated subtree to.
2140 *
2141 * @param[in] node Node (subtree) to duplicate.
Michal Vaskoddd76592022-01-17 13:34:48 +01002142 * @param[in] trg_ctx Target context for duplicated nodes.
Michal Vasko29d674b2021-08-25 11:18:35 +02002143 * @param[in] parent Initial parent to connect to.
2144 * @param[in] options Bitmask of options flags, see @ref dupoptions.
2145 * @param[out] dup_parent First duplicated parent node, if any.
2146 * @param[out] local_parent Correct parent to directly connect duplicated @p node to.
2147 * @return LY_ERR value.
2148 */
Michal Vasko3a41dff2020-07-15 14:30:28 +02002149static LY_ERR
Michal Vasko58d89e92023-05-23 09:56:19 +02002150lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
2151 uint32_t options, struct lyd_node **dup_parent, struct lyd_node **local_parent)
Radek Krejci22ebdba2019-07-25 13:59:43 +02002152{
Michal Vasko58d89e92023-05-23 09:56:19 +02002153 const struct lyd_node *orig_parent;
Michal Vaskoeaef7c92023-10-17 10:06:15 +02002154 struct lyd_node *iter = NULL;
Michal Vasko83522192022-07-20 08:07:34 +02002155 ly_bool repeat = 1, ext_parent = 0;
Michal Vasko3a41dff2020-07-15 14:30:28 +02002156
2157 *dup_parent = NULL;
2158 *local_parent = NULL;
2159
Michal Vasko83522192022-07-20 08:07:34 +02002160 if (node->flags & LYD_EXT) {
2161 ext_parent = 1;
2162 }
Michal Vasko58d89e92023-05-23 09:56:19 +02002163 for (orig_parent = lyd_parent(node); repeat && orig_parent; orig_parent = lyd_parent(orig_parent)) {
Michal Vasko83522192022-07-20 08:07:34 +02002164 if (ext_parent) {
2165 /* use the standard context */
2166 trg_ctx = LYD_CTX(orig_parent);
2167 }
Michal Vasko13c5b212023-02-14 10:03:01 +01002168 if (parent && (LYD_CTX(parent) == LYD_CTX(orig_parent)) && (parent->schema == orig_parent->schema)) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02002169 /* stop creating parents, connect what we have into the provided parent */
2170 iter = parent;
2171 repeat = 0;
Michal Vasko13c5b212023-02-14 10:03:01 +01002172 } else if (parent && (LYD_CTX(parent) != LYD_CTX(orig_parent)) &&
2173 lyd_compare_schema_equal(parent->schema, orig_parent->schema) &&
Michal Vasko58d89e92023-05-23 09:56:19 +02002174 lyd_compare_schema_parents_equal(parent, orig_parent)) {
Michal Vasko13c5b212023-02-14 10:03:01 +01002175 iter = parent;
2176 repeat = 0;
Michal Vasko3a41dff2020-07-15 14:30:28 +02002177 } else {
2178 iter = NULL;
Michal Vasko58d89e92023-05-23 09:56:19 +02002179 LY_CHECK_RET(lyd_dup_r(orig_parent, trg_ctx, NULL, 0, &iter, options, &iter));
Michal Vaskoeaef7c92023-10-17 10:06:15 +02002180
2181 /* insert into the previous duplicated parent */
2182 if (*dup_parent) {
2183 lyd_insert_node(iter, NULL, *dup_parent, 0);
2184 }
2185
2186 /* update the last duplicated parent */
2187 *dup_parent = iter;
Michal Vasko3a41dff2020-07-15 14:30:28 +02002188 }
Michal Vasko58d89e92023-05-23 09:56:19 +02002189
Michal Vaskoeaef7c92023-10-17 10:06:15 +02002190 /* set the first parent */
Michal Vasko3a41dff2020-07-15 14:30:28 +02002191 if (!*local_parent) {
Michal Vasko58d89e92023-05-23 09:56:19 +02002192 *local_parent = iter;
Michal Vasko3a41dff2020-07-15 14:30:28 +02002193 }
Michal Vasko58d89e92023-05-23 09:56:19 +02002194
Michal Vasko83522192022-07-20 08:07:34 +02002195 if (orig_parent->flags & LYD_EXT) {
2196 ext_parent = 1;
2197 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02002198 }
2199
2200 if (repeat && parent) {
2201 /* given parent and created parents chain actually do not interconnect */
Michal Vasko58d89e92023-05-23 09:56:19 +02002202 LOGERR(trg_ctx, LY_EINVAL, "None of the duplicated node \"%s\" schema parents match the provided parent \"%s\".",
2203 LYD_NAME(node), LYD_NAME(parent));
Michal Vasko3a41dff2020-07-15 14:30:28 +02002204 return LY_EINVAL;
2205 }
2206
Michal Vaskoeaef7c92023-10-17 10:06:15 +02002207 if (*dup_parent && parent) {
2208 /* last insert into a prevously-existing parent */
2209 lyd_insert_node(parent, NULL, *dup_parent, 0);
2210 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02002211 return LY_SUCCESS;
2212}
2213
2214static LY_ERR
Michal Vasko58d89e92023-05-23 09:56:19 +02002215lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, uint32_t options,
Michal Vaskoddd76592022-01-17 13:34:48 +01002216 ly_bool nosiblings, struct lyd_node **dup)
Michal Vasko3a41dff2020-07-15 14:30:28 +02002217{
2218 LY_ERR rc;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002219 const struct lyd_node *orig; /* original node to be duplicated */
2220 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
Radek Krejci22ebdba2019-07-25 13:59:43 +02002221 struct lyd_node *top = NULL; /* the most higher created node */
Michal Vasko58d89e92023-05-23 09:56:19 +02002222 struct lyd_node *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
Radek Krejci22ebdba2019-07-25 13:59:43 +02002223
Michal Vasko1feb9bb2022-07-20 08:44:07 +02002224 assert(node && trg_ctx);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002225
2226 if (options & LYD_DUP_WITH_PARENTS) {
Michal Vaskoddd76592022-01-17 13:34:48 +01002227 LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, trg_ctx, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
Michal Vasko20909752021-05-18 16:13:38 +02002228 &top, &local_parent), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002229 } else {
2230 local_parent = parent;
2231 }
2232
Radek Krejci22ebdba2019-07-25 13:59:43 +02002233 LY_LIST_FOR(node, orig) {
Michal Vasko35f4d772021-01-12 12:08:57 +01002234 if (lysc_is_key(orig->schema)) {
2235 if (local_parent) {
2236 /* the key must already exist in the parent */
Michal Vasko58d89e92023-05-23 09:56:19 +02002237 rc = lyd_find_sibling_schema(lyd_child(local_parent), orig->schema, first ? NULL : &first);
Michal Vaskoddd76592022-01-17 13:34:48 +01002238 LY_CHECK_ERR_GOTO(rc, LOGINT(trg_ctx), error);
Michal Vasko35f4d772021-01-12 12:08:57 +01002239 } else {
2240 assert(!(options & LYD_DUP_WITH_PARENTS));
2241 /* duplicating a single key, okay, I suppose... */
Michal Vaskoddd76592022-01-17 13:34:48 +01002242 rc = lyd_dup_r(orig, trg_ctx, NULL, 0, &first, options, first ? NULL : &first);
Michal Vasko35f4d772021-01-12 12:08:57 +01002243 LY_CHECK_GOTO(rc, error);
2244 }
2245 } else {
2246 /* if there is no local parent, it will be inserted into first */
Michal Vasko58d89e92023-05-23 09:56:19 +02002247 rc = lyd_dup_r(orig, trg_ctx, local_parent, 0, &first, options, first ? NULL : &first);
Michal Vasko35f4d772021-01-12 12:08:57 +01002248 LY_CHECK_GOTO(rc, error);
2249 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02002250 if (nosiblings) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002251 break;
2252 }
2253 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02002254
Michal Vasko3a41dff2020-07-15 14:30:28 +02002255 if (dup) {
2256 *dup = first;
2257 }
2258 return LY_SUCCESS;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002259
2260error:
2261 if (top) {
2262 lyd_free_tree(top);
2263 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01002264 lyd_free_siblings(first);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002265 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02002266 return rc;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002267}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002268
Michal Vasko1feb9bb2022-07-20 08:44:07 +02002269/**
2270 * @brief Check the context of node and parent when duplicating nodes.
2271 *
2272 * @param[in] node Node to duplicate.
2273 * @param[in] parent Parent of the duplicated node(s).
2274 * @return LY_ERR value.
2275 */
2276static LY_ERR
2277lyd_dup_ctx_check(const struct lyd_node *node, const struct lyd_node_inner *parent)
2278{
2279 const struct lyd_node *iter;
2280
2281 if (!node || !parent) {
2282 return LY_SUCCESS;
2283 }
2284
2285 if ((LYD_CTX(node) != LYD_CTX(parent))) {
2286 /* try to find top-level ext data parent */
2287 for (iter = node; iter && !(iter->flags & LYD_EXT); iter = lyd_parent(iter)) {}
2288
2289 if (!iter || !lyd_parent(iter) || (LYD_CTX(lyd_parent(iter)) != LYD_CTX(parent))) {
Michal Vaskoce55b462023-02-14 10:03:32 +01002290 LOGERR(LYD_CTX(node), LY_EINVAL, "Different contexts used in node duplication.");
Michal Vasko1feb9bb2022-07-20 08:44:07 +02002291 return LY_EINVAL;
2292 }
2293 }
2294
2295 return LY_SUCCESS;
2296}
2297
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002298LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02002299lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
Michal Vasko3a41dff2020-07-15 14:30:28 +02002300{
Michal Vaskoddd76592022-01-17 13:34:48 +01002301 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Michal Vasko1feb9bb2022-07-20 08:44:07 +02002302 LY_CHECK_RET(lyd_dup_ctx_check(node, parent));
Michal Vaskoddd76592022-01-17 13:34:48 +01002303
Michal Vasko58d89e92023-05-23 09:56:19 +02002304 return lyd_dup(node, LYD_CTX(node), (struct lyd_node *)parent, options, 1, dup);
Michal Vaskoddd76592022-01-17 13:34:48 +01002305}
2306
2307LIBYANG_API_DEF LY_ERR
2308lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent,
2309 uint32_t options, struct lyd_node **dup)
2310{
2311 LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
2312
Michal Vasko58d89e92023-05-23 09:56:19 +02002313 return lyd_dup(node, trg_ctx, (struct lyd_node *)parent, options, 1, dup);
Michal Vasko3a41dff2020-07-15 14:30:28 +02002314}
2315
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002316LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02002317lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
Michal Vasko3a41dff2020-07-15 14:30:28 +02002318{
Michal Vaskoddd76592022-01-17 13:34:48 +01002319 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Michal Vasko1feb9bb2022-07-20 08:44:07 +02002320 LY_CHECK_RET(lyd_dup_ctx_check(node, parent));
Michal Vaskoddd76592022-01-17 13:34:48 +01002321
Michal Vasko58d89e92023-05-23 09:56:19 +02002322 return lyd_dup(node, LYD_CTX(node), (struct lyd_node *)parent, options, 0, dup);
Michal Vaskoddd76592022-01-17 13:34:48 +01002323}
2324
2325LIBYANG_API_DEF LY_ERR
2326lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent,
2327 uint32_t options, struct lyd_node **dup)
2328{
2329 LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
2330
Michal Vasko58d89e92023-05-23 09:56:19 +02002331 return lyd_dup(node, trg_ctx, (struct lyd_node *)parent, options, 0, dup);
Michal Vasko3a41dff2020-07-15 14:30:28 +02002332}
2333
aPiecek41680342023-11-08 10:19:44 +01002334LY_ERR
2335lyd_dup_meta_single_to_ctx(const struct ly_ctx *parent_ctx, const struct lyd_meta *meta, struct lyd_node *parent,
2336 struct lyd_meta **dup)
Michal Vasko25a32822020-07-09 15:48:22 +02002337{
Radek Krejci011e4aa2020-09-04 15:22:31 +02002338 LY_ERR ret = LY_SUCCESS;
Michal Vasko25a32822020-07-09 15:48:22 +02002339 struct lyd_meta *mt, *last;
aPiecek41680342023-11-08 10:19:44 +01002340 const struct lysc_type *ant_type;
2341 struct lys_module *mod;
2342 const char *val_can;
Michal Vasko25a32822020-07-09 15:48:22 +02002343
aPiecek41680342023-11-08 10:19:44 +01002344 LY_CHECK_ARG_RET(NULL, meta, parent, LY_EINVAL);
Michal Vasko33c48972022-07-20 10:28:07 +02002345
Michal Vasko25a32822020-07-09 15:48:22 +02002346 /* create a copy */
2347 mt = calloc(1, sizeof *mt);
aPiecek41680342023-11-08 10:19:44 +01002348 LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_CTX(parent)), LY_EMEM);
2349
2350 if (parent_ctx != meta->annotation->module->ctx) {
2351 /* different contexts */
2352 mod = ly_ctx_get_module(parent_ctx, meta->annotation->module->name, meta->annotation->module->revision);
2353
2354 /* annotation */
2355 mt->annotation = lyd_get_meta_annotation(mod, meta->name, strlen(meta->name));
2356 lyplg_ext_get_storage(mt->annotation, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type);
2357 LY_CHECK_ERR_GOTO((ret = mt->annotation ? LY_SUCCESS : LY_EINVAL), LOGERR(parent_ctx, LY_EINVAL,
2358 "Annotation for metadata %s not found, value duplication failed.", meta->name), finish);
2359
2360 /* duplicate callback expect only the same contexts, so use the store callback */
2361 val_can = lyd_value_get_canonical(meta->annotation->module->ctx, &meta->value);
2362 ret = lyd_value_store(parent_ctx, &mt->value, ant_type, val_can, strlen(val_can), 1, NULL,
2363 LY_VALUE_CANON, NULL, LYD_HINT_DATA, parent->schema, NULL);
2364 } else {
2365 /* annotation */
2366 mt->annotation = meta->annotation;
2367 /* duplication of value */
2368 ret = meta->value.realtype->plugin->duplicate(parent_ctx, &meta->value, &mt->value);
2369 }
2370 LY_CHECK_ERR_GOTO(ret, LOGERR(LYD_CTX(parent), LY_EINT, "Value duplication failed."), finish);
2371 LY_CHECK_GOTO(ret = lydict_insert(parent_ctx, meta->name, 0, &mt->name), finish);
Michal Vasko25a32822020-07-09 15:48:22 +02002372
2373 /* insert as the last attribute */
aPiecek41680342023-11-08 10:19:44 +01002374 mt->parent = parent;
2375 if (parent->meta) {
2376 for (last = parent->meta; last->next; last = last->next) {}
Michal Vasko25a32822020-07-09 15:48:22 +02002377 last->next = mt;
2378 } else {
aPiecek41680342023-11-08 10:19:44 +01002379 parent->meta = mt;
Michal Vasko25a32822020-07-09 15:48:22 +02002380 }
2381
Radek Krejci011e4aa2020-09-04 15:22:31 +02002382finish:
2383 if (ret) {
2384 lyd_free_meta_single(mt);
2385 } else if (dup) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02002386 *dup = mt;
2387 }
2388 return LY_SUCCESS;
Michal Vasko25a32822020-07-09 15:48:22 +02002389}
2390
aPiecek41680342023-11-08 10:19:44 +01002391LIBYANG_API_DEF LY_ERR
2392lyd_dup_meta_single(const struct lyd_meta *meta, struct lyd_node *node, struct lyd_meta **dup)
2393{
2394 LY_CHECK_ARG_RET(NULL, meta, LY_EINVAL);
2395
2396 /* log to node context but value must always use the annotation context */
2397 return lyd_dup_meta_single_to_ctx(meta->annotation->module->ctx, meta, node, dup);
2398}
2399
Michal Vasko4490d312020-06-16 13:08:55 +02002400/**
2401 * @brief Merge a source sibling into target siblings.
2402 *
2403 * @param[in,out] first_trg First target sibling, is updated if top-level.
2404 * @param[in] parent_trg Target parent.
aPiecek55653c92023-11-09 13:43:19 +01002405 * @param[in,out] sibling_src_p Source sibling to merge, set to NULL if spent.
Michal Vaskocd3f6172021-05-18 16:14:50 +02002406 * @param[in] merge_cb Optional merge callback.
2407 * @param[in] cb_data Arbitrary callback data.
Michal Vasko4490d312020-06-16 13:08:55 +02002408 * @param[in] options Merge options.
aPieceke6955f42024-01-19 14:01:54 +01002409 * @param[in] lyds Pool of lyds data which can be reused.
2410 * @param[in,out] leader_p Cached first instance of target (leaf-)list.
Michal Vaskocd3f6172021-05-18 16:14:50 +02002411 * @param[in,out] dup_inst Duplicate instance cache for all @p first_trg siblings.
Michal Vasko4490d312020-06-16 13:08:55 +02002412 * @return LY_ERR value.
2413 */
2414static LY_ERR
aPieceke6955f42024-01-19 14:01:54 +01002415lyd_merge_sibling_r(struct lyd_node **first_trg, struct lyd_node *parent_trg,
2416 const struct lyd_node **sibling_src_p, lyd_merge_cb merge_cb, void *cb_data, uint16_t options,
2417 struct lyds_pool *lyds, struct lyd_node **leader_p, struct ly_ht **dup_inst)
Michal Vasko4490d312020-06-16 13:08:55 +02002418{
Michal Vasko4490d312020-06-16 13:08:55 +02002419 const struct lyd_node *child_src, *tmp, *sibling_src;
aPieceke6955f42024-01-19 14:01:54 +01002420 struct lyd_node *match_trg, *dup_src, *elem, *leader;
Michal Vaskod1afa502022-01-27 16:18:12 +01002421 struct lyd_node_opaq *opaq_trg, *opaq_src;
Michal Vasko4490d312020-06-16 13:08:55 +02002422 struct lysc_type *type;
aPieceke6955f42024-01-19 14:01:54 +01002423 const struct lysc_node *schema;
Michal Vasko8efac242023-03-30 08:24:56 +02002424 struct ly_ht *child_dup_inst = NULL;
Michal Vasko42c96e22024-01-18 08:18:06 +01002425 LY_ERR r;
Michal Vaskocd3f6172021-05-18 16:14:50 +02002426 ly_bool first_inst = 0;
Michal Vasko4490d312020-06-16 13:08:55 +02002427
2428 sibling_src = *sibling_src_p;
Michal Vaskocd3f6172021-05-18 16:14:50 +02002429 if (!sibling_src->schema) {
2430 /* try to find the same opaque node */
Michal Vasko42c96e22024-01-18 08:18:06 +01002431 r = lyd_find_sibling_opaq_next(*first_trg, LYD_NAME(sibling_src), &match_trg);
Michal Vaskocd3f6172021-05-18 16:14:50 +02002432 } else if (sibling_src->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Michal Vasko4490d312020-06-16 13:08:55 +02002433 /* try to find the exact instance */
Michal Vasko42c96e22024-01-18 08:18:06 +01002434 r = lyd_find_sibling_first(*first_trg, sibling_src, &match_trg);
Michal Vasko4490d312020-06-16 13:08:55 +02002435 } else {
2436 /* try to simply find the node, there cannot be more instances */
Michal Vasko42c96e22024-01-18 08:18:06 +01002437 r = lyd_find_sibling_val(*first_trg, sibling_src->schema, NULL, 0, &match_trg);
Michal Vasko4490d312020-06-16 13:08:55 +02002438 }
Michal Vasko42c96e22024-01-18 08:18:06 +01002439 LY_CHECK_RET(r && (r != LY_ENOTFOUND), r);
Michal Vasko4490d312020-06-16 13:08:55 +02002440
Michal Vaskocd3f6172021-05-18 16:14:50 +02002441 if (match_trg) {
2442 /* update match as needed */
2443 LY_CHECK_RET(lyd_dup_inst_next(&match_trg, *first_trg, dup_inst));
2444 } else {
2445 /* first instance of this node */
2446 first_inst = 1;
2447 }
2448
2449 if (match_trg) {
2450 /* call callback */
2451 if (merge_cb) {
2452 LY_CHECK_RET(merge_cb(match_trg, sibling_src, cb_data));
2453 }
2454
Michal Vasko4490d312020-06-16 13:08:55 +02002455 /* node found, make sure even value matches for all node types */
Michal Vaskod1afa502022-01-27 16:18:12 +01002456 if (!match_trg->schema) {
2457 if (lyd_compare_single(sibling_src, match_trg, 0)) {
2458 /* update value */
2459 opaq_trg = (struct lyd_node_opaq *)match_trg;
2460 opaq_src = (struct lyd_node_opaq *)sibling_src;
2461
2462 lydict_remove(LYD_CTX(opaq_trg), opaq_trg->value);
2463 lydict_insert(LYD_CTX(opaq_trg), opaq_src->value, 0, &opaq_trg->value);
2464 opaq_trg->hints = opaq_src->hints;
2465
2466 ly_free_prefix_data(opaq_trg->format, opaq_trg->val_prefix_data);
2467 opaq_trg->format = opaq_src->format;
2468 ly_dup_prefix_data(LYD_CTX(opaq_trg), opaq_src->format, opaq_src->val_prefix_data,
2469 &opaq_trg->val_prefix_data);
2470 }
2471 } else if ((match_trg->schema->nodetype == LYS_LEAF) &&
2472 lyd_compare_single(sibling_src, match_trg, LYD_COMPARE_DEFAULTS)) {
Michal Vasko4490d312020-06-16 13:08:55 +02002473 /* since they are different, they cannot both be default */
2474 assert(!(sibling_src->flags & LYD_DEFAULT) || !(match_trg->flags & LYD_DEFAULT));
2475
Michal Vasko3a41dff2020-07-15 14:30:28 +02002476 /* update value (or only LYD_DEFAULT flag) only if flag set or the source node is not default */
2477 if ((options & LYD_MERGE_DEFAULTS) || !(sibling_src->flags & LYD_DEFAULT)) {
Michal Vasko4490d312020-06-16 13:08:55 +02002478 type = ((struct lysc_node_leaf *)match_trg->schema)->type;
Michal Vaskob7be7a82020-08-20 09:09:04 +02002479 type->plugin->free(LYD_CTX(match_trg), &((struct lyd_node_term *)match_trg)->value);
2480 LY_CHECK_RET(type->plugin->duplicate(LYD_CTX(match_trg), &((struct lyd_node_term *)sibling_src)->value,
Michal Vasko69730152020-10-09 16:30:07 +02002481 &((struct lyd_node_term *)match_trg)->value));
Michal Vasko4490d312020-06-16 13:08:55 +02002482
2483 /* copy flags and add LYD_NEW */
Michal Vasko7e8315b2021-08-03 17:01:06 +02002484 match_trg->flags = sibling_src->flags | ((options & LYD_MERGE_WITH_FLAGS) ? 0 : LYD_NEW);
Michal Vasko4490d312020-06-16 13:08:55 +02002485 }
Michal Vasko8f359bf2020-07-28 10:41:15 +02002486 } else if ((match_trg->schema->nodetype & LYS_ANYDATA) && lyd_compare_single(sibling_src, match_trg, 0)) {
Michal Vasko4c583e82020-07-17 12:16:14 +02002487 /* update value */
2488 LY_CHECK_RET(lyd_any_copy_value(match_trg, &((struct lyd_node_any *)sibling_src)->value,
Radek Krejci0f969882020-08-21 16:56:47 +02002489 ((struct lyd_node_any *)sibling_src)->value_type));
Michal Vasko4490d312020-06-16 13:08:55 +02002490
2491 /* copy flags and add LYD_NEW */
Michal Vasko7e8315b2021-08-03 17:01:06 +02002492 match_trg->flags = sibling_src->flags | ((options & LYD_MERGE_WITH_FLAGS) ? 0 : LYD_NEW);
Michal Vaskocd3f6172021-05-18 16:14:50 +02002493 }
2494
2495 /* check descendants, recursively */
Michal Vasko42c96e22024-01-18 08:18:06 +01002496 r = LY_SUCCESS;
aPieceke6955f42024-01-19 14:01:54 +01002497 leader = NULL;
2498 schema = NULL;
Michal Vaskocd3f6172021-05-18 16:14:50 +02002499 LY_LIST_FOR_SAFE(lyd_child_no_keys(sibling_src), tmp, child_src) {
aPieceke6955f42024-01-19 14:01:54 +01002500 if ((options & LYD_MERGE_DESTRUCT) && (schema != child_src->schema) && LYDS_NODE_IS_LEADER(child_src)) {
2501 schema = child_src->schema;
2502 /* unlink lyds data and add them to the pool */
2503 lyds_pool_add((struct lyd_node *)child_src, lyds);
2504 }
2505
2506 r = lyd_merge_sibling_r(lyd_node_child_p(match_trg), match_trg, &child_src,
2507 merge_cb, cb_data, options, lyds, &leader, &child_dup_inst);
Michal Vasko42c96e22024-01-18 08:18:06 +01002508 if (r) {
Michal Vaskocd3f6172021-05-18 16:14:50 +02002509 break;
Michal Vasko4490d312020-06-16 13:08:55 +02002510 }
2511 }
aPieceke6955f42024-01-19 14:01:54 +01002512
Michal Vaskocd3f6172021-05-18 16:14:50 +02002513 lyd_dup_inst_free(child_dup_inst);
Michal Vasko42c96e22024-01-18 08:18:06 +01002514 LY_CHECK_RET(r);
Michal Vasko4490d312020-06-16 13:08:55 +02002515 } else {
2516 /* node not found, merge it */
2517 if (options & LYD_MERGE_DESTRUCT) {
2518 dup_src = (struct lyd_node *)sibling_src;
aPieceke6955f42024-01-19 14:01:54 +01002519 lyd_unlink_ignore_lyds(dup_src);
Michal Vasko4490d312020-06-16 13:08:55 +02002520 /* spend it */
2521 *sibling_src_p = NULL;
2522 } else {
Michal Vasko3a41dff2020-07-15 14:30:28 +02002523 LY_CHECK_RET(lyd_dup_single(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS, &dup_src));
Michal Vasko4490d312020-06-16 13:08:55 +02002524 }
2525
Michal Vasko7e8315b2021-08-03 17:01:06 +02002526 if (!(options & LYD_MERGE_WITH_FLAGS)) {
2527 /* set LYD_NEW for all the new nodes, required for validation */
2528 LYD_TREE_DFS_BEGIN(dup_src, elem) {
2529 elem->flags |= LYD_NEW;
2530 LYD_TREE_DFS_END(dup_src, elem);
2531 }
Michal Vasko4490d312020-06-16 13:08:55 +02002532 }
2533
aPieceke6955f42024-01-19 14:01:54 +01002534 if (lyds->rbn) {
2535 /* insert node and try to reuse free lyds data */
2536 lyds_insert2(parent_trg, first_trg, leader_p, dup_src, lyds);
2537 } else {
2538 /* generic insert node */
2539 lyd_insert_node(parent_trg, first_trg, dup_src, 0);
2540 }
Michal Vaskocd3f6172021-05-18 16:14:50 +02002541
2542 if (first_inst) {
2543 /* remember not to find this instance next time */
2544 LY_CHECK_RET(lyd_dup_inst_next(&dup_src, *first_trg, dup_inst));
2545 }
2546
2547 /* call callback, no source node */
2548 if (merge_cb) {
2549 LY_CHECK_RET(merge_cb(dup_src, NULL, cb_data));
2550 }
Michal Vasko4490d312020-06-16 13:08:55 +02002551 }
2552
2553 return LY_SUCCESS;
2554}
2555
Michal Vasko3a41dff2020-07-15 14:30:28 +02002556static LY_ERR
Michal Vaskocd3f6172021-05-18 16:14:50 +02002557lyd_merge(struct lyd_node **target, const struct lyd_node *source, const struct lys_module *mod,
2558 lyd_merge_cb merge_cb, void *cb_data, uint16_t options, ly_bool nosiblings)
Michal Vasko4490d312020-06-16 13:08:55 +02002559{
2560 const struct lyd_node *sibling_src, *tmp;
aPieceke6955f42024-01-19 14:01:54 +01002561 const struct lysc_node *schema;
2562 struct lyd_node *leader;
Michal Vasko8efac242023-03-30 08:24:56 +02002563 struct ly_ht *dup_inst = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +02002564 ly_bool first;
Michal Vaskocd3f6172021-05-18 16:14:50 +02002565 LY_ERR ret = LY_SUCCESS;
aPieceke6955f42024-01-19 14:01:54 +01002566 struct lyds_pool lyds = {0};
Michal Vasko4490d312020-06-16 13:08:55 +02002567
2568 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01002569 LY_CHECK_CTX_EQUAL_RET(*target ? LYD_CTX(*target) : NULL, source ? LYD_CTX(source) : NULL, mod ? mod->ctx : NULL,
2570 LY_EINVAL);
Michal Vasko4490d312020-06-16 13:08:55 +02002571
2572 if (!source) {
2573 /* nothing to merge */
2574 return LY_SUCCESS;
2575 }
2576
Michal Vasko831422b2020-11-24 11:20:51 +01002577 if ((*target && lysc_data_parent((*target)->schema)) || lysc_data_parent(source->schema)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +02002578 LOGERR(LYD_CTX(source), LY_EINVAL, "Invalid arguments - can merge only 2 top-level subtrees (%s()).", __func__);
Michal Vasko4490d312020-06-16 13:08:55 +02002579 return LY_EINVAL;
2580 }
2581
aPieceke6955f42024-01-19 14:01:54 +01002582 leader = NULL;
2583 schema = NULL;
Michal Vasko4490d312020-06-16 13:08:55 +02002584 LY_LIST_FOR_SAFE(source, tmp, sibling_src) {
Michal Vaskocd3f6172021-05-18 16:14:50 +02002585 if (mod && (lyd_owner_module(sibling_src) != mod)) {
2586 /* skip data nodes from different modules */
2587 continue;
2588 }
2589
aPieceke6955f42024-01-19 14:01:54 +01002590 if ((options & LYD_MERGE_DESTRUCT) && (schema != sibling_src->schema) && LYDS_NODE_IS_LEADER(sibling_src)) {
2591 schema = sibling_src->schema;
2592 /* unlink lyds data and add them to the pool */
2593 lyds_pool_add((struct lyd_node *)sibling_src, &lyds);
2594 }
2595
Radek Krejci857189e2020-09-01 13:26:36 +02002596 first = (sibling_src == source) ? 1 : 0;
aPieceke6955f42024-01-19 14:01:54 +01002597 ret = lyd_merge_sibling_r(target, NULL, &sibling_src, merge_cb, cb_data, options,
2598 &lyds, &leader, &dup_inst);
Michal Vaskocd3f6172021-05-18 16:14:50 +02002599 if (ret) {
2600 break;
2601 }
Michal Vasko4490d312020-06-16 13:08:55 +02002602 if (first && !sibling_src) {
2603 /* source was spent (unlinked), move to the next node */
2604 source = tmp;
2605 }
2606
Michal Vasko3a41dff2020-07-15 14:30:28 +02002607 if (nosiblings) {
Michal Vasko4490d312020-06-16 13:08:55 +02002608 break;
2609 }
2610 }
aPieceke6955f42024-01-19 14:01:54 +01002611 lyds_pool_clean(&lyds);
Michal Vasko4490d312020-06-16 13:08:55 +02002612
2613 if (options & LYD_MERGE_DESTRUCT) {
2614 /* free any leftover source data that were not merged */
2615 lyd_free_siblings((struct lyd_node *)source);
2616 }
2617
Michal Vaskocd3f6172021-05-18 16:14:50 +02002618 lyd_dup_inst_free(dup_inst);
2619 return ret;
Michal Vasko4490d312020-06-16 13:08:55 +02002620}
2621
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002622LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02002623lyd_merge_tree(struct lyd_node **target, const struct lyd_node *source, uint16_t options)
Michal Vasko3a41dff2020-07-15 14:30:28 +02002624{
Michal Vaskocd3f6172021-05-18 16:14:50 +02002625 return lyd_merge(target, source, NULL, NULL, NULL, options, 1);
Michal Vasko3a41dff2020-07-15 14:30:28 +02002626}
2627
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002628LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02002629lyd_merge_siblings(struct lyd_node **target, const struct lyd_node *source, uint16_t options)
Michal Vasko3a41dff2020-07-15 14:30:28 +02002630{
Michal Vaskocd3f6172021-05-18 16:14:50 +02002631 return lyd_merge(target, source, NULL, NULL, NULL, options, 0);
2632}
2633
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002634LIBYANG_API_DEF LY_ERR
Michal Vaskocd3f6172021-05-18 16:14:50 +02002635lyd_merge_module(struct lyd_node **target, const struct lyd_node *source, const struct lys_module *mod,
2636 lyd_merge_cb merge_cb, void *cb_data, uint16_t options)
2637{
2638 return lyd_merge(target, source, mod, merge_cb, cb_data, options, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +02002639}
2640
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002641static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02002642lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, ly_bool is_static)
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002643{
Michal Vasko14654712020-02-06 08:35:21 +01002644 /* ending \0 */
2645 ++reqlen;
2646
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002647 if (reqlen > *buflen) {
2648 if (is_static) {
2649 return LY_EINCOMPLETE;
2650 }
2651
2652 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
2653 if (!*buffer) {
2654 return LY_EMEM;
2655 }
2656
2657 *buflen = reqlen;
2658 }
2659
2660 return LY_SUCCESS;
2661}
2662
Michal Vaskod59035b2020-07-08 12:00:06 +02002663LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02002664lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002665{
2666 const struct lyd_node *key;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002667 size_t len;
2668 const char *val;
2669 char quot;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002670
Michal Vasko824d0832021-11-04 15:36:51 +01002671 for (key = lyd_child(node); key && key->schema && (key->schema->flags & LYS_KEY); key = key->next) {
Radek Krejci6d5ba0c2021-04-26 07:49:59 +02002672 val = lyd_get_value(key);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002673 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002674 LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002675
2676 quot = '\'';
2677 if (strchr(val, '\'')) {
2678 quot = '"';
2679 }
2680 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002681 }
2682
2683 return LY_SUCCESS;
2684}
2685
2686/**
2687 * @brief Append leaf-list value predicate to path.
2688 *
2689 * @param[in] node Node to print.
2690 * @param[in,out] buffer Buffer to print to.
2691 * @param[in,out] buflen Current buffer length.
2692 * @param[in,out] bufused Current number of characters used in @p buffer.
2693 * @param[in] is_static Whether buffer is static or can be reallocated.
2694 * @return LY_ERR
2695 */
2696static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02002697lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002698{
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002699 size_t len;
2700 const char *val;
2701 char quot;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002702
Radek Krejci6d5ba0c2021-04-26 07:49:59 +02002703 val = lyd_get_value(node);
Radek Krejcif13b87b2020-12-01 22:02:17 +01002704 len = 4 + strlen(val) + 2; /* "[.='" + val + "']" */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002705 LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002706
2707 quot = '\'';
2708 if (strchr(val, '\'')) {
2709 quot = '"';
2710 }
2711 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
2712
Michal Vaskoba99a3e2020-08-18 15:50:05 +02002713 return LY_SUCCESS;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002714}
2715
2716/**
2717 * @brief Append node position (relative to its other instances) predicate to path.
2718 *
2719 * @param[in] node Node to print.
2720 * @param[in,out] buffer Buffer to print to.
2721 * @param[in,out] buflen Current buffer length.
2722 * @param[in,out] bufused Current number of characters used in @p buffer.
2723 * @param[in] is_static Whether buffer is static or can be reallocated.
2724 * @return LY_ERR
2725 */
2726static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02002727lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002728{
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002729 size_t len;
Michal Vasko50cc0562021-05-18 16:15:43 +02002730 uint32_t pos;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002731 char *val = NULL;
2732 LY_ERR rc;
2733
Michal Vasko50cc0562021-05-18 16:15:43 +02002734 pos = lyd_list_pos(node);
2735 if (asprintf(&val, "%" PRIu32, pos) == -1) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002736 return LY_EMEM;
2737 }
2738
2739 len = 1 + strlen(val) + 1;
2740 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2741 if (rc != LY_SUCCESS) {
2742 goto cleanup;
2743 }
2744
2745 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
2746
2747cleanup:
2748 free(val);
2749 return rc;
2750}
2751
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002752LIBYANG_API_DEF char *
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002753lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
2754{
Radek Krejci857189e2020-09-01 13:26:36 +02002755 ly_bool is_static = 0;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002756 uint32_t i, depth;
Michal Vasko14654712020-02-06 08:35:21 +01002757 size_t bufused = 0, len;
Michal Vasko12eb6222022-03-18 13:35:49 +01002758 const struct lyd_node *iter, *parent;
2759 const struct lys_module *mod, *prev_mod;
Michal Vasko790b2bc2020-08-03 13:35:06 +02002760 LY_ERR rc = LY_SUCCESS;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002761
2762 LY_CHECK_ARG_RET(NULL, node, NULL);
2763 if (buffer) {
Michal Vasko16385f42021-05-18 16:16:09 +02002764 LY_CHECK_ARG_RET(LYD_CTX(node), buflen > 1, NULL);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002765 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01002766 } else {
2767 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002768 }
2769
2770 switch (pathtype) {
Radek Krejci635d2b82021-01-04 11:26:51 +01002771 case LYD_PATH_STD:
2772 case LYD_PATH_STD_NO_LAST_PRED:
Michal Vasko14654712020-02-06 08:35:21 +01002773 depth = 1;
Michal Vasko9e685082021-01-29 14:49:09 +01002774 for (iter = node; iter->parent; iter = lyd_parent(iter)) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002775 ++depth;
2776 }
2777
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002778 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01002779 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002780 /* find the right node */
Michal Vasko9e685082021-01-29 14:49:09 +01002781 for (iter = node, i = 1; i < depth; iter = lyd_parent(iter), ++i) {}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002782iter_print:
Michal Vasko12eb6222022-03-18 13:35:49 +01002783 /* get the module */
Michal Vasko420cc252023-08-24 08:14:24 +02002784 mod = lyd_node_module(iter);
Michal Vasko12eb6222022-03-18 13:35:49 +01002785 parent = lyd_parent(iter);
Michal Vasko420cc252023-08-24 08:14:24 +02002786 prev_mod = lyd_node_module(parent);
Michal Vasko12eb6222022-03-18 13:35:49 +01002787 if (prev_mod == mod) {
2788 mod = NULL;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002789 }
2790
2791 /* realloc string */
Michal Vaskoad92b672020-11-12 13:11:31 +01002792 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + (iter->schema ? strlen(iter->schema->name) :
2793 strlen(((struct lyd_node_opaq *)iter)->name.name));
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002794 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
2795 if (rc != LY_SUCCESS) {
2796 break;
2797 }
2798
2799 /* print next node */
Michal Vaskodbf3e652022-10-21 08:46:25 +02002800 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", LYD_NAME(iter));
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002801
Michal Vasko790b2bc2020-08-03 13:35:06 +02002802 /* do not always print the last (first) predicate */
Radek Krejci635d2b82021-01-04 11:26:51 +01002803 if (iter->schema && ((depth > 1) || (pathtype == LYD_PATH_STD))) {
Michal Vasko790b2bc2020-08-03 13:35:06 +02002804 switch (iter->schema->nodetype) {
2805 case LYS_LIST:
2806 if (iter->schema->flags & LYS_KEYLESS) {
2807 /* print its position */
2808 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2809 } else {
2810 /* print all list keys in predicates */
2811 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
2812 }
2813 break;
2814 case LYS_LEAFLIST:
2815 if (iter->schema->flags & LYS_CONFIG_W) {
2816 /* print leaf-list value */
2817 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
2818 } else {
2819 /* print its position */
2820 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2821 }
2822 break;
2823 default:
2824 /* nothing to print more */
2825 break;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002826 }
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002827 }
2828 if (rc != LY_SUCCESS) {
2829 break;
2830 }
2831
Michal Vasko14654712020-02-06 08:35:21 +01002832 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002833 }
2834 break;
2835 }
2836
2837 return buffer;
2838}
Michal Vaskoe444f752020-02-10 12:20:06 +01002839
Michal Vaskodbf3e652022-10-21 08:46:25 +02002840char *
2841lyd_path_set(const struct ly_set *dnodes, LYD_PATH_TYPE pathtype)
2842{
2843 uint32_t depth;
2844 size_t bufused = 0, buflen = 0, len;
2845 char *buffer = NULL;
2846 const struct lyd_node *iter, *parent;
2847 const struct lys_module *mod, *prev_mod;
2848 LY_ERR rc = LY_SUCCESS;
2849
2850 switch (pathtype) {
2851 case LYD_PATH_STD:
2852 case LYD_PATH_STD_NO_LAST_PRED:
2853 for (depth = 1; depth <= dnodes->count; ++depth) {
2854 /* current node */
2855 iter = dnodes->dnodes[depth - 1];
Michal Vasko420cc252023-08-24 08:14:24 +02002856 mod = lyd_node_module(iter);
Michal Vaskodbf3e652022-10-21 08:46:25 +02002857
2858 /* parent */
2859 parent = (depth > 1) ? dnodes->dnodes[depth - 2] : NULL;
Michal Vasko85be65e2023-06-13 09:44:17 +02002860 assert(!parent || !iter->schema || !parent->schema || (parent->schema->nodetype & LYD_NODE_ANY) ||
2861 (lysc_data_parent(iter->schema) == parent->schema) ||
Michal Vasko539d6a92023-09-11 10:31:12 +02002862 (!lysc_data_parent(iter->schema) && (LYD_CTX(iter) != LYD_CTX(parent))) ||
2863 (parent->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)));
Michal Vaskodbf3e652022-10-21 08:46:25 +02002864
2865 /* get module to print, if any */
Michal Vasko420cc252023-08-24 08:14:24 +02002866 prev_mod = lyd_node_module(parent);
Michal Vaskodbf3e652022-10-21 08:46:25 +02002867 if (prev_mod == mod) {
2868 mod = NULL;
2869 }
2870
2871 /* realloc string */
2872 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + (iter->schema ? strlen(iter->schema->name) :
2873 strlen(((struct lyd_node_opaq *)iter)->name.name));
2874 if ((rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, 0))) {
2875 break;
2876 }
2877
2878 /* print next node */
2879 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", LYD_NAME(iter));
2880
2881 /* do not always print the last (first) predicate */
2882 if (iter->schema && ((depth > 1) || (pathtype == LYD_PATH_STD))) {
2883 switch (iter->schema->nodetype) {
2884 case LYS_LIST:
2885 if (iter->schema->flags & LYS_KEYLESS) {
2886 /* print its position */
2887 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, 0);
2888 } else {
2889 /* print all list keys in predicates */
2890 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, 0);
2891 }
2892 break;
2893 case LYS_LEAFLIST:
2894 if (iter->schema->flags & LYS_CONFIG_W) {
2895 /* print leaf-list value */
2896 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, 0);
2897 } else {
2898 /* print its position */
2899 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, 0);
2900 }
2901 break;
2902 default:
2903 /* nothing to print more */
2904 break;
2905 }
2906 }
2907 if (rc) {
2908 break;
2909 }
2910 }
2911 break;
2912 }
2913
2914 return buffer;
2915}
2916
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002917LIBYANG_API_DEF struct lyd_meta *
Michal Vasko25a32822020-07-09 15:48:22 +02002918lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module, const char *name)
2919{
2920 struct lyd_meta *ret = NULL;
2921 const struct ly_ctx *ctx;
2922 const char *prefix, *tmp;
2923 char *str;
2924 size_t pref_len, name_len;
2925
2926 LY_CHECK_ARG_RET(NULL, module || strchr(name, ':'), name, NULL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01002927 LY_CHECK_CTX_EQUAL_RET(first ? first->annotation->module->ctx : NULL, module ? module->ctx : NULL, NULL);
Michal Vasko25a32822020-07-09 15:48:22 +02002928
2929 if (!first) {
2930 return NULL;
2931 }
2932
2933 ctx = first->annotation->module->ctx;
2934
2935 /* parse the name */
2936 tmp = name;
2937 if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
2938 LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
2939 return NULL;
2940 }
2941
2942 /* find the module */
2943 if (prefix) {
2944 str = strndup(prefix, pref_len);
2945 module = ly_ctx_get_module_latest(ctx, str);
2946 free(str);
Radek Krejci422afb12021-03-04 16:38:16 +01002947 LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", (int)pref_len, prefix), NULL);
Michal Vasko25a32822020-07-09 15:48:22 +02002948 }
2949
2950 /* find the metadata */
2951 LY_LIST_FOR(first, first) {
2952 if ((first->annotation->module == module) && !strcmp(first->name, name)) {
2953 ret = (struct lyd_meta *)first;
2954 break;
2955 }
2956 }
2957
2958 return ret;
2959}
2960
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002961LIBYANG_API_DEF LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01002962lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
2963{
Michal Vasko9beceb82022-04-05 12:14:15 +02002964 struct lyd_node **match_p, *iter, *dup = NULL;
Michal Vaskoe444f752020-02-10 12:20:06 +01002965 struct lyd_node_inner *parent;
Michal Vaskoe78faec2021-04-08 17:24:43 +02002966 ly_bool found;
Michal Vaskoe444f752020-02-10 12:20:06 +01002967
Michal Vaskof03ed032020-03-04 13:31:44 +01002968 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
Michal Vasko9beceb82022-04-05 12:14:15 +02002969 if (!siblings) {
2970 /* no data */
2971 if (match) {
2972 *match = NULL;
2973 }
2974 return LY_ENOTFOUND;
2975 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002976
Michal Vasko9beceb82022-04-05 12:14:15 +02002977 if (LYD_CTX(siblings) != LYD_CTX(target)) {
2978 /* create a duplicate in this context */
2979 LY_CHECK_RET(lyd_dup_single_to_ctx(target, LYD_CTX(siblings), NULL, 0, &dup));
2980 target = dup;
2981 }
2982
2983 if ((siblings->schema && target->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema)))) {
2984 /* schema mismatch */
2985 lyd_free_tree(dup);
Michal Vasko9b368d32020-02-14 13:53:31 +01002986 if (match) {
2987 *match = NULL;
2988 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002989 return LY_ENOTFOUND;
2990 }
2991
Michal Vaskoe78faec2021-04-08 17:24:43 +02002992 /* get first sibling */
2993 siblings = lyd_first_sibling(siblings);
Michal Vaskoe444f752020-02-10 12:20:06 +01002994
Michal Vasko9e685082021-01-29 14:49:09 +01002995 parent = siblings->parent;
Michal Vasko39311152023-08-07 11:03:41 +02002996 if (target->schema && parent && parent->schema && parent->children_ht) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002997 assert(target->hash);
2998
Michal Vaskoe78faec2021-04-08 17:24:43 +02002999 if (lysc_is_dup_inst_list(target->schema)) {
3000 /* we must search the instances from beginning to find the first matching one */
3001 found = 0;
3002 LYD_LIST_FOR_INST(siblings, target->schema, iter) {
Michal Vaskoee9b9482023-06-19 13:17:48 +02003003 if (!lyd_compare_single(target, iter, LYD_COMPARE_FULL_RECURSION)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +02003004 found = 1;
3005 break;
3006 }
3007 }
3008 if (found) {
3009 siblings = iter;
Michal Vaskoda859032020-07-14 12:20:14 +02003010 } else {
3011 siblings = NULL;
3012 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003013 } else {
Michal Vaskoe78faec2021-04-08 17:24:43 +02003014 /* find by hash */
3015 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
3016 siblings = *match_p;
3017 } else {
3018 /* not found */
3019 siblings = NULL;
3020 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003021 }
3022 } else {
Michal Vasko39311152023-08-07 11:03:41 +02003023 /* no children hash table or cannot be used */
Michal Vaskod989ba02020-08-24 10:59:24 +02003024 for ( ; siblings; siblings = siblings->next) {
Michal Vaskoee9b9482023-06-19 13:17:48 +02003025 if (lysc_is_dup_inst_list(target->schema)) {
3026 if (!lyd_compare_single(siblings, target, LYD_COMPARE_FULL_RECURSION)) {
3027 break;
3028 }
3029 } else {
Michal Vaskod8a52012023-08-15 11:38:10 +02003030 if (!lyd_compare_single(siblings, target, 0)) {
Michal Vaskoee9b9482023-06-19 13:17:48 +02003031 break;
3032 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003033 }
3034 }
3035 }
3036
Michal Vasko9beceb82022-04-05 12:14:15 +02003037 lyd_free_tree(dup);
Michal Vaskoe444f752020-02-10 12:20:06 +01003038 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01003039 if (match) {
3040 *match = NULL;
3041 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003042 return LY_ENOTFOUND;
3043 }
3044
Michal Vasko9b368d32020-02-14 13:53:31 +01003045 if (match) {
3046 *match = (struct lyd_node *)siblings;
3047 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003048 return LY_SUCCESS;
3049}
3050
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003051LIBYANG_API_DEF LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01003052lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
Radek Krejci0f969882020-08-21 16:56:47 +02003053 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01003054{
3055 LY_ERR rc;
3056 struct lyd_node *target = NULL;
Michal Vasko9beceb82022-04-05 12:14:15 +02003057 const struct lyd_node *parent;
Michal Vaskoe444f752020-02-10 12:20:06 +01003058
Michal Vasko4c583e82020-07-17 12:16:14 +02003059 LY_CHECK_ARG_RET(NULL, schema, !(schema->nodetype & (LYS_CHOICE | LYS_CASE)), LY_EINVAL);
Michal Vasko9beceb82022-04-05 12:14:15 +02003060 if (!siblings) {
3061 /* no data */
3062 if (match) {
3063 *match = NULL;
3064 }
3065 return LY_ENOTFOUND;
3066 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003067
Michal Vasko9beceb82022-04-05 12:14:15 +02003068 if ((LYD_CTX(siblings) != schema->module->ctx)) {
3069 /* parent of ext nodes is useless */
3070 parent = (siblings->flags & LYD_EXT) ? NULL : lyd_parent(siblings);
Michal Vaskoaf3df492022-12-02 14:03:52 +01003071 if (lyd_find_schema_ctx(schema, LYD_CTX(siblings), parent, 0, &schema)) {
3072 /* no schema node in siblings so certainly no data node either */
3073 if (match) {
3074 *match = NULL;
3075 }
3076 return LY_ENOTFOUND;
3077 }
Michal Vasko9beceb82022-04-05 12:14:15 +02003078 }
3079
3080 if (siblings->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(schema))) {
3081 /* schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01003082 if (match) {
3083 *match = NULL;
3084 }
Michal Vaskoe444f752020-02-10 12:20:06 +01003085 return LY_ENOTFOUND;
3086 }
3087
Michal Vaskof03ed032020-03-04 13:31:44 +01003088 if (key_or_value && !val_len) {
3089 val_len = strlen(key_or_value);
3090 }
3091
Michal Vaskob104f112020-07-17 09:54:54 +02003092 if ((schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && key_or_value) {
3093 /* create a data node and find the instance */
3094 if (schema->nodetype == LYS_LEAFLIST) {
3095 /* target used attributes: schema, hash, value */
Michal Vasko989cdb42023-10-06 15:32:37 +02003096 rc = lyd_create_term(schema, key_or_value, val_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02003097 LY_CHECK_RET(rc);
Michal Vaskob104f112020-07-17 09:54:54 +02003098 } else {
Michal Vasko90932a92020-02-12 14:33:03 +01003099 /* target used attributes: schema, hash, child (all keys) */
Michal Vasko004d3152020-06-11 19:59:22 +02003100 LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01003101 }
3102
3103 /* find it */
3104 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskob104f112020-07-17 09:54:54 +02003105 } else {
3106 /* find the first schema node instance */
3107 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01003108 }
3109
Michal Vaskoe444f752020-02-10 12:20:06 +01003110 lyd_free_tree(target);
3111 return rc;
3112}
Michal Vaskoccc02342020-05-21 10:09:21 +02003113
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003114LIBYANG_API_DEF LY_ERR
Michal Vaskoe78faec2021-04-08 17:24:43 +02003115lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
3116{
3117 struct lyd_node **match_p, *first, *iter;
3118 struct lyd_node_inner *parent;
Michal Vaskoee9b9482023-06-19 13:17:48 +02003119 uint32_t comp_opts;
Michal Vaskoe78faec2021-04-08 17:24:43 +02003120
Michal Vasko83ae7772022-06-08 10:01:55 +02003121 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01003122 LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
Michal Vaskoe78faec2021-04-08 17:24:43 +02003123
3124 LY_CHECK_RET(ly_set_new(set));
3125
3126 if (!siblings || (siblings->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema)))) {
3127 /* no data or schema mismatch */
3128 return LY_ENOTFOUND;
3129 }
3130
Michal Vaskoee9b9482023-06-19 13:17:48 +02003131 /* set options */
Michal Vaskod8a52012023-08-15 11:38:10 +02003132 comp_opts = (lysc_is_dup_inst_list(target->schema) ? LYD_COMPARE_FULL_RECURSION : 0);
Michal Vaskoee9b9482023-06-19 13:17:48 +02003133
Michal Vaskoe78faec2021-04-08 17:24:43 +02003134 /* get first sibling */
3135 siblings = lyd_first_sibling(siblings);
3136
3137 parent = siblings->parent;
3138 if (parent && parent->schema && parent->children_ht) {
3139 assert(target->hash);
3140
3141 /* find the first instance */
3142 lyd_find_sibling_first(siblings, target, &first);
3143 if (first) {
3144 /* add it so that it is the first in the set */
3145 if (ly_set_add(*set, first, 1, NULL)) {
3146 goto error;
3147 }
3148
3149 /* find by hash */
3150 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
3151 iter = *match_p;
3152 } else {
3153 /* not found */
3154 iter = NULL;
3155 }
3156 while (iter) {
3157 /* add all found nodes into the set */
Michal Vaskoee9b9482023-06-19 13:17:48 +02003158 if ((iter != first) && !lyd_compare_single(iter, target, comp_opts) && ly_set_add(*set, iter, 1, NULL)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +02003159 goto error;
3160 }
3161
3162 /* find next instance */
3163 if (lyht_find_next(parent->children_ht, &iter, iter->hash, (void **)&match_p)) {
3164 iter = NULL;
3165 } else {
3166 iter = *match_p;
3167 }
3168 }
3169 }
3170 } else {
3171 /* no children hash table */
3172 LY_LIST_FOR(siblings, siblings) {
Michal Vaskoee9b9482023-06-19 13:17:48 +02003173 if (!lyd_compare_single(target, siblings, comp_opts)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +02003174 ly_set_add(*set, (void *)siblings, 1, NULL);
3175 }
3176 }
3177 }
3178
3179 if (!(*set)->count) {
3180 return LY_ENOTFOUND;
3181 }
3182 return LY_SUCCESS;
3183
3184error:
3185 ly_set_free(*set, NULL);
3186 *set = NULL;
3187 return LY_EMEM;
3188}
3189
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003190LIBYANG_API_DEF LY_ERR
Michal Vasko1d4af6c2021-02-22 13:31:26 +01003191lyd_find_sibling_opaq_next(const struct lyd_node *first, const char *name, struct lyd_node **match)
3192{
3193 LY_CHECK_ARG_RET(NULL, name, LY_EINVAL);
3194
Michal Vaskoe271a312023-08-15 11:46:30 +02003195 if (first && first->schema) {
3196 first = first->prev;
3197 if (first->schema) {
3198 /* no opaque nodes */
3199 first = NULL;
3200 } else {
3201 /* opaque nodes are at the end, find quickly the first */
3202 while (!first->prev->schema) {
3203 first = first->prev;
3204 }
3205 }
3206 }
3207
Michal Vasko1d4af6c2021-02-22 13:31:26 +01003208 for ( ; first; first = first->next) {
Michal Vaskoe271a312023-08-15 11:46:30 +02003209 assert(!first->schema);
3210 if (!strcmp(LYD_NAME(first), name)) {
Michal Vasko1d4af6c2021-02-22 13:31:26 +01003211 break;
3212 }
3213 }
3214
3215 if (match) {
3216 *match = (struct lyd_node *)first;
3217 }
3218 return first ? LY_SUCCESS : LY_ENOTFOUND;
3219}
3220
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003221LIBYANG_API_DEF LY_ERR
Michal Vaskod96e2372023-02-24 16:07:51 +01003222lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
Michal Vaskoccc02342020-05-21 10:09:21 +02003223{
Michal Vaskod96e2372023-02-24 16:07:51 +01003224 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
Michal Vaskoccc02342020-05-21 10:09:21 +02003225
Michal Vaskobe1b0cb2024-01-22 14:32:15 +01003226 return lyd_find_xpath3(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, NULL, set);
Michal Vaskod96e2372023-02-24 16:07:51 +01003227}
Michal Vaskoccc02342020-05-21 10:09:21 +02003228
Michal Vaskod96e2372023-02-24 16:07:51 +01003229LIBYANG_API_DEF LY_ERR
3230lyd_find_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, struct ly_set **set)
3231{
3232 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
Michal Vaskoccc02342020-05-21 10:09:21 +02003233
Michal Vaskobe1b0cb2024-01-22 14:32:15 +01003234 return lyd_find_xpath3(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, vars, set);
Michal Vaskoccc02342020-05-21 10:09:21 +02003235}
Radek Krejcica989142020-11-05 11:32:22 +01003236
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003237LIBYANG_API_DEF LY_ERR
Michal Vaskobe1b0cb2024-01-22 14:32:15 +01003238lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath, LY_VALUE_FORMAT format,
Michal Vaskod96e2372023-02-24 16:07:51 +01003239 void *prefix_data, const struct lyxp_var *vars, struct ly_set **set)
Michal Vaskoe3716b32021-12-13 16:58:25 +01003240{
Michal Vaskod96e2372023-02-24 16:07:51 +01003241 LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
Michal Vaskoe3716b32021-12-13 16:58:25 +01003242
Michal Vaskod96e2372023-02-24 16:07:51 +01003243 *set = NULL;
3244
3245 return lyd_eval_xpath4(ctx_node, tree, NULL, xpath, format, prefix_data, vars, NULL, set, NULL, NULL, NULL);
Michal Vaskoe3716b32021-12-13 16:58:25 +01003246}
3247
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003248LIBYANG_API_DEF LY_ERR
Michal Vaskod96e2372023-02-24 16:07:51 +01003249lyd_eval_xpath(const struct lyd_node *ctx_node, const char *xpath, ly_bool *result)
aPiecekfba75362021-10-07 12:39:48 +02003250{
Michal Vaskod96e2372023-02-24 16:07:51 +01003251 return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, NULL, result);
Michal Vaskoc9eb3ca2021-07-16 10:20:37 +02003252}
3253
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003254LIBYANG_API_DEF LY_ERR
Michal Vasko10fabfc2022-08-09 08:55:43 +02003255lyd_eval_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, ly_bool *result)
3256{
3257 return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, vars, result);
3258}
3259
3260LIBYANG_API_DEF LY_ERR
Michal Vaskod96e2372023-02-24 16:07:51 +01003261lyd_eval_xpath3(const struct lyd_node *ctx_node, const struct lys_module *cur_mod, const char *xpath,
3262 LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, ly_bool *result)
aPiecekfba75362021-10-07 12:39:48 +02003263{
Michal Vaskod96e2372023-02-24 16:07:51 +01003264 return lyd_eval_xpath4(ctx_node, ctx_node, cur_mod, xpath, format, prefix_data, vars, NULL, NULL, NULL, NULL, result);
3265}
3266
3267LIBYANG_API_DEF LY_ERR
3268lyd_eval_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const struct lys_module *cur_mod,
3269 const char *xpath, LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, LY_XPATH_TYPE *ret_type,
3270 struct ly_set **node_set, char **string, long double *number, ly_bool *boolean)
3271{
3272 LY_ERR ret = LY_SUCCESS;
3273 struct lyxp_set xp_set = {0};
3274 struct lyxp_expr *exp = NULL;
3275 uint32_t i;
3276
3277 LY_CHECK_ARG_RET(NULL, tree, xpath, ((ret_type && node_set && string && number && boolean) ||
3278 (node_set && !string && !number && !boolean) || (!node_set && string && !number && !boolean) ||
3279 (!node_set && !string && number && !boolean) || (!node_set && !string && !number && boolean)), LY_EINVAL);
3280
3281 /* parse expression */
3282 ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(tree), xpath, 0, 1, &exp);
3283 LY_CHECK_GOTO(ret, cleanup);
3284
3285 /* evaluate expression */
3286 ret = lyxp_eval(LYD_CTX(tree), exp, cur_mod, format, prefix_data, ctx_node, ctx_node, tree, vars, &xp_set,
3287 LYXP_IGNORE_WHEN);
3288 LY_CHECK_GOTO(ret, cleanup);
3289
3290 /* return expected result type without or with casting */
3291 if (node_set) {
3292 /* node set */
3293 if (xp_set.type == LYXP_SET_NODE_SET) {
3294 /* transform into a set */
3295 LY_CHECK_GOTO(ret = ly_set_new(node_set), cleanup);
3296 (*node_set)->objs = malloc(xp_set.used * sizeof *(*node_set)->objs);
3297 LY_CHECK_ERR_GOTO(!(*node_set)->objs, LOGMEM(LYD_CTX(tree)); ret = LY_EMEM, cleanup);
3298 (*node_set)->size = xp_set.used;
3299 for (i = 0; i < xp_set.used; ++i) {
3300 if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
3301 ret = ly_set_add(*node_set, xp_set.val.nodes[i].node, 1, NULL);
3302 LY_CHECK_GOTO(ret, cleanup);
3303 }
3304 }
3305 if (ret_type) {
3306 *ret_type = LY_XPATH_NODE_SET;
3307 }
3308 } else if (!string && !number && !boolean) {
3309 LOGERR(LYD_CTX(tree), LY_EINVAL, "XPath \"%s\" result is not a node set.", xpath);
3310 ret = LY_EINVAL;
3311 goto cleanup;
3312 }
3313 }
3314
3315 if (string) {
3316 if ((xp_set.type != LYXP_SET_STRING) && !node_set) {
3317 /* cast into string */
3318 LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_STRING), cleanup);
3319 }
3320 if (xp_set.type == LYXP_SET_STRING) {
3321 /* string */
3322 *string = xp_set.val.str;
3323 xp_set.val.str = NULL;
3324 if (ret_type) {
3325 *ret_type = LY_XPATH_STRING;
3326 }
3327 }
3328 }
3329
3330 if (number) {
3331 if ((xp_set.type != LYXP_SET_NUMBER) && !node_set) {
3332 /* cast into number */
3333 LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_NUMBER), cleanup);
3334 }
3335 if (xp_set.type == LYXP_SET_NUMBER) {
3336 /* number */
3337 *number = xp_set.val.num;
3338 if (ret_type) {
3339 *ret_type = LY_XPATH_NUMBER;
3340 }
3341 }
3342 }
3343
3344 if (boolean) {
3345 if ((xp_set.type != LYXP_SET_BOOLEAN) && !node_set) {
3346 /* cast into boolean */
3347 LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN), cleanup);
3348 }
3349 if (xp_set.type == LYXP_SET_BOOLEAN) {
3350 /* boolean */
3351 *boolean = xp_set.val.bln;
3352 if (ret_type) {
3353 *ret_type = LY_XPATH_BOOLEAN;
3354 }
3355 }
3356 }
3357
3358cleanup:
3359 lyxp_set_free_content(&xp_set);
3360 lyxp_expr_free((struct ly_ctx *)LYD_CTX(tree), exp);
3361 return ret;
aPiecekfba75362021-10-07 12:39:48 +02003362}
3363
Michal Vasko99a77882024-01-04 14:50:51 +01003364/**
3365 * @brief Hash table node equal callback.
3366 */
3367static ly_bool
3368lyd_trim_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
3369{
3370 struct lyd_node *node1, *node2;
3371
3372 node1 = *(struct lyd_node **)val1_p;
3373 node2 = *(struct lyd_node **)val2_p;
3374
3375 return node1 == node2;
3376}
3377
3378LIBYANG_API_DEF LY_ERR
3379lyd_trim_xpath(struct lyd_node **tree, const char *xpath, const struct lyxp_var *vars)
3380{
3381 LY_ERR ret = LY_SUCCESS;
Michal Vaskoea4943c2024-01-16 15:27:29 +01003382 struct ly_ctx *ctx = NULL;
Michal Vasko99a77882024-01-04 14:50:51 +01003383 struct lyxp_set xp_set = {0};
3384 struct lyxp_expr *exp = NULL;
3385 struct lyd_node *node, *parent;
3386 struct lyxp_set_hash_node hnode;
3387 struct ly_ht *parent_ht = NULL;
3388 struct ly_set free_set = {0};
3389 uint32_t i, hash;
3390 ly_bool is_result;
3391
3392 LY_CHECK_ARG_RET(NULL, tree, xpath, LY_EINVAL);
3393
3394 if (!*tree) {
3395 /* nothing to do */
3396 goto cleanup;
3397 }
3398
3399 *tree = lyd_first_sibling(*tree);
3400 ctx = (struct ly_ctx *)LYD_CTX(*tree);
3401
3402 /* parse expression */
3403 ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
3404 LY_CHECK_GOTO(ret, cleanup);
3405
3406 /* evaluate expression */
3407 ret = lyxp_eval(ctx, exp, NULL, LY_VALUE_JSON, NULL, *tree, *tree, *tree, vars, &xp_set, LYXP_IGNORE_WHEN);
3408 LY_CHECK_GOTO(ret, cleanup);
3409
3410 /* create hash table for all the parents of results */
Michal Vasko0a0716d2024-01-04 15:02:12 +01003411 parent_ht = lyht_new(32, sizeof node, lyd_trim_equal_cb, NULL, 1);
Michal Vasko99a77882024-01-04 14:50:51 +01003412 LY_CHECK_GOTO(!parent_ht, cleanup);
3413
3414 for (i = 0; i < xp_set.used; ++i) {
3415 if (xp_set.val.nodes[i].type != LYXP_NODE_ELEM) {
3416 /* ignore */
3417 continue;
3418 }
3419
3420 for (parent = lyd_parent(xp_set.val.nodes[i].node); parent; parent = lyd_parent(parent)) {
3421 /* add the parent into parent_ht */
3422 ret = lyht_insert(parent_ht, &parent, parent->hash, NULL);
3423 if (ret == LY_EEXIST) {
3424 /* shared parent, we are done */
3425 break;
3426 }
3427 LY_CHECK_GOTO(ret, cleanup);
3428 }
3429 }
3430
3431 hnode.type = LYXP_NODE_ELEM;
3432 LY_LIST_FOR(*tree, parent) {
3433 LYD_TREE_DFS_BEGIN(parent, node) {
3434 if (lysc_is_key(node->schema)) {
3435 /* ignore */
3436 goto next_iter;
3437 }
3438
3439 /* check the results */
3440 is_result = 0;
3441 if (xp_set.ht) {
3442 hnode.node = node;
3443 hash = lyht_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
3444 hash = lyht_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
3445 hash = lyht_hash_multi(hash, NULL, 0);
3446
3447 if (!lyht_find(xp_set.ht, &hnode, hash, NULL)) {
3448 is_result = 1;
3449 }
3450 } else {
3451 /* not enough elements for a hash table */
3452 for (i = 0; i < xp_set.used; ++i) {
3453 if (xp_set.val.nodes[i].type != LYXP_NODE_ELEM) {
3454 /* ignore */
3455 continue;
3456 }
3457
3458 if (xp_set.val.nodes[i].node == node) {
3459 is_result = 1;
3460 break;
3461 }
3462 }
3463 }
3464
3465 if (is_result) {
3466 /* keep the whole subtree if the node is in the results */
3467 LYD_TREE_DFS_continue = 1;
3468 } else if (lyht_find(parent_ht, &node, node->hash, NULL)) {
3469 /* free the whole subtree if the node is not even among the selected parents */
3470 ret = ly_set_add(&free_set, node, 1, NULL);
3471 LY_CHECK_GOTO(ret, cleanup);
3472 LYD_TREE_DFS_continue = 1;
3473 } /* else keep the parent node because a subtree is in the results */
3474
3475next_iter:
3476 LYD_TREE_DFS_END(parent, node);
3477 }
3478 }
3479
3480 /* free */
3481 for (i = 0; i < free_set.count; ++i) {
3482 node = free_set.dnodes[i];
3483 if (*tree == node) {
3484 *tree = (*tree)->next;
3485 }
3486 lyd_free_tree(node);
3487 }
3488
3489cleanup:
3490 lyxp_set_free_content(&xp_set);
3491 lyxp_expr_free(ctx, exp);
3492 lyht_free(parent_ht, NULL);
3493 ly_set_erase(&free_set, NULL);
3494 return ret;
3495}
3496
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003497LIBYANG_API_DEF LY_ERR
Michal Vasko3e1f6552021-01-14 09:27:55 +01003498lyd_find_path(const struct lyd_node *ctx_node, const char *path, ly_bool output, struct lyd_node **match)
3499{
3500 LY_ERR ret = LY_SUCCESS;
3501 struct lyxp_expr *expr = NULL;
3502 struct ly_path *lypath = NULL;
3503
3504 LY_CHECK_ARG_RET(NULL, ctx_node, ctx_node->schema, path, LY_EINVAL);
3505
3506 /* parse the path */
Michal Vaskoed725d72021-06-23 12:03:45 +02003507 ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, strlen(path), 0, LY_PATH_BEGIN_EITHER,
Michal Vasko32ca49b2023-02-17 15:11:35 +01003508 LY_PATH_PREFIX_FIRST, LY_PATH_PRED_SIMPLE, &expr);
Michal Vasko3e1f6552021-01-14 09:27:55 +01003509 LY_CHECK_GOTO(ret, cleanup);
3510
3511 /* compile the path */
Michal Vaskoed725d72021-06-23 12:03:45 +02003512 ret = ly_path_compile(LYD_CTX(ctx_node), NULL, ctx_node->schema, NULL, expr,
Michal Vasko0884d212021-10-14 09:21:46 +02003513 output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, 0, LY_VALUE_JSON, NULL, &lypath);
Michal Vasko3e1f6552021-01-14 09:27:55 +01003514 LY_CHECK_GOTO(ret, cleanup);
3515
3516 /* evaluate the path */
Michal Vasko838829d2023-10-09 16:06:43 +02003517 ret = ly_path_eval_partial(lypath, ctx_node, NULL, 0, NULL, match);
Michal Vasko3e1f6552021-01-14 09:27:55 +01003518
3519cleanup:
3520 lyxp_expr_free(LYD_CTX(ctx_node), expr);
3521 ly_path_free(LYD_CTX(ctx_node), lypath);
3522 return ret;
3523}
3524
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01003525LIBYANG_API_DEF LY_ERR
Michal Vaskobb22b182021-06-14 08:14:21 +02003526lyd_find_target(const struct ly_path *path, const struct lyd_node *tree, struct lyd_node **match)
3527{
3528 LY_ERR ret;
3529 struct lyd_node *m;
3530
3531 LY_CHECK_ARG_RET(NULL, path, LY_EINVAL);
3532
Michal Vasko90189962023-02-28 12:10:34 +01003533 ret = ly_path_eval(path, tree, NULL, &m);
Michal Vaskobb22b182021-06-14 08:14:21 +02003534 if (ret) {
3535 if (match) {
3536 *match = NULL;
3537 }
3538 return LY_ENOTFOUND;
3539 }
3540
3541 if (match) {
3542 *match = m;
3543 }
3544 return LY_SUCCESS;
3545}
Irfand3b351a2023-09-14 14:52:15 +02003546
stewegf9041a22024-01-18 13:29:12 +01003547LY_ERR
3548lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct lyd_leafref_links_rec **record, ly_bool create)
3549{
3550 struct ly_ht *ht;
3551 uint32_t hash;
Michal Vaskob46061d2024-01-18 13:58:13 +01003552 struct lyd_leafref_links_rec rec = {0};
stewegf9041a22024-01-18 13:29:12 +01003553
3554 assert(node);
3555 assert(record);
3556
Michal Vaskob46061d2024-01-18 13:58:13 +01003557 *record = NULL;
3558
stewegf9041a22024-01-18 13:29:12 +01003559 if (!(ly_ctx_get_options(LYD_CTX(node)) & LY_CTX_LEAFREF_LINKING)) {
stewegf9041a22024-01-18 13:29:12 +01003560 return LY_EDENIED;
3561 }
3562
3563 rec.node = node;
stewegf9041a22024-01-18 13:29:12 +01003564 ht = LYD_CTX(node)->leafref_links_ht;
Michal Vasko67bf5872024-01-18 13:58:25 +01003565 hash = lyht_hash((const char *)&node, sizeof node);
3566
stewegf9041a22024-01-18 13:29:12 +01003567 if (lyht_find(ht, &rec, hash, (void **)record) == LY_ENOTFOUND) {
3568 if (create) {
3569 LY_CHECK_RET(lyht_insert_no_check(ht, &rec, hash, (void **)record));
3570 } else {
stewegf9041a22024-01-18 13:29:12 +01003571 return LY_ENOTFOUND;
3572 }
3573 }
3574
3575 return LY_SUCCESS;
3576}
3577
3578LIBYANG_API_DEF LY_ERR
3579lyd_leafref_get_links(const struct lyd_node_term *node, const struct lyd_leafref_links_rec **record)
3580{
3581 LY_CHECK_ARG_RET(NULL, node, record, LY_EINVAL);
3582
3583 return lyd_get_or_create_leafref_links_record(node, (struct lyd_leafref_links_rec **)record, 0);
3584}
3585
3586LY_ERR
3587lyd_link_leafref_node(const struct lyd_node_term *node, const struct lyd_node_term *leafref_node)
3588{
stewegf9041a22024-01-18 13:29:12 +01003589 const struct lyd_node_term **item = NULL;
3590 struct lyd_leafref_links_rec *rec;
steweg67388952024-01-25 12:14:50 +01003591 LY_ARRAY_COUNT_TYPE u;
stewegf9041a22024-01-18 13:29:12 +01003592
3593 assert(node);
3594 assert(leafref_node);
3595
3596 if (!(ly_ctx_get_options(LYD_CTX(node)) & LY_CTX_LEAFREF_LINKING)) {
3597 return LY_EDENIED;
3598 }
3599
steweg67388952024-01-25 12:14:50 +01003600 /* add leafref node into the list of target node */
stewegf9041a22024-01-18 13:29:12 +01003601 LY_CHECK_RET(lyd_get_or_create_leafref_links_record(node, &rec, 1));
3602 LY_ARRAY_FOR(rec->leafref_nodes, u) {
3603 if (rec->leafref_nodes[u] == leafref_node) {
3604 return LY_SUCCESS;
3605 }
3606 }
3607
3608 LY_ARRAY_NEW_RET(LYD_CTX(node), rec->leafref_nodes, item, LY_EMEM);
3609 *item = leafref_node;
steweg67388952024-01-25 12:14:50 +01003610
3611 /* add target node into the list of leafref node*/
stewegf9041a22024-01-18 13:29:12 +01003612 LY_CHECK_RET(lyd_get_or_create_leafref_links_record(leafref_node, &rec, 1));
steweg67388952024-01-25 12:14:50 +01003613 LY_ARRAY_FOR(rec->target_nodes, u) {
3614 if (rec->target_nodes[u] == node) {
3615 return LY_SUCCESS;
3616 }
3617 }
3618
3619 LY_ARRAY_NEW_RET(LYD_CTX(node), rec->target_nodes, item, LY_EMEM);
3620 *item = node;
3621
stewegf9041a22024-01-18 13:29:12 +01003622 return LY_SUCCESS;
3623}
3624
3625LIBYANG_API_DEF LY_ERR
3626lyd_leafref_link_node_tree(const struct lyd_node *tree)
3627{
3628 const struct lyd_node *sibling, *elem;
steweg67388952024-01-25 12:14:50 +01003629 struct ly_set *targets = NULL;
stewegf9041a22024-01-18 13:29:12 +01003630 char *errmsg;
3631 struct lyd_node_term *leafref_node;
3632 struct lysc_node_leaf *leaf_schema;
3633 struct lysc_type_leafref *lref;
steweg67388952024-01-25 12:14:50 +01003634 LY_ERR ret = LY_SUCCESS;
3635 uint32_t i;
stewegf9041a22024-01-18 13:29:12 +01003636
3637 LY_CHECK_ARG_RET(NULL, tree, LY_EINVAL);
3638
3639 if (!(ly_ctx_get_options(LYD_CTX(tree)) & LY_CTX_LEAFREF_LINKING)) {
3640 return LY_EDENIED;
3641 }
3642
3643 LY_LIST_FOR(tree, sibling) {
3644 LYD_TREE_DFS_BEGIN(sibling, elem) {
steweg0e1e5092024-02-12 09:06:04 +01003645 if (elem->schema && (elem->schema->nodetype & LYD_NODE_TERM)) {
stewegf9041a22024-01-18 13:29:12 +01003646 leafref_node = (struct lyd_node_term *)elem;
3647 leaf_schema = (struct lysc_node_leaf *)elem->schema;
Michal Vaskob46061d2024-01-18 13:58:13 +01003648
stewegf9041a22024-01-18 13:29:12 +01003649 if (leaf_schema->type->basetype == LY_TYPE_LEAFREF) {
3650 lref = (struct lysc_type_leafref *)leaf_schema->type;
steweg67388952024-01-25 12:14:50 +01003651 ly_set_free(targets, NULL);
3652 if (lyplg_type_resolve_leafref(lref, elem, &leafref_node->value, tree, &targets, &errmsg)) {
Michal Vaskob46061d2024-01-18 13:58:13 +01003653 /* leafref target not found */
stewegf9041a22024-01-18 13:29:12 +01003654 free(errmsg);
Michal Vaskob46061d2024-01-18 13:58:13 +01003655 } else {
3656 /* leafref target found, link it */
steweg67388952024-01-25 12:14:50 +01003657 for (i = 0; i < targets->count; ++i) {
3658 if (targets->dnodes[i]->schema->nodetype & LYD_NODE_TERM) {
3659 ret = lyd_link_leafref_node((struct lyd_node_term *)targets->dnodes[i], leafref_node);
3660 LY_CHECK_GOTO(ret, cleanup);
3661 }
3662 }
stewegf9041a22024-01-18 13:29:12 +01003663 }
3664 }
3665 }
3666 LYD_TREE_DFS_END(sibling, elem);
3667 }
3668 }
Michal Vaskob46061d2024-01-18 13:58:13 +01003669
steweg67388952024-01-25 12:14:50 +01003670cleanup:
3671 ly_set_free(targets, NULL);
3672 return ret;
stewegf9041a22024-01-18 13:29:12 +01003673}
3674
3675LY_ERR
3676lyd_unlink_leafref_node(const struct lyd_node_term *node, const struct lyd_node_term *leafref_node)
3677{
3678 LY_ERR ret;
3679 struct lyd_leafref_links_rec *rec;
3680
3681 assert(node);
3682 assert(leafref_node);
3683
3684 if (!(ly_ctx_get_options(LYD_CTX(node)) & LY_CTX_LEAFREF_LINKING)) {
3685 return LY_EDENIED;
3686 }
3687
steweg67388952024-01-25 12:14:50 +01003688 /* remove link from target node to leafref node */
stewegf9041a22024-01-18 13:29:12 +01003689 ret = lyd_get_or_create_leafref_links_record(node, &rec, 0);
3690 if (ret == LY_SUCCESS) {
3691 LY_ARRAY_REMOVE_VALUE(rec->leafref_nodes, leafref_node);
steweg67388952024-01-25 12:14:50 +01003692 if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec->target_nodes) == 0)) {
stewegf9041a22024-01-18 13:29:12 +01003693 lyd_free_leafref_nodes(node);
3694 }
3695 } else if (ret != LY_ENOTFOUND) {
3696 return ret;
3697 }
3698
steweg67388952024-01-25 12:14:50 +01003699 /* remove link from leafref node to target node */
stewegf9041a22024-01-18 13:29:12 +01003700 ret = lyd_get_or_create_leafref_links_record(leafref_node, &rec, 0);
3701 if (ret == LY_SUCCESS) {
steweg67388952024-01-25 12:14:50 +01003702 LY_ARRAY_REMOVE_VALUE(rec->target_nodes, node);
3703 if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec->target_nodes) == 0)) {
stewegf9041a22024-01-18 13:29:12 +01003704 lyd_free_leafref_nodes(leafref_node);
3705 }
3706 } else if (ret != LY_ENOTFOUND) {
3707 return ret;
3708 }
3709
3710 return LY_SUCCESS;
3711}