Blob Blame History Raw
From b9ce9b7ecd1db5afbfc1a51def601ec03e657f32 Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
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 <ascheel@redhat.com>
Reviewed-by: Michal Židek <mzidek@redhat.com>

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 <stdint.h>
+
 #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