/* clear values and optionally requests from property context * ctx -- property context * requests -- 0 = don't clear requests, 1 = clear requests */ void prop_clear(struct propctx *ctx, int requests) { struct proppool *new_pool, *tmp; unsigned i; /* We're going to need a new proppool once we reset things */ new_pool = alloc_proppool(ctx->mem_base->size + (ctx->used_values+1) * sizeof(struct propval)); if (new_pool == NULL) { _sasl_log(NULL, SASL_LOG_ERR, "failed to allocate memory\n"); exit(1); } if(requests) { /* We're wiping the whole shebang */ ctx->used_values = 0; } else { /* Need to keep around old requets */ struct propval *new_values = (struct propval *)new_pool->data; for(i=0; i<ctx->used_values; i++) { new_values[i].name = ctx->values[i].name; } } while(ctx->mem_base) { tmp = ctx->mem_base; ctx->mem_base = tmp->next; sasl_FREE(tmp); } /* Update allocation-related metadata */ ctx->allocated_values = ctx->used_values+1; new_pool->unused = new_pool->size - (ctx->allocated_values * sizeof(struct propval)); /* Setup pointers for the values array */ ctx->values = (struct propval *)new_pool->data; ctx->prev_val = NULL; /* Setup the pools */ ctx->mem_base = ctx->mem_cur = new_pool; /* Reset list_end and data_end for the new memory pool */ ctx->list_end = (char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval)); ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size; return; }
static int prop_init(struct propctx *ctx, unsigned estimate) { const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval); ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate); if(!ctx->mem_base) return SASL_NOMEM; ctx->mem_cur = ctx->mem_base; ctx->values = (struct propval *)ctx->mem_base->data; ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE; ctx->allocated_values = PROP_DEFAULT; ctx->used_values = 0; ctx->data_end = ctx->mem_base->data + ctx->mem_base->size; ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE); ctx->prev_val = NULL; return SASL_OK; }
/* add a property value to the context * ctx -- context from prop_new()/prop_request() * name -- name of property to which value will be added * if NULL, add to the same name as previous prop_set/setvals call * value -- a value for the property; will be copied into context * if NULL, remove existing values * vallen -- length of value, if <= 0 then strlen(value) will be used */ int prop_set(struct propctx *ctx, const char *name, const char *value, int vallen) { struct propval *cur; if(!ctx) return SASL_BADPARAM; if(!name && !ctx->prev_val) return SASL_BADPARAM; if(name) { struct propval *val; ctx->prev_val = NULL; for(val = ctx->values; val->name; val++) { if(!strcmp(name,val->name)){ ctx->prev_val = val; break; } } /* Couldn't find it! */ if(!ctx->prev_val) return SASL_BADPARAM; } cur = ctx->prev_val; if(name) /* New Entry */ { unsigned nvalues = 1; /* 1 for NULL entry */ const char **old_values = NULL; char **tmp, **tmp2; size_t size; if(cur->values) { if(!value) { /* If we would be adding a null value, then we are done */ return SASL_OK; } old_values = cur->values; tmp = (char **)cur->values; while(*tmp) { nvalues++; tmp++; } } if(value) { nvalues++; /* for the new value */ } size = nvalues * sizeof(char*); if(size > ctx->mem_cur->unused) { size_t needed; for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2); /* Allocate a new proppool */ ctx->mem_cur->next = alloc_proppool(needed); if(!ctx->mem_cur->next) return SASL_NOMEM; ctx->mem_cur = ctx->mem_cur->next; ctx->list_end = (char **)ctx->mem_cur->data; ctx->data_end = ctx->mem_cur->data + needed; } /* Grab the memory */ ctx->mem_cur->unused -= size; cur->values = (const char **)ctx->list_end; cur->values[nvalues - 1] = NULL; /* Finish updating the context */ ctx->list_end = (char **)(cur->values + nvalues); /* If we don't have an actual value to fill in, we are done */ if(!value) return SASL_OK; tmp2 = (char **)cur->values; if(old_values) { tmp = (char **)old_values; while(*tmp) { *tmp2 = *tmp; tmp++; tmp2++; } } /* Now allocate the last entry */ if(vallen <= 0) size = (size_t)(strlen(value) + 1); else size = (size_t)(vallen + 1); if(size > ctx->mem_cur->unused) { size_t needed; needed = ctx->mem_cur->size * 2; while(needed < size) { needed *= 2; } /* Allocate a new proppool */ ctx->mem_cur->next = alloc_proppool(needed); if(!ctx->mem_cur->next) return SASL_NOMEM; ctx->mem_cur = ctx->mem_cur->next; ctx->list_end = (char **)ctx->mem_cur->data; ctx->data_end = ctx->mem_cur->data + needed; } /* Update the data_end pointer */ ctx->data_end -= size; ctx->mem_cur->unused -= size; /* Copy and setup the new value! */ memcpy(ctx->data_end, value, size-1); ctx->data_end[size - 1] = '\0'; cur->values[nvalues - 2] = ctx->data_end; cur->nvalues++; cur->valsize += ((unsigned) size - 1); } else /* Appending an entry */ { char **tmp; size_t size; /* If we are setting it to be NULL, we are done */ if(!value) return SASL_OK; size = sizeof(char*); /* Is it in the current pool, and will it fit in the unused space? */ if(size > ctx->mem_cur->unused && (void *)cur->values > (void *)(ctx->mem_cur->data) && (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) { /* recursively call the not-fast way */ return prop_set(ctx, cur->name, value, vallen); } /* Note the invariant: the previous value list must be at the top of the CURRENT pool at this point */ /* Grab the memory */ ctx->mem_cur->unused -= size; ctx->list_end++; *(ctx->list_end - 1) = NULL; tmp = (ctx->list_end - 2); /* Now allocate the last entry */ if(vallen <= 0) size = strlen(value) + 1; else size = vallen + 1; if(size > ctx->mem_cur->unused) { size_t needed; needed = ctx->mem_cur->size * 2; while(needed < size) { needed *= 2; } /* Allocate a new proppool */ ctx->mem_cur->next = alloc_proppool(needed); if(!ctx->mem_cur->next) return SASL_NOMEM; ctx->mem_cur = ctx->mem_cur->next; ctx->list_end = (char **)ctx->mem_cur->data; ctx->data_end = ctx->mem_cur->data + needed; } /* Update the data_end pointer */ ctx->data_end -= size; ctx->mem_cur->unused -= size; /* Copy and setup the new value! */ memcpy(ctx->data_end, value, size-1); ctx->data_end[size - 1] = '\0'; *tmp = ctx->data_end; cur->nvalues++; cur->valsize += ((unsigned) size - 1); } return SASL_OK; }