LCOV - code coverage report
Current view: top level - collection - collection.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 797 936 85.1 %
Date: 2014-04-01 Functions: 51 52 98.1 %

          Line data    Source code
       1             : /*
       2             :     COLLECTION LIBRARY
       3             : 
       4             :     Implementation of the collection library interface.
       5             : 
       6             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
       7             : 
       8             :     Collection Library is free software: you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation, either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     Collection Library is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU Lesser General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU Lesser General Public License
      19             :     along with Collection Library.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : #include <string.h>
      24             : #include <stdlib.h>
      25             : #include <errno.h>
      26             : #include <ctype.h>
      27             : #include <time.h>
      28             : #include "trace.h"
      29             : 
      30             : /* The collection should use the real structures */
      31             : #include "collection_priv.h"
      32             : #include "collection.h"
      33             : 
      34             : 
      35             : /* Internal constants defined to denote actions that can be performed by find handler */
      36             : #define COLLECTION_ACTION_FIND       1
      37             : #define COLLECTION_ACTION_DEL        2
      38             : #define COLLECTION_ACTION_UPDATE     3
      39             : #define COLLECTION_ACTION_GET        4
      40             : 
      41             : 
      42             : /* Special internal error code to indicate that collection search was interrupted */
      43             : #define EINTR_INTERNAL 10000
      44             : 
      45             : 
      46             : /* Potential subject for management with libtools */
      47             : #define DATE_FORMAT "%c"
      48             : 
      49             : #define TIME_ARRAY_SIZE 100
      50             : 
      51             : /* Magic numbers for hashing */
      52             : #if SIZEOF_LONG == 8
      53             :     #define FNV1a_prime 1099511628211ul
      54             :     #define FNV1a_base 14695981039346656037ul
      55             : #elif SIZEOF_LONG_LONG == 8
      56             :     #define FNV1a_prime 1099511628211ull
      57             :     #define FNV1a_base 14695981039346656037ull
      58             : #else
      59             :     #error "Platform cannot support 64-bit constant integers"
      60             : #endif
      61             : 
      62             : /* Struct used for passing parameter for update operation */
      63             : struct update_property {
      64             :         int type;
      65             :         void *data;
      66             :         int length;
      67             :         int found;
      68             : };
      69             : 
      70             : /* This struct is used to construct path
      71             :  * to an item in the collection (tree)
      72             :  */
      73             : struct path_data {
      74             :     char *name;
      75             :     int length;
      76             :     struct path_data *previous_path;
      77             : };
      78             : 
      79             : /* Structure to keep data needed to
      80             :  * copy collection
      81             :  * while traversing it
      82             :  */
      83             : struct col_copy {
      84             :     int mode;
      85             :     struct path_data *current_path;
      86             :     char *given_name;
      87             :     int given_len;
      88             :     col_copy_cb copy_cb;
      89             :     void *ext_data;
      90             : };
      91             : 
      92             : /******************** FUNCTION DECLARATIONS ****************************/
      93             : 
      94             : /* Have to declare those due to function cross referencing */
      95             : static int col_find_item_and_do(struct collection_item *ci,
      96             :                                 const char *property_to_find,
      97             :                                 int type,
      98             :                                 int mode_flags,
      99             :                                 col_item_fn item_handler,
     100             :                                 void *custom_data,
     101             :                                 int action);
     102             : 
     103             : /* Traverse callback for find & delete function */
     104             : static int col_act_traverse_handler(struct collection_item *head,
     105             :                                     struct collection_item *previous,
     106             :                                     struct collection_item *current,
     107             :                                     void *passed_traverse_data,
     108             :                                     col_item_fn user_item_handler,
     109             :                                     void *custom_data,
     110             :                                     int *stop);
     111             : 
     112             : /* Traverse handler to find parent of the item */
     113             : static int col_parent_traverse_handler(struct collection_item *head,
     114             :                                        struct collection_item *previous,
     115             :                                        struct collection_item *current,
     116             :                                        void *traverse_data,
     117             :                                        col_item_fn user_item_handler,
     118             :                                        void *custom_data,
     119             :                                        int *stop);
     120             : 
     121             : /* Traverse callback signature */
     122             : typedef int (*internal_item_fn)(struct collection_item *head,
     123             :                                 struct collection_item *previous,
     124             :                                 struct collection_item *current,
     125             :                                 void *traverse_data,
     126             :                                 col_item_fn user_item_handler,
     127             :                                 void *custom_data,
     128             :                                 int *stop);
     129             : /* Function to walk_items */
     130             : static int col_walk_items(struct collection_item *ci,
     131             :                           int mode_flags,
     132             :                           internal_item_fn traverse_handler,
     133             :                           void *traverse_data,
     134             :                           col_item_fn user_item_handler,
     135             :                           void *custom_data,
     136             :                           unsigned *depth);
     137             : 
     138             : /* Function to get sub collection */
     139             : static int col_get_subcollection(const char *property,
     140             :                                   int property_len,
     141             :                                   int type,
     142             :                                   void *data,
     143             :                                   int length,
     144             :                                   void *found,
     145             :                                   int *dummy);
     146             : 
     147             : /* Function to destroy collection */
     148             : void col_destroy_collection(struct collection_item *ci);
     149             : 
     150             : /******************** SUPPLEMENTARY FUNCTIONS ****************************/
     151             : /* BASIC OPERATIONS */
     152             : 
     153             : /* Function that checks if property can be added */
     154      637698 : static int col_validate_property(const char *property)
     155             : {
     156             :     TRACE_FLOW_STRING("col_validate_property", "Entry point.");
     157             :     /* Only alpha numeric characters are allowed in names of the properties */
     158      637698 :     int invalid = 0;
     159             :     const char *check;
     160             : 
     161      637698 :     check = property;
     162     7981938 :     while (*check != '\0') {
     163             :         /* It turned out that limiting collection charcters is bad */
     164     6706543 :         if ((*check < ' ') || (*check == '!')) {
     165           1 :             invalid = 1;
     166           1 :             break;
     167             :         }
     168     6706542 :         check++;
     169             :     }
     170             :     TRACE_FLOW_NUMBER("col_validate_property. Returning ", invalid);
     171      637698 :     return invalid;
     172             : }
     173             : 
     174             : 
     175             : /* Function that cleans the item with callback */
     176      637683 : static void col_delete_item_with_cb(struct collection_item *item,
     177             :                                     col_item_cleanup_fn cb,
     178             :                                     void *custom_data)
     179             : {
     180             :     struct collection_item *other_collection;
     181             : 
     182             :     TRACE_FLOW_STRING("col_delete_item","Entry point.");
     183             : 
     184      637683 :     if (item == NULL) {
     185             :         TRACE_FLOW_STRING("col_delete_item","Nothing to delete!");
     186      637683 :         return;
     187             :     }
     188             : 
     189             :     /* Handle external or embedded collection */
     190      637683 :     if(item->type == COL_TYPE_COLLECTIONREF)  {
     191             :         /* Our data is a pointer to a whole external collection so dereference
     192             :          * it or delete */
     193        2660 :         other_collection = *((struct collection_item **)(item->data));
     194        2660 :         col_destroy_collection_with_cb(other_collection, cb, custom_data);
     195             :     }
     196             : 
     197             :     /* Call the callback */
     198      637683 :     if (cb) cb(item->property,
     199             :                item->property_len,
     200             :                item->type,
     201             :                item->data,
     202             :                item->length,
     203             :                custom_data);
     204             : 
     205             :     TRACE_INFO_STRING("Deleting property:", item->property);
     206             :     TRACE_INFO_NUMBER("Type:", item->type);
     207             : 
     208      637683 :     if (item->property != NULL) free(item->property);
     209      637683 :     if (item->data != NULL) free(item->data);
     210             : 
     211      637683 :     free(item);
     212             : 
     213             :     TRACE_FLOW_STRING("col_delete_item","Exit.");
     214             : }
     215             : 
     216             : /* Function that cleans the item */
     217      496996 : void col_delete_item(struct collection_item *item)
     218             : {
     219             :     TRACE_FLOW_STRING("col_delete_item","Entry point.");
     220             : 
     221      496996 :     col_delete_item_with_cb(item, NULL, NULL);
     222             : 
     223             :     TRACE_FLOW_STRING("col_delete_item","Exit.");
     224      496996 : }
     225             : 
     226             : 
     227             : 
     228             : /* A generic function to allocate a property item */
     229      637684 : int col_allocate_item(struct collection_item **ci, const char *property,
     230             :                       const void *item_data, int length, int type)
     231             : {
     232      637684 :     struct collection_item *item = NULL;
     233             : 
     234             :     TRACE_FLOW_STRING("col_allocate_item", "Entry point.");
     235             :     TRACE_INFO_NUMBER("Will be using type:", type);
     236             : 
     237             :     /* Check the length */
     238      637684 :     if (length >= COL_MAX_DATA) {
     239             :         TRACE_ERROR_STRING("col_allocate_item", "Data to long.");
     240           0 :         return EMSGSIZE;
     241             :     }
     242             : 
     243      637684 :     if (col_validate_property(property)) {
     244             :         TRACE_ERROR_STRING("Invalid chracters in the property name", property);
     245           1 :         return EINVAL;
     246             :     }
     247             : 
     248             :     /* Allocate memory for the structure */
     249      637683 :     item = (struct collection_item *)malloc(sizeof(struct collection_item));
     250      637683 :     if (item == NULL)  {
     251             :         TRACE_ERROR_STRING("col_allocate_item", "Malloc failed.");
     252           0 :         return ENOMEM;
     253             :     }
     254             : 
     255             :     /* After we initialize members we can use delete_item() in case of error */
     256      637683 :     item->next = NULL;
     257      637683 :     item->property = NULL;
     258      637683 :     item->data = NULL;
     259             :     TRACE_INFO_NUMBER("About to set type to:", type);
     260      637683 :     item->type = type;
     261             : 
     262             :     /* Copy property */
     263      637683 :     item->property = strdup(property);
     264      637683 :     if (item->property == NULL) {
     265             :         TRACE_ERROR_STRING("col_allocate_item", "Failed to dup property.");
     266           0 :         col_delete_item(item);
     267           0 :         return ENOMEM;
     268             :     }
     269             : 
     270      637683 :     item->phash = col_make_hash(property, 0, &(item->property_len));
     271             :     TRACE_INFO_NUMBER("Item hash", item->phash);
     272             :     TRACE_INFO_NUMBER("Item property length", item->property_len);
     273             :     TRACE_INFO_NUMBER("Item property strlen", strlen(item->property));
     274             : 
     275             :     /* Deal with data */
     276      637683 :     item->data = malloc(length);
     277      637683 :     if (item->data == NULL) {
     278             :         TRACE_ERROR_STRING("col_allocate_item", "Failed to dup data.");
     279           0 :         col_delete_item(item);
     280           0 :         return ENOMEM;
     281             :     }
     282             : 
     283      637683 :     memcpy(item->data, item_data, length);
     284      637683 :     item->length = length;
     285             : 
     286             :     /* Make sure that data is NULL terminated in case of string */
     287      637683 :     if (type == COL_TYPE_STRING) ((char *)(item->data))[length-1] = '\0';
     288             : 
     289      637683 :     *ci = item;
     290             : 
     291             :     TRACE_INFO_STRING("Item property", item->property);
     292             :     TRACE_INFO_NUMBER("Item property type", item->type);
     293             :     TRACE_INFO_NUMBER("Item data length", item->length);
     294             :     TRACE_FLOW_STRING("col_allocate_item", "Success exit.");
     295      637683 :     return EOK;
     296             : }
     297             : 
     298             : /* Structure used to find things in collection */
     299             : struct property_search {
     300             :     const char *property;
     301             :     uint64_t hash;
     302             :     struct collection_item *parent;
     303             :     int index;
     304             :     int count;
     305             :     int found;
     306             :     int use_type;
     307             :     int type;
     308             : };
     309             : 
     310             : /* Find the parent of the item with given name */
     311         582 : static int col_find_property(struct collection_item *collection,
     312             :                              const char *refprop,
     313             :                              int idx,
     314             :                              int use_type,
     315             :                              int type,
     316             :                              struct collection_item **parent)
     317             : {
     318             :     struct property_search ps;
     319         582 :     int i = 0;
     320         582 :     unsigned depth = 0;
     321             : 
     322             :     TRACE_FLOW_STRING("col_find_property", "Entry.");
     323             : 
     324         582 :     *parent = NULL;
     325             : 
     326         582 :     ps.property = refprop;
     327         582 :     ps.hash = FNV1a_base;
     328         582 :     ps.parent = NULL;
     329         582 :     ps.index = idx;
     330         582 :     ps.count = 0;
     331         582 :     ps.found = 0;
     332         582 :     ps.use_type = use_type;
     333         582 :     ps.type = type;
     334             : 
     335             :     /* Create hash of the string to search */
     336        4035 :     while(refprop[i] != 0) {
     337        2871 :         ps.hash = ps.hash ^ toupper(refprop[i]);
     338        2871 :         ps.hash *= FNV1a_prime;
     339        2871 :         i++;
     340             :     }
     341             : 
     342             :     /* We do not care about error here */
     343         582 :     (void)col_walk_items(collection, COL_TRAVERSE_ONELEVEL,
     344             :                          col_parent_traverse_handler,
     345             :                          (void *)parent, NULL, (void *)&ps,
     346             :                          &depth);
     347             : 
     348         582 :     if (*parent) {
     349             :         /* Item is found in the collection */
     350             :         TRACE_FLOW_STRING("col_find_property", "Exit - item found");
     351         198 :         return 1;
     352             :     }
     353             : 
     354             :     /* Item is not found */
     355             :     TRACE_FLOW_STRING("col_find_property", "Exit - item NOT found");
     356         384 :     return EOK;
     357             : }
     358             : 
     359             : 
     360             : 
     361             : /* Insert item into the current collection */
     362      637638 : int col_insert_item_into_current(struct collection_item *collection,
     363             :                                  struct collection_item *item,
     364             :                                  int disposition,
     365             :                                  const char *refprop,
     366             :                                  int idx,
     367             :                                  unsigned flags)
     368             : {
     369      637638 :     struct collection_header *header = NULL;
     370      637638 :     struct collection_item *parent = NULL;
     371      637638 :     struct collection_item *current = NULL;
     372      637638 :     int refindex = 0;
     373             : 
     374             :     TRACE_FLOW_STRING("col_insert_item_into_current", "Entry point");
     375             : 
     376             :     /* Do best effort on the item */
     377      637638 :     if ((!item) || (item->next)) {
     378             :         TRACE_ERROR_STRING("Passed in item is invalid", "");
     379           0 :         return EINVAL;
     380             :     }
     381             : 
     382      637638 :     if (collection == NULL) {
     383             :         TRACE_INFO_STRING("col_insert_item_into_current",
     384             :                           "Collection accepting is NULL");
     385        3927 :         if (item->type == COL_TYPE_COLLECTION) {
     386             :             /* This is a special case of self creation */
     387             :             TRACE_INFO_STRING("col_insert_item_into_current",
     388             :                               "Adding header item to new collection.");
     389        3927 :             collection = item;
     390             :         }
     391             :         else {
     392             :             TRACE_ERROR_STRING("Passed in item is invalid", "");
     393           0 :             return EINVAL;
     394             :         }
     395             :     }
     396             :     else {
     397             :         /* We can add items only to collections */
     398      633711 :         if (collection->type != COL_TYPE_COLLECTION) {
     399             :             TRACE_ERROR_STRING("Attempt to add item to non collection.","");
     400             :             TRACE_ERROR_STRING("Collection name:", collection->property);
     401             :             TRACE_ERROR_NUMBER("Collection type:", collection->type);
     402           0 :             return EINVAL;
     403             :         }
     404             :     }
     405             : 
     406             :     /* After processing flags we can process disposition */
     407             : 
     408      637638 :     header = (struct collection_header *)collection->data;
     409             : 
     410             :     /* Check flags first */
     411      637638 :     switch(flags) {
     412             :     case COL_INSERT_NOCHECK:    /* No check - good just fall through */
     413             :                                 TRACE_INFO_STRING("Insert without check", "");
     414      637072 :                                 break;
     415             :     case COL_INSERT_DUPOVER:    /* Find item and overwrite - ignore disposition */
     416         281 :                                 if (col_find_property(collection, item->property, 0, 0, 0, &parent)) {
     417          20 :                                     current = parent->next;
     418          20 :                                     item->next = current->next;
     419          20 :                                     parent->next = item;
     420          20 :                                     if (header->last == current) header->last = item;
     421          20 :                                     col_delete_item(current);
     422             :                                     /* Deleted one added another - count stays the same! */
     423             :                                     TRACE_FLOW_STRING("col_insert_item_into_current", "Dup overwrite exit");
     424          20 :                                     return EOK;
     425             :                                 }
     426             :                                 /* Not found so we fall thorough and add as requested */
     427         261 :                                 break;
     428             : 
     429             :     case COL_INSERT_DUPOVERT:   /* Find item by name and type and overwrite - ignore disposition */
     430           1 :                                 if (col_find_property(collection, item->property, 0, 1, item->type, &parent)) {
     431           1 :                                     current = parent->next;
     432           1 :                                     item->next = current->next;
     433           1 :                                     parent->next = item;
     434           1 :                                     if (header->last == current) header->last = item;
     435           1 :                                     col_delete_item(current);
     436             :                                     /* Deleted one added another - count stays the same! */
     437             :                                     TRACE_FLOW_STRING("col_insert_item_into_current", "Dup overwrite exit");
     438           1 :                                     return EOK;
     439             :                                 }
     440             :                                 /* Not found so we fall thorough and add as requested */
     441           0 :                                 break;
     442             : 
     443         282 :     case COL_INSERT_DUPERROR:   if (col_find_property(collection, item->property, 0, 0, 0, &parent)) {
     444             :                                     /* Return error */
     445             :                                     TRACE_ERROR_NUMBER("Duplicate property", EEXIST);
     446         159 :                                     return EEXIST;
     447             :                                 }
     448         123 :                                 break;
     449             : 
     450           0 :     case COL_INSERT_DUPERRORT:  if (col_find_property(collection, item->property, 0, 1, item->type, &parent)) {
     451             :                                     /* Return error */
     452             :                                     TRACE_ERROR_NUMBER("Duplicate property of the same type", EEXIST);
     453           0 :                                     return EEXIST;
     454             :                                 }
     455           0 :                                 break;
     456             : 
     457             :     case COL_INSERT_DUPMOVE:    /* Find item and delete */
     458           1 :                                 if (col_find_property(collection, item->property, 0, 0, 0, &parent)) {
     459           1 :                                     current = parent->next;
     460           1 :                                     parent->next = current->next;
     461           1 :                                     if (header->last == current) header->last = parent;
     462           1 :                                     col_delete_item(current);
     463           1 :                                     header->count--;
     464             :                                 }
     465             :                                 /* Now add item according to the disposition */
     466           1 :                                 break;
     467             : 
     468             :     case COL_INSERT_DUPMOVET:   /* Find item and delete */
     469             :                                 TRACE_INFO_STRING("Property:", item->property);
     470             :                                 TRACE_INFO_NUMBER("Type:", item->type);
     471           1 :                                 if (col_find_property(collection, item->property, 0, 1, item->type, &parent)) {
     472             :                                     TRACE_INFO_LNUMBER("Current:", parent->next);
     473           1 :                                     current = parent->next;
     474           1 :                                     parent->next = current->next;
     475           1 :                                     if (header->last == current) header->last = parent;
     476           1 :                                     col_delete_item(current);
     477           1 :                                     header->count--;
     478             :                                 }
     479             :                                 /* Now add item according to the disposition */
     480           1 :                                 break;
     481             : 
     482             :     default:                    /* The new ones should be added here */
     483             :                                 TRACE_ERROR_NUMBER("Flag is not implemented", ENOSYS);
     484           0 :                                 return ENOSYS;
     485             :     }
     486             : 
     487             : 
     488      637458 :     switch (disposition) {
     489             :     case COL_DSP_END:       /* Link new item to the last item in the list if there any */
     490      637439 :                             if (header->count != 0) header->last->next = item;
     491             :                             /* Make sure we save a new last element */
     492      637439 :                             header->last = item;
     493      637439 :                             header->count++;
     494      637439 :                             break;
     495             : 
     496             :     case COL_DSP_FRONT:     /* Same as above if there is header only */
     497           4 :                             if (header->count == 1) {
     498           1 :                                 header->last->next = item;
     499           1 :                                 header->last = item;
     500             :                             }
     501             :                             else {
     502           3 :                                 item->next = collection->next;
     503           3 :                                 collection->next = item;
     504             :                             }
     505           4 :                             header->count++;
     506           4 :                             break;
     507             : 
     508             :     case COL_DSP_BEFORE:    /* Check argument */
     509           3 :                             if (!refprop) {
     510             :                                 TRACE_ERROR_STRING("In this case property is required", "");
     511           0 :                                 return EINVAL;
     512             :                             }
     513             : 
     514             :                             /* We need to find property */
     515           3 :                             if (col_find_property(collection, refprop, 0, 0, 0, &parent)) {
     516           3 :                                 item->next = parent->next;
     517           3 :                                 parent->next = item;
     518           3 :                                 header->count++;
     519             :                             }
     520             :                             else {
     521             :                                 TRACE_ERROR_STRING("Property not found", refprop);
     522           0 :                                 return ENOENT;
     523             :                             }
     524           3 :                             break;
     525             : 
     526             :     case COL_DSP_AFTER:     /* Check argument */
     527           2 :                             if (!refprop) {
     528             :                                 TRACE_ERROR_STRING("In this case property is required", "");
     529           0 :                                 return EINVAL;
     530             :                             }
     531             : 
     532             :                             /* We need to find property */
     533           2 :                             if (col_find_property(collection, refprop, 0, 0, 0, &parent)) {
     534           2 :                                 parent = parent->next;
     535           2 :                                 if (parent->next) {
     536             :                                     /* It is not the last item */
     537           2 :                                     item->next = parent->next;
     538           2 :                                     parent->next = item;
     539             :                                 }
     540             :                                 else {
     541             :                                     /* It is the last item */
     542           0 :                                     header->last->next = item;
     543           0 :                                     header->last = item;
     544             :                                 }
     545           2 :                                 header->count++;
     546             :                             }
     547             :                             else {
     548             :                                 TRACE_ERROR_STRING("Property not found", refprop);
     549           0 :                                 return ENOENT;
     550             :                             }
     551           2 :                             break;
     552             : 
     553           5 :     case COL_DSP_INDEX:     if(idx == 0) {
     554             :                                 /* Same is first */
     555           1 :                                 if (header->count == 1) {
     556           0 :                                     header->last->next = item;
     557           0 :                                     header->last = item;
     558             :                                 }
     559             :                                 else {
     560           1 :                                     item->next = collection->next;
     561           1 :                                     collection->next = item;
     562             :                                 }
     563             :                             }
     564           4 :                             else if(idx >= header->count - 1) {
     565             :                                 /* In this case add to the end */
     566           3 :                                 header->last->next = item;
     567             :                                 /* Make sure we save a new last element */
     568           3 :                                 header->last = item;
     569             :                             }
     570             :                             else {
     571             :                                 /* In the middle */
     572           1 :                                 parent = collection;
     573             :                                 /* Move to the right position counting */
     574           3 :                                 while (idx > 0) {
     575           1 :                                     idx--;
     576           1 :                                     if (parent->next) parent = parent->next;
     577             :                                 }
     578           1 :                                 item->next = parent->next;
     579           1 :                                 parent->next = item;
     580             :                             }
     581           5 :                             header->count++;
     582           5 :                             break;
     583             : 
     584             :     case COL_DSP_FIRSTDUP:
     585             :     case COL_DSP_LASTDUP:
     586             :     case COL_DSP_NDUP:
     587             : 
     588           5 :                             if (disposition == COL_DSP_FIRSTDUP) refindex = 0;
     589           4 :                             else if (disposition == COL_DSP_LASTDUP) refindex = -1;
     590           2 :                             else refindex = idx;
     591             : 
     592             :                             /* We need to find property based on index */
     593           5 :                             if (col_find_property(collection, item->property, refindex, 0, 0, &parent)) {
     594           5 :                                 item->next = parent->next;
     595           5 :                                 parent->next = item;
     596           5 :                                 header->count++;
     597           5 :                                 if(header->last == parent) header->last = item;
     598             :                             }
     599             :                             else {
     600             :                                 TRACE_ERROR_STRING("Property not found", refprop);
     601           0 :                                 return ENOENT;
     602             :                             }
     603           5 :                             break;
     604             : 
     605             :     default:
     606             :                             TRACE_ERROR_STRING("Disposition is not implemented", "");
     607           0 :                             return ENOSYS;
     608             : 
     609             :     }
     610             : 
     611             : 
     612             :     TRACE_INFO_STRING("Collection:", collection->property);
     613             :     TRACE_INFO_STRING("Just added item is:", item->property);
     614             :     TRACE_INFO_NUMBER("Item type.", item->type);
     615             :     TRACE_INFO_NUMBER("Number of items in collection now is.", header->count);
     616             : 
     617             :     TRACE_FLOW_STRING("col_insert_item_into_current", "Exit");
     618      637458 :     return EOK;
     619             : }
     620             : 
     621             : /* Extract item from the current collection */
     622      496829 : int col_extract_item_from_current(struct collection_item *collection,
     623             :                                   int disposition,
     624             :                                   const char *refprop,
     625             :                                   int idx,
     626             :                                   int type,
     627             :                                   struct collection_item **ret_ref)
     628             : {
     629      496829 :     struct collection_header *header = NULL;
     630      496829 :     struct collection_item *parent = NULL;
     631      496829 :     struct collection_item *current = NULL;
     632      496829 :     struct collection_item *found = NULL;
     633      496829 :     int refindex = 0;
     634      496829 :     int use_type = 0;
     635             : 
     636             :     TRACE_FLOW_STRING("col_extract_item_from_current", "Entry point");
     637             : 
     638             :     /* Check that collection is not empty */
     639      496829 :     if ((collection == NULL) || (collection->type != COL_TYPE_COLLECTION)) {
     640             :         TRACE_ERROR_STRING("Collection can't be NULL", "");
     641           0 :         return EINVAL;
     642             :     }
     643             : 
     644      496829 :     header = (struct collection_header *)collection->data;
     645             : 
     646             :     /* Before moving forward we need to check if there is anything to extract */
     647      496829 :     if (header->count <= 1) {
     648             :         TRACE_ERROR_STRING("Collection is empty.", "Nothing to extract.");
     649          63 :         return ENOENT;
     650             :     }
     651             : 
     652      496766 :     if (type != 0) use_type = 1;
     653             : 
     654      496766 :     switch (disposition) {
     655             :     case COL_DSP_END:       /* Extract last item in the list. */
     656           4 :                             parent = collection;
     657           4 :                             current = collection->next;
     658          36 :                             while (current->next != NULL) {
     659          28 :                                 parent = current;
     660          28 :                                 current = current->next;
     661             :                             }
     662           4 :                             *ret_ref = parent->next;
     663           4 :                             parent->next = NULL;
     664             :                             /* Special case - one data element */
     665           4 :                             if (header->count == 2) header->last = collection;
     666           4 :                             else header->last = parent;
     667           4 :                             break;
     668             : 
     669             :     case COL_DSP_FRONT:     /* Extract first item in the list */
     670      496755 :                             *ret_ref = collection->next;
     671      496755 :                             collection->next = (*ret_ref)->next;
     672             :                             /* Special case - one data element */
     673      496755 :                             if (header->count == 2) header->last = collection;
     674      496755 :                             break;
     675             : 
     676             :     case COL_DSP_BEFORE:    /* Check argument */
     677           1 :                             if (!refprop) {
     678             :                                 TRACE_ERROR_STRING("In this case property is required", "");
     679           0 :                                 return EINVAL;
     680             :                             }
     681             : 
     682             :                             /* We have to do it in two steps */
     683             :                             /* First find the property that is mentioned */
     684           1 :                             if (col_find_property(collection, refprop, 0, use_type, type, &found)) {
     685             :                                 /* We found the requested property */
     686           1 :                                 if (found->next == collection->next) {
     687             :                                     /* The referenced property is the first in the list */
     688             :                                     TRACE_ERROR_STRING("Nothing to extract. Lists starts with property", refprop);
     689           0 :                                     return ENOENT;
     690             :                                 }
     691             :                                 /* Get to the parent of the item that is before the one that is found */
     692           1 :                                 parent = collection;
     693           1 :                                 current = collection->next;
     694           3 :                                 while (current != found) {
     695           1 :                                     parent = current;
     696           1 :                                     current = current->next;
     697             :                                 }
     698           1 :                                 *ret_ref = current;
     699           1 :                                 parent->next = current->next;
     700             : 
     701             :                             }
     702             :                             else {
     703             :                                 TRACE_ERROR_STRING("Property not found", refprop);
     704           0 :                                 return ENOENT;
     705             :                             }
     706           1 :                             break;
     707             : 
     708             :     case COL_DSP_AFTER:     /* Check argument */
     709           2 :                             if (!refprop) {
     710             :                                 TRACE_ERROR_STRING("In this case property is required", "");
     711           0 :                                 return EINVAL;
     712             :                             }
     713             : 
     714             :                             /* We need to find property */
     715           2 :                             if (col_find_property(collection, refprop, 0, use_type, type, &parent)) {
     716           2 :                                 current = parent->next;
     717           2 :                                 if (current->next) {
     718           2 :                                     *ret_ref = current->next;
     719           2 :                                     current->next = (*ret_ref)->next;
     720             :                                     /* If we removed the last element adjust header */
     721           2 :                                     if(current->next == NULL) header->last = current;
     722             :                                 }
     723             :                                 else {
     724             :                                     TRACE_ERROR_STRING("Property is last in the list", refprop);
     725           0 :                                     return ENOENT;
     726             :                                 }
     727             :                             }
     728             :                             else {
     729             :                                 TRACE_ERROR_STRING("Property not found", refprop);
     730           0 :                                 return ENOENT;
     731             :                             }
     732           2 :                             break;
     733             : 
     734           1 :     case COL_DSP_INDEX:     if (idx == 0) {
     735           0 :                                 *ret_ref = collection->next;
     736           0 :                                 collection->next = (*ret_ref)->next;
     737             :                                 /* Special case - one data element */
     738           0 :                                 if (header->count == 2) header->last = collection;
     739             :                             }
     740             :                             /* Index 0 stands for the first data element.
     741             :                              * Count includes header element.
     742             :                              */
     743           1 :                             else if (idx >= (header->count - 1)) {
     744             :                                 TRACE_ERROR_STRING("Index is out of boundaries", refprop);
     745           0 :                                 return ENOENT;
     746             :                             }
     747             :                             else {
     748             :                                 /* Loop till the element with right index */
     749           1 :                                 refindex = 0;
     750           1 :                                 parent = collection;
     751           1 :                                 current = collection->next;
     752           3 :                                 while (refindex < idx) {
     753           1 :                                     parent = current;
     754           1 :                                     current = current->next;
     755           1 :                                     refindex++;
     756             :                                 }
     757           1 :                                 *ret_ref = parent->next;
     758           1 :                                 parent->next = (*ret_ref)->next;
     759             :                                 /* If we removed the last element adjust header */
     760           1 :                                 if (parent->next == NULL) header->last = parent;
     761             :                             }
     762           1 :                             break;
     763             : 
     764             :     case COL_DSP_FIRSTDUP:
     765             :     case COL_DSP_LASTDUP:
     766             :     case COL_DSP_NDUP:
     767             : 
     768           3 :                             if (disposition == COL_DSP_FIRSTDUP) refindex = 0;
     769           2 :                             else if (disposition == COL_DSP_LASTDUP) refindex = -2;
     770           1 :                             else refindex = idx;
     771             : 
     772             :                             /* We need to find property based on index */
     773           3 :                             if (col_find_property(collection, refprop, refindex, use_type, type, &parent)) {
     774           3 :                                 *ret_ref = parent->next;
     775           3 :                                 parent->next = (*ret_ref)->next;
     776             :                                 /* If we removed the last element adjust header */
     777           3 :                                 if(parent->next == NULL) header->last = parent;
     778             :                             }
     779             :                             else {
     780             :                                 TRACE_ERROR_STRING("Property not found", refprop);
     781           0 :                                 return ENOENT;
     782             :                             }
     783           3 :                             break;
     784             : 
     785             :     default:
     786             :                             TRACE_ERROR_STRING("Disposition is not implemented", "");
     787           0 :                             return ENOSYS;
     788             : 
     789             :     }
     790             : 
     791             : 
     792             :     /* Clear item and reduce count */
     793      496766 :     (*ret_ref)->next = NULL;
     794      496766 :     header->count--;
     795             : 
     796             :     TRACE_INFO_STRING("Collection:", (*ret_ref)->property);
     797             :     TRACE_INFO_NUMBER("Item type.", (*ret_ref)->type);
     798             :     TRACE_INFO_NUMBER("Number of items in collection now is.", header->count);
     799             : 
     800             :     TRACE_FLOW_STRING("col_extract_item_from_current", "Exit");
     801      496766 :     return EOK;
     802             : }
     803             : 
     804             : /* Extract item from the collection */
     805          11 : int col_extract_item(struct collection_item *collection,
     806             :                      const char *subcollection,
     807             :                      int disposition,
     808             :                      const char *refprop,
     809             :                      int idx,
     810             :                      int type,
     811             :                      struct collection_item **ret_ref)
     812             : {
     813          11 :     struct collection_item *col = NULL;
     814          11 :     int error = EOK;
     815             : 
     816             :     TRACE_FLOW_STRING("col_extract_item", "Entry point");
     817             : 
     818             :     /* Check that collection is not empty */
     819          11 :     if ((collection == NULL) || (collection->type != COL_TYPE_COLLECTION)) {
     820             :         TRACE_ERROR_STRING("Collection can't be NULL", "");
     821           0 :         return EINVAL;
     822             :     }
     823             : 
     824             :     /* Get subcollection if needed */
     825          11 :     if (subcollection == NULL) {
     826          11 :         col = collection;
     827             :     }
     828             :     else {
     829             :         TRACE_INFO_STRING("Subcollection id not null, searching", subcollection);
     830           0 :         error = col_find_item_and_do(collection, subcollection,
     831             :                                      COL_TYPE_COLLECTIONREF,
     832             :                                      COL_TRAVERSE_DEFAULT,
     833             :                                      col_get_subcollection, (void *)(&col),
     834             :                                      COLLECTION_ACTION_FIND);
     835           0 :         if (error) {
     836             :             TRACE_ERROR_NUMBER("Search for subcollection returned error:", error);
     837           0 :             return error;
     838             :         }
     839             : 
     840           0 :         if (col == NULL) {
     841             :             TRACE_ERROR_STRING("Search for subcollection returned NULL pointer", "");
     842           0 :             return ENOENT;
     843             :         }
     844             : 
     845             :     }
     846             : 
     847             :     /* Extract from the current collection */
     848          11 :     error = col_extract_item_from_current(col,
     849             :                                           disposition,
     850             :                                           refprop,
     851             :                                           idx,
     852             :                                           type,
     853             :                                           ret_ref);
     854          11 :     if (error) {
     855             :         TRACE_ERROR_NUMBER("Failed to extract item from the current collection", error);
     856           0 :         return error;
     857             :     }
     858             : 
     859             :     TRACE_FLOW_STRING("col_extract_item", "Exit");
     860          11 :     return EOK;
     861             : }
     862             : 
     863             : 
     864             : /* Remove item (property) from collection.*/
     865           2 : int col_remove_item(struct collection_item *ci,
     866             :                     const char *subcollection,
     867             :                     int disposition,
     868             :                     const char *refprop,
     869             :                     int idx,
     870             :                     int type)
     871             : {
     872           2 :     int error = EOK;
     873           2 :     struct collection_item *ret_ref = NULL;
     874             : 
     875             :     TRACE_FLOW_STRING("col_remove_item", "Exit");
     876             : 
     877             :     /* Extract from the current collection */
     878           2 :     error = col_extract_item(ci,
     879             :                              subcollection,
     880             :                              disposition,
     881             :                              refprop,
     882             :                              idx,
     883             :                              type,
     884             :                              &ret_ref);
     885           2 :     if (error) {
     886             :         TRACE_ERROR_NUMBER("Failed to extract item from the collection", error);
     887           0 :         return error;
     888             :     }
     889             : 
     890           2 :     col_delete_item(ret_ref);
     891             : 
     892             :     TRACE_FLOW_STRING("col_remove_item", "Exit");
     893           2 :     return EOK;
     894             : }
     895             : 
     896             : /* Remove item (property) from current collection.
     897             :  * Just a simple wrapper.
     898             :  */
     899           1 : int col_remove_item_from_current(struct collection_item *ci,
     900             :                                  int disposition,
     901             :                                  const char *refprop,
     902             :                                  int idx,
     903             :                                  int type)
     904             : {
     905           1 :     int error = EOK;
     906             : 
     907             :     TRACE_FLOW_STRING("col_remove_item_from_current", "Exit");
     908             : 
     909             :     /* Remove item from current collection */
     910           1 :     error = col_remove_item(ci,
     911             :                             NULL,
     912             :                             disposition,
     913             :                             refprop,
     914             :                             idx,
     915             :                             type);
     916             : 
     917             :     TRACE_FLOW_NUMBER("col_remove_item_from_current. Exit. Returning", error);
     918           1 :     return error;
     919             : }
     920             : 
     921             : 
     922             : /* Insert the item into the collection or subcollection */
     923      637628 : int col_insert_item(struct collection_item *collection,
     924             :                     const char *subcollection,
     925             :                     struct collection_item *item,
     926             :                     int disposition,
     927             :                     const char *refprop,
     928             :                     int idx,
     929             :                     unsigned flags)
     930             : {
     931             :     int error;
     932      637628 :     struct collection_item *acceptor = NULL;
     933             : 
     934             :     TRACE_FLOW_STRING("col_insert_item", "Entry point.");
     935             : 
     936             :     /* Do best effort on the item */
     937      637628 :     if ((!item) || (item->next)) {
     938             :         TRACE_ERROR_STRING("Passed in item is invalid", "");
     939           0 :         return EINVAL;
     940             :     }
     941             : 
     942             :     /* Check that collection is not empty */
     943      637628 :     if ((collection == NULL) && (item->type != COL_TYPE_COLLECTION)) {
     944             :         TRACE_ERROR_STRING("Collection can't be NULL", "");
     945           0 :         return EINVAL;
     946             :     }
     947             : 
     948             :     /* Add item to collection */
     949      637628 :     if (subcollection == NULL) {
     950      637611 :         acceptor = collection;
     951             :     }
     952             :     else {
     953             :         TRACE_INFO_STRING("Subcollection id not null, searching", subcollection);
     954          17 :         error = col_find_item_and_do(collection, subcollection,
     955             :                                      COL_TYPE_COLLECTIONREF,
     956             :                                      COL_TRAVERSE_DEFAULT,
     957             :                                      col_get_subcollection, (void *)(&acceptor),
     958             :                                      COLLECTION_ACTION_FIND);
     959          17 :         if (error) {
     960             :             TRACE_ERROR_NUMBER("Search for subcollection returned error:", error);
     961           0 :             return error;
     962             :         }
     963             : 
     964          17 :         if (acceptor == NULL) {
     965             :             TRACE_ERROR_STRING("Search for subcollection returned NULL pointer", "");
     966           0 :             return ENOENT;
     967             :         }
     968             : 
     969             :     }
     970             : 
     971             :     /* Instert item to the current collection */
     972      637628 :     error = col_insert_item_into_current(acceptor,
     973             :                                          item,
     974             :                                          disposition,
     975             :                                          refprop,
     976             :                                          idx,
     977             :                                          flags);
     978             : 
     979      637628 :     if (error) {
     980             :         TRACE_ERROR_NUMBER("Failed to insert item into current collection", error);
     981         159 :         return error;
     982             :     }
     983             : 
     984             :     TRACE_FLOW_STRING("insert_item", "Exit");
     985      637469 :     return EOK;
     986             : }
     987             : 
     988             : 
     989             : /* Insert property with reference.
     990             :  * This is internal function so we do not check parameters.
     991             :  * See external wrapper below.
     992             :  */
     993      571341 : static int col_insert_property_with_ref_int(struct collection_item *collection,
     994             :                                             const char *subcollection,
     995             :                                             int disposition,
     996             :                                             const char *refprop,
     997             :                                             int idx,
     998             :                                             unsigned flags,
     999             :                                             const char *property,
    1000             :                                             int type,
    1001             :                                             const void *data,
    1002             :                                             int length,
    1003             :                                             struct collection_item **ret_ref)
    1004             : {
    1005      571341 :     struct collection_item *item = NULL;
    1006             :     int error;
    1007             : 
    1008             :     TRACE_FLOW_STRING("col_insert_property_with_ref_int", "Entry point.");
    1009             : 
    1010             :     /* Create a new property out of the given parameters */
    1011      571341 :     error = col_allocate_item(&item, property, data, length, type);
    1012      571341 :     if (error) {
    1013             :         TRACE_ERROR_NUMBER("Failed to allocate item", error);
    1014           1 :         return error;
    1015             :     }
    1016             : 
    1017             :     /* Send the property to the insert_item function */
    1018      571340 :     error = col_insert_item(collection,
    1019             :                             subcollection,
    1020             :                             item,
    1021             :                             disposition,
    1022             :                             refprop,
    1023             :                             idx,
    1024             :                             flags);
    1025      571340 :     if (error) {
    1026             :         TRACE_ERROR_NUMBER("Failed to insert item", error);
    1027         159 :         col_delete_item(item);
    1028         159 :         return error;
    1029             :     }
    1030             : 
    1031      571181 :     if (ret_ref) *ret_ref = item;
    1032             : 
    1033             :     TRACE_FLOW_STRING("col_insert_property_with_ref_int", "Exit");
    1034      571181 :     return EOK;
    1035             : }
    1036             : 
    1037             : /* Special function used to copy item from one
    1038             :  * collection to another using caller's callback.
    1039             :  */
    1040       66261 : static int col_copy_item_with_cb(struct collection_item *collection,
    1041             :                                  const char *property,
    1042             :                                  int type,
    1043             :                                  const void *data,
    1044             :                                  int length,
    1045             :                                  col_copy_cb copy_cb,
    1046             :                                  void *ext_data)
    1047             : {
    1048       66261 :     struct collection_item *item = NULL;
    1049       66261 :     int skip = 0;
    1050       66261 :     int error = EOK;
    1051             : 
    1052             :     TRACE_FLOW_STRING("col_copy_item_with_cb", "Entry point.");
    1053             : 
    1054             :     /* Create a new property out of the given parameters */
    1055       66261 :     error = col_allocate_item(&item, property, data, length, type);
    1056       66261 :     if (error) {
    1057             :         TRACE_ERROR_NUMBER("Failed to allocate item", error);
    1058           0 :         return error;
    1059             :     }
    1060             : 
    1061             :     /* Call callback if any */
    1062       66261 :     if (copy_cb) {
    1063             :         TRACE_INFO_STRING("Calling callback for item:", item->property);
    1064       66246 :         error = copy_cb(item, ext_data, &skip);
    1065       66246 :         if (error) {
    1066             :             TRACE_ERROR_NUMBER("Callback failed", error);
    1067           0 :             col_delete_item(item);
    1068           0 :             return error;
    1069             :         }
    1070             :     }
    1071             : 
    1072             :     /* Are we told to skip this item? */
    1073       66261 :     if (skip) col_delete_item(item);
    1074             :     else {
    1075             :         /* Insted property into the collection */
    1076       66260 :         error = col_insert_item(collection,
    1077             :                                 NULL,
    1078             :                                 item,
    1079             :                                 COL_DSP_END,
    1080             :                                 NULL,
    1081             :                                 0,
    1082             :                                 0);
    1083       66260 :         if (error) {
    1084             :             TRACE_ERROR_NUMBER("Failed to insert item", error);
    1085           0 :             col_delete_item(item);
    1086           0 :             return error;
    1087             :         }
    1088             :     }
    1089             : 
    1090             :     TRACE_FLOW_STRING("col_copy_item_with_cb", "Exit");
    1091       66261 :     return EOK;
    1092             : }
    1093             : 
    1094             : 
    1095             : /* This is public function so we need to check the validity
    1096             :  * of the arguments.
    1097             :  */
    1098      564754 : int col_insert_property_with_ref(struct collection_item *collection,
    1099             :                                  const char *subcollection,
    1100             :                                  int disposition,
    1101             :                                  const char *refprop,
    1102             :                                  int idx,
    1103             :                                  unsigned flags,
    1104             :                                  const char *property,
    1105             :                                  int type,
    1106             :                                  const void *data,
    1107             :                                  int length,
    1108             :                                  struct collection_item **ret_ref)
    1109             : {
    1110             :     int error;
    1111             : 
    1112             :     TRACE_FLOW_STRING("col_insert_property_with_ref", "Entry point.");
    1113             : 
    1114             :     /* Check that collection is not empty */
    1115      564754 :     if (collection == NULL) {
    1116             :         TRACE_ERROR_STRING("Collection cant be NULL", "");
    1117           0 :         return EINVAL;
    1118             :     }
    1119             : 
    1120      564754 :     error = col_insert_property_with_ref_int(collection,
    1121             :                                              subcollection,
    1122             :                                              disposition,
    1123             :                                              refprop,
    1124             :                                              idx,
    1125             :                                              flags,
    1126             :                                              property,
    1127             :                                              type,
    1128             :                                              data,
    1129             :                                              length,
    1130             :                                              ret_ref);
    1131             : 
    1132             :     TRACE_FLOW_NUMBER("col_insert_property_with_ref_int Returning:", error);
    1133      564754 :     return error;
    1134             : }
    1135             : /* TRAVERSE HANDLERS */
    1136             : 
    1137             : /* Special handler to just set a flag if the item is found */
    1138           8 : static int col_is_in_item_handler(const char *property,
    1139             :                                   int property_len,
    1140             :                                   int type,
    1141             :                                   void *data,
    1142             :                                   int length,
    1143             :                                   void *found,
    1144             :                                   int *dummy)
    1145             : {
    1146             :     TRACE_FLOW_STRING("col_is_in_item_handler", "Entry.");
    1147             :     TRACE_INFO_STRING("Property:", property);
    1148             :     TRACE_INFO_NUMBER("Property length:", property_len);
    1149             :     TRACE_INFO_NUMBER("Type:", type);
    1150             :     TRACE_INFO_NUMBER("Length:", length);
    1151             : 
    1152           8 :     *((int *)(found)) = COL_MATCH;
    1153             : 
    1154             :     TRACE_FLOW_STRING("col_is_in_item_handler", "Success Exit.");
    1155             : 
    1156           8 :     return EOK;
    1157             : }
    1158             : 
    1159             : /* Special handler to retrieve the sub collection */
    1160          94 : static int col_get_subcollection(const char *property,
    1161             :                                  int property_len,
    1162             :                                  int type,
    1163             :                                  void *data,
    1164             :                                  int length,
    1165             :                                  void *found,
    1166             :                                  int *dummy)
    1167             : {
    1168             :     TRACE_FLOW_STRING("col_get_subcollection", "Entry.");
    1169             :     TRACE_INFO_STRING("Property:", property);
    1170             :     TRACE_INFO_NUMBER("Property length:", property_len);
    1171             :     TRACE_INFO_NUMBER("Type:", type);
    1172             :     TRACE_INFO_NUMBER("Length:", length);
    1173             : 
    1174          94 :     *((struct collection_item **)(found)) = *((struct collection_item **)(data));
    1175             : 
    1176             :     TRACE_FLOW_STRING("col_get_subcollection","Success Exit.");
    1177             : 
    1178          94 :     return EOK;
    1179             : 
    1180             : }
    1181             : 
    1182             : 
    1183             : 
    1184             : /* CLEANUP */
    1185             : 
    1186             : /* Cleans the collection tree including current item. */
    1187             : /* The passed in variable should not be used after the call
    1188             :  * as memory is freed!!! */
    1189      144614 : static void col_delete_collection(struct collection_item *ci,
    1190             :                                   col_item_cleanup_fn cb,
    1191             :                                   void *custom_data)
    1192             : {
    1193             :     TRACE_FLOW_STRING("col_delete_collection", "Entry.");
    1194             : 
    1195      144614 :     if (ci == NULL) {
    1196             :         TRACE_FLOW_STRING("col_delete_collection", "Nothing to do Exit.");
    1197      148541 :         return;
    1198             :     }
    1199             : 
    1200             :     TRACE_INFO_STRING("Real work to do", "");
    1201             :     TRACE_INFO_STRING("Property", ci->property);
    1202             :     TRACE_INFO_NUMBER("Next item", ci->next);
    1203             : 
    1204      140687 :     col_delete_collection(ci->next, cb, custom_data);
    1205             : 
    1206             :     /* Delete this item */
    1207      140687 :     col_delete_item_with_cb(ci, cb, custom_data);
    1208             :     TRACE_FLOW_STRING("col_delete_collection", "Exit.");
    1209             : }
    1210             : 
    1211             : 
    1212             : /* NAME MANAGEMENT - used by search */
    1213             : 
    1214             : /* Internal data structures used for search */
    1215             : 
    1216             : 
    1217             : struct find_name {
    1218             :     const char *name_to_find;
    1219             :     int name_len_to_find;
    1220             :     uint64_t hash;
    1221             :     int type_to_match;
    1222             :     char *given_name;
    1223             :     int given_len;
    1224             :     struct path_data *current_path;
    1225             :     int action;
    1226             : };
    1227             : 
    1228             : /* Create a new name */
    1229       74166 : static int col_create_path_data(struct path_data **name_path,
    1230             :                                 const char *name, int length,
    1231             :                                 const char *property, int property_len,
    1232             :                                 char sep)
    1233             : {
    1234       74166 :     int error = EOK;
    1235             :     struct path_data *new_name_path;
    1236             : 
    1237             :     TRACE_FLOW_STRING("col_create_path_data", "Entry.");
    1238             : 
    1239             :     TRACE_INFO_STRING("Constructing path from name:", name);
    1240             :     TRACE_INFO_STRING("Constructing path from property:", property);
    1241             : 
    1242             :     /* Allocate structure */
    1243       74166 :     new_name_path = (struct path_data *)malloc(sizeof(struct path_data));
    1244       74166 :     if (new_name_path == NULL) {
    1245             :         TRACE_ERROR_NUMBER("Failed to allocate memory for new path struct.", ENOMEM);
    1246           0 :         return ENOMEM;
    1247             :     }
    1248       74166 :     new_name_path->name = malloc(length + property_len + 2);
    1249       74166 :     if (new_name_path->name == NULL) {
    1250             :         TRACE_ERROR_NUMBER("Failed to allocate memory for new path name.", ENOMEM);
    1251           0 :         free(new_name_path);
    1252           0 :         return ENOMEM;
    1253             :     }
    1254             : 
    1255             :     /* Construct the new name */
    1256       74166 :     new_name_path->length = 0;
    1257             : 
    1258       74166 :     if(length > 0) {
    1259        5564 :         memcpy(new_name_path->name, name, length);
    1260        5564 :         new_name_path->length = length;
    1261        5564 :         new_name_path->name[new_name_path->length] = sep;
    1262        5564 :         new_name_path->length++;
    1263        5564 :         new_name_path->name[new_name_path->length] = '\0';
    1264             :         TRACE_INFO_STRING("Name so far:", new_name_path->name);
    1265             :         TRACE_INFO_NUMBER("Len so far:", new_name_path->length);
    1266             :     }
    1267       74166 :     memcpy(&new_name_path->name[new_name_path->length], property, property_len);
    1268       74166 :     new_name_path->length += property_len;
    1269       74166 :     new_name_path->name[new_name_path->length] = '\0';
    1270             : 
    1271             :     /* Link to the chain */
    1272       74166 :     new_name_path->previous_path = *name_path;
    1273       74166 :     *name_path = new_name_path;
    1274             : 
    1275             :     TRACE_INFO_STRING("Constructed path", new_name_path->name);
    1276             : 
    1277             : 
    1278             :     TRACE_FLOW_NUMBER("col_create_path_data. Returning:", error);
    1279       74166 :     return error;
    1280             : }
    1281             : 
    1282             : /* Matching item name and type */
    1283   124997608 : static int col_match_item(struct collection_item *current,
    1284             :                           struct find_name *traverse_data)
    1285             : {
    1286             : 
    1287             :     const char *find_str;
    1288             :     const char *start;
    1289             :     const char *data_str;
    1290             : 
    1291             :     TRACE_FLOW_STRING("col_match_item", "Entry");
    1292             : 
    1293   124997608 :     if (traverse_data->type_to_match & current->type) {
    1294             : 
    1295             :         /* Check if there is any value to match */
    1296   249990697 :         if ((traverse_data->name_to_find == NULL) ||
    1297   124995348 :             (*(traverse_data->name_to_find) == '\0')) {
    1298             :             TRACE_INFO_STRING("col_match_item",
    1299             :                               "Returning MATCH because there is no search criteria!");
    1300           2 :             return COL_MATCH;
    1301             :         }
    1302             : 
    1303             :         /* Check the hashes - if they do not match return */
    1304   124995347 :         if (traverse_data->hash != current->phash) {
    1305             :             TRACE_INFO_STRING("col_match_item","Returning NO match!");
    1306   124994692 :             return COL_NOMATCH;
    1307             :         }
    1308             : 
    1309             :         /* We will do the actual string comparison only if the hashes matched */
    1310             : 
    1311             :         /* Start comparing the two strings from the end */
    1312         655 :         find_str = traverse_data->name_to_find + traverse_data->name_len_to_find;
    1313         655 :         start = current->property;
    1314         655 :         data_str = start + current->property_len;
    1315             : 
    1316             :         TRACE_INFO_STRING("Searching for:", traverse_data->name_to_find);
    1317             :         TRACE_INFO_STRING("Item name:", current->property);
    1318             :         TRACE_INFO_STRING("Current path:", traverse_data->current_path->name);
    1319             :         TRACE_INFO_NUMBER("Searching:", toupper(*find_str));
    1320             :         TRACE_INFO_NUMBER("Have:", toupper(*data_str));
    1321             : 
    1322             :         /* We start pointing to 0 so the loop will be executed at least once */
    1323        5477 :         while (toupper(*data_str) == toupper(*find_str)) {
    1324             : 
    1325             :             TRACE_INFO_STRING("Loop iteration:","");
    1326             : 
    1327        4819 :             if (data_str == start) {
    1328         658 :                 if (find_str > traverse_data->name_to_find) {
    1329          16 :                     if (*(find_str-1) == '!') {
    1330             :                         /* We matched the property but the search string is
    1331             :                          * longer so we need to continue matching */
    1332             :                         TRACE_INFO_STRING("col_match_item",
    1333             :                                           "Need to continue matching");
    1334          16 :                         start = traverse_data->current_path->name;
    1335          16 :                         data_str = &start[traverse_data->current_path->length - 1];
    1336          16 :                         find_str -= 2;
    1337          16 :                         continue;
    1338             :                     }
    1339             :                     else {
    1340             :                         TRACE_INFO_STRING("col_match_item","Returning NO match!");
    1341           0 :                         return COL_NOMATCH;
    1342             :                     }
    1343             :                 }
    1344             :                 else {
    1345             :                     TRACE_INFO_STRING("col_match_item","Returning MATCH!");
    1346         642 :                     return COL_MATCH;
    1347             :                 }
    1348             :             }
    1349        4171 :             else if ((find_str == traverse_data->name_to_find) &&
    1350          20 :                      (*(data_str-1) == '!')) return COL_MATCH;
    1351             : 
    1352        4151 :             data_str--;
    1353        4151 :             find_str--;
    1354             :             TRACE_INFO_NUMBER("Searching:", toupper(*find_str));
    1355             :             TRACE_INFO_NUMBER("Have:", toupper(*data_str));
    1356             : 
    1357             :         }
    1358             :     }
    1359             : 
    1360             :     TRACE_FLOW_STRING("col_match_item","Returning NO match!");
    1361        2262 :     return COL_NOMATCH;
    1362             : 
    1363             : }
    1364             : 
    1365             : /* Function to delete the data that contains search path */
    1366       74166 : static void col_delete_path_data(struct path_data *path)
    1367             : {
    1368             :     TRACE_FLOW_STRING("col_delete_path_data","Entry.");
    1369             : 
    1370       74166 :     if (path != NULL) {
    1371             :         TRACE_INFO_STRING("col_delete_path_data", "Item to delete exits.");
    1372       74166 :         if (path->previous_path != NULL) {
    1373             :             TRACE_INFO_STRING("col_delete_path_data",
    1374             :                               "But previous item to delete exits to. Nesting.");
    1375          34 :             col_delete_path_data(path->previous_path);
    1376             :         }
    1377       74166 :         if (path->name != NULL) {
    1378             :             TRACE_INFO_STRING("col_delete_path_data Deleting path:", path->name);
    1379       74166 :             free(path->name);
    1380             :         }
    1381             :         TRACE_INFO_STRING("col_delete_path_data", "Deleting path element");
    1382       74166 :         free(path);
    1383             :     }
    1384             :     TRACE_FLOW_STRING("col_delete_path_data", "Exit");
    1385       74166 : }
    1386             : 
    1387             : 
    1388             : /* MAIN TRAVERSAL FUNCTION */
    1389             : 
    1390             : /* Internal function to walk collection */
    1391             : /* For each item walked it will call traverse handler.
    1392             :    Traverse handler accepts: current item,
    1393             :    user provided item handler and user provided custom data. */
    1394             : /* See below different traverse handlers for different cases */
    1395       78903 : static int col_walk_items(struct collection_item *ci,
    1396             :                           int mode_flags,
    1397             :                           internal_item_fn traverse_handler,
    1398             :                           void *traverse_data,
    1399             :                           col_item_fn user_item_handler,
    1400             :                           void *custom_data,
    1401             :                           unsigned *depth)
    1402             : {
    1403             :     struct collection_item *current;
    1404       78903 :     struct collection_item *parent = NULL;
    1405             :     struct collection_item *sub;
    1406       78903 :     int stop = 0;
    1407       78903 :     int error = EOK;
    1408             : 
    1409             :     TRACE_FLOW_STRING("col_walk_items", "Entry.");
    1410             :     TRACE_INFO_NUMBER("Mode flags:", mode_flags);
    1411             : 
    1412             :     /* Increase depth */
    1413             :     /* NOTE: The depth is increased at the entry to the function.
    1414             :      * and decreased right before the exit so it is safe to decrease it.
    1415             :      */
    1416       78903 :     (*depth)++;
    1417             : 
    1418       78903 :     current = ci;
    1419             : 
    1420   125437065 :     while (current) {
    1421             : 
    1422             :         TRACE_INFO_STRING("Processing item:", current->property);
    1423             :         TRACE_INFO_NUMBER("Item type:", current->type);
    1424             : 
    1425   125280156 :         if (current->type == COL_TYPE_COLLECTIONREF) {
    1426             : 
    1427             :             TRACE_INFO_STRING("Subcollection:", current->property);
    1428             : 
    1429        9461 :             if ((mode_flags & COL_TRAVERSE_IGNORE) == 0) {
    1430             : 
    1431             :                 TRACE_INFO_STRING("Subcollection is not ignored.", "");
    1432             :                 /* We are not ignoring sub collections */
    1433             : 
    1434        9461 :                 if ((mode_flags & COL_TRAVERSE_FLAT) == 0) {
    1435             : 
    1436             :                     TRACE_INFO_STRING("Subcollection is not flattened.", "");
    1437             :                     /* We are not flattening sub collections.
    1438             :                      * The flattening means that we are not going
    1439             :                      * to return reference and headers for sub collections.
    1440             :                      * We will also not do special end collection
    1441             :                      * invocation for sub collections.
    1442             :                      */
    1443        9461 :                     error = traverse_handler(ci, parent, current, traverse_data,
    1444             :                                              user_item_handler, custom_data, &stop);
    1445        9461 :                     if (stop != 0) {
    1446             :                         TRACE_INFO_STRING("Traverse handler returned STOP.", "");
    1447         206 :                         error = EINTR_INTERNAL;
    1448             :                     }
    1449             :                     /* Check what error we got */
    1450        9461 :                     if (error == EINTR_INTERNAL) {
    1451             :                         TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error);
    1452         206 :                         (*depth)--;
    1453         206 :                         return error;
    1454             :                     }
    1455        9255 :                     else if (error) {
    1456             :                         TRACE_ERROR_NUMBER("Traverse handler returned error.", error);
    1457           0 :                         (*depth)--;
    1458           0 :                         return error;
    1459             :                     }
    1460             :                 }
    1461             : 
    1462        9255 :                 if ((mode_flags & COL_TRAVERSE_ONELEVEL) == 0) {
    1463             :                     TRACE_INFO_STRING("Before diving into sub collection","");
    1464        7916 :                     sub = *((struct collection_item **)(current->data));
    1465             :                     TRACE_INFO_STRING("Sub collection name", sub->property);
    1466             :                     TRACE_INFO_NUMBER("Header type", sub->type);
    1467             :                     /* We need to go into sub collections */
    1468        7916 :                     error = col_walk_items(sub, mode_flags,
    1469             :                                            traverse_handler, traverse_data,
    1470             :                                            user_item_handler, custom_data,
    1471             :                                            depth);
    1472             :                     TRACE_INFO_STRING("Returned from sub collection processing", "");
    1473             :                     TRACE_INFO_STRING("Done processing item:", current->property);
    1474             :                     TRACE_INFO_NUMBER("Done processing item type:", current->type);
    1475             : 
    1476             :                 }
    1477             :             }
    1478             :         }
    1479             :         else {
    1480             :             /* Check if it is a header and we are not on the root level.
    1481             :              * If we are flattening collection we need to skip headers
    1482             :              * for sub collections.
    1483             :              */
    1484             : 
    1485             :             /* Call handler if:
    1486             :              * a) It is not collection header
    1487             :              * OR
    1488             :              * b) It is header we are flattening but we are on top level
    1489             :              * OR
    1490             :              * c) It is header and we are not flattening.
    1491             :              */
    1492   125349598 :             if ((current->type != COL_TYPE_COLLECTION) ||
    1493      157806 :                 (((mode_flags & COL_TRAVERSE_FLAT) != 0) && (*depth == 1)) ||
    1494       78902 :                 ((mode_flags & COL_TRAVERSE_FLAT) == 0)) {
    1495             :                 /* Call handler then move on */
    1496   125270695 :                 error = traverse_handler(ci, parent, current,
    1497             :                                          traverse_data, user_item_handler,
    1498             :                                          custom_data, &stop);
    1499             : 
    1500             :             }
    1501             :         }
    1502             :         /* If we are stopped - return EINTR_INTERNAL */
    1503   125279950 :         if (stop != 0) {
    1504             :             TRACE_INFO_STRING("Traverse handler returned STOP.", "");
    1505         657 :             error = EINTR_INTERNAL;
    1506             :         }
    1507             :         /* Check what error we got */
    1508   125279950 :         if (error == EINTR_INTERNAL) {
    1509             :             TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error);
    1510         691 :             (*depth)--;
    1511         691 :             return error;
    1512             :         }
    1513   125279259 :         else if (error) {
    1514             :             TRACE_ERROR_NUMBER("Traverse handler returned error.", error);
    1515           0 :             (*depth)--;
    1516           0 :             return error;
    1517             :         }
    1518             : 
    1519             :         TRACE_INFO_NUMBER("Next element", current->next);
    1520             : 
    1521   125279259 :         parent = current;
    1522   125279259 :         current = current->next;
    1523             :     }
    1524             : 
    1525             :     TRACE_INFO_STRING("Out of loop", "");
    1526             : 
    1527             :     /* Check if we need to have a special
    1528             :      * call at the end of the collection.
    1529             :      */
    1530       78006 :     if ((mode_flags & COL_TRAVERSE_END) != 0) {
    1531             : 
    1532             :         /* Do this dummy invocation only:
    1533             :          * a) If we are flattening and on the root level
    1534             :          * b) We are not flattening
    1535             :          */
    1536      146956 :         if ((((mode_flags & COL_TRAVERSE_FLAT) != 0) && (*depth == 1)) ||
    1537       73478 :             ((mode_flags & COL_TRAVERSE_FLAT) == 0)) {
    1538             : 
    1539             :             TRACE_INFO_STRING("About to do the special end collection invocation of handler", "");
    1540       73478 :             error = traverse_handler(ci, parent, current,
    1541             :                                      traverse_data, user_item_handler,
    1542             :                                      custom_data, &stop);
    1543             :         }
    1544             :     }
    1545             : 
    1546             :     TRACE_FLOW_NUMBER("col_walk_items. Returns: ", error);
    1547       78006 :     (*depth)--;
    1548       78006 :     return error;
    1549             : }
    1550             : 
    1551             : 
    1552             : /* ACTION */
    1553             : 
    1554             : /* Find an item by property name and perform an action on it. */
    1555             : /* No pattern matching supported in the first implementation. */
    1556             : /* To refer to child properties use notatation like this: */
    1557             : /* parent!child!subchild!subsubchild etc.  */
    1558       68602 : static int col_find_item_and_do(struct collection_item *ci,
    1559             :                                 const char *property_to_find,
    1560             :                                 int type,
    1561             :                                 int mode_flags,
    1562             :                                 col_item_fn item_handler,
    1563             :                                 void *custom_data,
    1564             :                                 int action)
    1565             : {
    1566             : 
    1567       68602 :     int error = EOK;
    1568       68602 :     struct find_name *traverse_data = NULL;
    1569       68602 :     unsigned depth = 0;
    1570       68602 :     int count = 0;
    1571             :     const char *last_part;
    1572             :     char *sep;
    1573             : 
    1574             :     TRACE_FLOW_STRING("col_find_item_and_do", "Entry.");
    1575             : 
    1576             :     /* Item handler is always required */
    1577       68602 :     if ((item_handler == NULL) &&
    1578             :         (action == COLLECTION_ACTION_FIND)) {
    1579             :         TRACE_ERROR_NUMBER("No item handler - returning error!", EINVAL);
    1580           0 :         return EINVAL;
    1581             :     }
    1582             : 
    1583             :     /* Collection is requered */
    1584       68602 :     if (ci == NULL) {
    1585             :         TRACE_ERROR_NUMBER("No collection to search!", EINVAL);
    1586           0 :         return EINVAL;
    1587             :     }
    1588             : 
    1589             :     /* Make sure that there is anything to search */
    1590       68602 :     type &= COL_TYPE_ANY;
    1591       68602 :     if ((type == 0) && 
    1592           1 :         ((property_to_find == NULL) || 
    1593           1 :          ((property_to_find != NULL) && (*property_to_find == '\0')))) {
    1594             :         TRACE_ERROR_NUMBER("No item search criteria specified - returning error!", ENOENT);
    1595           2 :         return ENOENT;
    1596             :     }
    1597             : 
    1598             :     /* Prepare data for traversal */
    1599       68600 :     traverse_data = (struct find_name *)malloc(sizeof(struct find_name));
    1600       68600 :     if (traverse_data == NULL) {
    1601             :         TRACE_ERROR_NUMBER("Failed to allocate traverse data memory - returning error!", ENOMEM);
    1602           0 :         return ENOMEM;
    1603             :     }
    1604             : 
    1605             :     TRACE_INFO_STRING("col_find_item_and_do", "Filling in traverse data.");
    1606             : 
    1607       68600 :     traverse_data->name_to_find = property_to_find;
    1608             : 
    1609       68600 :     if (property_to_find != NULL) {
    1610             : 
    1611       68599 :         traverse_data->name_len_to_find = strlen(property_to_find);
    1612             : 
    1613             :         /* Check if the search string ends with "!" - this is illegal */
    1614       68599 :         if (traverse_data->name_to_find[traverse_data->name_len_to_find - 1] == '!') {
    1615             :             TRACE_ERROR_NUMBER("Search string is invalid.", EINVAL);
    1616           1 :             free(traverse_data);
    1617           1 :             return EINVAL;
    1618             :         }
    1619             : 
    1620             :         /* Find last ! if any */
    1621       68598 :         sep = strrchr(traverse_data->name_to_find, '!');
    1622       68598 :         if (sep != NULL) {
    1623          13 :             sep++;
    1624          13 :             last_part = sep;
    1625             :         }
    1626       68585 :         else last_part = traverse_data->name_to_find;
    1627             : 
    1628             :         TRACE_INFO_STRING("Last item", last_part);
    1629             : 
    1630             :         /* Create hash of the last part */
    1631       68598 :         traverse_data->hash = FNV1a_base;
    1632             : 
    1633             :         /* Create hash of the string to search */
    1634     1985707 :         while(last_part[count] != 0) {
    1635     1848511 :             traverse_data->hash = traverse_data->hash ^ toupper(last_part[count]);
    1636     1848511 :             traverse_data->hash *= FNV1a_prime;
    1637     1848511 :             count++;
    1638             :         }
    1639             :     }
    1640             :     else {
    1641             :         /* We a looking for a first element of a given type */
    1642             :         TRACE_INFO_STRING("No search string", "");
    1643           1 :         traverse_data->name_len_to_find = 0;
    1644             :     }
    1645             : 
    1646             : 
    1647       68599 :     traverse_data->type_to_match = type;
    1648       68599 :     traverse_data->given_name = NULL;
    1649       68599 :     traverse_data->given_len = 0;
    1650       68599 :     traverse_data->current_path = NULL;
    1651       68599 :     traverse_data->action = action;
    1652             : 
    1653       68599 :     mode_flags |= COL_TRAVERSE_END;
    1654             : 
    1655             :     TRACE_INFO_STRING("col_find_item_and_do", "About to walk the tree.");
    1656             :     TRACE_INFO_NUMBER("Traverse flags", mode_flags);
    1657             : 
    1658       68599 :     error = col_walk_items(ci, mode_flags, col_act_traverse_handler,
    1659             :                            (void *)traverse_data, item_handler, custom_data,
    1660             :                            &depth);
    1661             : 
    1662       68599 :     if (traverse_data->current_path != NULL) {
    1663             :         TRACE_INFO_STRING("find_item_and_do",
    1664             :                           "Path was not cleared - deleting");
    1665         654 :         col_delete_path_data(traverse_data->current_path);
    1666             :     }
    1667             : 
    1668       68599 :     free(traverse_data);
    1669             : 
    1670       68599 :     if (error && (error != EINTR_INTERNAL)) {
    1671             :         TRACE_ERROR_NUMBER("Walk items returned error. Returning: ", error);
    1672           0 :         return error;
    1673             :     }
    1674             :     else {
    1675             :         TRACE_FLOW_STRING("Walk items returned SUCCESS.", "");
    1676       68599 :         return EOK;
    1677             :     }
    1678             : }
    1679             : 
    1680             : /* Function to replace data in the item */
    1681           1 : static int col_update_current_item(struct collection_item *current,
    1682             :                                    struct update_property *update_data)
    1683             : {
    1684             :     TRACE_FLOW_STRING("col_update_current_item", "Entry");
    1685             : 
    1686             :     /* If type is different or same but it is string or binary we need to
    1687             :      * replace the storage */
    1688           2 :     if ((current->type != update_data->type) ||
    1689           2 :         ((current->type == update_data->type) &&
    1690           2 :         ((current->type == COL_TYPE_STRING) ||
    1691           1 :          (current->type == COL_TYPE_BINARY)))) {
    1692             :         TRACE_INFO_STRING("Replacing item data buffer", "");
    1693           0 :         free(current->data);
    1694           0 :         current->data = malloc(update_data->length);
    1695           0 :         if (current->data == NULL) {
    1696             :             TRACE_ERROR_STRING("Failed to allocate memory", "");
    1697           0 :             current->length = 0;
    1698           0 :             return ENOMEM;
    1699             :         }
    1700           0 :         current->length = update_data->length;
    1701             :     }
    1702             : 
    1703             :     TRACE_INFO_STRING("Overwriting item data", "");
    1704           1 :     memcpy(current->data, update_data->data, current->length);
    1705           1 :     current->type = update_data->type;
    1706             : 
    1707           1 :     if (current->type == COL_TYPE_STRING)
    1708           0 :         ((char *)(current->data))[current->length-1] = '\0';
    1709             : 
    1710             :     TRACE_FLOW_STRING("update_current_item", "Exit");
    1711           1 :     return EOK;
    1712             : }
    1713             : 
    1714             : /* TRAVERSE CALLBACKS */
    1715             : 
    1716             : /* Traverse handler for simple traverse function */
    1717             : /* Handler must be able to deal with NULL current item */
    1718      137420 : static int col_simple_traverse_handler(struct collection_item *head,
    1719             :                                        struct collection_item *previous,
    1720             :                                        struct collection_item *current,
    1721             :                                        void *traverse_data,
    1722             :                                        col_item_fn user_item_handler,
    1723             :                                        void *custom_data,
    1724             :                                        int *stop)
    1725             : {
    1726      137420 :     int error = EOK;
    1727             :     struct collection_item end_item;
    1728      137420 :     char zero = '\0';
    1729             : 
    1730             :     TRACE_FLOW_STRING("col_simple_traverse_handler", "Entry.");
    1731             : 
    1732      137420 :     if (current == NULL) {
    1733           0 :         memset((void *)&end_item, 0, sizeof(struct collection_item));
    1734           0 :         end_item.type = COL_TYPE_END;
    1735           0 :         end_item.property = &zero;
    1736           0 :         current = &end_item;
    1737             :     }
    1738             : 
    1739      137420 :     error = user_item_handler(current->property,
    1740             :                               current->property_len,
    1741             :                               current->type,
    1742             :                               current->data,
    1743             :                               current->length,
    1744             :                               custom_data,
    1745             :                               stop);
    1746             : 
    1747             :     TRACE_FLOW_NUMBER("col_simple_traverse_handler. Returning:", error);
    1748      137420 :     return error;
    1749             : }
    1750             : 
    1751             : /* Traverse handler for to find parent */
    1752        2111 : static int col_parent_traverse_handler(struct collection_item *head,
    1753             :                                        struct collection_item *previous,
    1754             :                                        struct collection_item *current,
    1755             :                                        void *traverse_data,
    1756             :                                        col_item_fn user_item_handler,
    1757             :                                        void *custom_data,
    1758             :                                        int *stop)
    1759             : {
    1760             :     struct property_search *to_find;
    1761        2111 :     int done = 0;
    1762        2111 :     int match = 0;
    1763             : 
    1764             :     TRACE_FLOW_STRING("col_parent_traverse_handler", "Entry.");
    1765             : 
    1766        2111 :     to_find = (struct property_search *)custom_data;
    1767             : 
    1768             :     TRACE_INFO_NUMBER("Looking for HASH:", (unsigned)(to_find->hash));
    1769             :     TRACE_INFO_NUMBER("Current HASH:", (unsigned)(current->phash));
    1770             : 
    1771             :     /* Check hashes first */
    1772        2111 :     if(to_find->hash == current->phash) {
    1773             : 
    1774             :         /* Check type if we are asked to use type */
    1775         203 :         if ((to_find->use_type) && (!(to_find->type & current->type))) {
    1776             :             TRACE_FLOW_STRING("parent_traverse_handler. Returning:","Exit. Hash is Ok, type is not");
    1777           0 :             return EOK;
    1778             :         }
    1779             : 
    1780             :         /* Validate property. Make sure we include terminating 0 in the comparison */
    1781         203 :         if (strncasecmp(current->property, to_find->property, current->property_len + 1) == 0) {
    1782             : 
    1783         203 :             match = 1;
    1784         203 :             to_find->found = 1;
    1785             : 
    1786             :             /* Do the right thing based on index */
    1787             :             /* If index is 0 we are looking for the first value in the list of duplicate properties */
    1788         203 :             if (to_find->index == 0) done = 1;
    1789             :             /* If index is non zero we are looking for N-th instance of the dup property */
    1790          11 :             else if (to_find->index > 0) {
    1791           5 :                 if (to_find->count == to_find->index) done = 1;
    1792             :                 else {
    1793             :                     /* Record found instance and move on */
    1794           3 :                     to_find->parent = previous;
    1795           3 :                     (to_find->count)++;
    1796             :                 }
    1797             :             }
    1798             :             /* If we are looking for last instance just record it */
    1799           6 :             else to_find->parent = previous;
    1800             :         }
    1801             :     }
    1802             : 
    1803        2111 :     if (done) {
    1804         194 :         *stop = 1;
    1805         194 :         *((struct collection_item **)traverse_data) = previous;
    1806             :     }
    1807             :     else {
    1808             :         /* As soon as we found first non matching one but there was a match
    1809             :          * return the parent of the last found item.
    1810             :          */
    1811        1917 :         if (((!match) || (current->next == NULL)) && (to_find->index != 0) && (to_find->found)) {
    1812           4 :             *stop = 1;
    1813           4 :             if (to_find->index == -2)
    1814           1 :                 *((struct collection_item **)traverse_data) = to_find->parent;
    1815             :             else
    1816           3 :                 *((struct collection_item **)traverse_data) = to_find->parent->next;
    1817             :         }
    1818             :     }
    1819             : 
    1820             : 
    1821             :     TRACE_FLOW_STRING("col_parent_traverse_handler. Returning:","Exit");
    1822        2111 :     return EOK;
    1823             : }
    1824             : 
    1825             : 
    1826             : /* Traverse callback for find & delete function */
    1827   125145246 : static int col_act_traverse_handler(struct collection_item *head,
    1828             :                                     struct collection_item *previous,
    1829             :                                     struct collection_item *current,
    1830             :                                     void *passed_traverse_data,
    1831             :                                     col_item_fn user_item_handler,
    1832             :                                     void *custom_data,
    1833             :                                     int *stop)
    1834             : {
    1835   125145246 :     int error = EOK;
    1836   125145246 :     struct find_name *traverse_data = NULL;
    1837             :     char *name;
    1838             :     int length;
    1839             :     struct path_data *temp;
    1840             :     struct collection_header *header;
    1841             :     char *property;
    1842             :     int property_len;
    1843             :     struct update_property *update_data;
    1844             : 
    1845             :     TRACE_FLOW_STRING("col_act_traverse_handler", "Entry.");
    1846             : 
    1847   125145246 :     traverse_data = (struct find_name *)passed_traverse_data;
    1848             : 
    1849             :     /* We can be called when current points to NULL */
    1850   125145246 :     if (current == NULL) {
    1851             :         TRACE_INFO_STRING("col_act_traverse_handler",
    1852             :                           "Special call at the end of the collection.");
    1853       73475 :         temp = traverse_data->current_path;
    1854       73475 :         traverse_data->current_path = temp->previous_path;
    1855       73475 :         temp->previous_path = NULL;
    1856       73475 :         col_delete_path_data(temp);
    1857       73475 :         traverse_data->given_name = NULL;
    1858       73475 :         traverse_data->given_len = 0;
    1859             :         TRACE_FLOW_NUMBER("Handling end of collection - removed path. Returning:", error);
    1860       73475 :         return error;
    1861             :     }
    1862             : 
    1863             :     /* Create new path at the beginning of a new sub collection */
    1864   125071771 :     if (current->type == COL_TYPE_COLLECTION) {
    1865             : 
    1866             :         TRACE_INFO_STRING("col_act_traverse_handler",
    1867             :                           "Processing collection handle.");
    1868             : 
    1869             :         /* Create new path */
    1870       74163 :         if (traverse_data->current_path != NULL) {
    1871             :             TRACE_INFO_STRING("Already have part of the path", "");
    1872        5564 :             name = traverse_data->current_path->name;
    1873        5564 :             length = traverse_data->current_path->length;
    1874             :             TRACE_INFO_STRING("Path:", name);
    1875             :             TRACE_INFO_NUMBER("Path len:", length);
    1876             :         }
    1877             :         else {
    1878       68599 :             name = NULL;
    1879       68599 :             length = 0;
    1880             :         }
    1881             : 
    1882       74163 :         if (traverse_data->given_name != NULL) {
    1883        5564 :             property = traverse_data->given_name;
    1884        5564 :             property_len = traverse_data->given_len;
    1885             :         }
    1886             :         else {
    1887       68599 :             property = current->property;
    1888       68599 :             property_len = current->property_len;
    1889             :         }
    1890             : 
    1891             :         TRACE_INFO_STRING("col_act_traverse_handler", "About to create path data.");
    1892             : 
    1893       74163 :         error = col_create_path_data(&(traverse_data->current_path),
    1894             :                                      name, length,
    1895             :                                      property, property_len, '!');
    1896             : 
    1897             :         TRACE_INFO_NUMBER("col_create_path_data returned:", error);
    1898       74163 :         return error;
    1899             :     }
    1900             : 
    1901             :     /* Handle the collection pointers */
    1902   124997608 :     if (current->type == COL_TYPE_COLLECTIONREF) {
    1903        5853 :         traverse_data->given_name = current->property;
    1904        5853 :         traverse_data->given_len = current->property_len;
    1905             :         TRACE_INFO_STRING("Saved given name:", traverse_data->given_name);
    1906             :     }
    1907             : 
    1908             :     TRACE_INFO_STRING("Processing item with property:", current->property);
    1909             : 
    1910             :     /* Do here what we do with items */
    1911   124997608 :     if (col_match_item(current, traverse_data)) {
    1912             :         TRACE_INFO_STRING("Matched item:", current->property);
    1913         654 :         switch (traverse_data->action) {
    1914             :         case COLLECTION_ACTION_FIND:
    1915             :             TRACE_INFO_STRING("It is a find action - calling handler.", "");
    1916         145 :             if (user_item_handler != NULL) {
    1917             :                 /* Call user handler */
    1918         145 :                 error = user_item_handler(current->property,
    1919             :                                           current->property_len,
    1920             :                                           current->type,
    1921             :                                           current->data,
    1922             :                                           current->length,
    1923             :                                           custom_data,
    1924             :                                           stop);
    1925             : 
    1926             :                 TRACE_INFO_NUMBER("Handler returned:", error);
    1927             :                 TRACE_INFO_NUMBER("Handler set STOP to:", *stop);
    1928             : 
    1929             :             }
    1930         145 :             break;
    1931             : 
    1932             :         case COLLECTION_ACTION_GET:
    1933             :             TRACE_INFO_STRING("It is a get action.", "");
    1934         505 :             if (custom_data != NULL)
    1935         505 :                 *((struct collection_item **)(custom_data)) = current;
    1936         505 :             break;
    1937             : 
    1938             :         case COLLECTION_ACTION_DEL:
    1939             :             TRACE_INFO_STRING("It is a delete action.", "");
    1940             :             /* Make sure we tell the caller we found a match */
    1941           3 :             if (custom_data != NULL)
    1942           3 :                 *(int *)custom_data = COL_MATCH;
    1943             : 
    1944             :             /* Adjust header of the collection */
    1945           3 :             header = (struct collection_header *)head->data;
    1946           3 :             header->count--;
    1947           3 :             if (current->next == NULL)
    1948           3 :                 header->last = previous;
    1949             : 
    1950             :             /* Unlink and delete iteam */
    1951             :             /* Previous can't be NULL here becuase we never delete
    1952             :              * header elements */
    1953           3 :             previous->next = current->next;
    1954           3 :             col_delete_item(current);
    1955             :             TRACE_INFO_STRING("Did the delete of the item.", "");
    1956           3 :             break;
    1957             : 
    1958             :         case COLLECTION_ACTION_UPDATE:
    1959             :             TRACE_INFO_STRING("It is an update action.", "");
    1960           2 :             if((current->type == COL_TYPE_COLLECTION) ||
    1961           1 :                (current->type == COL_TYPE_COLLECTIONREF)) {
    1962             :                 TRACE_ERROR_STRING("Can't update collections it is an error for now", "");
    1963           0 :                 return EINVAL;
    1964             :             }
    1965             : 
    1966             :             /* Make sure we tell the caller we found a match */
    1967           1 :             if (custom_data != NULL) {
    1968           1 :                 update_data = (struct update_property *)custom_data;
    1969           1 :                 update_data->found = COL_MATCH;
    1970           1 :                 error = col_update_current_item(current, update_data);
    1971             :             }
    1972             :             else {
    1973             :                 TRACE_ERROR_STRING("Error - update data is required", "");
    1974           0 :                 return EINVAL;
    1975             :             }
    1976             : 
    1977             :             TRACE_INFO_STRING("Did the delete of the item.", "");
    1978           1 :             break;
    1979             :         default:
    1980           0 :             break;
    1981             :         }
    1982             :         /* Force interrupt if we found */
    1983         654 :         *stop = 1;
    1984             :     }
    1985             : 
    1986             :     TRACE_FLOW_NUMBER("col_act_traverse_handler returning", error);
    1987   124997608 :     return error;
    1988             : }
    1989             : 
    1990             : 
    1991             : /* Traverse handler for copy function */
    1992       68857 : static int col_copy_traverse_handler(struct collection_item *head,
    1993             :                                      struct collection_item *previous,
    1994             :                                      struct collection_item *current,
    1995             :                                      void *passed_traverse_data,
    1996             :                                      col_item_fn user_item_handler,
    1997             :                                      void *custom_data,
    1998             :                                      int *stop)
    1999             : {
    2000       68857 :     int error = EOK;
    2001             :     struct collection_item *parent;
    2002       68857 :     struct collection_item *other = NULL;
    2003             :     struct col_copy *traverse_data;
    2004             :     struct path_data *temp;
    2005             :     char *name;
    2006             :     int length;
    2007       68857 :     char *property = NULL;
    2008             :     int property_len;
    2009             :     struct collection_header *header;
    2010             :     char *offset;
    2011             : 
    2012             :     TRACE_FLOW_STRING("col_copy_traverse_handler", "Entry.");
    2013             : 
    2014       68857 :     parent = (struct collection_item *)custom_data;
    2015       68857 :     traverse_data = (struct col_copy *)passed_traverse_data;
    2016             : 
    2017             :     /* We can be called when current points to NULL */
    2018             :     /* This will happen only in the FLATDOT case */
    2019       68857 :     if (current == NULL) {
    2020             :         TRACE_INFO_STRING("col_copy_traverse_handler",
    2021             :                           "Special call at the end of the collection.");
    2022           3 :         temp = traverse_data->current_path;
    2023           3 :         traverse_data->current_path = temp->previous_path;
    2024           3 :         temp->previous_path = NULL;
    2025           3 :         col_delete_path_data(temp);
    2026           3 :         traverse_data->given_name = NULL;
    2027           3 :         traverse_data->given_len = 0;
    2028             :         TRACE_FLOW_NUMBER("Handling end of collection - removed path. Returning:", error);
    2029           3 :         return error;
    2030             :     }
    2031             : 
    2032             :     /* Create new path at the beginning of a new sub collection */
    2033       68854 :     if (current->type == COL_TYPE_COLLECTION) {
    2034             : 
    2035             :         TRACE_INFO_STRING("col_copy_traverse_handler",
    2036             :                           "Processing collection handle.");
    2037        1398 :         if (traverse_data->mode == COL_COPY_FLATDOT) {
    2038             :             /* Create new path */
    2039           3 :             if (traverse_data->current_path != NULL) {
    2040             :                 TRACE_INFO_STRING("Already have part of the path", "");
    2041           0 :                 name = traverse_data->current_path->name;
    2042           0 :                 length = traverse_data->current_path->length;
    2043             :                 TRACE_INFO_STRING("Path:", name);
    2044             :                 TRACE_INFO_NUMBER("Path len:", length);
    2045           0 :                 if (traverse_data->given_name != NULL) {
    2046           0 :                     property = traverse_data->given_name;
    2047           0 :                     property_len = traverse_data->given_len;
    2048             :                 }
    2049             :                 else {
    2050           0 :                     property = current->property;
    2051           0 :                     property_len = current->property_len;
    2052             :                 }
    2053             :             }
    2054             :             else {
    2055             :                 /* Do not create prefix for top collection
    2056             :                  * if there is no given name.
    2057             :                  */
    2058           3 :                 name = NULL;
    2059           3 :                 length = 0;
    2060           3 :                 if (traverse_data->given_name != NULL) {
    2061           1 :                     property = traverse_data->given_name;
    2062           1 :                     property_len = traverse_data->given_len;
    2063             :                 }
    2064             :                 else {
    2065           2 :                     property = NULL;
    2066           2 :                     property_len = 0;
    2067             :                 }
    2068             :             }
    2069             : 
    2070             :             TRACE_INFO_STRING("col_copy_traverse_handler", "About to create path data.");
    2071             : 
    2072           3 :             error = col_create_path_data(&(traverse_data->current_path),
    2073             :                                          name, length,
    2074             :                                          property, property_len, '.');
    2075             : 
    2076             :             TRACE_FLOW_NUMBER("col_copy_traverse_handler processed header:", error);
    2077           3 :             return error;
    2078             :         }
    2079             :         else {
    2080             :             TRACE_FLOW_NUMBER("col_copy_traverse_handler skipping the header:", error);
    2081        1395 :             return error;
    2082             :         }
    2083             :     }
    2084             : 
    2085             : 
    2086             :     /* Check if this is a special case of sub collection */
    2087       67456 :     if (current->type == COL_TYPE_COLLECTIONREF) {
    2088             : 
    2089             :         TRACE_INFO_STRING("Found a subcollection we need to copy. Name:",
    2090             :                           current->property);
    2091             : 
    2092             :         /* Based on the mode we need to do different things */
    2093        1195 :         switch (traverse_data->mode) {
    2094             :         case COL_COPY_NORMAL:
    2095             : 
    2096        2390 :             error = col_copy_collection_with_cb(&other,
    2097        1195 :                                         *((struct collection_item **)(current->data)),
    2098        1195 :                                         current->property,
    2099             :                                         COL_COPY_NORMAL,
    2100             :                                         traverse_data->copy_cb,
    2101             :                                         traverse_data->ext_data);
    2102        1195 :             if (error) {
    2103             :                 TRACE_ERROR_NUMBER("Copy subcollection returned error:", error);
    2104           0 :                 return error;
    2105             :             }
    2106             : 
    2107             :             /* Add new item to a collection
    2108             :              * all references are now sub collections */
    2109        1195 :             error = col_insert_property_with_ref_int(parent,
    2110             :                                                      NULL,
    2111             :                                                      COL_DSP_END,
    2112             :                                                      NULL,
    2113             :                                                      0,
    2114             :                                                      0,
    2115        1195 :                                                      current->property,
    2116             :                                                      COL_TYPE_COLLECTIONREF,
    2117             :                                                      (void *)(&other),
    2118             :                                                      sizeof(struct collection_item **),
    2119             :                                                      NULL);
    2120             : 
    2121             :             TRACE_FLOW_NUMBER("col_copy_traverse_handler returning in NORMAL mode:", error);
    2122        1195 :             return error;
    2123             : 
    2124             :        case COL_COPY_KEEPREF:
    2125             : 
    2126             :             /* Just increase reference count of the referenced collection */
    2127           0 :                         other = *((struct collection_item **)(current->data));
    2128           0 :             header = (struct collection_header *)(other->data);
    2129           0 :             header->reference_count++;
    2130             : 
    2131             :             /* Add new item to a collection
    2132             :              * all references are now sub collections */
    2133           0 :             error = col_insert_property_with_ref_int(parent,
    2134             :                                                      NULL,
    2135             :                                                      COL_DSP_END,
    2136             :                                                      NULL,
    2137             :                                                      0,
    2138             :                                                      0,
    2139           0 :                                                      current->property,
    2140             :                                                      COL_TYPE_COLLECTIONREF,
    2141             :                                                      (void *)(&other),
    2142             :                                                      sizeof(struct collection_item **),
    2143             :                                                      NULL);
    2144             :             TRACE_FLOW_NUMBER("col_copy_traverse_handler returning in KEEPREF mode:", error);
    2145           0 :             return error;
    2146             : 
    2147             :         case COL_COPY_TOP:
    2148             :             /* Told to ignore sub collections */
    2149             :             TRACE_FLOW_NUMBER("col_copy_traverse_handler returning in TOP mode:", error);
    2150           0 :             return error;
    2151             : 
    2152             :         case COL_COPY_FLATDOT:
    2153             : 
    2154           0 :             traverse_data->given_name = current->property;
    2155           0 :             traverse_data->given_len = current->property_len;
    2156             :             TRACE_INFO_STRING("Saved given name:", traverse_data->given_name);
    2157             :             TRACE_FLOW_NUMBER("col_copy_traverse_handler returning in FLATDOT mode:", error);
    2158           0 :             return error;
    2159             : 
    2160             :         /* NOTE: The mode COL_COPY_FLAT is not in the list of cases becuase
    2161             :          * in this flat mode we traverse collection using COL_TRAVERSE_FLAT flag
    2162             :          * thus we should not be called on referenced collections at all
    2163             :          * by the col_walk_items() function.
    2164             :          */
    2165             : 
    2166             :         default:
    2167             :             TRACE_ERROR_NUMBER("col_copy_traverse_handler bad mode error:", EINVAL);
    2168           0 :             return EINVAL;
    2169             :         }
    2170             :     }
    2171             :     else {
    2172             : 
    2173       66261 :         if (traverse_data->mode == COL_COPY_FLATDOT) {
    2174             :             /* Since this code can't use asprintf have to do it hard way */
    2175          27 :             property = malloc(traverse_data->current_path->length +
    2176          18 :                               current->property_len + 2);
    2177           9 :             if (property == NULL) {
    2178             :                 TRACE_ERROR_NUMBER("Failed to allocate memory for a new name:", error);
    2179           0 :                 return error;
    2180             :             }
    2181             :             /* Add first part and dot only if we have prefix */
    2182           9 :             offset = property;
    2183           9 :             if (traverse_data->current_path->length) {
    2184           3 :                 memcpy(offset, traverse_data->current_path->name,
    2185           3 :                        traverse_data->current_path->length);
    2186           3 :                 offset[traverse_data->current_path->length] = '.';
    2187           3 :                 offset += traverse_data->current_path->length + 1;
    2188             :             }
    2189           9 :             memcpy(offset, current->property, current->property_len);
    2190           9 :             offset[current->property_len] = '\0';
    2191             :         }
    2192       66252 :         else property = current->property;
    2193             : 
    2194             :         TRACE_INFO_STRING("Using property:", property);
    2195             : 
    2196      132522 :         error = col_copy_item_with_cb(parent,
    2197             :                                       property,
    2198             :                                       current->type,
    2199       66261 :                                       current->data,
    2200             :                                       current->length,
    2201             :                                       traverse_data->copy_cb,
    2202             :                                       traverse_data->ext_data);
    2203             : 
    2204             :         /* Free property if we allocated it */
    2205       66261 :         if (traverse_data->mode == COL_COPY_FLATDOT) free(property);
    2206             : 
    2207       66261 :         if (error) {
    2208             :             TRACE_ERROR_NUMBER("Failed to copy property:", error);
    2209           0 :             return error;
    2210             :         }
    2211             :     }
    2212             : 
    2213             :     TRACE_FLOW_NUMBER("col_copy_traverse_handler returning", error);
    2214       66261 :     return error;
    2215             : }
    2216             : 
    2217             : 
    2218             : 
    2219             : 
    2220             : /********************* MAIN INTERFACE FUNCTIONS *****************************/
    2221             : 
    2222             : 
    2223             : /* CREATE */
    2224             : 
    2225             : /* Function that creates an named collection of a given class*/
    2226        3927 : int col_create_collection(struct collection_item **ci, const char *name,
    2227             :                           unsigned cclass)
    2228             : {
    2229        3927 :     struct collection_item *handle = NULL;
    2230             :     struct collection_header header;
    2231        3927 :     int error = EOK;
    2232             : 
    2233             :     TRACE_FLOW_STRING("col_create_collection", "Entry.");
    2234             : 
    2235             :     /* Prepare header */
    2236        3927 :     header.last = NULL;
    2237        3927 :     header.reference_count = 1;
    2238        3927 :     header.count = 0;
    2239        3927 :     header.cclass = cclass;
    2240             : 
    2241             :     /* Create a collection type property */
    2242        3927 :     error = col_insert_property_with_ref_int(NULL,
    2243             :                                              NULL,
    2244             :                                              COL_DSP_END,
    2245             :                                              NULL,
    2246             :                                              0,
    2247             :                                              0,
    2248             :                                              name,
    2249             :                                              COL_TYPE_COLLECTION,
    2250             :                                              &header,
    2251             :                                              sizeof(header),
    2252             :                                              &handle);
    2253             : 
    2254             : 
    2255        3927 :     if (error) return error;
    2256             : 
    2257        3927 :     *ci = handle;
    2258             : 
    2259             :     TRACE_FLOW_STRING("col_create_collection", "Success Exit.");
    2260        3927 :     return EOK;
    2261             : }
    2262             : 
    2263             : 
    2264             : /* DESTROY */
    2265             : 
    2266             : /* Function that destroys a collection */
    2267        4616 : void col_destroy_collection_with_cb(struct collection_item *ci,
    2268             :                                     col_item_cleanup_fn cb,
    2269             :                                     void *custom_data)
    2270             : {
    2271             :     struct collection_header *header;
    2272             : 
    2273             :     TRACE_FLOW_STRING("col_destroy_collection_with_cb", "Entry.");
    2274             : 
    2275             :     /* Do not try to delete NULL */
    2276        4616 :     if (ci == NULL) return;
    2277             : 
    2278             :     /* You can delete only whole collection not a part of it */
    2279        4155 :     if (ci->type != COL_TYPE_COLLECTION) {
    2280             :         TRACE_ERROR_STRING("Attempt to delete a non collection - BAD!", "");
    2281             :         TRACE_ERROR_NUMBER("Actual type is:", ci->type);
    2282           0 :         return;
    2283             :     }
    2284             : 
    2285             :     TRACE_INFO_STRING("Name:", ci->property);
    2286             : 
    2287             :     /* Collection can be referenced by other collection */
    2288        4155 :     header = (struct collection_header *)(ci->data);
    2289             :     TRACE_INFO_NUMBER("Reference count:", header->reference_count);
    2290        4155 :     if (header->reference_count > 1) {
    2291             :         TRACE_INFO_STRING("Dereferencing a referenced collection.", "");
    2292         228 :         header->reference_count--;
    2293             :         TRACE_INFO_NUMBER("Number after dereferencing.",
    2294             :                           header->reference_count);
    2295             :     }
    2296             :     else {
    2297        3927 :         col_delete_collection(ci, cb, custom_data);
    2298             :     }
    2299             : 
    2300             :     TRACE_FLOW_STRING("col_destroy_collection_with_cb", "Exit.");
    2301             : }
    2302             : 
    2303             : 
    2304             : /* Function that destroys a collection */
    2305         764 : void col_destroy_collection(struct collection_item *ci)
    2306             : {
    2307             :     TRACE_FLOW_STRING("col_destroy_collection", "Entry.");
    2308             : 
    2309         764 :     col_destroy_collection_with_cb(ci, NULL, NULL);
    2310             : 
    2311             :     TRACE_FLOW_STRING("col_destroy_collection", "Exit.");
    2312         764 : }
    2313             : 
    2314             : /* COPY */
    2315             : 
    2316             : /* Wrapper around a more advanced function */
    2317           2 : int col_copy_collection(struct collection_item **collection_copy,
    2318             :                         struct collection_item *collection_to_copy,
    2319             :                         const char *name_to_use,
    2320             :                         int copy_mode)
    2321             : {
    2322           2 :     int error = EOK;
    2323             :     TRACE_FLOW_STRING("col_copy_collection", "Entry.");
    2324             : 
    2325           2 :     error = col_copy_collection_with_cb(collection_copy,
    2326             :                                         collection_to_copy,
    2327             :                                         name_to_use,
    2328             :                                         copy_mode,
    2329             :                                         NULL,
    2330             :                                         NULL);
    2331             : 
    2332             :     TRACE_FLOW_NUMBER("col_copy_collection. Exit. Returning", error);
    2333           2 :     return error;
    2334             : }
    2335             : 
    2336             : /* Create a deep copy of the current collection. */
    2337             : /* Referenced collections of the donor are copied as sub collections. */
    2338        1395 : int col_copy_collection_with_cb(struct collection_item **collection_copy,
    2339             :                                 struct collection_item *collection_to_copy,
    2340             :                                 const char *name_to_use,
    2341             :                                 int copy_mode,
    2342             :                                 col_copy_cb copy_cb,
    2343             :                                 void *ext_data)
    2344             : {
    2345        1395 :     int error = EOK;
    2346        1395 :     struct collection_item *new_collection = NULL;
    2347             :     const char *name;
    2348             :     struct collection_header *header;
    2349        1395 :     unsigned depth = 0;
    2350             :     struct col_copy traverse_data;
    2351             :     int flags;
    2352             : 
    2353             :     TRACE_FLOW_STRING("col_copy_collection_with_cb", "Entry.");
    2354             : 
    2355             :     /* Collection is required */
    2356        1395 :     if (collection_to_copy == NULL) {
    2357             :         TRACE_ERROR_NUMBER("No collection to search!", EINVAL);
    2358           0 :         return EINVAL;
    2359             :     }
    2360             : 
    2361             :     /* Storage is required too */
    2362        1395 :     if (collection_copy == NULL) {
    2363             :         TRACE_ERROR_NUMBER("No memory provided to receive collection copy!", EINVAL);
    2364           0 :         return EINVAL;
    2365             :     }
    2366             : 
    2367             :     /* NOTE: Refine this check if adding a new copy mode */
    2368        1395 :     if ((copy_mode < 0) || (copy_mode > COL_COPY_TOP)) {
    2369             :         TRACE_ERROR_NUMBER("Invalid copy mode:", copy_mode);
    2370           0 :         return EINVAL;
    2371             :     }
    2372             : 
    2373             :     /* Determine what name to use */
    2374        1395 :     if (name_to_use != NULL)
    2375        1377 :         name = name_to_use;
    2376             :     else
    2377          18 :         name = collection_to_copy->property;
    2378             : 
    2379        1395 :     header = (struct collection_header *)collection_to_copy->data;
    2380             : 
    2381             :     /* Create a new collection */
    2382        1395 :     error = col_create_collection(&new_collection, name, header->cclass);
    2383        1395 :     if (error) {
    2384             :         TRACE_ERROR_NUMBER("col_create_collection failed returning", error);
    2385           0 :         return error;
    2386             :     }
    2387             : 
    2388        1395 :     traverse_data.mode = copy_mode;
    2389        1395 :     traverse_data.current_path = NULL;
    2390        1395 :     traverse_data.given_name = NULL;
    2391        1395 :     traverse_data.given_len = 0;
    2392        1395 :     traverse_data.copy_cb = copy_cb;
    2393        1395 :     traverse_data.ext_data = ext_data;
    2394             : 
    2395        1395 :     if (copy_mode == COL_COPY_FLATDOT) flags = COL_TRAVERSE_DEFAULT | COL_TRAVERSE_END;
    2396        1394 :     else if (copy_mode == COL_COPY_FLAT) flags = COL_TRAVERSE_FLAT;
    2397        1394 :     else flags = COL_TRAVERSE_ONELEVEL;
    2398             : 
    2399        1395 :     error = col_walk_items(collection_to_copy, flags,
    2400             :                            col_copy_traverse_handler, (void *)(&traverse_data),
    2401             :                            NULL, new_collection, &depth);
    2402             : 
    2403        1395 :     if (!error) *collection_copy = new_collection;
    2404           0 :     else col_destroy_collection(new_collection);
    2405             : 
    2406             :     TRACE_FLOW_NUMBER("col_copy_collection_with_cb returning", error);
    2407        1395 :     return error;
    2408             : 
    2409             : }
    2410             : 
    2411             : 
    2412             : /* EXTRACTION */
    2413             : 
    2414             : /* Extract collection */
    2415         128 : int col_get_collection_reference(struct collection_item *ci,
    2416             :                                  struct collection_item **acceptor,
    2417             :                                  const char *collection_to_find)
    2418             : {
    2419             :     struct collection_header *header;
    2420         128 :     struct collection_item *subcollection = NULL;
    2421         128 :     int error = EOK;
    2422             : 
    2423             :     TRACE_FLOW_STRING("col_get_collection_reference", "Entry.");
    2424             : 
    2425         256 :     if ((ci == NULL) ||
    2426         256 :         (ci->type != COL_TYPE_COLLECTION) ||
    2427             :         (acceptor == NULL)) {
    2428             :         TRACE_ERROR_NUMBER("Invalid parameter - returning error",EINVAL);
    2429           0 :         return EINVAL;
    2430             :     }
    2431             : 
    2432         128 :     if (collection_to_find) {
    2433             :         /* Find a sub collection */
    2434             :         TRACE_INFO_STRING("We are given subcollection name - search it:",
    2435             :                           collection_to_find);
    2436         127 :         error = col_find_item_and_do(ci, collection_to_find,
    2437             :                                      COL_TYPE_COLLECTIONREF,
    2438             :                                      COL_TRAVERSE_DEFAULT,
    2439             :                                      col_get_subcollection,
    2440             :                                      (void *)(&subcollection),
    2441             :                                      COLLECTION_ACTION_FIND);
    2442         127 :         if (error) {
    2443             :             TRACE_ERROR_NUMBER("Search failed returning error", error);
    2444           0 :             return error;
    2445             :         }
    2446             : 
    2447         127 :         if (subcollection == NULL) {
    2448             :             TRACE_ERROR_STRING("Search for subcollection returned NULL pointer", "");
    2449          55 :             return ENOENT;
    2450             :         }
    2451             :     }
    2452             :     else {
    2453             :         /* Create reference to the same collection */
    2454             :         TRACE_INFO_STRING("Creating reference to the top level collection.", "");
    2455           1 :         subcollection = ci;
    2456             :     }
    2457             : 
    2458          73 :     header = (struct collection_header *)subcollection->data;
    2459             :     TRACE_INFO_NUMBER("Count:", header->count);
    2460             :     TRACE_INFO_NUMBER("Ref count:", header->reference_count);
    2461          73 :     header->reference_count++;
    2462             :     TRACE_INFO_NUMBER("Ref count after increment:", header->reference_count);
    2463          73 :     *acceptor = subcollection;
    2464             : 
    2465             :     TRACE_FLOW_STRING("col_get_collection_reference", "Success Exit.");
    2466          73 :     return EOK;
    2467             : }
    2468             : 
    2469             : /* Get collection - if current item is a reference get a real collection from it. */
    2470           0 : int col_get_reference_from_item(struct collection_item *ci,
    2471             :                                 struct collection_item **acceptor)
    2472             : {
    2473             :     struct collection_header *header;
    2474           0 :     struct collection_item *subcollection = NULL;
    2475             : 
    2476             :     TRACE_FLOW_STRING("get_reference_from_item", "Entry.");
    2477             : 
    2478           0 :     if ((ci == NULL) ||
    2479           0 :         (ci->type != COL_TYPE_COLLECTIONREF) ||
    2480             :         (acceptor == NULL)) {
    2481             :         TRACE_ERROR_NUMBER("Invalid parameter - returning error",EINVAL);
    2482           0 :         return EINVAL;
    2483             :     }
    2484             : 
    2485           0 :     subcollection = *((struct collection_item **)ci->data);
    2486             : 
    2487           0 :     header = (struct collection_header *)subcollection->data;
    2488             :     TRACE_INFO_NUMBER("Count:", header->count);
    2489             :     TRACE_INFO_NUMBER("Ref count:", header->reference_count);
    2490           0 :     header->reference_count++;
    2491             :     TRACE_INFO_NUMBER("Ref count after increment:", header->reference_count);
    2492           0 :     *acceptor = subcollection;
    2493             : 
    2494             :     TRACE_FLOW_STRING("col_get_reference_from_item", "Success Exit.");
    2495           0 :     return EOK;
    2496             : }
    2497             : 
    2498             : /* ADDITION */
    2499             : 
    2500             : /* Add collection to collection */
    2501        1468 : int col_add_collection_to_collection(struct collection_item *ci,
    2502             :                                      const char *sub_collection_name,
    2503             :                                      const char *as_property,
    2504             :                                      struct collection_item *collection_to_add,
    2505             :                                      int mode)
    2506             : {
    2507        1468 :     struct collection_item *acceptor = NULL;
    2508             :     const char *name_to_use;
    2509             :     struct collection_header *header;
    2510             :     struct collection_item *collection_copy;
    2511        1468 :     int error = EOK;
    2512             :     struct col_copy traverse_data;
    2513        1468 :     unsigned depth = 0;
    2514             : 
    2515             : 
    2516             :     TRACE_FLOW_STRING("col_add_collection_to_collection", "Entry.");
    2517             : 
    2518        2936 :     if ((ci == NULL) ||
    2519        2936 :         (ci->type != COL_TYPE_COLLECTION) ||
    2520        2936 :         (collection_to_add == NULL) ||
    2521        1468 :         (collection_to_add->type != COL_TYPE_COLLECTION)) {
    2522             :         /* Need to debug here */
    2523             :         TRACE_ERROR_NUMBER("Missing parameter - returning error", EINVAL);
    2524           0 :         return EINVAL;
    2525             :     }
    2526             : 
    2527        1468 :     if (sub_collection_name != NULL) {
    2528             :         /* Find a sub collection */
    2529             :         TRACE_INFO_STRING("We are given subcollection name - search it:",
    2530             :                           sub_collection_name);
    2531           5 :         error = col_find_item_and_do(ci, sub_collection_name,
    2532             :                                      COL_TYPE_COLLECTIONREF,
    2533             :                                      COL_TRAVERSE_DEFAULT,
    2534             :                                      col_get_subcollection,
    2535             :                                      (void *)(&acceptor),
    2536             :                                      COLLECTION_ACTION_FIND);
    2537           5 :         if (error) {
    2538             :             TRACE_ERROR_NUMBER("Search failed returning error", error);
    2539           0 :             return error;
    2540             :         }
    2541             : 
    2542           5 :         if (acceptor == NULL) {
    2543             :             TRACE_ERROR_STRING("Search for subcollection returned NULL pointer", "");
    2544           0 :             return ENOENT;
    2545             :         }
    2546             : 
    2547             :     }
    2548             :     else {
    2549        1463 :         acceptor = ci;
    2550             :     }
    2551             : 
    2552        1468 :     if (as_property != NULL)
    2553           8 :         name_to_use = as_property;
    2554             :     else
    2555        1460 :         name_to_use = collection_to_add->property;
    2556             : 
    2557             : 
    2558             :     TRACE_INFO_STRING("Going to use name:", name_to_use);
    2559             : 
    2560             : 
    2561        1468 :     switch (mode) {
    2562             :     case COL_ADD_MODE_REFERENCE:
    2563             :         TRACE_INFO_STRING("We are adding a reference.", "");
    2564             :         TRACE_INFO_NUMBER("Type of the header element:",
    2565             :                           collection_to_add->type);
    2566             :         TRACE_INFO_STRING("Header name we are adding.",
    2567             :                           collection_to_add->property);
    2568             :         /* Create a pointer to external collection */
    2569             :         /* For future thread safety: Transaction start -> */
    2570          73 :         error = col_insert_property_with_ref_int(acceptor,
    2571             :                                                  NULL,
    2572             :                                                  COL_DSP_END,
    2573             :                                                  NULL,
    2574             :                                                  0,
    2575             :                                                  0,
    2576             :                                                  name_to_use,
    2577             :                                                  COL_TYPE_COLLECTIONREF,
    2578             :                                                  (void *)(&collection_to_add),
    2579             :                                                  sizeof(struct collection_item **),
    2580             :                                                  NULL);
    2581             : 
    2582             :         TRACE_INFO_NUMBER("Type of the header element after adding property:",
    2583             :                           collection_to_add->type);
    2584             :         TRACE_INFO_STRING("Header name we just added.",
    2585             :                           collection_to_add->property);
    2586          73 :         if (error) {
    2587             :             TRACE_ERROR_NUMBER("Adding property failed with error:", error);
    2588           0 :             return error;
    2589             :         }
    2590          73 :         header = (struct collection_header *)collection_to_add->data;
    2591             :         TRACE_INFO_NUMBER("Count:", header->count);
    2592             :         TRACE_INFO_NUMBER("Ref count:", header->reference_count);
    2593          73 :         header->reference_count++;
    2594             :         TRACE_INFO_NUMBER("Ref count after increment:",
    2595             :                           header->reference_count);
    2596             :         /* -> Transaction end */
    2597          73 :         break;
    2598             : 
    2599             :     case COL_ADD_MODE_EMBED:
    2600             :         TRACE_INFO_STRING("We are embedding the collection.", "");
    2601             :         /* First check if the passed in collection is referenced more than once */
    2602             :         TRACE_INFO_NUMBER("Type of the header element we are adding:",
    2603             :                           collection_to_add->type);
    2604             :         TRACE_INFO_STRING("Header name we are adding.",
    2605             :                           collection_to_add->property);
    2606             :         TRACE_INFO_NUMBER("Type of the header element we are adding to:",
    2607             :                           acceptor->type);
    2608             :         TRACE_INFO_STRING("Header name we are adding to.",
    2609             :                           acceptor->property);
    2610             : 
    2611        1391 :         error = col_insert_property_with_ref_int(acceptor,
    2612             :                                                  NULL,
    2613             :                                                  COL_DSP_END,
    2614             :                                                  NULL,
    2615             :                                                  0,
    2616             :                                                  0,
    2617             :                                                  name_to_use,
    2618             :                                                  COL_TYPE_COLLECTIONREF,
    2619             :                                                  (void *)(&collection_to_add),
    2620             :                                                  sizeof(struct collection_item **),
    2621             :                                                  NULL);
    2622             : 
    2623             : 
    2624             :         TRACE_INFO_NUMBER("Adding property returned:", error);
    2625        1391 :         break;
    2626             : 
    2627             :     case COL_ADD_MODE_CLONE:
    2628             :         TRACE_INFO_STRING("We are cloning the collection.", "");
    2629             :         TRACE_INFO_STRING("Name we will use.", name_to_use);
    2630             : 
    2631             :         /* For future thread safety: Transaction start -> */
    2632           1 :         error = col_copy_collection(&collection_copy,
    2633             :                                     collection_to_add, name_to_use,
    2634             :                                     COL_COPY_NORMAL);
    2635           1 :         if (error) return error;
    2636             : 
    2637             :         TRACE_INFO_STRING("We have a collection copy.", collection_copy->property);
    2638             :         TRACE_INFO_NUMBER("Collection type.", collection_copy->type);
    2639             :         TRACE_INFO_STRING("Acceptor collection.", acceptor->property);
    2640             :         TRACE_INFO_NUMBER("Acceptor collection type.", acceptor->type);
    2641             : 
    2642           1 :         error = col_insert_property_with_ref_int(acceptor,
    2643             :                                                  NULL,
    2644             :                                                  COL_DSP_END,
    2645             :                                                  NULL,
    2646             :                                                  0,
    2647             :                                                  0,
    2648             :                                                  name_to_use,
    2649             :                                                  COL_TYPE_COLLECTIONREF,
    2650             :                                                  (void *)(&collection_copy),
    2651             :                                                  sizeof(struct collection_item **),
    2652             :                                                  NULL);
    2653             : 
    2654             :         /* -> Transaction end */
    2655             :         TRACE_INFO_NUMBER("Adding property returned:", error);
    2656           1 :         break;
    2657             : 
    2658             :     case COL_ADD_MODE_FLAT:
    2659             :         TRACE_INFO_STRING("We are flattening the collection.", "");
    2660             : 
    2661           1 :         traverse_data.mode = COL_COPY_FLAT;
    2662           1 :         traverse_data.current_path = NULL;
    2663           1 :         traverse_data.copy_cb = NULL;
    2664           1 :         traverse_data.ext_data = NULL;
    2665             : 
    2666           1 :         if ((as_property) && (*as_property)) {
    2667             :             /* The normal assignement generates a warning
    2668             :              * becuase I am assigning const to a non const.
    2669             :              * I can't make the structure member to be const
    2670             :              * since it changes but it changes
    2671             :              * to point to different stings at different time
    2672             :              * This is just an initial sting it will use.
    2673             :              * The logic does not change the content of the string.
    2674             :              * To overcome the issue I use memcpy();
    2675             :              */
    2676           0 :             memcpy(&(traverse_data.given_name),
    2677             :                    &(as_property), sizeof(char *));
    2678           0 :             traverse_data.given_len = strlen(as_property);
    2679             :         }
    2680             :         else {
    2681           1 :             traverse_data.given_name = NULL;
    2682           1 :             traverse_data.given_len = 0;
    2683             :         }
    2684             : 
    2685           1 :         error = col_walk_items(collection_to_add, COL_TRAVERSE_FLAT,
    2686             :                                col_copy_traverse_handler, (void *)(&traverse_data),
    2687             :                                NULL, acceptor, &depth);
    2688             : 
    2689             :         TRACE_INFO_NUMBER("Copy collection flat returned:", error);
    2690           1 :         break;
    2691             : 
    2692             :     case COL_ADD_MODE_FLATDOT:
    2693             :         TRACE_INFO_STRING("We are flattening the collection with dots.", "");
    2694             : 
    2695           2 :         traverse_data.mode = COL_COPY_FLATDOT;
    2696           2 :         traverse_data.current_path = NULL;
    2697           2 :         traverse_data.copy_cb = NULL;
    2698           2 :         traverse_data.ext_data = NULL;
    2699             : 
    2700           2 :         if ((as_property) && (*as_property)) {
    2701             :             /* The normal assignement generates a warning
    2702             :              * becuase I am assigning const to a non const.
    2703             :              * I can't make the structure member to be const
    2704             :              * since it changes but it changes
    2705             :              * to point to different stings at different time
    2706             :              * This is just an initial sting it will use.
    2707             :              * The logic does not change the content of the string.
    2708             :              * To overcome the issue I use memcpy();
    2709             :              */
    2710           1 :             memcpy(&(traverse_data.given_name),
    2711             :                    &(as_property), sizeof(char *));
    2712           1 :             traverse_data.given_len = strlen(as_property);
    2713             :         }
    2714             :         else {
    2715           1 :             traverse_data.given_name = NULL;
    2716           1 :             traverse_data.given_len = 0;
    2717             :         }
    2718             : 
    2719           2 :         error = col_walk_items(collection_to_add, COL_TRAVERSE_DEFAULT | COL_TRAVERSE_END,
    2720             :                                col_copy_traverse_handler, (void *)(&traverse_data),
    2721             :                                NULL, acceptor, &depth);
    2722             : 
    2723             :         TRACE_INFO_NUMBER("Copy collection flatdot returned:", error);
    2724           2 :         break;
    2725             : 
    2726             :     default:
    2727           0 :         error = EINVAL;
    2728             :     }
    2729             : 
    2730             :     TRACE_FLOW_NUMBER("col_add_collection_to_collection returning:", error);
    2731        1468 :     return error;
    2732             : }
    2733             : 
    2734             : /* TRAVERSING */
    2735             : 
    2736             : /* Function to traverse the entire collection including optionally
    2737             :  * sub collections */
    2738         408 : int col_traverse_collection(struct collection_item *ci,
    2739             :                             int mode_flags,
    2740             :                             col_item_fn item_handler,
    2741             :                             void *custom_data)
    2742             : {
    2743             : 
    2744         408 :     int error = EOK;
    2745         408 :     unsigned depth = 0;
    2746             : 
    2747             :     TRACE_FLOW_STRING("col_traverse_collection", "Entry.");
    2748             : 
    2749         408 :     if (ci == NULL) {
    2750             :         TRACE_ERROR_NUMBER("No collection to traverse!", EINVAL);
    2751           0 :         return EINVAL;
    2752             :     }
    2753             : 
    2754         408 :     error = col_walk_items(ci, mode_flags, col_simple_traverse_handler,
    2755             :                            NULL, item_handler, custom_data, &depth);
    2756             : 
    2757         408 :     if ((error != 0) && (error != EINTR_INTERNAL)) {
    2758             :         TRACE_ERROR_NUMBER("Error walking tree", error);
    2759           0 :         return error;
    2760             :     }
    2761             : 
    2762             :     TRACE_FLOW_STRING("col_traverse_collection", "Success exit.");
    2763         408 :     return EOK;
    2764             : }
    2765             : 
    2766             : /* CHECK */
    2767             : 
    2768             : /* Convenience function to check if specific property is in the collection */
    2769          11 : int col_is_item_in_collection(struct collection_item *ci,
    2770             :                               const char *property_to_find,
    2771             :                               int type,
    2772             :                               int mode_flags,
    2773             :                               int *found)
    2774             : {
    2775             :     int error;
    2776             : 
    2777             :     TRACE_FLOW_STRING("col_is_item_in_collection","Entry.");
    2778             : 
    2779          11 :     *found = COL_NOMATCH;
    2780          11 :     error = col_find_item_and_do(ci, property_to_find,
    2781             :                                  type, mode_flags,
    2782             :                                  col_is_in_item_handler,
    2783             :                                  (void *)found,
    2784             :                                  COLLECTION_ACTION_FIND);
    2785             : 
    2786             :     TRACE_FLOW_NUMBER("col_is_item_in_collection returning", error);
    2787          11 :     return error;
    2788             : }
    2789             : 
    2790             : /* SEARCH */
    2791             : /* Search function. Looks up an item in the collection based on the property.
    2792             :    Essentually it is a traverse function with spacial traversing logic.
    2793             :  */
    2794          61 : int col_get_item_and_do(struct collection_item *ci,
    2795             :                         const char *property_to_find,
    2796             :                         int type,
    2797             :                         int mode_flags,
    2798             :                         col_item_fn item_handler,
    2799             :                         void *custom_data)
    2800             : {
    2801          61 :     int error = EOK;
    2802             : 
    2803             :     TRACE_FLOW_STRING("col_get_item_and_do","Entry.");
    2804             : 
    2805          61 :     error = col_find_item_and_do(ci, property_to_find,
    2806             :                                  type, mode_flags,
    2807             :                                  item_handler,
    2808             :                                  custom_data,
    2809             :                                  COLLECTION_ACTION_FIND);
    2810             : 
    2811             :     TRACE_FLOW_NUMBER("col_get_item_and_do returning", error);
    2812          61 :     return error;
    2813             : }
    2814             : 
    2815             : 
    2816             : /* Get raw item */
    2817       68376 : int col_get_item(struct collection_item *ci,
    2818             :                  const char *property_to_find,
    2819             :                  int type,
    2820             :                  int mode_flags,
    2821             :                  struct collection_item **item)
    2822             : {
    2823             : 
    2824       68376 :     int error = EOK;
    2825             : 
    2826             :     TRACE_FLOW_STRING("col_get_item", "Entry.");
    2827             : 
    2828       68376 :     error = col_find_item_and_do(ci, property_to_find,
    2829             :                                  type, mode_flags,
    2830             :                                  NULL, (void *)item,
    2831             :                                  COLLECTION_ACTION_GET);
    2832             : 
    2833             :     TRACE_FLOW_NUMBER("col_get_item returning", error);
    2834       68376 :     return error;
    2835             : }
    2836             : 
    2837             : /* DELETE */
    2838             : /* Delete property from the collection */
    2839           4 : int col_delete_property(struct collection_item *ci,
    2840             :                         const char *property_to_find,
    2841             :                         int type,
    2842             :                         int mode_flags)
    2843             : {
    2844           4 :     int error = EOK;
    2845             :     int found;
    2846             : 
    2847             :     TRACE_FLOW_STRING("col_delete_property", "Entry.");
    2848           4 :     found = COL_NOMATCH;
    2849             : 
    2850           4 :     error = col_find_item_and_do(ci, property_to_find,
    2851             :                                  type, mode_flags,
    2852             :                                  NULL, (void *)(&found),
    2853             :                                  COLLECTION_ACTION_DEL);
    2854             : 
    2855           4 :     if ((error == EOK) && (found == COL_NOMATCH))
    2856           1 :         error = ENOENT;
    2857             : 
    2858             :     TRACE_FLOW_NUMBER("col_delete_property returning", error);
    2859           4 :     return error;
    2860             : }
    2861             : 
    2862             : /* UPDATE */
    2863             : /* Update property in the collection */
    2864           1 : int col_update_property(struct collection_item *ci,
    2865             :                         const char *property_to_find,
    2866             :                         int type,
    2867             :                         void *new_data,
    2868             :                         int length,
    2869             :                         int mode_flags)
    2870             : {
    2871           1 :     int error = EOK;
    2872             :     struct update_property update_data;
    2873             : 
    2874             :     TRACE_FLOW_STRING("col_update_property", "Entry.");
    2875           1 :     update_data.type = type;
    2876           1 :     update_data.data = new_data;
    2877           1 :     update_data.length = length;
    2878           1 :     update_data.found = COL_NOMATCH;
    2879             : 
    2880           1 :     error = col_find_item_and_do(ci, property_to_find,
    2881             :                                  type, mode_flags,
    2882             :                                  NULL, (void *)(&update_data),
    2883             :                                  COLLECTION_ACTION_UPDATE);
    2884             : 
    2885           1 :     if ((error == EOK) && (update_data.found == COL_NOMATCH))
    2886           0 :         error = ENOENT;
    2887             : 
    2888             :     TRACE_FLOW_NUMBER("col_update_property returning", error);
    2889           1 :     return error;
    2890             : }
    2891             : 
    2892             : 
    2893             : /* Function to modify the item */
    2894       66634 : int col_modify_item(struct collection_item *item,
    2895             :                     const char *property,
    2896             :                     int type,
    2897             :                     const void *data,
    2898             :                     int length)
    2899             : {
    2900             :     TRACE_FLOW_STRING("col_modify_item", "Entry");
    2901             : 
    2902      133268 :     if ((item == NULL) ||
    2903      133268 :         (item->type == COL_TYPE_COLLECTION) ||
    2904       66634 :         (item->type == COL_TYPE_COLLECTIONREF)) {
    2905             :         TRACE_ERROR_NUMBER("Invalid argument or invalid argument type", EINVAL);
    2906           0 :         return EINVAL;
    2907             :     }
    2908             : 
    2909       66634 :     if (property != NULL) {
    2910          14 :         if (col_validate_property(property)) {
    2911             :             TRACE_ERROR_STRING("Invalid chracters in the property name", property);
    2912           0 :             return EINVAL;
    2913             :         }
    2914          14 :         free(item->property);
    2915          14 :         item->property = strdup(property);
    2916          14 :         if (item->property == NULL) {
    2917             :             TRACE_ERROR_STRING("Failed to allocate memory", "");
    2918           0 :             return ENOMEM;
    2919             :         }
    2920             : 
    2921             :         /* Update property length and hash if we rename the property */
    2922          14 :         item->phash = col_make_hash(property, 0, &(item->property_len));
    2923             :         TRACE_INFO_NUMBER("Item hash", item->phash);
    2924             :         TRACE_INFO_NUMBER("Item property length", item->property_len);
    2925             :         TRACE_INFO_NUMBER("Item property strlen", strlen(item->property));
    2926             : 
    2927             :     }
    2928             : 
    2929             :     /* We need to change data ? */
    2930       66634 :     if(length) {
    2931             : 
    2932             :         /* If type is different or same but it is string or binary we need to
    2933             :          * replace the storage */
    2934      133248 :         if ((item->type != type) ||
    2935      133232 :             ((item->type == type) &&
    2936      133230 :             ((item->type == COL_TYPE_STRING) || (item->type == COL_TYPE_BINARY)))) {
    2937             :             TRACE_INFO_STRING("Replacing item data buffer", "");
    2938       66632 :             free(item->data);
    2939       66632 :             item->data = malloc(length);
    2940       66632 :             if (item->data == NULL) {
    2941             :                 TRACE_ERROR_STRING("Failed to allocate memory", "");
    2942           0 :                 item->length = 0;
    2943           0 :                 return ENOMEM;
    2944             :             }
    2945       66632 :             item->length = length;
    2946             :         }
    2947             : 
    2948             :         TRACE_INFO_STRING("Overwriting item data", "");
    2949       66632 :         memcpy(item->data, data, item->length);
    2950       66632 :         item->type = type;
    2951             : 
    2952       66632 :         if (item->type == COL_TYPE_STRING)
    2953           4 :             ((char *)(item->data))[item->length - 1] = '\0';
    2954             :     }
    2955             : 
    2956             :     TRACE_FLOW_STRING("col_modify_item", "Exit");
    2957       66634 :     return EOK;
    2958             : }
    2959             : 
    2960             : 
    2961             : /* Set collection class */
    2962           1 : int col_set_collection_class(struct collection_item *item,
    2963             :                              unsigned cclass)
    2964             : {
    2965             :     struct collection_header *header;
    2966             : 
    2967             :     TRACE_FLOW_STRING("col_set_collection_class", "Entry");
    2968             : 
    2969           1 :     if (item->type != COL_TYPE_COLLECTION) {
    2970             :         TRACE_INFO_NUMBER("Not a collectin object. Type is", item->type);
    2971           0 :         return EINVAL;
    2972             :     }
    2973             : 
    2974           1 :     header = (struct collection_header *)item->data;
    2975           1 :     header->cclass = cclass;
    2976             :     TRACE_FLOW_STRING("col_set_collection_class", "Exit");
    2977           1 :     return EOK;
    2978             : }
    2979             : 
    2980             : /* Get collection class */
    2981      993039 : int col_get_collection_class(struct collection_item *item,
    2982             :                              unsigned *cclass)
    2983             : {
    2984             :     struct collection_header *header;
    2985             : 
    2986             :     TRACE_FLOW_STRING("col_get_collection_class", "Entry");
    2987             : 
    2988      993039 :     if (item->type != COL_TYPE_COLLECTION) {
    2989             :         TRACE_ERROR_NUMBER("Not a collection object. Type is", item->type);
    2990           0 :         return EINVAL;
    2991             :     }
    2992             : 
    2993      993039 :     header = (struct collection_header *)item->data;
    2994      993039 :     *cclass  = header->cclass;
    2995             :     TRACE_FLOW_STRING("col_get_collection_class", "Exit");
    2996      993039 :     return EOK;
    2997             : }
    2998             : 
    2999             : /* Get collection count */
    3000         282 : int col_get_collection_count(struct collection_item *item,
    3001             :                              unsigned *count)
    3002             : {
    3003             :     struct collection_header *header;
    3004             : 
    3005             :     TRACE_FLOW_STRING("col_get_collection_count", "Entry");
    3006             : 
    3007         282 :     if (item->type != COL_TYPE_COLLECTION) {
    3008             :         TRACE_ERROR_NUMBER("Not a collectin object. Type is", item->type);
    3009           0 :         return EINVAL;
    3010             :     }
    3011             : 
    3012         282 :     header = (struct collection_header *)item->data;
    3013         282 :     *count  = header->count;
    3014             :     TRACE_FLOW_STRING("col_get_collection_count", "Exit");
    3015         282 :     return EOK;
    3016             : 
    3017             : }
    3018             : 
    3019             : /* Convinience function to check if the collection is of the specific class */
    3020             : /* In case of internal error assumes that collection is not of the right class */
    3021      993038 : int col_is_of_class(struct collection_item *item, unsigned cclass)
    3022             : {
    3023      993038 :     int error = EOK;
    3024      993038 :     unsigned ret_class = 0;
    3025             : 
    3026             :     TRACE_FLOW_STRING("col_is_of_class invoked", "");
    3027             : 
    3028      993038 :     error = col_get_collection_class(item, &ret_class);
    3029      993038 :     if (error || (ret_class != cclass))
    3030           8 :         return 0;
    3031             :     else
    3032      993030 :         return 1;
    3033             : }
    3034             : 
    3035             : /* Get propery */
    3036        2126 : const char *col_get_item_property(struct collection_item *ci,
    3037             :                                   int *property_len)
    3038             : {
    3039        2126 :     if (property_len != NULL) *property_len = ci->property_len;
    3040        2126 :     return ci->property;
    3041             : }
    3042             : 
    3043             : /* Get type */
    3044       66624 : int col_get_item_type(struct collection_item *ci)
    3045             : {
    3046       66624 :     return ci->type;
    3047             : }
    3048             : 
    3049             : /* Get length */
    3050          17 : int col_get_item_length(struct collection_item *ci)
    3051             : {
    3052          17 :     return ci->length;
    3053             : }
    3054             : 
    3055             : /* Get data */
    3056      563574 : void *col_get_item_data(struct collection_item *ci)
    3057             : {
    3058      563574 :     return ci->data;
    3059             : }
    3060             : 
    3061             : /* Get hash */
    3062         376 : uint64_t col_get_item_hash(struct collection_item *ci)
    3063             : {
    3064         376 :     return ci->phash;
    3065             : }
    3066             : 
    3067             : /* Calculates hash of the string using internal hashing
    3068             :  * algorithm. Populates "length" with length
    3069             :  * of the string not counting 0.
    3070             :  * Length argument can be NULL.
    3071             :  */
    3072      637761 : uint64_t col_make_hash(const char *string, int sub_len, int *length)
    3073             : {
    3074      637761 :     uint64_t hash = 0;
    3075      637761 :     int str_len = 0;
    3076             : 
    3077             :     TRACE_FLOW_STRING("col_make_hash called for string:", string);
    3078             : 
    3079      637761 :     if (string) {
    3080      637761 :         hash = FNV1a_base;
    3081     7982591 :         while (string[str_len] != 0) {
    3082             : 
    3083             :             /* Check if we need to stop */
    3084     6707071 :             if ((sub_len > 0) && (str_len == sub_len)) break;
    3085             : 
    3086     6707069 :             hash = hash ^ toupper(string[str_len]);
    3087     6707069 :             hash *= FNV1a_prime;
    3088     6707069 :             str_len++;
    3089             :         }
    3090             :     }
    3091             : 
    3092      637761 :     if (length) *length = str_len;
    3093             : 
    3094             :     TRACE_FLOW_NUMBER("col_make_hash returning hash:", hash);
    3095             : 
    3096      637761 :     return hash;
    3097             : }

Generated by: LCOV version 1.10