Coverage Report

Created: 2026-07-16 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/tree_data.c
Line
Count
Source
1
/**
2
 * @file tree_data.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @author Michal Vasko <mvasko@cesnet.cz>
5
 * @brief Data tree functions
6
 *
7
 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
8
 *
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
16
#define _GNU_SOURCE
17
18
#include "tree_data.h"
19
20
#include <assert.h>
21
#include <ctype.h>
22
#include <inttypes.h>
23
#include <stdarg.h>
24
#include <stdint.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include "compat.h"
30
#include "context.h"
31
#include "dict.h"
32
#include "diff.h"
33
#include "hash_table.h"
34
#include "in.h"
35
#include "in_internal.h"
36
#include "log.h"
37
#include "ly_common.h"
38
#include "parser_data.h"
39
#include "parser_internal.h"
40
#include "path.h"
41
#include "plugins.h"
42
#include "plugins_exts/metadata.h"
43
#include "plugins_internal.h"
44
#include "plugins_types.h"
45
#include "set.h"
46
#include "tree.h"
47
#include "tree_data_internal.h"
48
#include "tree_data_sorted.h"
49
#include "tree_edit.h"
50
#include "tree_schema.h"
51
#include "tree_schema_internal.h"
52
#include "validation.h"
53
#include "xml.h"
54
#include "xpath.h"
55
56
static int lyd_insert_has_keys(const struct lyd_node *list);
57
58
static LY_ERR lyd_compare_siblings_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
59
        ly_bool parental_schemas_checked);
60
61
static LYD_FORMAT
62
lyd_parse_get_format(const struct ly_in *in, LYD_FORMAT format)
63
0
{
64
0
    if (!format && (in->type == LY_IN_FILEPATH)) {
65
        /* unknown format - try to detect it from filename's suffix */
66
0
        const char *path = in->method.fpath.filepath;
67
0
        size_t len = strlen(path);
68
69
        /* ignore trailing whitespaces */
70
0
        for ( ; len > 0 && isspace(path[len - 1]); len--) {}
71
72
0
        if ((len >= LY_XML_SUFFIX_LEN + 1) &&
73
0
                !strncmp(&path[len - LY_XML_SUFFIX_LEN], LY_XML_SUFFIX, LY_XML_SUFFIX_LEN)) {
74
0
            format = LYD_XML;
75
0
        } else if ((len >= LY_JSON_SUFFIX_LEN + 1) &&
76
0
                !strncmp(&path[len - LY_JSON_SUFFIX_LEN], LY_JSON_SUFFIX, LY_JSON_SUFFIX_LEN)) {
77
0
            format = LYD_JSON;
78
0
        } else if ((len >= LY_LYB_SUFFIX_LEN + 1) &&
79
0
                !strncmp(&path[len - LY_LYB_SUFFIX_LEN], LY_LYB_SUFFIX, LY_LYB_SUFFIX_LEN)) {
80
0
            format = LYD_LYB;
81
0
        } else if ((len >= LY_CBOR_SUFFIX_LEN + 1) &&
82
0
                !strncmp(&path[len - LY_CBOR_SUFFIX_LEN], LY_CBOR_SUFFIX, LY_CBOR_SUFFIX_LEN)) {
83
0
            format = LYD_CBOR;
84
0
        } /* else still unknown */
85
0
    }
86
87
0
    return format;
88
0
}
89
90
/**
91
 * @brief Parse YANG data into a data tree.
92
 *
93
 * @param[in] ctx libyang context.
94
 * @param[in] parent Parent to connect the parsed nodes to, if any.
95
 * @param[in,out] first_p Pointer to the first parsed node.
96
 * @param[in] in Input handle to read the input from.
97
 * @param[in] format Expected format of the data in @p in.
98
 * @param[in] parse_opts Options for parser.
99
 * @param[in] val_opts Options for validation.
100
 * @param[out] op Optional pointer to the parsed operation, if any.
101
 * @return LY_ERR value.
102
 */
103
static LY_ERR
104
lyd_parse(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
105
        LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
106
0
{
107
0
    LY_ERR r = LY_SUCCESS, rc = LY_SUCCESS;
108
0
    struct lyd_ctx *lydctx = NULL;
109
0
    struct ly_set parsed = {0};
110
0
    uint32_t i, int_opts = 0;
111
0
    const struct ly_err_item *eitem;
112
113
0
    assert(ctx && (parent || first_p));
114
115
0
    format = lyd_parse_get_format(in, format);
116
0
    if (first_p) {
117
0
        *first_p = NULL;
118
0
    }
119
120
    /* remember input position */
121
0
    in->func_start = in->current;
122
123
    /* set internal options */
124
0
    int_opts = LYD_INTOPT_WITH_SIBLINGS;
125
126
    /* parse the data */
127
0
    switch (format) {
128
0
    case LYD_XML:
129
0
        r = lyd_parse_xml(ctx, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed, &lydctx);
130
0
        break;
131
0
    case LYD_JSON:
132
0
        r = lyd_parse_json(ctx, parent, NULL, first_p, in, parse_opts, val_opts, int_opts, &parsed, &lydctx);
133
0
        break;
134
0
    case LYD_LYB:
135
0
        r = lyd_parse_lyb(ctx, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed, &lydctx);
136
0
        break;
137
#ifdef ENABLE_CBOR_SUPPORT
138
    case LYD_CBOR:
139
        r = lyd_parse_cbor(ctx, NULL, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
140
        break;
141
#else
142
0
    case LYD_CBOR:
143
0
        LOGARG(ctx, format);
144
0
        r = LY_EINVAL;
145
0
        break;
146
0
#endif /* ENABLE_CBOR_SUPPORT */
147
0
    case LYD_UNKNOWN:
148
0
        LOGARG(ctx, format);
149
0
        r = LY_EINVAL;
150
0
        break;
151
0
    }
152
0
    if (r) {
153
0
        rc = r;
154
0
        if ((r != LY_EVALID) || !lydctx || !(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR)) {
155
0
            goto cleanup;
156
0
        }
157
158
0
        eitem = ly_err_last(ctx);
159
0
        assert(eitem);
160
0
        if (eitem->vecode == LYVE_SYNTAX) {
161
            /* cannot get more errors on a syntax error */
162
0
            goto cleanup;
163
0
        }
164
0
    }
165
166
0
    if (parent && parsed.count) {
167
        /* use the first parsed node */
168
0
        if (first_p) {
169
0
            *first_p = parsed.dnodes[0];
170
0
        } else {
171
0
            first_p = &parsed.dnodes[0];
172
0
        }
173
0
    }
174
175
0
    if (!(parse_opts & LYD_PARSE_ONLY)) {
176
        /* validate data */
177
0
        r = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
178
0
                &lydctx->ext_val, NULL);
179
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
180
0
    }
181
182
    /* set the operation node */
183
0
    if (op) {
184
0
        *op = lydctx->op_node;
185
0
    }
186
187
0
cleanup:
188
0
    if (lydctx) {
189
0
        lydctx->free(lydctx);
190
0
    }
191
0
    if (rc) {
192
0
        if (parent) {
193
            /* free all the parsed subtrees */
194
0
            for (i = 0; i < parsed.count; ++i) {
195
0
                lyd_free_tree(parsed.dnodes[i]);
196
0
            }
197
0
        } else {
198
            /* free everything */
199
0
            lyd_free_all(*first_p);
200
0
            *first_p = NULL;
201
0
        }
202
0
    }
203
0
    ly_set_erase(&parsed, NULL);
204
0
    return rc;
205
0
}
206
207
LIBYANG_API_DEF LY_ERR
208
lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
209
        uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
210
0
{
211
0
    LY_CHECK_ARG_RET(ctx, ctx || parent, in, parent || tree, LY_EINVAL);
212
0
    LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
213
0
    LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
214
215
0
    if (!ctx) {
216
0
        ctx = LYD_CTX(parent);
217
0
    }
218
219
0
    return lyd_parse(ctx, parent, tree, in, format, parse_options, validate_options, NULL);
220
0
}
221
222
LIBYANG_API_DEF LY_ERR
223
lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, size_t data_len, LYD_FORMAT format,
224
        uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
225
0
{
226
0
    LY_ERR ret;
227
0
    struct ly_in *in;
228
229
0
    LY_CHECK_RET(ly_in_new_memory(data, &in));
230
0
    in->length = data_len;  // Set the length for the input
231
232
0
    ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
233
234
0
    ly_in_free(in, 0);
235
0
    return ret;
236
0
}
237
238
LIBYANG_API_DEF LY_ERR
239
lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, uint32_t parse_options,
240
        uint32_t validate_options, struct lyd_node **tree)
241
0
{
242
0
    LY_ERR ret;
243
0
    struct ly_in *in;
244
245
0
    LY_CHECK_RET(ly_in_new_memory(data, &in));
246
0
    ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
247
248
0
    ly_in_free(in, 0);
249
0
    return ret;
250
0
}
251
252
LIBYANG_API_DEF LY_ERR
253
lyd_parse_data_fd(const struct ly_ctx *ctx, int fd, LYD_FORMAT format, uint32_t parse_options, uint32_t validate_options,
254
        struct lyd_node **tree)
255
0
{
256
0
    LY_ERR ret;
257
0
    struct ly_in *in;
258
259
0
    LY_CHECK_RET(ly_in_new_fd(fd, &in));
260
0
    ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
261
262
0
    ly_in_free(in, 0);
263
0
    return ret;
264
0
}
265
266
LIBYANG_API_DEF LY_ERR
267
lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, uint32_t parse_options,
268
        uint32_t validate_options, struct lyd_node **tree)
269
0
{
270
0
    LY_ERR ret;
271
0
    struct ly_in *in;
272
273
0
    LY_CHECK_RET(ly_in_new_filepath(path, 0, &in));
274
0
    ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);
275
276
0
    ly_in_free(in, 0);
277
0
    return ret;
278
0
}
279
280
LIBYANG_API_DEF LY_ERR
281
lyd_parse_value_fragment(const struct ly_ctx *ctx, const char *path, struct ly_in *in, LYD_FORMAT format,
282
        uint32_t new_val_options, uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
283
0
{
284
0
    LY_ERR ret = LY_SUCCESS;
285
0
    struct lyxp_expr *exp = NULL;
286
0
    struct ly_path *p = NULL;
287
0
    struct lyd_node *new_last_parent = NULL, *new_top_parent = NULL;
288
0
    const struct lysc_node *new_node_schema = NULL;
289
0
    ly_bool p_decremented = 0;
290
0
    struct lyd_node *iter = NULL, *parent = NULL;
291
0
    const char *key_value = NULL;
292
0
    const char *path_key_value = NULL;
293
294
0
    LY_CHECK_ARG_RET(ctx, ctx, path && (path[0] == '/'), LY_EINVAL);
295
296
    /* other formats are not supported for now */
297
0
    if (format != LYD_JSON) {
298
0
        LOGARG(ctx, "invalid format (only JSON supported)");
299
0
        return LY_EINVAL;
300
0
    }
301
302
    /* parse path */
303
0
    LY_CHECK_GOTO(ret = ly_path_parse(ctx, NULL, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
304
0
            LY_PATH_PRED_SIMPLE, &exp), cleanup);
305
306
    /* compile path */
307
0
    LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, exp, new_val_options & LYD_NEW_VAL_OUTPUT ?
308
0
            LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p), cleanup);
309
310
    /* has to have a schema */
311
0
    new_node_schema = p[LY_ARRAY_COUNT(p) - 1].node;
312
313
    /* only the term nodes get their path shortened */
314
0
    if (new_node_schema->nodetype & LYD_NODE_TERM) {
315
        /* shorten the ly_path by one element (to avoid a leaflist without predicate at the end) */
316
0
        LY_ARRAY_DECREMENT(p);
317
0
        p_decremented = 1;
318
0
    }
319
320
0
    if (LY_ARRAY_COUNT(p)) {
321
        /* create nodes */
322
0
        LY_CHECK_GOTO(ret = lyd_new_path_create(NULL, ctx, p, path, NULL, 0, 0, new_val_options, &new_top_parent,
323
0
                &new_last_parent), cleanup);
324
0
    }
325
326
    /* parse the json value */
327
0
    LY_CHECK_GOTO(ret = lyd_parse_json(ctx, new_last_parent, new_node_schema, new_last_parent ? NULL : &new_top_parent,
328
0
            in, parse_options, validate_options, 0, NULL, NULL), cleanup);
329
330
    /* when setting keys they have to have a correct value (same as in the path) */
331
0
    if (lysc_is_key(new_node_schema)) {
332
0
        LY_LIST_FOR(lyd_child(new_last_parent), iter) {
333
            /* look for the same schema as is in the path */
334
0
            if (!strcmp(iter->schema->name, new_node_schema->name)) {
335
0
                key_value = lyd_get_value(iter);
336
0
                if (!path_key_value) {
337
0
                    path_key_value = key_value;
338
0
                } else {
339
0
                    if (strcmp(key_value, path_key_value)) {
340
0
                        LOGVAL(ctx, NULL, LYVE_DATA, "Path [%s] contains a different key [%s] than data [%s]", path,
341
0
                                path_key_value, key_value);
342
0
                        ret = LY_EINVAL;
343
0
                        goto cleanup;
344
0
                    }
345
346
                    /* when unlinking duplicate key we need to recalculate the list hash,
347
                       so store the list (parent) and recalculate the hash after unlinking the duplicate key */
348
0
                    parent = iter->parent;
349
0
                    assert(parent);
350
351
0
                    lyd_unlink(iter);
352
0
                    lyd_free_tree(iter);
353
354
0
                    lyd_unlink_hash(parent);
355
0
                    lyd_hash(parent);
356
0
                    lyd_insert_hash(parent);
357
0
                    break;
358
0
                }
359
0
            }
360
0
        }
361
0
    }
362
363
    /* set output tree */
364
0
    if (tree) {
365
0
        *tree = new_top_parent;
366
0
    }
367
368
0
cleanup:
369
0
    lyxp_expr_free(exp);
370
0
    if (p_decremented) {
371
0
        LY_ARRAY_INCREMENT(p);
372
0
    }
373
0
    ly_path_free(p);
374
0
    if (ret) {
375
0
        lyd_free_all(new_top_parent);
376
0
    }
377
0
    return ret;
378
0
}
379
380
LIBYANG_API_DEF LY_ERR
381
lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
382
        enum lyd_type data_type, uint32_t parse_options, struct lyd_node **tree, struct lyd_node **op)
383
0
{
384
0
    LY_ERR rc = LY_SUCCESS;
385
0
    struct lyd_ctx *lydctx = NULL;
386
0
    struct ly_set parsed = {0};
387
0
    struct lyd_node *first = NULL, *envp = NULL;
388
0
    uint32_t i, val_opts, int_opts = 0;
389
0
    ly_bool proto_msg = 0;
390
391
0
    LY_CHECK_ARG_RET(ctx, ctx || parent, in, !(parse_options & ~(LYD_PARSE_STRICT | LYD_PARSE_OPAQ)), data_type,
392
0
            parent || tree || op, LY_EINVAL);
393
394
0
    parse_options |= LYD_PARSE_ONLY;
395
396
0
    if (!ctx) {
397
0
        ctx = LYD_CTX(parent);
398
0
    }
399
0
    if (tree) {
400
0
        *tree = NULL;
401
0
    }
402
0
    if (op) {
403
0
        *op = NULL;
404
0
    }
405
406
0
    format = lyd_parse_get_format(in, format);
407
408
    /* remember input position */
409
0
    in->func_start = in->current;
410
411
    /* set validation opts */
412
0
    val_opts = 0;
413
414
0
    switch (data_type) {
415
0
    case LYD_TYPE_RPC_NETCONF:
416
0
    case LYD_TYPE_NOTIF_NETCONF:
417
0
        LY_CHECK_ARG_RET(ctx, format == LYD_XML, !parent, tree, op, LY_EINVAL);
418
0
        proto_msg = 1;
419
0
        break;
420
0
    case LYD_TYPE_REPLY_NETCONF:
421
0
        LY_CHECK_ARG_RET(ctx, format == LYD_XML, parent, parent->schema, parent->schema->nodetype & (LYS_RPC | LYS_ACTION),
422
0
                tree, !op, LY_EINVAL);
423
0
        proto_msg = 1;
424
0
        break;
425
0
    case LYD_TYPE_RPC_RESTCONF:
426
0
    case LYD_TYPE_REPLY_RESTCONF:
427
0
        LY_CHECK_ARG_RET(ctx, parent, parent->schema, parent->schema->nodetype & (LYS_RPC | LYS_ACTION), tree, !op, LY_EINVAL);
428
0
        proto_msg = 1;
429
0
        break;
430
0
    case LYD_TYPE_NOTIF_RESTCONF:
431
0
        LY_CHECK_ARG_RET(ctx, format == LYD_JSON, !parent, tree, op, LY_EINVAL);
432
0
        proto_msg = 1;
433
0
        break;
434
435
    /* set internal opts */
436
0
    case LYD_TYPE_RPC_YANG:
437
0
        int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
438
0
        break;
439
0
    case LYD_TYPE_NOTIF_YANG:
440
0
        int_opts = LYD_INTOPT_NOTIF | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
441
0
        break;
442
0
    case LYD_TYPE_REPLY_YANG:
443
0
        int_opts = LYD_INTOPT_REPLY | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
444
0
        break;
445
0
    default:
446
0
        LOGINT(ctx);
447
0
        rc = LY_EINT;
448
0
        goto cleanup;
449
0
    }
450
451
    /* parse a full protocol message */
452
0
    if (proto_msg) {
453
0
        if (format == LYD_XML) {
454
            /* parse the NETCONF (or RESTCONF XML) message */
455
0
            rc = lyd_parse_xml_netconf(ctx, parent, &first, in, parse_options, val_opts, data_type, &envp, &parsed, &lydctx);
456
0
        } else {
457
            /* parse the RESTCONF message */
458
0
            rc = lyd_parse_json_restconf(ctx, parent, &first, in, parse_options, val_opts, data_type, &envp, &parsed, &lydctx);
459
0
        }
460
0
        if (rc) {
461
0
            if (envp) {
462
                /* special situation when the envelopes were parsed successfully */
463
0
                *tree = envp;
464
0
            }
465
0
            goto cleanup;
466
0
        }
467
468
        /* set out params correctly */
469
0
        if (envp) {
470
            /* special out param meaning */
471
0
            *tree = envp;
472
0
        } else {
473
0
            *tree = parent ? NULL : first;
474
0
        }
475
0
        if (op) {
476
0
            *op = lydctx->op_node;
477
0
        }
478
0
        goto cleanup;
479
0
    }
480
481
    /* parse the data */
482
0
    switch (format) {
483
0
    case LYD_XML:
484
0
        rc = lyd_parse_xml(ctx, parent, &first, in, parse_options, val_opts, int_opts, &parsed, &lydctx);
485
0
        break;
486
0
    case LYD_JSON:
487
0
        rc = lyd_parse_json(ctx, parent, NULL, &first, in, parse_options, val_opts, int_opts, &parsed, &lydctx);
488
0
        break;
489
0
    case LYD_LYB:
490
0
        rc = lyd_parse_lyb(ctx, parent, &first, in, parse_options, val_opts, int_opts, &parsed, &lydctx);
491
0
        break;
492
#ifdef ENABLE_CBOR_SUPPORT
493
    case LYD_CBOR:
494
        rc = lyd_parse_cbor(ctx, NULL, parent, &first, in, parse_options, val_opts, int_opts, &parsed, NULL, &lydctx);
495
        break;
496
#else
497
0
    case LYD_CBOR:
498
0
        LOGARG(ctx, format);
499
0
        rc = LY_EINVAL;
500
0
        break;
501
0
#endif /* ENABLE_CBOR_SUPPORT */
502
0
    case LYD_UNKNOWN:
503
0
        LOGARG(ctx, format);
504
0
        rc = LY_EINVAL;
505
0
        break;
506
0
    }
507
0
    LY_CHECK_GOTO(rc, cleanup);
508
509
    /* set out params correctly */
510
0
    if (tree) {
511
0
        *tree = parent ? NULL : first;
512
0
    }
513
0
    if (op) {
514
0
        *op = lydctx->op_node;
515
0
    }
516
517
0
cleanup:
518
0
    if (lydctx) {
519
0
        lydctx->free(lydctx);
520
0
    }
521
0
    if (rc) {
522
        /* free all the parsed nodes */
523
0
        if (parsed.count) {
524
0
            i = parsed.count;
525
0
            do {
526
0
                --i;
527
0
                lyd_free_tree(parsed.dnodes[i]);
528
0
            } while (i);
529
0
        }
530
0
        if (tree && !envp) {
531
0
            *tree = NULL;
532
0
        }
533
0
        if (op) {
534
0
            *op = NULL;
535
0
        }
536
0
    }
537
0
    ly_set_erase(&parsed, NULL);
538
0
    return rc;
539
0
}
540
541
struct lyd_node *
542
lyd_insert_get_next_anchor(const struct lyd_node *first_sibling, const struct lyd_node *new_node)
543
0
{
544
0
    const struct lysc_node *schema, *sparent;
545
0
    struct lyd_node *match = NULL;
546
0
    ly_bool found;
547
0
    uint32_t getnext_opts;
548
549
0
    assert(new_node);
550
551
0
    if (!first_sibling || !new_node->schema || (new_node->flags & LYD_EXT)) {
552
        /* insert at the end, no next anchor */
553
0
        return NULL;
554
0
    }
555
556
0
    getnext_opts = 0;
557
0
    if (new_node->schema->flags & LYS_IS_OUTPUT) {
558
0
        getnext_opts = LYS_GETNEXT_OUTPUT;
559
0
    }
560
561
0
    if ((LYD_CTX(first_sibling) == LYD_CTX(new_node)) && first_sibling->parent && first_sibling->parent->schema &&
562
0
            ((struct lyd_node_inner *)first_sibling->parent)->children_ht) {
563
        /* find the anchor using hashes */
564
0
        sparent = first_sibling->parent->schema;
565
0
        schema = lys_getnext(new_node->schema, sparent, NULL, getnext_opts);
566
0
        while (schema) {
567
            /* keep trying to find the first existing instance of the closest following schema sibling,
568
             * otherwise return NULL - inserting at the end */
569
0
            if (!lyd_find_sibling_schema(first_sibling, schema, &match)) {
570
0
                break;
571
0
            }
572
573
0
            schema = lys_getnext(schema, sparent, NULL, getnext_opts);
574
0
        }
575
0
    } else {
576
        /* find the anchor without hashes */
577
0
        match = (struct lyd_node *)first_sibling;
578
0
        sparent = lysc_data_parent(new_node->schema);
579
0
        if (!sparent) {
580
            /* we are in top-level, skip all the data from preceding modules */
581
0
            LY_LIST_FOR(match, match) {
582
0
                if (!match->schema || (strcmp(lyd_owner_module(match)->name, lyd_owner_module(new_node)->name) >= 0)) {
583
0
                    break;
584
0
                }
585
0
            }
586
0
        }
587
588
        /* get the first schema sibling */
589
0
        schema = lys_getnext(NULL, sparent, new_node->schema->module->compiled, getnext_opts);
590
0
        if (!schema) {
591
            /* must be a top-level extension instance data, no anchor */
592
0
            return NULL;
593
0
        }
594
595
0
        found = 0;
596
0
        LY_LIST_FOR(match, match) {
597
0
            if (!match->schema || (lyd_owner_module(match) != lyd_owner_module(new_node))) {
598
                /* we have found an opaque node, which must be at the end, so use it OR
599
                 * modules do not match, so we must have traversed all the data from new_node module (if any),
600
                 * we have found the first node of the next module, that is what we want */
601
0
                break;
602
0
            }
603
604
            /* skip schema nodes until we find the instantiated one */
605
0
            while (!found) {
606
0
                if (new_node->schema == schema) {
607
                    /* we have found the schema of the new node, continue search to find the first
608
                     * data node with a different schema (after our schema) */
609
0
                    found = 1;
610
0
                    break;
611
0
                }
612
0
                if (match->schema == schema) {
613
                    /* current node (match) is a data node still before the new node, continue search in data */
614
0
                    break;
615
0
                }
616
617
0
                schema = lys_getnext(schema, sparent, new_node->schema->module->compiled, getnext_opts);
618
0
                if (!schema) {
619
                    /* must be a top-level extension instance data, no anchor */
620
0
                    return NULL;
621
0
                }
622
0
            }
623
624
0
            if (found && (match->schema != new_node->schema)) {
625
                /* find the next node after we have found our node schema data instance */
626
0
                break;
627
0
            }
628
0
        }
629
0
    }
630
631
0
    return match;
632
0
}
633
634
void
635
lyd_insert_after_node(struct lyd_node **first_sibling_p, struct lyd_node *sibling, struct lyd_node *node)
636
0
{
637
0
    struct lyd_node *first_sibling;
638
639
0
    assert(!node->next && (node->prev == node) && (sibling != node));
640
641
0
    if (sibling->next) {
642
        /* sibling had a succeeding node */
643
0
        sibling->next->prev = node;
644
0
        node->next = sibling->next;
645
0
    } else {
646
        /* sibling was last, find first sibling and change its prev */
647
0
        if (first_sibling_p && *first_sibling_p) {
648
0
            assert(!(*first_sibling_p)->prev->next);
649
0
            (*first_sibling_p)->prev = node;
650
0
        } else {
651
0
            first_sibling = lyd_first_sibling(sibling);
652
0
            first_sibling->prev = node;
653
0
            if (first_sibling_p) {
654
0
                *first_sibling_p = first_sibling;
655
0
            }
656
0
        }
657
0
    }
658
0
    node->prev = sibling;
659
0
    sibling->next = node;
660
0
    node->parent = sibling->parent;
661
662
0
    if (!(node->flags & LYD_DEFAULT)) {
663
        /* remove default flags from NP containers */
664
0
        lyd_np_cont_dflt_del(node->parent);
665
0
    }
666
0
}
667
668
void
669
lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
670
0
{
671
0
    assert(!node->next && (node->prev == node) && (sibling != node));
672
673
0
    node->next = sibling;
674
    /* covers situation of sibling being first */
675
0
    node->prev = sibling->prev;
676
0
    sibling->prev = node;
677
0
    if (node->prev->next) {
678
        /* sibling had a preceding node */
679
0
        node->prev->next = node;
680
0
    } else if (sibling->parent) {
681
        /* sibling was first and we must also change parent child pointer */
682
0
        ((struct lyd_node_inner *)sibling->parent)->child = node;
683
0
    }
684
0
    node->parent = sibling->parent;
685
686
0
    if (!(node->flags & LYD_DEFAULT)) {
687
        /* remove default flags from NP containers */
688
0
        lyd_np_cont_dflt_del(node->parent);
689
0
    }
690
0
}
691
692
/**
693
 * @brief Insert node as the first and only child of a parent.
694
 *
695
 * Handles inserting into NP containers and key-less lists.
696
 *
697
 * @param[in] parent Parent to insert into.
698
 * @param[in] node Node to insert.
699
 */
700
static void
701
lyd_insert_only_child(struct lyd_node *parent, struct lyd_node *node)
702
0
{
703
0
    assert(parent && !lyd_child_any(parent) && !node->next && (node->prev == node));
704
0
    assert(!parent->schema || (parent->schema->nodetype & (LYD_NODE_INNER | LYD_NODE_ANY)));
705
706
0
    ((struct lyd_node_inner *)parent)->child = node;
707
0
    node->parent = parent;
708
709
0
    if (!(node->flags & LYD_DEFAULT)) {
710
        /* remove default flags from NP containers */
711
0
        lyd_np_cont_dflt_del(parent);
712
0
    }
713
0
}
714
715
/**
716
 * @brief Learn whether a list instance has all the keys.
717
 *
718
 * @param[in] list List instance to check.
719
 * @return non-zero if all the keys were found,
720
 * @return 0 otherwise.
721
 */
722
static int
723
lyd_insert_has_keys(const struct lyd_node *list)
724
0
{
725
0
    const struct lyd_node *key;
726
0
    const struct lysc_node *skey = NULL;
727
728
0
    assert(list->schema->nodetype == LYS_LIST);
729
0
    key = lyd_child(list);
730
0
    while ((skey = lys_getnext(skey, list->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
731
0
        if (!key || (key->schema != skey)) {
732
            /* key missing */
733
0
            return 0;
734
0
        }
735
736
0
        key = key->next;
737
0
    }
738
739
    /* all keys found */
740
0
    return 1;
741
0
}
742
743
/**
744
 * @brief Get the first subsequent data node that contains a different schema definition.
745
 *
746
 * @param[in] first_sibling First sibling, NULL if no top-level sibling exist yet.
747
 * @param[in] node Node to be inserted.
748
 * @return Subsequent data node with a different schema.
749
 */
750
static struct lyd_node *
751
lyd_insert_node_find_anchor(struct lyd_node *first_sibling, struct lyd_node *node)
752
0
{
753
0
    struct lyd_node *anchor;
754
755
0
    if ((node->flags & LYD_EXT) && (!first_sibling || !(first_sibling->prev->flags & LYD_EXT))) {
756
0
        return NULL;
757
0
    }
758
759
    /* find the anchor, so we can insert somewhere before it */
760
0
    anchor = lyd_insert_get_next_anchor(first_sibling, node);
761
    /* cannot insert data node after opaque nodes */
762
0
    if (!anchor && node->schema && first_sibling && !first_sibling->prev->schema) {
763
0
        anchor = first_sibling->prev;
764
0
        while ((anchor != first_sibling) && !anchor->prev->schema) {
765
0
            anchor = anchor->prev;
766
0
        }
767
0
    }
768
769
0
    return anchor;
770
0
}
771
772
/**
773
 * @brief Insert @p node as (usually) the last node.
774
 *
775
 * @param[in] parent Parent to insert into, NULL for top-level sibling.
776
 * @param[in,out] first_sibling First sibling, NULL if no top-level sibling exist yet.
777
 * Can be also NULL if @p parent is set.
778
 * @param[in] node Individual node (without siblings) to insert.
779
 */
780
static void
781
lyd_insert_node_last(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
782
0
{
783
0
    struct lyd_node *anchor;
784
785
0
    assert(first_sibling && node);
786
787
0
    if (*first_sibling) {
788
        /* keep some order: data nodes, ext nodes, opaque nodes */
789
0
        anchor = (*first_sibling)->prev;
790
0
        if (node->flags & LYD_EXT) {
791
0
            while (!anchor->schema) {
792
0
                if (anchor->prev->next) {
793
0
                    anchor = anchor->prev;
794
0
                } else {
795
                    /* insert as the first node */
796
0
                    anchor = NULL;
797
0
                    break;
798
0
                }
799
0
            }
800
0
        }
801
802
0
        if (anchor) {
803
0
            lyd_insert_after_node(first_sibling, anchor, node);
804
0
        } else {
805
0
            lyd_insert_before_node(*first_sibling, node);
806
0
            *first_sibling = node;
807
0
        }
808
0
    } else if (parent) {
809
0
        lyd_insert_only_child(parent, node);
810
0
        *first_sibling = node;
811
0
    } else {
812
0
        *first_sibling = node;
813
0
    }
814
0
}
815
816
void
817
lyd_insert_node_ordby_schema(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
818
0
{
819
0
    struct lyd_node *anchor;
820
821
0
    assert(first_sibling && node);
822
823
0
    if ((anchor = lyd_insert_node_find_anchor(*first_sibling, node))) {
824
0
        lyd_insert_before_node(anchor, node);
825
0
        *first_sibling = *first_sibling != anchor ? *first_sibling : node;
826
0
    } else if (*first_sibling && node->schema && !(*first_sibling)->prev->schema) {
827
        /* cannot insert data node after opaque nodes */
828
0
        anchor = (*first_sibling)->prev;
829
0
        while ((anchor != *first_sibling) && !anchor->prev->schema) {
830
0
            anchor = anchor->prev;
831
0
        }
832
0
        lyd_insert_before_node(anchor, node);
833
0
        *first_sibling = *first_sibling != anchor ? *first_sibling : node;
834
0
    } else {
835
0
        lyd_insert_node_last(parent, first_sibling, node);
836
0
    }
837
0
}
838
839
void
840
lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, struct lyd_node *node, uint32_t order)
841
0
{
842
0
    LY_ERR ret = LY_SUCCESS;
843
0
    struct lyd_node *first_sibling, *leader;
844
845
    /* inserting list without its keys is not supported */
846
0
    assert((parent || first_sibling_p) && node && (node->hash || !node->schema));
847
0
    assert(!parent || !parent->schema ||
848
0
            (parent->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_ANYDATA)));
849
850
0
    if (!parent && first_sibling_p && (*first_sibling_p)) {
851
0
        parent = (*first_sibling_p)->parent;
852
0
    }
853
0
    first_sibling = parent ? lyd_child_any(parent) : *first_sibling_p;
854
855
0
    if ((order == LYD_INSERT_NODE_LAST) || !node->schema || (node->flags & LYD_EXT)) {
856
0
        lyd_insert_node_last(parent, &first_sibling, node);
857
0
    } else if (order == LYD_INSERT_NODE_LAST_BY_SCHEMA) {
858
0
        lyd_insert_node_ordby_schema(parent, &first_sibling, node);
859
0
    } else if (lyds_is_supported(node) &&
860
0
            (lyd_find_sibling_schema(first_sibling, node->schema, &leader) == LY_SUCCESS)) {
861
0
        ret = lyds_insert(&first_sibling, &leader, node);
862
0
        if (ret) {
863
            /* The operation on the sorting tree unexpectedly failed due to some internal issue,
864
             * but insert the node anyway although the nodes will not be sorted.
865
             */
866
0
            LOGWRN(LYD_CTX(node), "Data in \"%s\" are not sorted.", node->schema->name);
867
0
            lyd_insert_node_ordby_schema(parent, &first_sibling, node);
868
0
        }
869
0
    } else {
870
0
        lyd_insert_node_ordby_schema(parent, &first_sibling, node);
871
0
    }
872
873
    /* insert into parent HT */
874
0
    lyd_insert_hash(node);
875
876
    /* finish hashes for our parent, if needed and possible */
877
0
    if (node->schema && (node->schema->flags & LYS_KEY) && parent && parent->schema && lyd_insert_has_keys(parent)) {
878
0
        lyd_hash(parent);
879
880
        /* now we can insert even the list into its parent HT */
881
0
        lyd_insert_hash(parent);
882
0
    }
883
884
0
    if (first_sibling_p) {
885
0
        *first_sibling_p = first_sibling;
886
0
    }
887
888
0
#ifndef NDEBUG
889
0
    if ((order == LYD_INSERT_NODE_LAST) && lyds_is_supported(node) &&
890
0
            (node->prev->schema == node->schema) && (lyds_compare_single(node->prev, node) > 0)) {
891
0
        LOGWRN(LYD_CTX(node), "Data in \"%s\" are not sorted, inserted node should not be added to the end.",
892
0
                node->schema->name);
893
0
    }
894
0
#endif
895
0
}
896
897
/**
898
 * @brief Check that @p node can be unlinked.
899
 *
900
 * @param[in] node Node to check
901
 * @return LY_ERR value.
902
 */
903
static LY_ERR
904
lyd_unlink_check(struct lyd_node *node)
905
0
{
906
0
    if (!node) {
907
0
        return LY_SUCCESS;
908
0
    }
909
910
0
    if (lysc_is_key(node->schema) && node->parent) {
911
0
        LOGERR(LYD_CTX(node), LY_EINVAL, "Cannot unlink a list key \"%s\", unlink the list instance instead.",
912
0
                LYD_NAME(node));
913
0
        return LY_EINVAL;
914
0
    }
915
916
0
    return LY_SUCCESS;
917
0
}
918
919
/**
920
 * @brief Move schema instances before anchor or as the last.
921
 *
922
 * The nodes will remain sorted according to the schema.
923
 *
924
 * @param[in] first_dst First sibling, destination.
925
 * @param[in] node Starting node, all following nodes with the same schema will be moved.
926
 * @param[out] next_p Next node that has a different schema or NULL.
927
 * @return LY_ERR value.
928
 */
929
static LY_ERR
930
lyd_move_nodes_ordby_schema(struct lyd_node **first_dst, struct lyd_node *node, struct lyd_node **next_p)
931
0
{
932
0
    struct lyd_node *second, *anchor, *iter, *next, *dst, *src, *first_src = NULL;
933
934
0
    assert(first_dst && *first_dst && !(*first_dst)->prev->next && node && next_p);
935
936
0
    if ((anchor = lyd_insert_node_find_anchor(*first_dst, node))) {
937
        /* move the first node to the correct place according to the schema */
938
0
        LY_CHECK_RET(lyd_unlink_check(node));
939
0
        second = node->next;
940
0
        lyd_unlink_ignore_lyds(&first_src, node);
941
0
        lyd_insert_before_node(anchor, node);
942
0
        lyd_insert_hash(node);
943
0
        *first_dst = *first_dst != anchor ? *first_dst : node;
944
0
        if (!second || (node->schema != second->schema)) {
945
            /* no more nodes to move */
946
0
            *next_p = second;
947
0
            return LY_SUCCESS;
948
0
        }
949
0
        dst = node;
950
0
        src = second;
951
0
    } else {
952
        /* just move all instances to the end */
953
0
        dst = (*first_dst)->prev;
954
0
        src = node;
955
0
    }
956
957
    /* move the rest of source instances after @p node */
958
0
    LY_LIST_FOR_SAFE(src, next, iter) {
959
0
        LY_CHECK_RET(lyd_unlink_check(iter));
960
0
        if (iter->schema != src->schema) {
961
0
            break;
962
0
        }
963
0
        lyd_unlink_ignore_lyds(&first_src, iter);
964
0
        lyd_insert_after_node(first_dst, dst, iter);
965
0
        lyd_insert_hash(iter);
966
0
        dst = iter;
967
0
    }
968
0
    *next_p = iter;
969
970
0
    return LY_SUCCESS;
971
0
}
972
973
/**
974
 * @brief Move nodes regardless of schema.
975
 *
976
 * The destination for the move is NULL, or a childless parent.
977
 *
978
 * @param[in] parent Parent to insert into, NULL for top-level sibling.
979
 * @param[in] first_src First sibling, all following nodes will be moved.
980
 * @return LY_ERR value.
981
 */
982
static LY_ERR
983
lyd_move_nodes_at_once(struct lyd_node *parent, struct lyd_node *first_src)
984
0
{
985
0
    struct lyd_node *start, *next, *iter, *first_dst;
986
987
0
    assert(!lyd_child(parent) && first_src && !first_src->prev->next && !first_src->parent);
988
989
0
    LY_CHECK_RET(lyd_unlink_check(first_src));
990
991
    /* move the first node */
992
0
    start = first_src->next;
993
0
    first_dst = first_src;
994
0
    if (parent) {
995
0
        lyd_unlink_ignore_lyds(&first_src, first_dst);
996
0
        lyd_insert_only_child(parent, first_dst);
997
0
        lyd_insert_hash(first_dst);
998
0
    } else {
999
0
        lyd_unlink_ignore_lyds(&first_src, first_dst);
1000
0
    }
1001
1002
    /* move the rest of the nodes */
1003
0
    LY_LIST_FOR_SAFE(start, next, iter) {
1004
0
        LY_CHECK_RET(lyd_unlink_check(iter));
1005
0
        lyd_unlink_ignore_lyds(&first_src, iter);
1006
0
        lyd_insert_after_node(&first_dst, first_dst->prev, iter);
1007
0
        lyd_insert_hash(iter);
1008
0
    }
1009
1010
0
    return LY_SUCCESS;
1011
0
}
1012
1013
/**
1014
 * @brief Move the nodes in parts according to the schema.
1015
 *
1016
 * @param[in,out] first_dst First sibling, destination.
1017
 * @param[in] first_src First sibling, all following nodes will be moved.
1018
 * @return LY_ERR value.
1019
 */
1020
static LY_ERR
1021
lyd_move_nodes_by_schema(struct lyd_node **first_dst, struct lyd_node *first_src)
1022
0
{
1023
0
    LY_ERR ret;
1024
0
    struct lyd_node *next, *iter, *leader;
1025
1026
0
    assert(first_dst && *first_dst && !(*first_dst)->prev->next && first_src &&
1027
0
            !first_src->prev->next && !first_src->parent);
1028
1029
0
    for (iter = first_src; iter; iter = next) {
1030
0
        if (lyds_is_supported(iter) &&
1031
0
                (lyd_find_sibling_schema(*first_dst, iter->schema, &leader) == LY_SUCCESS)) {
1032
0
            ret = lyds_merge(first_dst, &leader, &first_src, iter, &next);
1033
0
            if (ret) {
1034
                /* The operation on the sorting tree unexpectedly failed due to some internal issue,
1035
                 * but insert the node anyway although the nodes will not be sorted.
1036
                 */
1037
0
                LOGWRN(LYD_CTX(first_src), "Data in \"%s\" are not sorted.", leader->schema->name);
1038
0
                LY_CHECK_RET(lyd_move_nodes_ordby_schema(first_dst, next, &next));
1039
0
            }
1040
0
        } else {
1041
0
            LY_CHECK_RET(lyd_move_nodes_ordby_schema(first_dst, iter, &next));
1042
0
        }
1043
0
    }
1044
1045
0
    return LY_SUCCESS;
1046
0
}
1047
1048
/**
1049
 * @brief Move a nodes into parent/siblings.
1050
 *
1051
 * @param[in] parent Parent to insert into, NULL for top-level sibling.
1052
 * @param[in,out] first_dst_p First sibling, NULL if no top-level sibling exist yet.
1053
 * Can be also NULL if @p parent is set.
1054
 * @param[in] first_src First sibling, all following nodes will be moved.
1055
 * @return LY_ERR value.
1056
 */
1057
static LY_ERR
1058
lyd_move_nodes(struct lyd_node *parent, struct lyd_node **first_dst_p, struct lyd_node *first_src)
1059
0
{
1060
0
    LY_ERR ret;
1061
0
    struct lyd_node *first_dst;
1062
1063
0
    assert((parent || first_dst_p) && first_src && !first_src->prev->next);
1064
1065
0
    if (!first_dst_p || !*first_dst_p) {
1066
0
        first_dst = lyd_child(parent);
1067
0
    } else {
1068
0
        first_dst = *first_dst_p;
1069
0
    }
1070
1071
0
    if (first_dst) {
1072
0
        ret = lyd_move_nodes_by_schema(&first_dst, first_src);
1073
0
    } else {
1074
0
        ret = lyd_move_nodes_at_once(parent, first_src);
1075
0
        first_dst = first_src;
1076
0
    }
1077
1078
0
    if (first_dst_p) {
1079
0
        *first_dst_p = first_dst;
1080
0
    }
1081
1082
0
    return ret;
1083
0
}
1084
1085
/**
1086
 * @brief Check schema place of a node to be inserted.
1087
 *
1088
 * @param[in] parent Schema node of the parent data node.
1089
 * @param[in] sibling Schema node of a sibling data node.
1090
 * @param[in] schema Schema node if the data node to be inserted.
1091
 * @return LY_SUCCESS on success.
1092
 * @return LY_EINVAL if the place is invalid.
1093
 */
1094
static LY_ERR
1095
lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *sibling, const struct lysc_node *schema)
1096
0
{
1097
0
    const struct lysc_node *par2;
1098
1099
0
    assert(!parent || !(parent->nodetype & (LYS_CASE | LYS_CHOICE)));
1100
0
    assert(!sibling || !(sibling->nodetype & (LYS_CASE | LYS_CHOICE)));
1101
0
    assert(!schema || !(schema->nodetype & (LYS_CASE | LYS_CHOICE)));
1102
1103
0
    if (!schema || (!parent && !sibling)) {
1104
        /* opaque nodes can be inserted wherever */
1105
0
        return LY_SUCCESS;
1106
0
    }
1107
1108
0
    if (!parent) {
1109
0
        parent = lysc_data_parent(sibling);
1110
0
    }
1111
1112
    /* find schema parent */
1113
0
    par2 = lysc_data_parent(schema);
1114
1115
0
    if (parent) {
1116
        /* inner node */
1117
0
        if (par2 != parent) {
1118
0
            LOGERR(schema->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name,
1119
0
                    parent->name);
1120
0
            return LY_EINVAL;
1121
0
        }
1122
0
    } else {
1123
        /* top-level node */
1124
0
        if (par2) {
1125
0
            LOGERR(schema->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
1126
0
            return LY_EINVAL;
1127
0
        }
1128
0
    }
1129
1130
0
    return LY_SUCCESS;
1131
0
}
1132
1133
LIBYANG_API_DEF LY_ERR
1134
lyd_insert_child(struct lyd_node *parent, struct lyd_node *node)
1135
0
{
1136
0
    LY_CHECK_ARG_RET(NULL, parent, node, !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
1137
1138
0
    if (!(node->flags & LYD_EXT)) {
1139
0
        LY_CHECK_RET(lyd_insert_check_schema(parent->schema, NULL, node->schema));
1140
0
    }
1141
1142
0
    if (node->parent || node->prev->next || !node->next) {
1143
0
        LY_CHECK_RET(lyd_unlink_tree(node));
1144
0
        lyd_insert_node(parent, NULL, node, LYD_INSERT_NODE_DEFAULT);
1145
0
    } else {
1146
0
        LY_CHECK_RET(lyd_move_nodes(parent, NULL, node));
1147
0
    }
1148
1149
0
    return LY_SUCCESS;
1150
0
}
1151
1152
LIBYANG_API_DEF LY_ERR
1153
lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct lyd_node **first)
1154
0
{
1155
0
    struct lyd_node *first_sibling;
1156
1157
0
    LY_CHECK_ARG_RET(NULL, node, sibling != node, LY_EINVAL);
1158
1159
0
    if (sibling) {
1160
0
        LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
1161
0
    }
1162
1163
0
    first_sibling = lyd_first_sibling(sibling);
1164
0
    if (node->parent || node->prev->next || !node->next) {
1165
0
        LY_CHECK_RET(lyd_unlink_tree(node));
1166
0
        lyd_insert_node(NULL, &first_sibling, node, LYD_INSERT_NODE_DEFAULT);
1167
0
    } else {
1168
0
        LY_CHECK_RET(lyd_move_nodes(NULL, &first_sibling, node));
1169
0
    }
1170
1171
0
    if (first) {
1172
0
        *first = first_sibling;
1173
0
    }
1174
1175
0
    return LY_SUCCESS;
1176
0
}
1177
1178
LIBYANG_API_DEF LY_ERR
1179
lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
1180
0
{
1181
0
    LY_CHECK_ARG_RET(NULL, sibling, node, sibling != node, LY_EINVAL);
1182
0
    LY_CHECK_CTX_EQUAL_RET(__func__, LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
1183
1184
0
    LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
1185
1186
0
    if (node->schema && (!(node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(node->schema->flags & LYS_ORDBY_USER))) {
1187
0
        LOGERR(LYD_CTX(sibling), LY_EINVAL, "Can be used only for user-ordered nodes.");
1188
0
        return LY_EINVAL;
1189
0
    }
1190
0
    if (node->schema && sibling->schema && (node->schema != sibling->schema)) {
1191
0
        LOGERR(LYD_CTX(sibling), LY_EINVAL, "Cannot insert before a different schema node instance.");
1192
0
        return LY_EINVAL;
1193
0
    }
1194
1195
0
    lyd_unlink(node);
1196
0
    lyd_insert_before_node(sibling, node);
1197
0
    lyd_insert_hash(node);
1198
1199
0
    return LY_SUCCESS;
1200
0
}
1201
1202
LIBYANG_API_DEF LY_ERR
1203
lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
1204
0
{
1205
0
    LY_CHECK_ARG_RET(NULL, sibling, node, sibling != node, LY_EINVAL);
1206
0
    LY_CHECK_CTX_EQUAL_RET(__func__, LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
1207
1208
0
    LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
1209
1210
0
    if (node->schema && (!(node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(node->schema->flags & LYS_ORDBY_USER))) {
1211
0
        LOGERR(LYD_CTX(sibling), LY_EINVAL, "Can be used only for user-ordered nodes.");
1212
0
        return LY_EINVAL;
1213
0
    }
1214
0
    if (node->schema && sibling->schema && (node->schema != sibling->schema)) {
1215
0
        LOGERR(LYD_CTX(sibling), LY_EINVAL, "Cannot insert after a different schema node instance.");
1216
0
        return LY_EINVAL;
1217
0
    }
1218
1219
0
    lyd_unlink(node);
1220
0
    lyd_insert_after_node(NULL, sibling, node);
1221
0
    lyd_insert_hash(node);
1222
1223
0
    return LY_SUCCESS;
1224
0
}
1225
1226
void
1227
lyd_unlink_ignore_lyds(struct lyd_node **first_sibling_p, struct lyd_node *node)
1228
0
{
1229
0
    struct lyd_node *first_sibling;
1230
1231
    /* update hashes while still linked into the tree */
1232
0
    lyd_unlink_hash(node);
1233
1234
    /* unlink leafref nodes */
1235
0
    if (node->schema && (node->schema->nodetype & LYD_NODE_TERM)) {
1236
0
        lyd_free_leafref_nodes((struct lyd_node_term *)node);
1237
0
    }
1238
1239
    /* unlink from siblings */
1240
0
    if (node->next) {
1241
0
        node->next->prev = node->prev;
1242
0
        if (node->prev->next) {
1243
0
            node->prev->next = node->next;
1244
0
        } else if (first_sibling_p) {
1245
            /* unlinking the first node */
1246
0
            *first_sibling_p = node->next;
1247
0
        }
1248
0
    } else {
1249
        /* unlinking the last node */
1250
        /* update the "last" pointer from the first node */
1251
0
        if (first_sibling_p && *first_sibling_p) {
1252
0
            (*first_sibling_p)->prev = node->prev;
1253
0
        } else {
1254
0
            first_sibling = lyd_first_sibling(node);
1255
0
            first_sibling->prev = node->prev;
1256
0
            if (first_sibling_p) {
1257
0
                *first_sibling_p = first_sibling;
1258
0
            }
1259
0
        }
1260
0
        node->prev->next = NULL;
1261
0
    }
1262
1263
    /* unlink from parent */
1264
0
    if (node->parent) {
1265
0
        if (((struct lyd_node_inner *)node->parent)->child == node) {
1266
            /* the node is the first child */
1267
0
            ((struct lyd_node_inner *)node->parent)->child = node->next;
1268
0
        }
1269
1270
        /* check for NP container whether its last non-default node is not being unlinked */
1271
0
        lyd_np_cont_dflt_set(node->parent);
1272
1273
0
        node->parent = NULL;
1274
0
    }
1275
1276
0
    node->next = NULL;
1277
0
    node->prev = node;
1278
0
}
1279
1280
void
1281
lyd_unlink(struct lyd_node *node)
1282
0
{
1283
0
    struct lyd_node *leader;
1284
1285
0
    if (!node) {
1286
0
        return;
1287
0
    }
1288
1289
    /* unlink from the lyds tree */
1290
0
    if (lyds_is_supported(node)) {
1291
0
        if (!node->prev->next || (node->prev->schema != node->schema)) {
1292
0
            leader = node;
1293
0
        } else {
1294
0
            lyd_find_sibling_val(node, node->schema, NULL, 0, &leader);
1295
0
            assert(leader);
1296
0
        }
1297
0
        lyds_unlink(&leader, node);
1298
0
    }
1299
1300
    /* unlink data tree */
1301
0
    lyd_unlink_ignore_lyds(NULL, node);
1302
0
}
1303
1304
LIBYANG_API_DEF LY_ERR
1305
lyd_unlink_siblings(struct lyd_node *node)
1306
0
{
1307
0
    struct lyd_node *next, *iter, *leader, *start, *first_sibling = NULL;
1308
1309
0
    if (lyds_is_supported(node) && node->prev->next && (node->prev->schema == node->schema)) {
1310
        /* unlink starts at the non-first item in the (leaf-)list */
1311
0
        lyd_find_sibling_val(node, node->schema, NULL, 0, &leader);
1312
0
        lyds_split(&first_sibling, leader, node, &start);
1313
0
    } else {
1314
        /* unlink @p node */
1315
0
        LY_CHECK_RET(lyd_unlink_check(node));
1316
0
        start = node->next;
1317
0
        lyd_unlink_ignore_lyds(&first_sibling, node);
1318
0
    }
1319
1320
    /* continue unlinking the rest */
1321
0
    LY_LIST_FOR_SAFE(start, next, iter) {
1322
0
        LY_CHECK_RET(lyd_unlink_check(iter));
1323
0
        lyd_unlink_ignore_lyds(&first_sibling, iter);
1324
0
        lyd_insert_after_node(&node, node->prev, iter);
1325
0
        lyd_insert_hash(iter);
1326
0
    }
1327
1328
0
    return LY_SUCCESS;
1329
0
}
1330
1331
LIBYANG_API_DEF LY_ERR
1332
lyd_unlink_tree(struct lyd_node *node)
1333
0
{
1334
0
    LY_CHECK_RET(lyd_unlink_check(node));
1335
0
    lyd_unlink(node);
1336
1337
0
    return LY_SUCCESS;
1338
0
}
1339
1340
void
1341
lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta, ly_bool clear_dflt)
1342
0
{
1343
0
    struct lyd_meta *last, *iter;
1344
1345
0
    assert(parent);
1346
1347
0
    if (!meta) {
1348
0
        return;
1349
0
    }
1350
1351
0
    for (iter = meta; iter; iter = iter->next) {
1352
0
        iter->parent = parent;
1353
0
    }
1354
1355
    /* insert as the last attribute */
1356
0
    if (parent->meta) {
1357
0
        for (last = parent->meta; last->next; last = last->next) {}
1358
0
        last->next = meta;
1359
0
    } else {
1360
0
        parent->meta = meta;
1361
0
    }
1362
1363
    /* remove default flags from NP containers */
1364
0
    if (clear_dflt) {
1365
0
        lyd_np_cont_dflt_del(parent);
1366
0
    }
1367
0
}
1368
1369
void
1370
lyd_unlink_meta_single(struct lyd_meta *meta)
1371
0
{
1372
0
    struct lyd_meta *iter;
1373
1374
0
    if (!meta) {
1375
0
        return;
1376
0
    }
1377
1378
0
    if (meta->parent && (meta->parent->meta == meta)) {
1379
0
        meta->parent->meta = meta->next;
1380
0
    } else if (meta->parent) {
1381
0
        for (iter = meta->parent->meta; iter->next && (iter->next != meta); iter = iter->next) {}
1382
0
        if (iter->next) {
1383
0
            iter->next = meta->next;
1384
0
        }
1385
0
    }
1386
1387
0
    meta->next = NULL;
1388
0
    meta->parent = NULL;
1389
0
}
1390
1391
struct lysc_ext_instance *
1392
lyd_get_meta_annotation(const struct lys_module *mod, const char *name, size_t name_len)
1393
0
{
1394
0
    LY_ARRAY_COUNT_TYPE u;
1395
0
    struct lyplg_ext *plugin;
1396
1397
0
    if (!mod) {
1398
0
        return NULL;
1399
0
    }
1400
1401
0
    LY_ARRAY_FOR(mod->compiled->exts, u) {
1402
0
        plugin = LYSC_GET_EXT_PLG(mod->compiled->exts[u].def->plugin_ref);
1403
0
        if (plugin && !strcmp(plugin->id, "ly2 metadata") &&
1404
0
                !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
1405
0
            return &mod->compiled->exts[u];
1406
0
        }
1407
0
    }
1408
1409
0
    return NULL;
1410
0
}
1411
1412
LY_ERR
1413
lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
1414
        uint32_t name_len, const void *value, uint64_t value_size_bits, ly_bool is_utf8, ly_bool store_only,
1415
        ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
1416
        const struct lyd_node *lnode, ly_bool clear_dflt, ly_bool *incomplete)
1417
0
{
1418
0
    LY_ERR ret = LY_SUCCESS;
1419
0
    struct lysc_ext_instance *ant = NULL;
1420
0
    const struct lysc_type *ant_type;
1421
0
    struct lyd_meta *mt, *last;
1422
1423
0
    assert((parent || meta) && mod);
1424
1425
0
    ant = lyd_get_meta_annotation(mod, name, name_len);
1426
0
    if (!ant) {
1427
        /* attribute is not defined as a metadata annotation (RFC 7952) */
1428
0
        if (!parent && ctx_node) {
1429
0
            LOG_LOCSET(ctx_node);
1430
0
        }
1431
0
        LOGVAL(mod->ctx, parent, LYVE_REFERENCE, "Annotation definition for attribute \"%s:%.*s\" not found.",
1432
0
                mod->name, (int)name_len, name);
1433
0
        if (!parent && ctx_node) {
1434
0
            LOG_LOCBACK(1);
1435
0
        }
1436
0
        ret = LY_EINVAL;
1437
0
        goto cleanup;
1438
0
    }
1439
1440
0
    mt = calloc(1, sizeof *mt);
1441
0
    LY_CHECK_ERR_GOTO(!mt, LOGMEM(mod->ctx); ret = LY_EMEM, cleanup);
1442
0
    mt->parent = parent;
1443
0
    mt->annotation = ant;
1444
0
    lyplg_ext_get_storage(ant, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type);
1445
0
    ret = lyd_value_store(mod->ctx, lnode, &mt->value, ant_type, value, value_size_bits, is_utf8, store_only, dynamic,
1446
0
            format, prefix_data, hints, ctx_node, incomplete);
1447
0
    LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
1448
0
    ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
1449
0
    LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
1450
1451
    /* insert as the last attribute */
1452
0
    if (parent) {
1453
0
        lyd_insert_meta(parent, mt, clear_dflt);
1454
0
    } else if (*meta) {
1455
0
        for (last = *meta; last->next; last = last->next) {}
1456
0
        last->next = mt;
1457
0
    }
1458
1459
0
    if (meta) {
1460
0
        *meta = mt;
1461
0
    }
1462
1463
0
cleanup:
1464
0
    return ret;
1465
0
}
1466
1467
void
1468
lyd_insert_attr(struct lyd_node *parent, struct lyd_attr *attr)
1469
0
{
1470
0
    struct lyd_attr *last, *iter;
1471
0
    struct lyd_node_opaq *opaq;
1472
1473
0
    assert(parent && !parent->schema);
1474
1475
0
    if (!attr) {
1476
0
        return;
1477
0
    }
1478
1479
0
    opaq = (struct lyd_node_opaq *)parent;
1480
0
    for (iter = attr; iter; iter = iter->next) {
1481
0
        iter->parent = opaq;
1482
0
    }
1483
1484
    /* insert as the last attribute */
1485
0
    if (opaq->attr) {
1486
0
        for (last = opaq->attr; last->next; last = last->next) {}
1487
0
        last->next = attr;
1488
0
    } else {
1489
0
        opaq->attr = attr;
1490
0
    }
1491
0
}
1492
1493
LY_ERR
1494
lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct ly_ctx *ctx, const char *name, uint32_t name_len,
1495
        const char *prefix, uint32_t prefix_len, const char *module_key, uint32_t module_key_len, const char *value,
1496
        uint32_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *val_prefix_data, uint32_t hints)
1497
0
{
1498
0
    LY_ERR ret = LY_SUCCESS;
1499
0
    struct lyd_attr *at, *last;
1500
1501
0
    assert(ctx && (parent || attr) && (!parent || !parent->schema));
1502
0
    assert(name && name_len && format);
1503
1504
0
    if (!value_len && (!dynamic || !*dynamic)) {
1505
0
        value = "";
1506
0
    }
1507
1508
0
    at = calloc(1, sizeof *at);
1509
0
    LY_CHECK_ERR_RET(!at, LOGMEM(ctx); ly_free_prefix_data(format, val_prefix_data), LY_EMEM);
1510
1511
0
    LY_CHECK_GOTO(ret = lydict_insert(ctx, name, name_len, &at->name.name), finish);
1512
0
    if (prefix_len) {
1513
0
        LY_CHECK_GOTO(ret = lydict_insert(ctx, prefix, prefix_len, &at->name.prefix), finish);
1514
0
    }
1515
0
    if (module_key_len) {
1516
0
        LY_CHECK_GOTO(ret = lydict_insert(ctx, module_key, module_key_len, &at->name.module_ns), finish);
1517
0
    }
1518
1519
0
    if (dynamic && *dynamic) {
1520
0
        ret = lydict_insert_zc(ctx, (char *)value, &at->value);
1521
0
        LY_CHECK_GOTO(ret, finish);
1522
0
        *dynamic = 0;
1523
0
    } else {
1524
0
        LY_CHECK_GOTO(ret = lydict_insert(ctx, value, value_len, &at->value), finish);
1525
0
    }
1526
0
    at->format = format;
1527
0
    at->val_prefix_data = val_prefix_data;
1528
0
    at->hints = hints;
1529
1530
    /* insert as the last attribute */
1531
0
    if (parent) {
1532
0
        lyd_insert_attr(parent, at);
1533
0
    } else if (*attr) {
1534
0
        for (last = *attr; last->next; last = last->next) {}
1535
0
        last->next = at;
1536
0
    }
1537
1538
0
finish:
1539
0
    if (ret) {
1540
0
        lyd_free_attr_single(ctx, at);
1541
0
    } else if (attr) {
1542
0
        *attr = at;
1543
0
    }
1544
0
    return LY_SUCCESS;
1545
0
}
1546
1547
ly_bool
1548
lyd_compare_schema_equal(const struct lysc_node *schema1, const struct lysc_node *schema2, ly_bool cmp_parents)
1549
0
{
1550
0
    if (!schema1 && !schema2) {
1551
0
        return 1;
1552
0
    } else if (!schema1 || !schema2) {
1553
0
        return 0;
1554
0
    }
1555
1556
0
    if (schema1->module->ctx == schema2->module->ctx) {
1557
0
        return (schema1 == schema2) ? 1 : 0;
1558
0
    }
1559
1560
0
    do {
1561
0
        if (schema1->nodetype != schema2->nodetype) {
1562
0
            return 0;
1563
0
        }
1564
1565
0
        if (strcmp(schema1->name, schema2->name)) {
1566
0
            return 0;
1567
0
        }
1568
1569
0
        if (strcmp(schema1->module->name, schema2->module->name)) {
1570
0
            return 0;
1571
0
        }
1572
1573
0
        schema1 = schema1->parent;
1574
0
        schema2 = schema2->parent;
1575
0
    } while (cmp_parents && schema1 && schema2);
1576
1577
0
    if ((schema1 && !schema2) || (!schema1 && schema2)) {
1578
0
        return 0;
1579
0
    }
1580
1581
0
    return 1;
1582
0
}
1583
1584
/**
1585
 * @brief Check the equality of the schemas for all parent nodes.
1586
 *
1587
 * Both nodes must be from different contexts.
1588
 *
1589
 * @param node1 Data of first node.
1590
 * @param node2 Data of second node.
1591
 * @return 1 if the all related parental schemas are equal otherwise 0.
1592
 */
1593
static ly_bool
1594
lyd_compare_schema_parents_equal(const struct lyd_node *node1, const struct lyd_node *node2)
1595
0
{
1596
0
    const struct lysc_node *parent1, *parent2;
1597
1598
0
    assert(node1 && node2);
1599
1600
0
    for (parent1 = node1->schema->parent, parent2 = node2->schema->parent;
1601
0
            parent1 && parent2;
1602
0
            parent1 = parent1->parent, parent2 = parent2->parent) {
1603
0
        if (!lyd_compare_schema_equal(parent1, parent2, 0)) {
1604
0
            return 0;
1605
0
        }
1606
0
    }
1607
1608
0
    if (parent1 || parent2) {
1609
0
        return 0;
1610
0
    }
1611
1612
0
    return 1;
1613
0
}
1614
1615
/**
1616
 * @brief Compare 2 nodes values including opaque node values.
1617
 *
1618
 * @param[in] node1 First node to compare.
1619
 * @param[in] node2 Second node to compare.
1620
 * @return LY_SUCCESS if equal.
1621
 * @return LY_ENOT if not equal.
1622
 * @return LY_ERR on error.
1623
 */
1624
static LY_ERR
1625
lyd_compare_single_value(const struct lyd_node *node1, const struct lyd_node *node2)
1626
0
{
1627
0
    const struct lyd_node_opaq *opaq1 = NULL, *opaq2 = NULL;
1628
0
    const char *val1, *val2, *col;
1629
0
    const struct lys_module *mod;
1630
0
    char *val_dyn = NULL;
1631
0
    LY_ERR rc = LY_SUCCESS;
1632
1633
0
    if (!node1->schema) {
1634
0
        opaq1 = (struct lyd_node_opaq *)node1;
1635
0
    }
1636
0
    if (!node2->schema) {
1637
0
        opaq2 = (struct lyd_node_opaq *)node2;
1638
0
    }
1639
1640
0
    if (opaq1 && opaq2 && (opaq1->format == LY_VALUE_XML) && (opaq2->format == LY_VALUE_XML)) {
1641
        /* opaque XML and opaque XML node */
1642
0
        if (lyxml_value_compare(LYD_CTX(node1), opaq1->value, opaq1->val_prefix_data, LYD_CTX(node2), opaq2->value,
1643
0
                opaq2->val_prefix_data)) {
1644
0
            return LY_ENOT;
1645
0
        }
1646
0
        return LY_SUCCESS;
1647
0
    }
1648
1649
    /* get their values */
1650
0
    if (opaq1 && ((opaq1->format == LY_VALUE_XML) || (opaq1->format == LY_VALUE_STR_NS)) && (col = strchr(opaq1->value, ':'))) {
1651
        /* XML value with a prefix, try to transform it into a JSON (canonical) value */
1652
0
        mod = ly_resolve_prefix(LYD_CTX(node1), opaq1->value, col - opaq1->value, opaq1->format, opaq1->val_prefix_data);
1653
0
        if (!mod) {
1654
            /* unable to compare */
1655
0
            return LY_ENOT;
1656
0
        }
1657
1658
0
        if (asprintf(&val_dyn, "%s%s", mod->name, col) == -1) {
1659
0
            LOGMEM(LYD_CTX(node1));
1660
0
            return LY_EMEM;
1661
0
        }
1662
0
        val1 = val_dyn;
1663
0
    } else {
1664
0
        val1 = lyd_get_value(node1);
1665
0
    }
1666
0
    if (opaq2 && ((opaq2->format == LY_VALUE_XML) || (opaq2->format == LY_VALUE_STR_NS)) && (col = strchr(opaq2->value, ':'))) {
1667
0
        mod = ly_resolve_prefix(LYD_CTX(node2), opaq2->value, col - opaq2->value, opaq2->format, opaq2->val_prefix_data);
1668
0
        if (!mod) {
1669
0
            return LY_ENOT;
1670
0
        }
1671
1672
0
        assert(!val_dyn);
1673
0
        if (asprintf(&val_dyn, "%s%s", mod->name, col) == -1) {
1674
0
            LOGMEM(LYD_CTX(node2));
1675
0
            return LY_EMEM;
1676
0
        }
1677
0
        val2 = val_dyn;
1678
0
    } else {
1679
0
        val2 = lyd_get_value(node2);
1680
0
    }
1681
1682
    /* compare values */
1683
0
    if (strcmp(val1, val2)) {
1684
0
        rc = LY_ENOT;
1685
0
    }
1686
1687
0
    free(val_dyn);
1688
0
    return rc;
1689
0
}
1690
1691
/**
1692
 * @brief Compare 2 data nodes if they are equivalent regarding the schema tree.
1693
 *
1694
 * Works correctly even if @p node1 and @p node2 have different contexts.
1695
 *
1696
 * @param[in] node1 The first node to compare.
1697
 * @param[in] node2 The second node to compare.
1698
 * @param[in] options Various @ref datacompareoptions.
1699
 * @param[in] parental_schemas_checked Flag set if parent schemas were checked for match.
1700
 * @return LY_SUCCESS if the nodes are equivalent.
1701
 * @return LY_ENOT if the nodes are not equivalent.
1702
 */
1703
static LY_ERR
1704
lyd_compare_single_schema(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
1705
        ly_bool parental_schemas_checked)
1706
0
{
1707
0
    if (LYD_CTX(node1) == LYD_CTX(node2)) {
1708
        /* same contexts */
1709
0
        if (options & LYD_COMPARE_OPAQ) {
1710
0
            if (lyd_node_schema(node1) != lyd_node_schema(node2)) {
1711
0
                return LY_ENOT;
1712
0
            }
1713
0
        } else {
1714
0
            if (node1->schema != node2->schema) {
1715
0
                return LY_ENOT;
1716
0
            }
1717
0
        }
1718
0
    } else {
1719
        /* different contexts */
1720
0
        if (!lyd_compare_schema_equal(node1->schema, node2->schema, 0)) {
1721
0
            return LY_ENOT;
1722
0
        }
1723
0
        if (!parental_schemas_checked) {
1724
0
            if (!lyd_compare_schema_parents_equal(node1, node2)) {
1725
0
                return LY_ENOT;
1726
0
            }
1727
0
            parental_schemas_checked = 1;
1728
0
        }
1729
0
    }
1730
1731
0
    return LY_SUCCESS;
1732
0
}
1733
1734
/**
1735
 * @brief Compare 2 data nodes if they are equivalent regarding the data they contain.
1736
 *
1737
 * Works correctly even if @p node1 and @p node2 have different contexts.
1738
 *
1739
 * @param[in] node1 The first node to compare.
1740
 * @param[in] node2 The second node to compare.
1741
 * @param[in] options Various @ref datacompareoptions.
1742
 * @return LY_SUCCESS if the nodes are equivalent.
1743
 * @return LY_ENOT if the nodes are not equivalent.
1744
 */
1745
static LY_ERR
1746
lyd_compare_single_data(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
1747
0
{
1748
0
    const struct lyd_node *iter1, *iter2;
1749
0
    struct lyd_node_any *any1, *any2;
1750
0
    int len1, len2;
1751
0
    LY_ERR r;
1752
1753
0
    if (!(options & LYD_COMPARE_OPAQ) && (node1->hash != node2->hash)) {
1754
0
        return LY_ENOT;
1755
0
    }
1756
    /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
1757
1758
0
    if (!node1->schema || !node2->schema) {
1759
0
        if (!(options & LYD_COMPARE_OPAQ) && ((node1->schema && !node2->schema) || (!node1->schema && node2->schema))) {
1760
0
            return LY_ENOT;
1761
0
        }
1762
0
        if ((!node1->schema && !node2->schema) || (node1->schema && (node1->schema->nodetype & LYD_NODE_TERM)) ||
1763
0
                (node2->schema && (node2->schema->nodetype & LYD_NODE_TERM))) {
1764
            /* compare values only if there are any to compare */
1765
0
            if ((r = lyd_compare_single_value(node1, node2))) {
1766
0
                return r;
1767
0
            }
1768
0
        }
1769
1770
0
        if (options & LYD_COMPARE_FULL_RECURSION) {
1771
0
            return lyd_compare_siblings_(lyd_child(node1), lyd_child(node2), options, 1);
1772
0
        }
1773
0
        return LY_SUCCESS;
1774
0
    } else {
1775
0
        switch (node1->schema->nodetype) {
1776
0
        case LYS_LEAF:
1777
0
        case LYS_LEAFLIST:
1778
0
            if (options & LYD_COMPARE_DEFAULTS) {
1779
0
                if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1780
0
                    return LY_ENOT;
1781
0
                }
1782
0
            }
1783
0
            if ((r = lyd_compare_single_value(node1, node2))) {
1784
0
                return r;
1785
0
            }
1786
1787
0
            return LY_SUCCESS;
1788
0
        case LYS_CONTAINER:
1789
0
        case LYS_RPC:
1790
0
        case LYS_ACTION:
1791
0
        case LYS_NOTIF:
1792
            /* implicit container is always equal to a container with non-default descendants */
1793
0
            if (options & LYD_COMPARE_FULL_RECURSION) {
1794
0
                return lyd_compare_siblings_(lyd_child(node1), lyd_child(node2), options, 1);
1795
0
            }
1796
0
            return LY_SUCCESS;
1797
0
        case LYS_LIST:
1798
0
            iter1 = lyd_child(node1);
1799
0
            iter2 = lyd_child(node2);
1800
1801
0
            if (options & LYD_COMPARE_FULL_RECURSION) {
1802
0
                return lyd_compare_siblings_(iter1, iter2, options, 1);
1803
0
            } else if (node1->schema->flags & LYS_KEYLESS) {
1804
                /* always equal */
1805
0
                return LY_SUCCESS;
1806
0
            }
1807
1808
            /* lists with keys, their equivalence is based on their keys */
1809
0
            for (const struct lysc_node *key = lysc_node_child(node1->schema);
1810
0
                    key && (key->flags & LYS_KEY);
1811
0
                    key = key->next) {
1812
0
                if (!iter1 || !iter2) {
1813
0
                    return (iter1 == iter2) ? LY_SUCCESS : LY_ENOT;
1814
0
                }
1815
0
                r = lyd_compare_single_schema(iter1, iter2, options, 1);
1816
0
                LY_CHECK_RET(r);
1817
0
                r = lyd_compare_single_data(iter1, iter2, options);
1818
0
                LY_CHECK_RET(r);
1819
1820
0
                iter1 = iter1->next;
1821
0
                iter2 = iter2->next;
1822
0
            }
1823
1824
0
            return LY_SUCCESS;
1825
0
        case LYS_ANYXML:
1826
0
        case LYS_ANYDATA:
1827
0
            any1 = (struct lyd_node_any *)node1;
1828
0
            any2 = (struct lyd_node_any *)node2;
1829
1830
0
            if (!any1->child && !any1->value && !any2->child && !any2->value) {
1831
                /* empty */
1832
0
                return LY_SUCCESS;
1833
0
            }
1834
0
            if ((any1->child && !any2->child) || (any1->value && !any2->value)) {
1835
                /* different value type */
1836
0
                return LY_ENOT;
1837
0
            }
1838
0
            if (any1->child) {
1839
0
                return lyd_compare_siblings_(any1->child, any2->child, options, 1);
1840
0
            } else {
1841
0
                assert(any1->value && any2->value);
1842
1843
0
                len1 = strlen(any1->value);
1844
0
                len2 = strlen(any2->value);
1845
0
                if ((len1 != len2) || strcmp(any1->value, any2->value)) {
1846
0
                    return LY_ENOT;
1847
0
                }
1848
0
                return LY_SUCCESS;
1849
0
            }
1850
0
        }
1851
0
    }
1852
1853
0
    LOGINT(LYD_CTX(node1));
1854
0
    return LY_EINT;
1855
0
}
1856
1857
/**
1858
 * @brief Compare all siblings at a node level.
1859
 *
1860
 * @param[in] node1 First sibling list.
1861
 * @param[in] node2 Second sibling list.
1862
 * @param[in] options Various @ref datacompareoptions.
1863
 * @param[in] parental_schemas_checked Flag set if parent schemas were checked for match.
1864
 * @return LY_SUCCESS if equal.
1865
 * @return LY_ENOT if not equal.
1866
 * @return LY_ERR on error.
1867
 */
1868
static LY_ERR
1869
lyd_compare_siblings_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
1870
        ly_bool parental_schemas_checked)
1871
0
{
1872
0
    LY_ERR r;
1873
0
    const struct lyd_node *iter2;
1874
1875
0
    while (node1 && node2) {
1876
        /* schema match */
1877
0
        r = lyd_compare_single_schema(node1, node2, options, parental_schemas_checked);
1878
0
        LY_CHECK_RET(r);
1879
1880
0
        if (node1->schema && (((node1->schema->nodetype == LYS_LIST) && !(node1->schema->flags & LYS_KEYLESS)) ||
1881
0
                ((node1->schema->nodetype == LYS_LEAFLIST) && (node1->schema->flags & LYS_CONFIG_W))) &&
1882
0
                (node1->schema->flags & LYS_ORDBY_SYSTEM)) {
1883
            /* find a matching instance in case they are ordered differently */
1884
0
            r = lyd_find_sibling_first(node2, node1, (struct lyd_node **)&iter2);
1885
0
            if (r == LY_ENOTFOUND) {
1886
                /* no matching instance, data not equal */
1887
0
                r = LY_ENOT;
1888
0
            }
1889
0
            LY_CHECK_RET(r);
1890
0
        } else {
1891
            /* compare with the current node */
1892
0
            iter2 = node2;
1893
0
        }
1894
1895
        /* data match */
1896
0
        r = lyd_compare_single_data(node1, iter2, options | LYD_COMPARE_FULL_RECURSION);
1897
0
        LY_CHECK_RET(r);
1898
1899
0
        node1 = node1->next;
1900
0
        node2 = node2->next;
1901
0
    }
1902
1903
0
    return (node1 || node2) ? LY_ENOT : LY_SUCCESS;
1904
0
}
1905
1906
LIBYANG_API_DEF LY_ERR
1907
lyd_compare_single(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
1908
0
{
1909
0
    LY_ERR r;
1910
1911
0
    if (!node1 || !node2) {
1912
0
        return (node1 == node2) ? LY_SUCCESS : LY_ENOT;
1913
0
    }
1914
1915
    /* schema match */
1916
0
    if ((r = lyd_compare_single_schema(node1, node2, options, 0))) {
1917
0
        return r;
1918
0
    }
1919
1920
    /* data match */
1921
0
    return lyd_compare_single_data(node1, node2, options);
1922
0
}
1923
1924
LIBYANG_API_DEF LY_ERR
1925
lyd_compare_siblings(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
1926
0
{
1927
0
    return lyd_compare_siblings_(node1, node2, options, 0);
1928
0
}
1929
1930
LIBYANG_API_DEF LY_ERR
1931
lyd_compare_meta(const struct lyd_meta *meta1, const struct lyd_meta *meta2)
1932
0
{
1933
0
    const struct ly_ctx *ctx;
1934
1935
0
    if (!meta1 || !meta2) {
1936
0
        if (meta1 == meta2) {
1937
0
            return LY_SUCCESS;
1938
0
        } else {
1939
0
            return LY_ENOT;
1940
0
        }
1941
0
    }
1942
1943
0
    ctx = meta1->annotation->module->ctx;
1944
0
    if ((ctx != meta2->annotation->module->ctx) || (meta1->annotation != meta2->annotation)) {
1945
0
        return LY_ENOT;
1946
0
    }
1947
1948
0
    return LYSC_GET_TYPE_PLG(meta1->value.realtype->plugin_ref)->compare(ctx, &meta1->value, &meta2->value);
1949
0
}
1950
1951
/**
1952
 * @brief Create a copy of the attribute.
1953
 *
1954
 * @param[in] attr Attribute to copy.
1955
 * @param[in] node Opaque where to append the new attribute.
1956
 * @param[out] dup Optional created attribute copy.
1957
 * @return LY_ERR value.
1958
 */
1959
static LY_ERR
1960
lyd_dup_attr_single(const struct lyd_attr *attr, struct lyd_node *node, struct lyd_attr **dup)
1961
0
{
1962
0
    LY_ERR ret = LY_SUCCESS;
1963
0
    struct lyd_attr *a, *last;
1964
0
    struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)node;
1965
1966
0
    LY_CHECK_ARG_RET(NULL, attr, node, !node->schema, LY_EINVAL);
1967
1968
    /* create a copy */
1969
0
    a = calloc(1, sizeof *attr);
1970
0
    LY_CHECK_ERR_RET(!a, LOGMEM(LYD_CTX(node)), LY_EMEM);
1971
1972
0
    LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->name.name, 0, &a->name.name), finish);
1973
0
    LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->name.prefix, 0, &a->name.prefix), finish);
1974
0
    LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->name.module_ns, 0, &a->name.module_ns), finish);
1975
0
    LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), attr->value, 0, &a->value), finish);
1976
0
    a->hints = attr->hints;
1977
0
    a->format = attr->format;
1978
0
    if (attr->val_prefix_data) {
1979
0
        ret = ly_dup_prefix_data(LYD_CTX(node), attr->format, attr->val_prefix_data, &a->val_prefix_data);
1980
0
        LY_CHECK_GOTO(ret, finish);
1981
0
    }
1982
1983
    /* insert as the last attribute */
1984
0
    a->parent = opaq;
1985
0
    if (opaq->attr) {
1986
0
        for (last = opaq->attr; last->next; last = last->next) {}
1987
0
        last->next = a;
1988
0
    } else {
1989
0
        opaq->attr = a;
1990
0
    }
1991
1992
0
finish:
1993
0
    if (ret) {
1994
0
        lyd_free_attr_single(LYD_CTX(node), a);
1995
0
    } else if (dup) {
1996
0
        *dup = a;
1997
0
    }
1998
0
    return LY_SUCCESS;
1999
0
}
2000
2001
/**
2002
 * @brief Find @p schema equivalent in @p trg_ctx.
2003
 *
2004
 * @param[in] schema Schema node to find.
2005
 * @param[in] trg_ctx Target context to search in.
2006
 * @param[in] parent Data parent of @p schema, if any.
2007
 * @param[in] log Whether to log directly.
2008
 * @param[out] trg_schema Found schema from @p trg_ctx to use.
2009
 * @return LY_RRR value.
2010
 */
2011
static LY_ERR
2012
lyd_find_schema_ctx(const struct lysc_node *schema, const struct ly_ctx *trg_ctx, const struct lyd_node *parent,
2013
        ly_bool log, const struct lysc_node **trg_schema)
2014
0
{
2015
0
    const struct lysc_node *src_parent = NULL, *trg_parent = NULL, *sp, *tp;
2016
0
    const struct lys_module *trg_mod = NULL;
2017
0
    char *path;
2018
2019
0
    if (!schema) {
2020
        /* opaque node */
2021
0
        *trg_schema = NULL;
2022
0
        return LY_SUCCESS;
2023
0
    }
2024
2025
0
    if (lysc_data_parent(schema) && parent && parent->schema) {
2026
        /* start from schema parent */
2027
0
        trg_parent = parent->schema;
2028
0
        src_parent = lysc_data_parent(schema);
2029
0
    }
2030
2031
0
    do {
2032
        /* find the next parent */
2033
0
        sp = schema;
2034
0
        while (lysc_data_parent(sp) != src_parent) {
2035
0
            sp = lysc_data_parent(sp);
2036
0
        }
2037
0
        src_parent = sp;
2038
2039
0
        if (!lysc_data_parent(src_parent)) {
2040
            /* find the module first */
2041
0
            trg_mod = ly_ctx_get_module_implemented(trg_ctx, src_parent->module->name);
2042
0
            if (!trg_mod) {
2043
0
                if (log) {
2044
0
                    LOGERR(trg_ctx, LY_ENOTFOUND, "Module \"%s\" not present/implemented in the target context.",
2045
0
                            src_parent->module->name);
2046
0
                }
2047
0
                return LY_ENOTFOUND;
2048
0
            }
2049
0
        }
2050
2051
        /* find the next parent */
2052
0
        assert(trg_parent || trg_mod);
2053
0
        tp = NULL;
2054
0
        while ((tp = lys_getnext(tp, trg_parent, trg_mod ? trg_mod->compiled : NULL, 0))) {
2055
0
            if (!strcmp(tp->name, src_parent->name) && !strcmp(tp->module->name, src_parent->module->name)) {
2056
0
                break;
2057
0
            }
2058
0
        }
2059
0
        if (!tp) {
2060
            /* schema node not found */
2061
0
            if (log) {
2062
0
                path = lysc_path(src_parent, LYSC_PATH_LOG, NULL, 0);
2063
0
                LOGERR(trg_ctx, LY_ENOTFOUND, "Schema node \"%s\" not found in the target context.", path);
2064
0
                free(path);
2065
0
            }
2066
0
            return LY_ENOTFOUND;
2067
0
        }
2068
2069
0
        trg_parent = tp;
2070
0
    } while (schema != src_parent);
2071
2072
    /* success */
2073
0
    *trg_schema = trg_parent;
2074
0
    return LY_SUCCESS;
2075
0
}
2076
2077
/**
2078
 * @brief Return the top-level context of a subtree of node. Handles extension data nodes.
2079
 *
2080
 * @param[in] node Node to use.
2081
 * @return
2082
 */
2083
static const struct ly_ctx *
2084
lyd_dup_get_top_ctx(const struct lyd_node *node)
2085
0
{
2086
0
    const struct lyd_node *par;
2087
2088
0
    par = node;
2089
0
    while (par && !(par->flags & LYD_EXT)) {
2090
0
        par = par->parent;
2091
0
    }
2092
2093
0
    if (par && par->parent) {
2094
        /* context of the first non-extension parent */
2095
0
        return LYD_CTX(par->parent);
2096
0
    }
2097
2098
    /* context of the node, all the parents have it */
2099
0
    return LYD_CTX(node);
2100
0
}
2101
2102
/**
2103
 * @brief Find (update) the target context for the next node, if needed.
2104
 *
2105
 * @param[in] orig_node First extension data node being processed from the original tree.
2106
 * @param[in] dup_parent Duplicated parent of @p orig_node, set if @p dup_sparent is NULL.
2107
 * @param[in] dup_sparent Schema node of the duplicated parent of @p orig_node, set if @p dup_parent is NULL.
2108
 * @param[in,out] trg_ctx Target context, may be updated.
2109
 * @return LY_ERR value.
2110
 */
2111
static LY_ERR
2112
lyd_find_ext_ctx(const struct lyd_node *orig_node, const struct lyd_node *dup_parent,
2113
        const struct lysc_node *dup_sparent, const struct ly_ctx **trg_ctx)
2114
0
{
2115
0
    LY_ERR r;
2116
0
    const struct lysc_node *snode;
2117
0
    char *path;
2118
2119
0
    assert(orig_node && (orig_node->flags & LYD_EXT) && *trg_ctx);
2120
2121
0
    if (!orig_node->parent) {
2122
        /* treat as a non-extension node */
2123
0
        return LY_SUCCESS;
2124
0
    }
2125
0
    assert(dup_parent || dup_sparent);
2126
2127
0
    if (LYD_CTX(orig_node->parent) == *trg_ctx) {
2128
        /* same contexts, just extension data */
2129
0
        *trg_ctx = LYD_CTX(orig_node);
2130
0
        return LY_SUCCESS;
2131
0
    }
2132
2133
    /* find the extension context to use from the target context */
2134
0
    r = lys_find_child_node_ext(*trg_ctx, NULL, dup_parent, dup_sparent, orig_node->schema->module->name,
2135
0
            strlen(orig_node->schema->module->name), LY_VALUE_JSON, NULL, LYD_NAME(orig_node),
2136
0
            strlen(LYD_NAME(orig_node)), 0, &snode, NULL);
2137
0
    if (r == LY_ENOT) {
2138
0
        path = lyd_path(orig_node, LYD_PATH_STD, NULL, 0);
2139
0
        LOGERR(*trg_ctx, LY_ENOTFOUND, "Schema node of an extension node \"%s\" not found in the target context.", path);
2140
0
        free(path);
2141
0
        return LY_ENOTFOUND;
2142
0
    } else if (r) {
2143
0
        return r;
2144
0
    }
2145
2146
    /* update the context */
2147
0
    *trg_ctx = snode->module->ctx;
2148
0
    return LY_SUCCESS;
2149
0
}
2150
2151
/**
2152
 * @brief Find (update) the target context for the specific nested node, if needed.
2153
 *
2154
 * @param[in] orig_node Nested data node being processed from the original tree.
2155
 * @param[in,out] trg_ctx Target context, may be updated.
2156
 * @return LY_ERR value.
2157
 */
2158
static LY_ERR
2159
lyd_find_ext_ctx_nested(const struct lyd_node *orig_node, const struct ly_ctx **trg_ctx)
2160
0
{
2161
0
    const struct lyd_node *parent;
2162
0
    const struct lysc_node *sparent;
2163
0
    char *path;
2164
2165
0
    if (lyd_dup_get_top_ctx(orig_node) == *trg_ctx) {
2166
        /* it is the same context, use the same one for extension data nodes as well (if node is nested in such data) */
2167
0
        *trg_ctx = LYD_CTX(orig_node);
2168
0
    } else {
2169
        /* not the same context, need to find the right one */
2170
0
        parent = orig_node;
2171
0
        while (parent && !(parent->flags & LYD_EXT)) {
2172
0
            parent = parent->parent;
2173
0
        }
2174
2175
0
        if (parent && parent->parent) {
2176
            /* find the parent schema node in the target context */
2177
0
            path = lysc_path(parent->parent->schema, LYSC_PATH_DATA, NULL, 0);
2178
0
            sparent = lys_find_path(*trg_ctx, NULL, path, 0);
2179
0
            if (!sparent) {
2180
0
                LOGERR(*trg_ctx, LY_ENOTFOUND, "Node \"%s\" was not found in the target context.", path);
2181
0
                free(path);
2182
0
                return LY_ENOTFOUND;
2183
0
            }
2184
0
            free(path);
2185
2186
0
            LY_CHECK_RET(lyd_find_ext_ctx(parent, NULL, sparent, trg_ctx));
2187
0
        }
2188
0
    }
2189
2190
0
    return LY_SUCCESS;
2191
0
}
2192
2193
/**
2194
 * @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
2195
 *
2196
 * Ignores ::LYD_DUP_WITH_PARENTS which is supposed to be handled by lyd_dup().
2197
 *
2198
 * @param[in] node Node to duplicate.
2199
 * @param[in] trg_ctx Target context for duplicated nodes.
2200
 * @param[in] parent Parent to insert into, NULL for top-level sibling.
2201
 * @param[in] insert_order Options for inserting (sorting) duplicated node, @ref insertorder.
2202
 * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
2203
 * @param[in] options Bitmask of options flags, see @ref dupoptions.
2204
 * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it to @p parent / @p first).
2205
 * @return LY_ERR value.
2206
 */
2207
static LY_ERR
2208
lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, uint32_t insert_order,
2209
        struct lyd_node **first, uint32_t options, struct lyd_node **dup_p)
2210
0
{
2211
0
    LY_ERR rc = LY_SUCCESS;
2212
0
    struct lyd_node *dup = NULL;
2213
0
    struct lyd_meta *meta;
2214
0
    struct lyd_attr *attr;
2215
0
    struct lyd_node_any *any;
2216
0
    const struct lysc_type *type;
2217
0
    const char *val_can;
2218
2219
0
    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
2220
2221
0
    if (node->flags & LYD_EXT) {
2222
0
        if (options & LYD_DUP_NO_EXT) {
2223
            /* no not duplicate this subtree */
2224
0
            return LY_SUCCESS;
2225
0
        }
2226
2227
0
        if (parent) {
2228
            /* update the context */
2229
0
            LY_CHECK_GOTO(rc = lyd_find_ext_ctx(node, parent, NULL, &trg_ctx), cleanup);
2230
0
        } /* else called from lyd_dup_get_local_parent() and the context is correct */
2231
0
    }
2232
2233
0
    if (!node->schema) {
2234
0
        dup = calloc(1, sizeof(struct lyd_node_opaq));
2235
0
        ((struct lyd_node_opaq *)dup)->ctx = trg_ctx;
2236
0
    } else {
2237
0
        switch (node->schema->nodetype) {
2238
0
        case LYS_RPC:
2239
0
        case LYS_ACTION:
2240
0
        case LYS_NOTIF:
2241
0
        case LYS_CONTAINER:
2242
0
        case LYS_LIST:
2243
0
            dup = calloc(1, sizeof(struct lyd_node_inner));
2244
0
            break;
2245
0
        case LYS_LEAF:
2246
0
        case LYS_LEAFLIST:
2247
0
            dup = calloc(1, sizeof(struct lyd_node_term));
2248
0
            break;
2249
0
        case LYS_ANYDATA:
2250
0
        case LYS_ANYXML:
2251
0
            dup = calloc(1, sizeof(struct lyd_node_any));
2252
0
            break;
2253
0
        default:
2254
0
            LOGINT(trg_ctx);
2255
0
            rc = LY_EINT;
2256
0
            goto cleanup;
2257
0
        }
2258
0
    }
2259
0
    LY_CHECK_ERR_GOTO(!dup, LOGMEM(trg_ctx); rc = LY_EMEM, cleanup);
2260
2261
0
    if (options & LYD_DUP_WITH_FLAGS) {
2262
0
        dup->flags = node->flags;
2263
0
    } else {
2264
0
        dup->flags = (node->flags & (LYD_DEFAULT | LYD_EXT)) | LYD_NEW;
2265
0
    }
2266
0
    if (options & LYD_DUP_WITH_PRIV) {
2267
0
        dup->priv = node->priv;
2268
0
    }
2269
2270
    /* find schema node */
2271
0
    if (trg_ctx == LYD_CTX(node)) {
2272
0
        dup->schema = node->schema;
2273
0
    } else {
2274
0
        rc = lyd_find_schema_ctx(node->schema, trg_ctx, parent, 1, &dup->schema);
2275
0
        if (rc) {
2276
            /* has no schema but is not an opaque node */
2277
0
            free(dup);
2278
0
            dup = NULL;
2279
0
            goto cleanup;
2280
0
        }
2281
0
    }
2282
0
    dup->prev = dup;
2283
2284
    /* duplicate metadata/attributes */
2285
0
    if (!(options & LYD_DUP_NO_META)) {
2286
0
        if (!node->schema) {
2287
0
            LY_LIST_FOR(((struct lyd_node_opaq *)node)->attr, attr) {
2288
0
                LY_CHECK_GOTO(rc = lyd_dup_attr_single(attr, dup, NULL), cleanup);
2289
0
            }
2290
0
        } else {
2291
0
            LY_LIST_FOR(node->meta, meta) {
2292
0
                LY_CHECK_GOTO(rc = lyd_dup_meta_single_to_ctx(trg_ctx, meta, dup, NULL), cleanup);
2293
0
            }
2294
0
        }
2295
0
    }
2296
2297
    /* nodetype-specific work */
2298
0
    if (!dup->schema) {
2299
0
        struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
2300
0
        struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
2301
0
        struct lyd_node *child;
2302
2303
0
        if (options & LYD_DUP_RECURSIVE) {
2304
            /* duplicate all the children */
2305
0
            LY_LIST_FOR(orig->child, child) {
2306
0
                LY_CHECK_GOTO(rc = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), cleanup);
2307
0
            }
2308
0
        }
2309
0
        LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->name.name, 0, &opaq->name.name), cleanup);
2310
0
        LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->name.prefix, 0, &opaq->name.prefix), cleanup);
2311
0
        LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->name.module_ns, 0, &opaq->name.module_ns), cleanup);
2312
0
        LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->value, 0, &opaq->value), cleanup);
2313
0
        opaq->hints = orig->hints;
2314
0
        opaq->format = orig->format;
2315
0
        if (orig->val_prefix_data) {
2316
0
            rc = ly_dup_prefix_data(trg_ctx, opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
2317
0
            LY_CHECK_GOTO(rc, cleanup);
2318
0
        }
2319
0
    } else if (dup->schema->nodetype & LYD_NODE_TERM) {
2320
0
        struct lyd_node_term *term = (struct lyd_node_term *)dup;
2321
0
        struct lyd_node_term *orig = (struct lyd_node_term *)node;
2322
2323
0
        term->hash = orig->hash;
2324
0
        if (trg_ctx == LYD_CTX(node)) {
2325
0
            rc = LYSC_GET_TYPE_PLG(orig->value.realtype->plugin_ref)->duplicate(trg_ctx, &orig->value, &term->value);
2326
0
            LY_CHECK_ERR_GOTO(rc, LOGERR(trg_ctx, rc, "Value duplication failed."), cleanup);
2327
0
        } else {
2328
            /* store canonical value in the target context */
2329
0
            val_can = lyd_get_value(node);
2330
0
            type = ((struct lysc_node_leaf *)term->schema)->type;
2331
0
            rc = lyd_value_store(trg_ctx, dup, &term->value, type, val_can, strlen(val_can) * 8, 1, 1, NULL,
2332
0
                    LY_VALUE_CANON, NULL, LYD_HINT_DATA, term->schema, NULL);
2333
0
            LY_CHECK_GOTO(rc, cleanup);
2334
0
        }
2335
0
    } else if (dup->schema->nodetype & LYD_NODE_INNER) {
2336
0
        struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
2337
0
        struct lyd_node *child;
2338
2339
0
        if (options & LYD_DUP_RECURSIVE) {
2340
            /* create a hash table with the size of the previous hash table (duplicate) */
2341
0
            if (orig->children_ht) {
2342
0
                ((struct lyd_node_inner *)dup)->children_ht = lyht_new(orig->children_ht->size,
2343
0
                        sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
2344
0
            }
2345
2346
            /* duplicate all the children */
2347
0
            LY_LIST_FOR(orig->child, child) {
2348
0
                LY_CHECK_GOTO(rc = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), cleanup);
2349
0
            }
2350
0
        } else if ((dup->schema->nodetype == LYS_LIST) && !(dup->schema->flags & LYS_KEYLESS)) {
2351
            /* always duplicate keys of a list */
2352
0
            for (child = orig->child; child && lysc_is_key(child->schema); child = child->next) {
2353
0
                LY_CHECK_GOTO(rc = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), cleanup);
2354
0
            }
2355
0
        }
2356
0
        lyd_hash(dup);
2357
2358
        /* NP cont dflt flag */
2359
0
        lyd_np_cont_dflt_set(dup);
2360
0
    } else if (dup->schema->nodetype & LYD_NODE_ANY) {
2361
0
        dup->hash = node->hash;
2362
0
        any = (struct lyd_node_any *)node;
2363
0
        LY_CHECK_GOTO(rc = lyd_any_copy_value(dup, any->child, any->value, any->hints), cleanup);
2364
0
        ((struct lyd_node_any *)dup)->hints = any->hints;
2365
0
    }
2366
2367
    /* insert */
2368
0
    lyd_insert_node(parent, first, dup, insert_order);
2369
2370
0
cleanup:
2371
0
    if (rc) {
2372
0
        lyd_free_tree(dup);
2373
0
    } else if (dup_p) {
2374
0
        *dup_p = dup;
2375
0
    }
2376
0
    return rc;
2377
0
}
2378
2379
/**
2380
 * @brief Get a parent node to connect duplicated subtree to.
2381
 *
2382
 * @param[in] node Node (subtree) to duplicate.
2383
 * @param[in,out] trg_ctx Target context for duplicated nodes, may be updated for @p node.
2384
 * @param[in] parent Initial parent to connect to.
2385
 * @param[in] options Bitmask of options flags, see @ref dupoptions.
2386
 * @param[out] dup_parent First duplicated parent node, if any.
2387
 * @param[out] local_parent Correct parent to directly connect duplicated @p node to.
2388
 * @return LY_ERR value.
2389
 */
2390
static LY_ERR
2391
lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx **trg_ctx, struct lyd_node *parent,
2392
        uint32_t options, struct lyd_node **dup_parent, struct lyd_node **local_parent)
2393
0
{
2394
0
    const struct lyd_node *orig_parent;
2395
0
    const struct ly_ctx *ctx, *top_ctx;
2396
0
    struct lyd_node *iter = NULL;
2397
0
    ly_bool repeat = 1;
2398
2399
0
    assert(node && *trg_ctx);
2400
2401
0
    *dup_parent = NULL;
2402
0
    *local_parent = NULL;
2403
2404
0
    if (!node->parent) {
2405
        /* no parents */
2406
0
        return LY_SUCCESS;
2407
0
    }
2408
2409
    /* adjust the context for node parent correctly */
2410
0
    top_ctx = *trg_ctx;
2411
0
    LY_CHECK_RET(lyd_find_ext_ctx_nested(node->parent, trg_ctx));
2412
0
    ctx = *trg_ctx;
2413
2414
0
    for (orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
2415
0
        if (parent && (LYD_CTX(parent) == LYD_CTX(orig_parent)) && (parent->schema == orig_parent->schema)) {
2416
            /* stop creating parents, connect what we have into the provided parent */
2417
0
            iter = parent;
2418
0
            repeat = 0;
2419
0
        } else if (parent && (LYD_CTX(parent) != LYD_CTX(orig_parent)) &&
2420
0
                lyd_compare_schema_equal(parent->schema, orig_parent->schema, 0) &&
2421
0
                lyd_compare_schema_parents_equal(parent, orig_parent)) {
2422
0
            iter = parent;
2423
0
            repeat = 0;
2424
0
        } else {
2425
0
            iter = NULL;
2426
0
            LY_CHECK_RET(lyd_dup_r(orig_parent, ctx, NULL, LYD_INSERT_NODE_DEFAULT, &iter, options, &iter));
2427
2428
            /* insert into the previous duplicated parent */
2429
0
            if (*dup_parent) {
2430
0
                lyd_insert_node(iter, NULL, *dup_parent, LYD_INSERT_NODE_DEFAULT);
2431
0
            }
2432
2433
            /* update the last duplicated parent */
2434
0
            *dup_parent = iter;
2435
0
        }
2436
2437
        /* set the first parent */
2438
0
        if (!*local_parent) {
2439
0
            *local_parent = iter;
2440
0
        }
2441
2442
0
        if (orig_parent->flags & LYD_EXT) {
2443
            /* parents of the nested extension data, use the original context */
2444
0
            ctx = top_ctx;
2445
0
        }
2446
0
    }
2447
2448
0
    if (repeat && parent) {
2449
        /* given parent and created parents chain actually do not interconnect */
2450
0
        LOGERR(*trg_ctx, LY_EINVAL, "None of the duplicated node \"%s\" schema parents match the provided parent \"%s\".",
2451
0
                LYD_NAME(node), LYD_NAME(parent));
2452
0
        return LY_EINVAL;
2453
0
    }
2454
2455
0
    if (*dup_parent && parent) {
2456
        /* last insert into a prevously-existing parent */
2457
0
        lyd_insert_node(parent, NULL, *dup_parent, LYD_INSERT_NODE_DEFAULT);
2458
0
    }
2459
0
    return LY_SUCCESS;
2460
0
}
2461
2462
static LY_ERR
2463
lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, uint32_t options,
2464
        ly_bool nosiblings, struct lyd_node **dup_p)
2465
0
{
2466
0
    LY_ERR rc;
2467
0
    const struct lyd_node *orig;            /* original node to be duplicated */
2468
0
    struct lyd_node *first_dup = NULL;      /* the first duplicated node, this is returned */
2469
0
    struct lyd_node *top = NULL;            /* the most higher created node */
2470
0
    struct lyd_node *local_parent = NULL;   /* the direct parent node for the duplicated node(s) */
2471
0
    struct lyd_node *dup = NULL;            /* duplicate node */
2472
0
    struct lyd_node *first_sibling = NULL;  /* first sibling node */
2473
0
    const struct lyd_node *first_llist = NULL;  /* first duplicated (leaf-)list node, if any */
2474
0
    uint32_t insert_order;
2475
2476
0
    assert(node && trg_ctx);
2477
2478
    /* create/find parents, adjusts the context as well */
2479
0
    if (options & LYD_DUP_WITH_PARENTS) {
2480
0
        LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, &trg_ctx, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
2481
0
                &top, &local_parent), error);
2482
0
    } else {
2483
0
        local_parent = parent;
2484
0
        LY_CHECK_GOTO(rc = lyd_find_ext_ctx_nested(node, &trg_ctx), error);
2485
0
    }
2486
2487
0
    LY_LIST_FOR(node, orig) {
2488
0
        if (lysc_is_key(orig->schema)) {
2489
0
            if (local_parent) {
2490
                /* the key must already exist in the parent */
2491
0
                rc = lyd_find_sibling_schema(lyd_child(local_parent), orig->schema, &dup);
2492
0
                LY_CHECK_ERR_GOTO(rc, LOGINT(trg_ctx), error);
2493
0
            } else {
2494
0
                assert(!(options & LYD_DUP_WITH_PARENTS));
2495
                /* duplicating a single key, okay, I suppose... */
2496
0
                rc = lyd_dup_r(orig, trg_ctx, NULL, LYD_INSERT_NODE_DEFAULT, &first_sibling, options, &dup);
2497
0
                LY_CHECK_GOTO(rc, error);
2498
0
            }
2499
0
        } else {
2500
            /* decide insert order */
2501
0
            insert_order = (options & LYD_DUP_NO_LYDS) ? LYD_INSERT_NODE_LAST_BY_SCHEMA : LYD_INSERT_NODE_DEFAULT;
2502
0
            if (first_llist) {
2503
0
                if (orig->schema != first_llist->schema) {
2504
                    /* all the (leaf-)list instances duplicated */
2505
0
                    first_llist = NULL;
2506
0
                } else {
2507
                    /* duplicating all the instances of a (leaf-)list, no need to change their order */
2508
0
                    insert_order = LYD_INSERT_NODE_LAST;
2509
0
                }
2510
0
            } else if (orig->schema && (orig->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
2511
                /* duplicating the first (leaf-)list instance, duplicate the rest more efficiently */
2512
0
                first_llist = orig;
2513
0
            }
2514
2515
            /* duplicate the node */
2516
0
            rc = lyd_dup_r(orig, trg_ctx, local_parent, insert_order, &first_sibling, options, &dup);
2517
0
            LY_CHECK_GOTO(rc, error);
2518
2519
0
            if (first_llist && dup->next) {
2520
                /* orig was not the last node (because we are inserting into a parent with some previous instances),
2521
                 * we must check find the order */
2522
0
                first_llist = NULL;
2523
0
            }
2524
0
        }
2525
0
        first_dup = first_dup ? first_dup : dup;
2526
2527
0
        if (nosiblings) {
2528
0
            break;
2529
0
        }
2530
0
    }
2531
2532
0
    if (dup_p) {
2533
0
        *dup_p = first_dup;
2534
0
    }
2535
0
    return LY_SUCCESS;
2536
2537
0
error:
2538
0
    if (top) {
2539
0
        lyd_free_tree(top);
2540
0
    } else if (first_dup) {
2541
0
        lyd_free_siblings(first_dup);
2542
0
    } else {
2543
0
        lyd_free_siblings(dup);
2544
0
    }
2545
0
    return rc;
2546
0
}
2547
2548
LIBYANG_API_DEF LY_ERR
2549
lyd_dup_single(const struct lyd_node *node, struct lyd_node *parent, uint32_t options, struct lyd_node **dup)
2550
0
{
2551
0
    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
2552
0
    if (parent && (lyd_dup_get_top_ctx(node) != lyd_dup_get_top_ctx(parent))) {
2553
0
        LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"node\" and \"parent\" contexts used in node duplication.");
2554
0
        return LY_EINVAL;
2555
0
    }
2556
2557
0
    return lyd_dup(node, lyd_dup_get_top_ctx(node), parent, options, 1, dup);
2558
0
}
2559
2560
LIBYANG_API_DEF LY_ERR
2561
lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
2562
        uint32_t options, struct lyd_node **dup)
2563
0
{
2564
0
    LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
2565
0
    if (parent && (trg_ctx != lyd_dup_get_top_ctx(parent))) {
2566
0
        LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"trg_ctx\" and \"parent\" contexts used in node duplication.");
2567
0
        return LY_EINVAL;
2568
0
    }
2569
2570
0
    return lyd_dup(node, trg_ctx, parent, options, 1, dup);
2571
0
}
2572
2573
LIBYANG_API_DEF LY_ERR
2574
lyd_dup_siblings(const struct lyd_node *node, struct lyd_node *parent, uint32_t options, struct lyd_node **dup)
2575
0
{
2576
0
    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
2577
0
    if (parent && (lyd_dup_get_top_ctx(node) != lyd_dup_get_top_ctx(parent))) {
2578
0
        LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"node\" and \"parent\" contexts used in node duplication.");
2579
0
        return LY_EINVAL;
2580
0
    }
2581
2582
0
    return lyd_dup(node, lyd_dup_get_top_ctx(node), parent, options, 0, dup);
2583
0
}
2584
2585
LIBYANG_API_DEF LY_ERR
2586
lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
2587
        uint32_t options, struct lyd_node **dup)
2588
0
{
2589
0
    LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
2590
0
    if (parent && (trg_ctx != lyd_dup_get_top_ctx(parent))) {
2591
0
        LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"trg_ctx\" and \"parent\" contexts used in node duplication.");
2592
0
        return LY_EINVAL;
2593
0
    }
2594
2595
0
    return lyd_dup(node, trg_ctx, parent, options, 0, dup);
2596
0
}
2597
2598
LY_ERR
2599
lyd_dup_meta_single_to_ctx(const struct ly_ctx *parent_ctx, const struct lyd_meta *meta, struct lyd_node *parent,
2600
        struct lyd_meta **dup)
2601
0
{
2602
0
    LY_ERR ret = LY_SUCCESS;
2603
0
    struct lyd_meta *mt, *last;
2604
0
    const struct lysc_type *ant_type;
2605
0
    struct lys_module *mod;
2606
0
    const char *val_can;
2607
2608
0
    LY_CHECK_ARG_RET(NULL, meta, parent, LY_EINVAL);
2609
2610
    /* create a copy */
2611
0
    mt = calloc(1, sizeof *mt);
2612
0
    LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_CTX(parent)), LY_EMEM);
2613
2614
0
    if (parent_ctx != meta->annotation->module->ctx) {
2615
        /* different contexts */
2616
0
        mod = ly_ctx_get_module(parent_ctx, meta->annotation->module->name, meta->annotation->module->revision);
2617
2618
        /* annotation */
2619
0
        mt->annotation = lyd_get_meta_annotation(mod, meta->name, strlen(meta->name));
2620
0
        lyplg_ext_get_storage(mt->annotation, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type);
2621
0
        LY_CHECK_ERR_GOTO((ret = mt->annotation ? LY_SUCCESS : LY_EINVAL), LOGERR(parent_ctx, LY_EINVAL,
2622
0
                "Annotation for metadata %s not found, value duplication failed.", meta->name), finish);
2623
2624
        /* duplicate callback expect only the same contexts, so use the store callback */
2625
0
        val_can = lyd_value_get_canonical(meta->annotation->module->ctx, &meta->value);
2626
0
        ret = lyd_value_store(parent_ctx, parent, &mt->value, ant_type, val_can, strlen(val_can) * 8, 1, 1, NULL,
2627
0
                LY_VALUE_CANON, NULL, LYD_HINT_DATA, parent->schema, NULL);
2628
0
    } else {
2629
        /* annotation */
2630
0
        mt->annotation = meta->annotation;
2631
        /* duplication of value */
2632
0
        ret = LYSC_GET_TYPE_PLG(meta->value.realtype->plugin_ref)->duplicate(parent_ctx, &meta->value, &mt->value);
2633
0
    }
2634
0
    LY_CHECK_ERR_GOTO(ret, LOGERR(LYD_CTX(parent), LY_EINT, "Value duplication failed."), finish);
2635
0
    LY_CHECK_GOTO(ret = lydict_insert(parent_ctx, meta->name, 0, &mt->name), finish);
2636
2637
    /* insert as the last attribute */
2638
0
    mt->parent = parent;
2639
0
    if (parent->meta) {
2640
0
        for (last = parent->meta; last->next; last = last->next) {}
2641
0
        last->next = mt;
2642
0
    } else {
2643
0
        parent->meta = mt;
2644
0
    }
2645
2646
0
finish:
2647
0
    if (ret) {
2648
0
        lyd_free_meta_single(mt);
2649
0
    } else if (dup) {
2650
0
        *dup = mt;
2651
0
    }
2652
0
    return LY_SUCCESS;
2653
0
}
2654
2655
LIBYANG_API_DEF LY_ERR
2656
lyd_dup_meta_single(const struct lyd_meta *meta, struct lyd_node *node, struct lyd_meta **dup)
2657
0
{
2658
0
    LY_CHECK_ARG_RET(NULL, meta, LY_EINVAL);
2659
2660
    /* log to node context but value must always use the annotation context */
2661
0
    return lyd_dup_meta_single_to_ctx(meta->annotation->module->ctx, meta, node, dup);
2662
0
}
2663
2664
/**
2665
 * @brief Merge a source sibling into target siblings.
2666
 *
2667
 * @param[in,out] first_trg First target sibling, is updated if top-level.
2668
 * @param[in] parent_trg Target parent.
2669
 * @param[in,out] sibling_src_p Source sibling to merge, set to NULL if spent.
2670
 * @param[in] merge_cb Optional merge callback.
2671
 * @param[in] cb_data Arbitrary callback data.
2672
 * @param[in] options Merge options.
2673
 * @param[in] lyds Pool of lyds data which can be reused.
2674
 * @param[in,out] leader_p Cached first instance of target (leaf-)list.
2675
 * @param[in,out] dup_inst Duplicate instance cache for all @p first_trg siblings.
2676
 * @return LY_ERR value.
2677
 */
2678
static LY_ERR
2679
lyd_merge_sibling_r(struct lyd_node **first_trg, struct lyd_node *parent_trg,
2680
        const struct lyd_node **sibling_src_p, lyd_merge_cb merge_cb, void *cb_data, uint16_t options,
2681
        struct lyds_pool *lyds, struct lyd_node **leader_p, struct ly_ht **dup_inst)
2682
0
{
2683
0
    const struct lyd_node *child_src, *tmp, *sibling_src;
2684
0
    struct lyd_node *match_trg, *dup_src, *elem, *leader;
2685
0
    struct lyd_node_opaq *opaq_trg, *opaq_src;
2686
0
    const struct lyd_node_any *any;
2687
0
    const struct lysc_node *schema;
2688
0
    struct ly_ht *child_dup_inst = NULL;
2689
0
    LY_ERR r;
2690
0
    ly_bool first_inst = 0;
2691
2692
0
    sibling_src = *sibling_src_p;
2693
0
    if (!sibling_src->schema) {
2694
        /* try to find the same opaque node */
2695
0
        r = lyd_find_sibling_opaq_next(*first_trg, LYD_NAME(sibling_src), &match_trg);
2696
0
    } else if (sibling_src->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2697
        /* try to find the exact instance */
2698
0
        r = lyd_find_sibling_first(*first_trg, sibling_src, &match_trg);
2699
0
    } else {
2700
        /* try to simply find the node, there cannot be more instances */
2701
0
        r = lyd_find_sibling_val(*first_trg, sibling_src->schema, NULL, 0, &match_trg);
2702
0
    }
2703
0
    LY_CHECK_RET(r && (r != LY_ENOTFOUND), r);
2704
2705
0
    if (match_trg) {
2706
        /* update match as needed */
2707
0
        LY_CHECK_RET(lyd_dup_inst_next(&match_trg, dup_inst));
2708
0
    } else {
2709
        /* first instance of this node */
2710
0
        first_inst = 1;
2711
0
    }
2712
2713
0
    if (match_trg) {
2714
        /* call callback */
2715
0
        if (merge_cb) {
2716
0
            LY_CHECK_RET(merge_cb(match_trg, sibling_src, cb_data));
2717
0
        }
2718
2719
        /* node found, make sure even value matches for all node types */
2720
0
        if (!match_trg->schema) {
2721
0
            if (lyd_compare_single(sibling_src, match_trg, 0)) {
2722
                /* update value */
2723
0
                opaq_trg = (struct lyd_node_opaq *)match_trg;
2724
0
                opaq_src = (struct lyd_node_opaq *)sibling_src;
2725
2726
0
                lydict_remove(LYD_CTX(opaq_trg), opaq_trg->value);
2727
0
                lydict_insert(LYD_CTX(opaq_trg), opaq_src->value, 0, &opaq_trg->value);
2728
0
                opaq_trg->hints = opaq_src->hints;
2729
2730
0
                ly_free_prefix_data(opaq_trg->format, opaq_trg->val_prefix_data);
2731
0
                opaq_trg->format = opaq_src->format;
2732
0
                ly_dup_prefix_data(LYD_CTX(opaq_trg), opaq_src->format, opaq_src->val_prefix_data,
2733
0
                        &opaq_trg->val_prefix_data);
2734
0
            }
2735
0
        } else if ((match_trg->schema->nodetype == LYS_LEAF) &&
2736
0
                ((options & LYD_MERGE_DEFAULTS) || !(sibling_src->flags & LYD_DEFAULT))) {
2737
            /* update value */
2738
0
            r = lyd_change_term_val(match_trg, &((struct lyd_node_term *)sibling_src)->value, 0,
2739
0
                    sibling_src->flags & LYD_DEFAULT);
2740
0
            LY_CHECK_RET(r && (r != LY_EEXIST) && (r != LY_ENOT), r);
2741
2742
0
            if (options & LYD_MERGE_WITH_FLAGS) {
2743
                /* keep the exact same flags */
2744
0
                match_trg->flags = sibling_src->flags;
2745
0
            }
2746
0
        } else if ((match_trg->schema->nodetype & LYS_ANYDATA) && lyd_compare_single(sibling_src, match_trg, 0)) {
2747
            /* update value */
2748
0
            any = (const struct lyd_node_any *)sibling_src;
2749
0
            LY_CHECK_RET(lyd_any_copy_value(match_trg, any->child, any->value, any->hints));
2750
2751
            /* copy flags and add LYD_NEW */
2752
0
            match_trg->flags = sibling_src->flags | ((options & LYD_MERGE_WITH_FLAGS) ? 0 : LYD_NEW);
2753
0
        }
2754
2755
        /* check descendants, recursively */
2756
0
        r = LY_SUCCESS;
2757
0
        leader = NULL;
2758
0
        schema = NULL;
2759
0
        LY_LIST_FOR_SAFE(lyd_child_no_keys(sibling_src), tmp, child_src) {
2760
0
            if ((options & LYD_MERGE_DESTRUCT) && (schema != child_src->schema) && LYDS_NODE_IS_LEADER(child_src)) {
2761
0
                schema = child_src->schema;
2762
                /* unlink lyds data and add them to the pool */
2763
0
                lyds_pool_add((struct lyd_node *)child_src, lyds);
2764
0
            }
2765
2766
0
            r = lyd_merge_sibling_r(lyd_node_child_p(match_trg), match_trg, &child_src,
2767
0
                    merge_cb, cb_data, options, lyds, &leader, &child_dup_inst);
2768
0
            if (r) {
2769
0
                break;
2770
0
            }
2771
0
        }
2772
2773
0
        lyd_dup_inst_free(child_dup_inst);
2774
0
        LY_CHECK_RET(r);
2775
0
    } else {
2776
        /* node not found, merge it */
2777
0
        if (options & LYD_MERGE_DESTRUCT) {
2778
0
            dup_src = (struct lyd_node *)sibling_src;
2779
0
            lyd_unlink_ignore_lyds(NULL, dup_src);
2780
            /* spend it */
2781
0
            *sibling_src_p = NULL;
2782
0
        } else {
2783
0
            LY_CHECK_RET(lyd_dup_single(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS, &dup_src));
2784
0
        }
2785
2786
0
        if (!(options & LYD_MERGE_WITH_FLAGS)) {
2787
            /* set LYD_NEW for all the new nodes, required for validation */
2788
0
            LYD_TREE_DFS_BEGIN(dup_src, elem) {
2789
0
                elem->flags |= LYD_NEW;
2790
0
                LYD_TREE_DFS_END(dup_src, elem);
2791
0
            }
2792
0
        }
2793
2794
0
        if (lyds->rbn) {
2795
            /* insert node and try to reuse free lyds data */
2796
0
            lyds_insert2(parent_trg, first_trg, leader_p, dup_src, lyds);
2797
0
        } else {
2798
            /* generic insert node */
2799
0
            lyd_insert_node(parent_trg, first_trg, dup_src, LYD_INSERT_NODE_DEFAULT);
2800
0
        }
2801
2802
0
        if (first_inst) {
2803
            /* remember not to find this instance next time */
2804
0
            LY_CHECK_RET(lyd_dup_inst_next(&dup_src, dup_inst));
2805
0
        }
2806
2807
        /* call callback, no source node */
2808
0
        if (merge_cb) {
2809
0
            LY_CHECK_RET(merge_cb(dup_src, NULL, cb_data));
2810
0
        }
2811
0
    }
2812
2813
0
    return LY_SUCCESS;
2814
0
}
2815
2816
static LY_ERR
2817
lyd_merge(struct lyd_node **target, const struct lyd_node *source, const struct lys_module *mod,
2818
        lyd_merge_cb merge_cb, void *cb_data, uint16_t options, ly_bool nosiblings)
2819
0
{
2820
0
    const struct lyd_node *sibling_src, *tmp;
2821
0
    const struct lysc_node *schema;
2822
0
    struct lyd_node *leader;
2823
0
    struct ly_ht *dup_inst = NULL;
2824
0
    ly_bool first;
2825
0
    LY_ERR ret = LY_SUCCESS;
2826
0
    struct lyds_pool lyds = {0};
2827
2828
0
    LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
2829
0
    LY_CHECK_CTX_EQUAL_RET(__func__, *target ? LYD_CTX(*target) : NULL, source ? LYD_CTX(source) : NULL,
2830
0
            mod ? mod->ctx : NULL, LY_EINVAL);
2831
2832
0
    if (!source) {
2833
        /* nothing to merge */
2834
0
        return LY_SUCCESS;
2835
0
    }
2836
2837
0
    if ((*target && lysc_data_parent((*target)->schema)) || lysc_data_parent(source->schema)) {
2838
0
        LOGERR(LYD_CTX(source), LY_EINVAL, "Invalid arguments - can merge only 2 top-level subtrees (%s()).", __func__);
2839
0
        return LY_EINVAL;
2840
0
    }
2841
2842
0
    leader = NULL;
2843
0
    schema = NULL;
2844
0
    LY_LIST_FOR_SAFE(source, tmp, sibling_src) {
2845
0
        if (mod && (lyd_owner_module(sibling_src) != mod)) {
2846
            /* skip data nodes from different modules */
2847
0
            continue;
2848
0
        }
2849
2850
0
        if ((options & LYD_MERGE_DESTRUCT) && (schema != sibling_src->schema) && LYDS_NODE_IS_LEADER(sibling_src)) {
2851
0
            schema = sibling_src->schema;
2852
            /* unlink lyds data and add them to the pool */
2853
0
            lyds_pool_add((struct lyd_node *)sibling_src, &lyds);
2854
0
        }
2855
2856
0
        first = (sibling_src == source) ? 1 : 0;
2857
0
        ret = lyd_merge_sibling_r(target, NULL, &sibling_src, merge_cb, cb_data, options,
2858
0
                &lyds, &leader, &dup_inst);
2859
0
        if (ret) {
2860
0
            break;
2861
0
        }
2862
0
        if (first && !sibling_src) {
2863
            /* source was spent (unlinked), move to the next node */
2864
0
            source = tmp;
2865
0
        }
2866
2867
0
        if (nosiblings) {
2868
0
            break;
2869
0
        }
2870
0
    }
2871
0
    lyds_pool_clean(&lyds);
2872
2873
0
    if (options & LYD_MERGE_DESTRUCT) {
2874
        /* free any leftover source data that were not merged */
2875
0
        lyd_free_siblings((struct lyd_node *)source);
2876
0
    }
2877
2878
0
    lyd_dup_inst_free(dup_inst);
2879
0
    return ret;
2880
0
}
2881
2882
LIBYANG_API_DEF LY_ERR
2883
lyd_merge_tree(struct lyd_node **target, const struct lyd_node *source, uint16_t options)
2884
0
{
2885
0
    return lyd_merge(target, source, NULL, NULL, NULL, options, 1);
2886
0
}
2887
2888
LIBYANG_API_DEF LY_ERR
2889
lyd_merge_siblings(struct lyd_node **target, const struct lyd_node *source, uint16_t options)
2890
0
{
2891
0
    return lyd_merge(target, source, NULL, NULL, NULL, options, 0);
2892
0
}
2893
2894
LIBYANG_API_DEF LY_ERR
2895
lyd_merge_module(struct lyd_node **target, const struct lyd_node *source, const struct lys_module *mod,
2896
        lyd_merge_cb merge_cb, void *cb_data, uint16_t options)
2897
0
{
2898
0
    return lyd_merge(target, source, mod, merge_cb, cb_data, options, 0);
2899
0
}
2900
2901
static LY_ERR
2902
lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, ly_bool is_static)
2903
0
{
2904
    /* ending \0 */
2905
0
    ++reqlen;
2906
2907
0
    if (reqlen > *buflen) {
2908
0
        if (is_static) {
2909
0
            return LY_EINCOMPLETE;
2910
0
        }
2911
2912
0
        *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
2913
0
        if (!*buffer) {
2914
0
            return LY_EMEM;
2915
0
        }
2916
2917
0
        *buflen = reqlen;
2918
0
    }
2919
2920
0
    return LY_SUCCESS;
2921
0
}
2922
2923
LY_ERR
2924
lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
2925
0
{
2926
0
    const struct lyd_node *key;
2927
0
    size_t len;
2928
0
    const char *val;
2929
0
    char quot;
2930
2931
0
    for (key = lyd_child(node); key && key->schema && (key->schema->flags & LYS_KEY); key = key->next) {
2932
0
        val = lyd_get_value(key);
2933
0
        len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
2934
0
        LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
2935
2936
0
        LY_CHECK_RET(ly_val_get_quot(LYD_CTX(node), val, &quot));
2937
0
        *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
2938
0
    }
2939
2940
0
    return LY_SUCCESS;
2941
0
}
2942
2943
/**
2944
 * @brief Append leaf-list value predicate to path.
2945
 *
2946
 * @param[in] node Node to print.
2947
 * @param[in,out] buffer Buffer to print to.
2948
 * @param[in,out] buflen Current buffer length.
2949
 * @param[in,out] bufused Current number of characters used in @p buffer.
2950
 * @param[in] is_static Whether buffer is static or can be reallocated.
2951
 * @return LY_ERR value.
2952
 */
2953
static LY_ERR
2954
lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
2955
0
{
2956
0
    size_t len;
2957
0
    const char *val;
2958
0
    char quot;
2959
2960
0
    val = lyd_get_value(node);
2961
0
    len = 4 + strlen(val) + 2; /* "[.='" + val + "']" */
2962
0
    LY_CHECK_RET(lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static));
2963
2964
0
    LY_CHECK_RET(ly_val_get_quot(LYD_CTX(node), val, &quot));
2965
0
    *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
2966
2967
0
    return LY_SUCCESS;
2968
0
}
2969
2970
/**
2971
 * @brief Append node position (relative to its other instances) predicate to path.
2972
 *
2973
 * @param[in] node Node to print.
2974
 * @param[in,out] buffer Buffer to print to.
2975
 * @param[in,out] buflen Current buffer length.
2976
 * @param[in,out] bufused Current number of characters used in @p buffer.
2977
 * @param[in] is_static Whether buffer is static or can be reallocated.
2978
 * @return LY_ERR
2979
 */
2980
static LY_ERR
2981
lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static)
2982
0
{
2983
0
    size_t len;
2984
0
    uint32_t pos;
2985
0
    char *val = NULL;
2986
0
    LY_ERR rc;
2987
2988
0
    pos = lyd_list_pos(node);
2989
0
    if (asprintf(&val, "%" PRIu32, pos) == -1) {
2990
0
        return LY_EMEM;
2991
0
    }
2992
2993
0
    len = 1 + strlen(val) + 1;
2994
0
    rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2995
0
    if (rc != LY_SUCCESS) {
2996
0
        goto cleanup;
2997
0
    }
2998
2999
0
    *bufused += sprintf(*buffer + *bufused, "[%s]", val);
3000
3001
0
cleanup:
3002
0
    free(val);
3003
0
    return rc;
3004
0
}
3005
3006
LIBYANG_API_DEF char *
3007
lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
3008
0
{
3009
0
    ly_bool is_static = 0;
3010
0
    uint32_t i, depth;
3011
0
    size_t bufused = 0, len;
3012
0
    const struct lyd_node *iter, *parent;
3013
0
    const struct lys_module *mod, *prev_mod;
3014
0
    LY_ERR rc = LY_SUCCESS;
3015
3016
0
    LY_CHECK_ARG_RET(NULL, node, NULL);
3017
0
    if (buffer) {
3018
0
        LY_CHECK_ARG_RET(LYD_CTX(node), buflen > 1, NULL);
3019
0
        is_static = 1;
3020
0
    } else {
3021
0
        buflen = 0;
3022
0
    }
3023
3024
0
    switch (pathtype) {
3025
0
    case LYD_PATH_STD:
3026
0
    case LYD_PATH_STD_NO_LAST_PRED:
3027
0
        depth = 1;
3028
0
        for (iter = node; iter->parent; iter = iter->parent) {
3029
0
            ++depth;
3030
0
        }
3031
3032
0
        goto iter_print;
3033
0
        while (depth) {
3034
            /* find the right node */
3035
0
            for (iter = node, i = 1; i < depth; iter = iter->parent, ++i) {}
3036
0
iter_print:
3037
            /* get the module */
3038
0
            mod = lyd_node_module(iter);
3039
0
            parent = iter->parent;
3040
0
            prev_mod = lyd_node_module(parent);
3041
0
            if (prev_mod == mod) {
3042
0
                mod = NULL;
3043
0
            }
3044
3045
            /* realloc string */
3046
0
            len = 1 + (mod ? strlen(mod->name) + 1 : 0) + (iter->schema ? strlen(iter->schema->name) :
3047
0
                    strlen(((struct lyd_node_opaq *)iter)->name.name));
3048
0
            rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
3049
0
            if (rc) {
3050
0
                break;
3051
0
            }
3052
3053
            /* print next node */
3054
0
            bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", LYD_NAME(iter));
3055
3056
            /* do not always print the last (first) predicate */
3057
0
            if (iter->schema && ((depth > 1) || (pathtype == LYD_PATH_STD))) {
3058
0
                switch (iter->schema->nodetype) {
3059
0
                case LYS_LIST:
3060
0
                    if (iter->schema->flags & LYS_KEYLESS) {
3061
                        /* print its position */
3062
0
                        rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
3063
0
                    } else {
3064
                        /* print all list keys in predicates */
3065
0
                        rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
3066
0
                    }
3067
0
                    break;
3068
0
                case LYS_LEAFLIST:
3069
0
                    if (iter->schema->flags & LYS_CONFIG_W) {
3070
                        /* print leaf-list value */
3071
0
                        rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
3072
0
                    } else {
3073
                        /* print its position */
3074
0
                        rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
3075
0
                    }
3076
0
                    break;
3077
0
                default:
3078
                    /* nothing to print more */
3079
0
                    break;
3080
0
                }
3081
0
            }
3082
0
            if (rc) {
3083
0
                break;
3084
0
            }
3085
3086
0
            --depth;
3087
0
        }
3088
0
        break;
3089
0
    }
3090
3091
0
    if (rc && !is_static) {
3092
0
        free(buffer);
3093
0
        buffer = NULL;
3094
0
    }
3095
0
    return buffer;
3096
0
}
3097
3098
char *
3099
lyd_path_set(const struct ly_set *dnodes, LYD_PATH_TYPE pathtype)
3100
0
{
3101
0
    uint32_t depth;
3102
0
    size_t bufused = 0, buflen = 0, len;
3103
0
    char *buffer = NULL;
3104
0
    const struct lyd_node *iter, *parent;
3105
0
    const struct lys_module *mod, *prev_mod;
3106
0
    LY_ERR rc = LY_SUCCESS;
3107
3108
0
    switch (pathtype) {
3109
0
    case LYD_PATH_STD:
3110
0
    case LYD_PATH_STD_NO_LAST_PRED:
3111
0
        for (depth = 1; depth <= dnodes->count; ++depth) {
3112
            /* current node */
3113
0
            iter = dnodes->dnodes[depth - 1];
3114
0
            mod = lyd_node_module(iter);
3115
3116
            /* parent */
3117
0
            parent = (depth > 1) ? dnodes->dnodes[depth - 2] : NULL;
3118
0
            assert(!parent || !iter->schema || !parent->schema || (parent->schema->nodetype & LYD_NODE_ANY) ||
3119
0
                    (lysc_data_parent(iter->schema) == parent->schema) || !lysc_data_parent(iter->schema) ||
3120
0
                    (parent->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)));
3121
3122
            /* get module to print, if any */
3123
0
            prev_mod = lyd_node_module(parent);
3124
0
            if (prev_mod == mod) {
3125
0
                mod = NULL;
3126
0
            }
3127
3128
            /* realloc string */
3129
0
            len = 1 + (mod ? strlen(mod->name) + 1 : 0) + (iter->schema ? strlen(iter->schema->name) :
3130
0
                    strlen(((struct lyd_node_opaq *)iter)->name.name));
3131
0
            if ((rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, 0))) {
3132
0
                break;
3133
0
            }
3134
3135
            /* print next node */
3136
0
            bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", LYD_NAME(iter));
3137
3138
            /* do not always print the last (first) predicate */
3139
0
            if (iter->schema && ((depth > 1) || (pathtype == LYD_PATH_STD))) {
3140
0
                switch (iter->schema->nodetype) {
3141
0
                case LYS_LIST:
3142
0
                    if (iter->schema->flags & LYS_KEYLESS) {
3143
                        /* print its position */
3144
0
                        rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, 0);
3145
0
                    } else {
3146
                        /* print all list keys in predicates */
3147
0
                        rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, 0);
3148
0
                    }
3149
0
                    break;
3150
0
                case LYS_LEAFLIST:
3151
0
                    if (iter->schema->flags & LYS_CONFIG_W) {
3152
                        /* print leaf-list value */
3153
0
                        rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, 0);
3154
0
                    } else {
3155
                        /* print its position */
3156
0
                        rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, 0);
3157
0
                    }
3158
0
                    break;
3159
0
                default:
3160
                    /* nothing to print more */
3161
0
                    break;
3162
0
                }
3163
0
            }
3164
0
            if (rc) {
3165
0
                break;
3166
0
            }
3167
0
        }
3168
0
        break;
3169
0
    }
3170
3171
0
    return buffer;
3172
0
}
3173
3174
LIBYANG_API_DEF struct lyd_meta *
3175
lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module, const char *name)
3176
0
{
3177
0
    struct lyd_meta *ret = NULL;
3178
0
    const struct ly_ctx *ctx;
3179
0
    const char *prefix, *tmp;
3180
0
    char *str;
3181
0
    uint32_t pref_len, name_len;
3182
3183
0
    LY_CHECK_ARG_RET(NULL, module || strchr(name, ':'), name, NULL);
3184
0
    LY_CHECK_CTX_EQUAL_RET(__func__, first ? first->annotation->module->ctx : NULL, module ? module->ctx : NULL, NULL);
3185
3186
0
    if (!first) {
3187
0
        return NULL;
3188
0
    }
3189
3190
0
    ctx = first->annotation->module->ctx;
3191
3192
    /* parse the name */
3193
0
    tmp = name;
3194
0
    if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
3195
0
        LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
3196
0
        return NULL;
3197
0
    }
3198
3199
    /* find the module */
3200
0
    if (prefix) {
3201
0
        str = strndup(prefix, pref_len);
3202
0
        module = ly_ctx_get_module_latest(ctx, str);
3203
0
        free(str);
3204
0
        LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", (int)pref_len, prefix), NULL);
3205
0
    }
3206
3207
    /* find the metadata */
3208
0
    LY_LIST_FOR(first, first) {
3209
0
        if ((first->annotation->module == module) && !strcmp(first->name, name)) {
3210
0
            ret = (struct lyd_meta *)first;
3211
0
            break;
3212
0
        }
3213
0
    }
3214
3215
0
    return ret;
3216
0
}
3217
3218
LIBYANG_API_DEF LY_ERR
3219
lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
3220
0
{
3221
0
    struct lyd_node **match_p, *iter, *parent;
3222
0
    ly_bool found;
3223
3224
0
    LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
3225
3226
0
    if (!siblings) {
3227
        /* no data */
3228
0
        if (match) {
3229
0
            *match = NULL;
3230
0
        }
3231
0
        return LY_ENOTFOUND;
3232
0
    }
3233
3234
0
    if ((siblings->schema && target->schema &&
3235
0
            !lyd_compare_schema_equal(lysc_data_parent(siblings->schema), lysc_data_parent(target->schema), 1))) {
3236
        /* schema mismatch */
3237
0
        if (match) {
3238
0
            *match = NULL;
3239
0
        }
3240
0
        return LY_ENOTFOUND;
3241
0
    }
3242
3243
    /* get first sibling */
3244
0
    siblings = lyd_first_sibling(siblings);
3245
3246
0
    parent = siblings->parent;
3247
0
    if (target->schema && parent && parent->schema && ((struct lyd_node_inner *)parent)->children_ht) {
3248
0
        assert(target->hash);
3249
3250
0
        if (lysc_is_dup_inst_list(target->schema)) {
3251
            /* we must search the instances from beginning to find the first matching one */
3252
0
            found = 0;
3253
0
            for (lyd_find_sibling_val(siblings, target->schema, NULL, 0, &iter);
3254
0
                    iter && lyd_compare_schema_equal(iter->schema, target->schema, 0);
3255
0
                    iter = iter->next) {
3256
0
                if (!lyd_compare_single(target, iter, LYD_COMPARE_FULL_RECURSION)) {
3257
0
                    found = 1;
3258
0
                    break;
3259
0
                }
3260
0
            }
3261
0
            if (found) {
3262
0
                siblings = iter;
3263
0
            } else {
3264
0
                siblings = NULL;
3265
0
            }
3266
0
        } else {
3267
            /* find by hash */
3268
0
            if (!lyht_find(((struct lyd_node_inner *)parent)->children_ht, &target, target->hash, (void **)&match_p)) {
3269
0
                siblings = *match_p;
3270
0
            } else {
3271
                /* not found */
3272
0
                siblings = NULL;
3273
0
            }
3274
0
        }
3275
0
    } else {
3276
        /* no children hash table or cannot be used */
3277
0
        for ( ; siblings; siblings = siblings->next) {
3278
0
            if (lysc_is_dup_inst_list(target->schema)) {
3279
0
                if (!lyd_compare_single(siblings, target, LYD_COMPARE_FULL_RECURSION)) {
3280
0
                    break;
3281
0
                }
3282
0
            } else {
3283
0
                if (!lyd_compare_single(siblings, target, 0)) {
3284
0
                    break;
3285
0
                }
3286
0
            }
3287
0
        }
3288
0
    }
3289
3290
0
    if (!siblings) {
3291
0
        if (match) {
3292
0
            *match = NULL;
3293
0
        }
3294
0
        return LY_ENOTFOUND;
3295
0
    }
3296
3297
0
    if (match) {
3298
0
        *match = (struct lyd_node *)siblings;
3299
0
    }
3300
0
    return LY_SUCCESS;
3301
0
}
3302
3303
LIBYANG_API_DEF LY_ERR
3304
lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
3305
        uint32_t val_len, struct lyd_node **match)
3306
0
{
3307
0
    LY_ERR rc;
3308
0
    struct lyd_node *target = NULL;
3309
3310
0
    LY_CHECK_ARG_RET(NULL, schema, !(schema->nodetype & (LYS_CHOICE | LYS_CASE)), LY_EINVAL);
3311
0
    if (!siblings) {
3312
        /* no data */
3313
0
        if (match) {
3314
0
            *match = NULL;
3315
0
        }
3316
0
        return LY_ENOTFOUND;
3317
0
    }
3318
3319
    /* no schema check, never reliable when ext data are involved */
3320
3321
0
    if (key_or_value && !val_len) {
3322
0
        val_len = strlen(key_or_value);
3323
0
    }
3324
3325
0
    if ((schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && key_or_value) {
3326
        /* create a data node and find the instance */
3327
0
        if (schema->nodetype == LYS_LEAFLIST) {
3328
            /* target used attributes: schema, hash, value */
3329
0
            rc = lyd_create_term(schema, NULL, key_or_value, val_len * 8, 0, 1, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
3330
0
                    NULL, &target);
3331
0
            LY_CHECK_RET(rc);
3332
0
        } else {
3333
            /* target used attributes: schema, hash, child (all keys) */
3334
0
            LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, 1, &target));
3335
0
        }
3336
3337
        /* find it */
3338
0
        rc = lyd_find_sibling_first(siblings, target, match);
3339
0
    } else {
3340
        /* find the first schema node instance */
3341
0
        rc = lyd_find_sibling_schema(siblings, schema, match);
3342
0
    }
3343
3344
0
    lyd_free_tree(target);
3345
0
    return rc;
3346
0
}
3347
3348
LIBYANG_API_DEF LY_ERR
3349
lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
3350
0
{
3351
0
    struct lyd_node **match_p, *first, *iter, *parent;
3352
0
    uint32_t comp_opts;
3353
3354
0
    LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
3355
0
    LY_CHECK_CTX_EQUAL_RET(__func__, siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
3356
3357
0
    LY_CHECK_RET(ly_set_new(set));
3358
3359
0
    if (!siblings || (siblings->schema && target->schema &&
3360
0
            (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema)))) {
3361
        /* no data or schema mismatch */
3362
0
        return LY_ENOTFOUND;
3363
0
    }
3364
3365
    /* set options */
3366
0
    comp_opts = (lysc_is_dup_inst_list(target->schema) ? LYD_COMPARE_FULL_RECURSION : 0);
3367
3368
    /* get first sibling */
3369
0
    siblings = lyd_first_sibling(siblings);
3370
3371
0
    parent = siblings->parent;
3372
0
    if (parent && parent->schema && ((struct lyd_node_inner *)parent)->children_ht) {
3373
0
        assert(target->hash);
3374
3375
        /* find the first instance */
3376
0
        lyd_find_sibling_first(siblings, target, &first);
3377
0
        if (first) {
3378
            /* add it so that it is the first in the set */
3379
0
            if (ly_set_add(*set, first, 1, NULL)) {
3380
0
                goto error;
3381
0
            }
3382
3383
            /* find by hash */
3384
0
            if (!lyht_find(((struct lyd_node_inner *)parent)->children_ht, &target, target->hash, (void **)&match_p)) {
3385
0
                iter = *match_p;
3386
0
            } else {
3387
                /* not found */
3388
0
                iter = NULL;
3389
0
            }
3390
0
            while (iter) {
3391
                /* add all found nodes into the set */
3392
0
                if ((iter != first) && !lyd_compare_single(iter, target, comp_opts) && ly_set_add(*set, iter, 1, NULL)) {
3393
0
                    goto error;
3394
0
                }
3395
3396
                /* find next instance */
3397
0
                if (lyht_find_next(((struct lyd_node_inner *)parent)->children_ht, &iter, iter->hash, (void **)&match_p)) {
3398
0
                    iter = NULL;
3399
0
                } else {
3400
0
                    iter = *match_p;
3401
0
                }
3402
0
            }
3403
0
        }
3404
0
    } else {
3405
        /* no children hash table */
3406
0
        LY_LIST_FOR(siblings, siblings) {
3407
0
            if (!lyd_compare_single(target, siblings, comp_opts)) {
3408
0
                ly_set_add(*set, (void *)siblings, 1, NULL);
3409
0
            }
3410
0
        }
3411
0
    }
3412
3413
0
    if (!(*set)->count) {
3414
0
        return LY_ENOTFOUND;
3415
0
    }
3416
0
    return LY_SUCCESS;
3417
3418
0
error:
3419
0
    ly_set_free(*set, NULL);
3420
0
    *set = NULL;
3421
0
    return LY_EMEM;
3422
0
}
3423
3424
LIBYANG_API_DEF LY_ERR
3425
lyd_find_sibling_opaq_next(const struct lyd_node *first, const char *name, struct lyd_node **match)
3426
0
{
3427
0
    LY_CHECK_ARG_RET(NULL, name, LY_EINVAL);
3428
3429
0
    if (first && first->schema) {
3430
        /* find the actual first node */
3431
0
        while (first->prev->next) {
3432
0
            first = first->prev;
3433
0
        }
3434
3435
0
        first = first->prev;
3436
0
        if (first->schema) {
3437
            /* no opaque nodes */
3438
0
            first = NULL;
3439
0
        } else {
3440
            /* opaque nodes are at the end, find quickly the first */
3441
0
            while (!first->prev->schema) {
3442
0
                first = first->prev;
3443
0
            }
3444
0
        }
3445
0
    }
3446
3447
0
    for ( ; first; first = first->next) {
3448
0
        assert(!first->schema);
3449
0
        if (!strcmp(LYD_NAME(first), name)) {
3450
0
            break;
3451
0
        }
3452
0
    }
3453
3454
0
    if (match) {
3455
0
        *match = (struct lyd_node *)first;
3456
0
    }
3457
0
    return first ? LY_SUCCESS : LY_ENOTFOUND;
3458
0
}
3459
3460
LIBYANG_API_DEF LY_ERR
3461
lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
3462
0
{
3463
0
    LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
3464
3465
0
    return lyd_find_xpath3(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, NULL, set);
3466
0
}
3467
3468
LIBYANG_API_DEF LY_ERR
3469
lyd_find_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, struct ly_set **set)
3470
0
{
3471
0
    LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
3472
3473
0
    return lyd_find_xpath3(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, vars, set);
3474
0
}
3475
3476
LIBYANG_API_DEF LY_ERR
3477
lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath, LY_VALUE_FORMAT format,
3478
        void *prefix_data, const struct lyxp_var *vars, struct ly_set **set)
3479
0
{
3480
0
    LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
3481
3482
0
    *set = NULL;
3483
3484
0
    return lyd_eval_xpath4(ctx_node, tree, NULL, xpath, format, prefix_data, vars, NULL, set, NULL, NULL, NULL);
3485
0
}
3486
3487
LIBYANG_API_DEF LY_ERR
3488
lyd_eval_xpath(const struct lyd_node *ctx_node, const char *xpath, ly_bool *result)
3489
0
{
3490
0
    return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, NULL, result);
3491
0
}
3492
3493
LIBYANG_API_DEF LY_ERR
3494
lyd_eval_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, ly_bool *result)
3495
0
{
3496
0
    return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, vars, result);
3497
0
}
3498
3499
LIBYANG_API_DEF LY_ERR
3500
lyd_eval_xpath3(const struct lyd_node *ctx_node, const struct lys_module *cur_mod, const char *xpath,
3501
        LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, ly_bool *result)
3502
0
{
3503
0
    return lyd_eval_xpath4(ctx_node, ctx_node, cur_mod, xpath, format, prefix_data, vars, NULL, NULL, NULL, NULL, result);
3504
0
}
3505
3506
LIBYANG_API_DEF LY_ERR
3507
lyd_eval_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const struct lys_module *cur_mod,
3508
        const char *xpath, LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, LY_XPATH_TYPE *ret_type,
3509
        struct ly_set **node_set, char **string, long double *number, ly_bool *boolean)
3510
0
{
3511
0
    LY_ERR ret = LY_SUCCESS;
3512
0
    struct lyxp_set xp_set = {0};
3513
0
    struct lyxp_expr *exp = NULL;
3514
0
    uint32_t i;
3515
3516
0
    LY_CHECK_ARG_RET(NULL, tree, xpath, ((ret_type && node_set && string && number && boolean) ||
3517
0
            (node_set && !string && !number && !boolean) || (!node_set && string && !number && !boolean) ||
3518
0
            (!node_set && !string && number && !boolean) || (!node_set && !string && !number && boolean)), LY_EINVAL);
3519
3520
    /* parse expression */
3521
0
    ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(tree), ctx_node, xpath, 0, 1, &exp);
3522
0
    LY_CHECK_GOTO(ret, cleanup);
3523
3524
    /* evaluate expression */
3525
0
    ret = lyxp_eval(LYD_CTX(tree), exp, cur_mod, format, prefix_data, ctx_node, ctx_node, tree, vars, &xp_set,
3526
0
            LYXP_IGNORE_WHEN);
3527
0
    LY_CHECK_GOTO(ret, cleanup);
3528
3529
    /* return expected result type without or with casting */
3530
0
    if (node_set) {
3531
        /* node set */
3532
0
        if (xp_set.type == LYXP_SET_NODE_SET) {
3533
            /* transform into a set */
3534
0
            LY_CHECK_GOTO(ret = ly_set_new(node_set), cleanup);
3535
0
            (*node_set)->objs = malloc(xp_set.used * sizeof *(*node_set)->objs);
3536
0
            LY_CHECK_ERR_GOTO(!(*node_set)->objs, LOGMEM(LYD_CTX(tree)); ret = LY_EMEM, cleanup);
3537
0
            (*node_set)->size = xp_set.used;
3538
0
            for (i = 0; i < xp_set.used; ++i) {
3539
0
                if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
3540
0
                    ret = ly_set_add(*node_set, xp_set.val.nodes[i].node, 1, NULL);
3541
0
                    LY_CHECK_GOTO(ret, cleanup);
3542
0
                }
3543
0
            }
3544
0
            if (ret_type) {
3545
0
                *ret_type = LY_XPATH_NODE_SET;
3546
0
            }
3547
0
        } else if (!string && !number && !boolean) {
3548
0
            LOGERR(LYD_CTX(tree), LY_EINVAL, "XPath \"%s\" result is not a node set.", xpath);
3549
0
            ret = LY_EINVAL;
3550
0
            goto cleanup;
3551
0
        }
3552
0
    }
3553
3554
0
    if (string) {
3555
0
        if ((xp_set.type != LYXP_SET_STRING) && !node_set) {
3556
            /* cast into string */
3557
0
            LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_STRING), cleanup);
3558
0
        }
3559
0
        if (xp_set.type == LYXP_SET_STRING) {
3560
            /* string */
3561
0
            *string = xp_set.val.str;
3562
0
            xp_set.val.str = NULL;
3563
0
            if (ret_type) {
3564
0
                *ret_type = LY_XPATH_STRING;
3565
0
            }
3566
0
        }
3567
0
    }
3568
3569
0
    if (number) {
3570
0
        if ((xp_set.type != LYXP_SET_NUMBER) && !node_set) {
3571
            /* cast into number */
3572
0
            LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_NUMBER), cleanup);
3573
0
        }
3574
0
        if (xp_set.type == LYXP_SET_NUMBER) {
3575
            /* number */
3576
0
            *number = xp_set.val.num;
3577
0
            if (ret_type) {
3578
0
                *ret_type = LY_XPATH_NUMBER;
3579
0
            }
3580
0
        }
3581
0
    }
3582
3583
0
    if (boolean) {
3584
0
        if ((xp_set.type != LYXP_SET_BOOLEAN) && !node_set) {
3585
            /* cast into boolean */
3586
0
            LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN), cleanup);
3587
0
        }
3588
0
        if (xp_set.type == LYXP_SET_BOOLEAN) {
3589
            /* boolean */
3590
0
            *boolean = xp_set.val.bln;
3591
0
            if (ret_type) {
3592
0
                *ret_type = LY_XPATH_BOOLEAN;
3593
0
            }
3594
0
        }
3595
0
    }
3596
3597
0
cleanup:
3598
0
    lyxp_set_free_content(&xp_set);
3599
0
    lyxp_expr_free(exp);
3600
0
    return ret;
3601
0
}
3602
3603
/**
3604
 * @brief Hash table node equal callback.
3605
 */
3606
static ly_bool
3607
lyd_trim_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
3608
0
{
3609
0
    struct lyd_node *node1, *node2;
3610
3611
0
    node1 = *(struct lyd_node **)val1_p;
3612
0
    node2 = *(struct lyd_node **)val2_p;
3613
3614
0
    return node1 == node2;
3615
0
}
3616
3617
LIBYANG_API_DEF LY_ERR
3618
lyd_trim_xpath(struct lyd_node **tree, const char *xpath, const struct lyxp_var *vars)
3619
0
{
3620
0
    LY_ERR ret = LY_SUCCESS;
3621
0
    struct ly_ctx *ctx = NULL;
3622
0
    struct lyxp_set xp_set = {0};
3623
0
    struct lyxp_expr *exp = NULL;
3624
0
    struct lyd_node *node, *parent;
3625
0
    struct lyxp_set_hash_node hnode;
3626
0
    struct ly_ht *parent_ht = NULL;
3627
0
    struct ly_set free_set = {0};
3628
0
    uint32_t i, hash;
3629
0
    ly_bool is_result;
3630
3631
0
    LY_CHECK_ARG_RET(NULL, tree, xpath, LY_EINVAL);
3632
3633
0
    if (!*tree) {
3634
        /* nothing to do */
3635
0
        goto cleanup;
3636
0
    }
3637
3638
0
    *tree = lyd_first_sibling(*tree);
3639
0
    ctx = (struct ly_ctx *)LYD_CTX(*tree);
3640
3641
    /* parse expression */
3642
0
    ret = lyxp_expr_parse(ctx, NULL, xpath, 0, 1, &exp);
3643
0
    LY_CHECK_GOTO(ret, cleanup);
3644
3645
    /* evaluate expression */
3646
0
    ret = lyxp_eval(ctx, exp, NULL, LY_VALUE_JSON, NULL, *tree, *tree, *tree, vars, &xp_set, LYXP_IGNORE_WHEN);
3647
0
    LY_CHECK_GOTO(ret, cleanup);
3648
3649
    /* create hash table for all the parents of results */
3650
0
    parent_ht = lyht_new(32, sizeof node, lyd_trim_equal_cb, NULL, 1);
3651
0
    LY_CHECK_GOTO(!parent_ht, cleanup);
3652
3653
0
    for (i = 0; i < xp_set.used; ++i) {
3654
0
        if (xp_set.val.nodes[i].type != LYXP_NODE_ELEM) {
3655
            /* ignore */
3656
0
            continue;
3657
0
        }
3658
3659
0
        for (parent = xp_set.val.nodes[i].node->parent; parent; parent = parent->parent) {
3660
            /* add the parent into parent_ht */
3661
0
            ret = lyht_insert(parent_ht, &parent, parent->hash, NULL);
3662
0
            if (ret == LY_EEXIST) {
3663
                /* shared parent, we are done */
3664
0
                break;
3665
0
            }
3666
0
            LY_CHECK_GOTO(ret, cleanup);
3667
0
        }
3668
0
    }
3669
3670
0
    hnode.type = LYXP_NODE_ELEM;
3671
0
    LY_LIST_FOR(*tree, parent) {
3672
0
        LYD_TREE_DFS_BEGIN(parent, node) {
3673
0
            if (lysc_is_key(node->schema)) {
3674
                /* ignore */
3675
0
                goto next_iter;
3676
0
            }
3677
3678
            /* check the results */
3679
0
            is_result = 0;
3680
0
            if (xp_set.ht) {
3681
0
                hnode.node = node;
3682
0
                hash = lyht_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
3683
0
                hash = lyht_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
3684
0
                hash = lyht_hash_multi(hash, NULL, 0);
3685
3686
0
                if (!lyht_find(xp_set.ht, &hnode, hash, NULL)) {
3687
0
                    is_result = 1;
3688
0
                }
3689
0
            } else {
3690
                /* not enough elements for a hash table */
3691
0
                for (i = 0; i < xp_set.used; ++i) {
3692
0
                    if (xp_set.val.nodes[i].type != LYXP_NODE_ELEM) {
3693
                        /* ignore */
3694
0
                        continue;
3695
0
                    }
3696
3697
0
                    if (xp_set.val.nodes[i].node == node) {
3698
0
                        is_result = 1;
3699
0
                        break;
3700
0
                    }
3701
0
                }
3702
0
            }
3703
3704
0
            if (is_result) {
3705
                /* keep the whole subtree if the node is in the results */
3706
0
                LYD_TREE_DFS_continue = 1;
3707
0
            } else if (lyht_find(parent_ht, &node, node->hash, NULL)) {
3708
                /* free the whole subtree if the node is not even among the selected parents */
3709
0
                ret = ly_set_add(&free_set, node, 1, NULL);
3710
0
                LY_CHECK_GOTO(ret, cleanup);
3711
0
                LYD_TREE_DFS_continue = 1;
3712
0
            } /* else keep the parent node because a subtree is in the results */
3713
3714
0
next_iter:
3715
0
            LYD_TREE_DFS_END(parent, node);
3716
0
        }
3717
0
    }
3718
3719
    /* free */
3720
0
    for (i = 0; i < free_set.count; ++i) {
3721
0
        node = free_set.dnodes[i];
3722
0
        if (*tree == node) {
3723
0
            *tree = (*tree)->next;
3724
0
        }
3725
0
        lyd_free_tree(node);
3726
0
    }
3727
3728
0
cleanup:
3729
0
    lyxp_set_free_content(&xp_set);
3730
0
    lyxp_expr_free(exp);
3731
0
    lyht_free(parent_ht, NULL);
3732
0
    ly_set_erase(&free_set, NULL);
3733
0
    return ret;
3734
0
}
3735
3736
LIBYANG_API_DEF LY_ERR
3737
lyd_find_path(const struct lyd_node *ctx_node, const char *path, ly_bool output, struct lyd_node **match)
3738
0
{
3739
0
    LY_ERR ret = LY_SUCCESS;
3740
0
    struct lyxp_expr *expr = NULL;
3741
0
    struct ly_path *lypath = NULL;
3742
0
    const struct lyd_node *tree = NULL;
3743
3744
0
    LY_CHECK_ARG_RET(NULL, ctx_node, ctx_node->schema, path, LY_EINVAL);
3745
3746
    /* parse the path */
3747
0
    ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
3748
0
            LY_PATH_PRED_SIMPLE, &expr);
3749
0
    LY_CHECK_GOTO(ret, cleanup);
3750
3751
    /* compile the path */
3752
0
    ret = ly_path_compile(LYD_CTX(ctx_node), ctx_node->schema, expr,
3753
0
            output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, 0, LY_VALUE_JSON, NULL, &lypath);
3754
0
    LY_CHECK_GOTO(ret, cleanup);
3755
3756
0
    if (lypath[0].doc_root) {
3757
        /* use the root context node for absolute paths, avoids specific XPath evaluation rules of extensions */
3758
0
        for (tree = ctx_node; tree->parent; tree = tree->parent) {}
3759
0
        ctx_node = NULL;
3760
0
    }
3761
3762
    /* evaluate the path */
3763
0
    ret = ly_path_eval_partial(lypath, ctx_node, tree, NULL, 0, NULL, match);
3764
3765
0
cleanup:
3766
0
    lyxp_expr_free(expr);
3767
0
    ly_path_free(lypath);
3768
0
    return ret;
3769
0
}
3770
3771
LIBYANG_API_DEF LY_ERR
3772
lyd_find_target(const struct ly_path *path, const struct lyd_node *tree, struct lyd_node **match)
3773
0
{
3774
0
    LY_ERR ret;
3775
0
    struct lyd_node *m;
3776
3777
0
    LY_CHECK_ARG_RET(NULL, path, LY_EINVAL);
3778
3779
0
    ret = ly_path_eval(path, tree, NULL, &m);
3780
0
    if (ret) {
3781
0
        if (match) {
3782
0
            *match = NULL;
3783
0
        }
3784
0
        return LY_ENOTFOUND;
3785
0
    }
3786
3787
0
    if (match) {
3788
0
        *match = m;
3789
0
    }
3790
0
    return LY_SUCCESS;
3791
0
}
3792
3793
LY_ERR
3794
lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct lyd_leafref_links_rec **record, ly_bool create)
3795
0
{
3796
0
    struct ly_ctx_shared_data *ctx_data;
3797
0
    LY_ERR ret = LY_SUCCESS;
3798
0
    uint32_t hash;
3799
0
    struct lyd_leafref_links_rec rec = {0};
3800
0
    struct lyd_leafref_links_rec *rec_p = &rec;
3801
0
    struct lyd_leafref_links_rec **rec_p2;
3802
3803
0
    assert(node);
3804
0
    assert(record);
3805
3806
0
    *record = NULL;
3807
3808
0
    if (!(ly_ctx_get_options(LYD_CTX(node)) & LY_CTX_LEAFREF_LINKING)) {
3809
0
        return LY_EDENIED;
3810
0
    }
3811
3812
0
    ctx_data = ly_ctx_shared_data_get(LYD_CTX(node));
3813
0
    rec.node = node;
3814
0
    hash = lyht_hash((const char *)&node, sizeof node);
3815
3816
    /* LL LOCK */
3817
0
    pthread_mutex_lock(&ctx_data->leafref_links_lock);
3818
3819
0
    ret = lyht_find(ctx_data->leafref_links_ht, &rec_p, hash, (void **)&rec_p2);
3820
0
    if ((ret == LY_ENOTFOUND) && create) {
3821
        /* create a new record */
3822
0
        rec_p = calloc(1, sizeof rec);
3823
0
        rec_p->node = node;
3824
0
        LY_CHECK_ERR_GOTO(!rec_p, LOGMEM(LYD_CTX(node)), cleanup);
3825
0
        ret = lyht_insert_no_check(ctx_data->leafref_links_ht, &rec_p, hash, (void **)&rec_p2);
3826
0
        LY_CHECK_ERR_GOTO(ret, free(rec_p), cleanup);
3827
0
    }
3828
3829
0
cleanup:
3830
0
    if (!ret) {
3831
0
        *record = *rec_p2;
3832
0
    }
3833
3834
    /* LL UNLOCK */
3835
0
    pthread_mutex_unlock(&ctx_data->leafref_links_lock);
3836
3837
0
    return ret;
3838
0
}
3839
3840
LIBYANG_API_DEF LY_ERR
3841
lyd_leafref_get_links(const struct lyd_node_term *node, const struct lyd_leafref_links_rec **record)
3842
0
{
3843
0
    LY_CHECK_ARG_RET(NULL, node, record, LY_EINVAL);
3844
3845
0
    return lyd_get_or_create_leafref_links_record(node, (struct lyd_leafref_links_rec **)record, 0);
3846
0
}
3847
3848
LY_ERR
3849
lyd_link_leafref_node(const struct lyd_node_term *node, const struct lyd_node_term *leafref_node)
3850
0
{
3851
0
    const struct lyd_node_term **item = NULL;
3852
0
    struct lyd_leafref_links_rec *rec;
3853
0
    LY_ARRAY_COUNT_TYPE u;
3854
3855
0
    assert(node);
3856
0
    assert(leafref_node);
3857
3858
0
    if (!(ly_ctx_get_options(LYD_CTX(node)) & LY_CTX_LEAFREF_LINKING)) {
3859
0
        return LY_EDENIED;
3860
0
    }
3861
3862
    /* add leafref node into the list of target node */
3863
0
    LY_CHECK_RET(lyd_get_or_create_leafref_links_record(node, &rec, 1));
3864
0
    LY_ARRAY_FOR(rec->leafref_nodes, u) {
3865
0
        if (rec->leafref_nodes[u] == leafref_node) {
3866
0
            return LY_SUCCESS;
3867
0
        }
3868
0
    }
3869
3870
0
    LY_ARRAY_NEW_RET(LYD_CTX(node), rec->leafref_nodes, item, LY_EMEM);
3871
0
    *item = leafref_node;
3872
3873
    /* add target node into the list of leafref node*/
3874
0
    LY_CHECK_RET(lyd_get_or_create_leafref_links_record(leafref_node, &rec, 1));
3875
0
    LY_ARRAY_FOR(rec->target_nodes, u) {
3876
0
        if (rec->target_nodes[u] == node) {
3877
0
            return LY_SUCCESS;
3878
0
        }
3879
0
    }
3880
3881
0
    LY_ARRAY_NEW_RET(LYD_CTX(node), rec->target_nodes, item, LY_EMEM);
3882
0
    *item = node;
3883
3884
0
    return LY_SUCCESS;
3885
0
}
3886
3887
/**
3888
 * @brief Traverse through data tree node suitable types and adds leafrefs links to the given nodes
3889
 *
3890
 * This API requires usage of ::LY_CTX_LEAFREF_LINKING context flag.
3891
 *
3892
 * @param[in] tree The data tree root node.
3893
 * @param[in] cur_node The current data node.
3894
 * @param[in] value The current node value.
3895
 * @param[in] type The leaf/leaf-list type of given data node.
3896
 *
3897
 * @return LY_SUCCESS on success.
3898
 * @return LY_ERR value on error.
3899
 */
3900
static LY_ERR
3901
lyd_leafref_link_node_tree_type(const struct lyd_node *tree, const struct lyd_node *cur_node, struct lyd_value *value, const struct lysc_type *type)
3902
0
{
3903
0
    char *errmsg;
3904
0
    struct ly_set *targets = NULL;
3905
0
    LY_ERR ret = LY_SUCCESS;
3906
0
    struct lysc_type_leafref *lref;
3907
0
    struct lysc_type_union *un;
3908
0
    LY_ARRAY_COUNT_TYPE u;
3909
0
    uint32_t i;
3910
0
    struct lyd_node_term *leafref_node = (struct lyd_node_term *)cur_node;
3911
3912
0
    if (type->basetype == LY_TYPE_LEAFREF) {
3913
0
        lref = (struct lysc_type_leafref *)type;
3914
0
        ly_set_free(targets, NULL);
3915
0
        if (lyplg_type_resolve_leafref(lref, cur_node, value, tree, &targets, &errmsg)) {
3916
            /* leafref target not found */
3917
0
            free(errmsg);
3918
0
        } else {
3919
            /* leafref target found, link it */
3920
0
            for (i = 0; i < targets->count; ++i) {
3921
0
                if (targets->dnodes[i]->schema->nodetype & LYD_NODE_TERM) {
3922
0
                    ret = lyd_link_leafref_node((struct lyd_node_term *)targets->dnodes[i], leafref_node);
3923
0
                    LY_CHECK_GOTO(ret, cleanup);
3924
0
                }
3925
0
            }
3926
0
        }
3927
0
    } else if (type->basetype == LY_TYPE_UNION) {
3928
0
        un = (struct lysc_type_union *)type;
3929
0
        LY_ARRAY_FOR(un->types, u) {
3930
0
            ret = lyd_leafref_link_node_tree_type(tree, cur_node, &leafref_node->value.subvalue->value, un->types[u]);
3931
0
            LY_CHECK_GOTO(ret, cleanup)
3932
0
        }
3933
0
    }
3934
3935
0
cleanup:
3936
0
    ly_set_free(targets, NULL);
3937
0
    return ret;
3938
0
}
3939
3940
LIBYANG_API_DEF LY_ERR
3941
lyd_leafref_link_node_tree(const struct lyd_node *tree)
3942
0
{
3943
0
    const struct lyd_node *sibling, *elem;
3944
0
    struct lyd_node_term *cur_node;
3945
0
    struct lysc_node_leaf *leaf_schema;
3946
3947
0
    LY_CHECK_ARG_RET(NULL, tree, LY_EINVAL);
3948
3949
0
    if (!(ly_ctx_get_options(LYD_CTX(tree)) & LY_CTX_LEAFREF_LINKING)) {
3950
0
        return LY_EDENIED;
3951
0
    }
3952
3953
0
    LY_LIST_FOR(tree, sibling) {
3954
0
        LYD_TREE_DFS_BEGIN(sibling, elem) {
3955
0
            if (elem->schema && (elem->schema->nodetype & LYD_NODE_TERM)) {
3956
0
                leaf_schema = (struct lysc_node_leaf *)elem->schema;
3957
0
                cur_node = (struct lyd_node_term *)elem;
3958
0
                LY_CHECK_RET(lyd_leafref_link_node_tree_type(tree, elem, &cur_node->value, leaf_schema->type));
3959
0
            }
3960
0
            LYD_TREE_DFS_END(sibling, elem);
3961
0
        }
3962
0
    }
3963
3964
0
    return LY_SUCCESS;
3965
0
}
3966
3967
LY_ERR
3968
lyd_unlink_leafref_node(const struct lyd_node_term *node, const struct lyd_node_term *leafref_node)
3969
0
{
3970
0
    LY_ERR ret;
3971
0
    struct lyd_leafref_links_rec *rec;
3972
3973
0
    assert(node);
3974
0
    assert(leafref_node);
3975
3976
0
    if (!(ly_ctx_get_options(LYD_CTX(node)) & LY_CTX_LEAFREF_LINKING)) {
3977
0
        return LY_EDENIED;
3978
0
    }
3979
3980
    /* remove link from target node to leafref node */
3981
0
    ret = lyd_get_or_create_leafref_links_record(node, &rec, 0);
3982
0
    if (ret == LY_SUCCESS) {
3983
0
        LY_ARRAY_REMOVE_VALUE(rec->leafref_nodes, leafref_node);
3984
0
        if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec->target_nodes) == 0)) {
3985
0
            lyd_free_leafref_nodes(node);
3986
0
        }
3987
0
    } else if (ret != LY_ENOTFOUND) {
3988
0
        return ret;
3989
0
    }
3990
3991
    /* remove link from leafref node to target node */
3992
0
    ret = lyd_get_or_create_leafref_links_record(leafref_node, &rec, 0);
3993
0
    if (ret == LY_SUCCESS) {
3994
0
        LY_ARRAY_REMOVE_VALUE(rec->target_nodes, node);
3995
0
        if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec->target_nodes) == 0)) {
3996
0
            lyd_free_leafref_nodes(leafref_node);
3997
0
        }
3998
0
    } else if (ret != LY_ENOTFOUND) {
3999
0
        return ret;
4000
0
    }
4001
4002
0
    return LY_SUCCESS;
4003
0
}