libyang  2.0.7
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
union.c
Go to the documentation of this file.
1 
15 #define _GNU_SOURCE /* strdup */
16 #include <sys/cdefs.h>
17 
18 #include "plugins_types.h"
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "libyang.h"
26 
27 /* additional internal headers for some useful simple macros */
28 #include "common.h"
29 #include "compat.h"
30 #include "plugins_internal.h" /* LY_TYPE_*_STR */
31 
57 static LY_ERR
58 union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value_union *subvalue,
59  ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lys_glob_unres *unres,
60  struct ly_err_item **err)
61 {
62  LY_ERR ret;
63  void *value;
64  size_t value_len;
65 
66  if (subvalue->format == LY_VALUE_LYB) {
67  /* skip the type index */
68  value = ((char *)subvalue->original) + 4;
69  value_len = subvalue->orig_len - 4;
70  } else {
71  value = subvalue->original;
72  value_len = subvalue->orig_len;
73  }
74 
75  ret = type->plugin->store(ctx, type, value, value_len, 0, subvalue->format, subvalue->prefix_data, subvalue->hints,
76  subvalue->ctx_node, &subvalue->value, unres, err);
77  LY_CHECK_RET((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), ret);
78 
79  if (resolve && (ret == LY_EINCOMPLETE)) {
80  /* we need the value resolved */
81  ret = subvalue->value.realtype->plugin->validate(ctx, type, ctx_node, tree, &subvalue->value, err);
82  if (ret) {
83  /* resolve failed, we need to free the stored value */
84  type->plugin->free(ctx, &subvalue->value);
85  }
86  }
87 
88  return ret;
89 }
90 
104 static LY_ERR
105 union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_value_union *subvalue,
106  ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lys_glob_unres *unres,
107  struct ly_err_item **err)
108 {
109  LY_ERR ret = LY_SUCCESS;
111  uint32_t prev_lo;
112 
113  if (!types || !LY_ARRAY_COUNT(types)) {
114  return LY_EINVAL;
115  }
116 
117  *err = NULL;
118 
119  /* turn logging off */
120  prev_lo = ly_log_options(0);
121 
122  /* use the first usable subtype to store the value */
123  for (u = 0; u < LY_ARRAY_COUNT(types); ++u) {
124  ret = union_store_type(ctx, types[u], subvalue, resolve, ctx_node, tree, unres, err);
125  if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) {
126  break;
127  }
128 
129  ly_err_free(*err);
130  *err = NULL;
131  }
132 
133  if (u == LY_ARRAY_COUNT(types)) {
134  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid union value \"%.*s\" - no matching subtype found.",
135  (int)subvalue->orig_len, (char *)subvalue->original);
136  }
137 
138  /* restore logging */
139  ly_log_options(prev_lo);
140  return ret;
141 }
142 
143 API LY_ERR
144 lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
145  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
146  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
147 {
148  LY_ERR ret = LY_SUCCESS;
149  struct lysc_type_union *type_u = (struct lysc_type_union *)type;
150  struct lyd_value_union *subvalue;
151  uint32_t type_idx;
152 
153  *err = NULL;
154 
155  /* init storage */
156  memset(storage, 0, sizeof *storage);
157  LYPLG_TYPE_VAL_INLINE_PREPARE(storage, subvalue);
158  LY_CHECK_ERR_GOTO(!subvalue, ret = LY_EMEM, cleanup);
159  storage->realtype = type;
160 
161  if (format == LY_VALUE_LYB) {
162  /* basic validation */
163  if (value_len < 4) {
164  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB union value size %zu (expected at least 4).",
165  value_len);
166  goto cleanup;
167  }
168  type_idx = *(uint32_t *)value;
169  if (type_idx >= LY_ARRAY_COUNT(type_u->types)) {
170  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB union type index %" PRIu32
171  " (type count " LY_PRI_ARRAY_COUNT_TYPE ").", type_idx, LY_ARRAY_COUNT(type_u->types));
172  goto cleanup;
173  }
174  }
175 
176  /* remember the original value */
177  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
178  subvalue->original = (void *)value;
179  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
180  } else if (value_len) {
181  subvalue->original = calloc(1, value_len);
182  LY_CHECK_ERR_GOTO(!subvalue->original, ret = LY_EMEM, cleanup);
183  memcpy(subvalue->original, value, value_len);
184  } else {
185  subvalue->original = strdup("");
186  LY_CHECK_ERR_GOTO(!subvalue->original, ret = LY_EMEM, cleanup);
187  }
188  subvalue->orig_len = value_len;
189 
190  /* store format-specific data for later prefix resolution */
191  ret = lyplg_type_prefix_data_new(ctx, value, value_len, format, prefix_data, &subvalue->format,
192  &subvalue->prefix_data);
193  LY_CHECK_GOTO(ret, cleanup);
194  subvalue->hints = hints;
195  subvalue->ctx_node = ctx_node;
196 
197  if (format == LY_VALUE_LYB) {
198  /* use the specific type to store the value */
199  ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 0, NULL, NULL, unres, err);
200  LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
201  } else {
202  /* use the first usable subtype to store the value */
203  ret = union_find_type(ctx, type_u->types, subvalue, 0, NULL, NULL, unres, err);
204  LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
205  }
206 
207  /* store canonical value, if any (use the specific type value) */
208  ret = lydict_insert(ctx, subvalue->value._canonical, 0, &storage->_canonical);
209  LY_CHECK_GOTO(ret, cleanup);
210 
211 cleanup:
212  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
213  free((void *)value);
214  }
215 
216  if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
217  lyplg_type_free_union(ctx, storage);
218  }
219  return ret;
220 }
221 
222 API LY_ERR
223 lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
224  const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
225 {
226  LY_ERR ret = LY_SUCCESS;
227  struct lysc_type_union *type_u = (struct lysc_type_union *)storage->realtype;
228  struct lyd_value_union *val = storage->subvalue;
229 
230  *err = NULL;
231 
232  if (!val->value.realtype->plugin->validate) {
233  /* nothing to resolve */
234  return LY_SUCCESS;
235  }
236 
237  /* resolve the stored value */
238  if (!val->value.realtype->plugin->validate(ctx, type, ctx_node, tree, &val->value, err)) {
239  /* resolve successful */
240  return LY_SUCCESS;
241  }
242 
243  /* Resolve failed, we have to try another subtype of the union.
244  * Unfortunately, since the realtype can change (e.g. in leafref), we are not able to detect
245  * which of the subtype's were tried the last time, so we have to try all of them again.
246  */
247  ly_err_free(*err);
248  *err = NULL;
249 
250  if (val->format == LY_VALUE_LYB) {
251  /* use the specific type to store the value */
252  uint32_t type_idx = *(uint32_t *)val->original;
253  ret = union_store_type(ctx, type_u->types[type_idx], val, 1, ctx_node, tree, NULL, err);
254  LY_CHECK_RET(ret);
255  } else {
256  /* use the first usable subtype to store the value */
257  ret = union_find_type(ctx, type_u->types, val, 1, ctx_node, tree, NULL, err);
258  LY_CHECK_RET(ret);
259  }
260 
261  /* store and resolve the value */
262  ret = union_find_type(ctx, type_u->types, val, 1, ctx_node, tree, NULL, err);
263  LY_CHECK_RET(ret);
264 
265  /* success, update the canonical value, if any generated */
266  lydict_remove(ctx, storage->_canonical);
267  LY_CHECK_RET(lydict_insert(ctx, val->value._canonical, 0, &storage->_canonical));
268  return LY_SUCCESS;
269 }
270 
271 API LY_ERR
272 lyplg_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2)
273 {
274  if (val1->realtype != val2->realtype) {
275  return LY_ENOT;
276  }
277 
278  if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
279  return LY_ENOT;
280  }
281  return val1->subvalue->value.realtype->plugin->compare(&val1->subvalue->value, &val2->subvalue->value);
282 }
283 
284 API const void *
285 lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
286  void *prefix_data, ly_bool *dynamic, size_t *value_len)
287 {
288  const void *ret;
289 
290  ret = value->subvalue->value.realtype->plugin->print(ctx, &value->subvalue->value, format, prefix_data, dynamic, value_len);
291  if (!value->_canonical && (format == LY_VALUE_CANON)) {
292  /* the canonical value is supposed to be stored now */
293  lydict_insert(ctx, value->subvalue->value._canonical, 0, (const char **)&value->_canonical);
294  }
295 
296  return ret;
297 }
298 
299 API LY_ERR
300 lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
301 {
302  LY_ERR ret = LY_SUCCESS;
303  struct lyd_value_union *orig_val = original->subvalue, *dup_val;
304 
305  /* init dup value */
306  memset(dup, 0, sizeof *dup);
307  dup->realtype = original->realtype;
308 
309  ret = lydict_insert(ctx, original->_canonical, ly_strlen(original->_canonical), &dup->_canonical);
310  LY_CHECK_GOTO(ret, cleanup);
311 
312  dup_val = calloc(1, sizeof *dup_val);
313  LY_CHECK_ERR_GOTO(!dup_val, LOGMEM(ctx); ret = LY_EMEM, cleanup);
314  dup->subvalue = dup_val;
315 
316  ret = orig_val->value.realtype->plugin->duplicate(ctx, &orig_val->value, &dup_val->value);
317  LY_CHECK_GOTO(ret, cleanup);
318 
319  if (orig_val->orig_len) {
320  dup_val->original = calloc(1, orig_val->orig_len);
321  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
322  memcpy(dup_val->original, orig_val->original, orig_val->orig_len);
323  } else {
324  dup_val->original = strdup("");
325  LY_CHECK_ERR_GOTO(!dup_val->original, LOGMEM(ctx); ret = LY_EMEM, cleanup);
326  }
327  dup_val->orig_len = orig_val->orig_len;
328 
329  dup_val->format = orig_val->format;
330  ret = lyplg_type_prefix_data_dup(ctx, orig_val->format, orig_val->prefix_data, &dup_val->prefix_data);
331  LY_CHECK_GOTO(ret, cleanup);
332 
333 cleanup:
334  if (ret) {
335  lyplg_type_free_union(ctx, dup);
336  }
337  return ret;
338 }
339 
340 API void
341 lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
342 {
343  struct lyd_value_union *val;
344 
346  LYD_VALUE_GET(value, val);
347  if (val) {
348  if (val->value.realtype) {
349  val->value.realtype->plugin->free(ctx, &val->value);
350  }
352  free(val->original);
353 
355  }
356 }
357 
365 const struct lyplg_type_record plugins_union[] = {
366  {
367  .module = "",
368  .revision = NULL,
369  .name = LY_TYPE_UNION_STR,
370 
371  .plugin.id = "libyang 2 - union,version 1",
372  .plugin.store = lyplg_type_store_union,
373  .plugin.validate = lyplg_type_validate_union,
374  .plugin.compare = lyplg_type_compare_union,
375  .plugin.sort = NULL,
376  .plugin.print = lyplg_type_print_union,
377  .plugin.duplicate = lyplg_type_dup_union,
378  .plugin.free = lyplg_type_free_union
379  },
380  {0}
381 };
libyang context handler.
LY_ERR lydict_remove(const struct ly_ctx *ctx, const char *value)
Remove specified string from the dictionary. It decrement reference counter for the string and if it ...
LY_ERR lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len, const char **str_p)
Insert string into dictionary. If the string is already present, only a reference counter is incremen...
LY_ERR
libyang's error codes returned by the libyang functions.
Definition: log.h:242
@ LYVE_DATA
Definition: log.h:279
@ LY_EINVAL
Definition: log.h:246
@ LY_EMEM
Definition: log.h:244
@ LY_ENOT
Definition: log.h:256
@ LY_EVALID
Definition: log.h:250
@ LY_SUCCESS
Definition: log.h:243
@ LY_EINCOMPLETE
Definition: log.h:252
Libyang full error structure.
Definition: log.h:287
uint32_t ly_log_options(uint32_t opts)
Set logger options. Default is LY_LOLOG | LY_LOSTORE_LAST.
const char * module
lyplg_type_print_clb print
lyplg_type_store_clb store
lyplg_type_compare_clb compare
lyplg_type_validate_clb validate
lyplg_type_dup_clb duplicate
lyplg_type_free_clb free
LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, size_t value_len, LY_VALUE_FORMAT format, const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p)
Store used prefixes in a string into an internal libyang structure used in lyd_value.
#define LYPLG_TYPE_VAL_INLINE_PREPARE(storage, type_val)
Prepare value memory for storing a specific type value, may be allocated dynamically.
#define LYPLG_TYPE_VAL_INLINE_DESTROY(type_val)
Destroy a prepared value.
LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig, void **dup)
Duplicate prefix data.
LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_msg,...)
Create and fill error structure.
void ly_err_free(void *ptr)
Destructor for the error records created with ly_err_new().
void lyplg_type_prefix_data_free(LY_VALUE_FORMAT format, void *prefix_data)
Free internal prefix data.
API void lyplg_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
Implementation of lyplg_type_free_clb for the built-in union type.
Definition: union.c:341
API LY_ERR lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
Implementation of lyplg_type_dup_clb for the built-in union type.
Definition: union.c:300
API LY_ERR lyplg_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in union type.
Definition: union.c:272
API const void * lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len)
Implementation of lyplg_type_print_clb for the built-in union type.
Definition: union.c:285
API LY_ERR lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
Implementation of lyplg_type_store_clb for the built-in union type.
Definition: union.c:144
API LY_ERR lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
Implementation of lyplg_type_validate_clb for the built-in union type.
Definition: union.c:223
#define LYPLG_TYPE_STORE_DYNAMIC
struct lyplg_type * plugin
Definition: tree_schema.h:1530
struct lysc_type ** types
Definition: tree_schema.h:1625
Compiled YANG data node.
Definition: tree_schema.h:1644
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:235
#define LY_PRI_ARRAY_COUNT_TYPE
Printing format specifier macro for LY_ARRAY_SIZE_TYPE values.
Definition: tree.h:109
#define LY_ARRAY_COUNT_TYPE
Type (i.e. size) of the sized array's size counter.
Definition: tree.h:104
@ LY_VALUE_CANON
Definition: tree.h:236
@ LY_VALUE_LYB
Definition: tree.h:241
The main libyang public header.
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:25
API for (user) types plugins.
const struct lysc_type * realtype
Definition: tree_data.h:535
void * original
Definition: tree_data.h:588
void * prefix_data
Definition: tree_data.h:594
uint32_t hints
Definition: tree_data.h:590
#define LYD_VALUE_GET(value, type_val)
Get the value in format specific to the type.
Definition: tree_data.h:573
size_t orig_len
Definition: tree_data.h:589
struct lyd_value value
Definition: tree_data.h:586
const char * _canonical
Definition: tree_data.h:532
LY_VALUE_FORMAT format
Definition: tree_data.h:591
const struct lysc_node * ctx_node
Definition: tree_data.h:595
Generic structure for a data node.
Definition: tree_data.h:754
YANG data representation.
Definition: tree_data.h:531
Special lyd_value structure for built-in union values.
Definition: tree_data.h:585
#define LOGMEM(CTX)
Definition: tree_edit.h:25
const struct lyplg_type_record plugins_union[]
Plugin information for union type implementation.
Definition: union.c:365