Skip to content

Commit

Permalink
Introducing LY_CTX_STORE_INVALID_DATA
Browse files Browse the repository at this point in the history
This patch separates the build-in type validations from store
operations to allow storing a node even if the value doesn't pass the
validations. To do that a new context option was introduced:
  LY_CTX_STORE_INVALID_DATA

This option also prevent loading of advanced plugins, which cannot
really separate store and validation operations
  • Loading branch information
steweg committed Feb 16, 2024
1 parent a9756fc commit 2ae2037
Show file tree
Hide file tree
Showing 14 changed files with 398 additions and 76 deletions.
6 changes: 5 additions & 1 deletion src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx)
struct ly_in *in = NULL;
LY_ERR rc = LY_SUCCESS;
struct lys_glob_unres unres = {0};
ly_bool no_advanced_builtin = 0;

LY_CHECK_ARG_RET(NULL, new_ctx, LY_EINVAL);

Expand All @@ -284,7 +285,10 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx)
lydict_init(&ctx->dict);

/* plugins */
LY_CHECK_ERR_GOTO(lyplg_init(), LOGINT(NULL); rc = LY_EINT, cleanup);
if (options & LY_CTX_STORE_INVALID_DATA) {
no_advanced_builtin = 1;
}
LY_CHECK_ERR_GOTO(lyplg_init(no_advanced_builtin), LOGINT(NULL); rc = LY_EINT, cleanup);

if (options & LY_CTX_LEAFREF_LINKING) {
ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1);
Expand Down
10 changes: 10 additions & 0 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,16 @@ struct ly_ctx;
'require-instance false;'. It also enables usage of
[lyd_leafref_get_links](@ref lyd_leafref_get_links) and
[lyd_leafref_link_node_tree](@ref lyd_leafref_link_node_tree) APIs. */
#define LY_CTX_STORE_INVALID_DATA 0x0800 /**< By default, storing of value of given data node is subject to build-in validations
as patterns, length, ranges etc. This option bypass these validations, and allow user
to validate the values manually by additional calls as lyd_validate.
It also supresses usage of advanced built-in plugin types (ipv4-address, ipv6-address etc.),
which expects that value is already valid during storage operation. Instead the value is
processed by basic plungin (usually string) with all its behavioral implications as hex-string
comparison becoming case-sensitive.
Change of this flag during the lifetime of context is not fully supported. Once the advanced
plugins are loaded during context creation, they will be used regardless of this flag.
Therefore it is recommended to set this flag during the first context creation. */

/** @} contextoptions */

Expand Down
54 changes: 28 additions & 26 deletions src/plugins.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ plugins_insert_dir(enum LYPLG type)
#endif

LY_ERR
lyplg_init(void)
lyplg_init(ly_bool no_advanced_builtin)
{
LY_ERR ret;

Expand All @@ -463,31 +463,33 @@ lyplg_init(void)
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);

/* yang */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);

/* ietf-inet-types */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);

/* ietf-yang-types */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);

/* ietf-netconf-acm */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);

/* internal extensions */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
if (!no_advanced_builtin) {
/* yang */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);

/* ietf-inet-types */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);

/* ietf-yang-types */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);

/* ietf-netconf-acm */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);

/* internal extensions */
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
}

#ifndef STATIC
/* external types */
Expand Down
3 changes: 2 additions & 1 deletion src/plugins_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@
*
* Covers both the types and extensions plugins.
*
* @param[in] no_advanced_builtin Whether to bypass loading of advanced internal built-in plugins.
* @return LY_SUCCESS in case of success
* @return LY_EINT in case of internal error
* @return LY_EMEM in case of memory allocation failure.
*/
LY_ERR lyplg_init(void);
LY_ERR lyplg_init(ly_bool no_advanced_builtin);

/**
* @brief Remove (unload) all the plugins currently available.
Expand Down
46 changes: 38 additions & 8 deletions src/plugins_types/decimal64.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
* | 8 | yes | `int64_t *` | little-endian value represented without floating point |
*/

static LY_ERR lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);

/**
* @brief Convert decimal64 number to canonical string.
*
Expand Down Expand Up @@ -140,24 +142,52 @@ lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *typ
LY_CHECK_GOTO(ret, cleanup);
}

if (type_dec->range) {
/* check range of the number */
ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
strlen(storage->_canonical), err);
LY_CHECK_GOTO(ret, cleanup);
/* preliminary validation */
ret = lyplg_type_validate_decimal64(ctx, type, NULL, NULL, storage, err);
if ((ret != LY_SUCCESS) && (ctx->flags & LY_CTX_STORE_INVALID_DATA)) {
/* preliminary validation failed, just notify the user to validate again */
if (*err) {
ly_err_free(*err);
*err = NULL;
}
ret = LY_EINCOMPLETE;
}

cleanup:
if (options & LYPLG_TYPE_STORE_DYNAMIC) {
free((void *)value);
}

if (ret) {
if (ret && (ret != LY_EINCOMPLETE)) {
lyplg_type_free_simple(ctx, storage);
}
return ret;
}

/**
* @brief Implementation of ::lyplg_type_validate_clb for the built-in decimal64 type.
*/
static LY_ERR
lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
{
LY_ERR ret;
struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
int64_t num;

LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
*err = NULL;
num = storage->dec64;

if (type_dec->range) {
/* check range of the number */
ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
strlen(storage->_canonical), err);
LY_CHECK_RET(ret);
}

return LY_SUCCESS;
}

LIBYANG_API_DEF LY_ERR
lyplg_type_compare_decimal64(const struct lyd_value *val1, const struct lyd_value *val2)
{
Expand Down Expand Up @@ -223,7 +253,7 @@ const struct lyplg_type_record plugins_decimal64[] = {

.plugin.id = "libyang 2 - decimal64, version 1",
.plugin.store = lyplg_type_store_decimal64,
.plugin.validate = NULL,
.plugin.validate = lyplg_type_validate_decimal64,
.plugin.compare = lyplg_type_compare_decimal64,
.plugin.sort = NULL,
.plugin.print = lyplg_type_print_decimal64,
Expand Down
Loading

0 comments on commit 2ae2037

Please sign in to comment.