r17703: Fixes to enable the entryUUID module to work for it's objectClass ->
[Samba/ekacnet.git] / source4 / dsdb / samdb / ldb_modules / partition.c
blob889c0bfeb07be1ef998f35a5526564d62e66cc84
1 /*
2 Partitions ldb module
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
6 * NOTICE: this module is NOT released under the GNU LGPL license as
7 * other ldb code. This module is release under the GNU GPL v2 or
8 * later license.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program 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
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Name: ldb
28 * Component: ldb partitions module
30 * Description: Implement LDAP partitions
32 * Author: Andrew Bartlett
35 #include "includes.h"
36 #include "ldb/include/includes.h"
38 struct partition {
39 struct ldb_module *module;
40 const char *backend;
41 struct ldb_dn *dn;
43 struct partition_private_data {
44 struct partition **partitions;
45 struct ldb_dn **replicate;
48 struct partition_context {
49 struct ldb_module *module;
50 struct ldb_request *orig_req;
52 struct ldb_request **down_req;
53 int num_requests;
54 int finished_requests;
57 static struct ldb_handle *partition_init_handle(struct ldb_request *req, struct ldb_module *module)
59 struct partition_context *ac;
60 struct ldb_handle *h;
62 h = talloc_zero(req, struct ldb_handle);
63 if (h == NULL) {
64 ldb_set_errstring(module->ldb, "Out of Memory");
65 return NULL;
68 h->module = module;
70 ac = talloc_zero(h, struct partition_context);
71 if (ac == NULL) {
72 ldb_set_errstring(module->ldb, "Out of Memory");
73 talloc_free(h);
74 return NULL;
77 h->private_data = (void *)ac;
79 ac->module = module;
80 ac->orig_req = req;
82 return h;
85 struct ldb_module *make_module_for_next_request(TALLOC_CTX *mem_ctx,
86 struct ldb_context *ldb,
87 struct ldb_module *module)
89 struct ldb_module *current;
90 static const struct ldb_module_ops ops; /* zero */
91 current = talloc_zero(mem_ctx, struct ldb_module);
92 if (current == NULL) {
93 return module;
96 current->ldb = ldb;
97 current->ops = &ops;
98 current->prev = NULL;
99 current->next = module;
100 return current;
103 struct ldb_module *find_backend(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn)
105 int i;
106 struct partition_private_data *data = talloc_get_type(module->private_data,
107 struct partition_private_data);
108 /* Look at base DN */
109 /* Figure out which partition it is under */
110 /* Skip the lot if 'data' isn't here yet (initialistion) */
111 for (i=0; data && data->partitions && data->partitions[i]; i++) {
112 if (ldb_dn_compare_base(module->ldb,
113 data->partitions[i]->dn,
114 dn) == 0) {
115 return make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
119 return module;
124 fire the caller's callback for every entry, but only send 'done' once.
126 static int partition_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
128 struct partition_context *ac;
130 if (!context || !ares) {
131 ldb_set_errstring(ldb, "partition_search_callback: NULL Context or Result in 'search' callback");
132 goto error;
135 ac = talloc_get_type(context, struct partition_context);
137 if (ares->type == LDB_REPLY_ENTRY) {
138 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
139 } else {
140 ac->finished_requests++;
141 if (ac->finished_requests == ac->num_requests) {
142 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
143 } else {
144 talloc_free(ares);
145 return LDB_SUCCESS;
148 error:
149 talloc_free(ares);
150 return LDB_ERR_OPERATIONS_ERROR;
154 only fire the 'last' callback, and only for START-TLS for now
156 static int partition_other_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
158 struct partition_context *ac;
160 if (!context) {
161 ldb_set_errstring(ldb, "partition_other_callback: NULL Context in 'other' callback");
162 goto error;
165 ac = talloc_get_type(context, struct partition_context);
167 if (!ac->orig_req->callback) {
168 talloc_free(ares);
169 return LDB_SUCCESS;
172 if (!ares
173 || (ares->type == LDB_REPLY_EXTENDED
174 && strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID))) {
175 ac->finished_requests++;
176 if (ac->finished_requests == ac->num_requests) {
177 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
179 talloc_free(ares);
180 return LDB_SUCCESS;
182 ldb_set_errstring(ldb, "partition_other_callback: Unknown reply type, only supports START_TLS");
183 error:
184 talloc_free(ares);
185 return LDB_ERR_OPERATIONS_ERROR;
189 static int partition_send_request(struct partition_context *ac, struct ldb_module *partition)
191 int ret;
192 struct ldb_module *next = make_module_for_next_request(ac->module, ac->module->ldb, partition);
194 ac->down_req = talloc_realloc(ac, ac->down_req,
195 struct ldb_request *, ac->num_requests + 1);
196 if (!ac->down_req) {
197 ldb_set_errstring(ac->module->ldb, "Out of Memory");
198 return LDB_ERR_OPERATIONS_ERROR;
200 ac->down_req[ac->num_requests] = talloc(ac, struct ldb_request);
201 if (ac->down_req[ac->num_requests] == NULL) {
202 ldb_set_errstring(ac->module->ldb, "Out of Memory");
203 return LDB_ERR_OPERATIONS_ERROR;
206 *ac->down_req[ac->num_requests] = *ac->orig_req; /* copy the request */
208 if (ac->down_req[ac->num_requests]->operation == LDB_SEARCH) {
209 ac->down_req[ac->num_requests]->callback = partition_search_callback;
210 ac->down_req[ac->num_requests]->context = ac;
211 } else {
212 ac->down_req[ac->num_requests]->callback = partition_other_callback;
213 ac->down_req[ac->num_requests]->context = ac;
216 /* Spray off search requests to all backends */
217 ret = ldb_next_request(next, ac->down_req[ac->num_requests]);
218 if (ret != LDB_SUCCESS) {
219 return ret;
222 ac->num_requests++;
223 return LDB_SUCCESS;
226 /* Send a request down to all the partitions */
227 static int partition_send_all(struct ldb_module *module,
228 struct partition_context *ac, struct ldb_request *req)
230 int i;
231 struct partition_private_data *data = talloc_get_type(module->private_data,
232 struct partition_private_data);
233 int ret = partition_send_request(ac, module->next);
234 if (ret != LDB_SUCCESS) {
235 return ret;
237 for (i=0; data && data->partitions && data->partitions[i]; i++) {
238 ret = partition_send_request(ac, data->partitions[i]->module);
239 if (ret != LDB_SUCCESS) {
240 return ret;
243 return LDB_SUCCESS;
246 /* Figure out which backend a request needs to be aimed at. Some
247 * requests must be replicated to all backends */
248 static int partition_replicate(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn)
250 int i;
251 struct ldb_module *backend;
252 struct partition_private_data *data = talloc_get_type(module->private_data,
253 struct partition_private_data);
255 /* Is this a special DN, we need to replicate to every backend? */
256 for (i=0; data->replicate && data->replicate[i]; i++) {
257 if (ldb_dn_compare(module->ldb,
258 data->replicate[i],
259 dn) == 0) {
260 struct ldb_handle *h;
261 struct partition_context *ac;
263 h = partition_init_handle(req, module);
264 if (!h) {
265 return LDB_ERR_OPERATIONS_ERROR;
267 /* return our own handle to deal with this call */
268 req->handle = h;
270 ac = talloc_get_type(h->private_data, struct partition_context);
272 return partition_send_all(module, ac, req);
276 /* Otherwise, we need to find the backend to fire it to */
278 /* Find backend */
279 backend = find_backend(module, req, dn);
281 /* issue request */
282 return ldb_next_request(backend, req);
286 /* search */
287 static int partition_search(struct ldb_module *module, struct ldb_request *req)
289 /* Find backend */
290 struct partition_private_data *data = talloc_get_type(module->private_data,
291 struct partition_private_data);
292 /* issue request */
294 /* (later) consider if we should be searching multiple
295 * partitions (for 'invisible' partition behaviour */
296 if (ldb_get_opaque(module->ldb, "global_catalog")) {
297 int ret, i;
298 struct ldb_handle *h;
299 struct partition_context *ac;
301 h = partition_init_handle(req, module);
302 if (!h) {
303 return LDB_ERR_OPERATIONS_ERROR;
305 /* return our own handle to deal with this call */
306 req->handle = h;
308 ac = talloc_get_type(h->private_data, struct partition_context);
310 for (i=0; data && data->partitions && data->partitions[i]; i++) {
311 /* Find all partitions under the search base */
312 if (ldb_dn_compare_base(module->ldb,
313 req->op.search.base,
314 data->partitions[i]->dn) == 0) {
315 ret = partition_send_request(ac, data->partitions[i]->module);
316 if (ret != LDB_SUCCESS) {
317 return ret;
322 /* Perhaps we didn't match any partitions. Try the main partition, then all partitions */
323 if (ac->num_requests == 0) {
324 return partition_send_all(module, ac, req);
327 return LDB_SUCCESS;
328 } else {
329 struct ldb_module *backend = find_backend(module, req, req->op.search.base);
331 return ldb_next_request(backend, req);
335 /* add */
336 static int partition_add(struct ldb_module *module, struct ldb_request *req)
338 return partition_replicate(module, req, req->op.add.message->dn);
341 /* modify */
342 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
344 return partition_replicate(module, req, req->op.mod.message->dn);
347 /* delete */
348 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
350 return partition_replicate(module, req, req->op.del.dn);
353 /* rename */
354 static int partition_rename(struct ldb_module *module, struct ldb_request *req)
356 /* Find backend */
357 struct ldb_module *backend = find_backend(module, req, req->op.rename.olddn);
358 struct ldb_module *backend2 = find_backend(module, req, req->op.rename.newdn);
360 if (backend->next != backend2->next) {
361 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
364 return partition_replicate(module, req, req->op.rename.olddn);
367 /* start a transaction */
368 static int partition_start_trans(struct ldb_module *module)
370 int i, ret;
371 struct partition_private_data *data = talloc_get_type(module->private_data,
372 struct partition_private_data);
373 /* Look at base DN */
374 /* Figure out which partition it is under */
375 /* Skip the lot if 'data' isn't here yet (initialistion) */
376 ret = ldb_next_start_trans(module);
377 if (ret != LDB_SUCCESS) {
378 return ret;
381 for (i=0; data && data->partitions && data->partitions[i]; i++) {
382 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
384 ret = ldb_next_start_trans(next);
385 talloc_free(next);
386 if (ret != LDB_SUCCESS) {
387 /* Back it out, if it fails on one */
388 for (i--; i >= 0; i--) {
389 next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
390 ldb_next_del_trans(next);
391 talloc_free(next);
393 return ret;
396 return LDB_SUCCESS;
399 /* end a transaction */
400 static int partition_end_trans(struct ldb_module *module)
402 int i, ret, ret2 = LDB_SUCCESS;
403 struct partition_private_data *data = talloc_get_type(module->private_data,
404 struct partition_private_data);
405 ret = ldb_next_end_trans(module);
406 if (ret != LDB_SUCCESS) {
407 return ret;
410 /* Look at base DN */
411 /* Figure out which partition it is under */
412 /* Skip the lot if 'data' isn't here yet (initialistion) */
413 for (i=0; data && data->partitions && data->partitions[i]; i++) {
414 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
416 ret = ldb_next_end_trans(next);
417 talloc_free(next);
418 if (ret != LDB_SUCCESS) {
419 ret2 = ret;
423 if (ret != LDB_SUCCESS) {
424 /* Back it out, if it fails on one */
425 for (i=0; data && data->partitions && data->partitions[i]; i++) {
426 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
427 ldb_next_del_trans(next);
428 talloc_free(next);
431 return ret;
434 /* delete a transaction */
435 static int partition_del_trans(struct ldb_module *module)
437 int i, ret, ret2 = LDB_SUCCESS;
438 struct partition_private_data *data = talloc_get_type(module->private_data,
439 struct partition_private_data);
440 ret = ldb_next_del_trans(module);
441 if (ret != LDB_SUCCESS) {
442 ret2 = ret;
445 /* Look at base DN */
446 /* Figure out which partition it is under */
447 /* Skip the lot if 'data' isn't here yet (initialistion) */
448 for (i=0; data && data->partitions && data->partitions[i]; i++) {
449 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
451 ret = ldb_next_del_trans(next);
452 talloc_free(next);
453 if (ret != LDB_SUCCESS) {
454 ret2 = ret;
457 return ret2;
460 static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
462 int i, ret;
463 uint64_t seq_number = 0;
464 struct partition_private_data *data = talloc_get_type(module->private_data,
465 struct partition_private_data);
466 ret = ldb_next_request(module, req);
467 if (ret != LDB_SUCCESS) {
468 return ret;
470 seq_number = seq_number + req->op.seq_num.seq_num;
472 /* Look at base DN */
473 /* Figure out which partition it is under */
474 /* Skip the lot if 'data' isn't here yet (initialistion) */
475 for (i=0; data && data->partitions && data->partitions[i]; i++) {
476 struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
478 ret = ldb_next_request(next, req);
479 talloc_free(next);
480 if (ret != LDB_SUCCESS) {
481 return ret;
483 seq_number = seq_number + req->op.seq_num.seq_num;
485 req->op.seq_num.seq_num = seq_number;
486 return LDB_SUCCESS;
489 static int sort_compare(void *void1,
490 void *void2, void *opaque)
492 struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
493 struct partition **pp1 = void1;
494 struct partition **pp2 = void2;
495 struct partition *partition1 = talloc_get_type(*pp1, struct partition);
496 struct partition *partition2 = talloc_get_type(*pp2, struct partition);
498 return ldb_dn_compare(ldb, partition1->dn, partition2->dn);
501 static int partition_init(struct ldb_module *module)
503 int ret, i;
504 TALLOC_CTX *mem_ctx = talloc_new(module);
505 static const char *attrs[] = { "partition", "replicateEntries", "modules", NULL };
506 struct ldb_result *res;
507 struct ldb_message *msg;
508 struct ldb_message_element *partition_attributes;
509 struct ldb_message_element *replicate_attributes;
510 struct ldb_message_element *modules_attributes;
512 struct partition_private_data *data;
514 if (!mem_ctx) {
515 return LDB_ERR_OPERATIONS_ERROR;
518 data = talloc(mem_ctx, struct partition_private_data);
519 if (data == NULL) {
520 return LDB_ERR_OPERATIONS_ERROR;
523 ret = ldb_search(module->ldb, ldb_dn_explode(mem_ctx, "@PARTITION"),
524 LDB_SCOPE_BASE,
525 NULL, attrs,
526 &res);
527 if (ret != LDB_SUCCESS) {
528 talloc_free(mem_ctx);
529 return ret;
531 talloc_steal(mem_ctx, res);
532 if (res->count == 0) {
533 talloc_free(mem_ctx);
534 return ldb_next_init(module);
537 if (res->count > 1) {
538 talloc_free(mem_ctx);
539 return LDB_ERR_CONSTRAINT_VIOLATION;
542 msg = res->msgs[0];
544 partition_attributes = ldb_msg_find_element(msg, "partition");
545 if (!partition_attributes) {
546 ldb_set_errstring(module->ldb, "partition_init: no partitions specified");
547 talloc_free(mem_ctx);
548 return LDB_ERR_CONSTRAINT_VIOLATION;
550 data->partitions = talloc_array(data, struct partition *, partition_attributes->num_values + 1);
551 if (!data->partitions) {
552 talloc_free(mem_ctx);
553 return LDB_ERR_OPERATIONS_ERROR;
555 for (i=0; i < partition_attributes->num_values; i++) {
556 char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data);
557 char *p = strchr(base, ':');
558 if (!p) {
559 ldb_asprintf_errstring(module->ldb,
560 "partition_init: "
561 "invalid form for partition record (missing ':'): %s", base);
562 talloc_free(mem_ctx);
563 return LDB_ERR_CONSTRAINT_VIOLATION;
565 p[0] = '\0';
566 p++;
567 if (!p[0]) {
568 ldb_asprintf_errstring(module->ldb,
569 "partition_init: "
570 "invalid form for partition record (missing backend database): %s", base);
571 talloc_free(mem_ctx);
572 return LDB_ERR_CONSTRAINT_VIOLATION;
574 data->partitions[i] = talloc(data->partitions, struct partition);
575 if (!data->partitions[i]) {
576 talloc_free(mem_ctx);
577 return LDB_ERR_OPERATIONS_ERROR;
580 data->partitions[i]->dn = ldb_dn_explode(data->partitions[i], base);
581 if (!data->partitions[i]->dn) {
582 ldb_asprintf_errstring(module->ldb,
583 "partition_init: invalid DN in partition record: %s", base);
584 talloc_free(mem_ctx);
585 return LDB_ERR_CONSTRAINT_VIOLATION;
588 data->partitions[i]->backend = private_path(data->partitions[i], p);
589 ret = ldb_connect_backend(module->ldb, data->partitions[i]->backend, NULL, &data->partitions[i]->module);
590 if (ret != LDB_SUCCESS) {
591 talloc_free(mem_ctx);
592 return ret;
595 data->partitions[i] = NULL;
597 /* sort these into order, most to least specific */
598 ldb_qsort(data->partitions, partition_attributes->num_values, sizeof(*data->partitions),
599 module->ldb, sort_compare);
601 for (i=0; data->partitions[i]; i++) {
602 struct ldb_request *req;
603 req = talloc_zero(mem_ctx, struct ldb_request);
604 if (req == NULL) {
605 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Out of memory!\n");
606 talloc_free(mem_ctx);
607 return LDB_ERR_OPERATIONS_ERROR;
610 req->operation = LDB_REQ_REGISTER_PARTITION;
611 req->op.reg_partition.dn = data->partitions[i]->dn;
613 ret = ldb_request(module->ldb, req);
614 if (ret != LDB_SUCCESS) {
615 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
616 talloc_free(mem_ctx);
617 return LDB_ERR_OTHER;
619 talloc_free(req);
622 replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
623 if (!replicate_attributes) {
624 data->replicate = NULL;
625 } else {
626 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
627 if (!data->replicate) {
628 talloc_free(mem_ctx);
629 return LDB_ERR_OPERATIONS_ERROR;
632 for (i=0; i < replicate_attributes->num_values; i++) {
633 data->replicate[i] = ldb_dn_explode(data->replicate, replicate_attributes->values[i].data);
634 if (!data->replicate[i]) {
635 ldb_asprintf_errstring(module->ldb,
636 "partition_init: "
637 "invalid DN in partition replicate record: %s",
638 replicate_attributes->values[i].data);
639 talloc_free(mem_ctx);
640 return LDB_ERR_CONSTRAINT_VIOLATION;
643 data->replicate[i] = NULL;
646 /* Make the private data available to any searches the modules may trigger in initialisation */
647 module->private_data = data;
648 talloc_steal(module, data);
650 modules_attributes = ldb_msg_find_element(msg, "modules");
651 if (modules_attributes) {
652 for (i=0; i < modules_attributes->num_values; i++) {
653 struct ldb_dn *base_dn;
654 int partition_idx;
655 struct partition *partition = NULL;
656 const char **modules = NULL;
658 char *base = talloc_strdup(data->partitions, (char *)modules_attributes->values[i].data);
659 char *p = strchr(base, ':');
660 if (!p) {
661 ldb_asprintf_errstring(module->ldb,
662 "partition_init: "
663 "invalid form for partition module record (missing ':'): %s", base);
664 talloc_free(mem_ctx);
665 return LDB_ERR_CONSTRAINT_VIOLATION;
667 p[0] = '\0';
668 p++;
669 if (!p[0]) {
670 ldb_asprintf_errstring(module->ldb,
671 "partition_init: "
672 "invalid form for partition module record (missing backend database): %s", base);
673 talloc_free(mem_ctx);
674 return LDB_ERR_CONSTRAINT_VIOLATION;
677 modules = ldb_modules_list_from_string(module->ldb, mem_ctx,
680 base_dn = ldb_dn_explode(mem_ctx, base);
681 if (!base_dn) {
682 talloc_free(mem_ctx);
683 return LDB_ERR_OPERATIONS_ERROR;
686 for (partition_idx = 0; data->partitions[partition_idx]; partition_idx++) {
687 if (ldb_dn_compare(module->ldb, data->partitions[partition_idx]->dn,
688 base_dn) == 0) {
689 partition = data->partitions[partition_idx];
690 break;
694 if (!partition) {
695 ldb_asprintf_errstring(module->ldb,
696 "partition_init: "
697 "invalid form for partition module record (no such partition): %s", base);
698 talloc_free(mem_ctx);
699 return LDB_ERR_CONSTRAINT_VIOLATION;
702 ret = ldb_load_modules_list(module->ldb, modules, partition->module, &partition->module);
703 if (ret != LDB_SUCCESS) {
704 talloc_free(mem_ctx);
705 return ret;
707 ret = ldb_init_module_chain(module->ldb, partition->module);
708 if (ret != LDB_SUCCESS) {
709 talloc_free(mem_ctx);
710 return ret;
715 talloc_free(mem_ctx);
716 return ldb_next_init(module);
719 static int partition_wait_none(struct ldb_handle *handle) {
720 struct partition_context *ac;
721 int ret;
722 int i;
724 if (!handle || !handle->private_data) {
725 return LDB_ERR_OPERATIONS_ERROR;
728 if (handle->state == LDB_ASYNC_DONE) {
729 return handle->status;
732 handle->state = LDB_ASYNC_PENDING;
733 handle->status = LDB_SUCCESS;
735 ac = talloc_get_type(handle->private_data, struct partition_context);
737 for (i=0; i < ac->num_requests; i++) {
738 ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
740 if (ret != LDB_SUCCESS) {
741 handle->status = ret;
742 goto done;
744 if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
745 handle->status = ac->down_req[i]->handle->status;
746 goto done;
749 if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
750 return LDB_SUCCESS;
754 ret = LDB_SUCCESS;
756 done:
757 handle->state = LDB_ASYNC_DONE;
758 return ret;
762 static int partition_wait_all(struct ldb_handle *handle) {
764 int ret;
766 while (handle->state != LDB_ASYNC_DONE) {
767 ret = partition_wait_none(handle);
768 if (ret != LDB_SUCCESS) {
769 return ret;
773 return handle->status;
776 static int partition_wait(struct ldb_handle *handle, enum ldb_wait_type type)
778 if (type == LDB_WAIT_ALL) {
779 return partition_wait_all(handle);
780 } else {
781 return partition_wait_none(handle);
785 static const struct ldb_module_ops partition_ops = {
786 .name = "partition",
787 .init_context = partition_init,
788 .search = partition_search,
789 .add = partition_add,
790 .modify = partition_modify,
791 .del = partition_delete,
792 .rename = partition_rename,
793 .start_transaction = partition_start_trans,
794 .end_transaction = partition_end_trans,
795 .del_transaction = partition_del_trans,
796 .sequence_number = partition_sequence_number,
797 .wait = partition_wait
800 int ldb_partition_init(void)
802 return ldb_register_module(&partition_ops);