/*
map a tdb error code to a ldb error code
*/
-static int ltdb_err_map(enum TDB_ERROR tdb_code)
+int ltdb_err_map(enum TDB_ERROR tdb_code)
{
switch (tdb_code) {
case TDB_SUCCESS:
static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn)
{
int ret = LDB_SUCCESS;
+ struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
+
+ /* only allow modifies inside a transaction, otherwise the
+ * ldb is unsafe */
+ if (ltdb->in_transaction == 0) {
+ ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
if (ldb_dn_is_special(dn) &&
(ldb_dn_check_special(dn, LTDB_INDEXLIST) ||
int ret = LDB_SUCCESS;
tdb_key = ltdb_key(module, msg->dn);
- if (!tdb_key.dptr) {
+ if (tdb_key.dptr == NULL) {
return LDB_ERR_OTHER;
}
goto done;
}
- ret = ltdb_index_add(module, msg);
- if (ret != LDB_SUCCESS) {
- tdb_delete(ltdb->tdb, tdb_key);
- }
-
done:
talloc_free(tdb_key.dptr);
talloc_free(tdb_data.dptr);
ret = ltdb_check_special_dn(module, msg);
if (ret != LDB_SUCCESS) {
- goto done;
+ return ret;
}
if (ltdb_cache_load(module) != 0) {
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto done;
+ return LDB_ERR_OPERATIONS_ERROR;
}
for (i=0;i<msg->num_elements;i++) {
if (el->num_values == 0) {
ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illegal)",
el->name, ldb_dn_get_linearized(msg->dn));
- ret = LDB_ERR_CONSTRAINT_VIOLATION;
- goto done;
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
if (el->num_values > 1) {
ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
el->name, ldb_dn_get_linearized(msg->dn));
- ret = LDB_ERR_CONSTRAINT_VIOLATION;
- goto done;
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
}
}
"Entry %s already exists",
ldb_dn_get_linearized(msg->dn));
}
- goto done;
+ return ret;
}
- ret = ltdb_index_one(module, msg, 1);
+ ret = ltdb_index_add_new(module, msg);
if (ret != LDB_SUCCESS) {
- goto done;
+ return ret;
}
ret = ltdb_modified(module, msg->dn);
- if (ret != LDB_SUCCESS) {
- goto done;
- }
-done:
return ret;
}
goto done;
}
- /* remove one level attribute */
- ret = ltdb_index_one(module, msg, 0);
- if (ret != LDB_SUCCESS) {
- goto done;
- }
-
/* remove any indexed attributes */
- ret = ltdb_index_del(module, msg);
+ ret = ltdb_index_delete(module, msg);
if (ret != LDB_SUCCESS) {
goto done;
}
returns 0 on success, -1 on failure (and sets errno)
*/
-static int msg_add_element(struct ldb_context *ldb,
- struct ldb_message *msg,
- struct ldb_message_element *el)
+static int ltdb_msg_add_element(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el)
{
struct ldb_message_element *e2;
unsigned int i;
struct ldb_message *msg, const char *name)
{
const char *dn;
- unsigned int i, j;
+ unsigned int i;
+ int ret;
+ struct ldb_message_element *el;
dn = ldb_dn_get_linearized(msg->dn);
if (dn == NULL) {
return -1;
}
- for (i=0;i<msg->num_elements;i++) {
- if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
- for (j=0;j<msg->elements[i].num_values;j++) {
- ltdb_index_del_value(module, dn,
- &msg->elements[i], j);
- }
- talloc_free(msg->elements[i].values);
- if (msg->num_elements > (i+1)) {
- memmove(&msg->elements[i],
- &msg->elements[i+1],
- sizeof(struct ldb_message_element)*
- (msg->num_elements - (i+1)));
- }
- msg->num_elements--;
- i--;
- msg->elements = talloc_realloc(msg, msg->elements,
- struct ldb_message_element,
- msg->num_elements);
+ el = ldb_msg_find_element(msg, name);
+ if (el == NULL) {
+ return -1;
+ }
+ i = el - msg->elements;
- /* per definition we find in a canonicalised message an
- attribute only once. So we are finished here. */
- return 0;
- }
+ ret = ltdb_index_del_element(module, dn, el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- /* Not found */
- return -1;
+ talloc_free(el->values);
+ if (msg->num_elements > (i+1)) {
+ memmove(el, el+1, sizeof(*el) * (msg->num_elements - (i+1)));
+ }
+ msg->num_elements--;
+ msg->elements = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element,
+ msg->num_elements);
+ return 0;
}
/*
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
unsigned int i;
- int found;
+ int found, ret;
struct ldb_message_element *el;
const struct ldb_schema_attribute *a;
for (i=0;i<el->num_values;i++) {
if (a->syntax->comparison_fn(ldb, ldb,
- &el->values[i], val) == 0) {
+ &el->values[i], val) == 0) {
+ if (el->num_values == 1) {
+ return msg_delete_attribute(module, ldb, msg, name);
+ }
+
+ ret = ltdb_index_del_value(module, ldb_dn_get_linearized(msg->dn), el, i);
+ if (ret != LDB_SUCCESS) {
+ return -1;
+ }
+
if (i<el->num_values-1) {
memmove(&el->values[i], &el->values[i+1],
sizeof(el->values[i])*
(el->num_values-(i+1)));
}
el->num_values--;
- if (el->num_values == 0) {
- return msg_delete_attribute(module, ldb,
- msg, name);
- }
/* per definition we find in a canonicalised message an
attribute value only once. So we are finished here */
/* Checks if element already exists */
idx = find_element(msg2, el->name);
if (idx == -1) {
- if (msg_add_element(ldb, msg2, el) != 0) {
+ if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
ret = LDB_ERR_OTHER;
goto done;
}
+ ret = ltdb_index_add_element(module, msg->dn, el);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
} else {
/* We cannot add another value on a existing one
if the attribute is single-valued */
/* Now combine existing and new values to a new
attribute record */
vals = talloc_realloc(msg2->elements,
- el2->values, struct ldb_val,
- el2->num_values + el->num_values);
+ el2->values, struct ldb_val,
+ el2->num_values + el->num_values);
if (vals == NULL) {
ldb_oom(ldb);
ret = LDB_ERR_OTHER;
el2->values = vals;
el2->num_values += el->num_values;
+
+ ret = ltdb_index_add_element(module, msg->dn, el);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
}
break;
}
}
+ /* TODO: This is O(n^2) - replace with more efficient check */
for (j=0; j<el->num_values; j++) {
if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
ldb_asprintf_errstring(ldb, "%s: value #%d provided more than once", el->name, j);
}
}
- /* Delete the attribute if it exists in the DB */
- msg_delete_attribute(module, ldb, msg2, el->name);
+ idx = find_element(msg2, el->name);
+ if (idx != -1) {
+ el2 = &(msg2->elements[idx]);
+ if (ldb_msg_element_compare(el, el2) == 0) {
+ /* we are replacing with the same values */
+ continue;
+ }
+
+ /* Delete the attribute if it exists in the DB */
+ ret = msg_delete_attribute(module, ldb, msg2, el->name);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ }
/* Recreate it with the new values */
- if (msg_add_element(ldb, msg2, el) != 0) {
+ if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
ret = LDB_ERR_OTHER;
goto done;
}
+ ret = ltdb_index_add_element(module, msg->dn, el);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
break;
case LDB_FLAG_MOD_DELETE:
ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
goto done;
}
-
- ret = ltdb_index_del_value(module, dn,
- &msg->elements[i], j);
- if (ret != LDB_SUCCESS) {
- goto done;
- }
}
}
-
break;
default:
ldb_asprintf_errstring(ldb,
msg = talloc(ctx, struct ldb_message);
if (msg == NULL) {
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto done;
+ return LDB_ERR_OPERATIONS_ERROR;
}
/* in case any attribute of the message was indexed, we need
ret = ltdb_search_dn1(module, req->op.rename.olddn, msg);
if (ret != LDB_SUCCESS) {
/* not finding the old record is an error */
- goto done;
+ return ret;
}
msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
if (msg->dn == NULL) {
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto done;
+ return LDB_ERR_OPERATIONS_ERROR;
}
/* Always delete first then add, to avoid conflicts with
*/
ret = ltdb_delete_internal(module, req->op.rename.olddn);
if (ret != LDB_SUCCESS) {
- goto done;
+ return ret;
}
ret = ltdb_add_internal(module, msg);
-done:
return ret;
}
return -1;
}
ldb_module_set_private(module, ltdb);
+ talloc_steal(module, ltdb);
if (ltdb_cache_load(module) != 0) {
talloc_free(module);