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)));
448 modify a record - internal interface
450 yuck - this is O(n^2). Luckily n is usually small so we probably
451 get away with it, but if we ever have really large attribute lists
452 then we'll need to look at this again
454 int ltdb_modify_internal(struct ldb_context *ldb, const struct ldb_message *msg)
456 struct ltdb_private *ltdb = ldb->private_data;
457 TDB_DATA tdb_key, tdb_data;
458 struct ldb_message msg2;
461 tdb_key = ltdb_key(ldb, msg->dn);
466 tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
467 if (!tdb_data.dptr) {
472 ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
474 ldb_free(ldb, tdb_key.dptr);
483 for (i=0;i<msg->num_elements;i++) {
484 switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
486 case LDB_FLAG_MOD_ADD:
487 /* add this element to the message. fail if it
489 ret = find_element(&msg2, msg->elements[i].name);
494 if (msg_add_element(ldb, &msg2, &msg->elements[i]) != 0) {
499 case LDB_FLAG_MOD_REPLACE:
500 /* replace all elements of this attribute name with the elements
502 if (msg_delete_attribute(ldb, &msg2, msg->elements[i].name) != 0) {
505 /* add the replacement element */
506 if (msg_add_element(ldb, &msg2, &msg->elements[i]) != 0) {
511 case LDB_FLAG_MOD_DELETE:
512 /* we could be being asked to delete all
513 values or just some values */
514 if (msg->elements[i].num_values == 0) {
515 if (msg_delete_attribute(ldb, &msg2,
516 msg->elements[i].name) != 0) {
521 for (j=0;j<msg->elements[i].num_values;j++) {
522 if (msg_delete_element(ldb,
524 msg->elements[i].name,
525 &msg->elements[i].values[j]) != 0) {
533 /* we've made all the mods - save the modified record back into the database */
534 ret = ltdb_store(ldb, &msg2, TDB_MODIFY);
536 ldb_free(ldb, tdb_key.dptr);
538 ltdb_unpack_data_free(ldb, &msg2);
542 ldb_free(ldb, tdb_key.dptr);
544 ltdb_unpack_data_free(ldb, &msg2);
551 static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
553 struct ltdb_private *ltdb = ldb->private_data;
556 ltdb->last_err_string = NULL;
558 if (ltdb_lock(ldb) != 0) {
562 if (ltdb_cache_load(ldb) != 0) {
567 ret = ltdb_modify_internal(ldb, msg);
570 ltdb_modified(ldb, msg->dn);
581 static int ltdb_close(struct ldb_context *ldb)
583 struct ltdb_private *ltdb = ldb->private_data;
586 ltdb->last_err_string = NULL;
588 ltdb_cache_free(ldb);
589 ldb_set_alloc(ldb, NULL, NULL);
591 ret = tdb_close(ltdb->tdb);
599 return extended error information
601 static const char *ltdb_errstring(struct ldb_context *ldb)
603 struct ltdb_private *ltdb = ldb->private_data;
604 if (ltdb->last_err_string) {
605 return ltdb->last_err_string;
607 return tdb_errorstr(ltdb->tdb);
611 static const struct ldb_backend_ops ltdb_ops = {
624 connect to the database
626 struct ldb_context *ltdb_connect(const char *url,
628 const char *options[])
631 int tdb_flags, open_flags;
632 struct ltdb_private *ltdb;
634 struct ldb_context *ldb;
636 ldb = calloc(1, sizeof(struct ldb_context));
643 if (strchr(url, ':')) {
644 if (strncmp(url, "tdb://", 6) != 0) {
653 tdb_flags = TDB_DEFAULT;
655 if (flags & LDB_FLG_RDONLY) {
656 open_flags = O_RDONLY;
658 open_flags = O_CREAT | O_RDWR;
661 /* note that we use quite a large default hash size */
662 tdb = tdb_open(path, 10000, tdb_flags, open_flags, 0666);
668 ltdb = ldb_malloc_p(ldb, struct ltdb_private);
677 ltdb->sequence_number = 0;
679 memset(<db->cache, 0, sizeof(ltdb->cache));
681 ldb->private_data = ltdb;
682 ldb->ops = <db_ops;