From: Nick Porter Date: Thu, 4 Aug 2022 10:42:26 +0000 (+0100) Subject: Define fr_pair_append_by_parent_da() for automatic creation of nested pairs X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7dd64133c151f284b831e92782be68ec374f5eb1;p=thirdparty%2Ffreeradius-server.git Define fr_pair_append_by_parent_da() for automatic creation of nested pairs plus macros for appending and populating pairs --- diff --git a/src/lib/util/pair.c b/src/lib/util/pair.c index 51d69d764ca..91c53d8b692 100644 --- a/src/lib/util/pair.c +++ b/src/lib/util/pair.c @@ -1268,6 +1268,75 @@ int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list return 0; } +/** Alloc a new fr_pair_t, adding the parent attributes if required + * + * A child pair will be added to the first available matching parent + * found. + * + * @param[in] ctx to allocate new #fr_pair_t in + * @param[out] out Pair we allocated. May be NULL if the caller doesn't + * care about manipulating the fr_pair_t. + * @param[in] list in which to insert the pair. + * @param[in] da of the attribute to create. + * @return + * - 0 on success. + * - -1 on failure. + */ +int fr_pair_append_by_da_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da) +{ + fr_pair_t *vp = NULL; + fr_da_stack_t da_stack; + fr_dict_attr_t const **find; + TALLOC_CTX *pair_ctx = ctx; + + /* + * Fast path for non-nested attributes + */ + if (da->depth <= 1) return fr_pair_append_by_da(ctx, out, list, da); + + fr_proto_da_stack_build(&da_stack, da); + find = &da_stack.da[0]; + + /* + * Walk down the da stack looking for candidate parent + * attributes and then allocating the leaf. + */ + while (true) { + fr_assert((*find)->depth <= da->depth); + + /* + * We're not at the leaf, look for a potential parent + */ + if ((*find) != da) vp = fr_pair_find_by_da(list, NULL, *find); + + /* + * Nothing found, create the pair + */ + if (!vp) { + if (fr_pair_append_by_da(pair_ctx, &vp, list, *find) < 0) { + *out = NULL; + return -1; + } + } + + /* + * We're at the leaf, return + */ + if ((*find) == da) { + *out = vp; + return 0; + } + + /* + * Prepare for next level + */ + list = &vp->vp_group; + pair_ctx = vp; + vp = NULL; + find++; + } +} + /** Return the first fr_pair_t matching the #fr_dict_attr_t or alloc a new fr_pair_t (and append) * * @param[in] ctx to allocate any new #fr_pair_t in. diff --git a/src/lib/util/pair.h b/src/lib/util/pair.h index 7078245ec3b..694d7ce3df6 100644 --- a/src/lib/util/pair.h +++ b/src/lib/util/pair.h @@ -291,6 +291,28 @@ do { \ } \ } while (0) +#define fr_pair_list_append_by_da_parent(_ctx, _vp, _list, _attr, _val, _tainted) \ +do { \ + _vp = NULL; \ + if (fr_pair_append_by_da_parent(_ctx, &_vp, _list, _attr) < 0) break; \ + fr_value_box(&_vp->data, _val, _tainted); \ + if (!vp_da_data_type_check(_vp)) { \ + fr_pair_delete(_list, _vp); \ + _vp = NULL; \ + } \ +} while (0) + +#define fr_pair_list_append_by_da_parent_len(_ctx, _vp, _list, _attr, _val, _len, _tainted) \ +do { \ + _vp = NULL; \ + if (fr_pair_append_by_da_parent(_ctx, &vp, _list, _attr) < 0) break; \ + fr_value_box_len(_vp, &_vp->data, _val, _len, _tainted); \ + if (!vp_da_data_type_check(_vp)) { \ + fr_pair_delete(_list, _vp); \ + _vp = NULL; \ + } \ +} while (0) + /** Prepend a pair to a list, assigning its value * * Version for simple C data types @@ -465,6 +487,9 @@ int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da) CC_HINT(nonnull(3,4)); +int fr_pair_append_by_da_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, + fr_dict_attr_t const *da) CC_HINT(nonnull(3,4)); + int fr_pair_update_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da, unsigned int n) CC_HINT(nonnull(3,4));