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