blob: 92003ff9e1de4956dafb45b3aaeb8ef5f0f7c688 [file] [log] [blame]
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001/**
Michal Vaskoafac7822020-10-20 14:22:26 +02002 * @file in.c
Radek Krejcif0e1ba52020-05-22 15:14:35 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskoafac7822020-10-20 14:22:26 +02004 * @brief libyang input functions.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02005 *
Michal Vaskoafac7822020-10-20 14:22:26 +02006 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02007 *
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#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
17
18#ifdef __APPLE__
19#define _DARWIN_C_SOURCE /* F_GETPATH */
20#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +020021
Michal Vaskoafac7822020-10-20 14:22:26 +020022#include "in.h"
23#include "in_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020024
Radek Krejcif0e1ba52020-05-22 15:14:35 +020025#include <errno.h>
26#include <fcntl.h>
27#include <limits.h>
Radek Krejci47fab892020-11-05 17:02:41 +010028#include <stdint.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020029#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020030#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020031#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020032#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020033
Radek Krejcica376bd2020-06-11 16:04:06 +020034#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020035#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020036#include "dict.h"
37#include "log.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020038#include "parser_data.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020039#include "parser_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010040#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010041#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010042#include "tree_data.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020043#include "tree_data_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010044#include "tree_schema.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020045#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020046
47API LY_IN_TYPE
48ly_in_type(const struct ly_in *in)
49{
50 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
51 return in->type;
52}
53
54API LY_ERR
55ly_in_new_fd(int fd, struct ly_in **in)
56{
57 size_t length;
58 char *addr;
59
60 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
61
62 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
63 if (!addr) {
64 LOGERR(NULL, LY_EINVAL, "Empty input file.");
65 return LY_EINVAL;
66 }
67
68 *in = calloc(1, sizeof **in);
69 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
70
71 (*in)->type = LY_IN_FD;
72 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020073 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +010074 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020075 (*in)->length = length;
76
77 return LY_SUCCESS;
78}
79
80API int
81ly_in_fd(struct ly_in *in, int fd)
82{
83 int prev_fd;
84 size_t length;
85 const char *addr;
86
87 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
88
89 prev_fd = in->method.fd;
90
91 if (fd != -1) {
92 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
93 if (!addr) {
94 LOGERR(NULL, LY_EINVAL, "Empty input file.");
95 return -1;
96 }
97
Michal Vasko22df3f02020-08-24 13:29:22 +020098 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +020099
100 in->method.fd = fd;
101 in->current = in->start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +0100102 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200103 in->length = length;
104 }
105
106 return prev_fd;
107}
108
109API LY_ERR
110ly_in_new_file(FILE *f, struct ly_in **in)
111{
112 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
113
114 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
115
116 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
117 (*in)->type = LY_IN_FILE;
118 (*in)->method.f = f;
119
120 return LY_SUCCESS;
121}
122
123API FILE *
124ly_in_file(struct ly_in *in, FILE *f)
125{
126 FILE *prev_f;
127
128 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
129
130 prev_f = in->method.f;
131
132 if (f) {
133 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
134 in->type = LY_IN_FD;
135 in->method.fd = fileno(prev_f);
136 if (ly_in_fd(in, fileno(f)) == -1) {
137 in->type = LY_IN_FILE;
138 in->method.f = prev_f;
139 return NULL;
140 }
141
142 /* if success, convert the result back */
143 in->type = LY_IN_FILE;
144 in->method.f = f;
145 }
146
147 return prev_f;
148}
149
150API LY_ERR
151ly_in_new_memory(const char *str, struct ly_in **in)
152{
153 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
154
155 *in = calloc(1, sizeof **in);
156 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
157
158 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200159 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100160 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200161
162 return LY_SUCCESS;
163}
164
Michal Vasko63f3d842020-07-08 10:10:14 +0200165API const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200166ly_in_memory(struct ly_in *in, const char *str)
167{
168 const char *data;
169
170 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
171
172 data = in->current;
173
174 if (str) {
175 in->start = in->current = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100176 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200177 }
178
179 return data;
180}
181
182API LY_ERR
183ly_in_reset(struct ly_in *in)
184{
185 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
186
Michal Vasko63f3d842020-07-08 10:10:14 +0200187 in->current = in->func_start = in->start;
Radek Krejcid54412f2020-12-17 20:25:35 +0100188 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200189 return LY_SUCCESS;
190}
191
192API LY_ERR
193ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
194{
Radek Krejci0f969882020-08-21 16:56:47 +0200195 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200196 char *fp;
197 int fd;
198
199 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
200
201 if (len) {
202 fp = strndup(filepath, len);
203 } else {
204 fp = strdup(filepath);
205 }
206
207 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200208 LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp),
Michal Vasko69730152020-10-09 16:30:07 +0200209 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200210
211 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
212
213 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
214 (*in)->type = LY_IN_FILEPATH;
215 (*in)->method.fpath.fd = fd;
216 (*in)->method.fpath.filepath = fp;
217
218 return LY_SUCCESS;
219}
220
221API const char *
222ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
223{
224 int fd, prev_fd;
225 char *fp = NULL;
226
227 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
228
229 if (!filepath) {
230 return in->method.fpath.filepath;
231 }
232
233 if (len) {
234 fp = strndup(filepath, len);
235 } else {
236 fp = strdup(filepath);
237 }
238
239 /* replace filepath */
240 fd = open(fp, O_RDONLY);
241 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
242
243 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
244 in->type = LY_IN_FD;
245 prev_fd = ly_in_fd(in, fd);
246 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
247
248 /* and convert the result back */
249 in->type = LY_IN_FILEPATH;
250 close(prev_fd);
251 free(in->method.fpath.filepath);
252 in->method.fpath.fd = fd;
253 in->method.fpath.filepath = fp;
254
255 return NULL;
256}
257
258void
259lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
260{
261 char path[PATH_MAX];
Michal Vasko69730152020-10-09 16:30:07 +0200262
Michal Vasko5aa44c02020-06-29 11:47:02 +0200263#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200264 char proc_path[32];
265 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200266#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200267
268 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
269 if (*filepath) {
270 /* filepath already set */
271 return;
272 }
273
274 switch (in->type) {
275 case LY_IN_FILEPATH:
276 if (realpath(in->method.fpath.filepath, path) != NULL) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200277 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200278 } else {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200279 lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200280 }
281
282 break;
283 case LY_IN_FD:
284#ifdef __APPLE__
285 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200286 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200287 }
288#else
289 /* get URI if there is /proc */
290 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
291 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200292 lydict_insert(ctx, path, len, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200293 }
294#endif
295 break;
296 case LY_IN_MEMORY:
297 case LY_IN_FILE:
298 /* nothing to do */
299 break;
300 default:
301 LOGINT(ctx);
302 break;
303 }
304
305}
306
307API void
Radek Krejci857189e2020-09-01 13:26:36 +0200308ly_in_free(struct ly_in *in, ly_bool destroy)
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200309{
310 if (!in) {
311 return;
312 } else if (in->type == LY_IN_ERROR) {
313 LOGINT(NULL);
314 return;
315 }
316
317 if (destroy) {
318 if (in->type == LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200319 free((char *)in->start);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200320 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +0200321 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200322
323 if (in->type == LY_IN_FILE) {
324 fclose(in->method.f);
325 } else {
326 close(in->method.fd);
327
328 if (in->type == LY_IN_FILEPATH) {
329 free(in->method.fpath.filepath);
330 }
331 }
332 }
333 } else if (in->type != LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200334 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200335
336 if (in->type == LY_IN_FILEPATH) {
337 close(in->method.fpath.fd);
338 free(in->method.fpath.filepath);
339 }
340 }
341
342 free(in);
343}
Michal Vasko63f3d842020-07-08 10:10:14 +0200344
345LY_ERR
346ly_in_read(struct ly_in *in, void *buf, size_t count)
347{
348 if (in->length && (in->length - (in->current - in->start) < count)) {
349 /* EOF */
350 return LY_EDENIED;
351 }
352
353 memcpy(buf, in->current, count);
354 in->current += count;
355 return LY_SUCCESS;
356}
357
358API size_t
359ly_in_parsed(const struct ly_in *in)
360{
361 return in->current - in->func_start;
362}
363
364LY_ERR
365ly_in_skip(struct ly_in *in, size_t count)
366{
367 if (in->length && (in->length - (in->current - in->start) < count)) {
368 /* EOF */
369 return LY_EDENIED;
370 }
371
372 in->current += count;
373 return LY_SUCCESS;
374}
Radek Krejci1798aae2020-07-14 13:26:06 +0200375
376void
377lyd_ctx_free(struct lyd_ctx *lydctx)
378{
Michal Vasko32711382020-12-03 14:14:31 +0100379 ly_set_erase(&lydctx->node_types, NULL);
380 ly_set_erase(&lydctx->meta_types, NULL);
381 ly_set_erase(&lydctx->node_when, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200382}
383
384LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100385lyd_parser_find_operation(const struct lyd_node *parent, uint32_t int_opts, struct lyd_node **op)
386{
387 const struct lyd_node *iter;
388
389 *op = NULL;
390
391 if (!parent) {
392 /* no parent, nothing to look for */
393 return LY_SUCCESS;
394 }
395
396 /* we need to find the operation node if it already exists */
397 for (iter = parent; iter; iter = lyd_parent(iter)) {
398 if (iter->schema && (iter->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
399 break;
400 }
401 }
402
403 if (!iter) {
404 /* no operation found */
405 return LY_SUCCESS;
406 }
407
408 if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY))) {
409 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent %s \"%s\" node when not parsing any operation.",
410 lys_nodetype2str(iter->schema->nodetype), iter->schema->name);
411 return LY_EINVAL;
412 } else if ((iter->schema->nodetype == LYS_RPC) && !(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY))) {
413 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent RPC \"%s\" node when not parsing RPC nor rpc-reply.",
414 iter->schema->name);
415 return LY_EINVAL;
416 } else if ((iter->schema->nodetype == LYS_ACTION) && !(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY))) {
417 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent action \"%s\" node when not parsing action nor rpc-reply.",
418 iter->schema->name);
419 return LY_EINVAL;
420 } else if ((iter->schema->nodetype == LYS_NOTIF) && !(int_opts & LYD_INTOPT_NOTIF)) {
421 LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent notification \"%s\" node when not parsing a notification.",
422 iter->schema->name);
423 return LY_EINVAL;
424 }
425
426 *op = (struct lyd_node *)iter;
427 return LY_SUCCESS;
428}
429
430LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200431lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
432{
Michal Vaskoe0665742021-02-11 11:08:44 +0100433 LY_ERR rc = LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100434
Radek Krejciddace2c2021-01-08 11:30:56 +0100435 LOG_LOCSET(snode, NULL, NULL, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200436
Michal Vaskoe0665742021-02-11 11:08:44 +0100437 if ((lydctx->parse_opts & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Michal Vasko224e7772021-02-18 14:22:33 +0100438 LOGVAL(lydctx->data_ctx->ctx, LY_VCODE_UNEXPNODE, "state", snode->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100439 rc = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100440 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200441 }
442
Michal Vaskoe0665742021-02-11 11:08:44 +0100443 if (snode->nodetype == LYS_RPC) {
Michal Vasko2552ea32020-12-08 15:32:34 +0100444 if (lydctx->int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200445 if (lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100446 goto error_node_dup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200447 }
448 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100449 goto error_node_inval;
450 }
451 } else if (snode->nodetype == LYS_ACTION) {
452 if (lydctx->int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) {
453 if (lydctx->op_node) {
454 goto error_node_dup;
455 }
456 } else {
457 goto error_node_inval;
Radek Krejci1798aae2020-07-14 13:26:06 +0200458 }
459 } else if (snode->nodetype == LYS_NOTIF) {
460 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
461 if (lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100462 goto error_node_dup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200463 }
464 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100465 goto error_node_inval;
Radek Krejci1798aae2020-07-14 13:26:06 +0200466 }
467 }
468
Michal Vaskoe0665742021-02-11 11:08:44 +0100469 /* success */
470 goto cleanup;
471
472error_node_dup:
473 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
474 lys_nodetype2str(snode->nodetype), snode->name, lys_nodetype2str(lydctx->op_node->schema->nodetype),
475 lydctx->op_node->schema->name);
476 rc = LY_EVALID;
477 goto cleanup;
478
479error_node_inval:
480 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\".", lys_nodetype2str(snode->nodetype),
481 snode->name);
482 rc = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100483
484cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100485 LOG_LOCBACK(1, 0, 0, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100486 return rc;
Radek Krejci1798aae2020-07-14 13:26:06 +0200487}
488
489LY_ERR
490lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const char *value, size_t value_len,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200491 ly_bool *dynamic, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, struct lyd_node **node)
Radek Krejci1798aae2020-07-14 13:26:06 +0200492{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200493 ly_bool incomplete;
Radek Krejci1798aae2020-07-14 13:26:06 +0200494
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200495 LY_CHECK_RET(lyd_create_term(schema, value, value_len, dynamic, format, prefix_data, hints, &incomplete, node));
496
Michal Vaskoe0665742021-02-11 11:08:44 +0100497 if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko32711382020-12-03 14:14:31 +0100498 LY_CHECK_RET(ly_set_add(&lydctx->node_types, *node, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200499 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200500 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200501}
502
503LY_ERR
504lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200505 const char *name, size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
506 void *prefix_data, uint32_t hints)
Radek Krejci1798aae2020-07-14 13:26:06 +0200507{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200508 ly_bool incomplete;
Michal Vaskob68571a2020-11-06 17:18:41 +0100509 struct lyd_meta *first = NULL;
510
511 if (meta && *meta) {
512 /* remember the first metadata */
513 first = *meta;
514 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200515
516 LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
Michal Vasko871a0252020-11-11 18:35:24 +0100517 hints, 0, &incomplete));
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200518
Michal Vaskoe0665742021-02-11 11:08:44 +0100519 if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vasko32711382020-12-03 14:14:31 +0100520 LY_CHECK_RET(ly_set_add(&lydctx->meta_types, *meta, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200521 }
Michal Vaskob68571a2020-11-06 17:18:41 +0100522
523 if (first) {
524 /* always return the first metadata */
525 *meta = first;
526 }
527
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200528 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200529}