[prev in list] [next in list] [prev in thread] [next in thread] 

List:       sssd-devel
Subject:    [SSSD] [INI] Patches for ding-libs: Merging config sections, handling metadata, remaining Coverity i
From:       dpal () redhat ! com (Dmitri Pal)
Date:       2011-01-24 18:11:59
Message-ID: 4D3DC0EF.1070703 () redhat ! com
[Download RAW message or body]

Sumit Bose wrote:
> On Mon, Jan 03, 2011 at 06:12:38PM -0500, Dmitri Pal wrote:
> 
> > Please see the attached patches. I tried to split the patches logically
> > into manageable sets.
> > Unfortunately I made a minor mistake and I am afraid I will do something
> > wrong to fix it.
> > I merged two wrong patches. Fortunately it was three liner with 1 liner
> > so it is not a big of the deal but I am really scared that I will do
> > something wrong and loose the work I have done.
> > So I hope it is Ok to send it as is.
> > 
> > 0001--INI-Making-Coverity-happy.patch  <- this is the patch I submitted
> > earlier that I merged by mistake. I was supposed to merge it with patch
> > 25 but picked the wrong one instead.
> > Patch 25 addresses the real issue found by Coverity as mentioned in
> > Stephen's review mail but it did not apply cleanly since it relies on
> > some code from the patches in the middle. 
> > 
> > 0002--INI-Adding-missing-function-declararion.patch  <- this is the
> > patch that was rejected from the second set sent earlier. Fixed
> > according to review comment.
> > 
> > 0003--BUILD-Allow-trace-per-component.patch <- This patch allows tracing
> > per component
> > 
> > The following set of patches introduces the merging of sections during
> > the reading of the file:
> > 0004--INI-New-error-codes-and-messages.patch
> > 0005--INI-New-merge-flags.patch
> > 0006--INI-Add-new-vars-to-parse-structure.patch
> > 0007--INI-Add-save_error-function.patch
> > 0008--INI-Change-parse_error-to-use-save_error.patch
> > 0009--INI-Preparing-for-merging-sections.patch
> > 0010--INI-Enhance-value-processing.patch
> > 0011--INI-Use-section-line-number.patch
> > 0012--INI-Refactor-section-processing.patch
> > 0013--INI-Return-error-in-DETECT-mode.patch
> > 0014--INI-New-test-files-for-section-merge.patch
> > 0015--INI-Test-DETECT-mode-and-use-new-file.patch
> > 0016--INI-Test-for-all-section-merge-modes.patch
> > 
> > Patches related porting of the meta data from old way of doing things to
> > the new way of doing things:
> > 0017--INI-Separate-close-and-destroy.patch
> > 
> 
> You should set file_ctx->file to NULL after fclose(file_ctx->file) to
> make the if(file_ctx->file) checks work in ini_config_file_close() and
> ini_config_file_destroy().
> 
> There are tab indents in merge_values_test() and merge_section_test().
> 
> 
> > 0018--INI-Function-to-reopen-file.patch
> > 0019--INI-Metadata-collection-is-gone.patch
> > 
> 
> You remove metadata from struct ini_cfgfile without removing all
> references to metadata in the same patch. You should make clear that
> more patches are needed to create a buildable version of libini or
> remove all references in this patch.
> 
> I wonder is the following is a change of defaults. With the patch the
> new file_ctx->file_stats are only set if INI_META_STATS is set while
> previously file-ctx>metadata was set unconditionally.
> 
> 
> > 0020--INI-Check-access-function.patch
> > 
> 
> I wonder if it is necessary to return EINVAL if flags == 0. I would say
> in this case no checks are requested and EOK could be returned?
> 
> I would prefer to copy file_ctx->file_stats.st_mode instead of modifying
> it, e.g. you might want to know the file type later on.
> 
> 
> > 0021--INI-Avoid-double-free.patch <- patch related to 17 (missed check)
> > 
> 
> oops, so you can ignore my comment to 00017, let's see if there is also
> a patch for ini_config_file_destroy(). "I might squash this patch into
> one of the previous ones." Yes, please.
> 
> 
> > 0022--INI-Function-to-check-for-changes.patch
> > 0023--INI-Tests-for-access-and-changes.patch
> > 
> 
> Why do you need sleep(1) ?
> The man page of system() does not mention that system() sets errno,
> please check the return code instead.
> 
> 
> > 0024--INI-Rename-error-print-function.patch <- rename error printing
> > function for consistency with new interface
> > 
> > 
> 
> Maybe ini_print_errors() should print a deprecated warning to make
> migrations easier.
> 
> 
> > 0025--INI-Initialize-variables-in-loops.patch <- Coverity issue
> > addressed. Related to patch 0001.
> > 
> > 0026--INI-Exposing-functions.patch <- Make some internal functions reusable
> > 
> > There is also patch 27. It is a piece of new functionality. It is a
> > preview. Please see the comment before reviewing it.
> > Do I need to split it into multiple patches or it is Ok as is? It is
> > pretty big but all changes are in one file and logically related.
> > The UNIT test is missing so I am not claiming it actually works as
> > expected.
> > 
> 
> I didn't had a look at 0027 so far.
> 
> bye,
> Sumit
> 
> 

Thank you for the review.
I will address the issues as soon as I find a moment.

> > -- 
> > Thank you,
> > Dmitri Pal
> > 
> > Sr. Engineering Manager IPA project,
> > Red Hat Inc.
> > 
> > 
> > -------------------------------
> > Looking to carve out IT costs?
> > www.redhat.com/carveoutcosts/
> > 
> > 
> 
> 
> > From 2cb4d6ad0bfad2170e09152379f29de2b9c29196 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Fri, 24 Dec 2010 00:38:48 -0500
> > Subject: [PATCH] [INI] Making Coverity happy
> > 
> > Coverity found issues 10078 & 10079. This patch
> > should make it happy, however I think that Coverity
> > is wrong unless I am missing something. If I am
> > I hope that this patch would be able to reveal the
> > real issue if any.
> > For now just renaming a variable.
> > 
> > [INI] Added missing initialization
> > 
> > One liner to initialize a variable.
> > ---
> > ini/ini_configobj.c   |    2 +-
> > ini/ini_valueobj_ut.c |    9 +++++----
> > 2 files changed, 6 insertions(+), 5 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.c b/ini/ini_configobj.c
> > index 3e5dec4733a49d03e44185637592f0efdbe7db3c..5e5e40b566abdf3ce2cbc225babe4b1e20c2dd47 \
> >                 100644
> > --- a/ini/ini_configobj.c
> > +++ b/ini/ini_configobj.c
> > @@ -215,7 +215,7 @@ int ini_config_copy(struct ini_cfgobj *ini_config,
> > struct ini_cfgobj **ini_new)
> > {
> > int error = EOK;
> > -    struct ini_cfgobj *new_co;
> > +    struct ini_cfgobj *new_co = NULL;
> > 
> > TRACE_FLOW_ENTRY();
> > 
> > diff --git a/ini/ini_valueobj_ut.c b/ini/ini_valueobj_ut.c
> > index 767a64cc2fe624800bed7e9dc4b53a90fa2d59c2..af62c140d215f9298dd5671d8aa544a84ef254b1 \
> >                 100644
> > --- a/ini/ini_valueobj_ut.c
> > +++ b/ini/ini_valueobj_ut.c
> > @@ -378,6 +378,7 @@ int vo_basic_test(void)
> > */
> > 
> > struct value_obj *vo = NULL;
> > +    struct value_obj *other_vo = NULL;
> > uint32_t wrap = 0;
> > struct ini_comment *ic = NULL;
> > FILE *ff = NULL;
> > @@ -429,7 +430,7 @@ int vo_basic_test(void)
> > }
> > 
> > /* Run other create test here */
> > -    error = other_create_test(ff, &vo);
> > +    error = other_create_test(ff, &other_vo);
> > if (error) {
> > printf("Create test failed %d.\n", error);
> > fclose(ff);
> > @@ -437,15 +438,15 @@ int vo_basic_test(void)
> > }
> > 
> > /* Run modify test here */
> > -    error = modify_test(ff, vo);
> > +    error = modify_test(ff, other_vo);
> > if (error) {
> > printf("Modify test failed %d.\n", error);
> > fclose(ff);
> > -        value_destroy(vo);
> > +        value_destroy(other_vo);
> > return error;
> > }
> > 
> > -    value_destroy(vo);
> > +    value_destroy(other_vo);
> > 
> > 
> > ic = NULL;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 68ecd60fac51706c743a5c4a4cfe87ec6ca9d304 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Fri, 24 Dec 2010 21:27:24 -0500
> > Subject: [PATCH] [INI] Adding missing function declararion.
> > 
> > One-liner that eliminates compilation warning.
> > 
> > [INI] Include proper header
> > 
> > Value object needs its own header file.
> > ---
> > ini/ini_valueobj.c |    1 +
> > 1 files changed, 1 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_valueobj.c b/ini/ini_valueobj.c
> > index a90fa451468aecc6c04f4411675ab67613a59cbe..f196c1ab3195db7cbe616e6e1275c656919fe156 \
> >                 100644
> > --- a/ini/ini_valueobj.c
> > +++ b/ini/ini_valueobj.c
> > @@ -29,6 +29,7 @@
> > #include "ini_comment.h"
> > #include "ini_defines.h"
> > #include "trace.h"
> > +#include "ini_valueobj.h"
> > 
> > struct value_obj {
> > struct ref_array *raw_lines;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 574be6d8c0896c8bee0c16224f52c2dbea48a44e Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Fri, 24 Dec 2010 22:38:42 -0500
> > Subject: [PATCH] [BUILD] Allow trace per component
> > 
> > This patch add ability to build tracing
> > for each component independently.
> > ---
> > Makefile.am  |   50 ++++++++++++++++++++++++++++++++++++++++++++++----
> > configure.ac |   15 ++++++++++++++-
> > 2 files changed, 60 insertions(+), 5 deletions(-)
> > 
> > diff --git a/Makefile.am b/Makefile.am
> > index 0946169308bab6585c93cca36d45b360b565f6b5..1780e9b234e68006af910413b3e8312c9db72c7b \
> >                 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -1,4 +1,7 @@
> > -TRACE_LEVEL=@TRACE_VAR@
> > +TRACE_INI=@TRACE_INI@
> > +TRACE_COLLECTION=@TRACE_COLLECTION@
> > +TRACE_REFARRAY=@TRACE_REFARRAY@
> > +TRACE_BASICOBJECTS=@TRACE_BASICOBJECTS@
> > 
> > RPMBUILD ?= $(PWD)/rpmbuild
> > 
> > @@ -28,8 +31,7 @@ AM_CPPFLAGS = \
> > -I$(srcdir)/ini \
> > -I$(srcdir)/basicobjects \
> > -I$(srcdir) \
> > -    -I$(srcdir)/trace \
> > -    $(TRACE_LEVEL)
> > +    -I$(srcdir)/trace
> > 
> > ACLOCAL_AMFLAGS = -I m4
> > 
> > @@ -132,6 +134,10 @@ libcollection_la_SOURCES = \
> > libcollection_la_LDFLAGS = \
> > -version-info 3:0:0
> > 
> > +libcollection_la_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_COLLECTION)
> > +
> > check_PROGRAMS += \
> > collection_ut \
> > collection_stack_ut \
> > @@ -142,11 +148,21 @@ TESTS += \
> > collection_queue_ut
> > 
> > collection_ut_SOURCES = collection/collection_ut.c
> > +collection_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_COLLECTION)
> > +
> > collection_ut_LDADD = libcollection.la
> > collection_stack_ut_SOURCES = collection/collection_stack_ut.c
> > collection_stack_ut_LDADD = libcollection.la
> > +collection_stack_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_COLLECTION)
> > collection_queue_ut_SOURCES = collection/collection_queue_ut.c
> > collection_queue_ut_LDADD = libcollection.la
> > +collection_queue_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_COLLECTION)
> > 
> > collection-docs:
> > if HAVE_DOXYGEN
> > @@ -167,10 +183,15 @@ libref_array_la_SOURCES = \
> > trace/trace.h
> > libref_array_la_LDFLAGS = \
> > -version-info 1:0:0
> > -
> > +libref_array_la_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_REFARRAY)
> > check_PROGRAMS += ref_array_ut
> > TESTS += ref_array_ut
> > ref_array_ut_SOURCES = refarray/ref_array_ut.c
> > +ref_array_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_REFARRAY)
> > ref_array_ut_LDADD = libref_array.la
> > 
> > dist_doc_DATA += refarray/README.ref_array
> > @@ -194,11 +215,17 @@ libbasicobjects_la_SOURCES = \
> > trace/trace.h
> > libbasicobjects_la_LDFLAGS = \
> > -version-info 1:0:0
> > +libbasicobjects_la_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_BASICOBJECTS)
> > 
> > check_PROGRAMS += simplebuffer_ut
> > TESTS += simplebuffer_ut
> > simplebuffer_ut_SOURCES = basicobjects/simplebuffer_ut.c
> > simplebuffer_ut_LDADD = libbasicobjects.la
> > +simplebuffer_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_BASICOBJECTS)
> > 
> > basicobjects-docs:
> > if HAVE_DOXYGEN
> > @@ -243,6 +270,9 @@ libini_config_la_LIBADD = \
> > libbasicobjects.la
> > libini_config_la_LDFLAGS = \
> > -version-info 3:0:0
> > +libini_config_la_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_INI)
> > 
> > dist_noinst_DATA += \
> > ini/ini.conf \
> > @@ -268,15 +298,27 @@ ini_config_ut_SOURCES = ini/ini_config_ut.c
> > ini_config_ut_LDADD = \
> > libini_config.la \
> > libcollection.la
> > +ini_config_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_INI)
> > 
> > ini_comment_ut_SOURCES = ini/ini_comment_ut.c
> > ini_comment_ut_LDADD = libini_config.la
> > +ini_comment_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_INI)
> > 
> > ini_valueobj_ut_SOURCES = ini/ini_valueobj_ut.c
> > ini_valueobj_ut_LDADD = libini_config.la
> > +ini_valueobj_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_INI)
> > 
> > ini_parse_ut_SOURCES = ini/ini_parse_ut.c
> > ini_parse_ut_LDADD = libini_config.la
> > +ini_parse_ut_CFLAGS = \
> > +    $(AM_CFLAGS) \
> > +    $(TRACE_INI)
> > 
> > ini_config-docs:
> > if HAVE_DOXYGEN
> > diff --git a/configure.ac b/configure.ac
> > index 2e22e8a6aaac271dfa4841c17f98411967e09fd9..d1b68f5fd76654e899738f6c8a29b516a23592c5 \
> >                 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -39,11 +39,24 @@ AC_PATH_PROG([DOXYGEN], [doxygen], [false])
> > AM_CONDITIONAL([HAVE_DOXYGEN], [test x$DOXYGEN != xfalse ])
> > 
> > # Enable trace build
> > +# To turn on the tracing of one of the componenets one has not only
> > +# to enable it with --enable-trace but to drop a file named "trace"
> > +# into a corresponding directory.
> > +# Tracing can be built for collection, ini, refarray or basicobjects.
> > +# The approach allows building different libraries with trace
> > +# independent of each other.
> > AC_ARG_ENABLE([trace],
> > [AS_HELP_STRING([--enable-trace[=LEVEL]],[build with low level tracing \
> > enabled])], [trace_level="$enableval"],
> > [trace_level="0"])
> > -AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] \
> > ],[AC_SUBST([TRACE_VAR],["-DTRACE_LEVEL=$trace_level"])]) +AS_IF([test \
> > ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] -a [ -e $srcdir/ini/trace] \
> > ], +      [AC_SUBST([TRACE_INI],["-DTRACE_LEVEL=$trace_level"])])
> > +AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] -a [ -e \
> > $srcdir/collection/trace] ], +      \
> > [AC_SUBST([TRACE_COLLECTION],["-DTRACE_LEVEL=$trace_level"])]) +AS_IF([test \
> > ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] -a [ -e \
> > $srcdir/refarray/trace] ], +      \
> > [AC_SUBST([TRACE_REFARRAY],["-DTRACE_LEVEL=$trace_level"])]) +AS_IF([test \
> > ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] -a [ -e \
> > $srcdir/basicobjects/trace] ], +      \
> > [AC_SUBST([TRACE_BASICOBJECTS],["-DTRACE_LEVEL=$trace_level"])]) 
> > AC_CHECK_SIZEOF([long])
> > AC_CHECK_SIZEOF([long long])
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 6a66a986e962554b161ddb46f8b1e85a7c791e27 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sat, 25 Dec 2010 23:24:35 -0500
> > Subject: [PATCH] [INI] New error codes and messages
> > 
> > Patch consists of two parts:
> > * Adding new constants for error messages to ini_configobj.h file
> > * Making ini_print.c use this header file instead of the old one.
> > ---
> > ini/ini_configobj.h |   12 ++++++----
> > ini/ini_print.c     |   54 +++++++++++++++++++++++++++++++++++++++++++++++---
> > 2 files changed, 57 insertions(+), 9 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index 88a8704277facb0f8883b2df28a709b26ae311f7..36558a701a86f6f656f2d0e3b155b9d901177fa7 \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -72,13 +72,15 @@
> > #define ERR_READ            8
> > /** @brief Line starts with space when it should not (Error). */
> > #define ERR_SPACE           9
> > +/** @brief Duplicate key is not allowed (Error). */
> > +#define ERR_DUPKEY          10
> > +/** @brief Duplicate key is detected while merging sections (Error). */
> > +#define ERR_DUPKEYSEC       11
> > +/** @brief Duplicate section is not allowed (Error). */
> > +#define ERR_DUPSECTION      12
> > 
> > /** @brief Size of the error array. */
> > -#define ERR_MAXPARSE        ERR_SPACE
> > -
> > -/**
> > - * @}
> > - */
> > +#define ERR_MAXPARSE        ERR_DUPSECTION
> > 
> > 
> > /**
> > diff --git a/ini/ini_print.c b/ini/ini_print.c
> > index 0430976cd56e89313cb386b99ad387263498c639..1dcfa54bfd72daf2c790d04c37ff2b3107eb7295 \
> >                 100644
> > --- a/ini/ini_print.c
> > +++ b/ini/ini_print.c
> > @@ -31,7 +31,8 @@
> > #include "collection.h"
> > #include "collection_tools.h"
> > #include "ini_defines.h"
> > -#include "ini_config.h"
> > +#include "ini_config_priv.h"
> > +#include "ini_configobj.h"
> > 
> > 
> > /*============================================================*/
> > @@ -42,6 +43,16 @@
> > * check that the class IDs did not get reused over time by
> > * other classes.
> > */
> > +/**
> > + * @brief Collection of error collections.
> > + *
> > + * When multiple files are read during one call
> > + * each file has its own set of parsing errors
> > + * and warnings. This is the collection
> > + * of such sets.
> > + */
> > +#define COL_CLASS_INI_PESET       COL_CLASS_INI_BASE + 3
> > +
> > /** @brief Collection of grammar errors.
> > *
> > * Reserved for future use.
> > @@ -53,6 +64,37 @@
> > */
> > #define COL_CLASS_INI_VERROR      COL_CLASS_INI_BASE + 6
> > 
> > +/**
> > + * @}
> > + */
> > +
> > +/**
> > + * @defgroup gramerr Grammar errors and warnings
> > + *
> > + * Placeholder for now. Reserved for future use.
> > + *
> > + * @{
> > + */
> > +#define ERR_MAXGRAMMAR      0
> > +/**
> > + * @}
> > + */
> > +
> > +/**
> > + * @defgroup valerr Validation errors and warnings
> > + *
> > + * Placeholder for now. Reserved for future use.
> > + *
> > + * @{
> > + */
> > +#define ERR_MAXVALID        0
> > +
> > +
> > +/**
> > + * @}
> > + */
> > +
> > +
> > #ifdef HAVE_VALIDATION
> > 
> > /** @brief Collection of lines from the INI file.
> > @@ -78,7 +120,11 @@ static const char *parsing_error_str(int parsing_error)
> > _("Property name is too long."),
> > _("Failed to read line."),
> > _("Invalid space character at the "
> > -                                  "beginning of the line.")
> > +                                  "beginning of the line."),
> > +                                _("Duplicate key is not allowed."),
> > +                                _("Duplicate key is detected while "
> > +                                  "merging sections."),
> > +                                _("Duplicate section is not allowed.")
> > };
> > 
> > /* Check the range */
> > @@ -208,7 +254,7 @@ static void print_error_list(FILE *file,
> > struct collection_iterator *iterator;
> > int error;
> > struct collection_item *item = NULL;
> > -    struct parse_error *pe;
> > +    struct ini_parse_error *pe;
> > unsigned int count;
> > 
> > TRACE_FLOW_STRING("print_error_list", "Entry");
> > @@ -256,7 +302,7 @@ static void print_error_list(FILE *file,
> > }
> > else {
> > /* Put error into provided format */
> > -            pe = (struct parse_error *)(col_get_item_data(item));
> > +            pe = (struct ini_parse_error *)(col_get_item_data(item));
> > fprintf(file, line_format,
> > col_get_item_property(item, NULL), /* Error or warning */
> > pe->error,                         /* Error */
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 2323da5507a13b5267152482a212442685cfcf05 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sat, 25 Dec 2010 23:29:05 -0500
> > Subject: [PATCH] [INI] New merge flags
> > 
> > Adding "DETECT" merge modes.
> > These modes would be useable for dry run cases to detect
> > if there are any potential merge conflicts.
> > Patch just defines new constans and adds input checks.
> > ---
> > ini/ini_configobj.h |    6 ++++++
> > ini/ini_fileobj.c   |    9 ++++++---
> > 2 files changed, 12 insertions(+), 3 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index 36558a701a86f6f656f2d0e3b155b9d901177fa7..f0c6882dbb1e066972f98309bf78a99670b985c5 \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -108,6 +108,8 @@
> > #define INI_MV1S_PRESERVE  0x0002
> > /** @brief Duplicates are allowed */
> > #define INI_MV1S_ALLOW     0x0003
> > +/** @brief Duplicates are allowed but errors are logged */
> > +#define INI_MV1S_DETECT    0x0004
> > 
> > /**
> > * @}
> > @@ -133,6 +135,8 @@
> > #define INI_MV2S_PRESERVE  0x0020
> > /** @brief Duplicates are allowed */
> > #define INI_MV2S_ALLOW     0x0030
> > +/** @brief Duplicates are allowed but errors are logged */
> > +#define INI_MV2S_DETECT    0x0040
> > 
> > /**
> > * @}
> > @@ -159,6 +163,8 @@
> > #define INI_MS_PRESERVE  0x0300
> > /** @brief Duplicates are allowed */
> > #define INI_MS_ALLOW     0x0400
> > +/** @brief Duplicates are allowed but errors are logged */
> > +#define INI_MS_DETECT    0x0500
> > 
> > /**
> > * @}
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index 94494f78a41b6af5e44686134ab1e48290b9ab38..7bc599b948563964830f9ade75966cf4f9aa3018 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -44,7 +44,8 @@ static int valid_collision_flags(uint32_t collision_flags)
> > if ((flag != INI_MV1S_OVERWRITE) &&
> > (flag != INI_MV1S_ERROR) &&
> > (flag != INI_MV1S_PRESERVE) &&
> > -        (flag != INI_MV1S_ALLOW)) {
> > +        (flag != INI_MV1S_ALLOW) &&
> > +        (flag != INI_MV1S_DETECT)) {
> > TRACE_ERROR_STRING("Invalid value collision flag","");
> > return 0;
> > }
> > @@ -53,7 +54,8 @@ static int valid_collision_flags(uint32_t collision_flags)
> > if ((flag != INI_MV2S_OVERWRITE) &&
> > (flag != INI_MV2S_ERROR) &&
> > (flag != INI_MV2S_PRESERVE) &&
> > -        (flag != INI_MV2S_ALLOW)) {
> > +        (flag != INI_MV2S_ALLOW) &&
> > +        (flag != INI_MV2S_DETECT)) {
> > TRACE_ERROR_STRING("Invalid value cross-section collision flag","");
> > return 0;
> > }
> > @@ -63,7 +65,8 @@ static int valid_collision_flags(uint32_t collision_flags)
> > (flag != INI_MS_OVERWRITE) &&
> > (flag != INI_MS_ERROR) &&
> > (flag != INI_MS_PRESERVE) &&
> > -        (flag != INI_MS_ALLOW)) {
> > +        (flag != INI_MS_ALLOW) &&
> > +        (flag != INI_MS_DETECT)) {
> > TRACE_ERROR_STRING("Invalid section collision flag","");
> > return 0;
> > }
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 45efaa8dc8de649d4714066ccd3b8441dd55b0e6 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sat, 25 Dec 2010 23:36:06 -0500
> > Subject: [PATCH] [INI] Add new vars to parse structure
> > 
> > Adding new varibles to the internal parsing structure
> > and initializing them.
> > ---
> > ini/ini_parse.c |   14 +++++++++++++-
> > 1 files changed, 13 insertions(+), 1 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index 18edc629e90fe47597357b7953f06990ab5a48f0..9667a02926ef7d984886896b206997a841f04619 \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -69,8 +69,11 @@ struct parser_obj {
> > uint32_t linenum;
> > /* Line number of the last found key */
> > uint32_t keylinenum;
> > +    /* Line number of the last found section */
> > +    uint32_t seclinenum;
> > /* Internal variables */
> > struct collection_item *sec;
> > +    struct collection_item *merge_sec;
> > struct ini_comment *ic;
> > char *last_read;
> > uint32_t last_read_len;
> > @@ -78,12 +81,15 @@ struct parser_obj {
> > uint32_t key_len;
> > struct ref_array *raw_lines;
> > struct ref_array *raw_lengths;
> > +    char *merge_key;
> > +    struct value_obj *merge_vo;
> > +    /* Merge error */
> > +    uint32_t merge_error;
> > int ret;
> > };
> > 
> > typedef int (*action_fn)(struct parser_obj *);
> > 
> > -
> > #define PARSE_ACTION       "action"
> > 
> > /* Actions */
> > @@ -181,9 +187,12 @@ static int parser_create(FILE *file,
> > 
> > /* Initialize internal varibles */
> > new_po->sec = NULL;
> > +    new_po->merge_sec = NULL;
> > new_po->ic = NULL;
> > new_po->last_error = 0;
> > new_po->linenum = 0;
> > +    new_po->keylinenum = 0;
> > +    new_po->seclinenum = 0;
> > new_po->last_read = NULL;
> > new_po->last_read_len = 0;
> > new_po->key = NULL;
> > @@ -191,6 +200,9 @@ static int parser_create(FILE *file,
> > new_po->raw_lines = NULL;
> > new_po->raw_lengths = NULL;
> > new_po->ret = EOK;
> > +    new_po->merge_key = NULL;
> > +    new_po->merge_vo = NULL;
> > +    new_po->merge_error = 0;
> > 
> > /* Create a queue */
> > new_po->queue = NULL;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 27cf7bc5c1089380cc7bc893deee8eb88db2d3d4 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sat, 25 Dec 2010 23:44:52 -0500
> > Subject: [PATCH] [INI] Add save_error function
> > 
> > Create a function to add error into error list.
> > ---
> > ini/ini_parse.c |   29 +++++++++++++++++++++++++++++
> > 1 files changed, 29 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index 9667a02926ef7d984886896b206997a841f04619..a2e05f9311d38ff5904b016c5c8335d56b26a170 \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -99,6 +99,13 @@ typedef int (*action_fn)(struct parser_obj *);
> > #define PARSE_ERROR     3 /* Handle error */
> > #define PARSE_DONE      4 /* We are done */
> > 
> > +/* Declarations of the reusble functions: */
> > +static int complete_value_processing(struct parser_obj *po);
> > +static int save_error(struct collection_item *el,
> > +                      unsigned line,
> > +                      int error,
> > +                      int idx);
> > +
> > 
> > int is_just_spaces(const char *str, uint32_t len)
> > {
> > @@ -946,6 +953,28 @@ static int parser_post(struct parser_obj *po)
> > return EOK;
> > }
> > 
> > +
> > +static int save_error(struct collection_item *el,
> > +                      unsigned line,
> > +                      int inerr,
> > +                      int idx)
> > +{
> > +    int error = EOK;
> > +    const char *errtxt[] = { ERROR_TXT, WARNING_TXT };
> > +    struct ini_parse_error pe;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    /* Clear the warning bit */
> > +    pe.error = inerr;
> > +    pe.line = line;
> > +    error = col_add_binary_property(el, NULL,
> > +                                    errtxt[idx], &pe, sizeof(pe));
> > +    TRACE_FLOW_RETURN(error);
> > +    return error;
> > +}
> > +
> > +
> > /* Error and warning processing */
> > static int parser_error(struct parser_obj *po)
> > {
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From e5a6bb7e8fab4b7e23f31ee1ab5ce10bf7dd33d5 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sat, 25 Dec 2010 23:48:35 -0500
> > Subject: [PATCH] [INI] Change parse_error to use save_error
> > 
> > * Changed parse_error to use save_error function
> > created in previous commit.
> > * Fixed comment to be more clear.
> > ---
> > ini/ini_parse.c |   18 +++++++++---------
> > 1 files changed, 9 insertions(+), 9 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index a2e05f9311d38ff5904b016c5c8335d56b26a170..e7eab28211655f7a225202552fd96b68c1e09450 \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -981,19 +981,17 @@ static int parser_error(struct parser_obj *po)
> > int error = EOK;
> > uint32_t action;
> > int idx = 0;
> > -    const char *errtxt[] = { ERROR_TXT, WARNING_TXT };
> > -    struct ini_parse_error pe;
> > 
> > TRACE_FLOW_ENTRY();
> > 
> > -    pe.line = po->linenum;
> > -    /* Clear the warning bit */
> > -    pe.error = po->last_error & ~INI_WARNING;
> > if (po->last_error & INI_WARNING) idx = 1;
> > -    error = col_add_binary_property(po->el, NULL,
> > -                                    errtxt[idx], &pe, sizeof(pe));
> > +
> > +    error = save_error(po->el,
> > +                       po->linenum,
> > +                       po->last_error & ~INI_WARNING,
> > +                       idx);
> > if (error) {
> > -        TRACE_ERROR_NUMBER("Failed to add error to collection",
> > +        TRACE_ERROR_NUMBER("Failed to add error to error list",
> > error);
> > return error;
> > }
> > @@ -1043,7 +1041,9 @@ static int parser_error(struct parser_obj *po)
> > /* If merging sections should produce error and we got error
> > * or if we merge sections but dup values produce error and
> > * we got error then it is not a fatal error so we need to handle
> > -             * it nicely. We check for reverse condition and return error,
> > +             * it nicely and suppress it here. We already in the procees
> > +             * of handling another error and merge error does not matter here.
> > +             * We check for reverse condition and return error,
> > * otherwise fall through.
> > */
> > if (!((((po->collision_flags & INI_MS_MASK) == INI_MS_ERROR) &&
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 10610699c6db3d181011c85447073f5ee4a04153 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sat, 25 Dec 2010 23:56:51 -0500
> > Subject: [PATCH] [INI] Preparing for merging sections
> > 
> > Patch implements three functions:
> > * Function to detect a collision between two section names.
> > * Function to empty section from all its keys
> > * Function to add values one by one from one section to
> > another.
> > ---
> > ini/ini_parse.c |  177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 177 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index e7eab28211655f7a225202552fd96b68c1e09450..fc43cb06daca64309e47f43047263c5f066fc43e \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -318,6 +318,183 @@ static int parser_read(struct parser_obj *po)
> > return EOK;
> > }
> > 
> > +/* Find if there is a collistion */
> > +static int check_section_collision(struct parser_obj *po)
> > +{
> > +    int error = EOK;
> > +    struct collection_item *item = NULL;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    TRACE_INFO_STRING("Searching for:", col_get_item_property(po->sec, NULL));
> > +
> > +    error = col_get_item(po->top,
> > +                         col_get_item_property(po->sec, NULL),
> > +                         COL_TYPE_ANY,
> > +                         COL_TRAVERSE_DEFAULT,
> > +                         &item);
> > +
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed searching for dup", error);
> > +        return error;
> > +    }
> > +
> > +    /* Check if there is a dup */
> > +    if (item) {
> > +        TRACE_INFO_STRING("Collision found:",
> > +                          col_get_item_property(item, NULL));
> > +        /* Get the actual section collection instead of reference */
> > +        po->merge_sec = *((struct collection_item **)
> > +                          (col_get_item_data(item)));
> > +    }
> > +    else {
> > +        TRACE_INFO_STRING("Collision not found.", "");
> > +        po->merge_sec = NULL;
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return EOK;
> > +}
> > +
> > +/* Clean all items in the section */
> > +static int empty_section(struct collection_item *sec)
> > +{
> > +    int error = EOK;
> > +    struct collection_item *item = NULL;
> > +    struct collection_item *save_item = NULL;
> > +    struct value_obj *vo = NULL;
> > +    int work_to_do = 1;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    do {
> > +        item = NULL;
> > +        error = col_extract_item_from_current(sec,
> > +                                              COL_DSP_FRONT,
> > +                                              NULL,
> > +                                              0,
> > +                                              COL_TYPE_ANY,
> > +                                              &item);
> > +        if ((error) && (error != ENOENT)) {
> > +            TRACE_ERROR_NUMBER("Failed to extract item.", error);
> > +            return error;
> > +        }
> > +
> > +        if (item) {
> > +            TRACE_INFO_STRING("Item found:",
> > +                              col_get_item_property(item, NULL));
> > +
> > +            if (strncmp(col_get_item_property(item, NULL),
> > +                        INI_SECTION_KEY, 1) == 0) {
> > +                /* Just ignore the first item */
> > +                save_item = item;
> > +                continue;
> > +            }
> > +
> > +            vo = *((struct value_obj **)(col_get_item_data(item)));
> > +            value_destroy(vo);
> > +            col_delete_item(item);
> > +        }
> > +        else {
> > +            TRACE_INFO_STRING("No more items:", "");
> > +            /* Restore saved item */
> > +            error = col_insert_item(sec,
> > +                                    NULL,
> > +                                    save_item,
> > +                                    COL_DSP_END,
> > +                                    NULL,
> > +                                    0,
> > +                                    COL_INSERT_NOCHECK);
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Failed to restore item.", error);
> > +                return error;
> > +            }
> > +
> > +            work_to_do = 0;
> > +        }
> > +    }
> > +    while (work_to_do);
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return EOK;
> > +}
> > +
> > +/* Merge contents of the section */
> > +static int merge_section(struct parser_obj *po)
> > +{
> > +    int error = EOK;
> > +    struct collection_item *item = NULL;
> > +    struct value_obj *vo = NULL;
> > +    int work_to_do = 1;
> > +    const char *key;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    do {
> > +        TRACE_INFO_STRING("Top of the merge loop", "");
> > +
> > +        item = NULL;
> > +        error = col_extract_item_from_current(po->sec,
> > +                                              COL_DSP_FRONT,
> > +                                              NULL,
> > +                                              0,
> > +                                              COL_TYPE_ANY,
> > +                                              &item);
> > +        if ((error) && (error != ENOENT)) {
> > +            TRACE_ERROR_NUMBER("Failed to extract item.", error);
> > +            return error;
> > +        }
> > +
> > +        if (item) {
> > +
> > +            TRACE_INFO_STRING("Item found:", col_get_item_property(item, NULL));
> > +
> > +            if (strncmp(col_get_item_property(item, NULL),
> > +                        INI_SECTION_KEY, 1) == 0) {
> > +                /* Just ignore the first item */
> > +                vo = *((struct value_obj **)(col_get_item_data(item)));
> > +                value_destroy(vo);
> > +                col_delete_item(item);
> > +                continue;
> > +            }
> > +
> > +            po->merge_vo = *((struct value_obj **)(col_get_item_data(item)));
> > +            key = col_get_item_property(item, NULL);
> > +            /* To be able to use po->merge_key in the loop
> > +             * we have to overcome constraints imposed by
> > +             * the "const" declaration.
> > +             */
> > +            memcpy(&(po->merge_key), &key, sizeof(char *));
> > +
> > +            /* Use the value processing function to inser the value */
> > +            error = complete_value_processing(po);
> > +
> > +            /* In case of error value is already cleaned */
> > +            po->merge_vo = NULL;
> > +            po->merge_key = NULL;
> > +            col_delete_item(item);
> > +            /* Now we can check the error */
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Failed to merge item.", error);
> > +                return error;
> > +            }
> > +        }
> > +        else {
> > +            TRACE_INFO_STRING("No more items:", "");
> > +            work_to_do = 0;
> > +        }
> > +    }
> > +    while (work_to_do);
> > +
> > +    /* If we reached this place the incoming section is empty.
> > +     * but just to be safe clean with callback. */
> > +    col_destroy_collection_with_cb(po->sec, ini_cleanup_cb, NULL);
> > +    po->sec = NULL;
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return EOK;
> > +}
> > +
> > /* Function to read next line from the file */
> > static int parser_save_section(struct parser_obj *po)
> > {
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From aa35a75674482febe3f5f67b3e7c7c7faf507f05 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:03:33 -0500
> > Subject: [PATCH] [INI] Enhance value processing
> > 
> > This patch refactores the value processing
> > function so that it can be used both in
> > normal mode when velues need to be constrcuted and
> > saved into the current section (po->sec) and in the
> > merge mode when values are already constructed
> > and need to be saved into a po->merge_sec.
> > ---
> > ini/ini_parse.c |  165 ++++++++++++++++++++++++++++++++++++++----------------
> > 1 files changed, 116 insertions(+), 49 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index fc43cb06daca64309e47f43047263c5f066fc43e..5dd873a339e5fce36bc13ea8bde65dbefc5d617f \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -529,6 +529,7 @@ static int parser_save_section(struct parser_obj *po)
> > static int complete_value_processing(struct parser_obj *po)
> > {
> > int error = EOK;
> > +    int error2 = EOK;
> > struct value_obj *vo = NULL;
> > struct value_obj *vo_old = NULL;
> > unsigned insertmode;
> > @@ -536,12 +537,19 @@ static int complete_value_processing(struct parser_obj *po)
> > int suppress = 0;
> > int doinsert = 0;
> > struct collection_item *item = NULL;
> > +    struct collection_item *section = NULL;
> > +    int merging = 0;
> > 
> > TRACE_FLOW_ENTRY();
> > 
> > -    /* If there is not open section create a default one */
> > -    if(!(po->sec)) {
> > -        /* Create a new section */
> > +    if (po->merge_sec) {
> > +        TRACE_INFO_STRING("Processing value in merge mode", "");
> > +        section = po->merge_sec;
> > +        merging = 1;
> > +    }
> > +    else if(!(po->sec)) {
> > +        TRACE_INFO_STRING("Creating default section", "");
> > +        /* If there is not open section create a default one */
> > error = col_create_collection(&po->sec,
> > INI_DEFAULT_SECTION,
> > COL_CLASS_INI_SECTION);
> > @@ -549,29 +557,44 @@ static int complete_value_processing(struct parser_obj *po)
> > TRACE_ERROR_NUMBER("Failed to create default section", error);
> > return error;
> > }
> > +        section = po->sec;
> > }
> > -
> > -    /* Construct value object from what we have */
> > -    error = value_create_from_refarray(po->raw_lines,
> > -                                       po->raw_lengths,
> > -                                       po->keylinenum,
> > -                                       INI_VALUE_READ,
> > -                                       po->key_len,
> > -                                       po->boundary,
> > -                                       po->ic,
> > -                                       &vo);
> > -
> > -    if (error) {
> > -        TRACE_ERROR_NUMBER("Failed to create value object", error);
> > -        return error;
> > +    else {
> > +        TRACE_INFO_STRING("Processing value in normal mode", "");
> > +        section = po->sec;
> > }
> > 
> > -    /* Forget about the arrays. They are now owned by the value object */
> > -    po->ic = NULL;
> > -    po->raw_lines = NULL;
> > -    po->raw_lengths = NULL;
> > +    if (merging) {
> > +        TRACE_INFO_STRING("Using merge key:", po->merge_key);
> > +        vo = po->merge_vo;
> > +        /* We are adding to the merge section so use MV2S flags.
> > +         * But flags are done in such a way that deviding MV2S by MV1S mask
> > +         * will translate MV2S flags into MV1S so we can use
> > +         * MV1S constants. */
> > +        TRACE_INFO_NUMBER("Collisions flags:", po->collision_flags);
> > +        mergemode = (po->collision_flags & INI_MV2S_MASK) / INI_MV1S_MASK;
> > +    }
> > +    else {
> > +        /* Construct value object from what we have */
> > +        error = value_create_from_refarray(po->raw_lines,
> > +                                           po->raw_lengths,
> > +                                           po->keylinenum,
> > +                                           INI_VALUE_READ,
> > +                                           po->key_len,
> > +                                           po->boundary,
> > +                                           po->ic,
> > +                                           &vo);
> > 
> > -    mergemode = po->collision_flags & INI_MV1S_MASK;
> > +        if (error) {
> > +            TRACE_ERROR_NUMBER("Failed to create value object", error);
> > +            return error;
> > +        }
> > +        /* Forget about the arrays. They are now owned by the value object */
> > +        po->ic = NULL;
> > +        po->raw_lines = NULL;
> > +        po->raw_lengths = NULL;
> > +        mergemode = po->collision_flags & INI_MV1S_MASK;
> > +    }
> > 
> > switch (mergemode) {
> > case INI_MV1S_ERROR:     insertmode = COL_INSERT_DUPERROR;
> > @@ -585,16 +608,18 @@ static int complete_value_processing(struct parser_obj *po)
> > doinsert = 1;
> > break;
> > case INI_MV1S_OVERWRITE: /* Special handling */
> > +    case INI_MV1S_DETECT:
> > default:
> > break;
> > }
> > 
> > /* Do not insert but search for dups first */
> > if (!doinsert) {
> > -        TRACE_INFO_STRING("Ovewrite mode. Lokking for:", po->key);
> > +        TRACE_INFO_STRING("Overwrite mode. Looking for:",
> > +                          (char *)(merging ? po->merge_key : po->key));
> > 
> > -        error = col_get_item(po->sec,
> > -                             po->key,
> > +        error = col_get_item(section,
> > +                             merging ? po->merge_key : po->key,
> > COL_TYPE_BINARY,
> > COL_TRAVERSE_DEFAULT,
> > &item);
> > @@ -607,21 +632,42 @@ static int complete_value_processing(struct parser_obj *po)
> > 
> > /* Check if there is a dup */
> > if (item) {
> > -            /* Dup exists - update it */
> > -            vo_old = *((struct value_obj **)(col_get_item_data(item)));
> > -            error = col_modify_binary_item(item,
> > -                                           NULL,
> > -                                           &vo,
> > -                                           sizeof(struct value_obj *));
> > -            if (error) {
> > -                TRACE_ERROR_NUMBER("Failed updating the value", error);
> > -                value_destroy(vo);
> > -                return error;
> > +            /* Check if we are in the detect mode */
> > +            if (mergemode == INI_MV1S_DETECT) {
> > +                po->merge_error = EEXIST;
> > +                /* There is a dup - inform user about it and continue */
> > +                error = save_error(po->el,
> > +                                   merging ? po->seclinenum : po->keylinenum,
> > +                                   merging ? ERR_DUPKEYSEC : ERR_DUPKEY,
> > +                                   0);
> > +                if (error) {
> > +                    TRACE_ERROR_NUMBER("Failed to save error", error);
> > +                    value_destroy(vo);
> > +                    return error;
> > +                }
> > +                doinsert = 1;
> > +                insertmode = COL_INSERT_NOCHECK;
> > +
> > +            }
> > +            else {
> > +
> > +                /* Dup exists - update it */
> > +                vo_old = *((struct value_obj **)(col_get_item_data(item)));
> > +                error = col_modify_binary_item(item,
> > +                                               NULL,
> > +                                               &vo,
> > +                                               sizeof(struct value_obj *));
> > +                if (error) {
> > +                    TRACE_ERROR_NUMBER("Failed updating the value", error);
> > +                    value_destroy(vo);
> > +                    return error;
> > +                }
> > +
> > +                /* If we failed to update it is better to leak then crash,
> > +                 * so destroy original value only on the successful update.
> > +                 */
> > +                value_destroy(vo_old);
> > }
> > -            /* If we failed to update it is better to leak then crash,
> > -             * so desctroy original value only on the successful update.
> > -             */
> > -            value_destroy(vo_old);
> > }
> > else {
> > /* No dup found so we can insert with no check */
> > @@ -632,31 +678,52 @@ static int complete_value_processing(struct parser_obj *po)
> > 
> > if (doinsert) {
> > /* Add value to collection */
> > -        error = col_insert_binary_property(po->sec,
> > +        error = col_insert_binary_property(section,
> > NULL,
> > COL_DSP_END,
> > NULL,
> > 0,
> > insertmode,
> > -                                           po->key,
> > +                                           merging ? po->merge_key : po->key,
> > &vo,
> > sizeof(struct value_obj *));
> > if (error) {
> > +            value_destroy(vo);
> > +
> > if ((suppress) && (error == EEXIST)) {
> > -                TRACE_INFO_STRING("Preseved exisitng value", po->key);
> > -                value_destroy(vo);
> > +                TRACE_INFO_STRING("Preseved exisitng value",
> > +                                  (char *)(merging ? po->merge_key : po->key));
> > }
> > else {
> > -                TRACE_ERROR_NUMBER("Failed to add value object to the section", \
> >                 error);
> > -                value_destroy(vo);
> > -                return error;
> > +                /* Check if this is a critical error or not */
> > +                if ((mergemode == INI_MV1S_ERROR) && (error == EEXIST)) {
> > +                    TRACE_ERROR_NUMBER("Failed to add value object "
> > +                                       "to the section", error);
> > +                    error2 = save_error(po->el,
> > +                                       merging ? po->seclinenum : \
> > po->keylinenum, +                                       merging ? ERR_DUPKEYSEC : \
> > ERR_DUPKEY, +                                       0);
> > +                    if (error2) {
> > +                        TRACE_ERROR_NUMBER("Failed to save error", error2);
> > +                        return error2;
> > +                    }
> > +                    return error;
> > +                }
> > +                else {
> > +                    TRACE_ERROR_NUMBER("Failed to add value object"
> > +                                       " to the section", error);
> > +                    return error;
> > +                }
> > }
> > }
> > }
> > 
> > -    free(po->key);
> > -    po->key = NULL;
> > -    po->key_len = 0;
> > +    if (!merging) {
> > +        free(po->key);
> > +        po->key = NULL;
> > +        po->key_len = 0;
> > +    }
> > +
> > TRACE_FLOW_EXIT();
> > return EOK;
> > }
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From f5e1f6494f6350d41fce3e063a8aebf72aa7c4ea Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:05:28 -0500
> > Subject: [PATCH] [INI] Use section line number
> > 
> > Use section line number for error reporting
> > about the section collisions.
> > ---
> > ini/ini_parse.c |    7 +++++--
> > 1 files changed, 5 insertions(+), 2 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index 5dd873a339e5fce36bc13ea8bde65dbefc5d617f..a1c3a26f0f88c80616bad5336be1126a1f9b99bf \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -1069,9 +1069,12 @@ static int handle_section(struct parser_obj *po, uint32_t \
> > *action) }
> > 
> > /* Save the line number of the last found key */
> > -    po->keylinenum = po->linenum;
> > +    po->seclinenum = po->linenum;
> > 
> > -    /* Complete processing of this value */
> > +    /* Complete processing of this value.
> > +     * A new section will be created inside and a special
> > +     * value will be added.
> > +     */
> > error = complete_value_processing(po);
> > if (error) {
> > TRACE_ERROR_NUMBER("Failed to complete value processing", error);
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 6d4b2785106cd6614eedb62069da76ecc2e90457 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:08:19 -0500
> > Subject: [PATCH] [INI] Refactor section processing
> > 
> > This patch adds functionality to respect
> > merge section flags and to process section
> > collisions differently dpending on these flags.
> > ---
> > ini/ini_parse.c |  114 ++++++++++++++++++++++++++++++++++++++++++++++++++----
> > 1 files changed, 105 insertions(+), 9 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index a1c3a26f0f88c80616bad5336be1126a1f9b99bf..d9c6d0a9bc71f197eb4bf752fd56958ba6f64df2 \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -499,25 +499,121 @@ static int merge_section(struct parser_obj *po)
> > static int parser_save_section(struct parser_obj *po)
> > {
> > int error = EOK;
> > +    uint32_t mergemode;
> > +    int add = 0;
> > +    int merge = 0;
> > 
> > TRACE_FLOW_ENTRY();
> > 
> > if (po->sec) {
> > 
> > -        /* For now just add as we did.
> > -         * Add merge code here !!!!
> > -         */
> > -        error = col_add_collection_to_collection(po->top,
> > -                                                 NULL, NULL,
> > -                                                 po->sec,
> > -                                                 COL_ADD_MODE_EMBED);
> > +        TRACE_INFO_STRING("Section exists.", "");
> > 
> > +        /* First detect if we have collision */
> > +        error = check_section_collision(po);
> > if (error) {
> > -            TRACE_ERROR_NUMBER("Failed to embed section", error);
> > +            TRACE_ERROR_NUMBER("Failed to check for collision", error);
> > return error;
> > }
> > 
> > -        po->sec = NULL;
> > +        if (po->merge_sec) {
> > +
> > +            TRACE_INFO_STRING("Merge collision detected", "");
> > +
> > +            mergemode = po->collision_flags & INI_MS_MASK;
> > +
> > +            switch (mergemode) {
> > +            case INI_MS_ERROR:      /* Report error and return */
> > +                                    TRACE_INFO_STRING("Reporting error",
> > +                                                      "duplicate section");
> > +                                    error = save_error(po->el,
> > +                                                       po->seclinenum,
> > +                                                       ERR_DUPSECTION,
> > +                                                       0);
> > +                                    if (error) {
> > +                                        TRACE_ERROR_NUMBER("Failed to "
> > +                                                           "save error",
> > +                                                            error);
> > +                                        return error;
> > +                                    }
> > +                                    /* Return error */
> > +                                    TRACE_FLOW_RETURN(EEXIST);
> > +                                    return EEXIST;
> > +
> > +            case INI_MS_PRESERVE:   /* Delete new section */
> > +                                    TRACE_INFO_STRING("Preserve mode", "");
> > +                                    col_destroy_collection_with_cb(
> > +                                                            po->sec,
> > +                                                            ini_cleanup_cb,
> > +                                                            NULL);
> > +                                    po->sec = NULL;
> > +                                    break;
> > +
> > +            case INI_MS_ALLOW:      TRACE_INFO_STRING("Allow mode", "");
> > +                                    add = 1;
> > +                                    break;
> > +
> > +            case INI_MS_OVERWRITE:  /* Empty existing section */
> > +                                    TRACE_INFO_STRING("Ovewrite mode", "");
> > +                                    error = empty_section(po->merge_sec);
> > +                                    if (error) {
> > +                                        TRACE_ERROR_NUMBER("Failed to "
> > +                                                           "empty section",
> > +                                                            error);
> > +                                        return error;
> > +                                    }
> > +                                    merge = 1;
> > +                                    break;
> > +
> > +            case INI_MS_DETECT:     /* Detect mode */
> > +                                    TRACE_INFO_STRING("Detect mode", "");
> > +                                    po->merge_error = EEXIST;
> > +                                    error = save_error(po->el,
> > +                                                       po->seclinenum,
> > +                                                       ERR_DUPSECTION,
> > +                                                       0);
> > +                                    if (error) {
> > +                                        TRACE_ERROR_NUMBER("Failed to "
> > +                                                           "save error",
> > +                                                            error);
> > +                                        return error;
> > +                                    }
> > +                                    merge = 1;
> > +                                    break;
> > +
> > +            case INI_MS_MERGE:      /* Merge */
> > +            default:                TRACE_INFO_STRING("Merge mode", "");
> > +                                    merge = 1;
> > +                                    break;
> > +            }
> > +
> > +            if (merge) {
> > +                error = merge_section(po);
> > +                if (error) {
> > +                    TRACE_ERROR_NUMBER("Failed to merge section", error);
> > +                    return error;
> > +                }
> > +            }
> > +
> > +            po->merge_sec = NULL;
> > +        }
> > +        else add = 1;
> > +
> > +        if (add) {
> > +            /* Add section to configuration */
> > +            TRACE_INFO_STRING("Now adding collection", "");
> > +            error = col_add_collection_to_collection(po->top,
> > +                                                     NULL, NULL,
> > +                                                     po->sec,
> > +                                                     COL_ADD_MODE_EMBED);
> > +
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Failed to embed section", error);
> > +                return error;
> > +            }
> > +
> > +            po->sec = NULL;
> > +        }
> > }
> > 
> > TRACE_FLOW_EXIT();
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 8fb3799dc674770bb622b630267a7a436449069e Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:10:23 -0500
> > Subject: [PATCH] [INI] Return error in DETECT mode
> > 
> > If in merge DETECT mode and there were no parsing errors
> > return error if there were merge collisions.
> > ---
> > ini/ini_parse.c |   11 +++++++++++
> > 1 files changed, 11 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index d9c6d0a9bc71f197eb4bf752fd56958ba6f64df2..3f45ac71ae46dff3413a6d4db5dd59a0838d078b \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -1441,7 +1441,18 @@ int parser_run(struct parser_obj *po)
> > col_delete_item(item);
> > 
> > if (action == PARSE_DONE) {
> > +
> > TRACE_INFO_NUMBER("We are done", error);
> > +
> > +            /* Report merge error in detect mode
> > +             * if no other error was detected. */
> > +            if ((po->ret == 0) &&
> > +                (po->merge_error != 0) &&
> > +                ((po->collision_flags & INI_MV1S_DETECT) ||
> > +                 (po->collision_flags & INI_MV2S_DETECT) ||
> > +                 (po->collision_flags & INI_MS_DETECT)))
> > +                po->ret = po->merge_error;
> > +
> > error = po->ret;
> > break;
> > }
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 235393228925b4aee6138820276450c233853464 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:15:12 -0500
> > Subject: [PATCH] [INI] New test files for section merge
> > 
> > smerge.conf  - test file
> > sexpect.conf - file contains output of the smerge.conf
> > processed in different merge modes
> > for sections and values
> > ---
> > Makefile.am            |    4 +-
> > ini/ini.d/sexpect.conf |  644 ++++++++++++++++++++++++++++++++++++++++++++++++
> > ini/ini.d/smerge.conf  |   33 +++
> > 3 files changed, 680 insertions(+), 1 deletions(-)
> > create mode 100644 ini/ini.d/sexpect.conf
> > create mode 100644 ini/ini.d/smerge.conf
> > 
> > diff --git a/Makefile.am b/Makefile.am
> > index 1780e9b234e68006af910413b3e8312c9db72c7b..4f9ab3427bb309b19ddec0da5e2125046d03babc \
> >                 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -280,7 +280,9 @@ dist_noinst_DATA += \
> > ini/ini.d/test.conf \
> > ini/ini.d/ipa.conf \
> > ini/ini.d/foo.conf \
> > -    ini/ini.d/mysssd.conf
> > +    ini/ini.d/mysssd.conf \
> > +    ini/ini.d/smerge.conf \
> > +    ini/ini.d/sexpect.conf
> > 
> > check_PROGRAMS += \
> > ini_config_ut \
> > diff --git a/ini/ini.d/sexpect.conf b/ini/ini.d/sexpect.conf
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..6a9222b0a9003ed1a6e9c10401573832980a3706
> >                 
> > --- /dev/null
> > +++ b/ini/ini.d/sexpect.conf
> > @@ -0,0 +1,644 @@
> > +# Section mode: MERGE, value mode: OVERWRITE
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: MERGE, value mode: ERROR
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: MERGE, value mode: PRESERVE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +#End of file
> > +# Section mode: MERGE, value mode: ALLOW
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: MERGE, value mode: DETECT
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: ERROR, value mode: OVERWRITE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: ERROR, value mode: ERROR
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: ERROR, value mode: PRESERVE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: ERROR, value mode: ALLOW
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: ERROR, value mode: DETECT
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: OVERWRITE, value mode: OVERWRITE
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: OVERWRITE, value mode: ERROR
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: OVERWRITE, value mode: PRESERVE
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: OVERWRITE, value mode: ALLOW
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: OVERWRITE, value mode: DETECT
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: PRESERVE, value mode: OVERWRITE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: PRESERVE, value mode: ERROR
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: PRESERVE, value mode: PRESERVE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: PRESERVE, value mode: ALLOW
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: PRESERVE, value mode: DETECT
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: ALLOW, value mode: OVERWRITE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: ALLOW, value mode: ERROR
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: ALLOW, value mode: PRESERVE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: ALLOW, value mode: ALLOW
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: ALLOW, value mode: DETECT
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: DETECT, value mode: OVERWRITE
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: DETECT, value mode: ERROR
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Section mode: DETECT, value mode: PRESERVE
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +#End of file
> > +# Section mode: DETECT, value mode: ALLOW
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > +# Section mode: DETECT, value mode: DETECT
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > diff --git a/ini/ini.d/smerge.conf b/ini/ini.d/smerge.conf
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..bdec46d86fb6ecd0d39f4b50aca01a53dabd9ebf
> >                 
> > --- /dev/null
> > +++ b/ini/ini.d/smerge.conf
> > @@ -0,0 +1,33 @@
> > +[section1]
> > +# Key 1
> > +key1 = section1a Value 1
> > +# Key 2
> > +key2 = section1a Value 2
> > +# Key 3
> > +key3 = section1a Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2a Value 1
> > +# Key 2
> > +key2 = section2a Value 2
> > +# Key 3
> > +key3 = section2a Value 3
> > +
> > +[section1]
> > +# Key 1
> > +key1 = section1b Value 1
> > +# Key 2
> > +key2 = section1b Value 2
> > +# Key 3
> > +key3 = section1b Value 3
> > +
> > +[section2]
> > +# Key 1
> > +key1 = section2b Value 1
> > +# Key 2
> > +key2 = section2b Value 2
> > +# Key 3
> > +key3 = section2b Value 3
> > +
> > +#End of file
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From a2b8565c919f3b39e9d7eeef9baa29081bb80f43 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:18:48 -0500
> > Subject: [PATCH] [INI] Test DETECT mode and use new file
> > 
> > Patch adds smerge.conf file to the list
> > of files to test and adds test for the DETECT
> > mode for inidividual values.
> > ---
> > ini/ini_parse_ut.c |   30 +++++++++++++++++++++++-------
> > 1 files changed, 23 insertions(+), 7 deletions(-)
> > 
> > diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
> > index 9327ebaab2dc529b593e0b550011bbac6b949b94..40c64bb15c0535dd2e8f5e62129a31ae53c3f35f \
> >                 100644
> > --- a/ini/ini_parse_ut.c
> > +++ b/ini/ini_parse_ut.c
> > @@ -173,6 +173,7 @@ int read_save_test(void)
> > "mysssd",
> > "ipa",
> > "test",
> > +                            "smerge",
> > NULL };
> > 
> > 
> > @@ -203,6 +204,7 @@ int read_again_test(void)
> > "mysssd",
> > "ipa",
> > "test",
> > +                            "smerge",
> > NULL };
> > 
> > 
> > @@ -279,14 +281,25 @@ int create_expect(const char *checkname)
> > fprintf(ff,"#Second value\n");
> > fprintf(ff,"bar = second value\n");
> > fprintf(ff,"#End of section\n");
> > +    /* Detect */
> > +    fprintf(ff,"#Hoho section\n");
> > +    fprintf(ff,"[hoho]\n");
> > +    fprintf(ff,"#Hoho value\n");
> > +    fprintf(ff,"val = hoho\n");
> > +    fprintf(ff,"#End of hoho\n");
> > +    fprintf(ff,"#Start of section\n");
> > +    fprintf(ff,"[foo]\n");
> > +    fprintf(ff,"#First value\n");
> > +    fprintf(ff,"bar = first value\n");
> > +    fprintf(ff,"#Second value\n");
> > +    fprintf(ff,"bar = second value\n");
> > +    fprintf(ff,"#End of section\n");
> > 
> > fclose(ff);
> > 
> > return EOK;
> > }
> > 
> > -
> > -
> > /* Check merge modes */
> > int merge_values_test(void)
> > {
> > @@ -301,12 +314,14 @@ int merge_values_test(void)
> > uint32_t mflags[] = { INI_MV1S_OVERWRITE,
> > INI_MV1S_ERROR,
> > INI_MV1S_PRESERVE,
> > -                          INI_MV1S_ALLOW };
> > +                          INI_MV1S_ALLOW,
> > +                          INI_MV1S_DETECT };
> > 
> > const char *mstr[] = { "OVERWRITE",
> > "ERROR",
> > "PRESERVE",
> > -                           "ALLOW" };
> > +                           "ALLOW",
> > +                           "DETECT" };
> > 
> > char filename[PATH_MAX];
> > const char *resname = "./merge.conf.out";
> > @@ -323,7 +338,7 @@ int merge_values_test(void)
> > return error;
> > }
> > 
> > -    for (i = 0; i < 4; i++) {
> > +    for (i = 0; i < 5; i++) {
> > 
> > INIOUT(printf("<==== Testing mode %s  ====>\n", mstr[i]));
> > 
> > @@ -360,8 +375,9 @@ int merge_values_test(void)
> > ini_config_free_errors(error_list);
> > }
> > 
> > -            if ((mflags[i] != INI_MV1S_ERROR) ||
> > -                ((mflags[i] = INI_MV1S_ERROR) && (error != EEXIST))) {
> > +            if (((mflags[i] != INI_MV1S_ERROR) && (mflags[i]!= INI_MV1S_DETECT)) \
> > || +                ((mflags[i] = INI_MV1S_ERROR) && (error != EEXIST)) ||
> > +                ((mflags[i] = INI_MV1S_DETECT) && (error != EEXIST))) {
> > printf("This is unexpected error %d in mode %d\n", error, mflags[i]);
> > 	            ini_config_destroy(ini_config);
> > 		        simplebuffer_free(sbobj);
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 24241d6fa2aa0b7e1595f0600d28238945f647d3 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 00:20:54 -0500
> > Subject: [PATCH] [INI] Test for all section merge modes
> > 
> > New test reads smerge.conf in all possible
> > modes and compares the combined result with
> > the sexpect.conf function.
> > ---
> > ini/ini_parse_ut.c |  188 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 188 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
> > index 40c64bb15c0535dd2e8f5e62129a31ae53c3f35f..95793dc39cfa73966192802a12d9bdc54c5ec545 \
> >                 100644
> > --- a/ini/ini_parse_ut.c
> > +++ b/ini/ini_parse_ut.c
> > @@ -438,6 +438,193 @@ int merge_values_test(void)
> > resname, checkname, error));
> > 
> > return error;
> > +}
> > +
> > +/* Check merge modes */
> > +int merge_section_test(void)
> > +{
> > +    int error = EOK;
> > +    int i, j;
> > +    struct ini_cfgfile *file_ctx = NULL;
> > +    FILE *ff = NULL;
> > +    struct ini_cfgobj *ini_config = NULL;
> > +    char **error_list = NULL;
> > +    struct simplebuffer *sbobj = NULL;
> > +    uint32_t left = 0;
> > +    uint32_t msecflags[] = { INI_MS_MERGE,
> > +                             INI_MS_ERROR,
> > +                             INI_MS_OVERWRITE,
> > +                             INI_MS_PRESERVE,
> > +                             INI_MS_ALLOW,
> > +                             INI_MS_DETECT };
> > +
> > +    uint32_t mflags[] = { INI_MV2S_OVERWRITE,
> > +                          INI_MV2S_ERROR,
> > +                          INI_MV2S_PRESERVE,
> > +                          INI_MV2S_ALLOW,
> > +                          INI_MV2S_DETECT };
> > +
> > +    const char *secmstr[] = { "MERGE",
> > +                              "ERROR",
> > +                              "OVERWRITE",
> > +                              "PRESERVE",
> > +                              "ALLOW",
> > +                              "DETECT" };
> > +
> > +    const char *mstr[] = { "OVERWRITE",
> > +                           "ERROR",
> > +                           "PRESERVE",
> > +                           "ALLOW",
> > +                           "DETECT" };
> > +
> > +    char filename[PATH_MAX];
> > +    char checkname[PATH_MAX];
> > +    const char *resname = "./smerge.conf.out";
> > +    char command[PATH_MAX * 3];
> > +    char mode[100];
> > +    char *srcdir;
> > +
> > +    srcdir = getenv("srcdir");
> > +    sprintf(filename, "%s/ini/ini.d/smerge.conf",
> > +                      (srcdir == NULL) ? "." : srcdir);
> > +    sprintf(checkname, "%s/ini/ini.d/sexpect.conf",
> > +                      (srcdir == NULL) ? "." : srcdir);
> > +
> > +    error = simplebuffer_alloc(&sbobj);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
> > +        return error;
> > +    }
> > +
> > +    for (i = 0; i < 6; i++) {
> > +        for (j = 0; j < 5; j++) {
> > +
> > +            INIOUT(printf("<==== Testing mode %s + %s ====>\n",
> > +                          secmstr[i], mstr[j]));
> > +
> > +            sprintf(mode, "# Section mode: %s, value mode: %s\n",
> > +                          secmstr[i], mstr[j]);
> > +
> > +            error = simplebuffer_add_str(sbobj,
> > +                                         mode,
> > +                                         strlen(mode),
> > +                                         100);
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Failed to add string.",
> > +                                   error);
> > +    	        simplebuffer_free(sbobj);
> > +                return error;
> > +            }
> > +
> > +            /* Create config collection */
> > +            error = ini_config_create(&ini_config);
> > +            if (error) {
> > +                printf("Failed to create collection. "
> > +                       "Error %d.\n", error);
> > +    	        simplebuffer_free(sbobj);
> > +                return error;
> > +            }
> > +
> > +            error = ini_config_file_open(filename,
> > +                                         INI_STOP_ON_ANY,
> > +                                         msecflags[i] | mflags[j],
> > +                                         0, /* TBD */
> > +                                         &file_ctx);
> > +            if (error) {
> > +                printf("Failed to open file for reading. "
> > +                       "Error %d.\n",  error);
> > +                ini_config_destroy(ini_config);
> > +    	        simplebuffer_free(sbobj);
> > +                return error;
> > +            }
> > +
> > +            error = ini_config_parse(file_ctx,
> > +                                     ini_config);
> > +            if (error) {
> > +                INIOUT(printf("Failed to parse configuration. "
> > +                              "Error %d.\n", error));
> > +
> > +                if (ini_config_error_count(file_ctx)) {
> > +                    INIOUT(printf("Errors detected while parsing: %s\n",
> > +                           ini_config_get_filename(file_ctx)));
> > +                    ini_config_get_errors(file_ctx, &error_list);
> > +                    INIOUT(ini_print_errors(stdout, error_list));
> > +                    ini_config_free_errors(error_list);
> > +                }
> > +
> > +                if (((msecflags[i] == INI_MS_ERROR) &&
> > +                     (error == EEXIST)) ||
> > +                    ((msecflags[i] == INI_MS_DETECT) &&
> > +                     (error == EEXIST)) ||
> > +                    ((msecflags[i] == INI_MS_MERGE) &&
> > +                     ((mflags[j] == INI_MV2S_ERROR) ||
> > +                      (mflags[j] == INI_MV2S_DETECT)) &&
> > +                      (error == EEXIST))) {
> > +                    INIOUT(printf("This is an expected error "
> > +                                  "%d in mode %d + %d\n",
> > +                                  error,
> > +                                  msecflags[i],
> > +                                  mflags[j]));
> > +                    /* We do not return here intentionally */
> > +                }
> > +                else {
> > +                    printf("This is unexpected error %d in mode %d + %d\n",
> > +                            error, msecflags[i], mflags[j]);
> > +    	            ini_config_destroy(ini_config);
> > +    		        simplebuffer_free(sbobj);
> > +    		        ini_config_file_close(file_ctx);
> > +                    return error;
> > +                }
> > +            }
> > +
> > +            ini_config_file_close(file_ctx);
> > +
> > +            INIOUT(col_debug_collection(ini_config->cfg,
> > +                   COL_TRAVERSE_DEFAULT));
> > +
> > +    	    error = ini_config_serialize(ini_config, sbobj);
> > +    	    if (error != EOK) {
> > +    	        printf("Failed to serialize configuration. "
> > +                       "Error %d.\n", error);
> > +    	        ini_config_destroy(ini_config);
> > +    	        simplebuffer_free(sbobj);
> > +    	        return error;
> > +    	    }
> > +
> > +            ini_config_destroy(ini_config);
> > +        }
> > +	}
> > +
> > +    errno = 0;
> > +    ff = fopen(resname, "w");
> > +    if(!ff) {
> > +        error = errno;
> > +        printf("Failed to open file for writing. Error %d.\n", error);
> > +        simplebuffer_free(sbobj);
> > +        return error;
> > +    }
> > +
> > +    /* Save */
> > +    left = simplebuffer_get_len(sbobj);
> > +    while (left > 0) {
> > +        error = simplebuffer_write(fileno(ff), sbobj, &left);
> > +        if (error) {
> > +            printf("Failed to write back the configuration %d.\n", error);
> > +            simplebuffer_free(sbobj);
> > +            fclose(ff);
> > +            return error;
> > +        }
> > +    }
> > +
> > +    simplebuffer_free(sbobj);
> > +    fclose(ff);
> > +
> > +    sprintf(command,"diff -q %s %s", resname, checkname);
> > +    error = system(command);
> > +    INIOUT(printf("Comparison of %s %s returned: %d\n",
> > +                  resname, checkname, error));
> > +
> > +    return error;
> > 
> > 
> > }
> > @@ -449,6 +636,7 @@ int main(int argc, char *argv[])
> > test_fn tests[] = { read_save_test,
> > read_again_test,
> > merge_values_test,
> > +                        merge_section_test,
> > NULL };
> > test_fn t;
> > int i = 0;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 8176dad24b0124a634450741f00b2d03c48ce437 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 18:08:27 -0500
> > Subject: [PATCH] [INI] Separate close and destroy
> > 
> > Allow closing file without destroying the context.
> > ---
> > ini/ini_configobj.h |    5 ++++-
> > ini/ini_fileobj.c   |   25 +++++++++++++++++++------
> > ini/ini_parse_ut.c  |   10 +++++-----
> > 3 files changed, 28 insertions(+), 12 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index f0c6882dbb1e066972f98309bf78a99670b985c5..e728c2e3cbc787586a542a184a07593ad1e03331 \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -213,9 +213,12 @@ int ini_config_file_open(const char *filename,
> > uint32_t metadata_flags,
> > struct ini_cfgfile **file_ctx);
> > 
> > -/* Close file context and destroy the object */
> > +/* Close file context */
> > void ini_config_file_close(struct ini_cfgfile *file_ctx);
> > 
> > +/* Close file context and destroy the object */
> > +void ini_config_file_destroy(struct ini_cfgfile *file_ctx);
> > +
> > /* How many errors do we have in the list ? */
> > unsigned ini_config_error_count(struct ini_cfgfile *file_ctx);
> > 
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index 7bc599b948563964830f9ade75966cf4f9aa3018..f998eb09d1b5c271be9a316196a510bac39455c2 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -75,12 +75,25 @@ static int valid_collision_flags(uint32_t collision_flags)
> > return 1;
> > }
> > 
> > -/* Close file context and destroy the object */
> > +
> > +/* Close file but not destroy the object */
> > void ini_config_file_close(struct ini_cfgfile *file_ctx)
> > {
> > TRACE_FLOW_ENTRY();
> > 
> > if(file_ctx) {
> > +        if(file_ctx->file) fclose(file_ctx->file);
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +}
> > +
> > +/* Close file context and destroy the object */
> > +void ini_config_file_destroy(struct ini_cfgfile *file_ctx)
> > +{
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    if(file_ctx) {
> > free(file_ctx->filename);
> > col_destroy_collection(file_ctx->error_list);
> > col_destroy_collection(file_ctx->metadata);
> > @@ -144,7 +157,7 @@ int ini_config_file_open(const char *filename,
> > new_ctx->filename = malloc(PATH_MAX + 1);
> > if (!(new_ctx->filename)) {
> > error = errno;
> > -        ini_config_file_close(new_ctx);
> > +        ini_config_file_destroy(new_ctx);
> > TRACE_ERROR_NUMBER("Failed to allocate memory for file path.", error);
> > return error;
> > }
> > @@ -155,7 +168,7 @@ int ini_config_file_open(const char *filename,
> > filename);
> > if(error) {
> > TRACE_ERROR_NUMBER("Failed to resolve path", error);
> > -        ini_config_file_close(new_ctx);
> > +        ini_config_file_destroy(new_ctx);
> > return error;
> > }
> > 
> > @@ -166,7 +179,7 @@ int ini_config_file_open(const char *filename,
> > if (!(new_ctx->file)) {
> > error = errno;
> > TRACE_ERROR_NUMBER("Failed to open file", error);
> > -        ini_config_file_close(new_ctx);
> > +        ini_config_file_destroy(new_ctx);
> > return error;
> > }
> > 
> > @@ -176,7 +189,7 @@ int ini_config_file_open(const char *filename,
> > COL_CLASS_INI_PERROR);
> > if (error) {
> > TRACE_ERROR_NUMBER("Failed to create error list", error);
> > -        ini_config_file_close(new_ctx);
> > +        ini_config_file_destroy(new_ctx);
> > return error;
> > }
> > 
> > @@ -185,7 +198,7 @@ int ini_config_file_open(const char *filename,
> > COL_CLASS_INI_META);
> > if (error) {
> > TRACE_ERROR_NUMBER("Failed to create metadata collection", error);
> > -        ini_config_file_close(new_ctx);
> > +        ini_config_file_destroy(new_ctx);
> > return error;
> > }
> > 
> > diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
> > index 95793dc39cfa73966192802a12d9bdc54c5ec545..f0a95527aa315b559e5c6fa42740fe4a3ba4e4b3 \
> >                 100644
> > --- a/ini/ini_parse_ut.c
> > +++ b/ini/ini_parse_ut.c
> > @@ -91,7 +91,7 @@ int test_one_file(const char *in_filename,
> > /* We do not return here intentionally */
> > }
> > 
> > -    ini_config_file_close(file_ctx);
> > +    ini_config_file_destroy(file_ctx);
> > 
> > INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT));
> > 
> > @@ -381,13 +381,13 @@ int merge_values_test(void)
> > printf("This is unexpected error %d in mode %d\n", error, mflags[i]);
> > 	            ini_config_destroy(ini_config);
> > 		        simplebuffer_free(sbobj);
> > -		        ini_config_file_close(file_ctx);
> > +		        ini_config_file_destroy(file_ctx);
> > return error;
> > }
> > /* We do not return here intentionally */
> > }
> > 
> > -        ini_config_file_close(file_ctx);
> > +        ini_config_file_destroy(file_ctx);
> > 
> > INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT));
> > 
> > @@ -572,12 +572,12 @@ int merge_section_test(void)
> > error, msecflags[i], mflags[j]);
> > 	            ini_config_destroy(ini_config);
> > 		        simplebuffer_free(sbobj);
> > -    		        ini_config_file_close(file_ctx);
> > +    		        ini_config_file_destroy(file_ctx);
> > return error;
> > }
> > }
> > 
> > -            ini_config_file_close(file_ctx);
> > +            ini_config_file_destroy(file_ctx);
> > 
> > INIOUT(col_debug_collection(ini_config->cfg,
> > COL_TRAVERSE_DEFAULT));
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 29e4a0a028b802eaa3bb1dfbc7a9080fc7f21f4b Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 18:34:02 -0500
> > Subject: [PATCH] [INI] Function to reopen file
> > 
> > This patch would allow to reopen file
> > and create a new context based on the old one.
> > ---
> > ini/ini_configobj.h |    4 ++
> > ini/ini_fileobj.c   |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 90 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index e728c2e3cbc787586a542a184a07593ad1e03331..3321bd3ea8985b9b12f04ab792fbcac307bbbe2e \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -213,6 +213,10 @@ int ini_config_file_open(const char *filename,
> > uint32_t metadata_flags,
> > struct ini_cfgfile **file_ctx);
> > 
> > +/* Create a file object from existing one */
> > +int ini_config_file_reopen(struct ini_cfgfile *file_ctx_in,
> > +                           struct ini_cfgfile **file_ctx_out);
> > +
> > /* Close file context */
> > void ini_config_file_close(struct ini_cfgfile *file_ctx);
> > 
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index f998eb09d1b5c271be9a316196a510bac39455c2..200c7af9de896c1abd26a57a508f9f540475b19d \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -210,6 +210,92 @@ int ini_config_file_open(const char *filename,
> > return error;
> > }
> > 
> > +/* Create a file object from existing one */
> > +int ini_config_file_reopen(struct ini_cfgfile *file_ctx_in,
> > +                           struct ini_cfgfile **file_ctx_out)
> > +{
> > +    int error = EOK;
> > +    struct ini_cfgfile *new_ctx = NULL;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    if ((!file_ctx_in) || (!file_ctx_out)) {
> > +        TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
> > +        return EINVAL;
> > +    }
> > +
> > +    /* Allocate structure */
> > +    errno = 0;
> > +    new_ctx = malloc(sizeof(struct ini_cfgfile));
> > +    if (!new_ctx) {
> > +        error = errno;
> > +        TRACE_ERROR_NUMBER("Failed to allocate file ctx.", error);
> > +        return error;
> > +    }
> > +
> > +    new_ctx->filename = NULL;
> > +    new_ctx->file = NULL;
> > +    new_ctx->error_list = NULL;
> > +    new_ctx->metadata = NULL;
> > +
> > +    /* TBD - decide whether we actually need an FD.
> > +       It will be done when we move the metadata
> > +       processing into this function. */
> > +    new_ctx->fd = -1;
> > +
> > +    /* Store flags */
> > +    new_ctx->error_level = file_ctx_in->error_level;
> > +    new_ctx->collision_flags = file_ctx_in->collision_flags;
> > +    new_ctx->metadata_flags = file_ctx_in->metadata_flags;
> > +    new_ctx->count = 0;
> > +
> > +    /* Copy full file path */
> > +    errno = 0;
> > +    new_ctx->filename = strndup(file_ctx_in->filename, PATH_MAX);
> > +    if (!(new_ctx->filename)) {
> > +        error = errno;
> > +        ini_config_file_destroy(new_ctx);
> > +        TRACE_ERROR_NUMBER("Failed to allocate memory for file path.", error);
> > +        return error;
> > +    }
> > +
> > +    /* Open file */
> > +    TRACE_INFO_STRING("File", new_ctx->filename);
> > +    errno = 0;
> > +    new_ctx->file = fopen(new_ctx->filename, "r");
> > +    if (!(new_ctx->file)) {
> > +        error = errno;
> > +        TRACE_ERROR_NUMBER("Failed to open file", error);
> > +        ini_config_file_destroy(new_ctx);
> > +        return error;
> > +    }
> > +
> > +    /* Create internal collections */
> > +    error = col_create_collection(&(new_ctx->error_list),
> > +                                  INI_ERROR,
> > +                                  COL_CLASS_INI_PERROR);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to create error list", error);
> > +        ini_config_file_close(new_ctx);
> > +        return error;
> > +    }
> > +
> > +    error = col_create_collection(&(new_ctx->metadata),
> > +                                  INI_METADATA,
> > +                                  COL_CLASS_INI_META);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to create metadata collection", error);
> > +        ini_config_file_destroy(new_ctx);
> > +        return error;
> > +    }
> > +
> > +
> > +    /* TBD - Add metadata processing here */
> > +
> > +    *file_ctx_out = new_ctx;
> > +    TRACE_FLOW_EXIT();
> > +    return error;
> > +}
> > 
> > /* How many errors do we have in the list ? */
> > unsigned ini_config_error_count(struct ini_cfgfile *file_ctx)
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 7030e51bb22e62e6f5d63b0faa923d2151336818 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 19:21:32 -0500
> > Subject: [PATCH] [INI] Metadata collection is gone
> > 
> > After some more thinking I decided not to use
> > metadata collection. It seems to be an overhead.
> > Patch does following:
> > * Replaces metadata collection in file context structure
> > with standard file stats
> > * Removes all operations against old metadata collection
> > * Defines new flags for data to collect
> > * Creates a function that consolidates common operations
> > between open and reopen functions.
> > ---
> > ini/ini_config_priv.h |   11 +++--
> > ini/ini_configobj.h   |   20 ++++++++
> > ini/ini_fileobj.c     |  121 ++++++++++++++++++++-----------------------------
> > 3 files changed, 75 insertions(+), 77 deletions(-)
> > 
> > diff --git a/ini/ini_config_priv.h b/ini/ini_config_priv.h
> > index 1880c3ff4caa91e7ed3a37e445a20294e76d8037..84742c70ceeb5b493b935c635e81c57d5ef487ce \
> >                 100644
> > --- a/ini/ini_config_priv.h
> > +++ b/ini/ini_config_priv.h
> > @@ -22,6 +22,9 @@
> > #ifndef INI_CONFIG_PRIV_H
> > #define INI_CONFIG_PRIV_H
> > 
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <unistd.h>
> > #include "collection.h"
> > 
> > /* Configuration object */
> > @@ -45,21 +48,19 @@ struct ini_cfgfile {
> > char *filename;
> > /* File stream */
> > FILE *file;
> > -    /* File descriptor that is passed in */
> > -    int fd;
> > /* Error level */
> > int error_level;
> > /* Collision flags - define how to merge things */
> > uint32_t collision_flags;
> > -    /* Collision flags - define how to merge things */
> > +    /* What meta data to collect */
> > uint32_t metadata_flags;
> > /**********************/
> > /* Internal variables */
> > /**********************/
> > /* Collection of errors detected during parsing */
> > struct collection_item *error_list;
> > -    /* Metadata about the file */
> > -    struct collection_item *metadata;
> > +    /* File stats */
> > +    struct stat file_stats;
> > /* Count of error lines */
> > unsigned count;
> > };
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index 3321bd3ea8985b9b12f04ab792fbcac307bbbe2e..898440252ef3a547566fe2b5e80753d7971a8e47 \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -82,6 +82,26 @@
> > /** @brief Size of the error array. */
> > #define ERR_MAXPARSE        ERR_DUPSECTION
> > 
> > +/**
> > + * @}
> > + */
> > +
> > +/**
> > + * @defgroup metacollect Constants that define what meta data to collect
> > + *
> > + * Constants in this section define what meta data to collect
> > + *
> > + *
> > + * @{
> > + */
> > +/** @brief Do not collect any data. */
> > +#define INI_META_NONE     0
> > +/** @brief Collect file stats. */
> > +#define INI_META_STATS    1
> > +
> > +/**
> > + * @}
> > + */
> > 
> > /**
> > * @defgroup collisionflags Flags that define collision resolution logic.
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index 200c7af9de896c1abd26a57a508f9f540475b19d..c10b4bf954366ddae90f1d06c53acd0332968599 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -96,7 +96,6 @@ void ini_config_file_destroy(struct ini_cfgfile *file_ctx)
> > if(file_ctx) {
> > free(file_ctx->filename);
> > col_destroy_collection(file_ctx->error_list);
> > -        col_destroy_collection(file_ctx->metadata);
> > if(file_ctx->file) fclose(file_ctx->file);
> > free(file_ctx);
> > }
> > @@ -104,6 +103,47 @@ void ini_config_file_destroy(struct ini_cfgfile *file_ctx)
> > TRACE_FLOW_EXIT();
> > }
> > 
> > +/* Internal common initialization part */
> > +static int common_file_init(struct ini_cfgfile *file_ctx)
> > +{
> > +    int error = EOK;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    /* Open file */
> > +    TRACE_INFO_STRING("File", file_ctx->filename);
> > +    errno = 0;
> > +    file_ctx->file = fopen(file_ctx->filename, "r");
> > +    if (!(file_ctx->file)) {
> > +        error = errno;
> > +        TRACE_ERROR_NUMBER("Failed to open file", error);
> > +        return error;
> > +    }
> > +
> > +    /* Create internal collections */
> > +    error = col_create_collection(&(file_ctx->error_list),
> > +                                  INI_ERROR,
> > +                                  COL_CLASS_INI_PERROR);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to create error list", error);
> > +        return error;
> > +    }
> > +
> > +    /* Collect stats */
> > +    if (file_ctx->metadata_flags & INI_META_STATS) {
> > +        errno = 0;
> > +        if (fstat(fileno(file_ctx->file),
> > +                  &(file_ctx->file_stats)) < 0) {
> > +            error = errno;
> > +            TRACE_ERROR_NUMBER("Failed to get file stats.", error);
> > +            return error;
> > +        }
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return EOK;
> > +}
> > +
> > /* Create a file object for parsing a config file */
> > int ini_config_file_open(const char *filename,
> > int error_level,
> > @@ -135,16 +175,9 @@ int ini_config_file_open(const char *filename,
> > return error;
> > }
> > 
> > -
> > new_ctx->filename = NULL;
> > new_ctx->file = NULL;
> > new_ctx->error_list = NULL;
> > -    new_ctx->metadata = NULL;
> > -
> > -    /* TBD - decide whether we actually need an FD.
> > -       It will be done when we move the metadata
> > -       processing into this function. */
> > -    new_ctx->fd = -1;
> > 
> > /* Store flags */
> > new_ctx->error_level = error_level;
> > @@ -172,39 +205,14 @@ int ini_config_file_open(const char *filename,
> > return error;
> > }
> > 
> > -    /* Open file */
> > -    TRACE_INFO_STRING("File", new_ctx->filename);
> > -    errno = 0;
> > -    new_ctx->file = fopen(new_ctx->filename, "r");
> > -    if (!(new_ctx->file)) {
> > -        error = errno;
> > -        TRACE_ERROR_NUMBER("Failed to open file", error);
> > -        ini_config_file_destroy(new_ctx);
> > -        return error;
> > -    }
> > -
> > -    /* Create internal collections */
> > -    error = col_create_collection(&(new_ctx->error_list),
> > -                                  INI_ERROR,
> > -                                  COL_CLASS_INI_PERROR);
> > -    if (error) {
> > -        TRACE_ERROR_NUMBER("Failed to create error list", error);
> > -        ini_config_file_destroy(new_ctx);
> > -        return error;
> > -    }
> > -
> > -    error = col_create_collection(&(new_ctx->metadata),
> > -                                  INI_METADATA,
> > -                                  COL_CLASS_INI_META);
> > -    if (error) {
> > -        TRACE_ERROR_NUMBER("Failed to create metadata collection", error);
> > +    /* Do common init */
> > +    error = common_file_init(new_ctx);
> > +    if(error) {
> > +        TRACE_ERROR_NUMBER("Failed to do common init", error);
> > ini_config_file_destroy(new_ctx);
> > return error;
> > }
> > 
> > -
> > -    /* TBD - Add metadata processing here */
> > -
> > *file_ctx = new_ctx;
> > TRACE_FLOW_EXIT();
> > return error;
> > @@ -236,12 +244,6 @@ int ini_config_file_reopen(struct ini_cfgfile *file_ctx_in,
> > new_ctx->filename = NULL;
> > new_ctx->file = NULL;
> > new_ctx->error_list = NULL;
> > -    new_ctx->metadata = NULL;
> > -
> > -    /* TBD - decide whether we actually need an FD.
> > -       It will be done when we move the metadata
> > -       processing into this function. */
> > -    new_ctx->fd = -1;
> > 
> > /* Store flags */
> > new_ctx->error_level = file_ctx_in->error_level;
> > @@ -259,39 +261,14 @@ int ini_config_file_reopen(struct ini_cfgfile *file_ctx_in,
> > return error;
> > }
> > 
> > -    /* Open file */
> > -    TRACE_INFO_STRING("File", new_ctx->filename);
> > -    errno = 0;
> > -    new_ctx->file = fopen(new_ctx->filename, "r");
> > -    if (!(new_ctx->file)) {
> > -        error = errno;
> > -        TRACE_ERROR_NUMBER("Failed to open file", error);
> > -        ini_config_file_destroy(new_ctx);
> > -        return error;
> > -    }
> > -
> > -    /* Create internal collections */
> > -    error = col_create_collection(&(new_ctx->error_list),
> > -                                  INI_ERROR,
> > -                                  COL_CLASS_INI_PERROR);
> > -    if (error) {
> > -        TRACE_ERROR_NUMBER("Failed to create error list", error);
> > -        ini_config_file_close(new_ctx);
> > -        return error;
> > -    }
> > -
> > -    error = col_create_collection(&(new_ctx->metadata),
> > -                                  INI_METADATA,
> > -                                  COL_CLASS_INI_META);
> > -    if (error) {
> > -        TRACE_ERROR_NUMBER("Failed to create metadata collection", error);
> > +    /* Do common init */
> > +    error = common_file_init(new_ctx);
> > +    if(error) {
> > +        TRACE_ERROR_NUMBER("Failed to do common init", error);
> > ini_config_file_destroy(new_ctx);
> > return error;
> > }
> > 
> > -
> > -    /* TBD - Add metadata processing here */
> > -
> > *file_ctx_out = new_ctx;
> > TRACE_FLOW_EXIT();
> > return error;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 87be7cfc4b8cc143a582a38a0d024e166d91df35 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 19:46:15 -0500
> > Subject: [PATCH] [INI] Check access function
> > 
> > Added check access constants and the check access function.
> > The function is effectively copied from ini_metadata.c
> > The flags are copied from ini_config.h
> > ---
> > ini/ini_configobj.h |   35 +++++++++++++++++++++++
> > ini/ini_fileobj.c   |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 110 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index 898440252ef3a547566fe2b5e80753d7971a8e47..eccad71c7245f1d035c5133c13b6078fc3e3dc5b \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -104,6 +104,41 @@
> > */
> > 
> > /**
> > + * @defgroup accesscheck Access control check flags
> > + *
> > + * @{
> > + */
> > +
> > +/**
> > + * @brief Validate access mode
> > + *
> > + * If this flag is specified the mode parameter
> > + * will be matched against the permissions set on the file
> > + * using the provided mask.
> > + */
> > +#define INI_ACCESS_CHECK_MODE   0x00000001
> > +
> > +/**
> > + * @brief Validate uid
> > + *
> > + * Provided uid will be checked against uid
> > + * of the file.
> > + */
> > +#define INI_ACCESS_CHECK_UID   0x00000002
> > +
> > +/**
> > + * @brief Validate gid
> > + *
> > + * Provided gid will be checked against gid
> > + * of the file.
> > + */
> > +#define INI_ACCESS_CHECK_GID   0x00000004
> > +
> > +/**
> > + * @}
> > + */
> > +
> > +/**
> > * @defgroup collisionflags Flags that define collision resolution logic.
> > *
> > * @{
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index c10b4bf954366ddae90f1d06c53acd0332968599..93a9372f3e37489862a33f1676ca68a532c62441 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -406,3 +406,78 @@ const char *ini_config_get_filename(struct ini_cfgfile \
> > *file_ctx) TRACE_FLOW_EXIT();
> > return ret;
> > }
> > +
> > +
> > +/* Check access */
> > +int ini_config_access_check(struct ini_cfgfile *file_ctx,
> > +                            uint32_t flags,
> > +                            uid_t uid,
> > +                            gid_t gid,
> > +                            mode_t mode,
> > +                            mode_t mask)
> > +{
> > +    int error = EOK;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    flags &= INI_ACCESS_CHECK_MODE |
> > +             INI_ACCESS_CHECK_GID |
> > +             INI_ACCESS_CHECK_UID;
> > +
> > +    if ((file_ctx == NULL) || (flags == 0)) {
> > +        TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
> > +        return EINVAL;
> > +
> > +    }
> > +
> > +    /* Check mode */
> > +    if (flags & INI_ACCESS_CHECK_MODE) {
> > +
> > +        TRACE_INFO_NUMBER("File mode as saved.",
> > +                          file_ctx->file_stats.st_mode);
> > +
> > +        file_ctx->file_stats.st_mode &= S_IRWXU | S_IRWXG | S_IRWXO;
> > +        TRACE_INFO_NUMBER("File mode adjusted.",
> > +                          file_ctx->file_stats.st_mode);
> > +
> > +        TRACE_INFO_NUMBER("Mode as provided.", mode);
> > +        mode &= S_IRWXU | S_IRWXG | S_IRWXO;
> > +        TRACE_INFO_NUMBER("Mode adjusted.", mode);
> > +
> > +        /* Adjust mask */
> > +        if (mask == 0) mask = S_IRWXU | S_IRWXG | S_IRWXO;
> > +        else mask &= S_IRWXU | S_IRWXG | S_IRWXO;
> > +
> > +        if ((mode & mask) != (file_ctx->file_stats.st_mode & mask)) {
> > +            TRACE_INFO_NUMBER("File mode:", (mode & mask));
> > +            TRACE_INFO_NUMBER("Mode adjusted.",
> > +                              (file_ctx->file_stats.st_mode & mask));
> > +            TRACE_ERROR_NUMBER("Access denied.", EACCES);
> > +            return EACCES;
> > +        }
> > +    }
> > +
> > +    /* Check uid */
> > +    if (flags & INI_ACCESS_CHECK_UID) {
> > +        if (file_ctx->file_stats.st_uid != uid) {
> > +            TRACE_ERROR_NUMBER("GID:", file_ctx->file_stats.st_uid);
> > +            TRACE_ERROR_NUMBER("GID passed in.", uid);
> > +            TRACE_ERROR_NUMBER("Access denied.", EACCES);
> > +            return EACCES;
> > +        }
> > +    }
> > +
> > +    /* Check gid */
> > +    if (flags & INI_ACCESS_CHECK_GID) {
> > +        if (file_ctx->file_stats.st_gid != gid) {
> > +            TRACE_ERROR_NUMBER("GID:", file_ctx->file_stats.st_gid);
> > +            TRACE_ERROR_NUMBER("GID passed in.", gid);
> > +            TRACE_ERROR_NUMBER("Access denied.", EACCES);
> > +            return EACCES;
> > +        }
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return error;
> > +
> > +}
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From c4d2383282b898f4c5914bf720301cdcabf5eb51 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 21:24:08 -0500
> > Subject: [PATCH] [INI] Avoid double free
> > 
> > I might squash this patch into one of the previous ones.
> > ---
> > ini/ini_fileobj.c |    5 ++++-
> > 1 files changed, 4 insertions(+), 1 deletions(-)
> > 
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index 93a9372f3e37489862a33f1676ca68a532c62441..2d47c8ff1d1a613dfc5baa8efd00b05c368f8447 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -82,7 +82,10 @@ void ini_config_file_close(struct ini_cfgfile *file_ctx)
> > TRACE_FLOW_ENTRY();
> > 
> > if(file_ctx) {
> > -        if(file_ctx->file) fclose(file_ctx->file);
> > +        if(file_ctx->file) {
> > +            fclose(file_ctx->file);
> > +            file_ctx->file = NULL;
> > +        }
> > }
> > 
> > TRACE_FLOW_EXIT();
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 81e90b377b432ef874fda11b6e82f6f0eb894807 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 21:28:59 -0500
> > Subject: [PATCH] [INI] Function to check for changes
> > 
> > Added function to detect changes to the configuration file.
> > ---
> > ini/ini_configobj.h |    4 ++--
> > ini/ini_fileobj.c   |   37 +++++++++++++++++++++++++++++++++++++
> > 2 files changed, 39 insertions(+), 2 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index eccad71c7245f1d035c5133c13b6078fc3e3dc5b..913b91e6abed18d30ba256edc280a1d0aa9d76ef \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -335,8 +335,8 @@ int ini_config_access_check(struct ini_cfgfile *file_ctx,
> > * - device ID
> > * - i-node
> > */
> > -int ini_config_changed(struct ini_cfgfile *file_ctx,
> > -                       struct ini_cfgfile *file_ctx_saved,
> > +int ini_config_changed(struct ini_cfgfile *file_ctx1,
> > +                       struct ini_cfgfile *file_ctx2,
> > int *changed);
> > 
> > 
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index 2d47c8ff1d1a613dfc5baa8efd00b05c368f8447..6de963971a0e9501fb86c23ee5faf6bfb5824bf0 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -484,3 +484,40 @@ int ini_config_access_check(struct ini_cfgfile *file_ctx,
> > return error;
> > 
> > }
> > +
> > +/* Determins if two file context different by comparing
> > + * - time stamp
> > + * - device ID
> > + * - i-node
> > + */
> > +int ini_config_changed(struct ini_cfgfile *file_ctx1,
> > +                       struct ini_cfgfile *file_ctx2,
> > +                       int *changed)
> > +{
> > +
> > +    int error = EOK;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    if ((file_ctx1 == NULL) ||
> > +        (file_ctx2 == NULL) ||
> > +        (changed == NULL)) {
> > +        TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
> > +        return EINVAL;
> > +    }
> > +
> > +    *changed = 0;
> > +
> > +    if((file_ctx1->file_stats.st_mtime !=
> > +        file_ctx2->file_stats.st_mtime) ||
> > +       (file_ctx1->file_stats.st_dev !=
> > +        file_ctx2->file_stats.st_dev) ||
> > +       (file_ctx1->file_stats.st_ino !=
> > +        file_ctx2->file_stats.st_ino)) {
> > +        TRACE_INFO_STRING("File changed!", "");
> > +        *changed = 1;
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return error;
> > +}
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 2ec4163bcbbcfa6c025b32cdbdbd3adf8c7a84f2 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 21:31:33 -0500
> > Subject: [PATCH] [INI] Tests for access and changes
> > 
> > Patch adds two functions. One tests permissions,
> > another validates if the file has changed or not.
> > ---
> > ini/ini_parse_ut.c |  248 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 248 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
> > index f0a95527aa315b559e5c6fa42740fe4a3ba4e4b3..f5b1c2c5b4e82de2baf29955901da28afc082cbb \
> >                 100644
> > --- a/ini/ini_parse_ut.c
> > +++ b/ini/ini_parse_ut.c
> > @@ -625,10 +625,256 @@ int merge_section_test(void)
> > resname, checkname, error));
> > 
> > return error;
> > +}
> > +
> > +int startup_test(void)
> > +{
> > +    int error = EOK;
> > +    struct ini_cfgfile *file_ctx = NULL;
> > +    struct ini_cfgobj *ini_config = NULL;
> > +    char **error_list = NULL;
> > +    char filename[PATH_MAX];
> > +    char *srcdir;
> > +
> > +    srcdir = getenv("srcdir");
> > +    sprintf(filename, "%s/ini/ini.d/foo.conf",
> > +                      (srcdir == NULL) ? "." : srcdir);
> > +
> > +    INIOUT(printf("<==== Startup test ====>\n"));
> > +
> > +    /* Open config file */
> > +    error = ini_config_file_open(filename,
> > +                                 INI_STOP_ON_NONE,
> > +                                 0,
> > +                                 INI_META_STATS,
> > +                                 &file_ctx);
> > +    if (error) {
> > +        printf("Failed to open file for reading. Error %d.\n",  error);
> > +        return error;
> > +    }
> > +
> > +    /* We will check just permissions here. */
> > +    error = ini_config_access_check(file_ctx,
> > +                                INI_ACCESS_CHECK_MODE, /* add uid & gui flags
> > +                                                        * in real case
> > +                                                        */
> > +                                0, /* <- will be real uid in real case */
> > +                                0, /* <- will be real gid in real case */
> > +                                0440, /* Checking for r--r----- */
> > +                                0);
> > +    /* This check is expected to fail since
> > +     * the actual permissions on the test file are: rw-rw-r--
> > +     */
> > +
> > +    if (!error) {
> > +        printf("Expected error got success!\n");
> > +        ini_config_file_destroy(file_ctx);
> > +        return EACCES;
> > +    }
> > +
> > +    error = ini_config_access_check(
> > +                        file_ctx,
> > +                        INI_ACCESS_CHECK_MODE, /* add uid & gui flags
> > +                                                * in real case
> > +                                                */
> > +                        0, /* <- will be real uid in real case */
> > +                        0, /* <- will be real gid in real case */
> > +                        0664, /* Checkling for rw-rw-r-- */
> > +                        0);
> > +
> > +    if (error) {
> > +        printf("Access check failed %d!\n", error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return EACCES;
> > +    }
> > +
> > +
> > +    /* Create config object */
> > +    error = ini_config_create(&ini_config);
> > +    if (error) {
> > +        printf("Failed to create collection. Error %d.\n", error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return error;
> > +    }
> > +
> > +    error = ini_config_parse(file_ctx,
> > +                             ini_config);
> > +    if (error) {
> > +        INIOUT(printf("Failed to parse configuration. Error %d.\n", error));
> > +
> > +        if (ini_config_error_count(file_ctx)) {
> > +            INIOUT(printf("Errors detected while parsing: %s\n",
> > +                   ini_config_get_filename(file_ctx)));
> > +            ini_config_get_errors(file_ctx, &error_list);
> > +            INIOUT(ini_print_errors(stdout, error_list));
> > +            ini_config_free_errors(error_list);
> > +        }
> > +        /* We do not return here intentionally */
> > +    }
> > +
> > +    ini_config_file_destroy(file_ctx);
> > +
> > +    INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT));
> > +
> > +    ini_config_destroy(ini_config);
> > +
> > +    return 0;
> > +}
> > +
> > +int reload_test(void)
> > +{
> > +    int error = EOK;
> > +    struct ini_cfgfile *file_ctx = NULL;
> > +    struct ini_cfgfile *file_ctx_new = NULL;
> > +    char infile[PATH_MAX];
> > +    char outfile[PATH_MAX];
> > +    char command[PATH_MAX * 3];
> > +    char *srcdir;
> > +    char *builddir;
> > +    int changed = 0;
> > +
> > +    INIOUT(printf("<==== Reload test ====>\n"));
> > +
> > +    srcdir = getenv("srcdir");
> > +    sprintf(infile, "%s/ini/ini.d/foo.conf",
> > +                      (srcdir == NULL) ? "." : srcdir);
> > +    builddir = getenv("builddir");
> > +    sprintf(outfile, "%s/foo.conf",
> > +                      (builddir == NULL) ? "." : builddir);
> > +    sprintf(command, "cp %s %s", infile, outfile);
> > +    errno = 0;
> > +    if(system(command)) {
> > +        error = errno;
> > +        printf("Failed to run copy command %d.\n",  error);
> > +        return error;
> > +    }
> > +
> > +    /* Open config file */
> > +    error = ini_config_file_open(outfile,
> > +                                 INI_STOP_ON_NONE,
> > +                                 0,
> > +                                 INI_META_STATS,
> > +                                 &file_ctx);
> > +    if (error) {
> > +        printf("Failed to open file for reading. Error %d.\n",  error);
> > +        return error;
> > +    }
> > +
> > +    error = ini_config_access_check(
> > +                    file_ctx,
> > +                    INI_ACCESS_CHECK_MODE, /* add uid & gui flags
> > +                                            * in real case
> > +                                            */
> > +                    0, /* <- will be real uid in real case */
> > +                    0, /* <- will be real gid in real case */
> > +                    0664, /* Checkling for rw-rw-r-- */
> > +                    0);
> > +
> > +    if (error) {
> > +        printf("Access check failed %d!\n", error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return EACCES;
> > +    }
> > +
> > +    /* ... Create config object and read configuration - not shown here.
> > +     *     See other examples ... */
> > +
> > +    /* Now close file but leave the context around */
> > +    ini_config_file_close(file_ctx);
> > +
> > +    /* Some time passed and we received a signal to reload... */
> > +    error = ini_config_file_reopen(file_ctx, &file_ctx_new);
> > +    if (error) {
> > +        printf("Failed to open file for reading. Error %d.\n",  error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return error;
> > +    }
> > +
> > +    changed = 0;
> > +    error = ini_config_changed(file_ctx,
> > +                               file_ctx_new,
> > +                               &changed);
> > +    if (error) {
> > +        printf("Failed to compare files. Error %d.\n",  error);
> > +        ini_config_file_destroy(file_ctx);
> > +        ini_config_file_destroy(file_ctx_new);
> > +        return error;
> > +    }
> > +
> > +    /* Check if file changed */
> > +    if (changed) {
> > +        printf("File changed when it shouldn't. This is unexpected error.\n");
> > +        ini_config_file_destroy(file_ctx);
> > +        ini_config_file_destroy(file_ctx_new);
> > +        return EINVAL;
> > +    }
> > +
> > +    /* Close file */
> > +    ini_config_file_destroy(file_ctx_new);
> > 
> > +    /* Emulate as if file changed */
> > +    errno = 0;
> > +    if (unlink(outfile)) {
> > +        error = errno;
> > +        printf("Failed to delete file %d.\n",  error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return error;
> > +    }
> > +
> > +    sleep(1);
> > +
> > +    errno = 0;
> > +    if (system(command)) {
> > +        error = errno;
> > +        printf("Failed to run copy command %d.\n",  error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return error;
> > +    }
> > +
> > +    /* Read again */
> > +    file_ctx_new = NULL;
> > +    error = ini_config_file_reopen(file_ctx, &file_ctx_new);
> > +    if (error) {
> > +        printf("Failed to open file for reading. Error %d.\n",  error);
> > +        ini_config_file_destroy(file_ctx);
> > +        return error;
> > +    }
> > 
> > +    changed = 0;
> > +    error = ini_config_changed(file_ctx,
> > +                               file_ctx_new,
> > +                               &changed);
> > +    if (error) {
> > +        printf("Failed to compare files. Error %d.\n",  error);
> > +        ini_config_file_destroy(file_ctx);
> > +        ini_config_file_destroy(file_ctx_new);
> > +        return error;
> > +    }
> > +
> > +    /* Check if file changed */
> > +    if (!changed) {
> > +        printf("File did not change when it should. This is an error.\n");
> > +        ini_config_file_destroy(file_ctx);
> > +        ini_config_file_destroy(file_ctx_new);
> > +        return EINVAL;
> > +    }
> > +
> > +    /* We do not need original context any more. */
> > +    ini_config_file_destroy(file_ctx);
> > +
> > +    /* New context is now original context */
> > +    file_ctx = file_ctx_new;
> > +
> > +    /* ... Create config object and read configuration - not shown here.
> > +     *     See other examples ... */
> > +
> > +    ini_config_file_destroy(file_ctx);
> > +
> > +    return 0;
> > }
> > 
> > +
> > +
> > /* Main function of the unit test */
> > int main(int argc, char *argv[])
> > {
> > @@ -637,6 +883,8 @@ int main(int argc, char *argv[])
> > read_again_test,
> > merge_values_test,
> > merge_section_test,
> > +                        startup_test,
> > +                        reload_test,
> > NULL };
> > test_fn t;
> > int i = 0;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 8654e77c640ac19e6997542589fbd1500ae6532d Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 21:45:39 -0500
> > Subject: [PATCH] [INI] Rename error print function
> > 
> > All config file processing functions start with "ini_config".
> > The only function that does not comply is
> > ini_print_errors. We can't rename it since
> > it is a part of the current active interface.
> > I marked that function needs to be removed when we
> > remove old interface and created a copy with
> > the correct name. I also updated unit test accordingly.
> > ---
> > ini/ini_configobj.h |    5 +----
> > ini/ini_parse_ut.c  |    8 ++++----
> > ini/ini_print.c     |   24 ++++++++++++++++++++++++
> > 3 files changed, 29 insertions(+), 8 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h
> > index 913b91e6abed18d30ba256edc280a1d0aa9d76ef..7089b62da31887e21eeffd6dceff76907ca9f1a6 \
> >                 100644
> > --- a/ini/ini_configobj.h
> > +++ b/ini/ini_configobj.h
> > @@ -300,10 +300,7 @@ int ini_config_copy(struct ini_cfgobj *ini_config,
> > struct ini_cfgobj **ini_new);
> > 
> > /* Function to print errors from the list */
> > -void ini_print_errors(FILE *file, char **error_list);
> > -
> > -
> > -
> > +void ini_config_print_errors(FILE *file, char **error_list);
> > 
> > /* Merge two configurations together creating a new one */
> > int ini_config_merge(struct ini_cfgobj *first,
> > diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
> > index f5b1c2c5b4e82de2baf29955901da28afc082cbb..696735aacee25fc71f2b60708aaf3d0e14081f2c \
> >                 100644
> > --- a/ini/ini_parse_ut.c
> > +++ b/ini/ini_parse_ut.c
> > @@ -85,7 +85,7 @@ int test_one_file(const char *in_filename,
> > INIOUT(printf("Errors detected while parsing: %s\n",
> > ini_config_get_filename(file_ctx)));
> > ini_config_get_errors(file_ctx, &error_list);
> > -            INIOUT(ini_print_errors(stdout, error_list));
> > +            INIOUT(ini_config_print_errors(stdout, error_list));
> > ini_config_free_errors(error_list);
> > }
> > /* We do not return here intentionally */
> > @@ -371,7 +371,7 @@ int merge_values_test(void)
> > INIOUT(printf("Errors detected while parsing: %s\n",
> > ini_config_get_filename(file_ctx)));
> > ini_config_get_errors(file_ctx, &error_list);
> > -                INIOUT(ini_print_errors(stdout, error_list));
> > +                INIOUT(ini_config_print_errors(stdout, error_list));
> > ini_config_free_errors(error_list);
> > }
> > 
> > @@ -548,7 +548,7 @@ int merge_section_test(void)
> > INIOUT(printf("Errors detected while parsing: %s\n",
> > ini_config_get_filename(file_ctx)));
> > ini_config_get_errors(file_ctx, &error_list);
> > -                    INIOUT(ini_print_errors(stdout, error_list));
> > +                    INIOUT(ini_config_print_errors(stdout, error_list));
> > ini_config_free_errors(error_list);
> > }
> > 
> > @@ -706,7 +706,7 @@ int startup_test(void)
> > INIOUT(printf("Errors detected while parsing: %s\n",
> > ini_config_get_filename(file_ctx)));
> > ini_config_get_errors(file_ctx, &error_list);
> > -            INIOUT(ini_print_errors(stdout, error_list));
> > +            INIOUT(ini_config_print_errors(stdout, error_list));
> > ini_config_free_errors(error_list);
> > }
> > /* We do not return here intentionally */
> > diff --git a/ini/ini_print.c b/ini/ini_print.c
> > index 1dcfa54bfd72daf2c790d04c37ff2b3107eb7295..42bd6fc221c71bf4f390a79e02a4928ecf747bd9 \
> >                 100644
> > --- a/ini/ini_print.c
> > +++ b/ini/ini_print.c
> > @@ -461,6 +461,9 @@ void print_config_parsing_errors(FILE *file,
> > 
> > 
> > /* Function to print errors from the list */
> > +/* THIS FUNCTION SHOUD BE REMOVED WHEN
> > + * OLD INTERFACE IS REMOVED - TBD.
> > + */
> > void ini_print_errors(FILE *file, char **error_list)
> > {
> > unsigned count = 0;
> > @@ -480,3 +483,24 @@ void ini_print_errors(FILE *file, char **error_list)
> > TRACE_FLOW_EXIT();
> > return;
> > }
> > +
> > +/* Function to print errors from the list */
> > +void ini_config_print_errors(FILE *file, char **error_list)
> > +{
> > +    unsigned count = 0;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    if (!error_list) {
> > +        TRACE_FLOW_STRING("List is empty.", "");
> > +        return;
> > +    }
> > +
> > +    while (error_list[count]) {
> > +        fprintf(file, "%s\n", error_list[count]);
> > +        count++;
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return;
> > +}
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From baa1b6eb9604729fa678a0988138a7aaa3f5c9c6 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Sun, 26 Dec 2010 21:58:24 -0500
> > Subject: [PATCH] [INI] Initialize variables in loops
> > 
> > It occured to me that one of the issues that Coverity
> > did not like (and I could not understand what it is
> > complaining about) is related to intializing the variables
> > in the loop.
> > This patch adds initialization in the loops.
> > ---
> > ini/ini_parse_ut.c    |    4 ++++
> > ini/ini_valueobj_ut.c |    3 +++
> > 2 files changed, 7 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
> > index 696735aacee25fc71f2b60708aaf3d0e14081f2c..5de79d954673a194bd080660f967c7b304dbdefe \
> >                 100644
> > --- a/ini/ini_parse_ut.c
> > +++ b/ini/ini_parse_ut.c
> > @@ -343,6 +343,7 @@ int merge_values_test(void)
> > INIOUT(printf("<==== Testing mode %s  ====>\n", mstr[i]));
> > 
> > /* Create config collection */
> > +        ini_config = NULL;
> > error = ini_config_create(&ini_config);
> > if (error) {
> > printf("Failed to create collection. Error %d.\n", error);
> > @@ -350,6 +351,7 @@ int merge_values_test(void)
> > return error;
> > }
> > 
> > +        file_ctx = NULL;
> > error = ini_config_file_open(filename,
> > INI_STOP_ON_ANY,
> > mflags[i],
> > @@ -517,6 +519,7 @@ int merge_section_test(void)
> > }
> > 
> > /* Create config collection */
> > +            ini_config = NULL;
> > error = ini_config_create(&ini_config);
> > if (error) {
> > printf("Failed to create collection. "
> > @@ -525,6 +528,7 @@ int merge_section_test(void)
> > return error;
> > }
> > 
> > +            file_ctx = NULL;
> > error = ini_config_file_open(filename,
> > INI_STOP_ON_ANY,
> > msecflags[i] | mflags[j],
> > diff --git a/ini/ini_valueobj_ut.c b/ini/ini_valueobj_ut.c
> > index af62c140d215f9298dd5671d8aa544a84ef254b1..c07ec85772084f1fd6dd157a9befae26c9aa6806 \
> >                 100644
> > --- a/ini/ini_valueobj_ut.c
> > +++ b/ini/ini_valueobj_ut.c
> > @@ -404,6 +404,7 @@ int vo_basic_test(void)
> > return error;
> > }
> > 
> > +        vo = NULL;
> > error = value_create_new(strvalue,
> > strlen(strvalue),
> > INI_VALUE_CREATED,
> > @@ -541,6 +542,7 @@ int vo_copy_test(void)
> > 
> > TRACE_INFO_NUMBER("Iteration:", wrap);
> > 
> > +        vo_copy = NULL;
> > error = value_copy(vo, &vo_copy);
> > if (error) {
> > printf("Failed to create a new value object %d.\n", error);
> > @@ -559,6 +561,7 @@ int vo_copy_test(void)
> > }
> > 
> > /* Get comment from the value */
> > +        ic = NULL;
> > error = value_extract_comment(vo_copy, &ic);
> > if (error) {
> > printf("Failed to extract comment %d.\n", error);
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From f9f8998bef402648d2565ada6789305e0c0ad46e Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Mon, 3 Jan 2011 14:36:47 -0500
> > Subject: [PATCH] [INI] Exposing functions
> > 
> > This patch makes two internal functions
> > resusable from different source modules.
> > ---
> > ini/ini_config_priv.h |    8 ++++++++
> > ini/ini_fileobj.c     |    2 +-
> > ini/ini_parse.c       |    2 +-
> > 3 files changed, 10 insertions(+), 2 deletions(-)
> > 
> > diff --git a/ini/ini_config_priv.h b/ini/ini_config_priv.h
> > index 84742c70ceeb5b493b935c635e81c57d5ef487ce..e714774a68a5e16b7a221f712abe2ea9179e88c8 \
> >                 100644
> > --- a/ini/ini_config_priv.h
> > +++ b/ini/ini_config_priv.h
> > @@ -82,4 +82,12 @@ void ini_cleanup_cb(const char *property,
> > /* Get parsing error */
> > const char *ini_get_error_str(int parsing_error, int family);
> > 
> > +/* Check if collision flags are valid */
> > +int valid_collision_flags(uint32_t collision_flags);
> > +
> > +/* Empty section */
> > +int empty_section(struct collection_item *sec);
> > +
> > +
> > +
> > #endif
> > diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c
> > index 6de963971a0e9501fb86c23ee5faf6bfb5824bf0..30a2f1545d7b22dcab3bb4eccd53c91fe7edfd62 \
> >                 100644
> > --- a/ini/ini_fileobj.c
> > +++ b/ini/ini_fileobj.c
> > @@ -34,7 +34,7 @@
> > 
> > 
> > /* Check if collision flags are valid */
> > -static int valid_collision_flags(uint32_t collision_flags)
> > +int valid_collision_flags(uint32_t collision_flags)
> > {
> > uint32_t flag;
> > 
> > diff --git a/ini/ini_parse.c b/ini/ini_parse.c
> > index 3f45ac71ae46dff3413a6d4db5dd59a0838d078b..e3ae938847b867780cb0d0d60d12868826952a85 \
> >                 100644
> > --- a/ini/ini_parse.c
> > +++ b/ini/ini_parse.c
> > @@ -357,7 +357,7 @@ static int check_section_collision(struct parser_obj *po)
> > }
> > 
> > /* Clean all items in the section */
> > -static int empty_section(struct collection_item *sec)
> > +int empty_section(struct collection_item *sec)
> > {
> > int error = EOK;
> > struct collection_item *item = NULL;
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > From 02c14799196cd1ffd0f53c6b2e995ac17a7f8917 Mon Sep 17 00:00:00 2001
> > From: Dmitri Pal <dpal at redhat.com>
> > Date: Mon, 3 Jan 2011 14:41:03 -0500
> > Subject: [PATCH] [INI] Function to merge two configurations
> > 
> > This patch provides first draft of the implementation
> > of the code to merge different configurations.
> > It is similar to the merge code that is implemented inside
> > the parser but different since it is not done during parsing
> > of one file but addresses use case when the configuration
> > is provided by different files that need to be merged together.
> > 
> > NOTE: It would make more sence to review function by function
> > from bottom of the patch rather than from the top.
> > ---
> > ini/ini_configobj.c |  456 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 456 insertions(+), 0 deletions(-)
> > 
> > diff --git a/ini/ini_configobj.c b/ini/ini_configobj.c
> > index 5e5e40b566abdf3ce2cbc225babe4b1e20c2dd47..d8583a224e8eebc4365df3909b6bac7c98477dc5 \
> >                 100644
> > --- a/ini/ini_configobj.c
> > +++ b/ini/ini_configobj.c
> > @@ -30,11 +30,19 @@
> > #include "ini_config_priv.h"
> > #include "ini_defines.h"
> > #include "ini_valueobj.h"
> > +#include "ini_configobj.h"
> > 
> > /* This constant belongs to ini_defines.h. Move from ini_config - TBD */
> > #define COL_CLASS_INI_BASE        20000
> > #define COL_CLASS_INI_CONFIG      COL_CLASS_INI_BASE + 0
> > 
> > +struct merge_data {
> > +    struct collection_item *ci;
> > +    uint32_t flags;
> > +    int error;
> > +    int found;
> > +};
> > +
> > /* Callback */
> > void ini_cleanup_cb(const char *property,
> > int property_len,
> > @@ -254,3 +262,451 @@ int ini_config_copy(struct ini_cfgobj *ini_config,
> > TRACE_FLOW_EXIT();
> > return error;
> > }
> > +
> > +/* Callback to process merging of the sections */
> > +static int merge_section_handler(const char *property,
> > +                                 int property_len,
> > +                                 int type,
> > +                                 void *data,
> > +                                 int length,
> > +                                 void *custom_data,
> > +                                 int *dummy)
> > +{
> > +    int error = EOK;
> > +    struct value_obj *vo = NULL;
> > +    struct value_obj *new_vo = NULL;
> > +    struct value_obj *vo_old = NULL;
> > +    struct merge_data *passed_data;
> > +    struct collection_item *acceptor = NULL;
> > +    struct collection_item *item = NULL;
> > +    unsigned insertmode;
> > +    uint32_t mergemode;
> > +    int suppress = 0;
> > +    int doinsert = 0;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    if ((type != COL_TYPE_BINARY) ||
> > +        ((type == COL_TYPE_BINARY) &&
> > +         (strncmp(property, INI_SECTION_KEY,
> > +                     sizeof(INI_SECTION_KEY)) == 0))) {
> > +        /* Skip items we do not care about */
> > +        TRACE_FLOW_EXIT();
> > +        return EOK;
> > +    }
> > +
> > +    /* Get value */
> > +    vo = *((struct value_obj **)(data));
> > +
> > +    /* Copy it */
> > +    error = value_copy(vo, &new_vo);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to copy value", error);
> > +        return error;
> > +    }
> > +
> > +    passed_data = (struct merge_data *)(custom_data);
> > +    acceptor = passed_data->ci;
> > +    mergemode = passed_data->flags & INI_MV2S_MASK;
> > +
> > +    switch (mergemode) {
> > +    case INI_MV2S_ERROR:     insertmode = COL_INSERT_DUPERROR;
> > +                             doinsert = 1;
> > +                             break;
> > +    case INI_MV2S_PRESERVE:  insertmode = COL_INSERT_DUPERROR;
> > +                             doinsert = 1;
> > +                             suppress = 1;
> > +                             break;
> > +    case INI_MV2S_ALLOW:     insertmode = COL_INSERT_NOCHECK;
> > +                             doinsert = 1;
> > +                             break;
> > +    case INI_MV2S_OVERWRITE: /* Special handling */
> > +    case INI_MV2S_DETECT:
> > +    default:
> > +                             break;
> > +    }
> > +
> > +    /* Do not insert but search for dups first */
> > +    if (!doinsert) {
> > +        TRACE_INFO_STRING("Overwrite mode. Looking for:",
> > +                          property);
> > +
> > +        error = col_get_item(acceptor,
> > +                             property,
> > +                             COL_TYPE_BINARY,
> > +                             COL_TRAVERSE_DEFAULT,
> > +                             &item);
> > +
> > +        if (error) {
> > +            TRACE_ERROR_NUMBER("Failed searching for dup", error);
> > +            value_destroy(new_vo);
> > +            return error;
> > +        }
> > +
> > +        /* Check if there is a dup */
> > +        if (item) {
> > +            /* Check if we are in the detect mode */
> > +            if (mergemode == INI_MV2S_DETECT) {
> > +                passed_data->error = EEXIST;
> > +                doinsert = 1;
> > +                insertmode = COL_INSERT_NOCHECK;
> > +            }
> > +            else {
> > +
> > +                /* Dup exists - update it */
> > +                vo_old = *((struct value_obj **)(col_get_item_data(item)));
> > +                error = col_modify_binary_item(item,
> > +                                               NULL,
> > +                                               &new_vo,
> > +                                               sizeof(struct value_obj *));
> > +                if (error) {
> > +                    TRACE_ERROR_NUMBER("Failed updating the value", error);
> > +                    value_destroy(new_vo);
> > +                    return error;
> > +                }
> > +
> > +                /* If we failed to update it is better to leak then crash,
> > +                 * so destroy original value only on the successful update.
> > +                 */
> > +                value_destroy(vo_old);
> > +            }
> > +        }
> > +        else {
> > +            /* No dup found so we can insert with no check */
> > +            doinsert = 1;
> > +            insertmode = COL_INSERT_NOCHECK;
> > +        }
> > +    }
> > +
> > +    if (doinsert) {
> > +        /* Add value to collection */
> > +        error = col_insert_binary_property(acceptor,
> > +                                           NULL,
> > +                                           COL_DSP_END,
> > +                                           NULL,
> > +                                           0,
> > +                                           insertmode,
> > +                                           property,
> > +                                           &new_vo,
> > +                                           sizeof(struct value_obj *));
> > +        if (error) {
> > +            value_destroy(new_vo);
> > +
> > +            if ((suppress) && (error == EEXIST)) {
> > +                TRACE_INFO_STRING("Preseved exisitng value",
> > +                                  property);
> > +            }
> > +            else {
> > +                /* Check if this is a critical error or not */
> > +                if ((mergemode == INI_MV1S_ERROR) && (error == EEXIST)) {
> > +                    TRACE_ERROR_NUMBER("Failed to add value object "
> > +                                       "to the section", error);
> > +                    passed_data->error = EEXIST;
> > +                    *dummy = 1;
> > +                }
> > +                else {
> > +                    TRACE_ERROR_NUMBER("Failed to add value object"
> > +                                       " to the section", error);
> > +                    return error;
> > +                }
> > +            }
> > +        }
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return error;
> > +}
> > +
> > +
> > +/* Internal function to merge two configs */
> > +static int merge_two_sections(struct collection_item *acceptor,
> > +                              struct collection_item *donor,
> > +                              uint32_t flags)
> > +{
> > +    int error = EOK;
> > +    struct merge_data data;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    data.ci = acceptor;
> > +    data.flags = flags;
> > +    data.error = 0;
> > +    data.found = 0;
> > +
> > +    error = col_traverse_collection(donor,
> > +                                    COL_TRAVERSE_ONELEVEL,
> > +                                    merge_section_handler,
> > +                                    (void *)(&data));
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Merge values failed", error);
> > +        return error;
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return data.error;
> > +}
> > +
> > +
> > +
> > +/* Callback to process the accepting config */
> > +static int acceptor_handler(const char *property,
> > +                            int property_len,
> > +                            int type,
> > +                            void *data,
> > +                            int length,
> > +                            void *custom_data,
> > +                            int *dummy)
> > +{
> > +    int error = EOK;
> > +    struct merge_data *passed_data;
> > +    struct collection_item *acceptor = NULL;
> > +    struct collection_item *donor = NULL;
> > +    uint32_t mergemode;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    passed_data = (struct merge_data *)(custom_data);
> > +    passed_data->found = 1;
> > +
> > +    donor = passed_data->ci;
> > +    acceptor = *((struct collection_item **)(data));
> > +
> > +    mergemode = passed_data->flags & INI_MS_MASK;
> > +
> > +    switch (mergemode) {
> > +    case INI_MS_ERROR:      /* Report error and return */
> > +                            TRACE_INFO_STRING("Error ",
> > +                                              "duplicate section");
> > +                            passed_data->error = EEXIST;
> > +                            break;
> > +
> > +    case INI_MS_PRESERVE:   /* Preserve what we have */
> > +                            TRACE_INFO_STRING("Preserve mode", "");
> > +                            break;
> > +
> > +    case INI_MS_OVERWRITE:  /* Empty existing section */
> > +                            TRACE_INFO_STRING("Ovewrite mode", "");
> > +                            error = empty_section(acceptor);
> > +                            if (error) {
> > +                                TRACE_ERROR_NUMBER("Failed to "
> > +                                                    "empty section",
> > +                                                    error);
> > +                                return error;
> > +                            }
> > +                            error = merge_two_sections(acceptor,
> > +                                                       donor,
> > +                                                       passed_data->flags);
> > +                            if (error) {
> > +                                TRACE_ERROR_NUMBER("Failed to merge "
> > +                                                    "sections", error);
> > +                                return error;
> > +                            }
> > +                            break;
> > +
> > +    case INI_MS_DETECT:     /* Detect mode */
> > +                            TRACE_INFO_STRING("Detect mode", "");
> > +                            passed_data->error = EEXIST;
> > +                            passed_data->found = 0;
> > +                            break;
> > +
> > +    case INI_MS_MERGE:      /* Merge */
> > +    default:                TRACE_INFO_STRING("Merge mode", "");
> > +                            error = merge_two_sections(acceptor,
> > +                                                       donor,
> > +                                                       passed_data->flags);
> > +                            if (error) {
> > +                                if (error != EEXIST) {
> > +                                    TRACE_ERROR_NUMBER("Failed to merge "
> > +                                                        "sections", error);
> > +                                    return error;
> > +                                }
> > +                                passed_data->error = error;
> > +                            }
> > +                            break;
> > +    }
> > +
> > +    *dummy = 1;
> > +    TRACE_FLOW_EXIT();
> > +    return EOK;
> > +}
> > +
> > +/* Callback to process the donating config */
> > +static int donor_handler(const char *property,
> > +                         int property_len,
> > +                         int type,
> > +                         void *data,
> > +                         int length,
> > +                         void *custom_data,
> > +                         int *dummy)
> > +{
> > +    int error = EOK;
> > +    struct merge_data *passed_data;
> > +    struct merge_data acceptor_data;
> > +    struct collection_item *new_ci = NULL;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    passed_data = (struct merge_data *)(custom_data);
> > +
> > +    /* All section are subcollections */
> > +    if(type == COL_TYPE_COLLECTIONREF) {
> > +
> > +        acceptor_data.flags = passed_data->flags;
> > +        acceptor_data.ci = *((struct collection_item **)(data));
> > +        acceptor_data.error = 0;
> > +        acceptor_data.found = 0;
> > +
> > +        /* Try to resolve collision only non ALLOW modes */
> > +        if (!(acceptor_data.flags & INI_MS_ALLOW)) {
> > +            error = col_get_item_and_do(passed_data->ci,
> > +                                        property,
> > +                                        COL_TYPE_COLLECTIONREF,
> > +                                        COL_TRAVERSE_ONELEVEL,
> > +                                        acceptor_handler,
> > +                                        (void *)(&acceptor_data));
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Critical error", error);
> > +                return error;
> > +            }
> > +        }
> > +
> > +        /* Was duplicate found ? */
> > +        if (acceptor_data.found) {
> > +            /* Check for logical error. It can be only EEXIST */
> > +            if (acceptor_data.error) {
> > +                /* Save error anyway */
> > +                passed_data->error = acceptor_data.error;
> > +                /* If it is section DETECT or MERGE+DETECT */
> > +                if ((passed_data->flags & INI_MS_DETECT) ||
> > +                    ((passed_data->flags & INI_MS_MERGE) &&
> > +                     (passed_data->flags & INI_MV2S_DETECT))) {
> > +                    TRACE_INFO_NUMBER("Non-critical error",
> > +                                      acceptor_data.error);
> > +                }
> > +                else {
> > +                    /* In any other mode we need to stop */
> > +                    TRACE_INFO_NUMBER("Merge error detected",
> > +                                      acceptor_data.error);
> > +                    /* Force stop */
> > +                    *dummy = 1;
> > +                }
> > +            }
> > +        }
> > +        else {
> > +            /* Not found? Then create a copy... */
> > +            error = col_copy_collection_with_cb(&new_ci,
> > +                                                acceptor_data.ci,
> > +                                                NULL,
> > +                                                COL_COPY_NORMAL,
> > +                                                ini_copy_cb,
> > +                                                NULL);
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Failed to copy collection", error);
> > +                return error;
> > +            }
> > +
> > +            /* ... and embed into the existing collection */
> > +            error = col_add_collection_to_collection(passed_data->ci,
> > +                                                     NULL,
> > +                                                     NULL,
> > +                                                     new_ci,
> > +                                                     COL_ADD_MODE_EMBED);
> > +            if (error) {
> > +                TRACE_ERROR_NUMBER("Failed to copy collection", error);
> > +                col_destroy_collection(new_ci);
> > +                return error;
> > +            }
> > +        }
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return EOK;
> > +}
> > +
> > +
> > +/* Internal function to merge two configs */
> > +static int merge_configs(struct ini_cfgobj *first,
> > +                         struct ini_cfgobj *second,
> > +                         uint32_t collision_flags)
> > +{
> > +    int error = EOK;
> > +    struct merge_data data;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    data.ci = first->cfg;
> > +    data.flags = collision_flags;
> > +    data.error = 0;
> > +    data.found = 0;
> > +
> > +    error = col_traverse_collection(second->cfg,
> > +                                    COL_TRAVERSE_ONELEVEL,
> > +                                    donor_handler,
> > +                                    (void *)(&data));
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Merge failed", error);
> > +        return error;
> > +    }
> > +
> > +    /* If boundaries are different re-align the values */
> > +    if (first->boundary != second->boundary) {
> > +
> > +        error = ini_config_set_wrap(first, first->boundary);
> > +        if (error) {
> > +            TRACE_ERROR_NUMBER("Failed to re-align", error);
> > +            return error;
> > +        }
> > +    }
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return error;
> > +}
> > +
> > +
> > +/* Merge two configurations together creating a new one */
> > +int ini_config_merge(struct ini_cfgobj *first,
> > +                     struct ini_cfgobj *second,
> > +                     uint32_t collision_flags,
> > +                     struct ini_cfgobj **result)
> > +{
> > +    int error = EOK;
> > +    struct ini_cfgobj *new_co = NULL;
> > +
> > +    TRACE_FLOW_ENTRY();
> > +
> > +    /* Check input params */
> > +    if ((!first) ||
> > +        (!second) ||
> > +        (!result)) {
> > +        TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
> > +        return EINVAL;
> > +    }
> > +
> > +    /* Check collision flags */
> > +    if (!valid_collision_flags(collision_flags)) {
> > +        TRACE_ERROR_NUMBER("Invalid flags.", EINVAL);
> > +        return EINVAL;
> > +    }
> > +
> > +    /* Create a copy */
> > +    /* TBD - create a COMPACT copy */
> > +    error = ini_config_copy(first, &new_co);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to copy collection", error);
> > +        return error;
> > +    }
> > +
> > +    /* Merge configs */
> > +    error = merge_configs(new_co, second, collision_flags);
> > +    if (error) {
> > +        TRACE_ERROR_NUMBER("Failed to copy collection", error);
> > +        ini_config_destroy(new_co);
> > +        return error;
> > +    }
> > +
> > +    *result = new_co;
> > +
> > +    TRACE_FLOW_EXIT();
> > +    return error;
> > +
> > +}
> > -- 
> > 1.5.5.6
> > 
> > 
> 
> 
> > _______________________________________________
> > sssd-devel mailing list
> > sssd-devel at lists.fedorahosted.org
> > https://fedorahosted.org/mailman/listinfo/sssd-devel
> > 
> 
> _______________________________________________
> sssd-devel mailing list
> sssd-devel at lists.fedorahosted.org
> https://fedorahosted.org/mailman/listinfo/sssd-devel
> 


-- 
Thank you,
Dmitri Pal

Sr. Engineering Manager IPA project,
Red Hat Inc.


-------------------------------
Looking to carve out IT costs?
www.redhat.com/carveoutcosts/


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic