/* Configuration copy callback */ static int ini_copy_cb(struct collection_item *item, void *ext_data, int *skip) { int error = EOK; struct value_obj *vo = NULL; struct value_obj *new_vo = NULL; TRACE_FLOW_ENTRY(); ext_data = NULL; *skip = 0; /* Banary items are the values */ if(col_get_item_type(item) == COL_TYPE_BINARY) { vo = *((struct value_obj **)(col_get_item_data(item))); error = value_copy(vo, &new_vo); if (error) { TRACE_ERROR_NUMBER("Failed to copy value", error); return error; } error = col_modify_binary_item(item, NULL, &new_vo, sizeof(struct value_obj *)); if (error) { TRACE_ERROR_NUMBER("Failed to copy value", error); value_destroy(new_vo); return error; } } TRACE_FLOW_EXIT(); return error; }
/* Complete value processing */ static int complete_value_processing(struct parser_obj *po) { int error = EOK; int error2 = EOK; struct value_obj *vo = NULL; struct value_obj *vo_old = NULL; unsigned insertmode; uint32_t mergemode; int suppress = 0; int doinsert = 0; struct collection_item *item = NULL; struct collection_item *section = NULL; int merging = 0; TRACE_FLOW_ENTRY(); if (po->merge_sec) { TRACE_INFO_STRING("Processing value in merge mode", ""); section = po->merge_sec; merging = 1; } else if(!(po->sec)) { TRACE_INFO_STRING("Creating default section", ""); /* If there is not open section create a default one */ error = col_create_collection(&po->sec, INI_DEFAULT_SECTION, COL_CLASS_INI_SECTION); if (error) { TRACE_ERROR_NUMBER("Failed to create default section", error); return error; } section = po->sec; } else { TRACE_INFO_STRING("Processing value in normal mode", ""); section = po->sec; } if (merging) { TRACE_INFO_STRING("Using merge key:", po->merge_key); vo = po->merge_vo; /* We are adding to the merge section so use MV2S flags. * But flags are done in such a way that deviding MV2S by MV1S mask * will translate MV2S flags into MV1S so we can use * MV1S constants. */ TRACE_INFO_NUMBER("Collisions flags:", po->collision_flags); mergemode = (po->collision_flags & INI_MV2S_MASK) / INI_MV1S_MASK; } else { /* Construct value object from what we have */ error = value_create_from_refarray(po->raw_lines, po->raw_lengths, po->keylinenum, INI_VALUE_READ, po->key_len, po->boundary, po->ic, &vo); if (error) { TRACE_ERROR_NUMBER("Failed to create value object", error); return error; } /* Forget about the arrays. They are now owned by the value object */ po->ic = NULL; po->raw_lines = NULL; po->raw_lengths = NULL; mergemode = po->collision_flags & INI_MV1S_MASK; } switch (mergemode) { case INI_MV1S_ERROR: insertmode = COL_INSERT_DUPERROR; doinsert = 1; break; case INI_MV1S_PRESERVE: insertmode = COL_INSERT_DUPERROR; doinsert = 1; suppress = 1; break; case INI_MV1S_ALLOW: insertmode = COL_INSERT_NOCHECK; doinsert = 1; break; case INI_MV1S_OVERWRITE: /* Special handling */ case INI_MV1S_DETECT: default: break; } /* Do not insert but search for dups first */ if (!doinsert) { TRACE_INFO_STRING("Overwrite mode. Looking for:", (char *)(merging ? po->merge_key : po->key)); error = col_get_item(section, merging ? po->merge_key : po->key, COL_TYPE_BINARY, COL_TRAVERSE_DEFAULT, &item); if (error) { TRACE_ERROR_NUMBER("Failed searching for dup", error); value_destroy(vo); return error; } /* Check if there is a dup */ if (item) { /* Check if we are in the detect mode */ if (mergemode == INI_MV1S_DETECT) { po->merge_error = EEXIST; /* There is a dup - inform user about it and continue */ error = save_error(po->el, merging ? po->seclinenum : po->keylinenum, merging ? ERR_DUPKEYSEC : ERR_DUPKEY, ERROR_TXT); if (error) { TRACE_ERROR_NUMBER("Failed to save error", error); value_destroy(vo); return error; } doinsert = 1; insertmode = COL_INSERT_NOCHECK; } else { /* Dup exists - update it */ vo_old = *((struct value_obj **)(col_get_item_data(item))); error = col_modify_binary_item(item, NULL, &vo, sizeof(struct value_obj *)); if (error) { TRACE_ERROR_NUMBER("Failed updating the value", error); value_destroy(vo); return error; } /* If we failed to update it is better to leak then crash, * so destroy original value only on the successful update. */ value_destroy(vo_old); } } else { /* No dup found so we can insert with no check */ doinsert = 1; insertmode = COL_INSERT_NOCHECK; } } if (doinsert) { /* Add value to collection */ error = col_insert_binary_property(section, NULL, COL_DSP_END, NULL, 0, insertmode, merging ? po->merge_key : po->key, &vo, sizeof(struct value_obj *)); if (error) { value_destroy(vo); if ((suppress) && (error == EEXIST)) { TRACE_INFO_STRING("Preseved exisitng value", (char *)(merging ? po->merge_key : po->key)); } else { /* Check if this is a critical error or not */ if ((mergemode == INI_MV1S_ERROR) && (error == EEXIST)) { TRACE_ERROR_NUMBER("Failed to add value object " "to the section", error); error2 = save_error(po->el, merging ? po->seclinenum : po->keylinenum, merging ? ERR_DUPKEYSEC : ERR_DUPKEY, ERROR_TXT); if (error2) { TRACE_ERROR_NUMBER("Failed to save error", error2); return error2; } return error; } else { TRACE_ERROR_NUMBER("Failed to add value object" " to the section", error); return error; } } } } if (!merging) { free(po->key); po->key = NULL; po->key_len = 0; } TRACE_FLOW_EXIT(); return EOK; }