4 Copyright (C) Andrew Tridgell 2004
5 Copyright (C) Stefan Metzmacher 2004
6 Copyright (C) Simo Sorce 2006
9 ** NOTE! The following LGPL license applies to the ldb
10 ** library. This does NOT imply that all of Samba is released
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2 of the License, or (at your option) any later version.
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 * Component: ldb tdb backend
33 * Description: core functions for tdb backend
35 * Author: Andrew Tridgell
36 * Author: Stefan Metzmacher
40 * - description: make the module use asyncronous calls
46 #include "ldb/include/includes.h"
48 #include "ldb/ldb_tdb/ldb_tdb.h"
52 map a tdb error code to a ldb error code
54 static int ltdb_err_map(enum TDB_ERROR tdb_code)
62 return LDB_ERR_OPERATIONS_ERROR;
64 return LDB_ERR_PROTOCOL_ERROR;
68 case TDB_ERR_LOCK_TIMEOUT:
69 return LDB_ERR_TIME_LIMIT_EXCEEDED;
71 return LDB_ERR_ENTRY_ALREADY_EXISTS;
73 return LDB_ERR_NO_SUCH_OBJECT;
75 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
81 struct ldb_async_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module,
83 int (*callback)(struct ldb_context *, void *, struct ldb_async_result *))
85 struct ltdb_async_context *ac;
86 struct ldb_async_handle *h;
88 h = talloc_zero(ltdb, struct ldb_async_handle);
90 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
96 ac = talloc_zero(h, struct ltdb_async_context);
98 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
103 h->private_data = (void *)ac;
105 h->state = LDB_ASYNC_INIT;
106 h->status = LDB_SUCCESS;
109 ac->context = context;
110 ac->callback = callback;
116 form a TDB_DATA for a record key
119 note that the key for a record can depend on whether the
120 dn refers to a case sensitive index record or not
122 struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn)
124 struct ldb_context *ldb = module->ldb;
126 char *key_str = NULL;
127 char *dn_folded = NULL;
130 most DNs are case insensitive. The exception is index DNs for
131 case sensitive attributes
133 there are 3 cases dealt with in this code:
135 1) if the dn doesn't start with @ then uppercase the attribute
136 names and the attributes values of case insensitive attributes
137 2) if the dn starts with @ then leave it alone - the indexing code handles
141 dn_folded = ldb_dn_linearize_casefold(ldb, dn);
146 key_str = talloc_asprintf(ldb, "DN=%s", dn_folded);
148 talloc_free(dn_folded);
154 key.dptr = (uint8_t *)key_str;
155 key.dsize = strlen(key_str) + 1;
167 check special dn's have valid attributes
168 currently only @ATTRIBUTES is checked
170 int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg)
174 if (! ldb_dn_is_special(msg->dn) ||
175 ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) {
179 /* we have @ATTRIBUTES, let's check attributes are fine */
180 /* should we check that we deny multivalued attributes ? */
181 for (i = 0; i < msg->num_elements; i++) {
182 for (j = 0; j < msg->elements[i].num_values; j++) {
183 if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) {
184 char *err_string = talloc_strdup(module, "Invalid attribute value in an @ATTRIBUTES entry");
186 ldb_set_errstring(module->ldb, err_string);
188 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
198 we've made a modification to a dn - possibly reindex and
199 update sequence number
201 static int ltdb_modified(struct ldb_module *module, const struct ldb_dn *dn)
205 if (ldb_dn_is_special(dn) &&
206 (ldb_dn_check_special(dn, LTDB_INDEXLIST) ||
207 ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) {
208 ret = ltdb_reindex(module);
212 !(ldb_dn_is_special(dn) &&
213 ldb_dn_check_special(dn, LTDB_BASEINFO)) ) {
214 ret = ltdb_increase_sequence_number(module);
221 store a record into the db
223 int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs)
225 struct ltdb_private *ltdb = module->private_data;
226 TDB_DATA tdb_key, tdb_data;
229 tdb_key = ltdb_key(module, msg->dn);
231 return LDB_ERR_OTHER;
234 ret = ltdb_pack_data(module, msg, &tdb_data);
236 talloc_free(tdb_key.dptr);
237 return LDB_ERR_OTHER;
240 ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
242 ret = ltdb_err_map(tdb_error(ltdb->tdb));
246 ret = ltdb_index_add(module, msg);
248 tdb_delete(ltdb->tdb, tdb_key);
252 talloc_free(tdb_key.dptr);
253 talloc_free(tdb_data.dptr);
259 static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg)
263 ret = ltdb_check_special_dn(module, msg);
264 if (ret != LDB_SUCCESS) {
265 return LDB_ERR_OPERATIONS_ERROR;
268 if (ltdb_cache_load(module) != 0) {
269 return LDB_ERR_OPERATIONS_ERROR;
272 ret = ltdb_store(module, msg, TDB_INSERT);
273 if (ret != LDB_SUCCESS) {
274 return LDB_ERR_OPERATIONS_ERROR;
277 ret = ltdb_modified(module, msg->dn);
278 if (ret != LDB_SUCCESS) {
279 return LDB_ERR_OPERATIONS_ERROR;
286 add a record to the database
288 static int ltdb_add(struct ldb_module *module, struct ldb_request *req)
290 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
291 struct ltdb_async_context *ltdb_ac;
292 int tret, ret = LDB_SUCCESS;
294 if (req->controls != NULL) {
295 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
296 if (check_critical_controls(req->controls)) {
297 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
301 req->async.handle = init_ltdb_handle(ltdb, module, req->async.context, req->async.callback);
302 if (req->async.handle == NULL) {
303 return LDB_ERR_OPERATIONS_ERROR;
305 ltdb_ac = talloc_get_type(req->async.handle->private_data, struct ltdb_async_context);
307 tret = ltdb_add_internal(module, req->op.add.message);
308 if (tret != LDB_SUCCESS) {
309 req->async.handle->status = tret;
313 if (ltdb_ac->callback) {
314 ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
318 req->async.handle->state = LDB_ASYNC_DONE;
323 delete a record from the database, not updating indexes (used for deleting
326 int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn)
328 struct ltdb_private *ltdb = module->private_data;
332 tdb_key = ltdb_key(module, dn);
334 return LDB_ERR_OTHER;
337 ret = tdb_delete(ltdb->tdb, tdb_key);
338 talloc_free(tdb_key.dptr);
341 ret = ltdb_err_map(tdb_error(ltdb->tdb));
347 static int ltdb_delete_internal(struct ldb_module *module, const struct ldb_dn *dn)
349 struct ldb_message *msg;
352 msg = talloc(module, struct ldb_message);
354 return LDB_ERR_OPERATIONS_ERROR;
357 /* in case any attribute of the message was indexed, we need
358 to fetch the old record */
359 ret = ltdb_search_dn1(module, dn, msg);
361 /* not finding the old record is an error */
363 return LDB_ERR_NO_SUCH_OBJECT;
366 ret = ltdb_delete_noindex(module, dn);
367 if (ret != LDB_SUCCESS) {
369 return LDB_ERR_NO_SUCH_OBJECT;
372 /* remove any indexed attributes */
373 ret = ltdb_index_del(module, msg);
374 if (ret != LDB_SUCCESS) {
376 return LDB_ERR_OPERATIONS_ERROR;
379 ret = ltdb_modified(module, dn);
380 if (ret != LDB_SUCCESS) {
381 return LDB_ERR_OPERATIONS_ERROR;
389 delete a record from the database
391 static int ltdb_delete(struct ldb_module *module, struct ldb_request *req)
393 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
394 struct ltdb_async_context *ltdb_ac;
395 int tret, ret = LDB_SUCCESS;
397 if (req->controls != NULL) {
398 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
399 if (check_critical_controls(req->controls)) {
400 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
404 req->async.handle = NULL;
406 if (ltdb_cache_load(module) != 0) {
407 return LDB_ERR_OPERATIONS_ERROR;
410 req->async.handle = init_ltdb_handle(ltdb, module, req->async.context, req->async.callback);
411 if (req->async.handle == NULL) {
412 return LDB_ERR_OPERATIONS_ERROR;
414 ltdb_ac = talloc_get_type(req->async.handle->private_data, struct ltdb_async_context);
416 tret = ltdb_delete_internal(module, req->op.del.dn);
417 if (tret != LDB_SUCCESS) {
418 req->async.handle->status = tret;
422 if (ltdb_ac->callback)
423 ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
426 req->async.handle->state = LDB_ASYNC_DONE;
431 find an element by attribute name. At the moment this does a linear search, it should
432 be re-coded to use a binary search once all places that modify records guarantee
435 return the index of the first matching element if found, otherwise -1
437 static int find_element(const struct ldb_message *msg, const char *name)
440 for (i=0;i<msg->num_elements;i++) {
441 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
450 add an element to an existing record. Assumes a elements array that we
451 can call re-alloc on, and assumed that we can re-use the data pointers from the
452 passed in additional values. Use with care!
454 returns 0 on success, -1 on failure (and sets errno)
456 static int msg_add_element(struct ldb_context *ldb,
457 struct ldb_message *msg, struct ldb_message_element *el)
459 struct ldb_message_element *e2;
462 e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element,
463 msg->num_elements+1);
471 e2 = &msg->elements[msg->num_elements];
474 e2->flags = el->flags;
476 if (el->num_values != 0) {
477 e2->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
483 for (i=0;i<el->num_values;i++) {
484 e2->values[i] = el->values[i];
486 e2->num_values = el->num_values;
494 delete all elements having a specified attribute name
496 static int msg_delete_attribute(struct ldb_module *module,
497 struct ldb_context *ldb,
498 struct ldb_message *msg, const char *name)
503 dn = ldb_dn_linearize(ldb, msg->dn);
508 for (i=0;i<msg->num_elements;i++) {
509 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
510 for (j=0;j<msg->elements[i].num_values;j++) {
511 ltdb_index_del_value(module, dn, &msg->elements[i], j);
513 talloc_free(msg->elements[i].values);
514 if (msg->num_elements > (i+1)) {
515 memmove(&msg->elements[i],
517 sizeof(struct ldb_message_element)*
518 (msg->num_elements - (i+1)));
522 msg->elements = talloc_realloc(msg, msg->elements,
523 struct ldb_message_element,
533 delete all elements matching an attribute name/value
535 return 0 on success, -1 on failure
537 static int msg_delete_element(struct ldb_module *module,
538 struct ldb_message *msg,
540 const struct ldb_val *val)
542 struct ldb_context *ldb = module->ldb;
545 struct ldb_message_element *el;
546 const struct ldb_attrib_handler *h;
548 found = find_element(msg, name);
553 el = &msg->elements[found];
555 h = ldb_attrib_handler(ldb, el->name);
557 for (i=0;i<el->num_values;i++) {
558 if (h->comparison_fn(ldb, ldb, &el->values[i], val) == 0) {
559 if (i<el->num_values-1) {
560 memmove(&el->values[i], &el->values[i+1],
561 sizeof(el->values[i])*(el->num_values-(i+1)));
564 if (el->num_values == 0) {
565 return msg_delete_attribute(module, ldb, msg, name);
576 modify a record - internal interface
578 yuck - this is O(n^2). Luckily n is usually small so we probably
579 get away with it, but if we ever have really large attribute lists
580 then we'll need to look at this again
582 int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg)
584 struct ldb_context *ldb = module->ldb;
585 struct ltdb_private *ltdb = module->private_data;
586 TDB_DATA tdb_key, tdb_data;
587 struct ldb_message *msg2;
591 tdb_key = ltdb_key(module, msg->dn);
593 return LDB_ERR_OTHER;
596 tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
597 if (!tdb_data.dptr) {
598 talloc_free(tdb_key.dptr);
599 return ltdb_err_map(tdb_error(ltdb->tdb));
602 msg2 = talloc(tdb_key.dptr, struct ldb_message);
604 talloc_free(tdb_key.dptr);
605 return LDB_ERR_OTHER;
608 ret = ltdb_unpack_data(module, &tdb_data, msg2);
610 talloc_free(tdb_key.dptr);
612 return LDB_ERR_OTHER;
619 for (i=0;i<msg->num_elements;i++) {
620 struct ldb_message_element *el = &msg->elements[i];
621 struct ldb_message_element *el2;
622 struct ldb_val *vals;
626 switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
628 case LDB_FLAG_MOD_ADD:
629 /* add this element to the message. fail if it
631 ret = find_element(msg2, el->name);
634 if (msg_add_element(ldb, msg2, el) != 0) {
641 el2 = &msg2->elements[ret];
643 /* An attribute with this name already exists, add all
644 * values if they don't already exist. */
646 for (j=0;j<el->num_values;j++) {
647 if (ldb_msg_find_val(el2, &el->values[j])) {
648 err_string = talloc_strdup(module, "Type or value exists");
649 if (err_string) ldb_set_errstring(module->ldb, err_string);
650 ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
655 vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val,
656 el2->num_values + el->num_values);
661 for (j=0;j<el->num_values;j++) {
662 vals[el2->num_values + j] =
663 ldb_val_dup(vals, &el->values[j]);
667 el2->num_values += el->num_values;
671 case LDB_FLAG_MOD_REPLACE:
672 /* replace all elements of this attribute name with the elements
673 listed. The attribute not existing is not an error */
674 msg_delete_attribute(module, ldb, msg2, msg->elements[i].name);
676 /* add the replacement element, if not empty */
677 if (msg->elements[i].num_values != 0 &&
678 msg_add_element(ldb, msg2, &msg->elements[i]) != 0) {
683 case LDB_FLAG_MOD_DELETE:
685 dn = ldb_dn_linearize(msg2, msg->dn);
686 if (dn == NULL) goto failed;
688 /* we could be being asked to delete all
689 values or just some values */
690 if (msg->elements[i].num_values == 0) {
691 if (msg_delete_attribute(module, ldb, msg2,
692 msg->elements[i].name) != 0) {
693 err_string = talloc_asprintf(module, "No such attribute: %s", msg->elements[i].name);
694 if (err_string) ldb_set_errstring(module->ldb, err_string);
695 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
700 for (j=0;j<msg->elements[i].num_values;j++) {
701 if (msg_delete_element(module,
703 msg->elements[i].name,
704 &msg->elements[i].values[j]) != 0) {
705 err_string = talloc_asprintf(module, "No such attribute: %s", msg->elements[i].name);
706 if (err_string) ldb_set_errstring(module->ldb, err_string);
707 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
710 if (ltdb_index_del_value(module, dn, &msg->elements[i], j) != 0) {
716 err_string = talloc_asprintf(module, "Invalid ldb_modify flags on %s: 0x%x",
717 msg->elements[i].name,
718 msg->elements[i].flags & LDB_FLAG_MOD_MASK);
719 if (err_string) ldb_set_errstring(module->ldb, err_string);
720 ret = LDB_ERR_PROTOCOL_ERROR;
725 /* we've made all the mods - save the modified record back into the database */
726 ret = ltdb_store(module, msg2, TDB_MODIFY);
727 if (ret != LDB_SUCCESS) {
731 if (ltdb_modified(module, msg->dn) != LDB_SUCCESS) {
732 ret = LDB_ERR_OPERATIONS_ERROR;
736 talloc_free(tdb_key.dptr);
741 talloc_free(tdb_key.dptr);
749 static int ltdb_modify(struct ldb_module *module, struct ldb_request *req)
751 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
752 struct ltdb_async_context *ltdb_ac;
753 int tret, ret = LDB_SUCCESS;
755 if (req->controls != NULL) {
756 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
757 if (check_critical_controls(req->controls)) {
758 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
762 req->async.handle = NULL;
764 req->async.handle = init_ltdb_handle(ltdb, module, req->async.context, req->async.callback);
765 if (req->async.handle == NULL) {
766 return LDB_ERR_OPERATIONS_ERROR;
768 ltdb_ac = talloc_get_type(req->async.handle->private_data, struct ltdb_async_context);
770 tret = ltdb_check_special_dn(module, req->op.mod.message);
771 if (tret != LDB_SUCCESS) {
772 req->async.handle->status = tret;
776 if (ltdb_cache_load(module) != 0) {
777 ret = LDB_ERR_OPERATIONS_ERROR;
781 tret = ltdb_modify_internal(module, req->op.mod.message);
782 if (tret != LDB_SUCCESS) {
783 req->async.handle->status = tret;
787 if (ltdb_ac->callback)
788 ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
791 req->async.handle->state = LDB_ASYNC_DONE;
798 static int ltdb_rename(struct ldb_module *module, struct ldb_request *req)
800 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
801 struct ltdb_async_context *ltdb_ac;
802 struct ldb_message *msg;
803 int tret, ret = LDB_SUCCESS;
805 if (req->controls != NULL) {
806 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
807 if (check_critical_controls(req->controls)) {
808 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
812 req->async.handle = NULL;
814 if (ltdb_cache_load(module) != 0) {
815 return LDB_ERR_OPERATIONS_ERROR;
818 req->async.handle = init_ltdb_handle(ltdb, module, req->async.context, req->async.callback);
819 if (req->async.handle == NULL) {
820 return LDB_ERR_OPERATIONS_ERROR;
822 ltdb_ac = talloc_get_type(req->async.handle->private_data, struct ltdb_async_context);
824 msg = talloc(ltdb_ac, struct ldb_message);
826 ret = LDB_ERR_OPERATIONS_ERROR;
830 /* in case any attribute of the message was indexed, we need
831 to fetch the old record */
832 tret = ltdb_search_dn1(module, req->op.rename.olddn, msg);
834 /* not finding the old record is an error */
835 req->async.handle->status = LDB_ERR_NO_SUCH_OBJECT;
839 msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
841 ret = LDB_ERR_OPERATIONS_ERROR;
845 tret = ltdb_add_internal(module, msg);
846 if (tret != LDB_SUCCESS) {
847 ret = LDB_ERR_OPERATIONS_ERROR;
851 tret = ltdb_delete_internal(module, req->op.rename.olddn);
852 if (tret != LDB_SUCCESS) {
853 ltdb_delete_internal(module, req->op.rename.newdn);
854 ret = LDB_ERR_OPERATIONS_ERROR;
858 if (ltdb_ac->callback)
859 ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL);
862 req->async.handle->state = LDB_ASYNC_DONE;
866 static int ltdb_start_trans(struct ldb_module *module)
868 struct ltdb_private *ltdb = module->private_data;
870 if (tdb_transaction_start(ltdb->tdb) != 0) {
871 return ltdb_err_map(tdb_error(ltdb->tdb));
877 static int ltdb_end_trans(struct ldb_module *module)
879 struct ltdb_private *ltdb = module->private_data;
881 if (tdb_transaction_commit(ltdb->tdb) != 0) {
882 return ltdb_err_map(tdb_error(ltdb->tdb));
888 static int ltdb_del_trans(struct ldb_module *module)
890 struct ltdb_private *ltdb = module->private_data;
892 if (tdb_transaction_cancel(ltdb->tdb) != 0) {
893 return ltdb_err_map(tdb_error(ltdb->tdb));
899 static int ltdb_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
901 return handle->status;
904 static int ltdb_request(struct ldb_module *module, struct ldb_request *req)
906 /* check for oustanding critical controls and return an error if found */
907 if (req->controls != NULL) {
908 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n");
909 if (check_critical_controls(req->controls)) {
910 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
914 /* search, add, modify, delete, rename are handled by their own, no other op supported */
915 return LDB_ERR_OPERATIONS_ERROR;
919 return sequenceNumber from @BASEINFO
921 static uint64_t ltdb_sequence_number(struct ldb_context *ldb)
923 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
924 const char *attrs[] = { "sequenceNumber", NULL };
925 struct ldb_result *res = NULL;
926 struct ldb_dn *dn = ldb_dn_explode(tmp_ctx, "@BASEINFO");
930 ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res);
931 talloc_steal(tmp_ctx, res);
932 if (ret != LDB_SUCCESS || res->count != 1) {
933 talloc_free(tmp_ctx);
934 /* zero is as good as anything when we don't know */
938 seq_num = ldb_msg_find_uint64(res->msgs[0], "sequenceNumber", 0);
939 talloc_free(tmp_ctx);
943 static const struct ldb_module_ops ltdb_ops = {
945 .search = ltdb_search,
947 .modify = ltdb_modify,
949 .rename = ltdb_rename,
950 .request = ltdb_request,
951 .start_transaction = ltdb_start_trans,
952 .end_transaction = ltdb_end_trans,
953 .del_transaction = ltdb_del_trans,
954 .async_wait = ltdb_async_wait
959 connect to the database
961 static int ltdb_connect(struct ldb_context *ldb, const char *url,
962 unsigned int flags, const char *options[])
965 int tdb_flags, open_flags;
966 struct ltdb_private *ltdb;
969 if (strchr(url, ':')) {
970 if (strncmp(url, "tdb://", 6) != 0) {
971 ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url);
979 tdb_flags = TDB_DEFAULT;
981 /* check for the 'nosync' option */
982 if (flags & LDB_FLG_NOSYNC) {
983 tdb_flags |= TDB_NOSYNC;
986 if (flags & LDB_FLG_RDONLY) {
987 open_flags = O_RDONLY;
989 open_flags = O_CREAT | O_RDWR;
992 ltdb = talloc_zero(ldb, struct ltdb_private);
998 /* note that we use quite a large default hash size */
999 ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, tdb_flags, open_flags, 0666);
1001 ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'\n", path);
1006 ltdb->sequence_number = 0;
1008 ldb->modules = talloc(ldb, struct ldb_module);
1009 if (!ldb->modules) {
1014 ldb->modules->ldb = ldb;
1015 ldb->modules->prev = ldb->modules->next = NULL;
1016 ldb->modules->private_data = ltdb;
1017 ldb->modules->ops = <db_ops;
1018 ldb->sequence_number = ltdb_sequence_number;
1023 int ldb_tdb_init(void)
1025 return ldb_register_backend("tdb", ltdb_connect);