From f7bf43ba4956f3bf24f44a289645bf36ef94d9ef Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Mon, 29 Mar 2010 16:58:29 -0400
Subject: [PATCH] [INI] Adding metadata interface

This patch:
1) Adds the definition of the metadata interface
to the header file. The functions that were exposed
for no good reason are now hidden.
2) Previously exposed functions and their descriptions
are removed from the public header and placed into
the source code for now.
3) The function that reads the config file no longer
tries to close file in case of error.
4) Lines collection is still passed in into the reading
function but as a collection itself not as a pointer
to it.
5) All the parts related to processing lines are currently
ifdefed using HAVE_VALIDATION that is currently is not defined.
This is done to disable creation of the lines collection
utill it is actually needed. I did not want to blindly remove
it though and loose already done work that will be useful
in future.
6) Version of the library and interface is updated
7) New header and source modules are introduced to hold functions
related to the meta data. They are mostly stubbed out.

This is incomplete patch. It builds and make check runs.
It is created just to simplify the review a bit.
---
 common/ini/Makefile.am     |    7 +-
 common/ini/configure.ac    |    2 +-
 common/ini/ini_config.c    |  534 +++++++++++++++++++++++++++++---------------
 common/ini/ini_config.h    |  390 ++++++++++++++++++++++++++-------
 common/ini/ini_config_ut.c |  113 ++++++++--
 common/ini/ini_metadata.c  |  104 +++++++++
 common/ini/ini_metadata.h  |   42 ++++
 7 files changed, 915 insertions(+), 277 deletions(-)
 create mode 100644 common/ini/ini_metadata.c
 create mode 100644 common/ini/ini_metadata.h

diff --git a/common/ini/Makefile.am b/common/ini/Makefile.am
index af81a9f893eab8ca7ff2d7e53bbc733faf1f6d6d..76205262dccc3e24301403d4935bfc7ae7a27cdf 100644
--- a/common/ini/Makefile.am
+++ b/common/ini/Makefile.am
@@ -33,12 +33,15 @@ dist_include_HEADERS = \
 # Build library
 lib_LTLIBRARIES = libini_config.la
 libini_config_la_SOURCES = \
-    ini_config.c
+    ini_config.c \
+    ini_metadata.c \
+    ini_metadata.h
+
 libini_config_la_LIBADD = \
     -L$(topbuilddir)/collection \
     -lcollection
 libini_config_la_LDFLAGS = \
-    -version-info 1:0:0
+    -version-info 2:0:0
 
 # Build unit test
 check_PROGRAMS = ini_config_ut
diff --git a/common/ini/configure.ac b/common/ini/configure.ac
index a8c751fd832536ecac31d1f38c91bae8b2c9e90c..aa2033c1e56564e025c71725a685e6959c45265d 100644
--- a/common/ini/configure.ac
+++ b/common/ini/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([ini_config],[0.4.0],[sssd-devel@lists.fedorahosted.org])
+AC_INIT([ini_config],[0.5.0],[sssd-devel@lists.fedorahosted.org])
 AC_CONFIG_SRCDIR([ini_config.c])
 AC_CONFIG_AUX_DIR([build])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign])
diff --git a/common/ini/ini_config.c b/common/ini/ini_config.c
index e87419a3057c879bf3baa4ff3290ac801ef5479d..9015590f5be80abe9a97a9c4374e90c7a842590e 100644
--- a/common/ini/ini_config.c
+++ b/common/ini/ini_config.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <locale.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include "config.h"
 /* For error text */
 #include <libintl.h>
@@ -37,6 +38,7 @@
 #include "collection_tools.h"
 #include "trace.h"
 #include "ini_config.h"
+#include "ini_metadata.h"
 
 #define NAME_OVERHEAD   10
 
@@ -79,20 +81,40 @@
 #define INI_ERROR       "errors"
 #define INI_ERROR_NAME  "errname"
 
-
 /* Internal sizes. MAX_KEY is defined in config.h */
 #define MAX_VALUE       PATH_MAX
 #define BUFFER_SIZE     MAX_KEY + MAX_VALUE + 3
 
-/* Internally used functions */
-static int config_with_lines(const char *application,
-                             FILE *config_file,
-                             const char *config_source,
-                             struct collection_item **ini_config,
-                             int error_level,
-                             struct collection_item **error_list,
-                             struct collection_item **lines);
 
+/*============================================================*/
+/* The following classes moved here from the public header
+ * They are reserved for future use.
+ *
+ * NOTE: before exposing these constants again in the common header
+ * check that the class IDs did not get reused over time by
+ * other classes.
+ */
+/** @brief Collection of grammar errors.
+ *
+ * Reserved for future use.
+ */
+#define COL_CLASS_INI_GERROR      COL_CLASS_INI_BASE + 5
+/** @brief Collection of validation errors.
+ *
+ * Reserved for future use.
+ */
+#define COL_CLASS_INI_VERROR      COL_CLASS_INI_BASE + 6
+
+#ifdef HAVE_VALIDATION
+
+/** @brief Collection of lines from the INI file.
+ *
+ * Reserved for future use
+ */
+#define COL_CLASS_INI_LINES       COL_CLASS_INI_BASE + 7
+
+#endif /* HAVE_VALIDATION */
+/*============================================================*/
 
 
 /* Different error string functions can be passed as callbacks */
@@ -122,7 +144,23 @@ const char *parsing_error_str(int parsing_error)
  * This function is currently not used.
  * It is planned to be used by the INI
  * file grammar parser.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
  */
+/** @brief Function to return a grammar error in template.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * This error is returned when the template
+ * is translated into the grammar object.
+ *
+ * @param[in] parsing_error    Error code for the grammar error.
+ *
+ * @return Error string.
+ */
+
 const char *grammar_error_str(int grammar_error)
 {
     const char *placeholder= _("Unknown grammar error.");
@@ -147,6 +185,22 @@ const char *grammar_error_str(int grammar_error)
  * This function is currently not used.
  * It is planned to be used by the INI
  * file grammar validator.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/** @brief Function to return a validation error.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * This is the error that it is returned when
+ * the INI file is validated against the
+ * grammar object.
+ *
+ * @param[in] parsing_error    Error code for the validation error.
+ *
+ * @return Error string.
  */
 const char *validation_error_str(int validation_error)
 {
@@ -186,7 +240,7 @@ static int ini_to_collection(FILE *file,
                              struct collection_item *ini_config,
                              int error_level,
                              struct collection_item **error_list,
-                             struct collection_item **lines)
+                             struct collection_item *lines)
 {
     int error;
     int status;
@@ -204,25 +258,18 @@ static int ini_to_collection(FILE *file,
 
     TRACE_FLOW_STRING("ini_to_collection", "Entry");
 
-    if (file == NULL) {
-        TRACE_ERROR_NUMBER("No file handle", EINVAL);
-        return EINVAL;
-    }
-
     /* Open the collection of errors */
     if (error_list != NULL) {
         *error_list = NULL;
         error = col_create_collection(error_list, INI_ERROR, COL_CLASS_INI_PERROR);
         if (error) {
             TRACE_ERROR_NUMBER("Failed to create error collection", error);
-            fclose(file);
             return error;
         }
         /* Add file name as the first item */
         error = col_add_str_property(*error_list, NULL, INI_ERROR_NAME, config_filename, 0);
         if (error) {
             TRACE_ERROR_NUMBER("Failed to and name to collection", error);
-            fclose(file);
             col_destroy_collection(*error_list);
             return error;
         }
@@ -239,16 +286,18 @@ static int ini_to_collection(FILE *file,
 
         switch (status) {
         case RET_PAIR:
+
+#ifdef HAVE_VALIDATION
+
             /* Add line to the collection of lines.
              * It is pretty safe in this case to just type cast the value to
              * int32_t since it is unrealistic that ini file will ever have
              * so many lines.
              */
             if (lines) {
-                error = col_add_int_property(*lines, NULL, key, (int32_t)line);
+                error = col_add_int_property(lines, NULL, key, (int32_t)line);
                 if (error) {
                     TRACE_ERROR_NUMBER("Failed to add line to line collection", error);
-                    fclose(file);
                     col_destroy_collection(current_section);
                     if (created) {
                         col_destroy_collection(*error_list);
@@ -258,6 +307,8 @@ static int ini_to_collection(FILE *file,
                 }
             }
 
+#endif /* HAVE_VALIDATION */
+
             /* Do we have a section at the top of the file ? */
             if (section_count == 0) {
                 /* Check if collection already exists */
@@ -273,7 +324,6 @@ static int ini_to_collection(FILE *file,
                                                                   current_section,
                                                                   COL_ADD_MODE_REFERENCE))) {
                         TRACE_ERROR_NUMBER("Failed to create collection", error);
-                        fclose(file);
                         col_destroy_collection(current_section);
                         if (created) {
                             col_destroy_collection(*error_list);
@@ -297,7 +347,6 @@ static int ini_to_collection(FILE *file,
                                             length);
             if (error != EOK) {
                 TRACE_ERROR_NUMBER("Failed to add pair to collection", error);
-                fclose(file);
                 col_destroy_collection(current_section);
                 if (created) {
                     col_destroy_collection(*error_list);
@@ -308,6 +357,9 @@ static int ini_to_collection(FILE *file,
             break;
 
         case RET_SECTION:
+
+#ifdef HAVE_VALIDATION
+
             /* Add line to the collection of lines */
             if (lines) {
                 /* For easier search make line numbers for the sections negative.
@@ -316,10 +368,9 @@ static int ini_to_collection(FILE *file,
                  * int32_t since it is unrealistic that ini file will ever have
                  * so many lines.
                  */
-                error = col_add_int_property(*lines, NULL, key, (int32_t)(-1 * line));
+                error = col_add_int_property(lines, NULL, key, (int32_t)(-1 * line));
                 if (error) {
                     TRACE_ERROR_NUMBER("Failed to add line to line collection", error);
-                    fclose(file);
                     col_destroy_collection(current_section);
                     if (created) {
                         col_destroy_collection(*error_list);
@@ -329,6 +380,8 @@ static int ini_to_collection(FILE *file,
                 }
             }
 
+#endif /* HAVE_VALIDATION */
+
             /* Read a new section */
             col_destroy_collection(current_section);
             current_section = NULL;
@@ -343,7 +396,6 @@ static int ini_to_collection(FILE *file,
                                                               current_section,
                                                               COL_ADD_MODE_REFERENCE))) {
                     TRACE_ERROR_NUMBER("Failed to add collection", error);
-                    fclose(file);
                     col_destroy_collection(current_section);
                     if (created) {
                         col_destroy_collection(*error_list);
@@ -370,7 +422,6 @@ static int ini_to_collection(FILE *file,
                                             ERROR_TXT, &pe, sizeof(pe));
             if (error) {
                 TRACE_ERROR_NUMBER("Failed to add error to collection", error);
-                fclose(file);
                 col_destroy_collection(current_section);
                 if (created) {
                     col_destroy_collection(*error_list);
@@ -382,7 +433,6 @@ static int ini_to_collection(FILE *file,
             if (error_level != INI_STOP_ON_NONE) {
                 TRACE_ERROR_STRING("Invalid format of the file", "");
                 col_destroy_collection(current_section);
-                fclose(file);
                 return EIO;
             }
             break;
@@ -395,7 +445,6 @@ static int ini_to_collection(FILE *file,
                                             WARNING_TXT, &pe, sizeof(pe));
             if (error) {
                 TRACE_ERROR_NUMBER("Failed to add warning to collection", error);
-                fclose(file);
                 col_destroy_collection(current_section);
                 if (created) {
                     col_destroy_collection(*error_list);
@@ -407,7 +456,6 @@ static int ini_to_collection(FILE *file,
             if (error_level == INI_STOP_ON_ANY) {
                 TRACE_ERROR_STRING("Invalid format of the file", "");
                 if (created) col_destroy_collection(current_section);
-                fclose(file);
                 return EIO;
             }
             TRACE_ERROR_STRING("Invalid string", "");
@@ -416,8 +464,11 @@ static int ini_to_collection(FILE *file,
         ext_err = -1;
     }
 
-    /* Close file */
-    fclose(file);
+    /* Note: File is not closed on this level any more.
+     * It opened on the level above, checked and closed there.
+     * It is not the responsibility of this function to close
+     * file any more.
+     */
 
     COL_DEBUG_COLLECTION(ini_config);
 
@@ -447,7 +498,23 @@ void free_ini_config_errors(struct collection_item *error_set)
     TRACE_FLOW_STRING("free_ini_config_errors", "Exit");
 }
 
-/* Function to free configuration lines list */
+#ifdef HAVE_VALIDATION
+
+/* Function to free configuration lines list.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/**
+ * @brief Function to free lines object.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * @param[in] lines       Lines object.
+ *
+ */
+
 void free_ini_config_lines(struct collection_item *lines)
 {
     TRACE_FLOW_STRING("free_ini_config_lines", "Entry");
@@ -455,6 +522,8 @@ void free_ini_config_lines(struct collection_item *lines)
     TRACE_FLOW_STRING("free_ini_config_lines", "Exit");
 }
 
+#endif /* HAVE_VALIDATION */
+
 
 /* Read configuration information from a file */
 int config_from_file(const char *application,
@@ -466,12 +535,13 @@ int config_from_file(const char *application,
     int error;
 
     TRACE_FLOW_STRING("config_from_file", "Entry");
-    error = config_from_file_with_lines(application,
-                                        config_filename,
-                                        ini_config,
-                                        error_level,
-                                        error_list,
-                                        NULL);
+    error = config_from_file_with_metadata(application,
+                                           config_filename,
+                                           ini_config,
+                                           error_level,
+                                           error_list,
+                                           0,
+                                           NULL);
     TRACE_FLOW_NUMBER("config_from_file. Returns", error);
     return error;
 }
@@ -487,97 +557,43 @@ int config_from_fd(const char *application,
     int error;
 
     TRACE_FLOW_STRING("config_from_fd", "Entry");
-    error = config_from_fd_with_lines(application, fd, config_source,
-                                      ini_config, error_level,
-                                      error_list, NULL);
+    error = config_from_fd_with_metadata(application,
+                                         fd,
+                                         config_source,
+                                         ini_config,
+                                         error_level,
+                                         error_list,
+                                         0,
+                                         NULL);
     TRACE_FLOW_NUMBER("config_from_fd. Returns", error);
     return error;
 }
 
-/* Function to read the ini file and have a collection
- * of which item appers on which line
- */
-int config_from_file_with_lines(const char *application,
-                                const char *config_filename,
-                                struct collection_item **ini_config,
-                                int error_level,
-                                struct collection_item **error_list,
-                                struct collection_item **lines)
-{
-    int error = EOK;
-    FILE *config_file = NULL;
 
-    TRACE_FLOW_STRING("config_from_file_with_lines", "Entry");
-
-    config_file = fopen(config_filename, "r");
-    if(!config_file) {
-        error = errno;
-        TRACE_ERROR_NUMBER("Failed to open file", error);
-        return error;
-    }
-
-    error = config_with_lines(application, config_file,
-                              config_filename, ini_config,
-                              error_level, error_list,
-                              lines);
-    TRACE_FLOW_NUMBER("config_from_file_with_lines. Returns", error);
-    return error;
-}
-
-/* Function to read the ini file and have a collection
- * of which item appers on which line
- */
-int config_from_fd_with_lines(const char *application,
-                              int fd,
-                              const char *config_source,
-                              struct collection_item **ini_config,
-                              int error_level,
-                              struct collection_item **error_list,
-                              struct collection_item **lines)
-{
-    int error = EOK;
-    FILE *config_file;
-
-    TRACE_FLOW_STRING("config_from_fd_with_lines", "Entry");
-
-    config_file = fdopen(fd, "r");
-    if (!config_file) {
-        error = errno;
-        TRACE_ERROR_NUMBER("Failed to dup file", error);
-        return error;
-    }
-
-    error = config_with_lines(application, config_file,
-                              config_source, ini_config,
-                              error_level, error_list,
-                              lines);
-    TRACE_FLOW_NUMBER("config_from_fd_with_lines. Returns", error);
-
-    return error;
-}
 
 /* Low level function that prepares the collection
  * and calls parser.
  */
-static int config_with_lines(const char *application,
-                             FILE *config_file,
-                             const char *config_source,
-                             struct collection_item **ini_config,
-                             int error_level,
-                             struct collection_item **error_list,
-                             struct collection_item **lines)
+static int config_with_metadata(const char *application,
+                                FILE *config_file,
+                                const char *config_source,
+                                struct collection_item **ini_config,
+                                int error_level,
+                                struct collection_item **error_list,
+                                uint32_t metaflags,
+                                struct collection_item *metadata)
 {
     int error;
     int created = 0;
+    struct collection_item *lines = NULL;
+
+#ifdef HAVE_VALIDATION
     int created_lines = 0;
+#endif
 
     TRACE_FLOW_STRING("config_from_file", "Entry");
 
-    if ((ini_config == NULL) ||
-        (application == NULL)) {
-        TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
-        return EINVAL;
-    }
+    /* Now we check arguments in the calling functions. */
 
     /* Create collection if needed */
     if (*ini_config == NULL) {
@@ -591,40 +607,32 @@ static int config_with_lines(const char *application,
         created = 1;
     }
     /* Is the collection of the right class? */
-    else if (col_is_of_class(*ini_config, COL_CLASS_INI_CONFIG)) {
+    else if (((col_is_of_class(*ini_config, COL_CLASS_INI_CONFIG))== 0) &&
+             ((col_is_of_class(*ini_config, COL_CLASS_INI_META))== 0)) {
         TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
         return EINVAL;
     }
 
-
-    /* Create collection if needed */
-    if (lines) {
-
-        /* Make sure that the lines collection is empty */
-        if (*lines) {
-            TRACE_ERROR_NUMBER("Collection of lines is not empty", EINVAL);
-            if (created) {
-                col_destroy_collection(*ini_config);
-                *ini_config = NULL;
-            }
-            return EINVAL;
-        }
-
-        error = col_create_collection(lines,
-                                      application,
-                                      COL_CLASS_INI_LINES);
-        if (error != EOK) {
-            TRACE_ERROR_NUMBER("Failed to create collection", error);
-            if (created) {
-                col_destroy_collection(*ini_config);
-                *ini_config = NULL;
-            }
-            return error;
+#ifdef HAVE_VALIDATION
+    /* This code is preserved for future use */
+    error = col_create_collection(lines,
+                                    application,
+                                    COL_CLASS_INI_LINES);
+    if (error != EOK) {
+        TRACE_ERROR_NUMBER("Failed to create collection", error);
+        if (created) {
+            col_destroy_collection(*ini_config);
+            *ini_config = NULL;
         }
-        created_lines = 1;
+        return error;
     }
+    created_lines = 1;
+#else
+    /* Until we implement validation do not read the lines. */
+    lines = NULL;
+#endif /* HAVE_VALIDATION */
 
-    /* Do the actual work */
+    /* Do the actual work - for now do not read lines.*/
     error = ini_to_collection(config_file, config_source,
                               *ini_config, error_level,
                               error_list, lines);
@@ -633,57 +641,146 @@ static int config_with_lines(const char *application,
         col_destroy_collection(*ini_config);
         *ini_config = NULL;
     }
-    /* Also create collection of lines if we created it */
-    if (error && created_lines) {
-        col_destroy_collection(*lines);
-        *lines = NULL;
-    }
+
+    /* FIXME - put lines collection into the metadata */
 
     TRACE_FLOW_NUMBER("config_from_file. Returns", error);
     return error;
 }
 
-/* Special wrapper around the inernal parser
- * to open the file first.
- * Used in conf_for_app function.
+/* Function to read the ini file from fd
+ * with meta data.
  */
-static int ini_to_col_from_file(const char *config_filename,
-                                struct collection_item *ini_config,
-                                int error_level,
-                                struct collection_item **error_list,
-                                struct collection_item **lines)
+int config_from_fd_with_metadata(const char *application,
+                                 int ext_fd,
+                                 const char *config_filename,
+                                 struct collection_item **ini_config,
+                                 int error_level,
+                                 struct collection_item **error_list,
+                                 uint32_t metaflags,
+                                 struct collection_item **metadata)
 {
     int error = EOK;
+    int file_error = EOK;
+    int save_error = 0;
+    int fd = -1;
     FILE *config_file = NULL;
 
-    TRACE_FLOW_STRING("ini_to_col_from_file", "Entry");
+    TRACE_FLOW_STRING("config_from_fd_with_metadata", "Entry");
+
+    /* We need to check arguments before we can move on,
+     * and start allocating memory.
+     */
+    if ((ini_config == NULL) ||
+        (application == NULL)) {
+        TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
+        return EINVAL;
+    }
+
+    /* Prepare meta data */
+    error = prepare_metadata(metaflags, metadata, &save_error);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to prepare metadata", error);
+        return error;
+    }
+
+    errno = 0;
+
+    if (ext_fd == -1) {
+        /* No file descriptor so use name */
+        config_file = fopen(config_filename, "r");
+    }
+    else {
+        /* Create a copy of the descriptor so that we can close it if needed */
+        fd = dup(ext_fd);
+        if (fd != -1) config_file = fdopen(fd, "r");
+    }
+    file_error = errno;
+
+    if (save_error) {
+        /* Record the result of the open file operation in metadata */
+        error = col_add_int_property(*metadata,
+                                     INI_META_SEC_ERROR,
+                                     INI_META_KEY_READ_ERROR,
+                                     file_error);
+        if (error) {
+            /* Something is really wrong if we failed here */
+            TRACE_ERROR_NUMBER("Failed to save file open error", error);
+            if (config_file) fclose(config_file);
+            return error;
+        }
+    }
 
-    config_file = fopen(config_filename, "r");
     if(!config_file) {
-        error = errno;
-        TRACE_ERROR_NUMBER("ini_to_col_from_file. Returns", error);
-        return ENOENT;
+        TRACE_ERROR_NUMBER("Failed to open file", file_error);
+        return file_error;
     }
 
-    error = ini_to_collection(config_file,
-                              config_filename,
-                              ini_config,
-                              error_level,
-                              error_list,
-                              lines);
-    TRACE_FLOW_NUMBER("ini_to_col_from_file. Returns", error);
+    /* Collect meta data before actually parsing the file */
+    error = collect_metadata(metaflags, metadata, config_file);
+    if(error) {
+        TRACE_ERROR_NUMBER("Failed to collect metadata", error);
+        return error;
+    }
+
+    if (!(metaflags & INI_META_ACTION_NOPARSE)) {
+        /* Parse data if needed */
+        error = config_with_metadata(application,
+                                     config_file,
+                                     config_filename,
+                                     ini_config,
+                                     error_level,
+                                     error_list,
+                                     metaflags,
+                                     *metadata);
+    }
+
+    /* We opened the file we close it */
+    fclose(config_file);
+
+    TRACE_FLOW_NUMBER("config_from_fd_with_metadata. Returns", error);
+    return error;
+}
+
+/* Function to read the ini file with metadata
+ * using file name.
+ */
+int config_from_file_with_metadata(const char *application,
+                                   const char *config_filename,
+                                   struct collection_item **ini_config,
+                                   int error_level,
+                                   struct collection_item **error_list,
+                                   uint32_t metaflags,
+                                   struct collection_item **metadata)
+{
+    int error = EOK;
+    TRACE_FLOW_STRING("config_from_file_with_metadata", "Entry");
+
+    error = config_from_fd_with_metadata(application,
+                                         -1,
+                                         config_filename,
+                                         ini_config,
+                                         error_level,
+                                         error_list,
+                                         metaflags,
+                                         metadata);
+
+    TRACE_FLOW_STRING("config_from_file_with_metadata", "Exit");
     return error;
 }
 
 
 /* Read default config file and then overwrite it with a specific one
  * from the directory */
-int config_for_app(const char *application,
-                   const char *config_file,
-                   const char *config_dir,
-                   struct collection_item **ini_config,
-                   int error_level,
-                   struct collection_item **error_set)
+int config_for_app_with_metadata(const char *application,
+                                 const char *config_file,
+                                 const char *config_dir,
+                                 struct collection_item **ini_config,
+                                 int error_level,
+                                 struct collection_item **error_set,
+                                 uint32_t metaflags,
+                                 struct collection_item **meta_default,
+                                 struct collection_item **meta_appini)
 {
     int error = EOK;
     char *file_name;
@@ -695,7 +792,7 @@ int config_for_app(const char *application,
     int tried = 0;
     int noents = 0;
 
-    TRACE_FLOW_STRING("config_to_collection", "Entry");
+    TRACE_FLOW_STRING("config_for_app", "Entry");
 
     if (ini_config == NULL) {
         TRACE_ERROR_NUMBER("Invalid parameter", EINVAL);
@@ -745,7 +842,8 @@ int config_for_app(const char *application,
         created = 1;
     }
     /* Is the collection of the right class? */
-    else if (col_is_of_class(*ini_config, COL_CLASS_INI_CONFIG)) {
+    else if ((col_is_of_class(*ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+             (col_is_of_class(*ini_config, COL_CLASS_INI_META) == 0)) {
         TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
         return EINVAL;
     }
@@ -753,8 +851,14 @@ int config_for_app(const char *application,
     /* Read master file */
     if (config_file != NULL) {
         TRACE_INFO_STRING("Reading master file:", config_file);
-        error = ini_to_col_from_file(config_file, *ini_config,
-                                     error_level, pass_common, NULL);
+        /* Get configuration information from the file */
+        error = config_from_file_with_metadata(application,
+                                               config_file,
+                                               ini_config,
+                                               error_level,
+                                               pass_common,
+                                               metaflags,
+                                               meta_default);
         tried++;
         /* ENOENT and EOK are Ok */
         if (error) {
@@ -812,8 +916,13 @@ int config_for_app(const char *application,
         sprintf(file_name, "%s%s%s.conf", config_dir, SLASH, application);
         TRACE_INFO_STRING("Opening file:", file_name);
         /* Read specific file */
-        error = ini_to_col_from_file(file_name, *ini_config,
-                                     error_level, pass_specific, NULL);
+        error = config_from_file_with_metadata(application,
+                                               file_name,
+                                               ini_config,
+                                               error_level,
+                                               pass_specific,
+                                               metaflags,
+                                               meta_appini);
         tried++;
         free(file_name);
         /* ENOENT and EOK are Ok */
@@ -874,6 +983,36 @@ int config_for_app(const char *application,
     return EOK;
 }
 
+
+/* Function to return configuration data
+ * for the application without meta data.
+ */
+int config_for_app(const char *application,
+                   const char *config_file,
+                   const char *config_dir,
+                   struct collection_item **ini_config,
+                   int error_level,
+                   struct collection_item **error_set)
+{
+    int error = EOK;
+    TRACE_FLOW_STRING("config_for_app", "Entry");
+
+    error = config_for_app_with_metadata(application,
+                                         config_file,
+                                         config_dir,
+                                         ini_config,
+                                         error_level,
+                                         error_set,
+                                         0,
+                                         NULL,
+                                         NULL);
+
+    TRACE_FLOW_NUMBER("config_for_app. Returning", error);
+    return error;
+}
+
+
+
 /* Reads a line from the file */
 int read_line(FILE *file,
               char *buf,
@@ -1127,7 +1266,22 @@ void print_file_parsing_errors(FILE *file,
 }
 
 
-/* Print errors and warnings that were detected while processing grammar */
+/* Print errors and warnings that were detected while processing grammar.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/**
+ * @brief Print errors and warnings that were detected while
+ * checking grammar of the template.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * @param[in] file           File descriptor.
+ * @param[in] error_list     List of the parsing errors.
+ *
+ */
 void print_grammar_errors(FILE *file,
                           struct collection_item *error_list)
 {
@@ -1141,7 +1295,22 @@ void print_grammar_errors(FILE *file,
                      grammar_error_str);
 }
 
-/* Print errors and warnings that were detected while validating INI file. */
+/* Print errors and warnings that were detected while validating INI file.
+ *
+ * The following doxygen description is moved here.
+ * When the function gets exposed move it into
+ * the header file.
+ */
+/**
+ * @brief Print errors and warnings that were detected while
+ * checking INI file against the grammar object.
+ *
+ * EXPERIMENTAL. Reserved for future use.
+ *
+ * @param[in] file           File descriptor.
+ * @param[in] error_list     List of the parsing errors.
+ *
+ */
 void print_validation_errors(FILE *file,
                              struct collection_item *error_list)
 {
@@ -1243,7 +1412,8 @@ int get_config_item(const char *section,
     }
 
     /* Is the collection of a right type */
-    if (!col_is_of_class(ini_config, COL_CLASS_INI_CONFIG)) {
+    if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+        (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) {
         TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
         return EINVAL;
     }
@@ -2054,7 +2224,8 @@ char **get_section_list(struct collection_item *ini_config, int *size, int *erro
     TRACE_FLOW_STRING("get_section_list","Entry");
     /* Do we have the item ? */
     if ((ini_config == NULL) ||
-        !col_is_of_class(ini_config, COL_CLASS_INI_CONFIG)) {
+        ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0))) {
         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
         if (error) *error = EINVAL;
         return NULL;
@@ -2079,7 +2250,8 @@ char **get_attribute_list(struct collection_item *ini_config, const char *sectio
     TRACE_FLOW_STRING("get_attribute_list","Entry");
     /* Do we have the item ? */
     if ((ini_config == NULL) ||
-        !col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) ||
+        ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
+         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) ||
         (section == NULL)) {
         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
         if (error) *error = EINVAL;
diff --git a/common/ini/ini_config.h b/common/ini/ini_config.h
index da8227b55d3125f47ec53506aa386ff0cbe27a72..bd2bdd998d9e948bcbc2f99fc469b8ad6eb5ad32 100644
--- a/common/ini/ini_config.h
+++ b/common/ini/ini_config.h
@@ -180,22 +180,13 @@
  * of such sets.
  */
 #define COL_CLASS_INI_PESET       COL_CLASS_INI_BASE + 3
-/** @brief Collection of grammar errors.
- *
- * Reserved for future use.
- */
-#define COL_CLASS_INI_GERROR      COL_CLASS_INI_BASE + 4
-/** @brief Collection of validation errors.
- *
- * Reserved for future use.
- */
-#define COL_CLASS_INI_VERROR      COL_CLASS_INI_BASE + 5
-/** @brief Collection of lines from the INI file.
+
+/**
+ * @brief Collection of metadata.
  *
- * Reserved for future use
+ * Collection that stores metadata.
  */
-#define COL_CLASS_INI_LINES       COL_CLASS_INI_BASE + 6
-
+#define COL_CLASS_INI_META        COL_CLASS_INI_BASE + 4
 /**
  * @}
  */
@@ -295,44 +286,185 @@ struct parse_error {
  */
 
 /**
- * @defgroup functions Functions
+ * @defgroup metadata Meta data
+ *
+ * Metadata is a collection of a similar structure as any ini file.
+ * The difference is that there are some predefined sections
+ * and attributes inside these sections.
+ * Using meta flags one can specify what section he is interested
+ * in including into the meta data. If a flag for a corresponding
+ * meta data section is specified the data for this section will
+ * be included into the meta data collection. The caller can then
+ * use meta data collection to get items from it and then get
+ * a specific value using a corresponding conversion function.
+ *
+ * Think about the meta data as an INI file that looks like this:
+ *
+ * <b>
+ * [ACCESS]
+ * - uid = <i>\<ini file owner uid\></i>
+ * - gid = <i>\<ini file group gid\></i>
+ * - perm = <i>\<permissions word\></i>
+ * - name = <i>\<file name\></i>
+ * - created = <i>\<time stamp\></i>
+ * - modified = <i>\<time stamp\></i>
+ * - ...
+ *
+ * [ERROR]
+ * - read_error = <i><file open error if any\></i>
+ * - ...
+ *
+ * [<i>TBD</i>]
+ * - ...
+ *
+ * </b>
+ *
+ * The names of the keys and sections provide an example
+ * of how the meta data is structured. Look information
+ * about specific sections and available keys in this manual
+ * to get the exact set of currently supported sections
+ * and keys.
+ *
  * @{
  */
 
-/** @brief Function to return a parsing error as a string.
+/**
+ * @brief Collect only meta data.
  *
- * @param[in] parsing_error    Error code for the parsing error.
+ * Special flag that indicates that only meta data
+ * needs to be collected. No parsing should be performed.
  *
- * @return Error string.
  */
-const char *parsing_error_str(int parsing_error);
+#define INI_META_ACTION_NOPARSE     0x10000000
 
-/** @brief Function to return a grammar error in template.
+/**
+ * @defgroup metasection Meta data section names
  *
- * EXPERIMENTAL. Reserved for future use.
+ * @{
+ */
+
+/**
+ * @brief Meta data section that stores file access information
+ * and ownership.
+ */
+#define INI_META_SEC_ACCESS     "ACCESS"
+
+/**
+ * @brief Meta data "access" section flag to include access section
+ * into the output.
+ */
+#define INI_META_SEC_ACCESS_FLAG     0x00000001
+
+
+/**
+ * @defgroup metaaccesskeys Key names available in the "ACCESS" section
  *
- * This error is returned when the template
- * is translated into the grammar object.
+ * @{
  *
- * @param[in] parsing_error    Error code for the grammar error.
+ */
+
+/**
+ * @brief The value for this key will store user ID of the INI file owner.
+ *
+ */
+#define INI_META_KEY_UID     "uid"
+
+/**
+ * @brief The value for this key will store group ID of the INI file owner.
+ *
+ */
+#define INI_META_KEY_GID     "gid"
+
+/**
+ * @brief The value for this key will store INI file access permissions.
+ *
+ */
+#define INI_META_KEY_PERM     "perm"
+
+/**
+ * @brief The value for this key will store INI file creation time stamp.
+ *
+ */
+#define INI_META_KEY_CREATED     "created"
+
+/**
+ * @brief The value for this key will store INI file modification time stamp.
+ *
+ */
+#define INI_META_KEY_MODIFIED     "modified"
+
+/**
+ * @brief The value for this key will store INI file full name.
  *
- * @return Error string.
  */
-const char *grammar_error_str(int parsing_error);
+#define INI_META_KEY_NAME     "name"
+
+/**
+ * @}
+ */
+
+/**
+ * @brief Meta data section that stores error related information.
+ */
+#define INI_META_SEC_ERROR     "ERROR"
+
+/**
+ * @brief Meta data "error" section flag to include access section
+ * into the output.
+ */
+#define INI_META_SEC_ERROR_FLAG     0x00000002
+
 
-/** @brief Function to return a validation error.
+/**
+ * @defgroup metaerrorkeys Key names available in the "ERROR" section
  *
- * EXPERIMENTAL. Reserved for future use.
+ * @{
  *
- * This is the error that it is returned when
- * the INI file is validated against the
- * grammar object.
+ */
+
+/**
+ * @brief The value for this key will store read error when file was opened.
  *
- * @param[in] parsing_error    Error code for the validation error.
+ * If file was opened by caller first but this section was requested
+ * the value will be zero.
+ */
+#define INI_META_KEY_READ_ERROR     "read_error"
+
+/**
+ * @brief The value for this key will store read error message if any.
+ *
+ * If file was opened by caller first but this section was requested
+ * the key will no be present. Also the key will no exist if no error
+ * occured.
+ */
+#define INI_META_KEY_READ_ERRMSG     "err_msg"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+/**
+ * @defgroup functions Functions
+ * @{
+ */
+
+/** @brief Function to return a parsing error as a string.
+ *
+ * @param[in] parsing_error    Error code for the parsing error.
  *
  * @return Error string.
  */
-const char *validation_error_str(int parsing_error);
+const char *parsing_error_str(int parsing_error);
+
 
 /**
  * @brief Read configuration information from a file.
@@ -397,36 +529,112 @@ int config_from_fd(const char *application,
                    struct collection_item **error_list);
 
 
+
 /**
  * @brief Read configuration information from a file with
- * extra collection of line numbers.
+ * additional meta data.
+ *
+ * Meta data consists of addition information about
+ * the file for example when it was created
+ * or who is the owner. For the detailed description
+ * of the meta data content and structure see
+ * \ref metadata "meta data" section.
+ *
+ * If the metadata argument is not NULL
+ * the calling function MUST always free meta data since it can
+ * be allocated even if the function returned error.
+ *
+ * @param[in]  application         Name of the application,
+ *                                 will be used as name of
+ *                                 the collection.
+ * @param[in]  config_filename     Name of the config file,
+ *                                 if NULL the configuration
+ *                                 collection will be empty.
+ * @param[out] ini_config          If *ini_config is NULL
+ *                                 a new ini object will be
+ *                                 allocated, otherwise
+ *                                 the one that is pointed to
+ *                                 will be updated.
+ * @param[in]  error_level         Break for errors, warnings
+ *                                 or best effort (don't break).
+ * @param[out] error_list          List of errors for the file
+ *                                 detected during parsing.
+ * @param[in]  metaflags           A bit mask of flags that define
+ *                                 what kind of metadata should
+ *                                 be collected.
+ * @param[out] metadata            Collection of metadata
+ *                                 values. See \ref metadata "meta data"
+ *                                 section for more details.
+ *                                 Can be NULL.
+ *
+ * @return 0 - Success.
+ * @return EINVAL - Invalid parameter.
+ * @return Any error returned by fopen().
  *
- * EXPERIMENTAL. Reserved for future use.
  *
  */
-int config_from_file_with_lines(
+int config_from_file_with_metadata(
                      const char *application,
                      const char *config_filename,
                      struct collection_item **ini_config,
                      int error_level,
                      struct collection_item **error_list,
-                     struct collection_item **lines);
+                     uint32_t metaflags,
+                     struct collection_item **metadata);
+
 
 /**
- * @brief Read configuration information from a file descriptor with
- * extra collection of line numbers.
+ * @brief Read configuration information from a file descriptor
+ * with additional meta data.
  *
- * EXPERIMENTAL. Reserved for future use.
+ * Meta data consists of addition information about
+ * the file for example when it was created
+ * or who is the owner. For the detailed description
+ * of the meta data content and structure see
+ * \ref metadata "meta data" section.
+ *
+ * If the metadata argument is not NULL
+ * the calling function MUST always free meta data since it can
+ * be allocated even if the function returned error.
+ *
+ * @param[in]  application         Name of the application,
+ *                                 will be used as name of
+ *                                 the collection.
+ * @param[in]  fd                  Previously opened file
+ *                                 descriptor for the config file.
+ * @param[in]  config_source       Name of the file being parsed,
+ *                                 for use when printing the error
+ *                                 list.
+ * @param[out] ini_config          If *ini_config is NULL
+ *                                 a new ini object will be
+ *                                 allocated, otherwise
+ *                                 the one that is pointed to
+ *                                 will be updated.
+ * @param[in]  error_level         Break for errors, warnings
+ *                                 or best effort (don't break).
+ * @param[out] error_list          List of errors for the file
+ *                                 detected during parsing.
+ * @param[in]  metaflags           A bit mask of flags that define
+ *                                 what kind of metadata should
+ *                                 be collected.
+ * @param[out] metadata            Collection of metadata
+ *                                 values. See \ref metadata "meta data"
+ *                                 section for more details.
+ *                                 Can be NULL.
+ *
+ * @return 0 - Success.
+ * @return EINVAL - Invalid parameter.
  *
  */
-int config_from_fd_with_lines(
+int config_from_fd_with_metadata(
                    const char *application,
                    int fd,
                    const char *config_source,
                    struct collection_item **ini_config,
                    int error_level,
                    struct collection_item **error_list,
-                   struct collection_item **lines);
+                   uint32_t metaflags,
+                   struct collection_item **metadata);
 
 
 /**
@@ -443,7 +651,7 @@ int config_from_fd_with_lines(
  *                                 the configuration files for
  *                                 different applications reside.
  *                                 Function will look for file
- *                                 with the name name constructed by
+ *                                 with the name constructed by
  *                                 appending ".ini" to the end of
  *                                 the "application" argument.
  * @param[out] ini_config          A new configuration object.
@@ -464,6 +672,64 @@ int config_for_app(const char *application,
                    struct collection_item **error_set);
 
 /**
+ * @brief Read default configuration file and then
+ * overwrite it with a specific one from the directory.
+ *
+ * If requested collect meta data for both.
+ *
+ * If the metadata argument is not NULL
+ * the calling function MUST always free meta data since it can
+ * be allocated even if the function returned error.
+ *
+ * @param[in]  application         Name of the application,
+ *                                 will be used as name of
+ *                                 the collection.
+ * @param[in]  config_file         Name of the configuration file,
+ *                                 with default settings for all
+ *                                 appplications.
+ * @param[in]  config_dir          Name of the directory where
+ *                                 the configuration files for
+ *                                 different applications reside.
+ *                                 Function will look for file
+ *                                 with the name constructed by
+ *                                 appending ".ini" to the end of
+ *                                 the "application" argument.
+ * @param[out] ini_config          A new configuration object.
+ * @param[in]  error_level         Break for errors, warnings
+ *                                 or best effort (don't break).
+ * @param[out] error_set           Collection of error lists.
+ *                                 One list per file.
+ * @param[in]  metaflags           A bit mask of flags that define
+ *                                 what kind of metadata should
+ *                                 be collected.
+ * @param[out] meta_default        Collection of metadata
+ *                                 values for the default common
+ *                                 config file for all applications.
+ *                                 See \ref metadata "meta data"
+ *                                 section for more details.
+ *                                 Can be NULL.
+ * @param[out] meta_appini         Collection of metadata
+ *                                 values for the application
+ *                                 specific config file.
+ *                                 See \ref metadata "meta data"
+ *                                 section for more details.
+ *                                 Can be NULL.
+ *
+ * @return 0 - Success.
+ * @return EINVAL - Invalid parameter.
+ * @return Any error returned by fopen().
+ */
+int config_for_app_with_metadata(
+                   const char *application,
+                   const char *config_file,
+                   const char *config_dir,
+                   struct collection_item **ini_config,
+                   int error_level,
+                   struct collection_item **error_set,
+                   uint32_t metaflags,
+                   struct collection_item **meta_default,
+                   struct collection_item **meta_appini);
+/**
  * @brief Function to free configuration object.
  *
  * @param[in] ini_config       Configuration object.
@@ -479,16 +745,14 @@ void free_ini_config(struct collection_item *ini_config);
  */
 void free_ini_config_errors(struct collection_item *error_set);
 
+
 /**
- * @brief Function to free lines object.
- *
- * EXPERIMENTAL. Reserved for future use.
+ * @brief Function to free metadata.
  *
- * @param[in] lines       Lines object.
+ * @param[in] error_set       Configuration meta data object.
  *
  */
-void free_ini_config_lines(struct collection_item *lines);
-
+void free_ini_config_metadata(struct collection_item *metadata);
 
 
 /**
@@ -501,34 +765,6 @@ void free_ini_config_lines(struct collection_item *lines);
 void print_file_parsing_errors(FILE *file,
                                struct collection_item *error_list);
 
-/**
- * @brief Print errors and warnings that were detected while
- * checking grammar of the template.
- *
- * EXPERIMENTAL. Reserved for future use.
- *
- * @param[in] file           File descriptor.
- * @param[in] error_list     List of the parsing errors.
- *
- */
-void print_grammar_errors(FILE *file,
-                          struct collection_item *error_list);
-
-/**
- * @brief Print errors and warnings that were detected while
- * checking INI file against the grammar object.
- *
- * EXPERIMENTAL. Reserved for future use.
- *
- * @param[in] file           File descriptor.
- * @param[in] error_list     List of the parsing errors.
- *
- */
-void print_validation_errors(FILE *file,
-                             struct collection_item *error_list);
-
-
-
 
 /**
  * @brief Print errors and warnings that were detected
diff --git a/common/ini/ini_config_ut.c b/common/ini/ini_config_ut.c
index 1c82a0579252df3b7c7ed950d0ab27d069730ee5..dde1c52cce87f62a1b7e41d51f55cc03fe3a1d65 100644
--- a/common/ini/ini_config_ut.c
+++ b/common/ini/ini_config_ut.c
@@ -87,7 +87,8 @@ int single_file(void)
     int error;
     struct collection_item *ini_config = NULL;
     struct collection_item *error_set = NULL;
-    struct collection_item *lines = NULL;
+    struct collection_item *metadata = NULL;
+    uint32_t flags;
 
     error = config_from_file("test", "./not_exist_ini.conf",
                              &ini_config, INI_STOP_ON_NONE, &error_set);
@@ -123,18 +124,54 @@ int single_file(void)
     ini_config = NULL;
     error_set = NULL;
 
-    COLOUT(printf("TEST WITH LINES\n"));
+    COLOUT(printf("TEST WITH METADATA NO PARSE\n"));
+    flags = INI_META_SEC_ACCESS_FLAG |
+            INI_META_SEC_ERROR_FLAG  |
+            INI_META_ACTION_NOPARSE;
 
-    error = config_from_file_with_lines("test", "./ini.conf",
-                                        &ini_config, INI_STOP_ON_NONE,
-                                        &error_set, &lines);
+    error = config_from_file_with_metadata("test", "./ini.conf",
+                                           &ini_config, INI_STOP_ON_NONE,
+                                           NULL,
+                                           flags,
+                                           &metadata);
     if (error) {
         printf("Attempt to read configuration returned error: %d\n",error);
+        printf("\n\nMetadata\n");
+        col_debug_collection(metadata, COL_TRAVERSE_DEFAULT);
+        free_ini_config_metadata(metadata);
         return error;
     }
 
+    if (ini_config) {
+        printf("Expected no config but got some.\n");
+        col_debug_collection(ini_config, COL_TRAVERSE_DEFAULT);
+        free_ini_config(ini_config);
+        printf("\n\nMetadata\n");
+        col_debug_collection(metadata, COL_TRAVERSE_DEFAULT);
+        free_ini_config_metadata(metadata);
+        return EINVAL;
+    }
+
+    COLOUT(printf("\n\nMeta data\n"));
+    COLOUT(col_debug_collection(metadata, COL_TRAVERSE_DEFAULT));
+    free_ini_config_metadata(metadata);
+
+    COLOUT(printf("\n\n----------------------\n"));
+
+    error = config_from_file_with_metadata("test", "./ini.conf",
+                                           &ini_config, INI_STOP_ON_NONE,
+                                           &error_set,
+                                           0,
+                                           NULL);
+    if (error) {
+        printf("Attempt to read configuration returned error: %d\n",error);
+        print_file_parsing_errors(stdout, error_set);
+        free_ini_config_errors(error_set);
+        return error;
+    }
+
+    COLOUT(printf("\n\n----------------------\n"));
     COLOUT(col_debug_collection(ini_config, COL_TRAVERSE_DEFAULT));
-    COLOUT(col_debug_collection(lines, COL_TRAVERSE_DEFAULT));
 
     COLOUT(printf("\n\n----------------------\n"));
     /* Output parsing errors (if any) */
@@ -144,7 +181,6 @@ int single_file(void)
 
     free_ini_config(ini_config);
     free_ini_config_errors(error_set);
-    free_ini_config_lines(lines);
 
     return 0;
 }
@@ -154,7 +190,8 @@ int single_fd(void)
     int error;
     struct collection_item *ini_config = NULL;
     struct collection_item *error_set = NULL;
-    struct collection_item *lines = NULL;
+    struct collection_item *metadata = NULL;
+    uint32_t flags;
 
     int fd = open("./ini.conf", O_RDONLY);
     if (fd < 0) {
@@ -187,7 +224,7 @@ int single_fd(void)
     ini_config = NULL;
     error_set = NULL;
 
-    COLOUT(printf("TEST WITH LINES\n"));
+    COLOUT(printf("TEST WITH FILE FD & META DATA\n"));
 
     fd = open("./ini.conf", O_RDONLY);
     if (fd < 0) {
@@ -195,18 +232,63 @@ int single_fd(void)
         printf("Attempt to read configuration returned error: %d\n", error);
         return error;
     }
-    error = config_from_fd_with_lines("test", fd,
-                                      "./ini.conf",
-                                      &ini_config,
-                                      INI_STOP_ON_NONE,
-                                      &error_set, &lines);
+
+    flags = INI_META_SEC_ACCESS_FLAG |
+            INI_META_SEC_ERROR_FLAG  |
+            INI_META_ACTION_NOPARSE;
+
+    error = config_from_fd_with_metadata("test", fd,
+                                         "./ini.conf",
+                                         &ini_config,
+                                         INI_STOP_ON_NONE,
+                                         &error_set,
+                                         flags,
+                                         &metadata);
+    if (error) {
+        printf("Attempt to read configuration returned error: %d\n",error);
+        printf("\n\nErrors\n");
+        print_file_parsing_errors(stdout, error_set);
+        free_ini_config_errors(error_set);
+        printf("\n\nMetadata\n");
+        col_debug_collection(metadata, COL_TRAVERSE_DEFAULT);
+        free_ini_config_metadata(metadata);
+        return error;
+    }
+
+    if (ini_config) {
+        printf("Expected no config but got some.\n");
+        col_debug_collection(ini_config, COL_TRAVERSE_DEFAULT);
+        free_ini_config(ini_config);
+        return EINVAL;
+    }
+
+    /* FIXME get elements of the meta data and check them */
+
+
+    COLOUT(printf("\n\nMeta data\n"));
+    COLOUT(col_debug_collection(metadata, COL_TRAVERSE_DEFAULT));
+    free_ini_config_metadata(metadata);
+
+
+    error = config_from_fd_with_metadata("test", fd,
+                                         "./ini.conf",
+                                         &ini_config,
+                                         INI_STOP_ON_NONE,
+                                         &error_set,
+                                         0,
+                                         NULL);
+
+    close(fd);
+
     if (error) {
         printf("Attempt to read configuration returned error: %d\n",error);
+        printf("\n\nErrors\n");
+        print_file_parsing_errors(stdout, error_set);
+        free_ini_config_errors(error_set);
         return error;
     }
 
     COLOUT(col_debug_collection(ini_config, COL_TRAVERSE_DEFAULT));
-    COLOUT(col_debug_collection(lines, COL_TRAVERSE_DEFAULT));
 
     COLOUT(printf("\n\n----------------------\n"));
     /* Output parsing errors (if any) */
@@ -216,7 +298,6 @@ int single_fd(void)
 
     free_ini_config(ini_config);
     free_ini_config_errors(error_set);
-    free_ini_config_lines(lines);
 
     return 0;
 }
diff --git a/common/ini/ini_metadata.c b/common/ini/ini_metadata.c
new file mode 100644
index 0000000000000000000000000000000000000000..630de699b9726cb5e285fb33fb8aff7c8640d46c
--- /dev/null
+++ b/common/ini/ini_metadata.c
@@ -0,0 +1,104 @@
+/*
+    INI LIBRARY
+
+    Functions to process metadata.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include "config.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "trace.h"
+#include "ini_config.h"
+#include "ini_metadata.h"
+
+#define INI_METADATA    "meta"
+
+/* Prepare metadata */
+int prepare_metadata(uint32_t metaflags,
+                     struct collection_item **metadata,
+                     int *save_error)
+{
+    int error = EOK;
+    struct collection_item *metasec = NULL;
+
+    TRACE_FLOW_STRING("prepare_metadata", "Entry");
+
+    /* Are we supposed to collect or process meta data ? */
+    if (!metadata) {
+        TRACE_FLOW_STRING("No meta data", "Exit");
+        return EOK;
+    }
+
+    /* Allocate metadata */
+    error = col_create_collection(metadata,
+                                  INI_METADATA,
+                                  COL_CLASS_INI_META);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to create meta data", error);
+        return error;
+    }
+
+    /* Check and create section for file error if needed */
+    if (metaflags & INI_META_SEC_ERROR_FLAG) {
+        /* Create ERROR collection */
+        if ((error = col_create_collection(&metasec,
+                                           INI_META_SEC_ERROR,
+                                           COL_CLASS_INI_SECTION)) ||
+            (error = col_add_collection_to_collection(
+                                           *metadata,
+                                           NULL,
+                                           NULL,
+                                           metasec,
+                                           COL_ADD_MODE_REFERENCE))) {
+            TRACE_ERROR_NUMBER("Failed to create error section", error);
+            col_destroy_collection(metasec);
+            col_destroy_collection(*metadata);
+            return error;
+        }
+        /* If we are here we would have to save file open error */
+        *save_error = 1;
+        col_destroy_collection(metasec);
+    }
+
+    TRACE_FLOW_STRING("prepare_metadata", "Exit");
+    return error;
+}
+
+
+
+/* Collect metadata for the file */
+int collect_metadata(uint32_t metaflags,
+                     struct collection_item **metadata,
+                     FILE *config_file)
+{
+    int error = EOK;
+
+    TRACE_FLOW_STRING("collect_metadata", "Entry");
+
+    TRACE_FLOW_STRING("collect_metadata", "Exit");
+    return error;
+}
+
+/* Function to free metadata */
+void free_ini_config_metadata(struct collection_item *metadata)
+{
+    TRACE_FLOW_STRING("free_ini_config_metadata", "Entry");
+    col_destroy_collection(metadata);
+    TRACE_FLOW_STRING("free_ini_config_metadata", "Exit");
+}
diff --git a/common/ini/ini_metadata.h b/common/ini/ini_metadata.h
new file mode 100644
index 0000000000000000000000000000000000000000..2839453a66b35b286636ebdd2bf39f5358556623
--- /dev/null
+++ b/common/ini/ini_metadata.h
@@ -0,0 +1,42 @@
+/*
+    INI LIBRARY
+
+    Header file for the meta data related functions.
+
+    Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+    INI Library is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    INI Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INI_METADATA_H
+#define INI_METADATA_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include "collection.h"
+
+
+/* Prepare metadata */
+int prepare_metadata(uint32_t metaflags,
+                     struct collection_item **metadata,
+                     int *save_error);
+
+/* Collect metadata for the file */
+int collect_metadata(uint32_t metaflags,
+                     struct collection_item **metadata,
+                     FILE *config_file);
+
+
+
+#endif
-- 
1.5.5.6

