From 19b0379167133ad8c37da3152fafbf92152140d4 Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Fri, 23 Jul 2010 14:33:56 -0400
Subject: [PATCH] [COLLECTION] Allow destroying collection with a callback

Addresses ticket #572
Bumps the library and interface version.
Updates the docs.

[COLLECTION] Changed callback signature
---
 common/collection/Makefile.am        |    2 +-
 common/collection/collection.c       |   57 +++++++++++++++++++++++++-----
 common/collection/collection.h       |   63 +++++++++++++++++++++++++++++++---
 common/collection/collection_queue.h |    3 ++
 common/collection/collection_stack.h |    3 ++
 common/collection/collection_tools.h |    4 ++
 common/collection/collection_ut.c    |   18 +++++++++-
 common/collection/configure.ac       |    2 +-
 contrib/sssd.spec.in                 |   34 +++++++++---------
 9 files changed, 151 insertions(+), 35 deletions(-)

diff --git a/common/collection/Makefile.am b/common/collection/Makefile.am
index 4e90aed12a2ff877fdeaa80b58de556ff2ed4706..caffcabae9f62234400398eb318f1e454615e80b 100644
--- a/common/collection/Makefile.am
+++ b/common/collection/Makefile.am
@@ -41,7 +41,7 @@ libcollection_la_SOURCES = \
     collection_priv.h \
     ../trace/trace.h
 libcollection_la_LDFLAGS = \
-    -version-info 2:0:0
+    -version-info 3:0:0
 
 # Build unit test
 check_PROGRAMS = collection_ut collection_stack_ut collection_queue_ut
diff --git a/common/collection/collection.c b/common/collection/collection.c
index 87ac32124f24ac91d64bcc841bf7b1971217fc72..f24102b1b62a6484b0640ac19e54ac79a1fd0f4f 100644
--- a/common/collection/collection.c
+++ b/common/collection/collection.c
@@ -172,8 +172,11 @@ static int col_validate_property(const char *property)
     return invalid;
 }
 
-/* Function that cleans the item */
-void col_delete_item(struct collection_item *item)
+
+/* Function that cleans the item with callback */
+static void col_delete_item_with_cb(struct collection_item *item,
+                                    col_item_cleanup_fn cb,
+                                    void *custom_data)
 {
     struct collection_item *other_collection;
 
@@ -189,9 +192,17 @@ void col_delete_item(struct collection_item *item)
         /* Our data is a pointer to a whole external collection so dereference
          * it or delete */
         other_collection = *((struct collection_item **)(item->data));
-        col_destroy_collection(other_collection);
+        col_destroy_collection_with_cb(other_collection, cb, custom_data);
     }
 
+    /* Call the callback */
+    if (cb) cb(item->property,
+               item->property_len,
+               item->type,
+               item->data,
+               item->length,
+               custom_data);
+
     TRACE_INFO_STRING("Deleting property:", item->property);
     TRACE_INFO_NUMBER("Type:", item->type);
 
@@ -203,6 +214,18 @@ void col_delete_item(struct collection_item *item)
     TRACE_FLOW_STRING("col_delete_item","Exit.");
 }
 
+/* Function that cleans the item */
+void col_delete_item(struct collection_item *item)
+{
+    TRACE_FLOW_STRING("col_delete_item","Entry point.");
+
+    col_delete_item_with_cb(item, NULL, NULL);
+
+    TRACE_FLOW_STRING("col_delete_item","Exit.");
+}
+
+
+
 /* A generic function to allocate a property item */
 int col_allocate_item(struct collection_item **ci, const char *property,
                       const void *item_data, int length, int type)
@@ -1164,7 +1187,9 @@ static int col_get_subcollection(const char *property,
 /* Cleans the collection tree including current item. */
 /* The passed in variable should not be used after the call
  * as memory is freed!!! */
-static void col_delete_collection(struct collection_item *ci)
+static void col_delete_collection(struct collection_item *ci,
+                                  col_item_cleanup_fn cb,
+                                  void *custom_data)
 {
     TRACE_FLOW_STRING("col_delete_collection", "Entry.");
 
@@ -1177,10 +1202,10 @@ static void col_delete_collection(struct collection_item *ci)
     TRACE_INFO_STRING("Property", ci->property);
     TRACE_INFO_NUMBER("Next item", ci->next);
 
-    col_delete_collection(ci->next);
+    col_delete_collection(ci->next, cb, custom_data);
 
     /* Delete this item */
-    col_delete_item(ci);
+    col_delete_item_with_cb(ci, cb, custom_data);
     TRACE_FLOW_STRING("col_delete_collection", "Exit.");
 }
 
@@ -2235,11 +2260,13 @@ int col_create_collection(struct collection_item **ci, const char *name,
 /* DESTROY */
 
 /* Function that destroys a collection */
-void col_destroy_collection(struct collection_item *ci)
+void col_destroy_collection_with_cb(struct collection_item *ci,
+                                    col_item_cleanup_fn cb,
+                                    void *custom_data)
 {
     struct collection_header *header;
 
-    TRACE_FLOW_STRING("col_destroy_collection", "Entry.");
+    TRACE_FLOW_STRING("col_destroy_collection_with_cb", "Entry.");
 
     /* Do not try to delete NULL */
     if (ci == NULL) return;
@@ -2263,13 +2290,23 @@ void col_destroy_collection(struct collection_item *ci)
                           header->reference_count);
     }
     else {
-        col_delete_collection(ci);
+        col_delete_collection(ci, cb, custom_data);
     }
 
-    TRACE_FLOW_STRING("col_destroy_collection", "Exit.");
+    TRACE_FLOW_STRING("col_destroy_collection_with_cb", "Exit.");
 }
 
 
+/* Function that destroys a collection */
+void col_destroy_collection(struct collection_item *ci)
+{
+    TRACE_FLOW_STRING("col_destroy_collection", "Entry.");
+
+    col_destroy_collection_with_cb(ci, NULL, NULL);
+
+    TRACE_FLOW_STRING("col_destroy_collection", "Exit.");
+}
+
 /* COPY */
 
 /* Wrapper around a more advanced function */
diff --git a/common/collection/collection.h b/common/collection/collection.h
index b656ebb344cebf9fb6ed5bb189dafc0fb7d10cbe..2ec81bdb68ae4b67e2bbca1a0e0fbd0202fefb1e 100644
--- a/common/collection/collection.h
+++ b/common/collection/collection.h
@@ -484,6 +484,60 @@ int col_create_collection(struct collection_item **ci,
 void col_destroy_collection(struct collection_item *ci);
 
 /**
+ * @brief Cleanup Callback
+ *
+ * Signature of the callback that needs to be used when
+ * the collection is destroyed and a special cleanup operation
+ * is required for items in the collection.
+ *
+ * @param[in]  property      The name of the property will
+ *                           be passed in this parameter.
+ * @param[in]  property_len  Length of the property name
+ *                           will be passed in this parameter.
+ * @param[in]  type          Type of the data will be passed
+ *                           in this parameter.
+ * @param[in]  data          Pointer to the data will be passed
+ *                           in this parameter.
+ * @param[in]  length        Length of data will be passed in
+ *                           this parameter.
+ * @param[in]  custom_data   Custom data will be passed in
+ *                           this parameter.
+ * @return No return value.
+ */
+
+typedef void (*col_item_cleanup_fn)(const char *property,
+                                    int property_len,
+                                    int type,
+                                    void *data,
+                                    int length,
+                                    void *custom_data);
+
+/**
+ * @brief Destroy a collection with callback
+ *
+ * Execute a provided callback for each item
+ * in the collection or subcollection immediately
+ * before freeing item. The callback is executed for each
+ * element including the collection header.
+ * It is the responsibility of the callback implementor
+ * to properly handle gifferent collection elements
+ * depending upon whether it is a header, reference to
+ * an embedded or external collection or a normal data
+ * element.
+ *
+ * The function will destroy a collection.
+ *
+ * @param[in] ci              Collection object.
+ * @param[in] cb              Cleanup callback.
+ * @param[in] custom_data     Application data passed into
+ *                            the cleanup callback.
+ *
+ */
+void col_destroy_collection_with_cb(struct collection_item *ci,
+                                    col_item_cleanup_fn cb,
+                                    void *custom_data);
+
+/**
  * @brief Copy item callback.
  *
  * Callback is used by the
@@ -618,7 +672,7 @@ int col_add_collection_to_collection(struct collection_item *ci,
  *                           in this parameter.
  * @param[in]  length        Length of data will be passed in
  *                           this parameter.
- * @param[in]  custom_dat    Custom data will be passed in
+ * @param[in]  custom_data   Custom data will be passed in
  *                           this parameter.
  * @param[out] stop          Pointer to a variable where the handler
  *                           can put nonzero to stop traversing
@@ -633,10 +687,9 @@ typedef int (*col_item_fn)(const char *property,
                            int type,
                            void *data,
                            int length,
-                           void *custom_dat,
+                           void *custom_data,
                            int *stop);
 
-
 /**
  * @brief Traverse collection
  *
@@ -2366,9 +2419,9 @@ int col_get_item_type(struct collection_item *ci);
 int col_get_item_length(struct collection_item *ci);
 
 /**
- * @brief Get property value from the item.
+ * @brief Get value from the item.
  *
- * Get property value from the item.
+ * Get value from the item.
  *
  * @param[in]  ci               Item to get value from.
  *                              If item is invalid the function
diff --git a/common/collection/collection_queue.h b/common/collection/collection_queue.h
index 86c392523d0fe36781fdce0c17d6cda88c878468..21350bec67757879fbf73291103cf021979bbfa8 100644
--- a/common/collection/collection_queue.h
+++ b/common/collection/collection_queue.h
@@ -319,5 +319,8 @@ int col_enqueue_item(struct collection_item *queue,
 int col_dequeue_item(struct collection_item *queue,
                      struct collection_item **item);
 
+/**
+ * @}
+ */
 
 #endif
diff --git a/common/collection/collection_stack.h b/common/collection/collection_stack.h
index f9b01309fce8cb19b16083fcabe855521a6ced34..1a7c4709508c2faeeef482d98257ad118627e371 100644
--- a/common/collection/collection_stack.h
+++ b/common/collection/collection_stack.h
@@ -322,4 +322,7 @@ int col_push_item(struct collection_item *stack,
 int col_pop_item(struct collection_item *stack,
                  struct collection_item **item);
 
+/**
+ * @}
+ */
 #endif
diff --git a/common/collection/collection_tools.h b/common/collection/collection_tools.h
index eec91caff073003be4fad8c8efd7f4f832ba6305..586eef103fea286af9bbf9d2a4c75f87c89740d6 100644
--- a/common/collection/collection_tools.h
+++ b/common/collection/collection_tools.h
@@ -265,4 +265,8 @@ char **col_collection_to_list(struct collection_item *handle,
  */
 void col_free_property_list(char **str_list);
 
+/**
+ * @}
+ */
+
 #endif
diff --git a/common/collection/collection_ut.c b/common/collection/collection_ut.c
index 92d9d0c47f9cef8133621fd3b5c3bc8edc12f603..2e4ead5d48387dd87128a4da9a054fa60e0820a6 100644
--- a/common/collection/collection_ut.c
+++ b/common/collection/collection_ut.c
@@ -1497,11 +1497,27 @@ int insert_extract_test(void)
     return EOK;
 }
 
+/* Cleanup collback */
+void cb(const char *property,
+        int property_len,
+        int type,
+        void *data,
+        int length,
+        void *ext_data)
+{
+    COLOUT(printf("%s\n", *((const char **)ext_data)));
+    COLOUT(printf("Property: %s\n", property));
+    COLOUT(printf("Length: %d\n", property_len));
+    COLOUT(printf("Type: %d\n", type));
+    COLOUT(printf("Data len: %d\n", length));
+}
+
 int delete_test(void)
 {
 
     struct collection_item *col;
     int error = EOK;
+    const char *str = "Cleanup Callback Test";
 
     COLOUT(printf("\n\n==== DELETION TEST 1====\n\n"));
 
@@ -1550,7 +1566,7 @@ int delete_test(void)
     COLOUT(printf("\n\n==== DELETION TEST 2 END ====\n\n"));
 
 
-    col_destroy_collection(col);
+    col_destroy_collection_with_cb(col, cb, (void *)(&str));
 
     return error;
 }
diff --git a/common/collection/configure.ac b/common/collection/configure.ac
index 02c0ab4c30820d8dbfeae9eb83a88ffc5627bacc..a064951adfd60fd1b1623335822eb539ae435cc4 100644
--- a/common/collection/configure.ac
+++ b/common/collection/configure.ac
@@ -1,5 +1,5 @@
 AC_INIT([collection],
-        [0.5.0],
+        [0.6.0],
         [sssd-devel@lists.fedorahosted.org])
 AC_CONFIG_SRCDIR([collection.c])
 AC_CONFIG_AUX_DIR([build])
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 8f5e1df8589c3fc99890b64a60c26a62623f9a30..833d68a337585637c8858dfeb710861e4306cf5e 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -13,11 +13,11 @@ URL: http://fedorahosted.org/sssd/
 Source0: %{name}-%{version}.tar.gz
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
-%global dhash_version 0.4.0
-%global path_utils_version 0.2.0
-%global collection_version 0.5.0
-%global ini_config_version 0.6.0
-%global refarray_version 0.1.0
+%define dhash_version 0.4.0
+%define path_utils_version 0.2.0
+%define collection_version 0.6.0
+%define ini_config_version 0.5.0
+%define refarray_version 0.1.0
 
 ### Patches ###
 
@@ -26,20 +26,20 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 Requires: libldb >= 0.9.3
 Requires: libtdb >= 1.1.3
 Requires: sssd-client = %{version}-%{release}
-Requires: libdhash >= %{dhash_version}
-Requires: libcollection >= %{collection_version}
-Requires: libini_config >= %{ini_config_version}
+Requires: libdhash = %{dhash_version}-%{release}
+Requires: libcollection = %{collection_version}-%{release}
+Requires: libini_config = %{ini_config_version}-%{release}
 Requires: cyrus-sasl-gssapi
 Requires: keyutils-libs
 Requires(post): python
 Requires(preun):  initscripts chkconfig
 Requires(postun): /sbin/service
 
-%global servicename sssd
-%global sssdstatedir %{_localstatedir}/lib/sss
-%global dbpath %{sssdstatedir}/db
-%global pipepath %{sssdstatedir}/pipes
-%global pubconfpath %{sssdstatedir}/pubconf
+%define servicename sssd
+%define sssdstatedir %{_localstatedir}/lib/sss
+%define dbpath %{sssdstatedir}/db
+%define pipepath %{sssdstatedir}/pipes
+%define pubconfpath %{sssdstatedir}/pubconf
 
 ### Build Dependencies ###
 
@@ -77,7 +77,7 @@ BuildRequires: libselinux-devel
 BuildRequires: libsemanage-devel
 BuildRequires: bind-utils
 BuildRequires: keyutils-libs-devel
-BuildRequires: libnl-devel
+
 
 %description
 Provides a set of daemons to manage access to remote directories and
@@ -160,7 +160,7 @@ and serialization
 Summary: INI file parser for C
 Group: Development/Libraries
 Version: %{ini_config_version}
-Requires: libcollection >= %{collection_version}
+Requires: libcollection = %{collection_version}-%{release}
 License: LGPLv3+
 
 %description -n libini_config
@@ -368,8 +368,8 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(-,root,root,-)
 %doc common/collection/COPYING
 %doc common/collection/COPYING.LESSER
-%{_libdir}/libcollection.so.2
-%{_libdir}/libcollection.so.2.0.0
+%{_libdir}/libcollection.so.3
+%{_libdir}/libcollection.so.3.0.0
 
 %files -n libcollection-devel
 %defattr(-,root,root,-)
-- 
1.5.5.6

