From 5f77bc5cc3a7277b2931c7acb8d198d7d64e9c87 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Aug 09 2017 17:58:16 +0000 Subject: Backport INI merge detection support Also, migrate to autosetup --- diff --git a/INI-Add-INI_MS_DETECT-merge-notifications.patch b/INI-Add-INI_MS_DETECT-merge-notifications.patch new file mode 100644 index 0000000..12da550 --- /dev/null +++ b/INI-Add-INI_MS_DETECT-merge-notifications.patch @@ -0,0 +1,63 @@ +From f4249d9eb263992f2804f8dc65de68e0964f9d1c Mon Sep 17 00:00:00 2001 +From: Alexander Scheel +Date: Thu, 3 Aug 2017 08:14:02 -0400 +Subject: [PATCH] INI: Add INI_MS_DETECT merge notifications +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In ini_config_augment, INI_MS_DETECT is supposed to detect +duplicate sections. Previously this was exposed only as +a return status of EEXIST. This updates the behavior to +return an error_list with warnings of files containing +one or more duplicate sections. + +Signed-off-by: Alexander Scheel +Reviewed-by: Michal Židek + +Merges: https://pagure.io/SSSD/ding-libs/issue/3167 +(cherry picked from commit fd539954e68ae49e6670f49e3ff3300cac3e4739) +--- + ini/ini_augment.c | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/ini/ini_augment.c b/ini/ini_augment.c +index 8e57c6a..0855381 100644 +--- a/ini/ini_augment.c ++++ b/ini/ini_augment.c +@@ -185,7 +185,7 @@ static int ini_aug_regex_prepare(const char *patterns[], + ini_aug_add_string(ra_err, + "Failed to process expression: %s." + " Compilation returned error: %s", +- *pat, err_str); ++ pat, err_str); + free(err_str); + + /* All error processing is done - advance to next pattern */ +@@ -814,6 +814,8 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + ((merge_flags & INI_MV2S_MASK) == INI_MV2S_DETECT)))) { + TRACE_ERROR_NUMBER("Got error in detect mode", error); + /* Fall through! */ ++ ini_aug_add_string(ra_err, "Duplicate section detected " ++ "in snippet: %s.", snip_name); + } + else { + ini_aug_add_string(ra_err, +@@ -944,14 +946,6 @@ int ini_config_augment(struct ini_cfgobj *base_cfg, + ra_err, + ra_ok, + result_cfg); +- if (error) { +- TRACE_ERROR_NUMBER("Failed to process snippet list.", +- error); +- ref_array_destroy(ra_list); +- ref_array_destroy(ra_err); +- ref_array_destroy(ra_ok); +- return error; +- } + + /* Cleanup */ + ref_array_destroy(ra_list); +-- +2.13.2 + diff --git a/INI-Extend-INI_MS_DETECT-to-be-non-exclusive.patch b/INI-Extend-INI_MS_DETECT-to-be-non-exclusive.patch new file mode 100644 index 0000000..51670a8 --- /dev/null +++ b/INI-Extend-INI_MS_DETECT-to-be-non-exclusive.patch @@ -0,0 +1,313 @@ +From b9ce9b7ecd1db5afbfc1a51def601ec03e657f32 Mon Sep 17 00:00:00 2001 +From: Alexander Scheel +Date: Wed, 12 Jul 2017 15:14:52 -0400 +Subject: [PATCH] INI: Extend INI_MS_DETECT to be non-exclusive +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This updates the INI_MS_DETECT flag such that it can be +used in combination with INI_MS_MERGE, INI_MS_OVERWRITE, +and INI_MS_PRESERVE. With the previous behavior, to detect +that duplicate sections exist in a config directory, two +separate calls to ini_augment would need to be made: +one with a copy baes_obj and INI_MS_DETECT, and one with +INI_MS_PRESERVE. + +Resolves: +https://pagure.io/SSSD/ding-libs/issue/3167 + +Signed-off-by: Alexander Scheel +Reviewed-by: Michal Židek + +Merges: https://pagure.io/SSSD/ding-libs/issue/3167 +(cherry picked from commit 3163a969bbcd10c4d9e48e191f978c6991ac01cd) +--- + ini/ini_augment.c | 4 +-- + ini/ini_configobj.c | 71 ++++++++++++++++++++++++++++++++--------------------- + ini/ini_configobj.h | 3 ++- + ini/ini_defines.h | 5 ++++ + ini/ini_parse.c | 32 +++++++++++------------- + 5 files changed, 67 insertions(+), 48 deletions(-) + +diff --git a/ini/ini_augment.c b/ini/ini_augment.c +index 0855381..e4ac94b 100644 +--- a/ini/ini_augment.c ++++ b/ini/ini_augment.c +@@ -808,9 +808,9 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + } + else if + ((error == EEXIST) && +- ((((merge_flags & INI_MS_MASK) == INI_MS_DETECT) && ++ ((ini_flags_have(INI_MS_DETECT, merge_flags) && + ((merge_flags & INI_MV2S_MASK) != INI_MV2S_ERROR)) || +- (((merge_flags & INI_MS_MASK) != INI_MS_ERROR) && ++ ((!ini_flags_have(INI_MS_ERROR, merge_flags)) && + ((merge_flags & INI_MV2S_MASK) == INI_MV2S_DETECT)))) { + TRACE_ERROR_NUMBER("Got error in detect mode", error); + /* Fall through! */ +diff --git a/ini/ini_configobj.c b/ini/ini_configobj.c +index 04e81ba..09bedc4 100644 +--- a/ini/ini_configobj.c ++++ b/ini/ini_configobj.c +@@ -270,6 +270,23 @@ static int ini_copy_cb(struct collection_item *item, + return error; + } + ++/* Check flags for flag */ ++int ini_flags_have(uint32_t flag, uint32_t flags) ++{ ++ switch (flag) { ++ case INI_MS_MERGE: ++ case INI_MS_ERROR: ++ case INI_MS_OVERWRITE: ++ case INI_MS_PRESERVE: ++ return flag == (flags & INI_MS_MODE_MASK); ++ case INI_MS_DETECT: ++ return flag == (flags & INI_MS_DETECT); ++ default: ++ TRACE_ERROR_NUMBER("Unsupported flag", flag); ++ } ++ return 0; ++} ++ + /* Copy configuration */ + int ini_config_copy(struct ini_cfgobj *ini_config, + struct ini_cfgobj **ini_new) +@@ -547,7 +564,12 @@ static int acceptor_handler(const char *property, + donor = passed_data->ci; + acceptor = *((struct collection_item **)(data)); + +- mergemode = passed_data->flags & INI_MS_MASK; ++ mergemode = passed_data->flags & INI_MS_MODE_MASK; ++ ++ if (passed_data->flags & INI_MS_DETECT) { ++ TRACE_INFO_STRING("Detect mode", ""); ++ passed_data->error = EEXIST; ++ } + + switch (mergemode) { + case INI_MS_ERROR: /* Report error and return */ +@@ -582,21 +604,6 @@ static int acceptor_handler(const char *property, + } + break; + +- case INI_MS_DETECT: /* Detect mode */ +- TRACE_INFO_STRING("Detect mode", ""); +- passed_data->error = EEXIST; +- error = merge_two_sections(donor, +- acceptor, +- passed_data->flags); +- if (error) { +- if (error != EEXIST) { +- TRACE_ERROR_NUMBER("Failed to merge " +- "sections", error); +- return error; +- } +- } +- break; +- + case INI_MS_MERGE: /* Merge */ + default: TRACE_INFO_STRING("Merge mode", ""); + error = merge_two_sections(donor, +@@ -608,14 +615,22 @@ static int acceptor_handler(const char *property, + "sections", error); + return error; + } +- passed_data->error = error; ++ ++ if (!(passed_data->flags & INI_MS_DETECT)) { ++ passed_data->error = error; ++ } ++ ++ error = EOK; + } + break; + } + +- *dummy = 1; ++ if (error == EOK) { ++ *dummy = 1; ++ } ++ + TRACE_FLOW_EXIT(); +- return EOK; ++ return error; + } + + /* Callback to process the donating config */ +@@ -671,8 +686,8 @@ static int donor_handler(const char *property, + /* Save error anyway */ + passed_data->error = acceptor_data.error; + /* If it is section DETECT or MERGE+DETECT */ +- if (((passed_data->flags & INI_MS_MASK) == INI_MS_DETECT) || +- (((passed_data->flags & INI_MS_MASK) != INI_MS_ERROR) && ++ if (ini_flags_have(INI_MS_DETECT, passed_data->flags) || ++ (!ini_flags_have(INI_MS_ERROR, passed_data->flags) && + ((passed_data->flags & INI_MV2S_MASK) == + INI_MV2S_DETECT))) { + TRACE_INFO_NUMBER("Non-critical error", +@@ -782,7 +797,7 @@ static int merge_configs(struct ini_cfgobj *donor, + + /* Check if we got error */ + if ((data.error) && +- (((collision_flags & INI_MS_MASK) == INI_MS_ERROR) || ++ (ini_flags_have(INI_MS_ERROR, collision_flags) || + ((collision_flags & INI_MV2S_MASK) == INI_MV2S_ERROR))) { + TRACE_ERROR_NUMBER("Got error in error mode", data.error); + return data.error; +@@ -806,7 +821,7 @@ static int merge_configs(struct ini_cfgobj *donor, + + /* Check if we got error */ + if ((data.error) && +- (((collision_flags & INI_MS_MASK) == INI_MS_DETECT) || ++ (ini_flags_have(INI_MS_DETECT, collision_flags) || + ((collision_flags & INI_MV2S_MASK) == INI_MV2S_DETECT))) { + TRACE_ERROR_NUMBER("Got error in error or detect mode", data.error); + error = data.error; +@@ -843,12 +858,12 @@ int valid_collision_flags(uint32_t collision_flags) + return 0; + } + +- flag = collision_flags & INI_MS_MASK; ++ /* Any combination of DETECT and a MODE flag is valid. */ ++ flag = collision_flags & INI_MS_MODE_MASK; + if ((flag != INI_MS_MERGE) && + (flag != INI_MS_OVERWRITE) && + (flag != INI_MS_ERROR) && +- (flag != INI_MS_PRESERVE) && +- (flag != INI_MS_DETECT)) { ++ (flag != INI_MS_PRESERVE)) { + TRACE_ERROR_STRING("Invalid section collision flag",""); + return 0; + } +@@ -906,9 +921,9 @@ int ini_config_merge(struct ini_cfgobj *first, + if (error) { + TRACE_ERROR_NUMBER("Failed to merge configuration", error); + if ((error == EEXIST) && +- ((((collision_flags & INI_MS_MASK) == INI_MS_DETECT) && ++ ((ini_flags_have(INI_MS_DETECT, collision_flags) && + ((collision_flags & INI_MV2S_MASK) != INI_MV2S_ERROR)) || +- (((collision_flags & INI_MS_MASK) != INI_MS_ERROR) && ++ (!ini_flags_have(INI_MS_ERROR, collision_flags) && + ((collision_flags & INI_MV2S_MASK) == INI_MV2S_DETECT)))) { + TRACE_ERROR_NUMBER("Got error in detect mode", error); + /* Fall through! */ +diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h +index 093916a..ca1e5ff 100644 +--- a/ini/ini_configobj.h ++++ b/ini/ini_configobj.h +@@ -344,7 +344,8 @@ enum ERR_PARSE { + #define INI_MS_OVERWRITE 0x0200 + /** @brief Second section is discarded */ + #define INI_MS_PRESERVE 0x0300 +-/** @brief Merge but log errors if duplicate sections are detected */ ++/** @brief Log errors if duplicate sections are detected; non-exclusive */ ++/** This defaults to MERGE, but can be used with OVERWRITE and PRESERVE **/ + #define INI_MS_DETECT 0x0400 + + /** +diff --git a/ini/ini_defines.h b/ini/ini_defines.h +index bb34510..d79019b 100644 +--- a/ini/ini_defines.h ++++ b/ini/ini_defines.h +@@ -22,6 +22,8 @@ + #ifndef INI_DEFINES_H + #define INI_DEFINES_H + ++#include ++ + #define NAME_OVERHEAD 10 + + #define SLASH "/" +@@ -115,9 +117,12 @@ + #define INI_MV2S_MASK 0x00F0 /* Merge values options mask + * for two sections. */ + #define INI_MS_MASK 0x0F00 /* Merge section options mask */ ++#define INI_MS_MODE_MASK 0x0300 /* Merge section merge mode mask */ + + + /* Different error string functions can be passed as callbacks */ + typedef const char * (*error_fn)(int error); + ++int ini_flags_have(uint32_t flag, uint32_t flags); ++ + #endif +diff --git a/ini/ini_parse.c b/ini/ini_parse.c +index e5baeca..3050223 100644 +--- a/ini/ini_parse.c ++++ b/ini/ini_parse.c +@@ -580,7 +580,7 @@ static int parser_save_section(struct parser_obj *po) + + TRACE_INFO_STRING("Merge collision detected", ""); + +- mergemode = po->collision_flags & INI_MS_MASK; ++ mergemode = po->collision_flags & INI_MS_MODE_MASK; + + switch (mergemode) { + case INI_MS_ERROR: +@@ -623,9 +623,15 @@ static int parser_save_section(struct parser_obj *po) + merge = 1; + break; + +- case INI_MS_DETECT: +- /* Detect mode */ +- TRACE_INFO_STRING("Detect mode", ""); ++ case INI_MS_MERGE: ++ /* Merge */ ++ default: ++ TRACE_INFO_STRING("Merge mode", ""); ++ merge = 1; ++ break; ++ } ++ ++ if (po->collision_flags & INI_MS_DETECT) { + po->merge_error = EEXIST; + error = save_error(po->el, + po->seclinenum, +@@ -637,15 +643,6 @@ static int parser_save_section(struct parser_obj *po) + error); + return error; + } +- merge = 1; +- break; +- +- case INI_MS_MERGE: +- /* Merge */ +- default: +- TRACE_INFO_STRING("Merge mode", ""); +- merge = 1; +- break; + } + + if (merge) { +@@ -1599,9 +1596,9 @@ static int parser_error(struct parser_obj *po) + * We check for reverse condition and return error, + * otherwise fall through. + */ +- if (!((((po->collision_flags & INI_MS_MASK) == INI_MS_ERROR) && ++ if (!(((ini_flags_have(INI_MS_ERROR, po->collision_flags)) && + (error == EEXIST)) || +- (((po->collision_flags & INI_MS_MASK) == INI_MS_MERGE) && ++ (ini_flags_have(INI_MS_ERROR, po->collision_flags) && + ((po->collision_flags & INI_MV2S_MASK) == INI_MV2S_ERROR) && + (error == EEXIST)))) { + return error; +@@ -1728,11 +1725,12 @@ int ini_config_parse(struct ini_cfgfile *file_ctx, + + error = parser_run(po); + if (error) { +- fl1 = collision_flags & INI_MS_MASK; ++ fl1 = collision_flags & INI_MS_MODE_MASK; + fl2 = collision_flags & INI_MV1S_MASK; + fl3 = collision_flags & INI_MV2S_MASK; + if ((error == EEXIST) && +- (((fl1 == INI_MS_DETECT) && ++ ((ini_flags_have(INI_MS_DETECT, collision_flags) && ++ (fl1 != INI_MS_ERROR) && + (fl2 != INI_MV1S_ERROR) && + (fl3 != INI_MV2S_ERROR)) || + ((fl2 == INI_MV1S_DETECT) && +-- +2.13.2 + diff --git a/INI-Prevent-null-return_cfg-during-augment.patch b/INI-Prevent-null-return_cfg-during-augment.patch new file mode 100644 index 0000000..d3a4384 --- /dev/null +++ b/INI-Prevent-null-return_cfg-during-augment.patch @@ -0,0 +1,160 @@ +From a1e11a21897b18addb8cf428f8afee4e95841327 Mon Sep 17 00:00:00 2001 +From: Alexander Scheel +Date: Wed, 12 Jul 2017 16:21:40 -0400 +Subject: [PATCH] INI: Prevent null return_cfg during augment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes the behavior of ini_config_augment so that result_cfg +will not be null unless out of memory. In particular, when base_cfg +is non-NULL and a fatal error occurred, result_cfg will now be a +copy of base_cfg. This reflects existing documentation, as base_cfg +will be augmented and result_cfg is the result of the merge. + +Resolves: +https://pagure.io/SSSD/ding-libs/issue/2776 + +Reviewed-by: Michal Židek +(cherry picked from commit 42cf1e061fc807b9d65a1003c1db1f0f3bebc7d7) +--- + ini/ini_augment.c | 55 +++++++++++++++++++++++++++++-------------------------- + 1 file changed, 29 insertions(+), 26 deletions(-) + +diff --git a/ini/ini_augment.c b/ini/ini_augment.c +index ea3d3da..8e57c6a 100644 +--- a/ini/ini_augment.c ++++ b/ini/ini_augment.c +@@ -679,27 +679,28 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + + TRACE_FLOW_ENTRY(); + +- len = ref_array_len(ra_list); +- if (len == 0) { +- /* List is empty - nothing to do */ +- *out_cfg = NULL; +- TRACE_FLOW_EXIT(); +- return EOK; +- } +- + error = ini_config_copy(cfg, &res_cfg); + if (error) { + TRACE_ERROR_NUMBER("Failed to copy config object", error); ++ *out_cfg = NULL; + return error; + } + ++ len = ref_array_len(ra_list); ++ if (len == 0) { ++ /* List is empty - nothing to do */ ++ *out_cfg = res_cfg; ++ TRACE_FLOW_EXIT(); ++ return EOK; ++ } ++ + /* Prepare patterns */ + error = ini_aug_regex_prepare(sections, + ra_err, + &ra_regex); + if (error) { + TRACE_ERROR_NUMBER("Failed to prepare regex array.", error); +- ini_config_destroy(res_cfg); ++ *out_cfg = res_cfg; + return error; + } + +@@ -710,9 +711,7 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + error = ini_config_create(&snip_cfg); + if (error) { + TRACE_ERROR_NUMBER("Failed to create config object", error); +- ini_config_destroy(res_cfg); +- ref_array_destroy(ra_regex); +- return error; ++ goto err; + } + + /* Process snippet */ +@@ -762,9 +761,7 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + if (error) { + TRACE_ERROR_NUMBER("Can't get errors.", error); + ini_config_destroy(snip_cfg); +- ini_config_destroy(res_cfg); +- ref_array_destroy(ra_regex); +- return error; ++ goto err; + } + + /* Copy errors into error array */ +@@ -795,9 +792,7 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + if (error) { + TRACE_ERROR_NUMBER("Failed to validate section.", error); + ini_config_destroy(snip_cfg); +- ini_config_destroy(res_cfg); +- ref_array_destroy(ra_regex); +- return error; ++ goto err; + } + } + +@@ -809,9 +804,7 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + if (error == ENOMEM) { + TRACE_ERROR_NUMBER("Merge failed.", error); + ini_config_destroy(snip_cfg); +- ini_config_destroy(res_cfg); +- ref_array_destroy(ra_regex); +- return error; ++ goto err; + } + else if + ((error == EEXIST) && +@@ -849,6 +842,20 @@ static int ini_aug_apply(struct ini_cfgobj *cfg, + *out_cfg = res_cfg; + TRACE_FLOW_EXIT(); + return error; ++ ++err: ++ ini_config_destroy(res_cfg); ++ ref_array_destroy(ra_regex); ++ ++ if (ini_config_copy(cfg, &res_cfg)) { ++ TRACE_ERROR_NUMBER("Failed to copy config object", error); ++ *out_cfg = NULL; ++ return error; ++ } ++ ++ *out_cfg = res_cfg; ++ ++ return error; + } + + /* Function to merge additional snippets of the config file +@@ -874,8 +881,6 @@ int ini_config_augment(struct ini_cfgobj *base_cfg, + struct ref_array *ra_err = NULL; + /* List of files that were merged */ + struct ref_array *ra_ok = NULL; +- /* Resulting configuration object */ +- struct ini_cfgobj *out_cfg = NULL; + + /* Check arguments */ + if (base_cfg == NULL) { +@@ -938,7 +943,7 @@ int ini_config_augment(struct ini_cfgobj *base_cfg, + merge_flags, + ra_err, + ra_ok, +- &out_cfg); ++ result_cfg); + if (error) { + TRACE_ERROR_NUMBER("Failed to process snippet list.", + error); +@@ -951,8 +956,6 @@ int ini_config_augment(struct ini_cfgobj *base_cfg, + /* Cleanup */ + ref_array_destroy(ra_list); + +- *result_cfg = out_cfg; +- + if (error_list) { + *error_list = ra_err; + } +-- +2.13.2 + diff --git a/INI-Test-INI_MS_DETECT-non-exclusive-behavior.patch b/INI-Test-INI_MS_DETECT-non-exclusive-behavior.patch new file mode 100644 index 0000000..56bca2b --- /dev/null +++ b/INI-Test-INI_MS_DETECT-non-exclusive-behavior.patch @@ -0,0 +1,309 @@ +From 7c04e712e8abafdbed02065a66b1589fa53b8f35 Mon Sep 17 00:00:00 2001 +From: Alexander Scheel +Date: Wed, 26 Jul 2017 13:35:45 -0400 +Subject: [PATCH] INI: Test INI_MS_DETECT non-exclusive behavior +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This adds test cases for the non-exclusive behavior of INI_MS_DETECT. + +Signed-off-by: Alexander Scheel +Reviewed-by: Michal Židek + +Merges: https://pagure.io/SSSD/ding-libs/issue/3167 +(cherry picked from commit e322192d1711677e78b197915b1a12537a0e510b) +--- + Makefile.am | 6 ++ + ini/ini_augment_ut_check.c | 250 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 256 insertions(+) + create mode 100644 ini/ini_augment_ut_check.c + +diff --git a/Makefile.am b/Makefile.am +index 65528a8..29d0dd6 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -70,11 +70,13 @@ libpath_utils_la_LDFLAGS = \ + + if HAVE_CHECK + check_PROGRAMS += path_utils_ut \ ++ ini_augment_ut_check \ + ini_configmod_ut_check \ + ini_parse_ut_check \ + ini_validators_ut_check \ + $(NULL) + TESTS += path_utils_ut \ ++ ini_augment_ut_check \ + ini_configmod_ut_check \ + ini_parse_ut_check \ + ini_validators_ut_check \ +@@ -349,6 +351,10 @@ ini_configmod_ut_SOURCES = ini/ini_configmod_ut.c + ini_configmod_ut_LDADD = libini_config.la libcollection.la \ + libbasicobjects.la libpath_utils.la libref_array.la + ++ini_augment_ut_check_SOURCES = ini/ini_augment_ut_check.c ++ini_augment_ut_check_CFLAGS = $(AM_CFLAGS) $(CHECK_CFLAGS) ++ini_augment_ut_check_LDADD = libini_config.la $(CHECK_LIBS) ++ + ini_configmod_ut_check_SOURCES = ini/ini_configmod_ut_check.c + ini_configmod_ut_check_CFLAGS = $(AM_CFLAGS) $(CHECK_CFLAGS) + ini_configmod_ut_check_LDADD = libini_config.la libcollection.la \ +diff --git a/ini/ini_augment_ut_check.c b/ini/ini_augment_ut_check.c +new file mode 100644 +index 0000000..be475a3 +--- /dev/null ++++ b/ini/ini_augment_ut_check.c +@@ -0,0 +1,250 @@ ++/* ++ INI LIBRARY ++ ++ Check based unit test for ini_config_augment. ++ ++ Copyright (C) Alexander Scheel 2017 ++ ++ INI Library is free software: you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ INI Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with INI Library. If not, see . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++ ++/* #define TRACE_LEVEL 7 */ ++#define TRACE_HOME ++#include "trace.h" ++#include "ini_configobj.h" ++#include "ini_config_priv.h" ++ ++static int write_to_file(char *path, char *text) ++{ ++ FILE *f = fopen(path, "w"); ++ int bytes = 0; ++ if (f == NULL) ++ return 1; ++ ++ bytes = fprintf(f, "%s", text); ++ if (bytes != strlen(text)) { ++ return 1; ++ } ++ ++ return fclose(f); ++} ++ ++static int exists_array(const char *needle, char **haystack, uint32_t count) ++{ ++ uint32_t i = 0; ++ ++ for (i = 0; i < count; i++) { ++ fprintf(stderr, "%s == %s?\n", needle, haystack[i]); ++ if (strcmp(needle, haystack[i]) == 0) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++START_TEST(test_ini_augment_merge_sections) ++{ ++ char base_path[PATH_MAX]; ++ char augment_path[PATH_MAX]; ++ ++ char config_base[] = ++ "[section]\n" ++ "key1 = first\n" ++ "key2 = exists\n"; ++ ++ char config_augment[] = ++ "[section]\n" ++ "key1 = augment\n" ++ "key3 = exists\n"; ++ ++ char *builddir; ++ ++ uint32_t flags[3] = { INI_MS_DETECT , INI_MS_DETECT | INI_MS_PRESERVE, ++ INI_MS_DETECT | INI_MS_OVERWRITE }; ++ ++ int expected_attributes_counts[3] = { 3, 2, 2 }; ++ const char *test_sections[3] = { "section", "section", "section" }; ++ const char *test_attributes[3] = { "key3", "key1", "key1" }; ++ const char *test_attribute_values[3] = {"exists", "first", "augment" }; ++ ++ int ret; ++ int iter; ++ ++ builddir = getenv("builddir"); ++ if (builddir == NULL) { ++ builddir = strdup("."); ++ } ++ ++ snprintf(base_path, PATH_MAX, "%s/tmp_augment_base.conf", builddir); ++ snprintf(augment_path, PATH_MAX, "%s/tmp_augment_augment.conf", builddir); ++ ++ ret = write_to_file(base_path, config_base); ++ fail_unless(ret == 0, "Failed to write %s: ret %d.\n", base_path, ret); ++ ++ write_to_file(augment_path, config_augment); ++ fail_unless(ret == 0, "Failed to write %s: ret %d.\n", augment_path, ret); ++ ++ for (iter = 0; iter < 3; iter++) { ++ uint32_t merge_flags = flags[iter]; ++ int expected_attributes_count = expected_attributes_counts[iter]; ++ const char *test_section = test_sections[iter]; ++ const char *test_attribute = test_attributes[iter]; ++ const char *test_attribute_value = test_attribute_values[iter]; ++ struct ini_cfgobj *in_cfg; ++ struct ini_cfgobj *result_cfg; ++ struct ini_cfgfile *file_ctx; ++ struct ref_array *error_list; ++ struct ref_array *success_list; ++ ++ char **sections; ++ int sections_count; ++ ++ char **attributes; ++ int attributes_count; ++ ++ struct value_obj *val; ++ char *val_str; ++ ++ /* Match only augment.conf */ ++ const char *m_patterns[] = { "^tmp_augment_augment.conf$", NULL }; ++ ++ /* Match all sections */ ++ const char *m_sections[] = { ".*", NULL }; ++ ++ /* Create config collection */ ++ ret = ini_config_create(&in_cfg); ++ fail_unless(ret == EOK, "Failed to create collection. Error %d\n", ++ ret); ++ ++ /* Open base.conf */ ++ ret = ini_config_file_open(base_path, 0, &file_ctx); ++ fail_unless(ret == EOK, "Failed to open file. Error %d\n", ret); ++ ++ /* Seed in_cfg with base.conf */ ++ ret = ini_config_parse(file_ctx, 1, 0, 0, in_cfg); ++ fail_unless(ret == EOK, "Failed to parse file context. Error %d\n", ++ ret); ++ ++ /* Update base.conf with augment.conf */ ++ ret = ini_config_augment(in_cfg, ++ builddir, ++ m_patterns, ++ m_sections, ++ NULL, ++ INI_STOP_ON_NONE, ++ 0, ++ INI_PARSE_NOSPACE|INI_PARSE_NOTAB, ++ merge_flags, ++ &result_cfg, ++ &error_list, ++ &success_list); ++ /* We always expect EEXIST due to DETECT being set. */ ++ fail_unless(ret == EEXIST, ++ "Failed to augment context. Error %d\n", ret); ++ ++ if (result_cfg) { ++ ini_config_destroy(in_cfg); ++ in_cfg = result_cfg; ++ result_cfg = NULL; ++ } ++ ++ /* Get a list of sections from the resulting cfg. */ ++ sections = ini_get_section_list(in_cfg, §ions_count, &ret); ++ fail_unless(ret == EOK, "Failed to get section list. Error %d\n", ret); ++ ++ /* Validate that the tested section exists. */ ++ ret = exists_array(test_section, sections, sections_count); ++ fail_if(ret == 0, "Failed to find expected section.\n"); ++ ++ /* Get a list of attributes from the resulting cfg. */ ++ attributes = ini_get_attribute_list(in_cfg, test_section, ++ &attributes_count, ++ &ret); ++ fail_unless(ret == EOK, "Failed to get attribute list. Error %d\n", ++ ret); ++ ++ /* Validate that the expected number of attributes exist. This ++ * distinguishes MERGE from PRESERVE/OVERWRITE. */ ++ fail_unless(expected_attributes_count == attributes_count, ++ "Expected %d attributes, but received %d.\n", ++ expected_attributes_count, attributes_count); ++ ++ /* Validate that the test attribute exists. This distinguishes ++ * PRESERVE from OVERWRITE. */ ++ ret = exists_array(test_attribute, attributes, attributes_count); ++ fail_if(ret == 0, "Failed to find expected attribute.\n"); ++ ++ ret = ini_get_config_valueobj(test_section, test_attribute, in_cfg, ++ 0, &val); ++ fail_unless(ret == EOK, "Failed to load value object. Error %d\n", ++ ret); ++ ++ val_str = ini_get_string_config_value(val, &ret); ++ fail_unless(ret == EOK, "Failed to get config value. Error %d\n", ret); ++ ++ /* Validate the value of the test attribute. */ ++ ret = strcmp(val_str, test_attribute_value); ++ ++ fail_unless(ret == 0, "Attribute %s didn't have expected value of " ++ "(%s): saw %s\n", test_attribute, test_attribute_value, ++ val_str); ++ ++ /* Cleanup */ ++ free(val_str); ++ ini_free_attribute_list(attributes); ++ ini_free_section_list(sections); ++ ref_array_destroy(error_list); ++ ini_config_file_destroy(file_ctx); ++ ref_array_destroy(success_list); ++ ini_config_destroy(in_cfg); ++ ini_config_destroy(result_cfg); ++ } ++ ++ remove(base_path); ++ remove(augment_path); ++ free(builddir); ++} ++END_TEST ++ ++static Suite *ini_augment_suite(void) ++{ ++ Suite *s = suite_create("ini_augment_suite"); ++ ++ TCase *tc_augment = tcase_create("ini_augment"); ++ tcase_add_test(tc_augment, test_ini_augment_merge_sections); ++ ++ suite_add_tcase(s, tc_augment); ++ ++ return s; ++} ++ ++int main(void) ++{ ++ int number_failed; ++ ++ Suite *s = ini_augment_suite(); ++ SRunner *sr = srunner_create(s); ++ srunner_run_all(sr, CK_ENV); ++ number_failed = srunner_ntests_failed(sr); ++ srunner_free(sr); ++ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; ++} +-- +2.13.2 + diff --git a/ding-libs.spec b/ding-libs.spec index 6202f91..2b437b5 100644 --- a/ding-libs.spec +++ b/ding-libs.spec @@ -1,6 +1,6 @@ Name: ding-libs Version: 0.6.0 -Release: 32%{?dist} +Release: 33%{?dist} Summary: "Ding is not GLib" assorted utility libraries Group: Development/Libraries License: LGPLv3+ @@ -19,6 +19,11 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) %global ini_config_version 1.3.0 ### Patches ### +Patch0: INI-Prevent-null-return_cfg-during-augment.patch +Patch1: INI-Add-INI_MS_DETECT-merge-notifications.patch +Patch2: INI-Extend-INI_MS_DETECT-to-be-non-exclusive.patch +Patch3: INI-Test-INI_MS_DETECT-non-exclusive-behavior.patch + ### Dependencies ### # ding-libs is a meta-package that will pull in all of its own @@ -34,6 +39,7 @@ Requires: libini_config = %{ini_config_version}-%{release} BuildRequires: autoconf BuildRequires: automake +BuildRequires: git BuildRequires: libtool BuildRequires: m4 BuildRequires: doxygen @@ -321,7 +327,7 @@ structure ############################################################################## %prep -%setup -q +%autosetup -S git %build autoreconf -ivf @@ -354,6 +360,10 @@ rm -f */doc/html/installdox rm -rf $RPM_BUILD_ROOT %changelog +* Wed Aug 09 2017 Robbie Harwood - 0.6.0-33 +- Backport INI merge detection support +- Migrate to autosetup + * Wed Aug 02 2017 Fedora Release Engineering - 0.6.0-32 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild