summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/ldb_tdb
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-04-03 12:29:21 +0000
committerAndrew Tridgell <tridge@samba.org>2004-04-03 12:29:21 +0000
commitee44733f94864fb0a1ae15d48e3335c0705a82ae (patch)
tree8f9691975aab7a6ce3736e64283e66a69db3c194 /source4/lib/ldb/ldb_tdb
parentf1c3fa060efcecde404d0bfb55c359ef7fe36ed8 (diff)
downloadsamba-ee44733f94864fb0a1ae15d48e3335c0705a82ae.tar.gz
samba-ee44733f94864fb0a1ae15d48e3335c0705a82ae.tar.bz2
samba-ee44733f94864fb0a1ae15d48e3335c0705a82ae.zip
added the rest of the ldb_modify() code, which required a fairly large
change in the ldb API. The API is now much closer to LDAP. (This used to be commit e9e85c464411c561c5073d262a2e3533fec175ca)
Diffstat (limited to 'source4/lib/ldb/ldb_tdb')
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_index.c208
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_match.c18
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_pack.c94
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_search.c52
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c263
-rw-r--r--source4/lib/ldb/ldb_tdb/ldbadd.c55
-rw-r--r--source4/lib/ldb/ldb_tdb/ldbdel.c50
-rw-r--r--source4/lib/ldb/ldb_tdb/ldbsearch.c73
8 files changed, 517 insertions, 296 deletions
diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c
index dda80a6b2a..8cda8abff8 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_index.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_index.c
@@ -74,13 +74,22 @@ static char *ldb_dn_key(const char *attr, const struct ldb_val *value)
/*
see if a attribute value is in the list of indexed attributes
*/
-static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr)
+static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
+ int *v_idx)
{
- int i;
+ int i, j;
for (i=0;i<msg->num_elements;i++) {
- if (strcmp(msg->elements[i].name, "@IDXATTR") == 0 &&
- strcmp((char *)msg->elements[i].value.data, attr) == 0) {
- return i;
+ if (strcmp(msg->elements[i].name, "@IDXATTR") == 0) {
+ const struct ldb_message_element *el =
+ &msg->elements[i];
+ for (j=0;j<el->num_values;j++) {
+ if (strcmp((char *)el->values[j].data, attr) == 0) {
+ if (v_idx) {
+ *v_idx = j;
+ }
+ return i;
+ }
+ }
}
}
return -1;
@@ -95,7 +104,7 @@ static int ltdb_index_dn_simple(struct ldb_context *ldb,
struct dn_list *list)
{
char *dn = NULL;
- int ret, i;
+ int ret, i, j;
struct ldb_message msg;
list->count = 0;
@@ -110,7 +119,7 @@ static int ltdb_index_dn_simple(struct ldb_context *ldb,
/* if the attribute isn't in the list of indexed attributes then
this node needs a full search */
- if (ldb_msg_find_idx(index_list, tree->u.simple.attr) == -1) {
+ if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL) == -1) {
return -1;
}
@@ -125,23 +134,30 @@ static int ltdb_index_dn_simple(struct ldb_context *ldb,
return ret;
}
- list->dn = malloc_array_p(char *, msg.num_elements);
- if (!list->dn) {
- ltdb_search_dn1_free(ldb, &msg);
- }
-
for (i=0;i<msg.num_elements;i++) {
+ struct ldb_message_element *el;
+
if (strcmp(msg.elements[i].name, "@IDX") != 0) {
continue;
}
- list->dn[list->count] =
- strdup((char *)msg.elements[i].value.data);
- if (!list->dn[list->count]) {
- dn_list_free(list);
- ltdb_search_dn1_free(ldb, &msg);
- return -1;
+
+ el = &msg.elements[i];
+
+ list->dn = malloc_array_p(char *, el->num_values);
+ if (!list->dn) {
+ break;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ list->dn[list->count] =
+ strdup((char *)el->values[j].data);
+ if (!list->dn[list->count]) {
+ dn_list_free(list);
+ ltdb_search_dn1_free(ldb, &msg);
+ return -1;
+ }
+ list->count++;
}
- list->count++;
}
ltdb_search_dn1_free(ldb, &msg);
@@ -471,17 +487,75 @@ int ltdb_search_indexed(struct ldb_context *ldb,
}
/*
+ add a index element where this is the first indexed DN for this value
+*/
+static int ltdb_index_add1_new(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ const char *dn)
+{
+ struct ldb_message_element *el2;
+
+ /* add another entry */
+ el2 = realloc_p(msg->elements, struct ldb_message_element, msg->num_elements+1);
+ if (!el2) {
+ return -1;
+ }
+
+ msg->elements = el2;
+ msg->elements[msg->num_elements].name = "@IDX";
+ msg->elements[msg->num_elements].num_values = 0;
+ msg->elements[msg->num_elements].values = malloc_p(struct ldb_val);
+ if (!msg->elements[msg->num_elements].values) {
+ return -1;
+ }
+ msg->elements[msg->num_elements].values[0].length = strlen(dn);
+ msg->elements[msg->num_elements].values[0].data = dn;
+ msg->elements[msg->num_elements].num_values = 1;
+ msg->num_elements++;
+
+ return 0;
+}
+
+
+/*
+ add a index element where this is not the first indexed DN for this
+ value
+*/
+static int ltdb_index_add1_add(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ int idx,
+ const char *dn)
+{
+ struct ldb_val *v2;
+
+ v2 = realloc_p(msg->elements[idx].values,
+ struct ldb_val,
+ msg->elements[idx].num_values+1);
+ if (!v2) {
+ return -1;
+ }
+ msg->elements[idx].values = v2;
+
+ msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
+ msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
+ msg->elements[idx].num_values++;
+
+ return 0;
+}
+
+/*
add an index entry for one message element
*/
static int ltdb_index_add1(struct ldb_context *ldb, const char *dn,
- struct ldb_message_element *el)
+ struct ldb_message_element *el, int v_idx)
{
struct ldb_message msg;
char *dn_key;
- int ret;
- struct ldb_message_element *el2;
+ int ret, i;
- dn_key = ldb_dn_key(el->name, &el->value);
+ dn_key = ldb_dn_key(el->name, &el->values[v_idx]);
if (!dn_key) {
return -1;
}
@@ -493,36 +567,37 @@ static int ltdb_index_add1(struct ldb_context *ldb, const char *dn,
}
if (ret == 0) {
- msg.dn = dn_key;
+ msg.dn = strdup(dn_key);
+ if (!msg.dn) {
+ free(dn_key);
+ errno = ENOMEM;
+ return -1;
+ }
msg.num_elements = 0;
msg.elements = NULL;
msg.private = NULL;
}
- /* add another entry */
- el2 = realloc_p(msg.elements, struct ldb_message_element, msg.num_elements+1);
- if (!el2) {
- if (ret == 1) {
- ltdb_search_dn1_free(ldb, &msg);
+ free(dn_key);
+
+ for (i=0;i<msg.num_elements;i++) {
+ if (strcmp("@IDX", msg.elements[i].name) == 0) {
+ break;
}
- free(dn_key);
- return -1;
}
- msg.elements = el2;
- msg.elements[msg.num_elements].name = "@IDX";
- msg.elements[msg.num_elements].value.length = strlen(dn);
- msg.elements[msg.num_elements].value.data = dn;
- msg.num_elements++;
-
- ret = ltdb_store(ldb, &msg, TDB_REPLACE);
-
- if (msg.num_elements == 1) {
- free(msg.elements);
+ if (i == msg.num_elements) {
+ ret = ltdb_index_add1_new(ldb, &msg, el, dn);
} else {
- ltdb_search_dn1_free(ldb, &msg);
+ ret = ltdb_index_add1_add(ldb, &msg, el, i, dn);
+ }
+
+ if (ret == 0) {
+ ret = ltdb_store(ldb, &msg, TDB_REPLACE);
}
+ ltdb_search_dn1_free(ldb, &msg);
+
return ret;
}
@@ -532,7 +607,7 @@ static int ltdb_index_add1(struct ldb_context *ldb, const char *dn,
*/
int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
{
- int ret, i;
+ int ret, i, j;
struct ldb_message index_list;
/* find the list of indexed fields */
@@ -543,17 +618,21 @@ int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
}
for (i=0;i<msg->num_elements;i++) {
- ret = ldb_msg_find_idx(&index_list, msg->elements[i].name);
+ ret = ldb_msg_find_idx(&index_list, msg->elements[i].name, NULL);
if (ret == -1) {
continue;
}
- ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i]);
- if (ret == -1) {
- ltdb_search_dn1_free(ldb, &index_list);
- return -1;
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i], j);
+ if (ret == -1) {
+ ltdb_search_dn1_free(ldb, &index_list);
+ return -1;
+ }
}
}
+ ltdb_search_dn1_free(ldb, &index_list);
+
return 0;
}
@@ -562,13 +641,13 @@ int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
delete an index entry for one message element
*/
static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
- struct ldb_message_element *el)
+ struct ldb_message_element *el, int v_idx)
{
struct ldb_message msg;
char *dn_key;
- int ret, i;
+ int ret, i, j;
- dn_key = ldb_dn_key(el->name, &el->value);
+ dn_key = ldb_dn_key(el->name, &el->values[v_idx]);
if (!dn_key) {
return -1;
}
@@ -586,19 +665,22 @@ static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
return 0;
}
- i = ldb_msg_find_idx(&msg, dn);
+ i = ldb_msg_find_idx(&msg, dn, &j);
if (i == -1) {
/* it ain't there. hmmm */
ltdb_search_dn1_free(ldb, &msg);
return 0;
}
- if (i != msg.num_elements - 1) {
- memmove(&msg.elements[i], &msg.elements[i+1], sizeof(msg.elements[i]));
+ if (j != msg.elements[i].num_values - 1) {
+ memmove(&msg.elements[i].values[j],
+ &msg.elements[i].values[j+1],
+ (msg.elements[i].num_values-1) *
+ sizeof(msg.elements[i].values[0]));
}
- msg.num_elements--;
+ msg.elements[i].num_values--;
- if (msg.num_elements == 0) {
+ if (msg.elements[i].num_values == 0) {
ret = ltdb_delete_noindex(ldb, dn_key);
} else {
ret = ltdb_store(ldb, &msg, TDB_REPLACE);
@@ -615,7 +697,7 @@ static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
*/
int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg)
{
- int ret, i;
+ int ret, i, j;
struct ldb_message index_list;
/* find the list of indexed fields */
@@ -626,14 +708,16 @@ int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg)
}
for (i=0;i<msg->num_elements;i++) {
- ret = ldb_msg_find_idx(&index_list, msg->elements[i].name);
+ ret = ldb_msg_find_idx(&index_list, msg->elements[i].name, NULL);
if (ret == -1) {
continue;
}
- ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i]);
- if (ret == -1) {
- ltdb_search_dn1_free(ldb, &index_list);
- return -1;
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i], j);
+ if (ret == -1) {
+ ltdb_search_dn1_free(ldb, &index_list);
+ return -1;
+ }
}
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_match.c b/source4/lib/ldb/ldb_tdb/ldb_match.c
index 89d204f56a..6f29726ee7 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_match.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_match.c
@@ -39,7 +39,7 @@
see if two ldb_val structures contain the same data
return 1 for a match, 0 for a mis-match
*/
-static int ldb_val_equal(struct ldb_val *v1, struct ldb_val *v2)
+int ldb_val_equal(const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) return 0;
@@ -108,7 +108,7 @@ static int match_leaf(struct ldb_context *ldb,
const char *base,
enum ldb_scope scope)
{
- int i;
+ int i, j;
if (!scope_match(msg->dn, base, scope)) {
return 0;
@@ -122,10 +122,16 @@ static int match_leaf(struct ldb_context *ldb,
}
for (i=0;i<msg->num_elements;i++) {
- if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0 &&
- (strcmp(tree->u.simple.value.data, "*") == 0 ||
- ldb_val_equal(&msg->elements[i].value, &tree->u.simple.value))) {
- return 1;
+ if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0) {
+ if (strcmp(tree->u.simple.value.data, "*") == 0) {
+ return 1;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (ldb_val_equal(&msg->elements[i].values[j],
+ &tree->u.simple.value)) {
+ return 1;
+ }
+ }
}
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_pack.c b/source4/lib/ldb/ldb_tdb/ldb_pack.c
index b0c825e8e2..1b0c8a1857 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_pack.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_pack.c
@@ -41,13 +41,16 @@
/*
pack a ldb message into a linear buffer in a TDB_DATA
+ note that this routine avoids saving elements with zero values,
+ as these are equivalent to having no element
+
caller frees the data buffer after use
*/
int ltdb_pack_data(struct ldb_context *ctx,
const struct ldb_message *message,
struct TDB_DATA *data)
{
- int i;
+ int i, j;
size_t size;
char *p;
@@ -55,8 +58,13 @@ int ltdb_pack_data(struct ldb_context *ctx,
size = 8;
for (i=0;i<message->num_elements;i++) {
- size += 1 + strlen(message->elements[i].name);
- size += 4 + message->elements[i].value.length + 1;
+ if (message->elements[i].num_values == 0) {
+ continue;
+ }
+ size += 1 + strlen(message->elements[i].name) + 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ size += 4 + message->elements[i].values[j].length + 1;
+ }
}
/* allocate it */
@@ -73,28 +81,50 @@ int ltdb_pack_data(struct ldb_context *ctx,
p += 8;
for (i=0;i<message->num_elements;i++) {
- size_t len = strlen(message->elements[i].name);
+ size_t len;
+ if (message->elements[i].num_values == 0) {
+ continue;
+ }
+ len = strlen(message->elements[i].name);
memcpy(p, message->elements[i].name, len+1);
p += len + 1;
- SIVAL(p, 0, message->elements[i].value.length);
- memcpy(p+4, message->elements[i].value.data,
- message->elements[i].value.length);
- p[4+message->elements[i].value.length] = 0;
- p += 4 + message->elements[i].value.length + 1;
+ SIVAL(p, 0, message->elements[i].num_values);
+ p += 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ SIVAL(p, 0, message->elements[i].values[j].length);
+ memcpy(p+4, message->elements[i].values[j].data,
+ message->elements[i].values[j].length);
+ p[4+message->elements[i].values[j].length] = 0;
+ p += 4 + message->elements[i].values[j].length + 1;
+ }
}
return 0;
}
+/*
+ free the memory allocated from a ltdb_unpack_data()
+*/
+void ltdb_unpack_data_free(struct ldb_message *message)
+{
+ int i;
+
+ for (i=0;i<message->num_elements;i++) {
+ if (message->elements[i].values) free(message->elements[i].values);
+ }
+ if (message->elements) free(message->elements);
+}
+
/*
unpack a ldb message from a linear buffer in TDB_DATA
note that this does not fill in the class and key elements
- caller frees. Memory for the elements[] array is malloced,
- but the memory for the elements is re-used from the TDB_DATA
- data. This means the caller only has to free the elements array
+ caller frees. Memory for the elements[] and values[] arrays are
+ malloced, but the memory for the elements is re-used from the
+ TDB_DATA data. This means the caller only has to free the elements
+ and values arrays. This can be done with ltdb_unpack_data_free()
*/
int ltdb_unpack_data(struct ldb_context *ctx,
const struct TDB_DATA *data,
@@ -102,7 +132,7 @@ int ltdb_unpack_data(struct ldb_context *ctx,
{
char *p;
unsigned int remaining;
- int i;
+ int i, j;
message->elements = NULL;
@@ -145,30 +175,44 @@ int ltdb_unpack_data(struct ldb_context *ctx,
for (i=0;i<message->num_elements;i++) {
size_t len;
- if (remaining < 6) {
+ if (remaining < 10) {
errno = EIO;
goto failed;
}
len = strnlen(p, remaining-6);
+ message->elements[i].flags = 0;
message->elements[i].name = p;
remaining -= len + 1;
p += len + 1;
- len = IVAL(p, 0);
- if (len > remaining-5) {
- errno = EIO;
- goto failed;
+ message->elements[i].num_values = IVAL(p, 0);
+ message->elements[i].values = NULL;
+ if (message->elements[i].num_values != 0) {
+ message->elements[i].values = malloc_array_p(struct ldb_val,
+ message->elements[i].num_values);
+ if (!message->elements[i].values) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+ p += 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ len = IVAL(p, 0);
+ if (len > remaining-5) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements[i].values[j].length = len;
+ message->elements[i].values[j].data = p+4;
+ remaining -= len+4+1;
+ p += len+4+1;
}
- message->elements[i].value.length = len;
- message->elements[i].value.data = p+4;
- remaining -= len+4+1;
- p += len+4+1;
}
return 0;
failed:
- if (message->elements) {
- free(message->elements);
- }
+ ltdb_unpack_data_free(message);
+
return -1;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c
index 952053c920..d7a7b7ffbd 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_search.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_search.c
@@ -40,11 +40,15 @@
*/
static void msg_free_all_parts(struct ldb_message *msg)
{
- int i;
+ int i, j;
if (msg->dn) free(msg->dn);
for (i=0;i<msg->num_elements;i++) {
if (msg->elements[i].name) free(msg->elements[i].name);
- if (msg->elements[i].value.data) free(msg->elements[i].value.data);
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (msg->elements[i].values[j].data)
+ free(msg->elements[i].values[j].data);
+ }
+ if (msg->elements[i].values) free(msg->elements[i].values);
}
free(msg->elements);
free(msg);
@@ -53,6 +57,7 @@ static void msg_free_all_parts(struct ldb_message *msg)
/*
TODO: this should take advantage of the sorted nature of the message
+
return index of the attribute, or -1 if not found
*/
int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr)
@@ -69,7 +74,7 @@ int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr)
/*
duplicate a ldb_val structure
*/
-static struct ldb_val ldb_val_dup(const struct ldb_val *v)
+struct ldb_val ldb_val_dup(const struct ldb_val *v)
{
struct ldb_val v2;
v2.length = v->length;
@@ -98,7 +103,8 @@ static struct ldb_val ldb_val_dup(const struct ldb_val *v)
*/
static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el)
{
- struct ldb_message_element *e2;
+ int i;
+ struct ldb_message_element *e2, *elnew;
e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1);
if (!e2) {
@@ -106,15 +112,31 @@ static int msg_add_element(struct ldb_message *ret, const struct ldb_message_ele
}
ret->elements = e2;
- e2[ret->num_elements].name = strdup(el->name);
- if (!e2[ret->num_elements].name) {
+ elnew = &e2[ret->num_elements];
+
+ elnew->name = strdup(el->name);
+ if (!elnew->name) {
return -1;
}
- e2[ret->num_elements].value = ldb_val_dup(&el->value);
- if (e2[ret->num_elements].value.length != el->value.length) {
- return -1;
+
+ if (el->num_values) {
+ elnew->values = malloc_array_p(struct ldb_val, el->num_values);
+ if (!elnew->values) {
+ return -1;
+ }
+ } else {
+ elnew->values = NULL;
}
+ for (i=0;i<el->num_values;i++) {
+ elnew->values[i] = ldb_val_dup(&el->values[i]);
+ if (elnew->values[i].length != el->values[i].length) {
+ return -1;
+ }
+ }
+
+ elnew->num_values = el->num_values;
+
ret->num_elements++;
return 0;
@@ -215,8 +237,12 @@ int ltdb_has_wildcard(const struct ldb_val *val)
*/
void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
{
- free(msg->dn);
- free(msg->private);
+ int i;
+ if (msg->dn) free(msg->dn);
+ if (msg->private) free(msg->private);
+ for (i=0;i<msg->num_elements;i++) {
+ if (msg->elements[i].values) free(msg->elements[i].values);
+ }
if (msg->elements) free(msg->elements);
}
@@ -375,7 +401,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
/* see if it matches the given expression */
if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree,
sinfo->base, sinfo->scope)) {
- if (msg.elements) free(msg.elements);
+ ltdb_unpack_data_free(&msg);
return 0;
}
@@ -385,7 +411,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
sinfo->failures++;
}
- if (msg.elements) free(msg.elements);
+ ltdb_unpack_data_free(&msg);
return ret;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index 17931352f7..95dce498f1 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -58,6 +58,44 @@ struct TDB_DATA ltdb_key(const char *dn)
return key;
}
+/*
+ lock the database for write - currently a single lock is used
+*/
+static int ltdb_lock(struct ldb_context *ldb)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA key;
+ int ret;
+
+ key = ltdb_key("LDBLOCK");
+ if (!key.dptr) {
+ return -1;
+ }
+
+ ret = tdb_chainlock(ltdb->tdb, key);
+
+ free(key.dptr);
+
+ return ret;
+}
+
+/*
+ unlock the database after a ltdb_lock()
+*/
+static void ltdb_unlock(struct ldb_context *ldb)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA key;
+
+ key = ltdb_key("LDBLOCK");
+ if (!key.dptr) {
+ return;
+ }
+
+ tdb_chainunlock(ltdb->tdb, key);
+
+ free(key.dptr);
+}
/*
store a record into the db
@@ -102,7 +140,17 @@ done:
*/
static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg)
{
- return ltdb_store(ldb, msg, TDB_INSERT);
+ int ret;
+
+ if (ltdb_lock(ldb) != 0) {
+ return -1;
+ }
+
+ ret = ltdb_store(ldb, msg, TDB_INSERT);
+
+ ltdb_unlock(ldb);
+
+ return ret;
}
@@ -135,18 +183,22 @@ static int ltdb_delete(struct ldb_context *ldb, const char *dn)
int ret;
struct ldb_message msg;
+ if (ltdb_lock(ldb) != 0) {
+ return -1;
+ }
+
/* in case any attribute of the message was indexed, we need
to fetch the old record */
ret = ltdb_search_dn1(ldb, dn, &msg);
if (ret != 1) {
/* not finding the old record is an error */
- return -1;
+ goto failed;
}
ret = ltdb_delete_noindex(ldb, dn);
if (ret == -1) {
ltdb_search_dn1_free(ldb, &msg);
- return -1;
+ goto failed;
}
/* remove any indexed attributes */
@@ -154,57 +206,244 @@ static int ltdb_delete(struct ldb_context *ldb, const char *dn)
ltdb_search_dn1_free(ldb, &msg);
+ ltdb_unlock(ldb);
return ret;
+
+failed:
+ ltdb_unlock(ldb);
+ return -1;
+}
+
+
+/*
+ find an element by attribute name. At the moment this does a linear search, it should
+ be re-coded to use a binary search once all places that modify records guarantee
+ sorted order
+
+ return the index of the first matching element if found, otherwise -1
+*/
+static int find_element(const struct ldb_message *msg, const char *name)
+{
+ int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ add an element to an existing record. Assumes a elements array that we
+ can call re-alloc on, and assumed that we can re-use the data pointers from the
+ passed in additional values. Use with care!
+
+ returns 0 on success, -1 on failure (and sets errno)
+*/
+static int msg_add_element(struct ldb_message *msg, struct ldb_message_element *el)
+{
+ struct ldb_message_element *e2;
+ int i;
+
+ e2 = realloc_p(msg->elements, struct ldb_message_element,
+ msg->num_elements+1);
+ if (!e2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = e2;
+
+ e2 = &msg->elements[msg->num_elements];
+
+ e2->name = el->name;
+ e2->flags = el->flags;
+ e2->values = NULL;
+ if (el->num_values != 0) {
+ e2->values = malloc_array_p(struct ldb_val, el->num_values);
+ if (!e2->values) {
+ free(e2->name);
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ for (i=0;i<el->num_values;i++) {
+ e2->values[i] = el->values[i];
+ }
+ e2->num_values = el->num_values;
+
+ msg->num_elements++;
+
+ return 0;
+}
+
+/*
+ delete all elements having a specified attribute name
+*/
+static int msg_delete_attribute(struct ldb_message *msg, const char *name)
+{
+ int i, count=0;
+ struct ldb_message_element *el2;
+
+ el2 = malloc_array_p(struct ldb_message_element, msg->num_elements);
+ if (!el2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, name) != 0) {
+ el2[count++] = msg->elements[i];
+ } else {
+ if (msg->elements[i].values) free(msg->elements[i].values);
+ }
+ }
+
+ msg->num_elements = count;
+ if (msg->elements) free(msg->elements);
+ msg->elements = el2;
+
+ return 0;
}
+/*
+ delete all elements matching an attribute name/value
+
+ return 0 on success, -1 on failure
+*/
+static int msg_delete_element(struct ldb_message *msg,
+ const char *name,
+ const struct ldb_val *val)
+{
+ int i;
+ struct ldb_message_element *el;
+
+ i = find_element(msg, name);
+ if (i == -1) {
+ return -1;
+ }
+
+ el = &msg->elements[i];
+
+ for (i=0;i<el->num_values;i++) {
+ if (ldb_val_equal(&el->values[i], val)) {
+ 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--;
+ return 0;
+ }
+ }
+
+ return -1;
+}
/*
modify a record
+
+ yuck - this is O(n^2). Luckily n is usually small so we probably
+ get away with it, but if we ever have really large attribute lists
+ then we'll need to look at this again
*/
static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
{
struct ltdb_private *ltdb = ldb->private;
TDB_DATA tdb_key, tdb_data;
struct ldb_message msg2;
- int ret;
+ int ret, i, j;
+
+ if (ltdb_lock(ldb) != 0) {
+ return -1;
+ }
tdb_key = ltdb_key(msg->dn);
if (!tdb_key.dptr) {
- return -1;
+ goto unlock_fail;
}
tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
if (!tdb_data.dptr) {
free(tdb_key.dptr);
- return -1;
+ goto unlock_fail;
}
ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
if (ret == -1) {
free(tdb_key.dptr);
free(tdb_data.dptr);
- return -1;
+ goto unlock_fail;
}
-#if 0
+ msg2.dn = msg->dn;
+
for (i=0;i<msg->num_elements;i++) {
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+
case LDB_FLAG_MOD_ADD:
+ /* add this element to the message. fail if it
+ already exists */
ret = find_element(&msg2, msg->elements[i].name);
if (ret != -1) {
errno = EEXIST;
goto failed;
}
-
+ if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
+ goto failed;
+ }
+ break;
+
+ case LDB_FLAG_MOD_REPLACE:
+ /* replace all elements of this attribute name with the elements
+ listed */
+ if (msg_delete_attribute(&msg2, msg->elements[i].name) != 0) {
+ goto failed;
+ }
+ /* add the replacement element */
+ if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
+ goto failed;
+ }
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+ /* we could be being asked to delete all
+ values or just some values */
+ if (msg->elements[i].num_values == 0) {
+ if (msg_delete_attribute(&msg2,
+ msg->elements[i].name) != 0) {
+ goto failed;
+ }
+ break;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (msg_delete_element(&msg2,
+ msg->elements[i].name,
+ &msg->elements[i].values[j]) != 0) {
+ goto failed;
+ }
+ }
+ break;
}
}
-failed:
-#endif
+ /* we've made all the mods - save the modified record back into the database */
+ ret = ltdb_store(ldb, &msg2, TDB_MODIFY);
+
+ free(tdb_key.dptr);
+ free(tdb_data.dptr);
+ ltdb_unpack_data_free(&msg2);
+ ltdb_unlock(ldb);
+ return ret;
+
+failed:
free(tdb_key.dptr);
free(tdb_data.dptr);
- if (msg2.elements) free(msg2.elements);
+ ltdb_unpack_data_free(&msg2);
+
+unlock_fail:
+ ltdb_unlock(ldb);
return -1;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldbadd.c b/source4/lib/ldb/ldb_tdb/ldbadd.c
deleted file mode 100644
index 3959a17525..0000000000
--- a/source4/lib/ldb/ldb_tdb/ldbadd.c
+++ /dev/null
@@ -1,55 +0,0 @@
- /*
- Unix SMB/CIFS implementation.
-
- a utility to add elements to a ldb
-
- Copyright (C) Andrew Tridgell 2004
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
- int main(void)
-{
- static struct ldb_context *ldb;
- struct ldb_message *msg;
- int ret;
- int count=0, failures=0;
-
- ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
-
- if (!ldb) {
- perror("ldb_connect");
- exit(1);
- }
-
- while ((msg = ldif_read(stdin))) {
- ret = ldb->ops->add(ldb, msg);
- if (ret != 0) {
- fprintf(stderr, "Failed to add record '%s'\n", msg->dn);
- failures++;
- } else {
- count++;
- }
- ldif_read_free(msg);
- }
-
- ldb->ops->close(ldb);
-
- printf("Added %d records with %d failures\n", count, failures);
-
- return 0;
-}
diff --git a/source4/lib/ldb/ldb_tdb/ldbdel.c b/source4/lib/ldb/ldb_tdb/ldbdel.c
deleted file mode 100644
index 8f8a03913f..0000000000
--- a/source4/lib/ldb/ldb_tdb/ldbdel.c
+++ /dev/null
@@ -1,50 +0,0 @@
- /*
- Unix SMB/CIFS implementation.
-
- a utility to delete elements in a ldb
-
- Copyright (C) Andrew Tridgell 2004
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
- int main(int argc, const char *argv[])
-{
- static struct ldb_context *ldb;
- int ret, i;
-
- if (argc < 2) {
- printf("Usage: ldbdel <dn...>\n");
- exit(1);
- }
-
- ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
- if (!ldb) {
- perror("ldb_connect");
- exit(1);
- }
-
- for (i=1;i<argc;i++) {
- ret = ldb->ops->delete(ldb, argv[i]);
- if (ret != 0) {
- printf("delete of '%s' failed\n", argv[i]);
- }
- }
-
- ldb->ops->close(ldb);
- return 0;
-}
diff --git a/source4/lib/ldb/ldb_tdb/ldbsearch.c b/source4/lib/ldb/ldb_tdb/ldbsearch.c
deleted file mode 100644
index a6d63e78d5..0000000000
--- a/source4/lib/ldb/ldb_tdb/ldbsearch.c
+++ /dev/null
@@ -1,73 +0,0 @@
- /*
- Unix SMB/CIFS implementation.
-
- simple ldb search tool
-
- Copyright (C) Andrew Tridgell 2004
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
- int main(int argc, const char *argv[])
-{
- static struct ldb_context *ldb;
- struct ldb_message **msgs;
- int ret, i;
- const char *expression;
- const char **attrs = NULL;
-
- if (argc < 2) {
- printf("Usage: ldbsearch <expression> [attrs...]\n");
- exit(1);
- }
-
- if (argc > 2) {
- attrs = argv+2;
- }
-
- expression = argv[1];
-
- ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
-
- if (!ldb) {
- perror("ldb_connect");
- exit(1);
- }
-
- ret = ldb->ops->search(ldb, expression, attrs, &msgs);
-
- if (ret == -1) {
- printf("search failed\n");
- exit(1);
- }
-
- printf("# returned %d records\n", ret);
-
- for (i=0;i<ret;i++) {
- printf("# record %d\n", i+1);
- ldif_write(stdout, msgs[i]);
- }
-
- ret = ldb->ops->search_free(ldb, msgs);
- if (ret == -1) {
- fprintf(stderr, "search_free failed\n");
- exit(1);
- }
-
- ldb->ops->close(ldb);
- return 0;
-}