Bug Summary

File:bld/../collection/collection.c
Location:line 576, column 46
Description:Field access results in a dereference of a null pointer (loaded from variable 'parent')

Annotated Source Code

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