4 Copyright (C) Andrew Tridgell 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb tdb backend
30 * Description: core functions for tdb backend
32 * Author: Andrew Tridgell
36 #include "ldb/ldb_tdb/ldb_tdb.h"
39 form a TDB_DATA for a record key
42 note that the key for a record can depend on whether the
43 dn refers to a case sensitive index record or not
45 struct TDB_DATA ltdb_key(struct ldb_context *ldb, const char *dn)
49 char *dn_folded = NULL;
50 const char *prefix = LTDB_INDEX ":";
55 most DNs are case insensitive. The exception is index DNs for
56 case sensitive attributes
58 there are 3 cases dealt with in this code:
60 1) if the dn doesn't start with @INDEX: then uppercase whole dn
61 2) if the dn starts with @INDEX:attr and 'attr' is a case insensitive
62 attribute then uppercase whole dn
63 3) if the dn starts with @INDEX:attr and 'attr' is a case sensitive
64 attribute then uppercase up to the value of the attribute, but
67 if (strncmp(dn, prefix, strlen(prefix)) == 0 &&
68 (s = strchr(dn+strlen(prefix), ':'))) {
69 char *attr_name, *attr_name_folded;
70 attr_name = ldb_strndup(ldb, dn+strlen(prefix), (s-(dn+strlen(prefix))));
74 flags = ltdb_attribute_flags(ldb, attr_name);
76 if (flags & LTDB_FLAG_CASE_INSENSITIVE) {
77 dn_folded = ldb_casefold(ldb, dn);
79 attr_name_folded = ldb_casefold(ldb, attr_name);
80 if (!attr_name_folded) {
83 ldb_asprintf(ldb, &dn_folded, "%s:%s:%s",
84 prefix, attr_name_folded,
86 ldb_free(ldb, attr_name_folded);
88 ldb_free(ldb, attr_name);
90 dn_folded = ldb_casefold(ldb, dn);
97 ldb_asprintf(ldb, &key_str, "DN=%s", dn_folded);
98 ldb_free(ldb, dn_folded);
105 key.dsize = strlen(key_str)+1;
117 lock the database for write - currently a single lock is used
119 static int ltdb_lock(struct ldb_context *ldb)
121 struct ltdb_private *ltdb = ldb->private_data;
125 key = ltdb_key(ldb, "LDBLOCK");
130 ret = tdb_chainlock(ltdb->tdb, key);
132 ldb_free(ldb, key.dptr);
138 unlock the database after a ltdb_lock()
140 static void ltdb_unlock(struct ldb_context *ldb)
142 struct ltdb_private *ltdb = ldb->private_data;
145 key = ltdb_key(ldb, "LDBLOCK");
150 tdb_chainunlock(ltdb->tdb, key);
152 ldb_free(ldb, key.dptr);
157 we've made a modification to a dn - possibly reindex and
158 update sequence number
160 static int ltdb_modified(struct ldb_context *ldb, const char *dn)
164 if (strcmp(dn, LTDB_INDEXLIST) == 0 ||
165 strcmp(dn, LTDB_ATTRIBUTES) == 0) {
166 ret = ltdb_reindex(ldb);
170 strcmp(dn, LTDB_BASEINFO) != 0) {
171 ret = ltdb_increase_sequence_number(ldb);
178 store a record into the db
180 int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs)
182 struct ltdb_private *ltdb = ldb->private_data;
183 TDB_DATA tdb_key, tdb_data;
186 tdb_key = ltdb_key(ldb, msg->dn);
191 ret = ltdb_pack_data(ldb, msg, &tdb_data);
193 ldb_free(ldb, tdb_key.dptr);
197 ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
202 ret = ltdb_index_add(ldb, msg);
204 tdb_delete(ltdb->tdb, tdb_key);
208 ldb_free(ldb, tdb_key.dptr);
209 ldb_free(ldb, tdb_data.dptr);
216 add a record to the database
218 static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg)
220 struct ltdb_private *ltdb = ldb->private_data;
223 ltdb->last_err_string = NULL;
225 if (ltdb_lock(ldb) != 0) {
229 if (ltdb_cache_load(ldb) != 0) {
234 ret = ltdb_store(ldb, msg, TDB_INSERT);
237 ltdb_modified(ldb, msg->dn);
246 delete a record from the database, not updating indexes (used for deleting
249 int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn)
251 struct ltdb_private *ltdb = ldb->private_data;
255 tdb_key = ltdb_key(ldb, dn);
260 ret = tdb_delete(ltdb->tdb, tdb_key);
261 ldb_free(ldb, tdb_key.dptr);
267 delete a record from the database
269 static int ltdb_delete(struct ldb_context *ldb, const char *dn)
271 struct ltdb_private *ltdb = ldb->private_data;
273 struct ldb_message msg;
275 ltdb->last_err_string = NULL;
277 if (ltdb_lock(ldb) != 0) {
281 if (ltdb_cache_load(ldb) != 0) {
286 /* in case any attribute of the message was indexed, we need
287 to fetch the old record */
288 ret = ltdb_search_dn1(ldb, dn, &msg);
290 /* not finding the old record is an error */
294 ret = ltdb_delete_noindex(ldb, dn);
296 ltdb_search_dn1_free(ldb, &msg);
300 /* remove any indexed attributes */
301 ret = ltdb_index_del(ldb, &msg);
303 ltdb_search_dn1_free(ldb, &msg);
306 ltdb_modified(ldb, dn);
319 find an element by attribute name. At the moment this does a linear search, it should
320 be re-coded to use a binary search once all places that modify records guarantee
323 return the index of the first matching element if found, otherwise -1
325 static int find_element(const struct ldb_message *msg, const char *name)
328 for (i=0;i<msg->num_elements;i++) {
329 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
338 add an element to an existing record. Assumes a elements array that we
339 can call re-alloc on, and assumed that we can re-use the data pointers from the
340 passed in additional values. Use with care!
342 returns 0 on success, -1 on failure (and sets errno)
344 static int msg_add_element(struct ldb_context *ldb,
345 struct ldb_message *msg, struct ldb_message_element *el)
347 struct ldb_message_element *e2;
350 e2 = ldb_realloc_p(ldb, msg->elements, struct ldb_message_element,
351 msg->num_elements+1);
359 e2 = &msg->elements[msg->num_elements];
362 e2->flags = el->flags;
364 if (el->num_values != 0) {
365 e2->values = ldb_malloc_array_p(ldb, struct ldb_val, el->num_values);
372 for (i=0;i<el->num_values;i++) {
373 e2->values[i] = el->values[i];
375 e2->num_values = el->num_values;
383 delete all elements having a specified attribute name
385 static int msg_delete_attribute(struct ldb_context *ldb,
386 struct ldb_message *msg, const char *name)
389 struct ldb_message_element *el2;
391 el2 = ldb_malloc_array_p(ldb, struct ldb_message_element, msg->num_elements);
397 for (i=0;i<msg->num_elements;i++) {
398 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
399 el2[count++] = msg->elements[i];
401 ldb_free(ldb, msg->elements[i].values);
405 msg->num_elements = count;
406 ldb_free(ldb, msg->elements);
413 delete all elements matching an attribute name/value
415 return 0 on success, -1 on failure
417 static int msg_delete_element(struct ldb_context *ldb,
418 struct ldb_message *msg,
420 const struct ldb_val *val)
423 struct ldb_message_element *el;
425 i = find_element(msg, name);
430 el = &msg->elements[i];
432 for (i=0;i<el->num_values;i++) {
433 if (ldb_val_equal(ldb, msg->elements[i].name, &el->values[i], val)) {
434 if (i<el->num_values-1) {
435 memmove(&el->values[i], &el->values[i+1],
436 sizeof(el->values[i])*(el->num_values-(i+1)));
439 if (el->num_values == 0) {
440 return msg_delete_attribute(ldb, msg, name);
451 modify a record - internal interface
453 yuck - this is O(n^2). Luckily n is usually small so we probably
454 get away with it, but if we ever have really large attribute lists
455 then we'll need to look at this again
457 int ltdb_modify_internal(struct ldb_context *ldb, const struct ldb_message *msg)
459 struct ltdb_private *ltdb = ldb->private_data;
460 TDB_DATA tdb_key, tdb_data;
461 struct ldb_message msg2;
464 tdb_key = ltdb_key(ldb, msg->dn);
469 tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
470 if (!tdb_data.dptr) {
475 ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
477 ldb_free(ldb, tdb_key.dptr);
486 for (i=0;i<msg->num_elements;i++) {
487 switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
489 case LDB_FLAG_MOD_ADD:
490 /* add this element to the message. fail if it
492 ret = find_element(&msg2, msg->elements[i].name);
494 ltdb->last_err_string = "Attribute exists";
497 if (msg_add_element(ldb, &msg2, &msg->elements[i]) != 0) {
502 case LDB_FLAG_MOD_REPLACE:
503 /* replace all elements of this attribute name with the elements
505 if (msg_delete_attribute(ldb, &msg2, msg->elements[i].name) != 0) {
506 ltdb->last_err_string = "No such attribute";
509 /* add the replacement element */
510 if (msg_add_element(ldb, &msg2, &msg->elements[i]) != 0) {
515 case LDB_FLAG_MOD_DELETE:
516 /* we could be being asked to delete all
517 values or just some values */
518 if (msg->elements[i].num_values == 0) {
519 if (msg_delete_attribute(ldb, &msg2,
520 msg->elements[i].name) != 0) {
521 ltdb->last_err_string = "No such attribute";
526 for (j=0;j<msg->elements[i].num_values;j++) {
527 if (msg_delete_element(ldb,
529 msg->elements[i].name,
530 &msg->elements[i].values[j]) != 0) {
531 ltdb->last_err_string = "No such attribute";
539 /* we've made all the mods - save the modified record back into the database */
540 ret = ltdb_store(ldb, &msg2, TDB_MODIFY);
542 ldb_free(ldb, tdb_key.dptr);
544 ltdb_unpack_data_free(ldb, &msg2);
548 ldb_free(ldb, tdb_key.dptr);
550 ltdb_unpack_data_free(ldb, &msg2);
557 static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
559 struct ltdb_private *ltdb = ldb->private_data;
562 ltdb->last_err_string = NULL;
564 if (ltdb_lock(ldb) != 0) {
568 if (ltdb_cache_load(ldb) != 0) {
573 ret = ltdb_modify_internal(ldb, msg);
576 ltdb_modified(ldb, msg->dn);
587 static int ltdb_close(struct ldb_context *ldb)
589 struct ltdb_private *ltdb = ldb->private_data;
592 ltdb->last_err_string = NULL;
594 ltdb_cache_free(ldb);
595 ldb_set_alloc(ldb, NULL, NULL);
597 ret = tdb_close(ltdb->tdb);
605 return extended error information
607 static const char *ltdb_errstring(struct ldb_context *ldb)
609 struct ltdb_private *ltdb = ldb->private_data;
610 if (ltdb->last_err_string) {
611 return ltdb->last_err_string;
613 return tdb_errorstr(ltdb->tdb);
617 static const struct ldb_backend_ops ltdb_ops = {
630 connect to the database
632 struct ldb_context *ltdb_connect(const char *url,
634 const char *options[])
637 int tdb_flags, open_flags;
638 struct ltdb_private *ltdb;
640 struct ldb_context *ldb;
642 ldb = calloc(1, sizeof(struct ldb_context));
649 if (strchr(url, ':')) {
650 if (strncmp(url, "tdb://", 6) != 0) {
659 tdb_flags = TDB_DEFAULT;
661 if (flags & LDB_FLG_RDONLY) {
662 open_flags = O_RDONLY;
664 open_flags = O_CREAT | O_RDWR;
667 /* note that we use quite a large default hash size */
668 tdb = tdb_open(path, 10000, tdb_flags, open_flags, 0666);
674 ltdb = ldb_malloc_p(ldb, struct ltdb_private);
683 ltdb->sequence_number = 0;
685 memset(<db->cache, 0, sizeof(ltdb->cache));
687 ldb->private_data = ltdb;
688 ldb->ops = <db_ops;