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.
At conditional (2): "item->type == 512": Taking true branch.
| |
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
At conditional (3): "item->property != NULL": Taking true branch.
|
198 if (item->property != NULL) free(item->property);
Event read_parm_fld: Reading a parameter field.
|
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 {
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 */
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->data" when calling "col_delete_item". [model] Event uninit_use_in_call: Using uninitialized value "item->type" when calling "col_delete_item". [model]
Also see events: [var_decl][alloc_fn] | |
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.");
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 }