Coverage Report

Created: 2026-03-12 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/tree_data_free.c
Line
Count
Source
1
/**
2
 * @file tree_data_free.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @brief Freeing functions for data tree structures
5
 *
6
 * Copyright (c) 2019 CESNET, z.s.p.o.
7
 *
8
 * This source code is licensed under BSD 3-Clause License (the "License").
9
 * You may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     https://opensource.org/licenses/BSD-3-Clause
13
 */
14
15
#include <assert.h>
16
#include <stdlib.h>
17
18
#include "common.h"
19
#include "dict.h"
20
#include "hash_table.h"
21
#include "log.h"
22
#include "plugins_types.h"
23
#include "tree.h"
24
#include "tree_data.h"
25
#include "tree_data_internal.h"
26
#include "tree_schema.h"
27
28
static void
29
lyd_free_meta(struct lyd_meta *meta, ly_bool siblings)
30
0
{
31
0
    struct lyd_meta *iter;
32
33
0
    if (!meta) {
34
0
        return;
35
0
    }
36
37
0
    if (meta->parent) {
38
0
        if (meta->parent->meta == meta) {
39
0
            if (siblings) {
40
0
                meta->parent->meta = NULL;
41
0
            } else {
42
0
                meta->parent->meta = meta->next;
43
0
            }
44
0
        } else {
45
0
            for (iter = meta->parent->meta; iter->next != meta; iter = iter->next) {}
46
0
            if (iter->next) {
47
0
                if (siblings) {
48
0
                    iter->next = NULL;
49
0
                } else {
50
0
                    iter->next = meta->next;
51
0
                }
52
0
            }
53
0
        }
54
0
    }
55
56
0
    if (!siblings) {
57
0
        meta->next = NULL;
58
0
    }
59
60
0
    for (iter = meta; iter; ) {
61
0
        meta = iter;
62
0
        iter = iter->next;
63
64
0
        lydict_remove(meta->annotation->module->ctx, meta->name);
65
0
        meta->value.realtype->plugin->free(meta->annotation->module->ctx, &meta->value);
66
0
        free(meta);
67
0
    }
68
0
}
69
70
API void
71
lyd_free_meta_single(struct lyd_meta *meta)
72
0
{
73
0
    lyd_free_meta(meta, 0);
74
0
}
75
76
API void
77
lyd_free_meta_siblings(struct lyd_meta *meta)
78
0
{
79
0
    lyd_free_meta(meta, 1);
80
0
}
81
82
static void
83
lyd_free_attr(const struct ly_ctx *ctx, struct lyd_attr *attr, ly_bool siblings)
84
0
{
85
0
    struct lyd_attr *iter;
86
87
0
    LY_CHECK_ARG_RET(NULL, ctx, );
88
0
    if (!attr) {
89
0
        return;
90
0
    }
91
92
0
    if (attr->parent) {
93
0
        if (attr->parent->attr == attr) {
94
0
            if (siblings) {
95
0
                attr->parent->attr = NULL;
96
0
            } else {
97
0
                attr->parent->attr = attr->next;
98
0
            }
99
0
        } else {
100
0
            for (iter = attr->parent->attr; iter->next != attr; iter = iter->next) {}
101
0
            if (iter->next) {
102
0
                if (siblings) {
103
0
                    iter->next = NULL;
104
0
                } else {
105
0
                    iter->next = attr->next;
106
0
                }
107
0
            }
108
0
        }
109
0
    }
110
111
0
    if (!siblings) {
112
0
        attr->next = NULL;
113
0
    }
114
115
0
    for (iter = attr; iter; ) {
116
0
        attr = iter;
117
0
        iter = iter->next;
118
119
0
        ly_free_prefix_data(attr->format, attr->val_prefix_data);
120
0
        lydict_remove(ctx, attr->name.name);
121
0
        lydict_remove(ctx, attr->name.prefix);
122
0
        lydict_remove(ctx, attr->name.module_ns);
123
0
        lydict_remove(ctx, attr->value);
124
0
        free(attr);
125
0
    }
126
0
}
127
128
API void
129
lyd_free_attr_single(const struct ly_ctx *ctx, struct lyd_attr *attr)
130
0
{
131
0
    lyd_free_attr(ctx, attr, 0);
132
0
}
133
134
API void
135
lyd_free_attr_siblings(const struct ly_ctx *ctx, struct lyd_attr *attr)
136
0
{
137
0
    lyd_free_attr(ctx, attr, 1);
138
0
}
139
140
/**
141
 * @brief Free Data (sub)tree.
142
 * @param[in] node Data node to be freed.
143
 * @param[in] top Recursion flag to unlink the root of the subtree being freed.
144
 */
145
static void
146
lyd_free_subtree(struct lyd_node *node, ly_bool top)
147
0
{
148
0
    struct lyd_node *iter, *next;
149
0
    struct lyd_node_opaq *opaq = NULL;
150
151
0
    assert(node);
152
153
0
    if (!node->schema) {
154
0
        opaq = (struct lyd_node_opaq *)node;
155
156
        /* free the children */
157
0
        LY_LIST_FOR_SAFE(lyd_child(node), next, iter) {
158
0
            lyd_free_subtree(iter, 0);
159
0
        }
160
161
0
        lydict_remove(LYD_CTX(opaq), opaq->name.name);
162
0
        lydict_remove(LYD_CTX(opaq), opaq->name.prefix);
163
0
        lydict_remove(LYD_CTX(opaq), opaq->name.module_ns);
164
0
        lydict_remove(LYD_CTX(opaq), opaq->value);
165
0
        ly_free_prefix_data(opaq->format, opaq->val_prefix_data);
166
0
    } else if (node->schema->nodetype & LYD_NODE_INNER) {
167
        /* remove children hash table in case of inner data node */
168
0
        lyht_free(((struct lyd_node_inner *)node)->children_ht);
169
0
        ((struct lyd_node_inner *)node)->children_ht = NULL;
170
171
        /* free the children */
172
0
        LY_LIST_FOR_SAFE(lyd_child(node), next, iter) {
173
0
            lyd_free_subtree(iter, 0);
174
0
        }
175
0
    } else if (node->schema->nodetype & LYD_NODE_ANY) {
176
        /* only frees the value this way */
177
0
        lyd_any_copy_value(node, NULL, 0);
178
0
    } else if (node->schema->nodetype & LYD_NODE_TERM) {
179
0
        ((struct lysc_node_leaf *)node->schema)->type->plugin->free(LYD_CTX(node), &((struct lyd_node_term *)node)->value);
180
0
    }
181
182
0
    if (!node->schema) {
183
0
        lyd_free_attr_siblings(LYD_CTX(node), opaq->attr);
184
0
    } else {
185
        /* free the node's metadata */
186
0
        lyd_free_meta_siblings(node->meta);
187
0
    }
188
189
    /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
190
0
    if (top) {
191
0
        lyd_unlink_tree(node);
192
0
    }
193
194
0
    free(node);
195
0
}
196
197
API void
198
lyd_free_tree(struct lyd_node *node)
199
0
{
200
0
    if (!node) {
201
0
        return;
202
0
    }
203
204
0
    lyd_free_subtree(node, 1);
205
0
}
206
207
static void
208
lyd_free_(struct lyd_node *node, ly_bool top)
209
0
{
210
0
    struct lyd_node *iter, *next;
211
212
0
    if (!node) {
213
0
        return;
214
0
    }
215
216
    /* get the first (top-level) sibling */
217
0
    if (top) {
218
0
        for ( ; node->parent; node = lyd_parent(node)) {}
219
0
    }
220
0
    while (node->prev->next) {
221
0
        node = node->prev;
222
0
    }
223
224
0
    LY_LIST_FOR_SAFE(node, next, iter) {
225
        /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
226
0
        lyd_free_subtree(iter, iter->parent ? 1 : 0);
227
0
    }
228
0
}
229
230
API void
231
lyd_free_siblings(struct lyd_node *node)
232
0
{
233
0
    lyd_free_(node, 0);
234
0
}
235
236
API void
237
lyd_free_all(struct lyd_node *node)
238
0
{
239
0
    lyd_free_(node, 1);
240
0
}