summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2017-10-05 14:56:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2017-10-05 14:56:34 +0000
commit14191ca88dbf6d94479153d90240f0ae83f70dd1 (patch)
treecf7294f15dc42c876fe7c136b1351523a7059897
parentReleasing progress-linux version 2:1.1.29-2~dschinn1. (diff)
downloadldb-14191ca88dbf6d94479153d90240f0ae83f70dd1.zip
ldb-14191ca88dbf6d94479153d90240f0ae83f70dd1.tar.xz
Merging upstream version 2:1.2.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--ABI/ldb-1.1.30.sigs272
-rw-r--r--ABI/ldb-1.1.31.sigs274
-rw-r--r--ABI/ldb-1.2.0.sigs276
-rw-r--r--ABI/ldb-1.2.1.sigs276
-rw-r--r--ABI/ldb-1.2.2.sigs277
-rw-r--r--ABI/pyldb-util-1.1.30.sigs2
-rw-r--r--ABI/pyldb-util-1.1.31.sigs2
-rw-r--r--ABI/pyldb-util-1.2.0.sigs2
-rw-r--r--ABI/pyldb-util-1.2.1.sigs2
-rw-r--r--ABI/pyldb-util-1.2.2.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.1.30.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.1.31.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.2.0.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.2.1.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.2.2.sigs2
-rw-r--r--buildtools/wafsamba/pkgconfig.py12
-rw-r--r--buildtools/wafsamba/samba3.py31
-rw-r--r--buildtools/wafsamba/samba_bundled.py21
-rw-r--r--buildtools/wafsamba/samba_conftests.py7
-rw-r--r--buildtools/wafsamba/samba_deps.py1
-rw-r--r--buildtools/wafsamba/samba_dist.py4
-rw-r--r--buildtools/wafsamba/samba_patterns.py22
-rw-r--r--buildtools/wafsamba/samba_python.py36
-rw-r--r--buildtools/wafsamba/samba_third_party.py6
-rw-r--r--buildtools/wafsamba/samba_utils.py25
-rw-r--r--buildtools/wafsamba/wafsamba.py37
-rw-r--r--[-rwxr-xr-x]buildtools/wafsamba/wscript16
-rw-r--r--common/ldb.c503
-rw-r--r--common/ldb_attributes.c12
-rw-r--r--common/ldb_ldif.c21
-rw-r--r--common/ldb_modules.c78
-rw-r--r--common/ldb_msg.c283
-rw-r--r--common/ldb_pack.c10
-rw-r--r--include/ldb.h240
-rw-r--r--include/ldb_module.h126
-rw-r--r--include/ldb_private.h68
-rw-r--r--ldb_sqlite3/ldb_sqlite3.c22
-rw-r--r--ldb_tdb/ldb_cache.c84
-rw-r--r--ldb_tdb/ldb_index.c297
-rw-r--r--ldb_tdb/ldb_search.c137
-rw-r--r--ldb_tdb/ldb_tdb.c240
-rw-r--r--ldb_tdb/ldb_tdb.h11
-rw-r--r--lib/replace/getifaddrs.c20
-rw-r--r--lib/replace/replace.c18
-rw-r--r--lib/replace/replace.h6
-rw-r--r--lib/replace/snprintf.c2
-rw-r--r--lib/replace/system/dir.h4
-rw-r--r--lib/replace/system/network.h4
-rw-r--r--lib/replace/system/time.h10
-rw-r--r--lib/replace/test/os2_delete.c2
-rw-r--r--lib/replace/test/shared_mmap.c5
-rw-r--r--lib/replace/test/shared_mremap.c5
-rw-r--r--lib/replace/test/snprintf.c2
-rw-r--r--lib/replace/wscript37
-rw-r--r--lib/replace/xattr.c105
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.10.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.9.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs15
-rw-r--r--lib/talloc/ABI/pytalloc-util.py3-2.1.9.sigs15
-rw-r--r--lib/talloc/ABI/talloc-2.1.10.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.9.sigs65
-rw-r--r--lib/talloc/pytalloc-util.pc.in4
-rw-r--r--lib/talloc/pytalloc.c13
-rw-r--r--lib/talloc/pytalloc.h28
-rw-r--r--lib/talloc/pytalloc_guide.txt73
-rw-r--r--lib/talloc/pytalloc_util.c95
-rw-r--r--lib/talloc/talloc.c14
-rw-r--r--lib/talloc/talloc.h9
-rw-r--r--lib/talloc/testsuite.c67
-rw-r--r--lib/talloc/wscript73
-rw-r--r--lib/tdb/ABI/tdb-1.3.13.sigs70
-rw-r--r--lib/tdb/ABI/tdb-1.3.14.sigs71
-rw-r--r--lib/tdb/ABI/tdb-1.3.15.sigs71
-rw-r--r--lib/tdb/common/dump.c6
-rw-r--r--lib/tdb/common/io.c103
-rw-r--r--lib/tdb/common/lock.c58
-rw-r--r--lib/tdb/common/mutex.c116
-rw-r--r--lib/tdb/common/open.c70
-rw-r--r--lib/tdb/common/tdb.c9
-rw-r--r--lib/tdb/common/tdb_private.h18
-rw-r--r--lib/tdb/common/transaction.c64
-rw-r--r--lib/tdb/common/traverse.c50
-rw-r--r--lib/tdb/include/tdb.h29
-rw-r--r--lib/tdb/man/tdbbackup.8.xml8
-rw-r--r--lib/tdb/man/tdbtool.8.xml10
-rw-r--r--lib/tdb/test/run-fcntl-deadlock.c202
-rw-r--r--lib/tdb/test/run-nested-traverse.c31
-rw-r--r--lib/tdb/test/run-rdlock-upgrade.c166
-rw-r--r--lib/tdb/test/run-traverse-in-transaction.c3
-rw-r--r--lib/tdb/tools/tdbtool.c87
-rw-r--r--lib/tdb/wscript13
-rw-r--r--lib/tevent/ABI/tevent-0.9.32.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.33.sigs99
-rwxr-xr-xlib/tevent/release-script.sh48
-rw-r--r--lib/tevent/testsuite.c10
-rw-r--r--lib/tevent/tevent.c77
-rw-r--r--lib/tevent/tevent.h2
-rw-r--r--lib/tevent/tevent.py1
-rw-r--r--lib/tevent/tevent_req.c11
-rw-r--r--lib/tevent/tevent_threads.c31
-rw-r--r--[-rwxr-xr-x]lib/tevent/wscript11
-rw-r--r--man/ldb.3.xml2
-rw-r--r--man/ldbadd.1.xml2
-rw-r--r--man/ldbdel.1.xml2
-rw-r--r--man/ldbedit.1.xml2
-rw-r--r--man/ldbmodify.1.xml2
-rw-r--r--man/ldbrename.1.xml2
-rw-r--r--man/ldbsearch.1.xml2
-rw-r--r--pyldb-util.pc.in4
-rw-r--r--pyldb.c16
-rw-r--r--tests/ldb_mod_op_test.c2987
-rw-r--r--tests/ldb_msg.c379
-rwxr-xr-xtests/python/api.py639
-rw-r--r--third_party/cmocka/cmocka.c3306
-rw-r--r--third_party/cmocka/cmocka.h2284
-rw-r--r--third_party/cmocka/cmocka_private.h163
-rw-r--r--third_party/cmocka/wscript19
-rw-r--r--third_party/waf/wafadmin/3rdparty/paranoid.py4
-rw-r--r--third_party/waf/wafadmin/Tools/config_c.py4
-rw-r--r--third_party/waf/wafadmin/Tools/msvc.py2
-rw-r--r--tools/cmdline.c27
-rw-r--r--tools/cmdline.h3
-rw-r--r--tools/ldbdump.c2
-rw-r--r--tools/ldbedit.c10
-rw-r--r--tools/ldbsearch.c2
-rw-r--r--[-rwxr-xr-x]wscript120
126 files changed, 14980 insertions, 1182 deletions
diff --git a/ABI/ldb-1.1.30.sigs b/ABI/ldb-1.1.30.sigs
new file mode 100644
index 0000000..ef9c53e
--- /dev/null
+++ b/ABI/ldb-1.1.30.sigs
@@ -0,0 +1,272 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/ldb-1.1.31.sigs b/ABI/ldb-1.1.31.sigs
new file mode 100644
index 0000000..d183708
--- /dev/null
+++ b/ABI/ldb-1.1.31.sigs
@@ -0,0 +1,274 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/ldb-1.2.0.sigs b/ABI/ldb-1.2.0.sigs
new file mode 100644
index 0000000..1be2ae7
--- /dev/null
+++ b/ABI/ldb-1.2.0.sigs
@@ -0,0 +1,276 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/ldb-1.2.1.sigs b/ABI/ldb-1.2.1.sigs
new file mode 100644
index 0000000..1be2ae7
--- /dev/null
+++ b/ABI/ldb-1.2.1.sigs
@@ -0,0 +1,276 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/ldb-1.2.2.sigs b/ABI/ldb-1.2.2.sigs
new file mode 100644
index 0000000..9dc61cd
--- /dev/null
+++ b/ABI/ldb-1.2.2.sigs
@@ -0,0 +1,277 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/ABI/pyldb-util-1.1.30.sigs b/ABI/pyldb-util-1.1.30.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.1.30.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util-1.1.31.sigs b/ABI/pyldb-util-1.1.31.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.1.31.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util-1.2.0.sigs b/ABI/pyldb-util-1.2.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.2.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util-1.2.1.sigs b/ABI/pyldb-util-1.2.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.2.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util-1.2.2.sigs b/ABI/pyldb-util-1.2.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.2.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.1.30.sigs b/ABI/pyldb-util.py3-1.1.30.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.1.30.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.1.31.sigs b/ABI/pyldb-util.py3-1.1.31.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.1.31.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.2.0.sigs b/ABI/pyldb-util.py3-1.2.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.2.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.2.1.sigs b/ABI/pyldb-util.py3-1.2.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.2.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/ABI/pyldb-util.py3-1.2.2.sigs b/ABI/pyldb-util.py3-1.2.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.2.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/buildtools/wafsamba/pkgconfig.py b/buildtools/wafsamba/pkgconfig.py
index 25cec78..999bad4 100644
--- a/buildtools/wafsamba/pkgconfig.py
+++ b/buildtools/wafsamba/pkgconfig.py
@@ -38,16 +38,20 @@ def subst_at_vars(task):
return 0
-def PKG_CONFIG_FILES(bld, pc_files, vnum=None):
+def PKG_CONFIG_FILES(bld, pc_files, vnum=None, extra_name=None):
'''install some pkg_config pc files'''
dest = '${PKGCONFIGDIR}'
dest = bld.EXPAND_VARIABLES(dest)
for f in TO_LIST(pc_files):
- base=os.path.basename(f)
+ if extra_name:
+ target = f.split('.pc')[0] + extra_name + ".pc"
+ else:
+ target = f
+ base=os.path.basename(target)
t = bld.SAMBA_GENERATOR('PKGCONFIG_%s' % base,
rule=subst_at_vars,
source=f+'.in',
- target=f)
+ target=target)
bld.add_manual_dependency(bld.path.find_or_declare(f), bld.env['PREFIX'])
t.vars = []
if t.env.RPATH_ON_INSTALL:
@@ -58,7 +62,7 @@ def PKG_CONFIG_FILES(bld, pc_files, vnum=None):
t.env.PACKAGE_VERSION = vnum
for v in [ 'PREFIX', 'EXEC_PREFIX', 'LIB_RPATH' ]:
t.vars.append(t.env[v])
- bld.INSTALL_FILES(dest, f, flat=True, destname=base)
+ bld.INSTALL_FILES(dest, target, flat=True, destname=base)
Build.BuildContext.PKG_CONFIG_FILES = PKG_CONFIG_FILES
diff --git a/buildtools/wafsamba/samba3.py b/buildtools/wafsamba/samba3.py
index 6d06fd9..44daff9 100644
--- a/buildtools/wafsamba/samba3.py
+++ b/buildtools/wafsamba/samba3.py
@@ -2,37 +2,10 @@
# and for SAMBA_ macros for building libraries, binaries etc
import Options, Build, os
-from optparse import SUPPRESS_HELP
-from samba_utils import os_path_relpath, TO_LIST
+from samba_utils import os_path_relpath, TO_LIST, samba_add_onoff_option
from samba_autoconf import library_flags
-
-def SAMBA3_ADD_OPTION(opt, option, help=(), dest=None, default=True,
- with_name="with", without_name="without"):
- if default is None:
- default_str = "auto"
- elif default is True:
- default_str = "yes"
- elif default is False:
- default_str = "no"
- else:
- default_str = str(default)
-
- if help == ():
- help = ("Build with %s support (default=%s)" % (option, default_str))
- if dest is None:
- dest = "with_%s" % option.replace('-', '_')
-
- with_val = "--%s-%s" % (with_name, option)
- without_val = "--%s-%s" % (without_name, option)
-
- #FIXME: This is broken and will always default to "default" no matter if
- # --with or --without is chosen.
- opt.add_option(with_val, help=help, action="store_true", dest=dest,
- default=default)
- opt.add_option(without_val, help=SUPPRESS_HELP, action="store_false",
- dest=dest)
-Options.Handler.SAMBA3_ADD_OPTION = SAMBA3_ADD_OPTION
+Options.Handler.SAMBA3_ADD_OPTION = samba_add_onoff_option
def SAMBA3_IS_STATIC_MODULE(bld, module):
'''Check whether module is in static list'''
diff --git a/buildtools/wafsamba/samba_bundled.py b/buildtools/wafsamba/samba_bundled.py
index ea88807..aa6199e 100644
--- a/buildtools/wafsamba/samba_bundled.py
+++ b/buildtools/wafsamba/samba_bundled.py
@@ -110,6 +110,7 @@ def LIB_MUST_BE_PRIVATE(conf, libname):
@conf
def CHECK_BUNDLED_SYSTEM_PKG(conf, libname, minversion='0.0.0',
+ maxversion=None, version_blacklist=[],
onlyif=None, implied_deps=None, pkg=None):
'''check if a library is available as a system library.
@@ -117,12 +118,15 @@ def CHECK_BUNDLED_SYSTEM_PKG(conf, libname, minversion='0.0.0',
'''
return conf.CHECK_BUNDLED_SYSTEM(libname,
minversion=minversion,
+ maxversion=maxversion,
+ version_blacklist=version_blacklist,
onlyif=onlyif,
implied_deps=implied_deps,
pkg=pkg)
@conf
def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
+ maxversion=None, version_blacklist=[],
checkfunctions=None, headers=None, checkcode=None,
onlyif=None, implied_deps=None,
require_headers=True, pkg=None, set_target=True):
@@ -181,16 +185,29 @@ def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
minversion = minimum_library_version(conf, libname, minversion)
msg = 'Checking for system %s' % libname
+ msg_ver = []
if minversion != '0.0.0':
- msg += ' >= %s' % minversion
+ msg_ver.append('>=%s' % minversion)
+ if maxversion is not None:
+ msg_ver.append('<=%s' % maxversion)
+ for v in version_blacklist:
+ msg_ver.append('!=%s' % v)
+ if msg_ver != []:
+ msg += " (%s)" % (" ".join(msg_ver))
uselib_store=libname.upper()
if pkg is None:
pkg = libname
+ version_checks = '%s >= %s' % (pkg, minversion)
+ if maxversion is not None:
+ version_checks += ' %s <= %s' % (pkg, maxversion)
+ for v in version_blacklist:
+ version_checks += ' %s != %s' % (pkg, v)
+
# try pkgconfig first
if (conf.CHECK_CFG(package=pkg,
- args='"%s >= %s" --cflags --libs' % (pkg, minversion),
+ args='"%s" --cflags --libs' % (version_checks),
msg=msg, uselib_store=uselib_store) and
check_functions_headers_code()):
if set_target:
diff --git a/buildtools/wafsamba/samba_conftests.py b/buildtools/wafsamba/samba_conftests.py
index 045f858..511176d 100644
--- a/buildtools/wafsamba/samba_conftests.py
+++ b/buildtools/wafsamba/samba_conftests.py
@@ -24,7 +24,7 @@ def check(self, *k, **kw):
if not 'env' in kw:
kw['env'] = self.env.copy()
- # match the configuration test with speficic options, for example:
+ # match the configuration test with specific options, for example:
# --with-libiconv -> Options.options.iconv_open -> "Checking for library iconv"
additional_dirs = []
if 'msg' in kw:
@@ -286,7 +286,9 @@ def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None):
os.makedirs(subdir)
Utils.writef(os.path.join(subdir, 'lib1.c'), 'int lib_func(void) { return 42; }\n')
- Utils.writef(os.path.join(dir, 'main.c'), 'int main(void) {return !(lib_func() == 42);}\n')
+ Utils.writef(os.path.join(dir, 'main.c'),
+ 'int lib_func(void);\n'
+ 'int main(void) {return !(lib_func() == 42);}\n')
bld = Build.BuildContext()
bld.log = conf.log
@@ -436,6 +438,7 @@ def CHECK_UNAME(conf):
ret = True
for v in "sysname machine release version".split():
if not conf.CHECK_CODE('''
+ int printf(const char *format, ...);
struct utsname n;
if (uname(&n) == -1) return -1;
printf("%%s", n.%s);
diff --git a/buildtools/wafsamba/samba_deps.py b/buildtools/wafsamba/samba_deps.py
index 2ffe745..978a5e9 100644
--- a/buildtools/wafsamba/samba_deps.py
+++ b/buildtools/wafsamba/samba_deps.py
@@ -229,6 +229,7 @@ def add_init_functions(self):
if modules == []:
sname = sname.replace('-','_')
+ sname = sname.replace('.','_')
sname = sname.replace('/','_')
cflags.append('-DSTATIC_%s_MODULES=%s' % (sname, sentinel))
if sentinel == 'NULL':
diff --git a/buildtools/wafsamba/samba_dist.py b/buildtools/wafsamba/samba_dist.py
index dbcb02a..2e52820 100644
--- a/buildtools/wafsamba/samba_dist.py
+++ b/buildtools/wafsamba/samba_dist.py
@@ -115,7 +115,7 @@ def dist(appname='', version=''):
blacklisted = True
if blacklisted:
continue
- if os.path.isdir(abspath):
+ if os.path.isdir(abspath) and not os.path.islink(abspath):
continue
if dstsubdir != '.':
f = dstsubdir + '/' + f
@@ -182,7 +182,7 @@ def dist(appname='', version=''):
absfile = os.path.join(srcdir, file)
- if os.path.isdir(absfile):
+ if os.path.isdir(absfile) and not os.path.islink(absfile):
destdir = destfile
dir = file
files = list_directory_files(dir)
diff --git a/buildtools/wafsamba/samba_patterns.py b/buildtools/wafsamba/samba_patterns.py
index ceca2cc..2b93937 100644
--- a/buildtools/wafsamba/samba_patterns.py
+++ b/buildtools/wafsamba/samba_patterns.py
@@ -14,7 +14,7 @@ def write_version_header(task):
return 0
-def SAMBA_MKVERSION(bld, target):
+def SAMBA_MKVERSION(bld, target, source='VERSION'):
'''generate the version.h header for Samba'''
# We only force waf to re-generate this file if we are installing,
@@ -22,7 +22,7 @@ def SAMBA_MKVERSION(bld, target):
# git revision) included in the version.
t = bld.SAMBA_GENERATOR('VERSION',
rule=write_version_header,
- source= 'VERSION',
+ source=source,
target=target,
always=bld.is_install)
Build.BuildContext.SAMBA_MKVERSION = SAMBA_MKVERSION
@@ -51,7 +51,6 @@ def write_build_options_header(fp):
fp.write("*/\n")
fp.write("\n")
fp.write("#include \"includes.h\"\n")
- fp.write("#include \"build_env.h\"\n")
fp.write("#include \"dynconfig/dynconfig.h\"\n")
fp.write("#include \"lib/cluster_support.h\"\n")
@@ -92,19 +91,6 @@ def write_build_options_header(fp):
fp.write(" return;\n")
fp.write(" }\n")
fp.write("\n")
- fp.write("#ifdef _BUILD_ENV_H\n")
- fp.write(" /* Output information about the build environment */\n")
- fp.write(" output(screen,\"Build environment:\\n\");\n")
- fp.write(" output(screen,\" Built by: %s@%s\\n\",BUILD_ENV_USER,BUILD_ENV_HOST);\n")
- fp.write(" output(screen,\" Built on: %s\\n\",BUILD_ENV_DATE);\n")
- fp.write("\n")
- fp.write(" output(screen,\" Built using: %s\\n\",BUILD_ENV_COMPILER);\n")
- fp.write(" output(screen,\" Build host: %s\\n\",BUILD_ENV_UNAME);\n")
- fp.write(" output(screen,\" SRCDIR: %s\\n\",BUILD_ENV_SRCDIR);\n")
- fp.write(" output(screen,\" BUILDDIR: %s\\n\",BUILD_ENV_BUILDDIR);\n")
- fp.write("\n")
- fp.write("\n")
- fp.write("#endif\n")
fp.write("\n")
fp.write(" /* Output various paths to files and directories */\n")
fp.write(" output(screen,\"\\nPaths:\\n\");\n")
@@ -122,6 +108,7 @@ def write_build_options_header(fp):
fp.write(" output(screen,\" PIDDIR: %s\\n\", get_dyn_PIDDIR());\n")
fp.write(" output(screen,\" SMB_PASSWD_FILE: %s\\n\",get_dyn_SMB_PASSWD_FILE());\n")
fp.write(" output(screen,\" PRIVATE_DIR: %s\\n\",get_dyn_PRIVATE_DIR());\n")
+ fp.write(" output(screen,\" BINDDNS_DIR: %s\\n\",get_dyn_BINDDNS_DIR());\n")
fp.write("\n")
def write_build_options_footer(fp):
@@ -178,6 +165,9 @@ def write_build_options(task):
keys_header_other.append(key)
else:
keys_option_have.append(key)
+ elif key.startswith("static_init_"):
+ l = key.split("(")
+ keys_misc.append(l[0])
else:
keys_misc.append(key)
diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index 057a017..f97439c 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -40,6 +40,18 @@ def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
@conf
def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
+ if conf.env.disable_python:
+ if mandatory:
+ raise Utils.WafError("Cannot check for python headers when "
+ "--disable-python specified")
+
+ conf.msg("python headers", "Check disabled due to --disable-python")
+ # we don't want PYTHONDIR in config.h, as otherwise changing
+ # --prefix causes a complete rebuild
+ del(conf.env.defines['PYTHONDIR'])
+ del(conf.env.defines['PYTHONARCHDIR'])
+ return
+
if conf.env["python_headers_checked"] == []:
if conf.env['EXTRA_PYTHON']:
conf.setenv('extrapython')
@@ -75,6 +87,20 @@ def _check_python_headers(conf, mandatory):
conf.env['PYTHON_SO_ABI_FLAG'] = abi_pattern % ''
else:
conf.env['PYTHON_SO_ABI_FLAG'] = ''
+ conf.env['PYTHON_LIBNAME_SO_ABI_FLAG'] = (
+ conf.env['PYTHON_SO_ABI_FLAG'].replace('_', '-'))
+
+ for lib in conf.env['LINKFLAGS_PYEMBED']:
+ if lib.startswith('-L'):
+ conf.env.append_unique('LIBPATH_PYEMBED', lib[2:]) # strip '-L'
+ conf.env['LINKFLAGS_PYEMBED'].remove(lib)
+
+ return
+
+def PYTHON_BUILD_IS_ENABLED(self):
+ return self.CONFIG_SET('HAVE_PYTHON_H')
+
+Build.BuildContext.PYTHON_BUILD_IS_ENABLED = PYTHON_BUILD_IS_ENABLED
def SAMBA_PYTHON(bld, name,
@@ -91,6 +117,11 @@ def SAMBA_PYTHON(bld, name,
enabled=True):
'''build a python extension for Samba'''
+ # force-disable when we can't build python modules, so
+ # every single call doesn't need to pass this in.
+ if not bld.PYTHON_BUILD_IS_ENABLED():
+ enabled = False
+
if bld.env['IS_EXTRA_PYTHON']:
name = 'extra-' + name
@@ -138,7 +169,10 @@ Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
def pyembed_libname(bld, name, extrapython=False):
- return name + bld.env['PYTHON_SO_ABI_FLAG']
+ if bld.env['PYTHON_SO_ABI_FLAG']:
+ return name + bld.env['PYTHON_SO_ABI_FLAG']
+ else:
+ return name
Build.BuildContext.pyembed_libname = pyembed_libname
diff --git a/buildtools/wafsamba/samba_third_party.py b/buildtools/wafsamba/samba_third_party.py
index 8cfa4df..ac77be7 100644
--- a/buildtools/wafsamba/samba_third_party.py
+++ b/buildtools/wafsamba/samba_third_party.py
@@ -33,3 +33,9 @@ def CHECK_POPT(conf):
return conf.CHECK_BUNDLED_SYSTEM('popt', checkfunctions='poptGetContext', headers='popt.h')
Build.BuildContext.CHECK_POPT = CHECK_POPT
+
+@conf
+def CHECK_CMOCKA(conf):
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('cmocka', minversion='1.1.1')
+
+Build.BuildContext.CHECK_CMOCKA = CHECK_CMOCKA
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
index 49a8759..0f95c12 100644
--- a/buildtools/wafsamba/samba_utils.py
+++ b/buildtools/wafsamba/samba_utils.py
@@ -2,6 +2,7 @@
# and for SAMBA_ macros for building libraries, binaries etc
import os, sys, re, fnmatch, shlex
+from optparse import SUPPRESS_HELP
import Build, Options, Utils, Task, Logs, Configure
from TaskGen import feature, before, after
from Configure import conf, ConfigurationContext
@@ -669,3 +670,27 @@ def samba_before_apply_obj_vars(self):
if is_standard_libpath(v, i):
v['LIBPATH'].remove(i)
+def samba_add_onoff_option(opt, option, help=(), dest=None, default=True,
+ with_name="with", without_name="without"):
+ if default is None:
+ default_str = "auto"
+ elif default is True:
+ default_str = "yes"
+ elif default is False:
+ default_str = "no"
+ else:
+ default_str = str(default)
+
+ if help == ():
+ help = ("Build with %s support (default=%s)" % (option, default_str))
+ if dest is None:
+ dest = "with_%s" % option.replace('-', '_')
+
+ with_val = "--%s-%s" % (with_name, option)
+ without_val = "--%s-%s" % (without_name, option)
+
+ opt.add_option(with_val, help=help, action="store_true", dest=dest,
+ default=default)
+ opt.add_option(without_val, help=SUPPRESS_HELP, action="store_false",
+ dest=dest)
+Options.Handler.samba_add_onoff_option = samba_add_onoff_option
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 4a47dbf..57913af 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -144,7 +144,7 @@ def SAMBA_LIBRARY(bld, libname, source,
'''define a Samba library'''
if pyembed and bld.env['IS_EXTRA_PYTHON']:
- public_headers = pc_files = None
+ public_headers = None
if private_library and public_headers:
raise Utils.WafError("private library '%s' must not have public header files" %
@@ -225,7 +225,7 @@ def SAMBA_LIBRARY(bld, libname, source,
if vnum is None and soname is None:
raise Utils.WafError("public library '%s' must have a vnum" %
libname)
- if pc_files is None and not bld.env['IS_EXTRA_PYTHON']:
+ if pc_files is None:
raise Utils.WafError("public library '%s' must have pkg-config file" %
libname)
if public_headers is None and not bld.env['IS_EXTRA_PYTHON']:
@@ -328,7 +328,10 @@ def SAMBA_LIBRARY(bld, libname, source,
t.link_name = link_name
if pc_files is not None and not private_library:
- bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
+ if pyembed and bld.env['IS_EXTRA_PYTHON']:
+ bld.PKG_CONFIG_FILES(pc_files, vnum=vnum, extra_name=bld.env['PYTHON_SO_ABI_FLAG'])
+ else:
+ bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
if (manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and
bld.env['XSLTPROC_MANPAGES']):
@@ -462,7 +465,8 @@ def SAMBA_MODULE(bld, modname, source,
pyembed=False,
manpages=None,
allow_undefined_symbols=False,
- allow_warnings=False
+ allow_warnings=False,
+ install=True
):
'''define a Samba module.'''
@@ -532,7 +536,8 @@ def SAMBA_MODULE(bld, modname, source,
pyembed=pyembed,
manpages=manpages,
allow_undefined_symbols=allow_undefined_symbols,
- allow_warnings=allow_warnings
+ allow_warnings=allow_warnings,
+ install=install
)
@@ -880,13 +885,31 @@ def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
python_fixup=python_fixup, base_name=trim_path)
Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
+def INSTALL_DIR(bld, path, chmod=0o755):
+ """Install a directory if it doesn't exist, always set permissions."""
+
+ if not path:
+ return []
+
+ if bld.is_install > 0:
+ path = bld.EXPAND_VARIABLES(path)
+ if not os.path.isdir(path):
+ try:
+ os.makedirs(path)
+ os.chmod(path, chmod)
+ except OSError, e:
+ if not os.path.isdir(path):
+ raise Utils.WafError("Cannot create the folder '%s' (error: %s)" % (path, e))
+ else:
+ os.chmod(path, chmod)
+Build.BuildContext.INSTALL_DIR = INSTALL_DIR
-def INSTALL_DIRS(bld, destdir, dirs):
+def INSTALL_DIRS(bld, destdir, dirs, chmod=0o755):
'''install a set of directories'''
destdir = bld.EXPAND_VARIABLES(destdir)
dirs = bld.EXPAND_VARIABLES(dirs)
for d in TO_LIST(dirs):
- bld.install_dir(os.path.join(destdir, d))
+ INSTALL_DIR(bld, os.path.join(destdir, d), chmod)
Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index 8802e5a..430d164 100755..100644
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -196,6 +196,10 @@ def set_options(opt):
help='tag release in git at the same time',
type='string', action='store', dest='TAG_RELEASE')
+ opt.add_option('--disable-python',
+ help='do not generate python modules',
+ action='store_true', dest='disable_python', default=False)
+
opt.add_option('--extra-python', type=str,
help=("build selected libraries for the specified "
"additional version of Python "
@@ -208,6 +212,8 @@ def configure(conf):
conf.env.hlist = []
conf.env.srcdir = conf.srcdir
+ conf.define('SRCDIR', conf.env['srcdir'])
+
if Options.options.timestamp_dependencies:
conf.ENABLE_TIMESTAMP_DEPENDENCIES()
@@ -279,8 +285,14 @@ def configure(conf):
conf.env.AUTOCONF_HOST = Options.options.AUTOCONF_HOST
conf.env.AUTOCONF_PROGRAM_PREFIX = Options.options.AUTOCONF_PROGRAM_PREFIX
+ conf.env.disable_python = Options.options.disable_python
+
conf.env.EXTRA_PYTHON = Options.options.EXTRA_PYTHON
+ if (conf.env.disable_python and conf.env.EXTRA_PYTHON):
+ Logs.error('ERROR: cannot specify both --disable-python and --extra-python.')
+ sys.exit(1)
+
if (conf.env.AUTOCONF_HOST and
conf.env.AUTOCONF_BUILD and
conf.env.AUTOCONF_BUILD != conf.env.AUTOCONF_HOST):
@@ -490,12 +502,12 @@ struct foo bar = { .y = 'X', .x = 1 };
if not conf.CHECK_LARGEFILE():
raise Utils.WafError('Samba requires large file support support, but not available on this platform: sizeof(off_t) < 8')
- if 'HAVE_STDDEF_H' in conf.env and 'HAVE_STDLIB_H' in conf.env:
+ if conf.env.HAVE_STDDEF_H and conf.env.HAVE_STDLIB_H:
conf.DEFINE('STDC_HEADERS', 1)
conf.CHECK_HEADERS('sys/time.h time.h', together=True)
- if 'HAVE_SYS_TIME_H' in conf.env and 'HAVE_TIME_H' in conf.env:
+ if conf.env.HAVE_SYS_TIME_H and conf.env.HAVE_TIME_H:
conf.DEFINE('TIME_WITH_SYS_TIME', 1)
# cope with different extensions for libraries
diff --git a/common/ldb.c b/common/ldb.c
index 6067256..a4d9977 100644
--- a/common/ldb.c
+++ b/common/ldb.c
@@ -108,7 +108,7 @@ struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx)
}
/* A new event context so that callers who don't want ldb
- * operating on thier global event context can work without
+ * operating on their global event context can work without
* having to provide their own private one explicitly */
if (ev_ctx == NULL) {
ev_ctx = tevent_context_init(ldb);
@@ -326,17 +326,19 @@ int ldb_error_at(struct ldb_context *ldb, int ecode,
#define FIRST_OP_NOERR(ldb, op) do { \
- module = ldb->modules; \
- while (module && module->ops->op == NULL) module = module->next; \
- if ((ldb->flags & LDB_FLG_ENABLE_TRACING) && module) { \
+ next_module = ldb->modules; \
+ while (next_module && next_module->ops->op == NULL) { \
+ next_module = next_module->next; \
+ }; \
+ if ((ldb->flags & LDB_FLG_ENABLE_TRACING) && next_module) { \
ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_trace_request: (%s)->" #op, \
- module->ops->name); \
+ next_module->ops->name); \
} \
} while (0)
#define FIRST_OP(ldb, op) do { \
FIRST_OP_NOERR(ldb, op); \
- if (module == NULL) { \
+ if (next_module == NULL) { \
ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \
return LDB_ERR_OPERATIONS_ERROR; \
} \
@@ -348,7 +350,7 @@ int ldb_error_at(struct ldb_context *ldb, int ecode,
*/
int ldb_transaction_start(struct ldb_context *ldb)
{
- struct ldb_module *module;
+ struct ldb_module *next_module;
int status;
ldb_debug(ldb, LDB_DEBUG_TRACE,
@@ -369,7 +371,7 @@ int ldb_transaction_start(struct ldb_context *ldb)
ldb_reset_err_string(ldb);
- status = module->ops->start_transaction(module);
+ status = next_module->ops->start_transaction(next_module);
if (status != LDB_SUCCESS) {
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
@@ -378,13 +380,13 @@ int ldb_transaction_start(struct ldb_context *ldb)
ldb_strerror(status),
status);
}
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "start ldb transaction error: %s",
- ldb_errstring(module->ldb));
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "start ldb transaction error: %s",
+ ldb_errstring(next_module->ldb));
}
} else {
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "start ldb transaction success");
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "start ldb transaction success");
}
}
return status;
@@ -395,7 +397,7 @@ int ldb_transaction_start(struct ldb_context *ldb)
*/
int ldb_transaction_prepare_commit(struct ldb_context *ldb)
{
- struct ldb_module *module;
+ struct ldb_module *next_module;
int status;
if (ldb->prepare_commit_done) {
@@ -418,17 +420,17 @@ int ldb_transaction_prepare_commit(struct ldb_context *ldb)
/* call prepare transaction if available */
FIRST_OP_NOERR(ldb, prepare_commit);
- if (module == NULL) {
+ if (next_module == NULL) {
return LDB_SUCCESS;
}
- status = module->ops->prepare_commit(module);
+ status = next_module->ops->prepare_commit(next_module);
if (status != LDB_SUCCESS) {
ldb->transaction_active--;
- /* if a module fails the prepare then we need
+ /* if a next_module fails the prepare then we need
to call the end transaction for everyone */
FIRST_OP(ldb, del_transaction);
- module->ops->del_transaction(module);
+ next_module->ops->del_transaction(next_module);
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
ldb_asprintf_errstring(ldb,
@@ -436,9 +438,9 @@ int ldb_transaction_prepare_commit(struct ldb_context *ldb)
ldb_strerror(status),
status);
}
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "prepare commit transaction error: %s",
- ldb_errstring(module->ldb));
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "prepare commit transaction error: %s",
+ ldb_errstring(next_module->ldb));
}
}
@@ -451,7 +453,7 @@ int ldb_transaction_prepare_commit(struct ldb_context *ldb)
*/
int ldb_transaction_commit(struct ldb_context *ldb)
{
- struct ldb_module *module;
+ struct ldb_module *next_module;
int status;
status = ldb_transaction_prepare_commit(ldb);
@@ -480,7 +482,7 @@ int ldb_transaction_commit(struct ldb_context *ldb)
ldb_reset_err_string(ldb);
FIRST_OP(ldb, end_transaction);
- status = module->ops->end_transaction(module);
+ status = next_module->ops->end_transaction(next_module);
if (status != LDB_SUCCESS) {
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
@@ -489,13 +491,13 @@ int ldb_transaction_commit(struct ldb_context *ldb)
ldb_strerror(status),
status);
}
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "commit ldb transaction error: %s",
- ldb_errstring(module->ldb));
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "commit ldb transaction error: %s",
+ ldb_errstring(next_module->ldb));
}
/* cancel the transaction */
FIRST_OP(ldb, del_transaction);
- module->ops->del_transaction(module);
+ next_module->ops->del_transaction(next_module);
}
return status;
}
@@ -506,7 +508,7 @@ int ldb_transaction_commit(struct ldb_context *ldb)
*/
int ldb_transaction_cancel(struct ldb_context *ldb)
{
- struct ldb_module *module;
+ struct ldb_module *next_module;
int status;
ldb->transaction_active--;
@@ -529,7 +531,7 @@ int ldb_transaction_cancel(struct ldb_context *ldb)
FIRST_OP(ldb, del_transaction);
- status = module->ops->del_transaction(module);
+ status = next_module->ops->del_transaction(next_module);
if (status != LDB_SUCCESS) {
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
@@ -538,9 +540,9 @@ int ldb_transaction_cancel(struct ldb_context *ldb)
ldb_strerror(status),
status);
}
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "cancel ldb transaction error: %s",
- ldb_errstring(module->ldb));
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "cancel ldb transaction error: %s",
+ ldb_errstring(next_module->ldb));
}
}
return status;
@@ -605,7 +607,7 @@ int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
return handle->status;
}
- ev = ldb_get_event_context(handle->ldb);
+ ev = ldb_handle_get_event_context(handle);
if (NULL == ev) {
return ldb_oom(handle->ldb);
}
@@ -711,6 +713,62 @@ int ldb_set_timeout_from_prev_req(struct ldb_context *ldb,
}
+struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb)
+{
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->status = LDB_SUCCESS;
+ h->state = LDB_ASYNC_INIT;
+ h->ldb = ldb;
+ h->flags = 0;
+ h->location = NULL;
+ h->parent = NULL;
+
+ if (h->ldb->require_private_event_context == true) {
+ h->event_context = tevent_context_init(h);
+ if (h->event_context == NULL) {
+ ldb_set_errstring(ldb,
+ "Out of Memory allocating "
+ "event context for new handle");
+ return NULL;
+ }
+ tevent_set_debug(h->event_context, ldb_tevent_debug, ldb);
+ tevent_loop_allow_nesting(h->event_context);
+ }
+
+ return h;
+}
+
+static struct ldb_handle *ldb_handle_new_child(TALLOC_CTX *mem_ctx,
+ struct ldb_request *parent_req)
+{
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(parent_req->handle->ldb,
+ "Out of Memory");
+ return NULL;
+ }
+
+ h->status = LDB_SUCCESS;
+ h->state = LDB_ASYNC_INIT;
+ h->ldb = parent_req->handle->ldb;
+ h->parent = parent_req;
+ h->nesting = parent_req->handle->nesting + 1;
+ h->flags = parent_req->handle->flags;
+ h->custom_flags = parent_req->handle->custom_flags;
+ h->event_context = parent_req->handle->event_context;
+
+ return h;
+}
+
/*
set the permissions for new files to be passed to open() in
backends that use local files
@@ -745,6 +803,38 @@ int ldb_request_get_status(struct ldb_request *req)
return req->handle->status;
}
+/*
+ * This function obtains the private event context for the handle,
+ * which may have been created to avoid nested event loops during
+ * ldb_tdb with the locks held
+ */
+struct tevent_context *ldb_handle_get_event_context(struct ldb_handle *handle)
+{
+ if (handle->event_context != NULL) {
+ return handle->event_context;
+ }
+ return ldb_get_event_context(handle->ldb);
+}
+
+/*
+ * This function forces a specific ldb handle to use the global event
+ * context. This allows a nested event loop to operate, so any open
+ * transaction also needs to be aborted.
+ *
+ * Any events on this event context will be lost
+ *
+ * This is used in Samba when sending an IRPC to another part of the
+ * same process instead of making a local DB modification.
+ */
+void ldb_handle_use_global_event_context(struct ldb_handle *handle)
+{
+ TALLOC_FREE(handle->event_context);
+}
+
+void ldb_set_require_private_event_context(struct ldb_context *ldb)
+{
+ ldb->require_private_event_context = true;
+}
/*
trace a ldb request
@@ -876,6 +966,146 @@ static int ldb_msg_check_element_flags(struct ldb_context *ldb,
return LDB_SUCCESS;
}
+/*
+ * This context allows us to make the unlock be a talloc destructor
+ *
+ * This ensures that a request started, but not waited on, will still
+ * unlock.
+ */
+struct ldb_db_lock_context {
+ struct ldb_request *req;
+ struct ldb_context *ldb;
+};
+
+/*
+ * We have to have a the unlock on a destructor so that we unlock the
+ * DB if a caller calls talloc_free(req). We trust that the ldb
+ * context has not already gone away.
+ */
+static int ldb_db_lock_destructor(struct ldb_db_lock_context *lock_context)
+{
+ int ret;
+ struct ldb_module *next_module;
+ FIRST_OP_NOERR(lock_context->ldb, read_unlock);
+ if (next_module != NULL) {
+ ret = next_module->ops->read_unlock(next_module);
+ } else {
+ ret = LDB_SUCCESS;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(lock_context->ldb,
+ LDB_DEBUG_FATAL,
+ "Failed to unlock db: %s / %s",
+ ldb_errstring(lock_context->ldb),
+ ldb_strerror(ret));
+ }
+ return 0;
+}
+
+static int ldb_lock_backend_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_db_lock_context *lock_context;
+ int ret;
+
+ lock_context = talloc_get_type(req->context,
+ struct ldb_db_lock_context);
+
+ if (!ares) {
+ return ldb_module_done(lock_context->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS || ares->type == LDB_REPLY_DONE) {
+ ret = ldb_module_done(lock_context->req, ares->controls,
+ ares->response, ares->error);
+ /*
+ * If this is a LDB_REPLY_DONE or an error, unlock the
+ * DB by calling the destructor on this context
+ */
+ talloc_free(lock_context);
+ return ret;
+ }
+
+ /* Otherwise pass on the callback */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ return ldb_module_send_entry(lock_context->req, ares->message,
+ ares->controls);
+
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(lock_context->req,
+ ares->referral);
+ default:
+ /* Can't happen */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+}
+
+/*
+ * Do an ldb_search() with a lock held, but release it if the request
+ * is freed with talloc_free()
+ */
+static int lock_search(struct ldb_module *lock_module, struct ldb_request *req)
+{
+ /* Used in FIRST_OP_NOERR to find where to send the lock request */
+ struct ldb_module *next_module = NULL;
+ struct ldb_request *down_req = NULL;
+ struct ldb_db_lock_context *lock_context;
+ struct ldb_context *ldb = ldb_module_get_ctx(lock_module);
+ int ret;
+
+ lock_context = talloc(req, struct ldb_db_lock_context);
+ if (lock_context == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ lock_context->ldb = ldb;
+ lock_context->req = req;
+
+ ret = ldb_build_search_req_ex(&down_req, ldb, req,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ lock_context,
+ ldb_lock_backend_callback,
+ req);
+ LDB_REQ_SET_LOCATION(down_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* call DB lock */
+ FIRST_OP_NOERR(ldb, read_lock);
+ if (next_module != NULL) {
+ ret = next_module->ops->read_lock(next_module);
+ } else {
+ ret = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
+ if (ret == LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION) {
+ /* We might be talking LDAP */
+ ldb_reset_err_string(ldb);
+ ret = 0;
+ TALLOC_FREE(lock_context);
+
+ return ldb_next_request(lock_module, req);
+ } else if ((ret != LDB_SUCCESS) && (ldb->err_string == NULL)) {
+ /* if no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb, "Failed to get DB lock: %s (%d)",
+ ldb_strerror(ret), ret);
+ } else {
+ talloc_set_destructor(lock_context, ldb_db_lock_destructor);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_request(lock_module, down_req);
+}
/*
start an ldb request
@@ -884,7 +1114,7 @@ static int ldb_msg_check_element_flags(struct ldb_context *ldb,
*/
int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
{
- struct ldb_module *module;
+ struct ldb_module *next_module;
int ret;
if (req->callback == NULL) {
@@ -901,15 +1131,32 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
/* call the first module in the chain */
switch (req->operation) {
case LDB_SEARCH:
+ {
+ /*
+ * A fake module to allow ldb_next_request() to be
+ * re-used and to keep the locking out of this function.
+ */
+ static const struct ldb_module_ops lock_module_ops = {
+ .name = "lock_searches",
+ .search = lock_search
+ };
+ struct ldb_module lock_module = {
+ .ldb = ldb,
+ .next = ldb->modules,
+ .ops = &lock_module_ops
+ };
+ next_module = &lock_module;
+
/* due to "ldb_build_search_req" base DN always != NULL */
if (!ldb_dn_validate(req->op.search.base)) {
ldb_asprintf_errstring(ldb, "ldb_search: invalid basedn '%s'",
ldb_dn_get_linearized(req->op.search.base));
return LDB_ERR_INVALID_DN_SYNTAX;
}
- FIRST_OP(ldb, search);
- ret = module->ops->search(module, req);
+
+ ret = next_module->ops->search(next_module, req);
break;
+ }
case LDB_ADD:
if (!ldb_dn_validate(req->op.add.message->dn)) {
ldb_asprintf_errstring(ldb, "ldb_add: invalid dn '%s'",
@@ -936,7 +1183,7 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
*/
return ret;
}
- ret = module->ops->add(module, req);
+ ret = next_module->ops->add(next_module, req);
break;
case LDB_MODIFY:
if (!ldb_dn_validate(req->op.mod.message->dn)) {
@@ -953,7 +1200,7 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
*/
return ret;
}
- ret = module->ops->modify(module, req);
+ ret = next_module->ops->modify(next_module, req);
break;
case LDB_DELETE:
if (!ldb_dn_validate(req->op.del.dn)) {
@@ -962,7 +1209,7 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
return LDB_ERR_INVALID_DN_SYNTAX;
}
FIRST_OP(ldb, del);
- ret = module->ops->del(module, req);
+ ret = next_module->ops->del(next_module, req);
break;
case LDB_RENAME:
if (!ldb_dn_validate(req->op.rename.olddn)) {
@@ -976,15 +1223,15 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
return LDB_ERR_INVALID_DN_SYNTAX;
}
FIRST_OP(ldb, rename);
- ret = module->ops->rename(module, req);
+ ret = next_module->ops->rename(next_module, req);
break;
case LDB_EXTENDED:
FIRST_OP(ldb, extended);
- ret = module->ops->extended(module, req);
+ ret = next_module->ops->extended(next_module, req);
break;
default:
FIRST_OP(ldb, request);
- ret = module->ops->request(module, req);
+ ret = next_module->ops->request(next_module, req);
break;
}
@@ -1146,6 +1393,42 @@ int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares)
return ldb_request_done(req, LDB_SUCCESS);
}
+static struct ldb_request *ldb_build_req_common(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req = NULL;
+
+ req = talloc_zero(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ return NULL;
+ }
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ if (parent != NULL) {
+ req->handle = ldb_handle_new_child(req, parent);
+ if (req->handle == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ } else {
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ }
+
+ return req;
+}
+
int ldb_build_search_req_ex(struct ldb_request **ret_req,
struct ldb_context *ldb,
TALLOC_CTX *mem_ctx,
@@ -1162,7 +1445,8 @@ int ldb_build_search_req_ex(struct ldb_request **ret_req,
*ret_req = NULL;
- req = talloc(mem_ctx, struct ldb_request);
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
if (req == NULL) {
ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
@@ -1184,25 +1468,6 @@ int ldb_build_search_req_ex(struct ldb_request **ret_req,
}
req->op.search.attrs = attrs;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
*ret_req = req;
return LDB_SUCCESS;
}
@@ -1250,7 +1515,8 @@ int ldb_build_add_req(struct ldb_request **ret_req,
*ret_req = NULL;
- req = talloc(mem_ctx, struct ldb_request);
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
if (req == NULL) {
ldb_set_errstring(ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
@@ -1258,27 +1524,7 @@ int ldb_build_add_req(struct ldb_request **ret_req,
req->operation = LDB_ADD;
req->op.add.message = message;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
*ret_req = req;
-
return LDB_SUCCESS;
}
@@ -1295,7 +1541,8 @@ int ldb_build_mod_req(struct ldb_request **ret_req,
*ret_req = NULL;
- req = talloc(mem_ctx, struct ldb_request);
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
if (req == NULL) {
ldb_set_errstring(ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
@@ -1303,27 +1550,8 @@ int ldb_build_mod_req(struct ldb_request **ret_req,
req->operation = LDB_MODIFY;
req->op.mod.message = message;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
*ret_req = req;
-
return LDB_SUCCESS;
}
@@ -1340,7 +1568,8 @@ int ldb_build_del_req(struct ldb_request **ret_req,
*ret_req = NULL;
- req = talloc(mem_ctx, struct ldb_request);
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
if (req == NULL) {
ldb_set_errstring(ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
@@ -1348,27 +1577,7 @@ int ldb_build_del_req(struct ldb_request **ret_req,
req->operation = LDB_DELETE;
req->op.del.dn = dn;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
*ret_req = req;
-
return LDB_SUCCESS;
}
@@ -1386,7 +1595,8 @@ int ldb_build_rename_req(struct ldb_request **ret_req,
*ret_req = NULL;
- req = talloc(mem_ctx, struct ldb_request);
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
if (req == NULL) {
ldb_set_errstring(ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
@@ -1395,27 +1605,7 @@ int ldb_build_rename_req(struct ldb_request **ret_req,
req->operation = LDB_RENAME;
req->op.rename.olddn = olddn;
req->op.rename.newdn = newdn;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
*ret_req = req;
-
return LDB_SUCCESS;
}
@@ -1462,7 +1652,8 @@ int ldb_build_extended_req(struct ldb_request **ret_req,
*ret_req = NULL;
- req = talloc(mem_ctx, struct ldb_request);
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
if (req == NULL) {
ldb_set_errstring(ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
@@ -1471,27 +1662,7 @@ int ldb_build_extended_req(struct ldb_request **ret_req,
req->operation = LDB_EXTENDED;
req->op.extended.oid = oid;
req->op.extended.data = data;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
*ret_req = req;
-
return LDB_SUCCESS;
}
diff --git a/common/ldb_attributes.c b/common/ldb_attributes.c
index 2021a0b..98ec5a4 100644
--- a/common/ldb_attributes.c
+++ b/common/ldb_attributes.c
@@ -383,3 +383,15 @@ void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
ldb->schema.attribute_handler_override_private = private_data;
ldb->schema.attribute_handler_override = override;
}
+
+/*
+ set that the attribute handler override function - used to delegate
+ schema handling to external code, is handling setting
+ LDB_ATTR_FLAG_INDEXED
+ */
+void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
+ bool one_level_indexes)
+{
+ ldb->schema.index_handler_override = true;
+ ldb->schema.one_level_indexes = one_level_indexes;
+}
diff --git a/common/ldb_ldif.c b/common/ldb_ldif.c
index 0aeda94..b90d27e 100644
--- a/common/ldb_ldif.c
+++ b/common/ldb_ldif.c
@@ -1080,3 +1080,24 @@ char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
return ldb_ldif_write_string(ldb, mem_ctx, &ldif);
}
+
+/*
+ * convenient function to turn a ldb_message into a string. Useful for
+ * debugging but also safer if some of the LDIF could be sensitive.
+ *
+ * The secret attributes are specified in a 'const char * const *' within
+ * the LDB_SECRET_ATTRIBUTE_LIST opaque set on the ldb
+ *
+ */
+char *ldb_ldif_message_redacted_string(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ enum ldb_changetype changetype,
+ const struct ldb_message *msg)
+{
+ struct ldb_ldif ldif;
+
+ ldif.changetype = changetype;
+ ldif.msg = discard_const_p(struct ldb_message, msg);
+
+ return ldb_ldif_write_redacted_trace_string(ldb, mem_ctx, &ldif);
+}
diff --git a/common/ldb_modules.c b/common/ldb_modules.c
index 62f20af..25551e1 100644
--- a/common/ldb_modules.c
+++ b/common/ldb_modules.c
@@ -280,7 +280,17 @@ int ldb_register_module(const struct ldb_module_ops *ops)
if (ldb_find_module_ops(ops->name) != NULL)
return LDB_ERR_ENTRY_ALREADY_EXISTS;
- entry = talloc(talloc_autofree_context(), struct ops_list_entry);
+ /*
+ * ldb modules are not (yet) unloaded and
+ * are only loaded once (the above check
+ * makes sure of this). Allocate off the NULL
+ * context. We never want this to be freed
+ * until process shutdown. If eventually we
+ * want to unload ldb modules we can add a
+ * deregister function that walks and
+ * frees the list.
+ */
+ entry = talloc(NULL, struct ops_list_entry);
if (entry == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -641,6 +651,52 @@ int ldb_next_end_trans(struct ldb_module *module)
return ret;
}
+int ldb_next_read_lock(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, read_lock);
+ ret = module->ops->read_lock(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb,
+ "read_lock error in module %s: %s (%d)",
+ module->ops->name, ldb_strerror(ret),
+ ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE,
+ "ldb_next_read_lock error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+int ldb_next_read_unlock(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, read_unlock);
+ ret = module->ops->read_unlock(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb,
+ "read_unlock error in module %s: %s (%d)",
+ module->ops->name, ldb_strerror(ret),
+ ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE,
+ "ldb_next_read_unlock error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
int ldb_next_prepare_commit(struct ldb_module *module)
{
int ret;
@@ -684,26 +740,6 @@ int ldb_next_del_trans(struct ldb_module *module)
return ret;
}
-struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb)
-{
- struct ldb_handle *h;
-
- h = talloc_zero(mem_ctx, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return NULL;
- }
-
- h->status = LDB_SUCCESS;
- h->state = LDB_ASYNC_INIT;
- h->ldb = ldb;
- h->flags = 0;
- h->location = NULL;
- h->parent = NULL;
-
- return h;
-}
-
/* calls the request callback to send an entry
*
* params:
diff --git a/common/ldb_msg.c b/common/ldb_msg.c
index 3f65351..c2782db 100644
--- a/common/ldb_msg.c
+++ b/common/ldb_msg.c
@@ -1,4 +1,4 @@
-/*
+/*
ldb database library
Copyright (C) Andrew Tridgell 2004
@@ -6,7 +6,7 @@
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@@ -44,7 +44,7 @@ struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
/*
find an element in a message by attribute name
*/
-struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
const char *attr_name)
{
unsigned int i;
@@ -77,7 +77,7 @@ int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
find a value in an element
assumes case sensitive comparison
*/
-struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
struct ldb_val *val)
{
unsigned int i;
@@ -89,6 +89,219 @@ struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
return NULL;
}
+
+static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+
+/*
+ ldb_msg_find_duplicate_val() will set the **duplicate pointer to the first
+ duplicate value it finds. It does a case sensitive comparison (memcmp).
+
+ LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown
+ options flag, otherwise LDB_SUCCESS.
+*/
+#define LDB_DUP_QUADRATIC_THRESHOLD 10
+
+int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message_element *el,
+ struct ldb_val **duplicate,
+ uint32_t options)
+{
+ unsigned int i, j;
+ struct ldb_val *val;
+
+ if (options != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *duplicate = NULL;
+
+ /*
+ If there are not many values, it is best to avoid the talloc
+ overhead and just do a brute force search.
+ */
+ if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) {
+ for (j = 0; j < el->num_values; j++) {
+ val = &el->values[j];
+ for ( i = j + 1; i < el->num_values; i++) {
+ if (ldb_val_equal_exact(val, &el->values[i])) {
+ *duplicate = val;
+ return LDB_SUCCESS;
+ }
+ }
+ }
+ } else {
+ struct ldb_val *values;
+ values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
+ if (values == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(values, el->values,
+ el->num_values * sizeof(struct ldb_val));
+ TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
+ for (i = 1; i < el->num_values; i++) {
+ if (ldb_val_equal_exact(&values[i],
+ &values[i - 1])) {
+ /* find the original location */
+ for (j = 0; j < el->num_values; j++) {
+ if (ldb_val_equal_exact(&values[i],
+ &el->values[j])
+ ) {
+ *duplicate = &el->values[j];
+ break;
+ }
+ }
+ talloc_free(values);
+ if (*duplicate == NULL) {
+ /* how we got here, I don't know */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+ }
+ }
+ talloc_free(values);
+ }
+ return LDB_SUCCESS;
+}
+
+
+/*
+ Determine whether the values in an element are also in another element.
+
+ Without any flags, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS if the elements
+ share values, or LDB_SUCCESS if they don't. In this case, the function
+ simply determines the set intersection and it doesn't matter in which order
+ the elements are provided.
+
+ With the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, any values in common are
+ removed from the first element and LDB_SUCCESS is returned.
+
+ LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown option.
+ LDB_ERR_INAPPROPRIATE_MATCHING is returned if the elements differ in name.
+*/
+
+int ldb_msg_find_common_values(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el,
+ struct ldb_message_element *el2,
+ uint32_t options)
+{
+ struct ldb_val *values;
+ struct ldb_val *values2;
+ unsigned int i, j, k, n_values;
+
+ bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+
+ if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (strcmp(el->name, el2->name) != 0) {
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+ if (el->num_values == 0 || el2->num_values == 0) {
+ return LDB_SUCCESS;
+ }
+ /*
+ With few values, it is better to do the brute-force search than the
+ clever search involving tallocs, memcpys, sorts, etc.
+ */
+ if (MIN(el->num_values, el2->num_values) == 1 ||
+ MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
+ for (i = 0; i < el2->num_values; i++) {
+ for (j = 0; j < el->num_values; j++) {
+ if (ldb_val_equal_exact(&el->values[j],
+ &el2->values[i])) {
+ if (! remove_duplicates) {
+ return \
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ /*
+ With the remove_duplicates flag, we
+ resolve the intersection by removing
+ the offending one from el.
+ */
+ el->num_values--;
+ for (k = j; k < el->num_values; k++) {
+ el->values[k] = \
+ el->values[k + 1];
+ }
+ j--; /* rewind */
+ }
+ }
+ }
+ return LDB_SUCCESS;
+ }
+
+ values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
+ if (values == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ values2 = talloc_array(mem_ctx, struct ldb_val,
+ el2->num_values);
+ if (values2 == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(values, el->values,
+ el->num_values * sizeof(struct ldb_val));
+ memcpy(values2, el2->values,
+ el2->num_values * sizeof(struct ldb_val));
+ TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
+ TYPESAFE_QSORT(values2, el2->num_values, ldb_val_cmp);
+
+ /*
+ el->n_values may diverge from the number of values in the sorted
+ list when the remove_duplicates flag is used.
+ */
+ n_values = el->num_values;
+ i = 0;
+ j = 0;
+ while (i != n_values && j < el2->num_values) {
+ int ret = ldb_val_cmp(&values[i], &values2[j]);
+ if (ret < 0) {
+ i++;
+ } else if (ret > 0) {
+ j++;
+ } else {
+ /* we have a collision */
+ if (! remove_duplicates) {
+ TALLOC_FREE(values);
+ TALLOC_FREE(values2);
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ /*
+ With the remove_duplicates flag we need to find
+ this in the original list and remove it, which is
+ inefficient but hopefully rare.
+ */
+ for (k = 0; k < el->num_values; k++) {
+ if (ldb_val_equal_exact(&el->values[k],
+ &values[i])) {
+ break;
+ }
+ }
+ el->num_values--;
+ for (; k < el->num_values; k++) {
+ el->values[k] = el->values[k + 1];
+ }
+ i++;
+ }
+ }
+ TALLOC_FREE(values);
+ TALLOC_FREE(values2);
+
+ return LDB_SUCCESS;
+}
+
/*
duplicate a ldb_val structure
*/
@@ -181,8 +394,8 @@ int ldb_msg_add_empty(struct ldb_message *msg,
* is invalidated for some reason, this will
* corrupt *msg contents also
*/
-int ldb_msg_add(struct ldb_message *msg,
- const struct ldb_message_element *el,
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
int flags)
{
int ret;
@@ -207,7 +420,7 @@ int ldb_msg_add(struct ldb_message *msg,
/*
add a value to a message
*/
-int ldb_msg_add_value(struct ldb_message *msg,
+int ldb_msg_add_value(struct ldb_message *msg,
const char *attr_name,
const struct ldb_val *val,
struct ldb_message_element **return_el)
@@ -244,7 +457,7 @@ int ldb_msg_add_value(struct ldb_message *msg,
/*
add a value to a message, stealing it into the 'right' place
*/
-int ldb_msg_add_steal_value(struct ldb_message *msg,
+int ldb_msg_add_steal_value(struct ldb_message *msg,
const char *attr_name,
struct ldb_val *val)
{
@@ -262,7 +475,7 @@ int ldb_msg_add_steal_value(struct ldb_message *msg,
/*
add a string element to a message
*/
-int ldb_msg_add_string(struct ldb_message *msg,
+int ldb_msg_add_string(struct ldb_message *msg,
const char *attr_name, const char *str)
{
struct ldb_val val;
@@ -281,7 +494,7 @@ int ldb_msg_add_string(struct ldb_message *msg,
/*
add a string element to a message, stealing it into the 'right' place
*/
-int ldb_msg_add_steal_string(struct ldb_message *msg,
+int ldb_msg_add_steal_string(struct ldb_message *msg,
const char *attr_name, char *str)
{
struct ldb_val val;
@@ -318,7 +531,7 @@ int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
/*
add a printf formatted element to a message
*/
-int ldb_msg_add_fmt(struct ldb_message *msg,
+int ldb_msg_add_fmt(struct ldb_message *msg,
const char *attr_name, const char *fmt, ...)
{
struct ldb_val val;
@@ -341,7 +554,7 @@ int ldb_msg_add_fmt(struct ldb_message *msg,
compare two ldb_message_element structures
assumes case sensitive comparison
*/
-int ldb_msg_element_compare(struct ldb_message_element *el1,
+int ldb_msg_element_compare(struct ldb_message_element *el1,
struct ldb_message_element *el2)
{
unsigned int i;
@@ -383,7 +596,7 @@ bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
compare two ldb_message_element structures
comparing by element name
*/
-int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
struct ldb_message_element *el2)
{
return ldb_attr_cmp(el1->name, el2->name);
@@ -393,7 +606,7 @@ int ldb_msg_element_compare_name(struct ldb_message_element *el1,
convenience functions to return common types from a message
these return the first value if the attribute is multi-valued
*/
-const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
+const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
const char *attr_name)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
@@ -403,7 +616,7 @@ const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
return &el->values[0];
}
-int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
const char *attr_name,
int default_value)
{
@@ -467,7 +680,7 @@ unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
return ret;
}
-int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
const char *attr_name,
int64_t default_value)
{
@@ -531,7 +744,7 @@ uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
return ret;
}
-double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
const char *attr_name,
double default_value)
{
@@ -560,7 +773,7 @@ double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
return ret;
}
-int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
const char *attr_name,
int default_value)
{
@@ -577,7 +790,7 @@ int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
return default_value;
}
-const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
const char *attr_name,
const char *default_value)
{
@@ -624,7 +837,7 @@ void ldb_msg_sort_elements(struct ldb_message *msg)
shallow copy a message - copying only the elements array so that the caller
can safely add new elements without changing the message
*/
-struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
+struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg)
{
struct ldb_message *msg2;
@@ -635,7 +848,7 @@ struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
*msg2 = *msg;
- msg2->elements = talloc_array(msg2, struct ldb_message_element,
+ msg2->elements = talloc_array(msg2, struct ldb_message_element,
msg2->num_elements);
if (msg2->elements == NULL) goto failed;
@@ -654,7 +867,7 @@ failed:
/*
copy a message, allocating new memory for all parts
*/
-struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg)
{
struct ldb_message *msg2;
@@ -692,7 +905,7 @@ failed:
/**
* Canonicalize a message, merging elements of the same name
*/
-struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
const struct ldb_message *msg)
{
int ret;
@@ -764,7 +977,7 @@ int ldb_msg_normalize(struct ldb_context *ldb,
* If you then use this in a ldb_modify() call,
* it can be used to save edits to a message
*/
-struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
struct ldb_message *msg1,
struct ldb_message *msg2)
{
@@ -870,7 +1083,7 @@ failed:
}
-int ldb_msg_sanity_check(struct ldb_context *ldb,
+int ldb_msg_sanity_check(struct ldb_context *ldb,
const struct ldb_message *msg)
{
unsigned int i, j;
@@ -887,7 +1100,7 @@ int ldb_msg_sanity_check(struct ldb_context *ldb,
if (msg->elements[i].values[j].length == 0) {
/* an attribute cannot be empty */
ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
- msg->elements[i].name,
+ msg->elements[i].name,
ldb_dn_get_linearized(msg->dn));
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
}
@@ -1069,18 +1282,18 @@ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
time_t ldb_string_to_time(const char *s)
{
struct tm tm;
-
+
if (s == NULL) return 0;
-
+
memset(&tm, 0, sizeof(tm));
if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
return 0;
}
tm.tm_year -= 1900;
tm.tm_mon -= 1;
-
+
return timegm(&tm);
}
@@ -1182,12 +1395,12 @@ char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
time_t ldb_string_utc_to_time(const char *s)
{
struct tm tm;
-
+
if (s == NULL) return 0;
-
+
memset(&tm, 0, sizeof(tm));
if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
return 0;
}
@@ -1195,7 +1408,7 @@ time_t ldb_string_utc_to_time(const char *s)
tm.tm_year += 100;
}
tm.tm_mon -= 1;
-
+
return timegm(&tm);
}
@@ -1224,7 +1437,7 @@ int ldb_msg_check_string_attribute(const struct ldb_message *msg,
{
struct ldb_message_element *el;
struct ldb_val val;
-
+
el = ldb_msg_find_element(msg, name);
if (el == NULL) {
return 0;
diff --git a/common/ldb_pack.c b/common/ldb_pack.c
index a63dd58..448c577 100644
--- a/common/ldb_pack.c
+++ b/common/ldb_pack.c
@@ -274,7 +274,10 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
if (flags & LDB_UNPACK_DATA_FLAG_NO_DN) {
message->dn = NULL;
} else {
- message->dn = ldb_dn_new(message, ldb, (char *)p);
+ struct ldb_val blob;
+ blob.data = discard_const_p(uint8_t, p);
+ blob.length = dn_len;
+ message->dn = ldb_dn_from_ldb_val(message, ldb, &blob);
if (message->dn == NULL) {
errno = ENOMEM;
goto failed;
@@ -298,6 +301,11 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
goto failed;
}
+
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_ATTRS) {
+ return 0;
+ }
+
if (message->num_elements == 0) {
return 0;
}
diff --git a/include/ldb.h b/include/ldb.h
index 397f994..9918b4e 100644
--- a/include/ldb.h
+++ b/include/ldb.h
@@ -1,4 +1,4 @@
-/*
+/*
ldb database library
Copyright (C) Andrew Tridgell 2004
@@ -8,7 +8,7 @@
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@@ -56,7 +56,7 @@
major restrictions as compared to normal LDAP:
- each record must have a unique key field
- - the key must be representable as a NULL terminated C string and may not
+ - the key must be representable as a NULL terminated C string and may not
contain a comma or braces
major restrictions as compared to tdb:
@@ -75,7 +75,7 @@
blobs of arbitrary size.
\note the data is null (0x00) terminated, but the length does not
- include the terminator.
+ include the terminator.
*/
struct ldb_val {
uint8_t *data; /*!< result data */
@@ -171,7 +171,7 @@ struct ldb_message_element {
/**
a ldb_message represents all or part of a record. It can contain an arbitrary
- number of elements.
+ number of elements.
*/
struct ldb_message {
struct ldb_dn *dn;
@@ -198,8 +198,8 @@ struct ldb_ldif {
struct ldb_message *msg; /*!< The changes */
};
-enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
- LDB_SCOPE_BASE=0,
+enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
+ LDB_SCOPE_BASE=0,
LDB_SCOPE_ONELEVEL=1,
LDB_SCOPE_SUBTREE=2};
@@ -207,7 +207,7 @@ struct ldb_context;
struct tevent_context;
/* debugging uses one of the following levels */
-enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR,
+enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR,
LDB_DEBUG_WARNING, LDB_DEBUG_TRACE};
/**
@@ -216,7 +216,7 @@ enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR,
of a severity level
*/
struct ldb_debug_ops {
- void (*debug)(void *context, enum ldb_debug_level level,
+ void (*debug)(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
void *context;
};
@@ -262,7 +262,7 @@ struct ldb_utf8_fns {
/**
Flag to tell ldif handlers not to force encoding of binary
- structures in base64
+ structures in base64
*/
#define LDB_FLG_SHOW_BINARY 16
@@ -271,6 +271,15 @@ struct ldb_utf8_fns {
*/
#define LDB_FLG_ENABLE_TRACING 32
+/**
+ Flags to tell LDB not to create a new database file:
+
+ Without this flag ldb_tdb (for example) will create a blank file
+ during an invocation of ldb_connect(), even when the caller only
+ wanted read operations, for example in ldbsearch.
+*/
+#define LDB_FLG_DONT_CREATE_DB 64
+
/*
structures for ldb_parse_tree handling code
*/
@@ -401,15 +410,15 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
/**
The attribute is not returned by default
*/
-#define LDB_ATTR_FLAG_HIDDEN (1<<0)
+#define LDB_ATTR_FLAG_HIDDEN (1<<0)
/* the attribute handler name should be freed when released */
-#define LDB_ATTR_FLAG_ALLOCATED (1<<1)
+#define LDB_ATTR_FLAG_ALLOCATED (1<<1)
/**
The attribute is supplied by the application and should not be removed
*/
-#define LDB_ATTR_FLAG_FIXED (1<<2)
+#define LDB_ATTR_FLAG_FIXED (1<<2)
/*
when this is set, attempts to create two records which have the same
@@ -432,12 +441,17 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
*/
#define LDB_ATTR_FLAG_FROM_DB (1<<6)
+/*
+ * The attribute was loaded from a DB, rather than via the C API
+ */
+#define LDB_ATTR_FLAG_INDEXED (1<<7)
+
/**
LDAP attribute syntax for a DN
This is the well-known LDAP attribute syntax for a DN.
- See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
*/
#define LDB_SYNTAX_DN "1.3.6.1.4.1.1466.115.121.1.12"
@@ -446,7 +460,7 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
This is the well-known LDAP attribute syntax for a Directory String.
- \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
*/
#define LDB_SYNTAX_DIRECTORY_STRING "1.3.6.1.4.1.1466.115.121.1.15"
@@ -455,7 +469,7 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
This is the well-known LDAP attribute syntax for an integer.
- See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
*/
#define LDB_SYNTAX_INTEGER "1.3.6.1.4.1.1466.115.121.1.27"
@@ -464,7 +478,7 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
This is the well-known LDAP attribute syntax for a boolean.
- See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
*/
#define LDB_SYNTAX_BOOLEAN "1.3.6.1.4.1.1466.115.121.1.7"
@@ -473,7 +487,7 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
This is the well-known LDAP attribute syntax for an octet string.
- See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
*/
#define LDB_SYNTAX_OCTET_STRING "1.3.6.1.4.1.1466.115.121.1.40"
@@ -482,7 +496,7 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
This is the well-known LDAP attribute syntax for a UTC time.
- See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
*/
#define LDB_SYNTAX_UTC_TIME "1.3.6.1.4.1.1466.115.121.1.53"
#define LDB_SYNTAX_GENERALIZED_TIME "1.3.6.1.4.1.1466.115.121.1.24"
@@ -497,7 +511,7 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
/**
OID for getting and manipulating attributes from the ldb
without interception in the operational module.
- It can be used to access attribute that used to be stored in the sam
+ It can be used to access attribute that used to be stored in the sam
and that are now calculated.
*/
#define LDB_CONTROL_BYPASS_OPERATIONAL_OID "1.3.6.1.4.1.7165.4.3.13"
@@ -546,7 +560,7 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
OID for the paged results control. This control is included in the
searchRequest and searchResultDone messages as part of the controls
field of the LDAPMessage, as defined in Section 4.1.12 of
- LDAP v3.
+ LDAP v3.
\sa <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>.
*/
@@ -662,7 +676,7 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
#define LDB_CONTROL_ASQ_NAME "asq"
/**
- OID for LDAP Directory Sync extension.
+ OID for LDAP Directory Sync extension.
This control is included in SearchRequest or SearchResponse
messages as part of the controls field of the LDAPMessage.
@@ -700,8 +714,8 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
#define LDB_CONTROL_PERMISSIVE_MODIFY_OID "1.2.840.113556.1.4.1413"
#define LDB_CONTROL_PERMISSIVE_MODIFY_NAME "permissive_modify"
-/**
- OID to allow the server to be more 'fast and loose' with the data being added.
+/**
+ OID to allow the server to be more 'fast and loose' with the data being added.
\sa <a href="http://msdn.microsoft.com/en-us/library/aa366982(v=VS.85).aspx">Microsoft documentation of this OID</a>
*/
@@ -1047,6 +1061,10 @@ int ldb_global_init(void);
\param mem_ctx pointer to a talloc memory context. Pass NULL if there is
no suitable context available.
+ \note The LDB modules will be loaded from directory specified by the environment
+ variable LDB_MODULES_PATH. If the variable is not specified, the compiled-in default
+ is used.
+
\return pointer to ldb_context that should be free'd (using talloc_free())
at the end of the program.
*/
@@ -1114,7 +1132,7 @@ struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb);
struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb);
/**
- The default async search callback function
+ The default async search callback function
\param req the request we are callback of
\param ares a single reply from the async core
@@ -1192,7 +1210,7 @@ int ldb_build_search_req_ex(struct ldb_request **ret_req,
\param ret_req the request structure is returned here (talloced on mem_ctx)
\param ldb the context associated with the database (from ldb_init())
\param mem_ctx a talloc memory context (used as parent of ret_req)
- \param message contains the entry to be added
+ \param message contains the entry to be added
\param controls an array of controls
\param context the callback function context
\param the callback function to handle the async replies
@@ -1309,27 +1327,27 @@ int ldb_request_add_control(struct ldb_request *req, const char *oid, bool criti
int ldb_request_replace_control(struct ldb_request *req, const char *oid, bool critical, void *data);
/**
- check if a control with the specified "oid" exist and return it
+ check if a control with the specified "oid" exist and return it
\param req the request struct where to add the control
\param oid the object identifier of the control as string
- \return the control, NULL if not found
+ \return the control, NULL if not found
*/
struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid);
/**
- check if a control with the specified "oid" exist and return it
+ check if a control with the specified "oid" exist and return it
\param rep the reply struct where to add the control
\param oid the object identifier of the control as string
- \return the control, NULL if not found
+ \return the control, NULL if not found
*/
struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid);
/**
Search the database
- This function searches the database, and returns
+ This function searches the database, and returns
records that match an LDAP-like search expression
\param ldb the context associated with the database (from ldb_init())
@@ -1354,7 +1372,7 @@ int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
This function adds a record to the database. This function will fail
if a record with the specified class and key already exists in the
- database.
+ database.
\param ldb the context associated with the database (from
ldb_init())
@@ -1363,7 +1381,7 @@ int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
\return result code (LDB_SUCCESS if the record was added, otherwise
a failure code)
*/
-int ldb_add(struct ldb_context *ldb,
+int ldb_add(struct ldb_context *ldb,
const struct ldb_message *message);
/**
@@ -1378,7 +1396,7 @@ int ldb_add(struct ldb_context *ldb,
\return result code (LDB_SUCCESS if the record was modified as
requested, otherwise a failure code)
*/
-int ldb_modify(struct ldb_context *ldb,
+int ldb_modify(struct ldb_context *ldb,
const struct ldb_message *message);
/**
@@ -1389,7 +1407,7 @@ int ldb_modify(struct ldb_context *ldb,
\param ldb the context associated with the database (from
ldb_init())
\param olddn the DN for the record to be renamed.
- \param newdn the new DN
+ \param newdn the new DN
\return result code (LDB_SUCCESS if the record was renamed as
requested, otherwise a failure code)
@@ -1411,7 +1429,7 @@ int ldb_rename(struct ldb_context *ldb, struct ldb_dn *olddn, struct ldb_dn *new
int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn);
/**
- The default async extended operation callback function
+ The default async extended operation callback function
\param req the request we are callback of
\param ares a single reply from the async core
@@ -1438,7 +1456,7 @@ int ldb_extended_default_callback(struct ldb_request *req, struct ldb_reply *are
\param mem_ctx a talloc memory context (used as parent of ret_req)
\param oid the OID of the extended operation.
\param data a void pointer a the extended operation specific parameters,
- it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it
+ it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it
\param controls an array of controls
\param context the callback function context
\param the callback function to handle the async replies
@@ -1462,13 +1480,13 @@ int ldb_build_extended_req(struct ldb_request **ret_req,
\param ldb the context associated with the database (from ldb_init())
\param oid the OID of the extended operation.
\param data a void pointer a the extended operation specific parameters,
- it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it
+ it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it
\param res the result of the extended operation
\return result code (LDB_SUCCESS if the extended operation returned fine,
otherwise a failure code)
*/
-int ldb_extended(struct ldb_context *ldb,
+int ldb_extended(struct ldb_context *ldb,
const char *oid,
void *data,/* NULL or a valid talloc pointer! talloc_get_type() will be used on it */
struct ldb_result **res);
@@ -1526,7 +1544,7 @@ void ldb_set_utf8_default(struct ldb_context *ldb);
\param ldb the ldb context
\param mem_ctx the memory context to allocate the result string
- memory from.
+ memory from.
\param s the string that is to be folded
\return a copy of the string, converted to upper case
@@ -1556,7 +1574,7 @@ int ldb_valid_attr_name(const char *s);
\param ldb the ldb context (from ldb_init())
\param fprintf_fn a function pointer for the write function. This must take
a private data pointer, followed by a format string, and then a variable argument
- list.
+ list.
\param private_data pointer that will be provided back to the write
function. This is useful for maintaining state or context.
\param ldif the message to write out
@@ -1570,7 +1588,7 @@ int ldb_valid_attr_name(const char *s);
\sa ldb_ldif_read for the reader equivalent to this function.
*/
int ldb_ldif_write(struct ldb_context *ldb,
- int (*fprintf_fn)(void *, const char *, ...) PRINTF_ATTRIBUTE(2,3),
+ int (*fprintf_fn)(void *, const char *, ...) PRINTF_ATTRIBUTE(2,3),
void *private_data,
const struct ldb_ldif *ldif);
@@ -1591,7 +1609,7 @@ void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *msg);
Read an LDIF message
This function creates an LDIF message using a caller supplied read
- function.
+ function.
\param ldb the ldb context (from ldb_init())
\param fgetc_fn a function pointer for the read function. This must
@@ -1614,7 +1632,7 @@ void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *msg);
\sa ldb_ldif_write for the writer equivalent to this function.
*/
-struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
+struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
int (*fgetc_fn)(void *), void *private_data);
/**
@@ -1702,26 +1720,56 @@ int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif
\sa ldb_ldif_read_string for the reader equivalent to this function.
*/
-char * ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+char * ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
const struct ldb_ldif *msg);
-/*
- Produce a string form of an ldb message
+/**
+ Write an LDB message to a string
- convenient function to turn a ldb_message into a string. Useful for
- debugging
- */
-char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ \param ldb the ldb context (from ldb_init())
+ \param mem_ctx the talloc context on which to attach the string)
+ \param changetype LDB_CHANGETYPE_ADD or LDB_CHANGETYPE_MODIFY
+ \param msg the message to write out
+
+ \return the string containing the LDIF, or NULL on error
+
+ \sa ldb_ldif_message_redacted_string for a safer version of this
+ function
+*/
+char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
enum ldb_changetype changetype,
const struct ldb_message *msg);
+/**
+ Write an LDB message to a string
+
+ \param ldb the ldb context (from ldb_init())
+ \param mem_ctx the talloc context on which to attach the string)
+ \param changetype LDB_CHANGETYPE_ADD or LDB_CHANGETYPE_MODIFY
+ \param msg the message to write out
+
+ \return the string containing the LDIF, or NULL on error, but
+ with secret attributes redacted
+
+ \note The secret attributes are specified in a
+ 'const char * const *' within the LDB_SECRET_ATTRIBUTE_LIST
+ opaque set on the ldb
+
+ \sa ldb_ldif_message_string for an exact representiation of the
+ message as LDIF
+*/
+char *ldb_ldif_message_redacted_string(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ enum ldb_changetype changetype,
+ const struct ldb_message *msg);
+
/**
Base64 encode a buffer
\param mem_ctx the memory context that the result is allocated
- from.
+ from.
\param buf pointer to the array that is to be encoded
\param len the number of elements in the array to be encoded
@@ -1749,15 +1797,15 @@ int ldb_base64_decode(char *s);
/**
Get the linear form of a DN (without any extended components)
-
+
\param dn The DN to linearize
*/
const char *ldb_dn_get_linearized(struct ldb_dn *dn);
/**
- Allocate a copy of the linear form of a DN (without any extended components) onto the supplied memory context
-
+ Allocate a copy of the linear form of a DN (without any extended components) onto the supplied memory context
+
\param dn The DN to linearize
\param mem_ctx TALLOC context to return result on
*/
@@ -1766,7 +1814,7 @@ char *ldb_dn_alloc_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
/**
Get the linear form of a DN (with any extended components)
-
+
\param mem_ctx TALLOC context to return result on
\param dn The DN to linearize
\param mode Style of extended DN to return (0 is HEX representation of binary form, 1 is a string form)
@@ -1778,21 +1826,21 @@ void ldb_dn_extended_filter(struct ldb_dn *dn, const char * const *accept_list);
void ldb_dn_remove_extended_components(struct ldb_dn *dn);
bool ldb_dn_has_extended(struct ldb_dn *dn);
-int ldb_dn_extended_add_syntax(struct ldb_context *ldb,
+int ldb_dn_extended_add_syntax(struct ldb_context *ldb,
unsigned flags,
const struct ldb_dn_extended_syntax *syntax);
-/**
+/**
Allocate a new DN from a string
\param mem_ctx TALLOC context to return resulting ldb_dn structure on
- \param dn The new DN
+ \param dn The new DN
\note The DN will not be parsed at this time. Use ldb_dn_validate to tell if the DN is syntacticly correct
*/
struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *dn);
-/**
+/**
Allocate a new DN from a printf style format string and arguments
\param mem_ctx TALLOC context to return resulting ldb_dn structure on
@@ -1802,11 +1850,11 @@ struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const ch
*/
struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) PRINTF_ATTRIBUTE(3,4);
-/**
+/**
Allocate a new DN from a struct ldb_val (useful to avoid buffer overrun)
\param mem_ctx TALLOC context to return resulting ldb_dn structure on
- \param dn The new DN
+ \param dn The new DN
\note The DN will not be parsed at this time. Use ldb_dn_validate to tell if the DN is syntacticly correct
*/
@@ -1814,7 +1862,7 @@ struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, cons
struct ldb_dn *ldb_dn_from_ldb_val(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn);
/**
- Determine if this DN is syntactically valid
+ Determine if this DN is syntactically valid
\param dn The DN to validate
*/
@@ -1921,31 +1969,31 @@ int ldb_msg_add_empty(struct ldb_message *msg,
/**
add a element to a ldb_message
*/
-int ldb_msg_add(struct ldb_message *msg,
- const struct ldb_message_element *el,
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
int flags);
-int ldb_msg_add_value(struct ldb_message *msg,
+int ldb_msg_add_value(struct ldb_message *msg,
const char *attr_name,
const struct ldb_val *val,
struct ldb_message_element **return_el);
-int ldb_msg_add_steal_value(struct ldb_message *msg,
+int ldb_msg_add_steal_value(struct ldb_message *msg,
const char *attr_name,
struct ldb_val *val);
-int ldb_msg_add_steal_string(struct ldb_message *msg,
+int ldb_msg_add_steal_string(struct ldb_message *msg,
const char *attr_name, char *str);
-int ldb_msg_add_string(struct ldb_message *msg,
+int ldb_msg_add_string(struct ldb_message *msg,
const char *attr_name, const char *str);
int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
struct ldb_dn *dn);
-int ldb_msg_add_fmt(struct ldb_message *msg,
+int ldb_msg_add_fmt(struct ldb_message *msg,
const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
/**
compare two message elements - return 0 on match
*/
-int ldb_msg_element_compare(struct ldb_message_element *el1,
+int ldb_msg_element_compare(struct ldb_message_element *el1,
struct ldb_message_element *el2);
-int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
struct ldb_message_element *el2);
/**
@@ -1956,25 +2004,25 @@ int ldb_msg_element_compare_name(struct ldb_message_element *el1,
single valued.
*/
const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name);
-int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
const char *attr_name,
int default_value);
-unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
const char *attr_name,
unsigned int default_value);
-int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
const char *attr_name,
int64_t default_value);
-uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
const char *attr_name,
uint64_t default_value);
-double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
const char *attr_name,
double default_value);
-int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
const char *attr_name,
int default_value);
-const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
const char *attr_name,
const char *default_value);
@@ -1985,9 +2033,9 @@ struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
void ldb_msg_sort_elements(struct ldb_message *msg);
-struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
+struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg);
-struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg);
/*
@@ -1999,7 +2047,7 @@ struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
* to steal the returned object into a TALLOC_CTX
* with short lifetime.
*/
-struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
const struct ldb_message *msg) _DEPRECATED_;
int ldb_msg_normalize(struct ldb_context *ldb,
@@ -2017,7 +2065,7 @@ int ldb_msg_normalize(struct ldb_context *ldb,
* to steal the returned object into a TALLOC_CTX
* with short lifetime.
*/
-struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
struct ldb_message *msg1,
struct ldb_message *msg2) _DEPRECATED_;
@@ -2074,7 +2122,7 @@ int ldb_msg_sanity_check(struct ldb_context *ldb,
/**
Duplicate an ldb_val structure
- This function copies an ldb value structure.
+ This function copies an ldb value structure.
\param mem_ctx the memory context that the duplicated value will be
allocated from
@@ -2088,7 +2136,7 @@ struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v);
this allows the user to set a debug function for error reporting
*/
int ldb_set_debug(struct ldb_context *ldb,
- void (*debug)(void *context, enum ldb_debug_level level,
+ void (*debug)(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0),
void *context);
@@ -2118,8 +2166,8 @@ void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr);
void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el);
-void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
- const char *attr,
+void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
+ const char *attr,
const char *replace);
/*
@@ -2134,7 +2182,7 @@ struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx,
This function converts a time_t structure to an LDAP formatted
GeneralizedTime string.
-
+
\param mem_ctx the memory context to allocate the return string in
\param t the time structure to convert
@@ -2166,7 +2214,7 @@ int ldb_val_to_time(const struct ldb_val *v, time_t *t);
This function converts a time_t structure to an LDAP formatted
UTCTime string.
-
+
\param mem_ctx the memory context to allocate the return string in
\param t the time structure to convert
@@ -2222,16 +2270,16 @@ do { \
/**
Convert a control into its string representation.
-
+
\param mem_ctx TALLOC context to return result on, and to allocate error_string on
\param control A struct ldb_control to convert
- \return string representation of the control
+ \return string representation of the control
*/
char* ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *control);
/**
- Convert a string representing a control into a ldb_control structure
-
+ Convert a string representing a control into a ldb_control structure
+
\param ldb LDB context
\param mem_ctx TALLOC context to return result on, and to allocate error_string on
\param control_strings A string-formatted control
@@ -2240,8 +2288,8 @@ char* ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr
*/
struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *control_strings);
/**
- Convert an array of string represention of a control into an array of ldb_control structures
-
+ Convert an array of string represention of a control into an array of ldb_control structures
+
\param ldb LDB context
\param mem_ctx TALLOC context to return result on, and to allocate error_string on
\param control_strings Array of string-formatted controls
@@ -2251,7 +2299,7 @@ struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLO
struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings);
/**
- return the ldb flags
+ return the ldb flags
*/
unsigned int ldb_get_flags(struct ldb_context *ldb);
diff --git a/include/ldb_module.h b/include/ldb_module.h
index 833d5a8..71b4074 100644
--- a/include/ldb_module.h
+++ b/include/ldb_module.h
@@ -35,6 +35,41 @@
#include <ldb.h>
+#if defined(_SAMBA_BUILD_) && defined(USING_SYSTEM_LDB)
+
+/*
+ * Versions before 1.2.0 doesn't define these values
+ * so we assime 1.1.29 (which was used in Samba 4.6)
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=12859
+ */
+#ifndef EXPECTED_SYSTEM_LDB_VERSION_MAJOR
+#define EXPECTED_SYSTEM_LDB_VERSION_MAJOR 1
+#endif
+#ifndef EXPECTED_SYSTEM_LDB_VERSION_MINOR
+#define EXPECTED_SYSTEM_LDB_VERSION_MINOR 1
+#endif
+#ifndef EXPECTED_SYSTEM_LDB_VERSION_MINOR
+#define EXPECTED_SYSTEM_LDB_VERSION_MINOR 29
+#endif
+
+/*
+ * Only Samba versions which expect ldb >= 1.2.0
+ * are compatible with read_[un]lock() behaviour.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=12859
+ */
+#if EXPECTED_SYSTEM_LDB_VERSION_MAJOR > 1
+#define __LDB_READ_LOCK_COMPATIBLE__ 1
+#elif EXPECTED_SYSTEM_LDB_VERSION_MINOR > 1
+#define __LDB_READ_LOCK_COMPATIBLE__ 1
+#endif
+#ifndef __LDB_READ_LOCK_COMPATIBLE__
+#error "Samba < 4.7 is not compatible with this version of ldb due to assumptions around read locks"
+#endif
+
+#endif /* defined(_SAMBA_BUILD_) && defined(USING_SYSTEM_LDB) */
+
struct ldb_context;
struct ldb_module;
@@ -77,6 +112,8 @@ struct ldb_module_ops {
int (*end_transaction)(struct ldb_module *);
int (*del_transaction)(struct ldb_module *);
int (*sequence_number)(struct ldb_module *, struct ldb_request *);
+ int (*read_lock)(struct ldb_module *);
+ int (*read_unlock)(struct ldb_module *);
void *private_data;
};
@@ -122,10 +159,30 @@ void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name);
/* we allow external code to override the name -> schema_attribute function */
typedef const struct ldb_schema_attribute *(*ldb_attribute_handler_override_fn_t)(struct ldb_context *, void *, const char *);
+/**
+ Allow the caller to define a callback for the attribute handler
+
+ \param ldb The ldb context
+ \param override The callback to be used for attribute lookups
+ \param private_data Private data for the callback
+
+*/
void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
ldb_attribute_handler_override_fn_t override,
void *private_data);
+/**
+ Allow the caller to define that the callback for the attribute handler
+ also overrides the index list
+
+ \param ldb The ldb context
+ \param one_level_indexes Indicates that the index for SCOPE_ONELEVEL
+ should also be maintained
+
+*/
+void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
+ bool one_level_indexes);
+
/* A useful function to build comparison functions with */
int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
ldb_attr_handler_t canonicalise_fn,
@@ -183,6 +240,8 @@ int ldb_next_end_trans(struct ldb_module *module);
int ldb_next_del_trans(struct ldb_module *module);
int ldb_next_prepare_commit(struct ldb_module *module);
int ldb_next_init(struct ldb_module *module);
+int ldb_next_read_lock(struct ldb_module *module);
+int ldb_next_read_unlock(struct ldb_module *module);
void ldb_set_errstring(struct ldb_context *ldb, const char *err_string);
void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
@@ -197,6 +256,17 @@ typedef int (*ldb_connect_fn)(struct ldb_context *ldb, const char *url,
unsigned int flags, const char *options[],
struct ldb_module **module);
+/**
+ Require that LDB use a private event context for each request
+
+ A private event context may need to be created to avoid nested event
+ loops during ldb_tdb with the locks held. This indicates that a
+ backend is in use that requires this to hold locks safely.
+
+ \param handle The ldb handle to set the flag on
+ */
+void ldb_set_require_private_event_context(struct ldb_context *ldb);
+
struct ldb_backend_ops {
const char *name;
ldb_connect_fn connect_fn;
@@ -208,6 +278,18 @@ int ldb_register_backend(const char *url_prefix, ldb_connect_fn, bool);
struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb);
+/**
+ Obtains the private event context for the handle,
+
+ A private event context may have been created to avoid nested event
+ loops during ldb_tdb with the locks held. Otherwise return the
+ global one.
+
+ \param handle The ldb handle to obtain the event context for
+ \return the tevent event context for this handle (private or global)
+ */
+struct tevent_context *ldb_handle_get_event_context(struct ldb_handle *handle);
+
int ldb_module_send_entry(struct ldb_request *req,
struct ldb_message *msg,
struct ldb_control **ctrls);
@@ -236,19 +318,32 @@ void ldb_set_default_dns(struct ldb_context *ldb);
int ldb_reply_add_control(struct ldb_reply *ares, const char *oid, bool critical, void *data);
/**
- mark a request as untrusted. This tells the rootdse module to remove
- unregistered controls
- */
+ mark a request as untrusted.
+
+ This tells the rootdse module to remove unregistered controls
+
+ \param req the request to mark as untrusted
+*/
void ldb_req_mark_untrusted(struct ldb_request *req);
/**
mark a request as trusted.
- */
+
+ This tells the rootdse module to allow unregistered controls
+
+ \param req the request to mark as trusted
+*/
void ldb_req_mark_trusted(struct ldb_request *req);
/**
return true is a request is untrusted
- */
+
+ This indicates the request came across a trust boundary
+ for example over LDAP
+
+ \param req the request check
+ \return is req trusted
+*/
bool ldb_req_is_untrusted(struct ldb_request *req);
/**
@@ -423,6 +518,10 @@ int ldb_unpack_data(struct ldb_context *ldb,
* LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC is also specified.
*
* Likewise if LDB_UNPACK_DATA_FLAG_NO_DN is specified, the DN is omitted.
+ *
+ * If LDB_UNPACK_DATA_FLAG_NO_ATTRS is specified, then no attributes
+ * are unpacked or returned.
+ *
*/
int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
const struct ldb_val *data,
@@ -435,5 +534,22 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
#define LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC 0x0001
#define LDB_UNPACK_DATA_FLAG_NO_DN 0x0002
#define LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC 0x0004
+#define LDB_UNPACK_DATA_FLAG_NO_ATTRS 0x0008
+
+/**
+ Forces a specific ldb handle to use the global event context.
+
+ This allows a nested event loop to operate, so any open
+ transaction also needs to be aborted.
+
+ Any events on this event context will be lost.
+
+ This is used in Samba when sending an IRPC to another part of the
+ same process instead of making a local DB modification.
+
+ \param handle The ldb handle to force to use the global context
+
+ */
+void ldb_handle_use_global_event_context(struct ldb_handle *handle);
#endif
diff --git a/include/ldb_private.h b/include/ldb_private.h
index 644d49c..ae7ec3c 100644
--- a/include/ldb_private.h
+++ b/include/ldb_private.h
@@ -62,6 +62,9 @@ struct ldb_handle {
uint32_t custom_flags;
unsigned nesting;
+ /* Private event context (if not NULL) */
+ struct tevent_context *event_context;
+
/* used for debugging */
struct ldb_request *parent;
const char *location;
@@ -88,6 +91,13 @@ struct ldb_schema {
unsigned num_dn_extended_syntax;
struct ldb_dn_extended_syntax *dn_extended_syntax;
+
+ /*
+ * If set, the attribute_handler_override has the details of
+ * what attributes have an index
+ */
+ bool index_handler_override;
+ bool one_level_indexes;
};
/*
@@ -130,6 +140,13 @@ struct ldb_context {
struct tevent_context *ev_ctx;
+ /*
+ * If the backend holds locks, we must not use a global event
+ * context, so this flag will be set and ldb_handle_new() will
+ * build a new event context
+ */
+ bool require_private_event_context;
+
bool prepare_commit_done;
char *partial_debug;
@@ -220,4 +237,55 @@ char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *
*/
struct ldb_context *ldb_dn_get_ldb_context(struct ldb_dn *dn);
+#define LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES 1
+
+/**
+ Determine whether any values in an element are also in another element,
+ and optionally fix that.
+
+ \param ldb an ldb context
+ \param mem_ctx a talloc context
+ \param el an element
+ \param other_el another element
+ \param options flags controlling the function behaviour
+
+ Without the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, return
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS if the elements share values, and
+ LDB_SUCCESS if they don't. That is, determine whether there is an
+ intersection without changing anything.
+
+ With the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, any values in common
+ are removed from the first element and LDB_SUCCESS is returned.
+
+ LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown option.
+ LDB_ERR_INAPPROPRIATE_MATCHING means the elements differ in name.
+*/
+
+int ldb_msg_find_common_values(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el,
+ struct ldb_message_element *other_el,
+ uint32_t options);
+
+/**
+ Detect whether an element contains duplicate values
+
+ \param ldb a currently unused ldb_context struct
+ \param mem_ctx a talloc context
+ \param el the element to search
+ \param duplicate will point to a duplicate value if there are duplicates,
+ or NULL otherwise.
+ \param options is a flags field. All values are reserved.
+
+ \return an ldb error code. LDB_ERR_OPERATIONS_ERROR indicates an allocation
+ failure or an unknown option flag. Otherwise LDB_SUCCESS.
+
+ \note This search is case sensitive
+*/
+int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message_element *el,
+ struct ldb_val **duplicate,
+ uint32_t options);
+
#endif
diff --git a/ldb_sqlite3/ldb_sqlite3.c b/ldb_sqlite3/ldb_sqlite3.c
index 60b39e8..f94dc99 100644
--- a/ldb_sqlite3/ldb_sqlite3.c
+++ b/ldb_sqlite3/ldb_sqlite3.c
@@ -1152,12 +1152,24 @@ static int lsql_modify(struct lsql_context *ctx)
switch (flags) {
case LDB_FLAG_MOD_REPLACE:
+ struct ldb_val *duplicate = NULL;
- for (j=0; j<el->num_values; j++) {
- if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
- ldb_asprintf_errstring(ldb, "%s: value #%d provided more than once", el->name, j);
- return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- }
+ ret = ldb_msg_find_duplicate_val(ldb, el, el,
+ &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value '%.*s' "
+ "on '%s' provided more than "
+ "once in REPLACE",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg2->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
}
/* remove all attributes before adding the replacements */
diff --git a/ldb_tdb/ldb_cache.c b/ldb_tdb/ldb_cache.c
index 5ea09d6..f08e073 100644
--- a/ldb_tdb/ldb_cache.c
+++ b/ldb_tdb/ldb_cache.c
@@ -226,6 +226,59 @@ failed:
return -1;
}
+/*
+ register any index records we find for the DB
+*/
+static int ltdb_index_load(struct ldb_module *module,
+ struct ltdb_private *ltdb)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_dn *indexlist_dn;
+ int r;
+
+ if (ldb->schema.index_handler_override) {
+ /*
+ * we skip loading the @INDEXLIST record when a module is
+ * supplying its own attribute handling
+ */
+ ltdb->cache->attribute_indexes = true;
+ ltdb->cache->one_level_indexes = ldb->schema.one_level_indexes;
+ return 0;
+ }
+
+ talloc_free(ltdb->cache->indexlist);
+
+ ltdb->cache->indexlist = ldb_msg_new(ltdb->cache);
+ if (ltdb->cache->indexlist == NULL) {
+ return -1;
+ }
+ ltdb->cache->one_level_indexes = false;
+ ltdb->cache->attribute_indexes = false;
+
+ indexlist_dn = ldb_dn_new(ltdb, ldb, LTDB_INDEXLIST);
+ if (indexlist_dn == NULL) {
+ return -1;
+ }
+
+ r = ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC
+ |LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC
+ |LDB_UNPACK_DATA_FLAG_NO_DN);
+ TALLOC_FREE(indexlist_dn);
+
+ if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
+ return -1;
+ }
+
+ if (ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXONE) != NULL) {
+ ltdb->cache->one_level_indexes = true;
+ }
+ if (ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXATTR) != NULL) {
+ ltdb->cache->attribute_indexes = true;
+ }
+
+ return 0;
+}
/*
initialise the baseinfo record
@@ -316,7 +369,6 @@ int ltdb_cache_load(struct ldb_module *module)
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
struct ldb_dn *baseinfo_dn = NULL, *options_dn = NULL;
- struct ldb_dn *indexlist_dn = NULL;
uint64_t seq;
struct ldb_message *baseinfo = NULL, *options = NULL;
int r;
@@ -332,10 +384,6 @@ int ltdb_cache_load(struct ldb_module *module)
if (ltdb->cache == NULL) {
ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
if (ltdb->cache == NULL) goto failed;
- ltdb->cache->indexlist = ldb_msg_new(ltdb->cache);
- if (ltdb->cache->indexlist == NULL) {
- goto failed;
- }
}
baseinfo = ldb_msg_new(ltdb->cache);
@@ -385,6 +433,7 @@ int ltdb_cache_load(struct ldb_module *module)
if (options_dn == NULL) goto failed;
r= ltdb_search_dn1(module, options_dn, options, 0);
+ talloc_free(options_dn);
if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
goto failed;
}
@@ -402,7 +451,6 @@ int ltdb_cache_load(struct ldb_module *module)
ltdb->disallow_dn_filter = false;
}
- talloc_free(ltdb->cache->indexlist);
/*
* ltdb_attributes_unload() calls internally talloc_free() on
* any non-fixed elemnts in ldb->schema.attributes.
@@ -412,31 +460,11 @@ int ltdb_cache_load(struct ldb_module *module)
* partition module.
*/
ltdb_attributes_unload(module);
- ltdb->cache->indexlist = ldb_msg_new(ltdb->cache);
- if (ltdb->cache->indexlist == NULL) {
- goto failed;
- }
- ltdb->cache->one_level_indexes = false;
- ltdb->cache->attribute_indexes = false;
-
- indexlist_dn = ldb_dn_new(module, ldb, LTDB_INDEXLIST);
- if (indexlist_dn == NULL) goto failed;
- r = ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist,
- LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC
- |LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC
- |LDB_UNPACK_DATA_FLAG_NO_DN);
- if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
+ if (ltdb_index_load(module, ltdb) == -1) {
goto failed;
}
- if (ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXONE) != NULL) {
- ltdb->cache->one_level_indexes = true;
- }
- if (ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXATTR) != NULL) {
- ltdb->cache->attribute_indexes = true;
- }
-
/*
* NOTE WELL: This is per-ldb, not per module, so overwrites
* the handlers across all databases when used under Samba's
@@ -449,13 +477,11 @@ int ltdb_cache_load(struct ldb_module *module)
done:
talloc_free(options);
talloc_free(baseinfo);
- talloc_free(indexlist_dn);
return 0;
failed:
talloc_free(options);
talloc_free(baseinfo);
- talloc_free(indexlist_dn);
return -1;
}
diff --git a/ldb_tdb/ldb_index.c b/ldb_tdb/ldb_index.c
index 53fcde5..3510dd9 100644
--- a/ldb_tdb/ldb_index.c
+++ b/ldb_tdb/ldb_index.c
@@ -54,6 +54,10 @@ int ltdb_index_transaction_start(struct ldb_module *module)
{
struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
ltdb->idxptr = talloc_zero(ltdb, struct ltdb_idxptr);
+ if (ltdb->idxptr == NULL) {
+ return ldb_oom(ldb_module_get_ctx(module));
+ }
+
return LDB_SUCCESS;
}
@@ -79,7 +83,9 @@ static int ltdb_dn_list_find_val(const struct dn_list *list, const struct ldb_va
{
unsigned int i;
for (i=0; i<list->count; i++) {
- if (dn_list_cmp(&list->dn[i], v) == 0) return i;
+ if (dn_list_cmp(&list->dn[i], v) == 0) {
+ return i;
+ }
}
return -1;
}
@@ -445,12 +451,34 @@ static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb,
/*
see if a attribute value is in the list of indexed attributes
*/
-static bool ltdb_is_indexed(const struct ldb_message *index_list, const char *attr)
+static bool ltdb_is_indexed(struct ldb_module *module,
+ struct ltdb_private *ltdb,
+ const char *attr)
{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
unsigned int i;
struct ldb_message_element *el;
- el = ldb_msg_find_element(index_list, LTDB_IDXATTR);
+ if (ldb->schema.index_handler_override) {
+ const struct ldb_schema_attribute *a
+ = ldb_schema_attribute_by_name(ldb, attr);
+
+ if (a == NULL) {
+ return false;
+ }
+
+ if (a->flags & LDB_ATTR_FLAG_INDEXED) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (!ltdb->cache->attribute_indexes) {
+ return false;
+ }
+
+ el = ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXATTR);
if (el == NULL) {
return false;
}
@@ -481,8 +509,8 @@ static bool ltdb_is_indexed(const struct ldb_message *index_list, const char *at
equality search only)
*/
static int ltdb_index_dn_simple(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list)
{
struct ldb_context *ldb;
@@ -496,7 +524,7 @@ static int ltdb_index_dn_simple(struct ldb_module *module,
/* if the attribute isn't in the list of indexed attributes then
this node needs a full search */
- if (!ltdb_is_indexed(index_list, tree->u.equality.attr)) {
+ if (!ltdb_is_indexed(module, ltdb, tree->u.equality.attr)) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -517,12 +545,10 @@ static bool list_union(struct ldb_context *, struct dn_list *, const struct dn_l
return a list of dn's that might match a leaf indexed search
*/
static int ltdb_index_dn_leaf(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list)
{
- struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module),
- struct ltdb_private);
if (ltdb->disallow_dn_filter &&
(ldb_attr_cmp(tree->u.equality.attr, "dn") == 0)) {
/* in AD mode we do not support "(dn=...)" search filters */
@@ -540,7 +566,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
list->count = 1;
return LDB_SUCCESS;
}
- return ltdb_index_dn_simple(module, tree, index_list, list);
+ return ltdb_index_dn_simple(module, ltdb, tree, list);
}
@@ -653,8 +679,8 @@ static bool list_union(struct ldb_context *ldb,
}
static int ltdb_index_dn(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list);
@@ -662,8 +688,8 @@ static int ltdb_index_dn(struct ldb_module *module,
process an OR list (a union)
*/
static int ltdb_index_dn_or(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list)
{
struct ldb_context *ldb;
@@ -683,7 +709,8 @@ static int ltdb_index_dn_or(struct ldb_module *module,
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
+ ret = ltdb_index_dn(module, ltdb,
+ tree->u.list.elements[i], list2);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* X || 0 == X */
@@ -715,8 +742,8 @@ static int ltdb_index_dn_or(struct ldb_module *module,
NOT an index results
*/
static int ltdb_index_dn_not(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list)
{
/* the only way to do an indexed not would be if we could
@@ -746,8 +773,8 @@ static bool ltdb_index_unique(struct ldb_context *ldb,
process an AND expression (intersection)
*/
static int ltdb_index_dn_and(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list)
{
struct ldb_context *ldb;
@@ -771,7 +798,7 @@ static int ltdb_index_dn_and(struct ldb_module *module,
continue;
}
- ret = ltdb_index_dn(module, subtree, index_list, list);
+ ret = ltdb_index_dn(module, ltdb, subtree, list);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* 0 && X == 0 */
return LDB_ERR_NO_SUCH_OBJECT;
@@ -798,7 +825,7 @@ static int ltdb_index_dn_and(struct ldb_module *module,
return ldb_module_oom(module);
}
- ret = ltdb_index_dn(module, subtree, index_list, list2);
+ ret = ltdb_index_dn(module, ltdb, subtree, list2);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* X && 0 == 0 */
@@ -884,27 +911,27 @@ static int ltdb_index_dn_one(struct ldb_module *module,
an error. return LDB_ERR_NO_SUCH_OBJECT for no matches, or LDB_SUCCESS for matches
*/
static int ltdb_index_dn(struct ldb_module *module,
+ struct ltdb_private *ltdb,
const struct ldb_parse_tree *tree,
- const struct ldb_message *index_list,
struct dn_list *list)
{
int ret = LDB_ERR_OPERATIONS_ERROR;
switch (tree->operation) {
case LDB_OP_AND:
- ret = ltdb_index_dn_and(module, tree, index_list, list);
+ ret = ltdb_index_dn_and(module, ltdb, tree, list);
break;
case LDB_OP_OR:
- ret = ltdb_index_dn_or(module, tree, index_list, list);
+ ret = ltdb_index_dn_or(module, ltdb, tree, list);
break;
case LDB_OP_NOT:
- ret = ltdb_index_dn_not(module, tree, index_list, list);
+ ret = ltdb_index_dn_not(module, ltdb, tree, list);
break;
case LDB_OP_EQUALITY:
- ret = ltdb_index_dn_leaf(module, tree, index_list, list);
+ ret = ltdb_index_dn_leaf(module, ltdb, tree, list);
break;
case LDB_OP_SUBSTRING:
@@ -1087,7 +1114,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
talloc_free(dn_list);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list);
+ ret = ltdb_index_dn(ac->module, ltdb, ac->tree, dn_list);
if (ret != LDB_SUCCESS) {
talloc_free(dn_list);
return ret;
@@ -1122,8 +1149,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
* @return An ldb error code
*/
static int ltdb_index_add1(struct ldb_module *module, const char *dn,
- struct ldb_message_element *el, int v_idx,
- bool is_new)
+ struct ldb_message_element *el, int v_idx)
{
struct ldb_context *ldb;
struct ldb_dn *dn_key;
@@ -1154,22 +1180,25 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn,
if (list->count > 0 &&
a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX) {
- talloc_free(list);
+ /*
+ * We do not want to print info about a possibly
+ * confidential DN that the conflict was with in the
+ * user-visible error string
+ */
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ __location__ ": unique index violation on %s in %s, "
+ "conficts with %*.*s in %s",
+ el->name, dn,
+ (int)list->dn[0].length,
+ (int)list->dn[0].length,
+ list->dn[0].data,
+ ldb_dn_get_linearized(dn_key));
ldb_asprintf_errstring(ldb, __location__ ": unique index violation on %s in %s",
el->name, dn);
+ talloc_free(list);
return LDB_ERR_ENTRY_ALREADY_EXISTS;
}
- /* If we are doing an ADD, then this can not already be in the index,
- as it was not already in the database, and this has already been
- checked because the store succeeded */
- if (! is_new) {
- if (ltdb_dn_list_find_str(list, dn) != -1) {
- talloc_free(list);
- return LDB_SUCCESS;
- }
- }
-
/* overallocate the list a bit, to reduce the number of
* realloc trigered copies */
alloc_len = ((list->count+1)+7) & ~7;
@@ -1178,7 +1207,13 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn,
talloc_free(list);
return LDB_ERR_OPERATIONS_ERROR;
}
- list->dn[list->count].data = (uint8_t *)talloc_strdup(list->dn, dn);
+
+ list->dn[list->count].data
+ = (uint8_t *)talloc_strdup(list->dn, dn);
+ if (list->dn[list->count].data == NULL) {
+ talloc_free(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
list->dn[list->count].length = strlen(dn);
list->count++;
@@ -1193,11 +1228,11 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn,
add index entries for one elements in a message
*/
static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
- struct ldb_message_element *el, bool is_new)
+ struct ldb_message_element *el)
{
unsigned int i;
for (i = 0; i < el->num_values; i++) {
- int ret = ltdb_index_add1(module, dn, el, i, is_new);
+ int ret = ltdb_index_add1(module, dn, el, i);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1211,8 +1246,7 @@ static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
*/
static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
struct ldb_message_element *elements,
- unsigned int num_el,
- bool is_new)
+ unsigned int num_el)
{
struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
unsigned int i;
@@ -1221,17 +1255,17 @@ static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
return LDB_SUCCESS;
}
- if (ltdb->cache->indexlist->num_elements == 0) {
+ if (!ltdb->cache->attribute_indexes) {
/* no indexed fields */
return LDB_SUCCESS;
}
for (i = 0; i < num_el; i++) {
int ret;
- if (!ltdb_is_indexed(ltdb->cache->indexlist, elements[i].name)) {
+ if (!ltdb_is_indexed(module, ltdb, elements[i].name)) {
continue;
}
- ret = ltdb_index_add_el(module, dn, &elements[i], is_new);
+ ret = ltdb_index_add_el(module, dn, &elements[i]);
if (ret != LDB_SUCCESS) {
struct ldb_context *ldb = ldb_module_get_ctx(module);
ldb_asprintf_errstring(ldb,
@@ -1248,9 +1282,11 @@ static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
/*
insert a one level index for a message
*/
-static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_message *msg, int add)
-{
- struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
+static int ltdb_index_onelevel(struct ldb_module *module,
+ const struct ldb_message *msg, int add)
+{
+ struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module),
+ struct ltdb_private);
struct ldb_message_element el;
struct ldb_val val;
struct ldb_dn *pdn;
@@ -1285,7 +1321,7 @@ static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_messa
el.num_values = 1;
if (add) {
- ret = ltdb_index_add1(module, dn, &el, 0, add);
+ ret = ltdb_index_add1(module, dn, &el, 0);
} else { /* delete */
ret = ltdb_index_del_value(module, msg->dn, &el, 0);
}
@@ -1306,10 +1342,10 @@ int ltdb_index_add_element(struct ldb_module *module, struct ldb_dn *dn,
if (ldb_dn_is_special(dn)) {
return LDB_SUCCESS;
}
- if (!ltdb_is_indexed(ltdb->cache->indexlist, el->name)) {
+ if (!ltdb_is_indexed(module, ltdb, el->name)) {
return LDB_SUCCESS;
}
- return ltdb_index_add_el(module, ldb_dn_get_linearized(dn), el, true);
+ return ltdb_index_add_el(module, ldb_dn_get_linearized(dn), el);
}
/*
@@ -1329,8 +1365,7 @@ int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements,
- true);
+ ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1439,7 +1474,7 @@ int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
return LDB_SUCCESS;
}
- if (!ltdb_is_indexed(ltdb->cache->indexlist, el->name)) {
+ if (!ltdb_is_indexed(module, ltdb, el->name)) {
return LDB_SUCCESS;
}
for (i = 0; i < el->num_values; i++) {
@@ -1533,7 +1568,7 @@ struct ltdb_reindex_context {
/*
traversal function that adds @INDEX records during a re index
*/
-static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
+static int re_key(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
{
struct ldb_context *ldb;
struct ltdb_reindex_context *ctx = (struct ltdb_reindex_context *)state;
@@ -1544,17 +1579,22 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
.data = data.dptr,
.length = data.dsize,
};
- const char *dn = NULL;
int ret;
TDB_DATA key2;
-
+ bool is_record;
+
ldb = ldb_module_get_ctx(module);
- if (strncmp((char *)key.dptr, "DN=@", 4) == 0 ||
- strncmp((char *)key.dptr, "DN=", 3) != 0) {
+ if (key.dsize > 4 &&
+ memcmp(key.dptr, "DN=@", 4) == 0) {
return 0;
}
+ is_record = ltdb_key_is_record(key);
+ if (is_record == false) {
+ return 0;
+ }
+
msg = ldb_msg_new(module);
if (msg == NULL) {
return -1;
@@ -1568,10 +1608,21 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
if (ret != 0) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %s\n",
ldb_dn_get_linearized(msg->dn));
+ ctx->error = ret;
talloc_free(msg);
return -1;
}
+ if (msg->dn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Refusing to re-index as GUID "
+ "key %*.*s with no DN\n",
+ (int)key.dsize, (int)key.dsize,
+ (char *)key.dptr);
+ talloc_free(msg);
+ return -1;
+ }
+
/* check if the DN key has changed, perhaps due to the
case insensitivity of an element changing */
key2 = ltdb_key(module, msg->dn);
@@ -1582,14 +1633,98 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
talloc_free(msg);
return 0;
}
- if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) {
- tdb_delete(tdb, key);
- tdb_store(tdb, key2, data, 0);
+ if (key.dsize != key2.dsize ||
+ (memcmp(key.dptr, key2.dptr, key.dsize) != 0)) {
+ int tdb_ret;
+ tdb_ret = tdb_delete(tdb, key);
+ if (tdb_ret != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Failed to delete %*.*s "
+ "for rekey as %*.*s: %s",
+ (int)key.dsize, (int)key.dsize,
+ (const char *)key.dptr,
+ (int)key2.dsize, (int)key2.dsize,
+ (const char *)key.dptr,
+ tdb_errorstr(tdb));
+ ctx->error = ltdb_err_map(tdb_error(tdb));
+ return -1;
+ }
+ tdb_ret = tdb_store(tdb, key2, data, 0);
+ if (tdb_ret != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Failed to rekey %*.*s as %*.*s: %s",
+ (int)key.dsize, (int)key.dsize,
+ (const char *)key.dptr,
+ (int)key2.dsize, (int)key2.dsize,
+ (const char *)key.dptr,
+ tdb_errorstr(tdb));
+ ctx->error = ltdb_err_map(tdb_error(tdb));
+ return -1;
+ }
}
talloc_free(key2.dptr);
+ talloc_free(msg);
+
+ return 0;
+}
+
+/*
+ traversal function that adds @INDEX records during a re index
+*/
+static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct ldb_context *ldb;
+ struct ltdb_reindex_context *ctx = (struct ltdb_reindex_context *)state;
+ struct ldb_module *module = ctx->module;
+ struct ldb_message *msg;
+ const char *dn = NULL;
+ unsigned int nb_elements_in_db;
+ const struct ldb_val val = {
+ .data = data.dptr,
+ .length = data.dsize,
+ };
+ int ret;
+ bool is_record;
+
+ ldb = ldb_module_get_ctx(module);
+
+ if (key.dsize > 4 &&
+ memcmp(key.dptr, "DN=@", 4) == 0) {
+ return 0;
+ }
+
+ is_record = ltdb_key_is_record(key);
+ if (is_record == false) {
+ return 0;
+ }
+
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ return -1;
+ }
+
+ ret = ldb_unpack_data_only_attr_list_flags(ldb, &val,
+ msg,
+ NULL, 0,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC,
+ &nb_elements_in_db);
+ if (ret != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %s\n",
+ ldb_dn_get_linearized(msg->dn));
+ ctx->error = ret;
+ talloc_free(msg);
+ return -1;
+ }
+
if (msg->dn == NULL) {
- dn = (char *)key.dptr + 3;
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Refusing to re-index as GUID "
+ "key %*.*s with no DN\n",
+ (int)key.dsize, (int)key.dsize,
+ (char *)key.dptr);
+ talloc_free(msg);
+ return -1;
} else {
dn = ldb_dn_get_linearized(msg->dn);
}
@@ -1603,8 +1738,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
return -1;
}
- ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements,
- false);
+ ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements);
if (ret != LDB_SUCCESS) {
ctx->error = ret;
@@ -1630,16 +1764,31 @@ int ltdb_reindex(struct ldb_module *module)
return LDB_ERR_OPERATIONS_ERROR;
}
+ /*
+ * Ensure we read (and so remove) the entries from the real
+ * DB, no values stored so far are any use as we want to do a
+ * re-index
+ */
+ ltdb_index_transaction_cancel(module);
+
+ ret = ltdb_index_transaction_start(module);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
/* first traverse the database deleting any @INDEX records by
* putting NULL entries in the in-memory tdb
*/
ret = tdb_traverse(ltdb->tdb, delete_index, module);
if (ret < 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "index deletion traverse failed: %s",
+ ldb_errstring(ldb));
return LDB_ERR_OPERATIONS_ERROR;
}
/* if we don't have indexes we have nothing todo */
- if (ltdb->cache->indexlist->num_elements == 0) {
+ if (!ltdb->cache->attribute_indexes) {
return LDB_SUCCESS;
}
@@ -1647,10 +1796,28 @@ int ltdb_reindex(struct ldb_module *module)
ctx.error = 0;
/* now traverse adding any indexes for normal LDB records */
+ ret = tdb_traverse(ltdb->tdb, re_key, &ctx);
+ if (ret < 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "key correction traverse failed: %s",
+ ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ctx.error != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "reindexing failed: %s", ldb_errstring(ldb));
+ return ctx.error;
+ }
+
+ ctx.error = 0;
+
+ /* now traverse adding any indexes for normal LDB records */
ret = tdb_traverse(ltdb->tdb, re_index, &ctx);
if (ret < 0) {
struct ldb_context *ldb = ldb_module_get_ctx(module);
- ldb_asprintf_errstring(ldb, "reindexing traverse failed: %s", ldb_errstring(ldb));
+ ldb_asprintf_errstring(ldb, "reindexing traverse failed: %s",
+ ldb_errstring(ldb));
return LDB_ERR_OPERATIONS_ERROR;
}
diff --git a/ldb_tdb/ldb_search.c b/ldb_tdb/ldb_search.c
index 373855f..a6c408a 100644
--- a/ldb_tdb/ldb_search.c
+++ b/ldb_tdb/ldb_search.c
@@ -109,102 +109,6 @@ static int msg_add_distinguished_name(struct ldb_message *msg)
}
/*
- add all elements from one message into another
- */
-static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
- const struct ldb_message *msg)
-{
- struct ldb_context *ldb;
- unsigned int i;
- int check_duplicates = (ret->num_elements != 0);
-
- ldb = ldb_module_get_ctx(module);
-
- if (msg_add_distinguished_name(ret) != 0) {
- return -1;
- }
-
- for (i=0;i<msg->num_elements;i++) {
- const struct ldb_schema_attribute *a;
- a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
- if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
- continue;
- }
- if (msg_add_element(ret, &msg->elements[i],
- check_duplicates) != 0) {
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/*
- pull the specified list of attributes from a message
- */
-static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
- TALLOC_CTX *mem_ctx,
- const struct ldb_message *msg,
- const char * const *attrs)
-{
- struct ldb_message *ret;
- unsigned int i;
-
- ret = talloc(mem_ctx, struct ldb_message);
- if (!ret) {
- return NULL;
- }
-
- ret->dn = ldb_dn_copy(ret, msg->dn);
- if (!ret->dn) {
- talloc_free(ret);
- return NULL;
- }
-
- ret->num_elements = 0;
- ret->elements = NULL;
-
- if (!attrs) {
- if (msg_add_all_elements(module, ret, msg) != 0) {
- talloc_free(ret);
- return NULL;
- }
- return ret;
- }
-
- for (i=0;attrs[i];i++) {
- struct ldb_message_element *el;
-
- if (strcmp(attrs[i], "*") == 0) {
- if (msg_add_all_elements(module, ret, msg) != 0) {
- talloc_free(ret);
- return NULL;
- }
- continue;
- }
-
- if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
- if (msg_add_distinguished_name(ret) != 0) {
- return NULL;
- }
- continue;
- }
-
- el = ldb_msg_find_element(msg, attrs[i]);
- if (!el) {
- continue;
- }
- if (msg_add_element(ret, el, 1) != 0) {
- talloc_free(ret);
- return NULL;
- }
- }
-
- return ret;
-}
-
-/*
search the database for a single simple dn.
return LDB_ERR_NO_SUCH_OBJECT on record-not-found
and LDB_SUCCESS on success
@@ -346,44 +250,6 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
}
/*
- add a set of attributes from a record to a set of results
- return 0 on success, -1 on failure
-*/
-int ltdb_add_attr_results(struct ldb_module *module,
- TALLOC_CTX *mem_ctx,
- struct ldb_message *msg,
- const char * const attrs[],
- unsigned int *count,
- struct ldb_message ***res)
-{
- struct ldb_message *msg2;
- struct ldb_message **res2;
-
- /* pull the attributes that the user wants */
- msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
- if (!msg2) {
- return -1;
- }
-
- /* add to the results list */
- res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
- if (!res2) {
- talloc_free(msg2);
- return -1;
- }
-
- (*res) = res2;
-
- (*res)[*count] = talloc_move(*res, &msg2);
- (*res)[(*count)+1] = NULL;
- (*count)++;
-
- return 0;
-}
-
-
-
-/*
filter the specified list of attributes from a message
removing not requested attrs from the new message constructed.
@@ -544,8 +410,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
ac = talloc_get_type(state, struct ltdb_context);
ldb = ldb_module_get_ctx(ac->module);
- if (key.dsize < 4 ||
- strncmp((char *)key.dptr, "DN=", 3) != 0) {
+ if (ltdb_key_is_record(key) == false) {
return 0;
}
diff --git a/ldb_tdb/ldb_tdb.c b/ldb_tdb/ldb_tdb.c
index 7cc0a2e..ccad816 100644
--- a/ldb_tdb/ldb_tdb.c
+++ b/ldb_tdb/ldb_tdb.c
@@ -119,6 +119,7 @@ int ltdb_unlock_read(struct ldb_module *module)
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
if (ltdb->in_transaction == 0 && ltdb->read_lock_count == 1) {
tdb_unlockall_read(ltdb->tdb);
+ ltdb->read_lock_count--;
return 0;
}
ltdb->read_lock_count--;
@@ -126,6 +127,35 @@ int ltdb_unlock_read(struct ldb_module *module)
}
+/*
+ * Determine if this key could hold a record. We allow the new GUID
+ * index, the old DN index and a possible future ID=
+ */
+bool ltdb_key_is_record(TDB_DATA key)
+{
+ if (key.dsize < 4) {
+ return false;
+ }
+
+ if (memcmp(key.dptr, "DN=", 3) == 0) {
+ return true;
+ }
+
+ if (memcmp(key.dptr, "ID=", 3) == 0) {
+ return true;
+ }
+
+ if (key.dsize < 6) {
+ return false;
+ }
+
+ if (memcmp(key.dptr, "GUID=", 5) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
/*
form a TDB_DATA for a record key
caller frees
@@ -330,7 +360,7 @@ static int ltdb_add_internal(struct ldb_module *module,
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
int ret = LDB_SUCCESS;
- unsigned int i, j;
+ unsigned int i;
for (i=0;i<msg->num_elements;i++) {
struct ldb_message_element *el = &msg->elements[i];
@@ -355,12 +385,25 @@ static int ltdb_add_internal(struct ldb_module *module,
continue;
}
- /* TODO: This is O(n^2) - replace with more efficient check */
- for (j=0; j<el->num_values; j++) {
- if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
- ldb_asprintf_errstring(ldb,
- "attribute '%s': value #%u on '%s' provided more than once",
- el->name, j, ldb_dn_get_linearized(msg->dn));
+ if (check_single_value &&
+ !(el->flags &
+ LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
+ struct ldb_val *duplicate = NULL;
+
+ ret = ldb_msg_find_duplicate_val(ldb, discard_const(msg),
+ el, &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value '%.*s' on '%s' "
+ "provided more than once in ADD object",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg->dn));
return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
}
}
@@ -522,8 +565,7 @@ static int find_element(const struct ldb_message *msg, const char *name)
returns 0 on success, -1 on failure (and sets errno)
*/
-static int ltdb_msg_add_element(struct ldb_context *ldb,
- struct ldb_message *msg,
+static int ltdb_msg_add_element(struct ldb_message *msg,
struct ldb_message_element *el)
{
struct ldb_message_element *e2;
@@ -567,7 +609,6 @@ static int ltdb_msg_add_element(struct ldb_context *ldb,
delete all elements having a specified attribute name
*/
static int msg_delete_attribute(struct ldb_module *module,
- struct ldb_context *ldb,
struct ldb_message *msg, const char *name)
{
unsigned int i;
@@ -634,7 +675,7 @@ static int msg_delete_element(struct ldb_module *module,
}
if (matched) {
if (el->num_values == 1) {
- return msg_delete_attribute(module, ldb, msg, name);
+ return msg_delete_attribute(module, msg, name);
}
ret = ltdb_index_del_value(module, msg->dn, el, i);
@@ -674,57 +715,43 @@ int ltdb_modify_internal(struct ldb_module *module,
struct ldb_request *req)
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
- void *data = ldb_module_get_private(module);
- struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- TDB_DATA tdb_key, tdb_data;
- struct ldb_val ldb_data;
struct ldb_message *msg2;
- unsigned int i, j, k;
+ unsigned int i, j;
int ret = LDB_SUCCESS, idx;
struct ldb_control *control_permissive = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(req);
+ if (mem_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
if (req) {
control_permissive = ldb_request_get_control(req,
LDB_CONTROL_PERMISSIVE_MODIFY_OID);
}
- tdb_key = ltdb_key(module, msg->dn);
- if (!tdb_key.dptr) {
- return LDB_ERR_OTHER;
- }
-
- tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
- if (!tdb_data.dptr) {
- talloc_free(tdb_key.dptr);
- return ltdb_err_map(tdb_error(ltdb->tdb));
- }
-
- msg2 = ldb_msg_new(tdb_key.dptr);
+ msg2 = ldb_msg_new(mem_ctx);
if (msg2 == NULL) {
- free(tdb_data.dptr);
ret = LDB_ERR_OTHER;
goto done;
}
- ldb_data.data = tdb_data.dptr;
- ldb_data.length = tdb_data.dsize;
-
- ret = ldb_unpack_data(ldb_module_get_ctx(module), &ldb_data, msg2);
- free(tdb_data.dptr);
- if (ret == -1) {
- ret = LDB_ERR_OTHER;
+ ret = ltdb_search_dn1(module, msg->dn,
+ msg2,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC);
+ if (ret != LDB_SUCCESS) {
goto done;
}
- if (!msg2->dn) {
- msg2->dn = msg->dn;
- }
-
for (i=0; i<msg->num_elements; i++) {
struct ldb_message_element *el = &msg->elements[i], *el2;
struct ldb_val *vals;
const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
const char *dn;
+ uint32_t options = 0;
+ if (control_permissive != NULL) {
+ options |= LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+ }
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
@@ -769,7 +796,7 @@ int ltdb_modify_internal(struct ldb_module *module,
/* Checks if element already exists */
idx = find_element(msg2, el->name);
if (idx == -1) {
- if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
+ if (ltdb_msg_add_element(msg2, el) != 0) {
ret = LDB_ERR_OTHER;
goto done;
}
@@ -793,30 +820,43 @@ int ltdb_modify_internal(struct ldb_module *module,
/* Check that values don't exist yet on multi-
valued attributes or aren't provided twice */
- /* TODO: This is O(n^2) - replace with more efficient check */
- for (j = 0; j < el->num_values; j++) {
- if (ldb_msg_find_val(el2, &el->values[j]) != NULL) {
- if (control_permissive) {
- /* remove this one as if it was never added */
- el->num_values--;
- for (k = j; k < el->num_values; k++) {
- el->values[k] = el->values[k + 1];
- }
- j--; /* rewind */
-
- continue;
- }
-
+ if (!(el->flags &
+ LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
+ struct ldb_val *duplicate = NULL;
+ ret = ldb_msg_find_common_values(ldb,
+ msg2,
+ el,
+ el2,
+ options);
+
+ if (ret ==
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
ldb_asprintf_errstring(ldb,
- "attribute '%s': value #%u on '%s' already exists",
- el->name, j, ldb_dn_get_linearized(msg2->dn));
- ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ "attribute '%s': value "
+ "#%u on '%s' already "
+ "exists", el->name, j,
+ ldb_dn_get_linearized(msg2->dn));
+ goto done;
+ } else if (ret != LDB_SUCCESS) {
goto done;
}
- if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
- ldb_asprintf_errstring(ldb,
- "attribute '%s': value #%u on '%s' provided more than once",
- el->name, j, ldb_dn_get_linearized(msg2->dn));
+
+ ret = ldb_msg_find_duplicate_val(
+ ldb, msg2, el, &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value "
+ "'%.*s' on '%s' "
+ "provided more than "
+ "once in ADD",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg->dn));
ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
goto done;
}
@@ -864,16 +904,26 @@ int ltdb_modify_internal(struct ldb_module *module,
* in Samba, or someone else who can claim to
* know what they are doing.
*/
- if (!(el->flags & LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
- /* TODO: This is O(n^2) - replace with more efficient check */
- for (j=0; j<el->num_values; j++) {
- if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
- ldb_asprintf_errstring(ldb,
- "attribute '%s': value #%u on '%s' provided more than once",
- el->name, j, ldb_dn_get_linearized(msg2->dn));
- ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- goto done;
- }
+ if (!(el->flags & LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
+ struct ldb_val *duplicate = NULL;
+
+ ret = ldb_msg_find_duplicate_val(ldb, msg2, el,
+ &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value '%.*s' "
+ "on '%s' provided more than "
+ "once in REPLACE",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg2->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
}
}
@@ -895,7 +945,7 @@ int ltdb_modify_internal(struct ldb_module *module,
}
/* Delete the attribute if it exists in the DB */
- if (msg_delete_attribute(module, ldb, msg2,
+ if (msg_delete_attribute(module, msg2,
el->name) != 0) {
ret = LDB_ERR_OTHER;
goto done;
@@ -903,7 +953,7 @@ int ltdb_modify_internal(struct ldb_module *module,
}
/* Recreate it with the new values */
- if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
+ if (ltdb_msg_add_element(msg2, el) != 0) {
ret = LDB_ERR_OTHER;
goto done;
}
@@ -924,7 +974,7 @@ int ltdb_modify_internal(struct ldb_module *module,
if (msg->elements[i].num_values == 0) {
/* Delete the whole attribute */
- ret = msg_delete_attribute(module, ldb, msg2,
+ ret = msg_delete_attribute(module, msg2,
msg->elements[i].name);
if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
control_permissive) {
@@ -947,7 +997,7 @@ int ltdb_modify_internal(struct ldb_module *module,
if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
control_permissive) {
ret = LDB_SUCCESS;
- } else {
+ } else if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
ldb_asprintf_errstring(ldb,
"attribute '%s': no matching attribute value while deleting attribute on '%s'",
msg->elements[i].name, dn);
@@ -979,7 +1029,7 @@ int ltdb_modify_internal(struct ldb_module *module,
}
done:
- talloc_free(tdb_key.dptr);
+ TALLOC_FREE(mem_ctx);
return ret;
}
@@ -1117,6 +1167,7 @@ static int ltdb_start_trans(struct ldb_module *module)
static int ltdb_prepare_commit(struct ldb_module *module)
{
+ int ret;
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
@@ -1124,15 +1175,21 @@ static int ltdb_prepare_commit(struct ldb_module *module)
return LDB_SUCCESS;
}
- if (ltdb_index_transaction_commit(module) != 0) {
+ ret = ltdb_index_transaction_commit(module);
+ if (ret != LDB_SUCCESS) {
tdb_transaction_cancel(ltdb->tdb);
ltdb->in_transaction--;
- return ltdb_err_map(tdb_error(ltdb->tdb));
+ return ret;
}
if (tdb_transaction_prepare_commit(ltdb->tdb) != 0) {
+ ret = ltdb_err_map(tdb_error(ltdb->tdb));
ltdb->in_transaction--;
- return ltdb_err_map(tdb_error(ltdb->tdb));
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Failure during tdb_transaction_prepare_commit(): %s -> %s",
+ tdb_errorstr(ltdb->tdb),
+ ldb_strerror(ret));
+ return ret;
}
ltdb->prepared_commit = true;
@@ -1142,11 +1199,12 @@ static int ltdb_prepare_commit(struct ldb_module *module)
static int ltdb_end_trans(struct ldb_module *module)
{
+ int ret;
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
if (!ltdb->prepared_commit) {
- int ret = ltdb_prepare_commit(module);
+ ret = ltdb_prepare_commit(module);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1156,7 +1214,12 @@ static int ltdb_end_trans(struct ldb_module *module)
ltdb->prepared_commit = false;
if (tdb_transaction_commit(ltdb->tdb) != 0) {
- return ltdb_err_map(tdb_error(ltdb->tdb));
+ ret = ltdb_err_map(tdb_error(ltdb->tdb));
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Failure during tdb_transaction_commit(): %s -> %s",
+ tdb_errorstr(ltdb->tdb),
+ ldb_strerror(ret));
+ return ret;
}
return LDB_SUCCESS;
@@ -1459,7 +1522,7 @@ static int ltdb_handle_request(struct ldb_module *module,
return LDB_ERR_TIME_LIMIT_EXCEEDED;
}
- ev = ldb_get_event_context(ldb);
+ ev = ldb_handle_get_event_context(req->handle);
ac = talloc_zero(ldb, struct ltdb_context);
if (ac == NULL) {
@@ -1525,6 +1588,8 @@ static const struct ldb_module_ops ltdb_ops = {
.end_transaction = ltdb_end_trans,
.prepare_commit = ltdb_prepare_commit,
.del_transaction = ltdb_del_trans,
+ .read_lock = ltdb_lock_read,
+ .read_unlock = ltdb_unlock_read,
};
/*
@@ -1539,6 +1604,13 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url,
int tdb_flags, open_flags;
struct ltdb_private *ltdb;
+ /*
+ * We hold locks, so we must use a private event context
+ * on each returned handle
+ */
+
+ ldb_set_require_private_event_context(ldb);
+
/* parse the url */
if (strchr(url, ':')) {
if (strncmp(url, "tdb://", 6) != 0) {
@@ -1565,6 +1637,8 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url,
if (flags & LDB_FLG_RDONLY) {
open_flags = O_RDONLY;
+ } else if (flags & LDB_FLG_DONT_CREATE_DB) {
+ open_flags = O_RDWR;
} else {
open_flags = O_CREAT | O_RDWR;
}
diff --git a/ldb_tdb/ldb_tdb.h b/ldb_tdb/ldb_tdb.h
index 7caedeb..a391606 100644
--- a/ldb_tdb/ldb_tdb.h
+++ b/ldb_tdb/ldb_tdb.h
@@ -102,12 +102,6 @@ int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
unsigned int unpack_flags);
-int ltdb_add_attr_results(struct ldb_module *module,
- TALLOC_CTX *mem_ctx,
- struct ldb_message *msg,
- const char * const attrs[],
- unsigned int *count,
- struct ldb_message ***res);
int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg, const char * const *attrs,
struct ldb_message **filtered_msg);
@@ -116,6 +110,11 @@ int ltdb_search(struct ltdb_context *ctx);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */
int ltdb_lock_read(struct ldb_module *module);
int ltdb_unlock_read(struct ldb_module *module);
+/*
+ * Determine if this key could hold a record. We allow the new GUID
+ * index, the old DN index and a possible future ID=
+ */
+bool ltdb_key_is_record(TDB_DATA key);
TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn);
int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req);
diff --git a/lib/replace/getifaddrs.c b/lib/replace/getifaddrs.c
index c2d20f8..9e377e5 100644
--- a/lib/replace/getifaddrs.c
+++ b/lib/replace/getifaddrs.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Andrew Tridgell 1998
@@ -94,17 +94,17 @@ int rep_getifaddrs(struct ifaddrs **ifap)
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
-
+
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return -1;
- }
+ }
ifr = ifc.ifc_req;
-
+
n = ifc.ifc_len / sizeof(struct ifreq);
/* Loop through interfaces, looking for given IP address */
@@ -171,7 +171,7 @@ int rep_getifaddrs(struct ifaddrs **ifap)
close(fd);
return 0;
-}
+}
#define _FOUND_IFACE_ANY
#endif /* HAVE_IFACE_IFCONF */
@@ -200,14 +200,14 @@ int rep_getifaddrs(struct ifaddrs **ifap)
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
-
+
strioctl.ic_cmd = SIOCGIFCONF;
strioctl.ic_dp = buff;
strioctl.ic_len = sizeof(buff);
if (ioctl(fd, I_STR, &strioctl) < 0) {
close(fd);
return -1;
- }
+ }
/* we can ignore the possible sizeof(int) here as the resulting
number of interface structures won't change */
@@ -217,16 +217,16 @@ int rep_getifaddrs(struct ifaddrs **ifap)
at the start of the buffer if the offered size is a
multiple of the structure size plus an int */
if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
- ifr = (struct ifreq *)(buff + sizeof(int));
+ ifr = (struct ifreq *)(buff + sizeof(int));
} else {
- ifr = (struct ifreq *)buff;
+ ifr = (struct ifreq *)buff;
}
/* Loop through interfaces */
for (i = 0; i<n; i++) {
ifreq = ifr[i];
-
+
curif = calloc(1, sizeof(struct ifaddrs));
if (lastif == NULL) {
*ifap = curif;
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
index b5d7f11..9351b6c 100644
--- a/lib/replace/replace.c
+++ b/lib/replace/replace.c
@@ -820,6 +820,24 @@ int rep_strerror_r(int errnum, char *buf, size_t buflen)
strncpy(buf, s, buflen);
return 0;
}
+#elif (!defined(STRERROR_R_XSI_NOT_GNU))
+#undef strerror_r
+int rep_strerror_r(int errnum, char *buf, size_t buflen)
+{
+ char *s = strerror_r(errnum, buf, buflen);
+ if (s == NULL) {
+ /* Shouldn't happen, should always get a string */
+ return EINVAL;
+ }
+ if (s != buf) {
+ strlcpy(buf, s, buflen);
+ if (strlen(s) > buflen - 1) {
+ return ERANGE;
+ }
+ }
+ return 0;
+
+}
#endif
#ifndef HAVE_CLOCK_GETTIME
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
index c69a069..a41e9f8 100644
--- a/lib/replace/replace.h
+++ b/lib/replace/replace.h
@@ -171,6 +171,10 @@
#include <sys/types.h>
#endif
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
+
#ifdef HAVE_SETPROCTITLE_H
#include <setproctitle.h>
#endif
@@ -624,7 +628,7 @@ ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
char *rep_get_current_dir_name(void);
#endif
-#ifndef HAVE_STRERROR_R
+#if (!defined(HAVE_STRERROR_R) || !defined(STRERROR_R_XSI_NOT_GNU))
#define strerror_r rep_strerror_r
int rep_strerror_r(int errnum, char *buf, size_t buflen);
#endif
diff --git a/lib/replace/snprintf.c b/lib/replace/snprintf.c
index 63eb036..2cd9c43 100644
--- a/lib/replace/snprintf.c
+++ b/lib/replace/snprintf.c
@@ -34,7 +34,7 @@
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
- * which showed it, so that's been fixed. Also, formated the code
+ * which showed it, so that's been fixed. Also, formatted the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
diff --git a/lib/replace/system/dir.h b/lib/replace/system/dir.h
index dec2d54..0955b19 100644
--- a/lib/replace/system/dir.h
+++ b/lib/replace/system/dir.h
@@ -46,6 +46,10 @@
#define mkdir(dir, mode) mkdir(dir)
#endif
+#if HAVE_LIBGEN_H
+# include <libgen.h>
+#endif
+
/* Test whether a file name is the "." or ".." directory entries.
* These really should be inline functions.
*/
diff --git a/lib/replace/system/network.h b/lib/replace/system/network.h
index 4a3fd07..8254551 100644
--- a/lib/replace/system/network.h
+++ b/lib/replace/system/network.h
@@ -365,4 +365,8 @@ struct addrinfo {
#endif /* HAVE_LINUX_IPV6_V6ONLY_26 */
#endif /* HAVE_IPV6 */
+#ifndef SCOPE_DELIMITER
+#define SCOPE_DELIMITER '%'
+#endif
+
#endif
diff --git a/lib/replace/system/time.h b/lib/replace/system/time.h
index b6d2609..00f0d7f 100644
--- a/lib/replace/system/time.h
+++ b/lib/replace/system/time.h
@@ -79,13 +79,21 @@ int rep_utimes(const char *filename, const struct timeval tv[2]);
typedef int clockid_t;
int rep_clock_gettime(clockid_t clk_id, struct timespec *tp);
#endif
-/* make sure we have a best effort CUSTOM_CLOCK_MONOTONIC we can rely on */
+/* make sure we have a best effort CUSTOM_CLOCK_MONOTONIC we can rely on.
+ *
+ * on AIX the values of CLOCK_* are cast expressions, not integer constants,
+ * this prevents them from being compared against in a preprocessor directive.
+ * The following ...IS_* macros can be used to check which clock is in use.
+ */
#if defined(CLOCK_MONOTONIC)
#define CUSTOM_CLOCK_MONOTONIC CLOCK_MONOTONIC
+#define CUSTOM_CLOCK_MONOTONIC_IS_MONOTONIC
#elif defined(CLOCK_HIGHRES)
#define CUSTOM_CLOCK_MONOTONIC CLOCK_HIGHRES
+#define CUSTOM_CLOCK_MONOTONIC_IS_HIGHRES
#else
#define CUSTOM_CLOCK_MONOTONIC CLOCK_REALTIME
+#define CUSTOM_CLOCK_MONOTONIC_IS_REALTIME
#endif
#endif
diff --git a/lib/replace/test/os2_delete.c b/lib/replace/test/os2_delete.c
index 0816f61..4b99ccf 100644
--- a/lib/replace/test/os2_delete.c
+++ b/lib/replace/test/os2_delete.c
@@ -63,7 +63,7 @@ static int os2_delete(DIR *d)
off_t offsets[READDIR_SIZE];
int i, j;
struct dirent *de;
- char names[READDIR_SIZE][30];
+ char names[READDIR_SIZE][256];
/* scan, remembering offsets */
for (i=0, de=readdir(d);
diff --git a/lib/replace/test/shared_mmap.c b/lib/replace/test/shared_mmap.c
index 50dad8d..9d6e3fc 100644
--- a/lib/replace/test/shared_mmap.c
+++ b/lib/replace/test/shared_mmap.c
@@ -4,6 +4,9 @@
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -15,7 +18,7 @@
#define MAP_FILE 0
#endif
-main()
+int main(void)
{
int *buf;
int i;
diff --git a/lib/replace/test/shared_mremap.c b/lib/replace/test/shared_mremap.c
index 05032ad..08040e2 100644
--- a/lib/replace/test/shared_mremap.c
+++ b/lib/replace/test/shared_mremap.c
@@ -3,6 +3,9 @@
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -18,7 +21,7 @@
#define MAP_FAILED (int *)-1
#endif
-main()
+int main(void)
{
int *buf;
int fd;
diff --git a/lib/replace/test/snprintf.c b/lib/replace/test/snprintf.c
index d06630b..77473f0 100644
--- a/lib/replace/test/snprintf.c
+++ b/lib/replace/test/snprintf.c
@@ -26,4 +26,4 @@ void foo(const char *format, ...)
printf("1");
exit(0);
}
-main() { foo("hello"); }
+int main(void) { foo("hello"); }
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 1dfd902..6972f2d 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -81,6 +81,9 @@ def configure(conf):
conf.CHECK_HEADERS('sys/atomic.h')
conf.CHECK_HEADERS('libgen.h')
+ if conf.CHECK_CFLAGS('-Wno-format-truncation'):
+ conf.define('HAVE_WNO_FORMAT_TRUNCATION', '1')
+
# Check for process set name support
conf.CHECK_CODE('''
#include <sys/prctl.h>
@@ -189,7 +192,7 @@ def configure(conf):
''',
define='HAVE_IPV6',
lib='nsl socket',
- headers='sys/socket.h netdb.h netinet/in.h')
+ headers='sys/socket.h netdb.h netinet/in.h net/if.h')
if conf.CONFIG_SET('HAVE_SYS_UCONTEXT_H') and conf.CONFIG_SET('HAVE_SIGNAL_H'):
conf.CHECK_CODE('''
@@ -246,6 +249,18 @@ def configure(conf):
if conf.CONFIG_SET('HAVE_MEMALIGN'):
conf.CHECK_DECLS('memalign', headers='malloc.h')
+ # glibc up to 2.3.6 had dangerously broken posix_fallocate(). DON'T USE IT.
+ if conf.CHECK_CODE('''
+#define _XOPEN_SOURCE 600
+#include <stdlib.h>
+#if defined(__GLIBC__) && ((__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 4))
+#error probably broken posix_fallocate
+#endif
+''',
+ '_POSIX_FALLOCATE_CAPABLE_LIBC',
+ msg='Checking for posix_fallocate-capable libc'):
+ conf.CHECK_FUNCS('posix_fallocate')
+
conf.CHECK_FUNCS('prctl dirname basename')
# libbsd on some platforms provides strlcpy and strlcat
@@ -376,7 +391,7 @@ removeea setea
if conf.CHECK_FUNCS_IN('dgettext gettext', '', checklibc=True, headers='libintl.h'):
# save for dependency definitions
conf.env.intl_libs=''
- # others (e.g. FreeBSD) have seperate libintl
+ # others (e.g. FreeBSD) have separate libintl
elif conf.CHECK_FUNCS_IN('dgettext gettext', 'intl', checklibc=False, headers='libintl.h'):
# save for dependency definitions
conf.env.intl_libs='intl'
@@ -466,6 +481,7 @@ removeea setea
conf.DEFINE('HAVE_ROBUST_MUTEXES', 1)
conf.CHECK_FUNCS_IN('crypt', 'crypt', checklibc=True)
+ conf.CHECK_FUNCS_IN('crypt_r', 'crypt', checklibc=True)
conf.CHECK_VARIABLE('rl_event_hook', define='HAVE_DECL_RL_EVENT_HOOK', always=True,
headers='readline.h readline/readline.h readline/history.h')
@@ -626,6 +642,13 @@ removeea setea
conf.RECURSE('system')
conf.SAMBA_CONFIG_H()
+ if conf.CHECK_FUNCS('strerror_r'):
+ # Check if strerror_r is XSI-Compatable, the default GNU implementation
+ # is not
+ conf.CHECK_CODE('int strerror_r(int errnum, char *buf, size_t buflen);',
+ 'STRERROR_R_XSI_NOT_GNU',
+ headers='string.h', addmain=False, link=False,
+ msg="Checking for XSI (rather than GNU) prototype for strerror_r")
REPLACEMENT_FUNCTIONS = {
@@ -703,10 +726,14 @@ def build(bld):
private_library=True,
deps='crypt dl nsl socket rt attr' + extra_libs)
+ replace_test_cflags="-Wno-format-zero-length"
+ if bld.CONFIG_SET('HAVE_WNO_FORMAT_TRUNCATION'):
+ replace_test_cflags += " -Wno-format-truncation"
bld.SAMBA_SUBSYSTEM('replace-test',
- source='''test/testsuite.c test/strptime.c
- test/os2_delete.c test/getifaddrs.c''',
- deps='replace')
+ source='''test/testsuite.c test/strptime.c
+ test/os2_delete.c test/getifaddrs.c''',
+ deps='replace',
+ cflags=replace_test_cflags)
if bld.env.standalone_replace:
bld.SAMBA_BINARY('replace_testsuite',
diff --git a/lib/replace/xattr.c b/lib/replace/xattr.c
index ce52d1a..2479c21 100644
--- a/lib/replace/xattr.c
+++ b/lib/replace/xattr.c
@@ -61,11 +61,21 @@ ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t si
#elif defined(HAVE_GETEA)
return getea(path, name, value, size);
#elif defined(HAVE_EXTATTR_GET_FILE)
- char *s;
ssize_t retval;
- int attrnamespace = (strncmp(name, "system", 6) == 0) ?
- EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
- const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
/*
* The BSD implementation has a nasty habit of silently truncating
* the returned value to the size of the buffer, so we have to check
@@ -125,11 +135,20 @@ ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
#elif defined(HAVE_FGETEA)
return fgetea(filedes, name, value, size);
#elif defined(HAVE_EXTATTR_GET_FD)
- char *s;
ssize_t retval;
- int attrnamespace = (strncmp(name, "system", 6) == 0) ?
- EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
- const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
if (size == 0) {
@@ -414,10 +433,19 @@ int rep_removexattr (const char *path, const char *name)
#elif defined(HAVE_REMOVEEA)
return removeea(path, name);
#elif defined(HAVE_EXTATTR_DELETE_FILE)
- char *s;
- int attrnamespace = (strncmp(name, "system", 6) == 0) ?
- EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
- const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
return extattr_delete_file(path, attrnamespace, attrname);
#elif defined(HAVE_ATTR_REMOVE)
@@ -455,10 +483,19 @@ int rep_fremovexattr (int filedes, const char *name)
#elif defined(HAVE_FREMOVEEA)
return fremoveea(filedes, name);
#elif defined(HAVE_EXTATTR_DELETE_FD)
- char *s;
- int attrnamespace = (strncmp(name, "system", 6) == 0) ?
- EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
- const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
return extattr_delete_fd(filedes, attrnamespace, attrname);
#elif defined(HAVE_ATTR_REMOVEF)
@@ -496,11 +533,21 @@ int rep_setxattr (const char *path, const char *name, const void *value, size_t
#elif defined(HAVE_SETEA)
return setea(path, name, value, size, flags);
#elif defined(HAVE_EXTATTR_SET_FILE)
- char *s;
int retval = 0;
- int attrnamespace = (strncmp(name, "system", 6) == 0) ?
- EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
- const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
if (flags) {
/* Check attribute existence */
retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
@@ -563,11 +610,21 @@ int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size
#elif defined(HAVE_FSETEA)
return fsetea(filedes, name, value, size, flags);
#elif defined(HAVE_EXTATTR_SET_FD)
- char *s;
int retval = 0;
- int attrnamespace = (strncmp(name, "system", 6) == 0) ?
- EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
- const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
if (flags) {
/* Check attribute existence */
retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.10.sigs b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.9.sigs b/lib/talloc/ABI/pytalloc-util-2.1.9.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.9.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs b/lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs
new file mode 100644
index 0000000..62f066f
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util.py3-2.1.10.sigs
@@ -0,0 +1,15 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util.py3-2.1.9.sigs b/lib/talloc/ABI/pytalloc-util.py3-2.1.9.sigs
new file mode 100644
index 0000000..62f066f
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util.py3-2.1.9.sigs
@@ -0,0 +1,15 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/talloc-2.1.10.sigs b/lib/talloc/ABI/talloc-2.1.10.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.10.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.9.sigs b/lib/talloc/ABI/talloc-2.1.9.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.9.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/pytalloc-util.pc.in b/lib/talloc/pytalloc-util.pc.in
index b87c94e..06f83e2 100644
--- a/lib/talloc/pytalloc-util.pc.in
+++ b/lib/talloc/pytalloc-util.pc.in
@@ -3,9 +3,9 @@ exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
-Name: pytalloc-util
+Name: pytalloc-util@PYTHON_SO_ABI_FLAG@
Description: Utility functions for using talloc objects with Python
Version: @TALLOC_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util@PYTHON_SO_ABI_FLAG@
+Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util@PYTHON_LIBNAME_SO_ABI_FLAG@
Cflags: -I${includedir}
URL: http://talloc.samba.org/
diff --git a/lib/talloc/pytalloc.c b/lib/talloc/pytalloc.c
index 2039528..3532fdf 100644
--- a/lib/talloc/pytalloc.c
+++ b/lib/talloc/pytalloc.c
@@ -238,6 +238,14 @@ static PyTypeObject TallocBaseObject_Type = {
#endif
};
+static PyTypeObject TallocGenericObject_Type = {
+ .tp_name = "talloc.GenericObject",
+ .tp_doc = "Python wrapper for a talloc-maintained object.",
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_base = &TallocBaseObject_Type,
+ .tp_basicsize = sizeof(pytalloc_BaseObject),
+};
+
#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
#if PY_MAJOR_VERSION >= 3
@@ -261,6 +269,9 @@ static PyObject *module_init(void)
if (PyType_Ready(&TallocBaseObject_Type) < 0)
return NULL;
+ if (PyType_Ready(&TallocGenericObject_Type) < 0)
+ return NULL;
+
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
@@ -273,6 +284,8 @@ static PyObject *module_init(void)
PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
Py_INCREF(&TallocBaseObject_Type);
PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type);
+ Py_INCREF(&TallocGenericObject_Type);
+ PyModule_AddObject(m, "GenericObject", (PyObject *)&TallocGenericObject_Type);
return m;
}
diff --git a/lib/talloc/pytalloc.h b/lib/talloc/pytalloc.h
index 6a0ac18..11653bf 100644
--- a/lib/talloc/pytalloc.h
+++ b/lib/talloc/pytalloc.h
@@ -40,6 +40,10 @@ int pytalloc_Check(PyObject *);
int pytalloc_BaseObject_check(PyObject *);
+int _pytalloc_check_type(PyObject *py_obj, const char *type_name);
+#define pytalloc_check_type(py_obj, type) \
+ _pytalloc_check_type((PyObject *)(py_obj), #type)
+
/* Retrieve the pointer for a pytalloc_object. Like talloc_get_type()
* but for pytalloc_Objects. */
void *_pytalloc_get_type(PyObject *py_obj, const char *type_name);
@@ -58,8 +62,30 @@ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void
#define pytalloc_new(type, typeobj) pytalloc_steal(typeobj, talloc_zero(NULL, type))
#if PY_MAJOR_VERSION < 3
-PyObject *pytalloc_CObject_FromTallocPtr(void *);
+/*
+ * Don't use this anymore! Use pytalloc_GenericObject_steal()
+ * or pytalloc_GenericObject_reference().
+ */
+#ifndef _DEPRECATED_
+#ifdef HAVE___ATTRIBUTE__
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
#endif
+PyObject *pytalloc_CObject_FromTallocPtr(void *) _DEPRECATED_;
+#endif
+
+/*
+ * Wrap a generic talloc pointer into a talloc.GenericObject,
+ * this is a subclass of talloc.BaseObject.
+ */
+PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr);
+#define pytalloc_GenericObject_steal(talloc_ptr) \
+ pytalloc_GenericObject_steal_ex(talloc_ptr, talloc_ptr)
+PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr);
+#define pytalloc_GenericObject_reference(talloc_ptr) \
+ pytalloc_GenericObject_reference_ex(talloc_ptr, talloc_ptr)
size_t pytalloc_BaseObject_size(void);
diff --git a/lib/talloc/pytalloc_guide.txt b/lib/talloc/pytalloc_guide.txt
index 962d449..bd2b68c 100644
--- a/lib/talloc/pytalloc_guide.txt
+++ b/lib/talloc/pytalloc_guide.txt
@@ -92,6 +92,15 @@ Check whether a specific object is a talloc BaseObject. Returns non-zero if it i
a pytalloc_BaseObject and zero otherwise.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_check_type(PyObject *py_obj, type)
+
+Check if the object based on `pytalloc_*Object` py_obj. type should be a
+C type, similar to a type passed to `talloc_get_type`.
+This can be used as a check before using pytalloc_get_type()
+or an alternative codepath. Returns non-zero if it is
+an object of the expected type and zero otherwise.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
type *pytalloc_get_type(PyObject *py_obj, type)
Retrieve the pointer from a `pytalloc_Object` py_obj. type should be a
@@ -113,7 +122,9 @@ Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseOb
PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
Create a new Python wrapping object for a talloc pointer and context, with
-py_type as associated Python sub type object.
+py_type as associated Python sub type object. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
This will *not* increment the reference counter for the talloc context,
so the caller should make sure such an increment has happened. When the Python
@@ -123,7 +134,9 @@ object goes away, it will unreference the talloc context.
PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
Create a new Python wrapping object for a talloc pointer and context, with
-py_type as associated Python sub type object.
+py_type as associated Python sub type object. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
This will *not* increment the reference counter for the talloc context,
so the caller should make sure such an increment has happened. When the Python
@@ -133,7 +146,9 @@ object goes away, it will unreference the talloc context.
PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
Create a new Python wrapping object for a talloc pointer and context, with
-py_type as associated Python sub type object.
+py_type as associated Python sub type object. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
This will increment the reference counter for the talloc context.
@@ -142,7 +157,8 @@ PyObject *pytalloc_reference(PyTypeObject *py_type, void *talloc_ptr)
Create a new Python wrapping object for a talloc pointer, with
py_type as associated Python sub type object. The pointer will also be used
-as the talloc context.
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
This will increment the reference counter for the talloc context.
@@ -153,14 +169,59 @@ Create a new, empty pytalloc_Object with the specified Python type object. type
should be a C type, similar to talloc_new().
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-PyObject *pytalloc_CObject_FromTallocPtr(void *);
+PyObject *pytalloc_GenericObject_steal_ex(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
+
+This will *not* increment the reference counter for the talloc context,
+so the caller should make sure such an increment has happened. When the Python
+object goes away, it will unreference the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_steal(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
+
+This will *not* increment the reference counter for the talloc context,
+so the caller should make sure such an increment has happened. When the Python
+object goes away, it will unreference the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_reference_ex(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
+
+This will increment the reference counter for the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_reference(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
+
+This will increment the reference counter for the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+DEPRECATED! PyObject *pytalloc_CObject_FromTallocPtr(void *);
Create a new pytalloc_Object for an abitrary talloc-maintained C pointer. This will
use a generic VoidPtr Python type, which just provides an opaque object in
Python. The caller is responsible for incrementing the talloc reference count before calling
this function - it will dereference the talloc pointer when it is garbage collected.
-This function is only available on Python 2.
+This function is deprecated and only available on Python 2.
+Use pytalloc_GenericObject_{reference,steal}[_ex]() instead.
Debug function for talloc in Python
-----------------------------------
diff --git a/lib/talloc/pytalloc_util.c b/lib/talloc/pytalloc_util.c
index cb71dc9..923fe5d 100644
--- a/lib/talloc/pytalloc_util.c
+++ b/lib/talloc/pytalloc_util.c
@@ -64,6 +64,26 @@ _PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
return type;
}
+static PyTypeObject *pytalloc_GetGenericObjectType(void)
+{
+ static PyTypeObject *type = NULL;
+ PyObject *mod;
+
+ if (type != NULL) {
+ return type;
+ }
+
+ mod = PyImport_ImportModule("talloc");
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(mod, "GenericObject");
+ Py_DECREF(mod);
+
+ return type;
+}
+
/**
* Import an existing talloc pointer into a Python object.
*/
@@ -204,6 +224,26 @@ _PUBLIC_ PyObject *pytalloc_CObject_FromTallocPtr(void *ptr)
#endif
+/*
+ * Wrap a generic talloc pointer into a talloc.GenericObject,
+ * this is a subclass of talloc.BaseObject.
+ */
+_PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr)
+{
+ PyTypeObject *tp = pytalloc_GetGenericObjectType();
+ return pytalloc_steal_ex(tp, mem_ctx, ptr);
+}
+
+/*
+ * Wrap a generic talloc pointer into a talloc.GenericObject,
+ * this is a subclass of talloc.BaseObject.
+ */
+_PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr)
+{
+ PyTypeObject *tp = pytalloc_GetGenericObjectType();
+ return pytalloc_reference_ex(tp, mem_ctx, ptr);
+}
+
_PUBLIC_ int pytalloc_Check(PyObject *obj)
{
PyTypeObject *tp = pytalloc_GetObjectType();
@@ -223,21 +263,66 @@ _PUBLIC_ size_t pytalloc_BaseObject_size(void)
return sizeof(pytalloc_BaseObject);
}
-_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
+static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name,
+ bool check_only, const char *function)
{
- void *ptr = _pytalloc_get_ptr(py_obj);
+ TALLOC_CTX *mem_ctx;
+ void *ptr = NULL;
void *type_obj = talloc_check_name(ptr, type_name);
+ mem_ctx = _pytalloc_get_mem_ctx(py_obj);
+ ptr = _pytalloc_get_ptr(py_obj);
+
+ if (mem_ctx != ptr) {
+ if (check_only) {
+ return NULL;
+ }
+
+ PyErr_Format(PyExc_TypeError, "%s: expected %s, "
+ "but the pointer is no talloc pointer, "
+ "pytalloc_get_ptr() would get the raw pointer.",
+ function, type_name);
+ return NULL;
+ }
+
+ type_obj = talloc_check_name(ptr, type_name);
if (type_obj == NULL) {
- const char *name = talloc_get_name(ptr);
- PyErr_Format(PyExc_TypeError, "pytalloc: expected %s, got %s",
- type_name, name);
+ const char *name = NULL;
+
+ if (check_only) {
+ return NULL;
+ }
+
+ name = talloc_get_name(ptr);
+ PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s",
+ function, type_name, name);
return NULL;
}
return ptr;
}
+_PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name)
+{
+ void *ptr = NULL;
+
+ ptr = _pytalloc_get_checked_type(py_obj, type_name,
+ true, /* check_only */
+ "pytalloc_check_type");
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ return 1;
+}
+
+_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
+{
+ return _pytalloc_get_checked_type(py_obj, type_name,
+ false, /* not check_only */
+ "pytalloc_get_type");
+}
+
_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
{
if (pytalloc_BaseObject_check(py_obj)) {
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 279021c..7721fa4 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -37,17 +37,13 @@
#include <sys/auxv.h>
#endif
-#ifdef TALLOC_BUILD_VERSION_MAJOR
#if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR)
#error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR"
#endif
-#endif
-#ifdef TALLOC_BUILD_VERSION_MINOR
#if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR)
#error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR"
#endif
-#endif
/* Special macros that are no-ops except when run under Valgrind on
* x86. They've moved a little bit from valgrind 1.0.4 to 1.9.4 */
@@ -82,8 +78,9 @@
static unsigned int talloc_magic = (
~TALLOC_FLAG_MASK & (
TALLOC_MAGIC_BASE +
- (TALLOC_VERSION_MAJOR << 12) +
- (TALLOC_VERSION_MINOR << 4)));
+ (TALLOC_BUILD_VERSION_MAJOR << 24) +
+ (TALLOC_BUILD_VERSION_MINOR << 16) +
+ (TALLOC_BUILD_VERSION_RELEASE << 8)));
/* by default we abort when given a bad pointer (such as when talloc_free() is called
on a pointer that came from malloc() */
@@ -453,7 +450,7 @@ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
const char *pp = (const char *)ptr;
struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) {
- if ((tc->flags & (~0xF)) == talloc_magic) {
+ if ((tc->flags & (~TALLOC_FLAG_MASK)) == talloc_magic) {
talloc_abort_magic(tc->flags & (~TALLOC_FLAG_MASK));
return NULL;
}
@@ -2739,9 +2736,6 @@ _PUBLIC_ size_t talloc_get_size(const void *context)
struct talloc_chunk *tc;
if (context == NULL) {
- context = null_context;
- }
- if (context == NULL) {
return 0;
}
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
index b0917b5..618430a 100644
--- a/lib/talloc/talloc.h
+++ b/lib/talloc/talloc.h
@@ -43,7 +43,7 @@ extern "C" {
*/
#define TALLOC_VERSION_MAJOR 2
-#define TALLOC_VERSION_MINOR 0
+#define TALLOC_VERSION_MINOR 1
int talloc_version_major(void);
int talloc_version_minor(void);
@@ -407,10 +407,11 @@ const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIB
*
* @param[in] new_ctx The new parent context.
*
- * @param[in] pptr Pointer to the talloc chunk to move.
+ * @param[in] pptr Pointer to a pointer to the talloc chunk to move.
+ *
+ * @return The pointer to the talloc chunk that moved.
+ * It does not have any failure modes.
*
- * @return The pointer of the talloc chunk it has been moved to,
- * NULL on error.
*/
void *talloc_move(const void *new_ctx, void **pptr);
#else
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index 835d38b..dfaeec1 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -610,7 +610,7 @@ static bool test_realloc_child(void)
void *root;
struct el2 {
const char *name;
- } *el2, *el2_2, *el2_3;
+ } *el2, *el2_2, *el2_3, **el_list_save;
struct el1 {
int count;
struct el2 **list, **list2, **list3;
@@ -640,7 +640,13 @@ static bool test_realloc_child(void)
el2_3 = talloc(el1->list3, struct el2);
CHECK_PARENT("el2", el2_3, el1->list3);
+ el_list_save = el1->list;
el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+ if (el1->list == el_list_save) {
+ printf("failure: talloc_realloc didn't move pointer");
+ return false;
+ }
+
CHECK_PARENT("el1_after_realloc", el1->list, el1);
el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
CHECK_PARENT("el1_after_realloc", el1->list2, el1);
@@ -651,6 +657,12 @@ static bool test_realloc_child(void)
CHECK_PARENT("el2", el2_2, el1->list2);
CHECK_PARENT("el2", el2_3, el1->list3);
+ /* Finally check realloc with multiple children */
+ el1 = talloc_realloc(root, el1, struct el1, 100);
+ CHECK_PARENT("el1->list", el1->list, el1);
+ CHECK_PARENT("el1->list2", el1->list2, el1);
+ CHECK_PARENT("el1->list3", el1->list3, el1);
+
talloc_free(root);
printf("success: REALLOC WITH CHILD\n");
@@ -973,6 +985,57 @@ static bool test_loop(void)
return true;
}
+static int realloc_parent_destructor_count;
+
+static int test_realloc_parent_destructor(char *ptr)
+{
+ realloc_parent_destructor_count++;
+ return 0;
+}
+
+static bool test_realloc_on_destructor_parent(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent;
+ char *a, *b, *C, *D;
+ realloc_parent_destructor_count = 0;
+
+ printf("test: free_for_exit\n# TALLOC FREE FOR EXIT\n");
+
+ parent = talloc_strdup(top, "parent");
+ a = talloc_strdup(parent, "a");
+ b = talloc_strdup(a, "b");
+ C = talloc_strdup(a, "C");
+ D = talloc_strdup(b, "D");
+ talloc_set_destructor(D, test_realloc_parent_destructor);
+ /* Capitalised ones have destructors.
+ *
+ * parent --> a -> b -> D
+ * -> c
+ */
+
+ a = talloc_realloc(parent, a, char, 2048);
+
+ torture_assert("check talloc_realloc", a != NULL, "talloc_realloc failed");
+
+ talloc_set_destructor(C, test_realloc_parent_destructor);
+ /*
+ * parent --> a[2048] -> b -> D
+ * -> C
+ *
+ */
+
+ talloc_free(parent);
+
+ torture_assert("check destructor realloc_parent_destructor",
+ realloc_parent_destructor_count == 2,
+ "FAILED TO FIRE free_for_exit_destructor\n");
+
+
+ printf("success: free_for_exit\n");
+ return true;
+}
+
static int fail_destructor_str(char *ptr)
{
return -1;
@@ -1994,6 +2057,8 @@ bool torture_local_talloc(struct torture_context *tctx)
test_reset();
ret &= test_free_parent_deny_child();
test_reset();
+ ret &= test_realloc_on_destructor_parent();
+ test_reset();
ret &= test_free_parent_reparent_child();
test_reset();
ret &= test_free_parent_reparent_child_in_pool();
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index 41f3be7..ab74e72 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'talloc'
-VERSION = '2.1.8'
+VERSION = '2.1.10'
blddir = 'bin'
@@ -32,9 +32,6 @@ def set_options(opt):
opt.add_option('--enable-talloc-compat1',
help=("Build talloc 1.x.x compat library [False]"),
action="store_true", dest='TALLOC_COMPAT1', default=False)
- opt.add_option('--disable-python',
- help=("disable the pytalloc module"),
- action="store_true", dest='disable_python', default=False)
def configure(conf):
@@ -42,22 +39,28 @@ def configure(conf):
conf.env.standalone_talloc = conf.IN_LAUNCH_DIR()
- conf.env.disable_python = getattr(Options.options, 'disable_python', False)
-
- if not conf.env.standalone_talloc:
- if conf.CHECK_BUNDLED_SYSTEM_PKG('talloc', minversion=VERSION,
- implied_deps='replace'):
- conf.define('USING_SYSTEM_TALLOC', 1)
- if conf.CHECK_BUNDLED_SYSTEM_PKG('pytalloc-util', minversion=VERSION,
- implied_deps='talloc replace'):
- conf.define('USING_SYSTEM_PYTALLOC_UTIL', 1)
+ conf.define('TALLOC_BUILD_VERSION_MAJOR', int(VERSION.split('.')[0]))
+ conf.define('TALLOC_BUILD_VERSION_MINOR', int(VERSION.split('.')[1]))
+ conf.define('TALLOC_BUILD_VERSION_RELEASE', int(VERSION.split('.')[2]))
conf.env.TALLOC_COMPAT1 = False
if conf.env.standalone_talloc:
conf.env.TALLOC_COMPAT1 = Options.options.TALLOC_COMPAT1
+ conf.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+ conf.env.TALLOC_VERSION = VERSION
conf.CHECK_XSLTPROC_MANPAGES()
+ conf.CHECK_HEADERS('sys/auxv.h')
+ conf.CHECK_FUNCS('getauxval')
+
+ conf.SAMBA_CONFIG_H()
+
+ conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+
+ # We need to set everything non-python up before here, because
+ # SAMBA_CHECK_PYTHON makes a copy of conf and we need it set up correctly
+
if not conf.env.disable_python:
# also disable if we don't have the python libs installed
conf.SAMBA_CHECK_PYTHON(mandatory=False, version=(2,4,2))
@@ -66,20 +69,35 @@ def configure(conf):
Logs.warn('Disabling pytalloc-util as python devel libs not found')
conf.env.disable_python = True
- conf.CHECK_HEADERS('sys/auxv.h')
- conf.CHECK_FUNCS('getauxval')
-
- conf.SAMBA_CONFIG_H()
+ if not conf.env.standalone_talloc:
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('talloc', minversion=VERSION,
+ implied_deps='replace'):
+ conf.define('USING_SYSTEM_TALLOC', 1)
- conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+ if conf.env.disable_python:
+ using_system_pytalloc_util = False
+ else:
+ using_system_pytalloc_util = True
+ if not conf.CHECK_BUNDLED_SYSTEM_PKG('pytalloc-util', minversion=VERSION,
+ implied_deps='talloc replace'):
+ using_system_pytalloc_util = False
+
+ # We need to get a pytalloc-util for all the python versions
+ # we are building for
+ if conf.env['EXTRA_PYTHON']:
+ name = 'pytalloc-util' + conf.all_envs['extrapython']['PYTHON_SO_ABI_FLAG']
+ if not conf.CHECK_BUNDLED_SYSTEM_PKG(name, minversion=VERSION,
+ implied_deps='talloc replace'):
+ using_system_pytalloc_util = False
+
+ if using_system_pytalloc_util:
+ conf.define('USING_SYSTEM_PYTALLOC_UTIL', 1)
def build(bld):
bld.RECURSE('lib/replace')
if bld.env.standalone_talloc:
- bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
- bld.env.TALLOC_VERSION = VERSION
private_library = False
# should we also install the symlink to libtalloc1.so here?
@@ -122,7 +140,7 @@ def build(bld):
private_library=private_library,
manpages='man/talloc.3')
- if not bld.CONFIG_SET('USING_SYSTEM_PYTALLOC_UTIL') and not bld.env.disable_python:
+ if not bld.CONFIG_SET('USING_SYSTEM_PYTALLOC_UTIL'):
for env in bld.gen_python_environments(['PKGCONFIGDIR']):
name = bld.pyembed_libname('pytalloc-util')
@@ -136,18 +154,19 @@ def build(bld):
abi_match='pytalloc_* _pytalloc_*',
private_library=private_library,
public_headers=('' if private_library else 'pytalloc.h'),
- pc_files='pytalloc-util.pc'
+ pc_files='pytalloc-util.pc',
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
)
bld.SAMBA_PYTHON('pytalloc',
'pytalloc.c',
deps='talloc ' + name,
- enabled=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED(),
realname='talloc.so')
bld.SAMBA_PYTHON('test_pytalloc',
'test_pytalloc.c',
deps='pytalloc',
- enabled=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED(),
realname='_test_pytalloc.so',
install=False)
@@ -155,12 +174,18 @@ def build(bld):
def test(ctx):
'''run talloc testsuite'''
import Utils, samba_utils
+
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
cmd = os.path.join(Utils.g_module.blddir, 'talloc_testsuite')
ret = samba_utils.RUN_COMMAND(cmd)
print("testsuite returned %d" % ret)
magic_helper_cmd = os.path.join(Utils.g_module.blddir, 'talloc_test_magic_differs_helper')
magic_cmd = os.path.join(srcdir, 'lib', 'talloc',
'test_magic_differs.sh')
+ if not os.path.exists(magic_cmd):
+ magic_cmd = os.path.join(srcdir, 'test_magic_differs.sh')
magic_ret = samba_utils.RUN_COMMAND(magic_cmd + " " + magic_helper_cmd)
print("magic differs test returned %d" % magic_ret)
diff --git a/lib/tdb/ABI/tdb-1.3.13.sigs b/lib/tdb/ABI/tdb-1.3.13.sigs
new file mode 100644
index 0000000..48f4278
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.13.sigs
@@ -0,0 +1,70 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.14.sigs b/lib/tdb/ABI/tdb-1.3.14.sigs
new file mode 100644
index 0000000..61ce5e6
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.14.sigs
@@ -0,0 +1,71 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.15.sigs b/lib/tdb/ABI/tdb-1.3.15.sigs
new file mode 100644
index 0000000..61ce5e6
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.15.sigs
@@ -0,0 +1,71 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/common/dump.c b/lib/tdb/common/dump.c
index 5f6a78b..73286b8 100644
--- a/lib/tdb/common/dump.c
+++ b/lib/tdb/common/dump.c
@@ -62,7 +62,11 @@ static int tdb_dump_chain(struct tdb_context *tdb, int i)
{
tdb_off_t rec_ptr, top;
- top = TDB_HASH_TOP(i);
+ if (i == -1) {
+ top = FREELIST_TOP;
+ } else {
+ top = TDB_HASH_TOP(i);
+ }
if (tdb_lock(tdb, i, F_WRLCK) != 0)
return -1;
diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c
index fe47d18..15ba5b7 100644
--- a/lib/tdb/common/io.c
+++ b/lib/tdb/common/io.c
@@ -52,29 +52,68 @@ static bool tdb_adjust_offset(struct tdb_context *tdb, off_t *off)
static ssize_t tdb_pwrite(struct tdb_context *tdb, const void *buf,
size_t count, off_t offset)
{
+ ssize_t ret;
+
if (!tdb_adjust_offset(tdb, &offset)) {
return -1;
}
- return pwrite(tdb->fd, buf, count, offset);
+
+ do {
+ ret = pwrite(tdb->fd, buf, count, offset);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
}
static ssize_t tdb_pread(struct tdb_context *tdb, void *buf,
size_t count, off_t offset)
{
+ ssize_t ret;
+
if (!tdb_adjust_offset(tdb, &offset)) {
return -1;
}
- return pread(tdb->fd, buf, count, offset);
+
+ do {
+ ret = pread(tdb->fd, buf, count, offset);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
}
static int tdb_ftruncate(struct tdb_context *tdb, off_t length)
{
+ ssize_t ret;
+
if (!tdb_adjust_offset(tdb, &length)) {
return -1;
}
- return ftruncate(tdb->fd, length);
+
+ do {
+ ret = ftruncate(tdb->fd, length);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
}
+#if HAVE_POSIX_FALLOCATE
+static int tdb_posix_fallocate(struct tdb_context *tdb, off_t offset,
+ off_t len)
+{
+ ssize_t ret;
+
+ if (!tdb_adjust_offset(tdb, &offset)) {
+ return -1;
+ }
+
+ do {
+ ret = posix_fallocate(tdb->fd, offset, len);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
+}
+#endif
+
static int tdb_fstat(struct tdb_context *tdb, struct stat *buf)
{
int ret;
@@ -358,6 +397,7 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
{
char buf[8192];
tdb_off_t new_size;
+ int ret;
if (tdb->read_only || tdb->traverse_read) {
tdb->ecode = TDB_ERR_RDONLY;
@@ -373,7 +413,36 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
return -1;
}
- if (tdb_ftruncate(tdb, new_size) == -1) {
+#if HAVE_POSIX_FALLOCATE
+ ret = tdb_posix_fallocate(tdb, size, addition);
+ if (ret == 0) {
+ return 0;
+ }
+ if (ret == ENOSPC) {
+ /*
+ * The Linux glibc (at least as of 2.24) fallback if
+ * the file system does not support fallocate does not
+ * reset the file size back to where it was. Also, to
+ * me it is unclear from the posix spec of
+ * posix_fallocate whether this is allowed or
+ * not. Better be safe than sorry and "goto fail" but
+ * "return -1" here, leaving the EOF pointer too
+ * large.
+ */
+ goto fail;
+ }
+
+ /*
+ * Retry the "old" way. Possibly unnecessary, but looking at
+ * our configure script there seem to be weird failure modes
+ * for posix_fallocate. See commit 3264a98ff16de, which
+ * probably refers to
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=1083.
+ */
+#endif
+
+ ret = tdb_ftruncate(tdb, new_size);
+ if (ret == -1) {
char b = 0;
ssize_t written = tdb_pwrite(tdb, &b, 1, new_size - 1);
if (written == 0) {
@@ -409,14 +478,14 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
"returned 0 twice: giving up!\n"));
errno = ENOSPC;
- return -1;
+ goto fail;
}
if (written == -1) {
tdb->ecode = TDB_ERR_OOM;
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
"%u bytes failed (%s)\n", (int)n,
strerror(errno)));
- return -1;
+ goto fail;
}
if (written != n) {
TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
@@ -427,6 +496,28 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
size += written;
}
return 0;
+
+fail:
+ {
+ int err = errno;
+
+ /*
+ * We're holding the freelist lock or are inside a
+ * transaction. Cutting the file is safe, the space we
+ * tried to allocate can't have been used anywhere in
+ * the meantime.
+ */
+
+ ret = tdb_ftruncate(tdb, size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: "
+ "retruncate to %ju failed\n",
+ (uintmax_t)size));
+ }
+ errno = err;
+ }
+
+ return -1;
}
diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
index 195dbb5..9f30c7a 100644
--- a/lib/tdb/common/lock.c
+++ b/lib/tdb/common/lock.c
@@ -137,7 +137,33 @@ static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len)
return fcntl(tdb->fd, F_SETLKW, &fl);
}
-/* list -1 is the alloc list, otherwise a hash chain. */
+/*
+ * Calculate the lock offset for a list
+ *
+ * list -1 is the freelist, otherwise a hash chain.
+ *
+ * Note that we consistently (but without real reason) lock hash chains at an
+ * offset that is 4 bytes below the real offset of the corresponding list head
+ * in the db.
+ *
+ * This is the memory layout of the hashchain array:
+ *
+ * FREELIST_TOP + 0 = freelist
+ * FREELIST_TOP + 4 = hashtbale list 0
+ * FREELIST_TOP + 8 = hashtbale list 1
+ * ...
+ *
+ * Otoh lock_offset computes:
+ *
+ * freelist = FREELIST_TOP - 4
+ * list 0 = FREELIST_TOP + 0
+ * list 1 = FREELIST_TOP + 4
+ * ...
+ *
+ * Unfortunately we can't change this calculation in order to align the locking
+ * offset with the memory layout, as that would make the locking incompatible
+ * between different tdb versions.
+ */
static tdb_off_t lock_offset(int list)
{
return FREELIST_TOP + 4*list;
@@ -257,12 +283,14 @@ int tdb_allrecord_upgrade(struct tdb_context *tdb)
TDB_LOG((tdb, TDB_DEBUG_ERROR,
"tdb_allrecord_upgrade failed: count %u too high\n",
tdb->allrecord_lock.count));
+ tdb->ecode = TDB_ERR_LOCK;
return -1;
}
if (tdb->allrecord_lock.off != 1) {
TDB_LOG((tdb, TDB_DEBUG_ERROR,
"tdb_allrecord_upgrade failed: already upgraded?\n"));
+ tdb->ecode = TDB_ERR_LOCK;
return -1;
}
@@ -294,7 +322,7 @@ fail:
static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb,
tdb_off_t offset)
{
- unsigned int i;
+ int i;
for (i=0; i<tdb->num_lockrecs; i++) {
if (tdb->lockrecs[i].off == offset) {
@@ -321,6 +349,22 @@ int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
new_lck = find_nestlock(tdb, offset);
if (new_lck) {
+ if ((new_lck->ltype == F_RDLCK) && (ltype == F_WRLCK)) {
+ if (!tdb_have_mutexes(tdb)) {
+ int ret;
+ /*
+ * Upgrade the underlying fcntl
+ * lock. Mutexes don't do readlocks,
+ * so this only applies to fcntl
+ * locking.
+ */
+ ret = tdb_brlock(tdb, ltype, offset, 1, flags);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ new_lck->ltype = F_WRLCK;
+ }
/*
* Just increment the in-memory struct, posix locks
* don't stack.
@@ -381,7 +425,7 @@ static int tdb_lock_and_recover(struct tdb_context *tdb)
static bool have_data_locks(const struct tdb_context *tdb)
{
- unsigned int i;
+ int i;
for (i = 0; i < tdb->num_lockrecs; i++) {
if (tdb->lockrecs[i].off >= lock_offset(-1))
@@ -560,7 +604,8 @@ static int tdb_allrecord_check(struct tdb_context *tdb, int ltype,
return -1;
}
- if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) {
+ if (tdb->allrecord_lock.count &&
+ tdb->allrecord_lock.ltype == (uint32_t)ltype) {
tdb->allrecord_lock.count++;
return 0;
}
@@ -706,7 +751,7 @@ int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock)
}
/* Upgradable locks are marked as write locks. */
- if (tdb->allrecord_lock.ltype != ltype
+ if (tdb->allrecord_lock.ltype != (uint32_t)ltype
&& (!tdb->allrecord_lock.off || ltype != F_RDLCK)) {
tdb->ecode = TDB_ERR_LOCK;
return -1;
@@ -945,7 +990,8 @@ bool tdb_have_extra_locks(struct tdb_context *tdb)
/* The transaction code uses this to remove all locks. */
void tdb_release_transaction_locks(struct tdb_context *tdb)
{
- unsigned int i, active = 0;
+ int i;
+ unsigned int active = 0;
if (tdb->allrecord_lock.count != 0) {
tdb_allrecord_unlock(tdb, tdb->allrecord_lock.ltype, false);
diff --git a/lib/tdb/common/mutex.c b/lib/tdb/common/mutex.c
index cac3916..8a122d5 100644
--- a/lib/tdb/common/mutex.c
+++ b/lib/tdb/common/mutex.c
@@ -752,12 +752,23 @@ static bool tdb_robust_mutex_setup_sigchild(void (*handler)(int),
static void tdb_robust_mutex_handler(int sig)
{
- if (tdb_robust_mutex_pid != -1) {
+ pid_t child_pid = tdb_robust_mutex_pid;
+
+ if (child_pid != -1) {
pid_t pid;
- int status;
- pid = waitpid(tdb_robust_mutex_pid, &status, WNOHANG);
- if (pid == tdb_robust_mutex_pid) {
+ pid = waitpid(child_pid, NULL, WNOHANG);
+ if (pid == -1) {
+ switch (errno) {
+ case ECHILD:
+ tdb_robust_mutex_pid = -1;
+ return;
+
+ default:
+ return;
+ }
+ }
+ if (pid == child_pid) {
tdb_robust_mutex_pid = -1;
return;
}
@@ -776,6 +787,44 @@ static void tdb_robust_mutex_handler(int sig)
tdb_robust_mutext_old_handler(sig);
}
+static void tdb_robust_mutex_wait_for_child(pid_t *child_pid)
+{
+ int options = WNOHANG;
+
+ if (*child_pid == -1) {
+ return;
+ }
+
+ while (tdb_robust_mutex_pid > 0) {
+ pid_t pid;
+
+ /*
+ * First we try with WNOHANG, as the process might not exist
+ * anymore. Once we've sent SIGKILL we block waiting for the
+ * exit.
+ */
+ pid = waitpid(*child_pid, NULL, options);
+ if (pid == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else if (errno == ECHILD) {
+ break;
+ } else {
+ abort();
+ }
+ }
+ if (pid == *child_pid) {
+ break;
+ }
+
+ kill(*child_pid, SIGKILL);
+ options = 0;
+ }
+
+ tdb_robust_mutex_pid = -1;
+ *child_pid = -1;
+}
+
_PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
{
void *ptr = NULL;
@@ -788,9 +837,8 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
char c = 0;
bool ok;
static bool initialized;
- sigset_t mask, old_mask, suspend_mask;
+ pid_t saved_child_pid = -1;
bool cleanup_ma = false;
- bool cleanup_sigmask = false;
if (initialized) {
return tdb_mutex_locking_cached;
@@ -798,8 +846,6 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
initialized = true;
- sigemptyset(&suspend_mask);
-
ok = tdb_mutex_locking_supported();
if (!ok) {
return false;
@@ -845,26 +891,13 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
}
m = (pthread_mutex_t *)ptr;
- /*
- * Block SIGCHLD so we can atomically wait for it later with
- * sigsuspend()
- */
- sigemptyset(&mask);
- sigaddset(&mask, SIGCHLD);
- ret = pthread_sigmask(SIG_BLOCK, &mask, &old_mask);
- if (ret != 0) {
- goto cleanup;
- }
- cleanup_sigmask = true;
- suspend_mask = old_mask;
- sigdelset(&suspend_mask, SIGCHLD);
-
if (tdb_robust_mutex_setup_sigchild(tdb_robust_mutex_handler,
&tdb_robust_mutext_old_handler) == false) {
goto cleanup;
}
tdb_robust_mutex_pid = fork();
+ saved_child_pid = tdb_robust_mutex_pid;
if (tdb_robust_mutex_pid == 0) {
size_t nwritten;
close(pipe_down[1]);
@@ -914,14 +947,7 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
goto cleanup;
}
- while (tdb_robust_mutex_pid > 0) {
- ret = sigsuspend(&suspend_mask);
- if (ret != -1 || errno != EINTR) {
- abort();
- }
- }
- tdb_robust_mutex_setup_sigchild(tdb_robust_mutext_old_handler, NULL);
- tdb_robust_mutext_old_handler = SIG_ERR;
+ tdb_robust_mutex_wait_for_child(&saved_child_pid);
ret = pthread_mutex_trylock(m);
if (ret != EOWNERDEAD) {
@@ -950,23 +976,21 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
tdb_mutex_locking_cached = true;
cleanup:
- while (tdb_robust_mutex_pid > 0) {
- kill(tdb_robust_mutex_pid, SIGKILL);
- ret = sigsuspend(&suspend_mask);
- if (ret != -1 || errno != EINTR) {
- abort();
- }
- }
+ /*
+ * Note that we don't reset the signal handler we just reset
+ * tdb_robust_mutex_pid to -1. This is ok as this code path is only
+ * called once per process.
+ *
+ * Leaving our signal handler avoids races with other threads potentialy
+ * setting up their SIGCHLD handlers.
+ *
+ * The worst thing that can happen is that the other newer signal
+ * handler will get the SIGCHLD signal for our child and/or reap the
+ * child with a wait() function. tdb_robust_mutex_wait_for_child()
+ * handles the case where waitpid returns ECHILD.
+ */
+ tdb_robust_mutex_wait_for_child(&saved_child_pid);
- if (tdb_robust_mutext_old_handler != SIG_ERR) {
- tdb_robust_mutex_setup_sigchild(tdb_robust_mutext_old_handler, NULL);
- }
- if (cleanup_sigmask) {
- ret = pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
- if (ret != 0) {
- abort();
- }
- }
if (m != NULL) {
pthread_mutex_destroy(m);
}
diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c
index f3ef856..cfb476d 100644
--- a/lib/tdb/common/open.c
+++ b/lib/tdb/common/open.c
@@ -300,7 +300,8 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td
struct tdb_header header;
struct tdb_context *tdb;
struct stat st;
- int rev = 0, locked = 0;
+ int rev = 0;
+ bool locked = false;
unsigned char *vp;
uint32_t vertest;
unsigned v;
@@ -512,37 +513,42 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td
/* we need to zero database if we are the only one with it open */
if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
- (!tdb->read_only) &&
- (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
- ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
- TDB_LOCK_WAIT);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "tdb_brlock failed for %s: %s\n",
- name, strerror(errno)));
- goto fail;
- }
- ret = tdb_new_database(tdb, &header, hash_size);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "tdb_new_database failed for %s: %s\n",
- name, strerror(errno)));
- tdb_unlockall(tdb);
- goto fail;
- }
- ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "tdb_unlockall failed for %s: %s\n",
- name, strerror(errno)));
- goto fail;
- }
- ret = lseek(tdb->fd, 0, SEEK_SET);
- if (ret == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
- "lseek failed for %s: %s\n",
- name, strerror(errno)));
- goto fail;
+ (!tdb->read_only)) {
+ ret = tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK,
+ TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+ locked = (ret == 0);
+
+ if (locked) {
+ ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
+ TDB_LOCK_WAIT);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_brlock failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ ret = tdb_new_database(tdb, &header, hash_size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_new_database failed for "
+ "%s: %s\n", name, strerror(errno)));
+ tdb_unlockall(tdb);
+ goto fail;
+ }
+ ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_unlockall failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ ret = lseek(tdb->fd, 0, SEEK_SET);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "lseek failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
}
}
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index a67d8fb..04f7f97 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -541,6 +541,11 @@ static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
for (i=0; i<num_dbufs; i++) {
size_t dsize = dbufs[i].dsize;
+ if ((dsize != 0) && (dbufs[i].dptr == NULL)) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ goto fail;
+ }
+
dbufs_len += dsize;
if (dbufs_len < dsize) {
tdb->ecode = TDB_ERR_OOM;
@@ -614,6 +619,10 @@ static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
ofs += key.dsize;
for (i=0; i<num_dbufs; i++) {
+ if (dbufs[i].dsize == 0) {
+ continue;
+ }
+
ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
dbufs[i].dsize);
if (ret == -1) {
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
index 7ff29aa..eeac10a 100644
--- a/lib/tdb/common/tdb_private.h
+++ b/lib/tdb/common/tdb_private.h
@@ -126,6 +126,22 @@ void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
#endif
+/*
+ * Note: the BUCKET macro is broken as it returns an unexpected result when
+ * called as BUCKET(-1) for the freelist:
+ *
+ * -1 is sign converted to an unsigned int 4294967295 and then the modulo
+ * tdb->hashtable_size is computed. So with a hashtable_size of 10 the result
+ * is
+ *
+ * 4294967295 % hashtable_size = 5.
+ *
+ * where it should be -1 (C uses symmetric modulo).
+ *
+ * As all callers will lock the same wrong list consistently locking is still
+ * consistent. We can not change this without an incompatible on-disk format
+ * change, otherwise different tdb versions would use incompatible locking.
+ */
#define BUCKET(hash) ((hash) % tdb->hash_size)
#define DOCONV() (tdb->flags & TDB_CONVERT)
@@ -178,7 +194,7 @@ struct tdb_lock_type {
struct tdb_traverse_lock {
struct tdb_traverse_lock *next;
uint32_t off;
- uint32_t hash;
+ uint32_t list;
int lock_rw;
};
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index 0dd057b..7d281fc 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -43,7 +43,7 @@
tdb_free() the old record to place it on the normal tdb freelist
before allocating the new record
- - during transactions, keep a linked list of writes all that have
+ - during transactions, keep a linked list of all writes that have
been performed by intercepting all tdb_write() calls. The hooked
transaction versions of tdb_read() and tdb_write() check this
linked list and try to use the elements of the list in preference
@@ -210,6 +210,10 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
{
uint32_t blk;
+ if (buf == NULL) {
+ return -1;
+ }
+
/* Only a commit is allowed on a prepared transaction */
if (tdb->transaction->prepared) {
tdb->ecode = TDB_ERR_EINVAL;
@@ -234,9 +238,7 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
}
len -= len2;
off += len2;
- if (buf != NULL) {
- buf = (const void *)(len2 + (const char *)buf);
- }
+ buf = (const void *)(len2 + (const char *)buf);
}
if (len == 0) {
@@ -289,11 +291,7 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
}
/* overwrite part of an existing block */
- if (buf == NULL) {
- memset(tdb->transaction->blocks[blk] + off, 0, len);
- } else {
- memcpy(tdb->transaction->blocks[blk] + off, buf, len);
- }
+ memcpy(tdb->transaction->blocks[blk] + off, buf, len);
if (blk == tdb->transaction->num_blocks-1) {
if (len + off > tdb->transaction->last_block_size) {
tdb->transaction->last_block_size = len + off;
@@ -393,10 +391,20 @@ static int transaction_oob(struct tdb_context *tdb, tdb_off_t off,
static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
tdb_off_t addition)
{
- /* add a write to the transaction elements, so subsequent
- reads see the zero data */
- if (transaction_write(tdb, size, NULL, addition) != 0) {
- return -1;
+ const char buf_zero[8192] = {0};
+ size_t buf_len = sizeof(buf_zero);
+
+ while (addition > 0) {
+ size_t n = MIN(addition, buf_len);
+ int ret;
+
+ ret = transaction_write(tdb, size, buf_zero, n);
+ if (ret != 0) {
+ return ret;
+ }
+
+ addition -= n;
+ size += n;
}
tdb->transaction->expanded = true;
@@ -412,6 +420,14 @@ static const struct tdb_methods transaction_methods = {
transaction_expand_file,
};
+/*
+ * Is a transaction currently active on this context?
+ *
+ */
+_PUBLIC_ bool tdb_transaction_active(struct tdb_context *tdb)
+{
+ return (tdb->transaction != NULL);
+}
/*
start a tdb transaction. No token is returned, as only a single
@@ -476,6 +492,10 @@ static int _tdb_transaction_start(struct tdb_context *tdb,
SAFE_FREE(tdb->transaction);
if ((lockflags & TDB_LOCK_WAIT) == 0) {
tdb->ecode = TDB_ERR_NOLOCK;
+ } else {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_start: "
+ "failed to get transaction lock\n"));
}
return -1;
}
@@ -982,7 +1002,23 @@ static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
/* upgrade the main transaction lock region to a write lock */
if (tdb_allrecord_upgrade(tdb) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
+ if (tdb->ecode == TDB_ERR_RDONLY && tdb->read_only) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_prepare_commit: "
+ "failed to upgrade hash locks: "
+ "database is read only\n"));
+ } else if (tdb->ecode == TDB_ERR_RDONLY
+ && tdb->traverse_read) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_prepare_commit: "
+ "failed to upgrade hash locks: "
+ "a database traverse is in progress\n"));
+ } else {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_prepare_commit: "
+ "failed to upgrade hash locks: %s\n",
+ tdb_errorstr(tdb)));
+ }
_tdb_transaction_cancel(tdb);
return -1;
}
diff --git a/lib/tdb/common/traverse.c b/lib/tdb/common/traverse.c
index f33ef34..9b83379 100644
--- a/lib/tdb/common/traverse.c
+++ b/lib/tdb/common/traverse.c
@@ -37,8 +37,8 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
int want_next = (tlock->off != 0);
/* Lock each chain from the start one. */
- for (; tlock->hash < tdb->hash_size; tlock->hash++) {
- if (!tlock->off && tlock->hash != 0) {
+ for (; tlock->list < tdb->hash_size; tlock->list++) {
+ if (!tlock->off && tlock->list != 0) {
/* this is an optimisation for the common case where
the hash chain is empty, which is particularly
common for the use of tdb with ldb, where large
@@ -67,18 +67,18 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
factor of around 80 in speed on a linux 2.6.x
system (testing using ldbtest).
*/
- tdb->methods->next_hash_chain(tdb, &tlock->hash);
- if (tlock->hash == tdb->hash_size) {
+ tdb->methods->next_hash_chain(tdb, &tlock->list);
+ if (tlock->list == tdb->hash_size) {
continue;
}
}
- if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1)
+ if (tdb_lock(tdb, tlock->list, tlock->lock_rw) == -1)
return TDB_NEXT_LOCK_ERR;
/* No previous record? Start at top of chain. */
if (!tlock->off) {
- if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->list),
&tlock->off) == -1)
goto fail;
} else {
@@ -121,7 +121,7 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
tdb_do_delete(tdb, current, rec) != 0)
goto fail;
}
- tdb_unlock(tdb, tlock->hash, tlock->lock_rw);
+ tdb_unlock(tdb, tlock->list, tlock->lock_rw);
want_next = 0;
}
/* We finished iteration without finding anything */
@@ -130,7 +130,7 @@ static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock
fail:
tlock->off = 0;
- if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0)
+ if (tdb_unlock(tdb, tlock->list, tlock->lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
return TDB_NEXT_LOCK_ERR;
}
@@ -181,7 +181,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
if (key.dptr == NULL) {
ret = -1;
- if (tdb_unlock(tdb, tl->hash, tl->lock_rw)
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw)
!= 0) {
goto out;
}
@@ -205,7 +205,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
key.dptr, full_len, 0);
if (nread == -1) {
ret = -1;
- if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw) != 0)
goto out;
if (tdb_unlock_record(tdb, tl->off) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
@@ -218,7 +218,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf);
/* Drop chain lock, call out */
- if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) {
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw) != 0) {
ret = -1;
goto out;
}
@@ -244,7 +244,7 @@ out:
/*
- a read style traverse - temporarily marks the db read only
+ a read style traverse - temporarily marks each record read only
*/
_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb,
tdb_traverse_func fn, void *private_data)
@@ -252,19 +252,11 @@ _PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb,
struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
int ret;
- /* we need to get a read lock on the transaction lock here to
- cope with the lock ordering semantics of solaris10 */
- if (tdb_transaction_lock(tdb, F_RDLCK, TDB_LOCK_WAIT)) {
- return -1;
- }
-
tdb->traverse_read++;
tdb_trace(tdb, "tdb_traverse_read_start");
ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
tdb->traverse_read--;
- tdb_transaction_unlock(tdb, F_RDLCK);
-
return ret;
}
@@ -322,7 +314,7 @@ _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
/* release any old lock */
if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0)
return tdb_null;
- tdb->travlocks.off = tdb->travlocks.hash = 0;
+ tdb->travlocks.off = tdb->travlocks.list = 0;
tdb->travlocks.lock_rw = F_RDLCK;
/* Grab first record: locks chain and returned record. */
@@ -338,7 +330,7 @@ _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
tdb_trace_retrec(tdb, "tdb_firstkey", key);
/* Unlock the hash chain of the record we just read. */
- if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
return key;
}
@@ -346,7 +338,7 @@ _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
/* find the next entry in the database, returning its key */
_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
{
- uint32_t oldhash;
+ uint32_t oldlist;
TDB_DATA key = tdb_null;
struct tdb_record rec;
unsigned char *k = NULL;
@@ -354,7 +346,7 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
/* Is locked key the old key? If so, traverse will be reliable. */
if (tdb->travlocks.off) {
- if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw))
+ if (tdb_lock(tdb,tdb->travlocks.list,tdb->travlocks.lock_rw))
return tdb_null;
if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1
|| !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
@@ -367,7 +359,7 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
SAFE_FREE(k);
return tdb_null;
}
- if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) {
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0) {
SAFE_FREE(k);
return tdb_null;
}
@@ -384,13 +376,13 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null);
return tdb_null;
}
- tdb->travlocks.hash = BUCKET(rec.full_hash);
+ tdb->travlocks.list = BUCKET(rec.full_hash);
if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
return tdb_null;
}
}
- oldhash = tdb->travlocks.hash;
+ oldlist = tdb->travlocks.list;
/* Grab next record: locks chain and returned record,
unlocks old record */
@@ -400,11 +392,11 @@ _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
key.dsize);
/* Unlock the chain of this new record */
- if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
}
/* Unlock the chain of old record */
- if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0)
+ if (tdb_unlock(tdb, oldlist, tdb->travlocks.lock_rw) != 0)
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key);
return key;
diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h
index e86d267..535f07a 100644
--- a/lib/tdb/include/tdb.h
+++ b/lib/tdb/include/tdb.h
@@ -651,15 +651,36 @@ tdb_log_func tdb_log_fn(struct tdb_context *tdb);
void *tdb_get_logging_private(struct tdb_context *tdb);
/**
+ * @brief Is a transaction active?
+ *
+ * It is helpful for the application to know if a transaction is
+ * active, rather than needing to maintain an application-level reference
+ * count.
+ *
+ * @param[in] tdb The database to start the transaction.
+ *
+ * @return true if there is a transaction active, false otherwise
+ *
+ * @see tdb_transaction_start()
+ * @see tdb_transaction_prepare_commit()
+ * @see tdb_transaction_commit()
+ * @see tdb_transaction_cancel()
+ */
+bool tdb_transaction_active(struct tdb_context *tdb);
+
+/**
* @brief Start a transaction.
*
* All operations after the transaction start can either be committed with
* tdb_transaction_commit() or cancelled with tdb_transaction_cancel().
*
- * If you call tdb_transaction_start() again on the same tdb context while a
- * transaction is in progress, then the same transaction buffer is re-used. The
- * number of tdb_transaction_{commit,cancel} operations must match the number
- * of successful tdb_transaction_start() calls.
+ * If (the default) TDB_ALLOW_NESTING was specified or
+ * TDB_DISALLOW_NESTING was not specified as a flag via tdb_open() or
+ * tdb_open_ex(), you call tdb_transaction_start() again on the same
+ * tdb context while a transaction is in progress, then the same
+ * transaction buffer is re-used. The number of
+ * tdb_transaction_{commit,cancel} operations must match the number of
+ * successful tdb_transaction_start() calls.
*
* Note that transactions are by default disk synchronous, and use a recover
* area in the database to automatically recover the database on the next open
diff --git a/lib/tdb/man/tdbbackup.8.xml b/lib/tdb/man/tdbbackup.8.xml
index 740b3d5..a73fb56 100644
--- a/lib/tdb/man/tdbbackup.8.xml
+++ b/lib/tdb/man/tdbbackup.8.xml
@@ -23,6 +23,7 @@
<arg choice="opt">-s suffix</arg>
<arg choice="opt">-v</arg>
<arg choice="opt">-h</arg>
+ <arg choice="opt">-n hashsize</arg>
<arg choice="opt">-l</arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -71,6 +72,13 @@
</varlistentry>
<varlistentry>
+ <term>-n hashsize</term>
+ <listitem><para>
+ The <command>-n</command> option sets the hash size for the new backup tdb.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-l</term>
<listitem><para>
This options disables any locking, by passing TDB_NOLOCK
diff --git a/lib/tdb/man/tdbtool.8.xml b/lib/tdb/man/tdbtool.8.xml
index 9a9b95e..045cbde 100644
--- a/lib/tdb/man/tdbtool.8.xml
+++ b/lib/tdb/man/tdbtool.8.xml
@@ -160,6 +160,16 @@
</varlistentry>
<varlistentry>
+ <term><option>storehex</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>DATA</replaceable>
+ </term>
+ <listitem><para>Store (replace) a record in the
+ current database where key and data are in hex format.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>show</option>
<replaceable>KEY</replaceable>
</term>
diff --git a/lib/tdb/test/run-fcntl-deadlock.c b/lib/tdb/test/run-fcntl-deadlock.c
new file mode 100644
index 0000000..0a328af
--- /dev/null
+++ b/lib/tdb/test/run-fcntl-deadlock.c
@@ -0,0 +1,202 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include <errno.h>
+#include "tap-interface.h"
+
+/*
+ * This tests the low level locking requirement
+ * for the allrecord lock/prepare_commit and traverse_read interaction.
+ *
+ * The pattern with the traverse_read and prepare_commit interaction is
+ * the following:
+ *
+ * 1. transaction_start got the allrecord lock with F_RDLCK.
+ *
+ * 2. the traverse_read code walks the database in a sequence like this
+ * (per chain):
+ * 2.1 chainlock(chainX, F_RDLCK)
+ * 2.2 recordlock(chainX.record1, F_RDLCK)
+ * 2.3 chainunlock(chainX, F_RDLCK)
+ * 2.4 callback(chainX.record1)
+ * 2.5 chainlock(chainX, F_RDLCK)
+ * 2.6 recordunlock(chainX.record1, F_RDLCK)
+ * 2.7 recordlock(chainX.record2, F_RDLCK)
+ * 2.8 chainunlock(chainX, F_RDLCK)
+ * 2.9 callback(chainX.record2)
+ * 2.10 chainlock(chainX, F_RDLCK)
+ * 2.11 recordunlock(chainX.record2, F_RDLCK)
+ * 2.12 chainunlock(chainX, F_RDLCK)
+ * 2.13 goto next chain
+ *
+ * So it has always one record locked in F_RDLCK mode and tries to
+ * get the 2nd one before it releases the first one.
+ *
+ * 3. prepare_commit tries to upgrade the allrecord lock to F_RWLCK
+ * If that happens at the time of 2.4, the operation of
+ * 2.5 may deadlock with the allrecord lock upgrade.
+ * On Linux step 2.5 works in order to make some progress with the
+ * locking, but on solaris it might fail because the kernel
+ * wants to satisfy the 1st lock requester before the 2nd one.
+ *
+ * I think the first step is a standalone test that does this:
+ *
+ * process1: F_RDLCK for ofs=0 len=2
+ * process2: F_RDLCK for ofs=0 len=1
+ * process1: upgrade ofs=0 len=2 to F_RWLCK (in blocking mode)
+ * process2: F_RDLCK for ofs=1 len=1
+ * process2: unlock ofs=0 len=2
+ * process1: should continue at that point
+ *
+ * Such a test follows here...
+ */
+
+static int raw_fcntl_lock(int fd, int rw, off_t off, off_t len, bool waitflag)
+{
+ struct flock fl;
+ int cmd;
+ fl.l_type = rw;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ cmd = waitflag ? F_SETLKW : F_SETLK;
+
+ return fcntl(fd, cmd, &fl);
+}
+
+static int raw_fcntl_unlock(int fd, off_t off, off_t len)
+{
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ return fcntl(fd, F_SETLKW, &fl);
+}
+
+
+int pipe_r;
+int pipe_w;
+char buf[2];
+
+static void expect_char(char c)
+{
+ read(pipe_r, buf, 1);
+ if (*buf != c) {
+ fail("We were expecting %c, but got %c", c, buf[0]);
+ }
+}
+
+static void send_char(char c)
+{
+ write(pipe_w, &c, 1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int process;
+ int fd;
+ const char *filename = "run-fcntl-deadlock.lck";
+ int pid;
+ int pipes_1_2[2];
+ int pipes_2_1[2];
+ int ret;
+
+ pipe(pipes_1_2);
+ pipe(pipes_2_1);
+ fd = open(filename, O_RDWR | O_CREAT, 0755);
+
+ pid = fork();
+ if (pid == 0) {
+ pipe_r = pipes_1_2[0];
+ pipe_w = pipes_2_1[1];
+ process = 2;
+ alarm(15);
+ } else {
+ pipe_r = pipes_2_1[0];
+ pipe_w = pipes_1_2[1];
+ process = 1;
+ alarm(15);
+ }
+
+ /* a: process1: F_RDLCK for ofs=0 len=2 */
+ if (process == 1) {
+ ret = raw_fcntl_lock(fd, F_RDLCK, 0, 2, true);
+ ok(ret == 0,
+ "process 1 lock ofs=0 len=2: %d - %s",
+ ret, strerror(errno));
+ diag("process 1 took read lock on range 0,2");
+ send_char('a');
+ }
+
+ /* process2: F_RDLCK for ofs=0 len=1 */
+ if (process == 2) {
+ expect_char('a');
+ ret = raw_fcntl_lock(fd, F_RDLCK, 0, 1, true);
+ ok(ret == 0,
+ "process 2 lock ofs=0 len=1: %d - %s",
+ ret, strerror(errno));;
+ diag("process 2 took read lock on range 0,1");
+ send_char('b');
+ }
+
+ /* process1: upgrade ofs=0 len=2 to F_RWLCK (in blocking mode) */
+ if (process == 1) {
+ expect_char('b');
+ send_char('c');
+ diag("process 1 starts upgrade on range 0,2");
+ ret = raw_fcntl_lock(fd, F_WRLCK, 0, 2, true);
+ ok(ret == 0,
+ "process 1 RW lock ofs=0 len=2: %d - %s",
+ ret, strerror(errno));
+ diag("process 1 got read upgrade done");
+ /* at this point process 1 is blocked on 2 releasing the
+ read lock */
+ }
+
+ /*
+ * process2: F_RDLCK for ofs=1 len=1
+ * process2: unlock ofs=0 len=2
+ */
+ if (process == 2) {
+ expect_char('c'); /* we know process 1 is *about* to lock */
+ sleep(1);
+ ret = raw_fcntl_lock(fd, F_RDLCK, 1, 1, true);
+ ok(ret == 0,
+ "process 2 lock ofs=1 len=1: %d - %s",
+ ret, strerror(errno));
+ diag("process 2 got read lock on 1,1\n");
+ ret = raw_fcntl_unlock(fd, 0, 2);
+ ok(ret == 0,
+ "process 2 unlock ofs=0 len=2: %d - %s",
+ ret, strerror(errno));
+ diag("process 2 released read lock on 0,2\n");
+ sleep(1);
+ send_char('d');
+ }
+
+ if (process == 1) {
+ expect_char('d');
+ }
+
+ diag("process %d has got to the end\n", process);
+
+ return 0;
+}
diff --git a/lib/tdb/test/run-nested-traverse.c b/lib/tdb/test/run-nested-traverse.c
index 22ee3e2..aeaa085 100644
--- a/lib/tdb/test/run-nested-traverse.c
+++ b/lib/tdb/test/run-nested-traverse.c
@@ -41,7 +41,30 @@ static int traverse2(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
return 0;
}
-static int traverse1(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+static int traverse1r(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *p)
+{
+ ok1(correct_key(key));
+ ok1(correct_data(data));
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, STORE, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ tdb_traverse(tdb, traverse2, NULL);
+
+ /* That should *not* release the all-records lock! */
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, STORE, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ return 0;
+}
+
+static int traverse1w(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
void *p)
{
ok1(correct_key(key));
@@ -50,7 +73,7 @@ static int traverse1(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
== WOULD_HAVE_BLOCKED);
tdb_traverse(tdb, traverse2, NULL);
- /* That should *not* release the transaction lock! */
+ /* That should *not* release the all-records lock! */
ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
== WOULD_HAVE_BLOCKED);
return 0;
@@ -80,8 +103,8 @@ int main(int argc, char *argv[])
data.dsize = strlen("world");
ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- tdb_traverse(tdb, traverse1, NULL);
- tdb_traverse_read(tdb, traverse1, NULL);
+ tdb_traverse(tdb, traverse1w, NULL);
+ tdb_traverse_read(tdb, traverse1r, NULL);
tdb_close(tdb);
return exit_status();
diff --git a/lib/tdb/test/run-rdlock-upgrade.c b/lib/tdb/test/run-rdlock-upgrade.c
new file mode 100644
index 0000000..042001b
--- /dev/null
+++ b/lib/tdb/test/run-rdlock-upgrade.c
@@ -0,0 +1,166 @@
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+#include "logging.h"
+
+static TDB_DATA key, data;
+
+static void do_chainlock(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock_read(tdb, key);
+ ok(ret == 0, "tdb_chainlock_read should succeed");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == 0, "read should succeed");
+
+ exit(0);
+}
+
+static void do_trylock(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ /*
+ * tdb used to have a bug where with fcntl locks an upgrade
+ * from a readlock to writelock did not check for the
+ * underlying fcntl lock. Mutexes don't distinguish between
+ * readlocks and writelocks, so that bug does not apply here.
+ */
+
+ ret = tdb_chainlock_read(tdb, key);
+ ok(ret == 0, "tdb_chainlock_read should succeed");
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should fail");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == 0, "read should succeed");
+
+ exit(0);
+}
+
+static int do_tests(const char *name, int tdb_flags)
+{
+ int ret;
+ pid_t chainlock_child, store_child;
+ int chainlock_down[2];
+ int chainlock_up[2];
+ int store_down[2];
+ int store_up[2];
+ char c;
+ ssize_t nread;
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ret = pipe(chainlock_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(chainlock_up);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(store_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(store_up);
+ ok(ret == 0, "pipe should succeed");
+
+ chainlock_child = fork();
+ ok(chainlock_child != -1, "fork should succeed");
+
+ if (chainlock_child == 0) {
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(store_up[0]);
+ close(store_up[1]);
+ close(store_down[0]);
+ close(store_down[1]);
+ do_chainlock(name, tdb_flags,
+ chainlock_up[1], chainlock_down[0]);
+ exit(0);
+ }
+ close(chainlock_up[1]);
+ close(chainlock_down[0]);
+
+ nread = read(chainlock_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ /*
+ * Now we have a process holding a chain read lock. Start
+ * another process trying to write lock. This should fail.
+ */
+
+ store_child = fork();
+ ok(store_child != -1, "fork should succeed");
+
+ if (store_child == 0) {
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(store_up[0]);
+ close(store_down[1]);
+ do_trylock(name, tdb_flags,
+ store_up[1], store_down[0]);
+ exit(0);
+ }
+ close(store_up[1]);
+ close(store_down[0]);
+
+ nread = read(store_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(store_up[0]);
+ close(store_down[1]);
+ diag("%s tests done", name);
+ return exit_status();
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ ret = do_tests("rdlock-upgrade.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "rdlock-upgrade.tdb tests should succeed");
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-traverse-in-transaction.c b/lib/tdb/test/run-traverse-in-transaction.c
index 17d6412..d187b9b 100644
--- a/lib/tdb/test/run-traverse-in-transaction.c
+++ b/lib/tdb/test/run-traverse-in-transaction.c
@@ -63,7 +63,9 @@ int main(int argc, char *argv[])
ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS);
+ ok1(tdb_transaction_active(tdb) == 0);
ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_transaction_active(tdb) == 1);
ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
== WOULD_HAVE_BLOCKED);
tdb_traverse(tdb, traverse, NULL);
@@ -77,6 +79,7 @@ int main(int argc, char *argv[])
ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
== WOULD_HAVE_BLOCKED);
ok1(tdb_transaction_commit(tdb) == 0);
+ ok1(tdb_transaction_active(tdb) == 0);
/* Now we should be fine. */
ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
== SUCCESS);
diff --git a/lib/tdb/tools/tdbtool.c b/lib/tdb/tools/tdbtool.c
index beb3af1..e3535b9 100644
--- a/lib/tdb/tools/tdbtool.c
+++ b/lib/tdb/tools/tdbtool.c
@@ -48,6 +48,7 @@ enum commands {
CMD_DUMP,
CMD_INSERT,
CMD_MOVE,
+ CMD_STOREHEX,
CMD_STORE,
CMD_SHOW,
CMD_KEYS,
@@ -83,6 +84,7 @@ COMMAND_TABLE cmd_table[] = {
{"dump", CMD_DUMP},
{"insert", CMD_INSERT},
{"move", CMD_MOVE},
+ {"storehex", CMD_STOREHEX},
{"store", CMD_STORE},
{"show", CMD_SHOW},
{"keys", CMD_KEYS},
@@ -229,6 +231,7 @@ static void help(void)
" info : print summary info about the database\n"
" insert key data : insert a record\n"
" move key file : move a record to a destination tdb\n"
+" storehex key data : store a record (replace), key/value in hex format\n"
" store key data : store a record (replace)\n"
" show key : show a record by key\n"
" delete key : delete a record by key\n"
@@ -346,6 +349,86 @@ static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
}
}
+static bool hexchar(char c, uint8_t *v)
+{
+ if ((c >= '0') && (c <= '9')) {
+ *v = (c - '0');
+ return true;
+ }
+ if ((c >= 'A') && (c <= 'F')) {
+ *v = (c - 'A' + 10);
+ return true;
+ }
+ if ((c >= 'a') && (c <= 'f')) {
+ *v = (c - 'a' + 10);
+ return true;
+ }
+ return false;
+}
+
+static bool parse_hex(const char *src, size_t srclen, uint8_t *dst)
+{
+ size_t i=0;
+
+ if ((srclen % 2) != 0) {
+ return false;
+ }
+
+ while (i<srclen) {
+ bool ok;
+ uint8_t hi,lo;
+
+ ok = (hexchar(src[i++], &hi) && hexchar(src[i++], &lo));
+ if (!ok) {
+ return false;
+ }
+ *dst = (hi<<4)|lo;
+ dst += 1;
+ }
+
+ return true;
+}
+
+static void store_hex_tdb(char *keystr, size_t keylen,
+ char *datastr, size_t datalen)
+{
+ if ((keystr == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+ if ((datastr == NULL) || (datalen == 0)) {
+ terror("need data");
+ return;
+ }
+
+ {
+ uint8_t keybuf[keylen/2];
+ TDB_DATA key = { .dptr = keybuf, .dsize = sizeof(keybuf) };
+ uint8_t databuf[datalen/2];
+ TDB_DATA data = { .dptr = databuf, .dsize = sizeof(databuf) };
+ bool ok;
+
+ ok = parse_hex(keystr, keylen, keybuf);
+ if (!ok) {
+ terror("need hex key");
+ return;
+ }
+ ok = parse_hex(datastr, datalen, databuf);
+ if (!ok) {
+ terror("need hex data");
+ return;
+ }
+
+ printf("storing key/data:\n");
+ print_data((char *)key.dptr, key.dsize);
+ print_data((char *)data.dptr, data.dsize);
+
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) {
+ terror("store failed");
+ }
+ }
+}
+
static void show_tdb(char *keyname, size_t keylen)
{
TDB_DATA key, dbuf;
@@ -693,6 +776,10 @@ static int do_command(void)
bIterate = 0;
store_tdb(arg1,arg1len,arg2,arg2len);
return 0;
+ case CMD_STOREHEX:
+ bIterate = 0;
+ store_hex_tdb(arg1,arg1len,arg2,arg2len);
+ return 0;
case CMD_SHOW:
bIterate = 0;
show_tdb(arg1, arg1len);
diff --git a/lib/tdb/wscript b/lib/tdb/wscript
index 34058e4..11bc0db 100644
--- a/lib/tdb/wscript
+++ b/lib/tdb/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tdb'
-VERSION = '1.3.12'
+VERSION = '1.3.15'
blddir = 'bin'
@@ -34,12 +34,14 @@ tdb1_unit_tests = [
'run-readonly-check',
'run-rescue',
'run-rescue-find_entry',
+ 'run-rdlock-upgrade',
'run-rwlock-check',
'run-summary',
'run-transaction-expand',
'run-traverse-in-transaction',
'run-wronghash-fail',
'run-zero-append',
+ 'run-fcntl-deadlock',
'run-marklock-deadlock',
'run-allrecord-traverse-deadlock',
'run-mutex-openflags2',
@@ -60,10 +62,6 @@ def set_options(opt):
help=("Disable the use of pthread robust mutexes"),
action="store_true", dest='disable_tdb_mutex_locking',
default=False)
- if opt.IN_LAUNCH_DIR():
- opt.add_option('--disable-python',
- help=("disable the pytdb module"),
- action="store_true", dest='disable_python', default=False)
def configure(conf):
@@ -82,11 +80,10 @@ def configure(conf):
implied_deps='replace'):
conf.define('USING_SYSTEM_TDB', 1)
conf.env.building_tdb = False
- if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION):
+ if not conf.env.disable_python and \
+ conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION):
conf.define('USING_SYSTEM_PYTDB', 1)
- conf.env.disable_python = getattr(Options.options, 'disable_python', False)
-
if (conf.CONFIG_SET('HAVE_ROBUST_MUTEXES') and
conf.env.building_tdb and
not conf.env.disable_tdb_mutex_locking):
diff --git a/lib/tevent/ABI/tevent-0.9.32.sigs b/lib/tevent/ABI/tevent-0.9.32.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.32.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.33.sigs b/lib/tevent/ABI/tevent-0.9.33.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.33.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/release-script.sh b/lib/tevent/release-script.sh
deleted file mode 100755
index 077f562..0000000
--- a/lib/tevent/release-script.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-
-if [ "$1" = "" ]; then
- echo "Please provide version string, eg: 1.2.0"
- exit 1
-fi
-
-if [ ! -d "lib/tevent" ]; then
- echo "Run this script from the samba base directory."
- exit 1
-fi
-
-git clean -f -x -d lib/tevent
-git clean -f -x -d lib/replace
-
-curbranch=`git-branch |grep "^*" | tr -d "* "`
-
-version=$1
-strver=`echo ${version} | tr "." "-"`
-
-# Checkout the release tag
-git branch -f tevent-release-script-${strver} tevent-${strver}
-if [ ! "$?" = "0" ]; then
- echo "Unable to checkout tevent-${strver} release"
- exit 1
-fi
-
-git checkout tevent-release-script-${strver}
-
-# Test configure agrees with us
-confver=`grep "^AC_INIT" lib/tevent/configure.ac | tr -d "AC_INIT(tevent, " | tr -d ")"`
-if [ ! "$confver" = "$version" ]; then
- echo "Wrong version, requested release for ${version}, found ${confver}"
- exit 1
-fi
-
-# Now build tarball
-cp -a lib/tevent tevent-${version}
-cp -a lib/replace tevent-${version}/libreplace
-pushd tevent-${version}
-./autogen.sh
-popd
-tar cvzf tevent-${version}.tar.gz tevent-${version}
-rm -fr tevent-${version}
-
-#Clean up
-git checkout $curbranch
-git branch -d tevent-release-script-${strver}
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 4783ab4..e508452 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -25,7 +25,7 @@
*/
#include "includes.h"
-#include "lib/tevent/tevent.h"
+#include "tevent.h"
#include "system/filesys.h"
#include "system/select.h"
#include "system/network.h"
@@ -1207,6 +1207,14 @@ static bool test_multi_tevent_threaded_2(struct torture_context *test,
ev = tevent_context_init(test);
torture_assert(test, ev != NULL, "tevent_context_init failed");
+ /*
+ * tevent_re_initialise used to have a bug where it did not
+ * re-initialise the thread support after taking it
+ * down. Excercise that code path.
+ */
+ ret = tevent_re_initialise(ev);
+ torture_assert(test, ret == 0, "tevent_re_initialise failed");
+
tctx = tevent_threaded_context_create(ev, ev);
torture_assert(test, tctx != NULL,
"tevent_threaded_context_create failed");
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 65b101f..5f44b03 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -341,6 +341,11 @@ int tevent_common_context_destructor(struct tevent_context *ev)
DLIST_REMOVE(ev->threaded_contexts, tctx);
}
+
+ ret = pthread_mutex_destroy(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
#endif
tevent_common_wakeup_fini(ev);
@@ -392,46 +397,26 @@ int tevent_common_context_destructor(struct tevent_context *ev)
return 0;
}
-/*
- create a event_context structure for a specific implemementation.
- This must be the first events call, and all subsequent calls pass
- this event_context as the first element. Event handlers also
- receive this as their first argument.
-
- This function is for allowing third-party-applications to hook in gluecode
- to their own event loop code, so that they can make async usage of our client libs
-
- NOTE: use tevent_context_init() inside of samba!
-*/
-struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
- const struct tevent_ops *ops,
- void *additional_data)
+static int tevent_common_context_constructor(struct tevent_context *ev)
{
- struct tevent_context *ev;
int ret;
- ev = talloc_zero(mem_ctx, struct tevent_context);
- if (!ev) return NULL;
-
#ifdef HAVE_PTHREAD
ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork);
if (ret != 0) {
- talloc_free(ev);
- return NULL;
+ return ret;
}
ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
if (ret != 0) {
- talloc_free(ev);
- return NULL;
+ return ret;
}
ret = pthread_mutex_lock(&tevent_contexts_mutex);
if (ret != 0) {
pthread_mutex_destroy(&ev->scheduled_mutex);
- talloc_free(ev);
- return NULL;
+ return ret;
}
DLIST_ADD(tevent_contexts, ev);
@@ -440,11 +425,40 @@ struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
if (ret != 0) {
abort();
}
-
#endif
talloc_set_destructor(ev, tevent_common_context_destructor);
+ return 0;
+}
+
+/*
+ create a event_context structure for a specific implemementation.
+ This must be the first events call, and all subsequent calls pass
+ this event_context as the first element. Event handlers also
+ receive this as their first argument.
+
+ This function is for allowing third-party-applications to hook in gluecode
+ to their own event loop code, so that they can make async usage of our client libs
+
+ NOTE: use tevent_context_init() inside of samba!
+*/
+struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
+ const struct tevent_ops *ops,
+ void *additional_data)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ ev = talloc_zero(mem_ctx, struct tevent_context);
+ if (!ev) return NULL;
+
+ ret = tevent_common_context_constructor(ev);
+ if (ret != 0) {
+ talloc_free(ev);
+ return NULL;
+ }
+
ev->ops = ops;
ev->additional_data = additional_data;
@@ -602,16 +616,7 @@ struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
im = talloc(mem_ctx, struct tevent_immediate);
if (im == NULL) return NULL;
- im->prev = NULL;
- im->next = NULL;
- im->event_ctx = NULL;
- im->create_location = location;
- im->handler = NULL;
- im->private_data = NULL;
- im->handler_name = NULL;
- im->schedule_location = NULL;
- im->cancel_fn = NULL;
- im->additional_data = NULL;
+ *im = (struct tevent_immediate) { .create_location = location };
return im;
}
@@ -875,6 +880,8 @@ int tevent_re_initialise(struct tevent_context *ev)
{
tevent_common_context_destructor(ev);
+ tevent_common_context_constructor(ev);
+
return ev->ops->context_init(ev);
}
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index ba4bb4d..728cf62 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -1777,7 +1777,7 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
*
* It is the duty of the caller of tevent_threaded_context_create() to
* keep the event context around longer than any
- * tevent_threaded_context. tevent will abort if ev is talllc_free'ed
+ * tevent_threaded_context. tevent will abort if ev is talloc_free'ed
* with an active tevent_threaded_context.
*
* If tevent is build without pthread support, this always returns
diff --git a/lib/tevent/tevent.py b/lib/tevent/tevent.py
index c296544..7045504 100644
--- a/lib/tevent/tevent.py
+++ b/lib/tevent/tevent.py
@@ -1,4 +1,3 @@
-#!/usr/bin/python
#
# Python integration for tevent
#
diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
index e309c3d..15754d3 100644
--- a/lib/tevent/tevent_req.c
+++ b/lib/tevent/tevent_req.c
@@ -31,19 +31,24 @@ char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
{
return talloc_asprintf(mem_ctx,
"tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
- " state[%s (%p)] timer[%p]",
+ " state[%s (%p)] timer[%p] finish[%s]",
req, req->internal.create_location,
req->internal.state,
(unsigned long long)req->internal.error,
(unsigned long long)req->internal.error,
- talloc_get_name(req->data),
+ req->internal.private_type,
req->data,
- req->internal.timer
+ req->internal.timer,
+ req->internal.finish_location
);
}
char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
{
+ if (req == NULL) {
+ return talloc_strdup(mem_ctx, "tevent_req[NULL]");
+ }
+
if (!req->private_print) {
return tevent_req_default_print(req, mem_ctx);
}
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 8197323..4d1a880 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -381,6 +381,23 @@ static int tevent_threaded_context_destructor(
DLIST_REMOVE(tctx->event_ctx->threaded_contexts, tctx);
}
+ /*
+ * We have to coordinate with _tevent_threaded_schedule_immediate's
+ * unlock of the event_ctx_mutex. We're in the main thread here,
+ * and we can be scheduled before the helper thread finalizes its
+ * call _tevent_threaded_schedule_immediate. This means we would
+ * pthreadpool_destroy a locked mutex, which is illegal.
+ */
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
ret = pthread_mutex_destroy(&tctx->event_ctx_mutex);
if (ret != 0) {
abort();
@@ -443,15 +460,14 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
ev = tctx->event_ctx;
- ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
- if (ret != 0) {
- abort();
- }
-
if (ev == NULL) {
/*
* Our event context is already gone.
*/
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
return;
}
@@ -479,6 +495,11 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
abort();
}
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
/*
* We might want to wake up the main thread under the lock. We
* had a slightly similar situation in pthreadpool, changed
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 580ca4d..bc874bb 100755..100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tevent'
-VERSION = '0.9.31'
+VERSION = '0.9.33'
blddir = 'bin'
@@ -22,10 +22,6 @@ def set_options(opt):
opt.PRIVATE_EXTENSION_DEFAULT('tevent', noextension='tevent')
opt.RECURSE('lib/replace')
opt.RECURSE('lib/talloc')
- if opt.IN_LAUNCH_DIR():
- opt.add_option('--disable-python',
- help=("disable the pytevent module"),
- action="store_true", dest='disable_python', default=False)
def configure(conf):
@@ -38,7 +34,8 @@ def configure(conf):
if conf.CHECK_BUNDLED_SYSTEM_PKG('tevent', minversion=VERSION,
onlyif='talloc', implied_deps='replace talloc'):
conf.define('USING_SYSTEM_TEVENT', 1)
- if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytevent', 'tevent', minversion=VERSION):
+ if not conf.env.disable_python and \
+ conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytevent', 'tevent', minversion=VERSION):
conf.define('USING_SYSTEM_PYTEVENT', 1)
if conf.CHECK_FUNCS('epoll_create', headers='sys/epoll.h'):
@@ -61,8 +58,6 @@ def configure(conf):
if not conf.CONFIG_SET('USING_SYSTEM_TEVENT'):
conf.DEFINE('TEVENT_NUM_SIGNALS', tevent_num_signals)
- conf.env.disable_python = getattr(Options.options, 'disable_python', False)
-
if not conf.env.disable_python:
# also disable if we don't have the python libs installed
conf.find_program('python', var='PYTHON')
diff --git a/man/ldb.3.xml b/man/ldb.3.xml
index b93d532..b832d0c 100644
--- a/man/ldb.3.xml
+++ b/man/ldb.3.xml
@@ -248,7 +248,7 @@ ldb_search(3) manual pages.
<para>
ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/man/ldbadd.1.xml b/man/ldbadd.1.xml
index 3a3ed2c..db360a1 100644
--- a/man/ldbadd.1.xml
+++ b/man/ldbadd.1.xml
@@ -92,7 +92,7 @@
<title>AUTHOR</title>
<para> ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/man/ldbdel.1.xml b/man/ldbdel.1.xml
index d57cf2a..18bef3c 100644
--- a/man/ldbdel.1.xml
+++ b/man/ldbdel.1.xml
@@ -90,7 +90,7 @@
<title>AUTHOR</title>
<para> ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/man/ldbedit.1.xml b/man/ldbedit.1.xml
index fd98c60..627d20c 100644
--- a/man/ldbedit.1.xml
+++ b/man/ldbedit.1.xml
@@ -184,7 +184,7 @@
<para>
ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/man/ldbmodify.1.xml b/man/ldbmodify.1.xml
index 5d6b468..405e47a 100644
--- a/man/ldbmodify.1.xml
+++ b/man/ldbmodify.1.xml
@@ -80,7 +80,7 @@
<title>AUTHOR</title>
<para> ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/man/ldbrename.1.xml b/man/ldbrename.1.xml
index 102cee4..81472a6 100644
--- a/man/ldbrename.1.xml
+++ b/man/ldbrename.1.xml
@@ -94,7 +94,7 @@
<title>AUTHOR</title>
<para> ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/man/ldbsearch.1.xml b/man/ldbsearch.1.xml
index e693a29..abf369d 100644
--- a/man/ldbsearch.1.xml
+++ b/man/ldbsearch.1.xml
@@ -106,7 +106,7 @@
<title>AUTHOR</title>
<para> ldb was written by
- <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
diff --git a/pyldb-util.pc.in b/pyldb-util.pc.in
index 348ae8b..60ec702 100644
--- a/pyldb-util.pc.in
+++ b/pyldb-util.pc.in
@@ -4,10 +4,10 @@ libdir=@libdir@
includedir=@includedir@
modulesdir=@LDB_MODULESDIR@
-Name: pyldb-util
+Name: pyldb-util@PYTHON_SO_ABI_FLAG@
Description: Python bindings for LDB
Version: @PACKAGE_VERSION@
Requires: ldb
-Libs: @LIB_RPATH@ -L${libdir} -lpyldb-util
+Libs: @LIB_RPATH@ -L${libdir} -lpyldb-util@PYTHON_LIBNAME_SO_ABI_FLAG@
Cflags: -I${includedir}
URL: http://ldb.samba.org/
diff --git a/pyldb.c b/pyldb.c
index bea837f..515a69e 100644
--- a/pyldb.c
+++ b/pyldb.c
@@ -3047,7 +3047,7 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
if (py_elements != NULL) {
Py_ssize_t i;
- if (PyBytes_Check(py_elements)) {
+ if (PyBytes_Check(py_elements) || PyStr_Check(py_elements)) {
char *_msg = NULL;
el->num_values = 1;
el->values = talloc_array(el, struct ldb_val, 1);
@@ -3056,12 +3056,17 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
PyErr_NoMemory();
return NULL;
}
- result = PyBytes_AsStringAndSize(py_elements, &_msg, &size);
+ if (PyBytes_Check(py_elements)) {
+ result = PyBytes_AsStringAndSize(py_elements, &_msg, &size);
+ msg = _msg;
+ } else {
+ msg = PyStr_AsUTF8AndSize(py_elements, &size);
+ result = (msg == NULL) ? -1 : 0;
+ }
if (result != 0) {
talloc_free(mem_ctx);
return NULL;
}
- msg = _msg;
el->values[0].data = talloc_memdup(el->values,
(const uint8_t *)msg, size + 1);
el->values[0].length = size;
@@ -3944,7 +3949,7 @@ static PyObject *py_register_module(PyObject *module, PyObject *args)
if (!PyArg_ParseTuple(args, "O", &input))
return NULL;
- ops = talloc_zero(talloc_autofree_context(), struct ldb_module_ops);
+ ops = talloc_zero(NULL, struct ldb_module_ops);
if (ops == NULL) {
PyErr_NoMemory();
return NULL;
@@ -3967,6 +3972,9 @@ static PyObject *py_register_module(PyObject *module, PyObject *args)
ops->del_transaction = py_module_del_transaction;
ret = ldb_register_module(ops);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(ops);
+ }
PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, NULL);
diff --git a/tests/ldb_mod_op_test.c b/tests/ldb_mod_op_test.c
new file mode 100644
index 0000000..5e439f8
--- /dev/null
+++ b/tests/ldb_mod_op_test.c
@@ -0,0 +1,2987 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#define TEVENT_DEPRECATED 1
+#include <tevent.h>
+
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+
+#define DEFAULT_BE "tdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int ldbtest_noconn_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static void test_connect(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ int ret;
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+}
+
+static struct ldb_message *get_test_ldb_message(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb)
+{
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ int ret;
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new(msg, ldb, "dc=samba,dc=org");
+ assert_non_null(msg->dn);
+ ret = ldb_msg_add_string(msg, "public", "key");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "supersecret", "password");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "binary", "\xff\xff\0");
+ assert_int_equal(ret, LDB_SUCCESS);
+ return msg;
+}
+
+static void test_ldif_message(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *got_ldif;
+ const char *expected_ldif =
+ "dn: dc=samba,dc=org\n"
+ "changetype: add\n"
+ "public: key\n"
+ "supersecret: password\n"
+ "binary:: //8=\n"
+ "\n";
+
+ struct ldb_message *msg = get_test_ldb_message(test_ctx,
+ test_ctx->ldb);
+
+ got_ldif = ldb_ldif_message_string(test_ctx->ldb,
+ test_ctx,
+ LDB_CHANGETYPE_ADD,
+ msg);
+ assert_string_equal(got_ldif, expected_ldif);
+ TALLOC_FREE(got_ldif);
+}
+
+static void test_ldif_message_redacted(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ int ret;
+ char *got_ldif;
+ const char *expected_ldif =
+ "dn: dc=samba,dc=org\n"
+ "changetype: add\n"
+ "public: key\n"
+ "# supersecret::: REDACTED SECRET ATTRIBUTE\n"
+ "binary:: //8=\n"
+ "\n";
+
+ const char *secret_attrs[] = {
+ "supersecret",
+ NULL
+ };
+
+ struct ldb_message *msg = ldb_msg_new(test_ctx);
+
+ ldb_set_opaque(test_ctx->ldb,
+ LDB_SECRET_ATTRIBUTE_LIST_OPAQUE,
+ secret_attrs);
+
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new(msg, test_ctx->ldb, "dc=samba,dc=org");
+ ret = ldb_msg_add_string(msg, "public", "key");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "supersecret", "password");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "binary", "\xff\xff\0");
+ assert_int_equal(ret, LDB_SUCCESS);
+ got_ldif = ldb_ldif_message_redacted_string(test_ctx->ldb,
+ test_ctx,
+ LDB_CHANGETYPE_ADD,
+ msg);
+ assert_string_equal(got_ldif, expected_ldif);
+ TALLOC_FREE(got_ldif);
+ assert_int_equal(ret, 0);
+}
+
+static int ldbtest_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ int ret;
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_ldb_add(void **state)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_search(void **state)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_dn *basedn2;
+ struct ldb_result *result = NULL;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = basedn;
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val1");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ basedn2 = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test2");
+ assert_non_null(basedn2);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = basedn2;
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val2");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+ ldb_dn_get_linearized(basedn));
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn2,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+ ldb_dn_get_linearized(basedn2));
+
+ talloc_free(tmp_ctx);
+}
+
+static int base_search_count(struct ldbtest_ctx *test_ctx, const char *entry_dn)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ int ret;
+ int count;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", entry_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+
+ count = result->count;
+ talloc_free(tmp_ctx);
+ return count;
+}
+
+static int sub_search_count(struct ldbtest_ctx *test_ctx,
+ const char *base_dn,
+ const char *filter)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ int ret;
+ int count;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_SUBTREE, NULL, "%s", filter);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+
+ count = result->count;
+ talloc_free(tmp_ctx);
+ return count;
+}
+
+/* In general it would be better if utility test functions didn't assert
+ * but only returned a value, then assert in the test shows correct
+ * line
+ */
+static void assert_dn_exists(struct ldbtest_ctx *test_ctx,
+ const char *entry_dn)
+{
+ int count;
+
+ count = base_search_count(test_ctx, entry_dn);
+ assert_int_equal(count, 1);
+}
+
+static void assert_dn_doesnt_exist(struct ldbtest_ctx *test_ctx,
+ const char *entry_dn)
+{
+ int count;
+
+ count = base_search_count(test_ctx, entry_dn);
+ assert_int_equal(count, 0);
+}
+
+static void add_dn_with_cn(struct ldbtest_ctx *test_ctx,
+ struct ldb_dn *dn,
+ const char *cn_value)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ assert_dn_doesnt_exist(test_ctx,
+ ldb_dn_get_linearized(dn));
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+ msg->dn = dn;
+
+ ret = ldb_msg_add_string(msg, "cn", cn_value);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_exists(test_ctx,
+ ldb_dn_get_linearized(dn));
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_del(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ const char *basedn = "dc=ldb_del_test";
+ struct ldb_dn *dn;
+
+ dn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "%s", basedn);
+ assert_non_null(dn);
+
+ add_dn_with_cn(test_ctx, dn, "test_del_cn_val");
+
+ ret = ldb_delete(test_ctx->ldb, dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_doesnt_exist(test_ctx, basedn);
+}
+
+static void test_ldb_del_noexist(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *basedn;
+ int ret;
+
+ basedn = ldb_dn_new(test_ctx, test_ctx->ldb, "dc=nosuchplace");
+ assert_non_null(basedn);
+
+ ret = ldb_delete(test_ctx->ldb, basedn);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+}
+
+static void test_ldb_handle(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_request *request = NULL;
+ struct ldb_request *request2 = NULL;
+ struct ldb_result *res = NULL;
+ const char *attrs[] = { "cn", NULL };
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ assert_non_null(res);
+
+ ret = ldb_build_search_req(&request, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ /* We are against ldb_tdb, so expect private event contexts */
+ assert_ptr_not_equal(ldb_handle_get_event_context(request->handle),
+ ldb_get_event_context(test_ctx->ldb));
+
+ ret = ldb_build_search_req(&request2, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ request);
+ assert_int_equal(ret, 0);
+
+ /* Expect that same event context will be chained */
+ assert_ptr_equal(ldb_handle_get_event_context(request->handle),
+ ldb_handle_get_event_context(request2->handle));
+
+ /* Now force this to use the global context */
+ ldb_handle_use_global_event_context(request2->handle);
+ assert_ptr_equal(ldb_handle_get_event_context(request2->handle),
+ ldb_get_event_context(test_ctx->ldb));
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_build_search_req(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_request *request = NULL;
+ struct ldb_request *request2 = NULL;
+ struct ldb_result *res = NULL;
+ const char *attrs[] = { "cn", NULL };
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ assert_non_null(res);
+
+ ret = ldb_build_search_req(&request, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ assert_int_equal(request->operation, LDB_SEARCH);
+ assert_ptr_equal(request->op.search.base, basedn);
+ assert_int_equal(request->op.search.scope, LDB_SCOPE_BASE);
+ assert_non_null(request->op.search.tree);
+ assert_ptr_equal(request->op.search.attrs, attrs);
+ assert_ptr_equal(request->context, res);
+ assert_ptr_equal(request->callback, ldb_search_default_callback);
+
+ ret = ldb_build_search_req(&request2, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ request);
+ assert_int_equal(ret, 0);
+ assert_ptr_equal(request, request2->handle->parent);
+ assert_int_equal(request->starttime, request2->starttime);
+ assert_int_equal(request->timeout, request2->timeout);
+
+ talloc_free(tmp_ctx);
+}
+
+static void add_keyval(struct ldbtest_ctx *test_ctx,
+ const char *key,
+ const char *val)
+{
+ int ret;
+ struct ldb_message *msg;
+
+ msg = ldb_msg_new(test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "%s=%s", key, val);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, key, val);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ talloc_free(msg);
+}
+
+static struct ldb_result *get_keyval(struct ldbtest_ctx *test_ctx,
+ const char *key,
+ const char *val)
+{
+ int ret;
+ struct ldb_result *result;
+ struct ldb_dn *basedn;
+
+ basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "%s=%s", key, val);
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, test_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+
+ return result;
+}
+
+static void test_transactions(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_result *res;
+
+ /* start lev-0 transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "vegetable", "carrot");
+
+ /* commit lev-0 transaction */
+ ret = ldb_transaction_commit(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ /* start another lev-1 nested transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "fruit", "apple");
+
+ /* abort lev-1 nested transaction */
+ ret = ldb_transaction_cancel(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ res = get_keyval(test_ctx, "vegetable", "carrot");
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+
+ res = get_keyval(test_ctx, "fruit", "apple");
+ assert_non_null(res);
+ assert_int_equal(res->count, 0);
+}
+
+struct ldb_mod_test_ctx {
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *entry_dn;
+};
+
+struct keyval {
+ const char *key;
+ const char *val;
+};
+
+static struct ldb_message *build_mod_msg(TALLOC_CTX *mem_ctx,
+ struct ldbtest_ctx *test_ctx,
+ const char *dn,
+ int modify_flags,
+ struct keyval *kvs)
+{
+ struct ldb_message *msg;
+ int ret;
+ int i;
+
+ msg = ldb_msg_new(mem_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "%s", dn);
+ assert_non_null(msg->dn);
+
+ for (i = 0; kvs[i].key != NULL; i++) {
+ if (modify_flags) {
+ ret = ldb_msg_add_empty(msg, kvs[i].key,
+ modify_flags, NULL);
+ assert_int_equal(ret, 0);
+ }
+
+ if (kvs[i].val) {
+ ret = ldb_msg_add_string(msg, kvs[i].key, kvs[i].val);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ }
+
+ return msg;
+}
+
+static void ldb_test_add_data(TALLOC_CTX *mem_ctx,
+ struct ldbtest_ctx *ldb_test_ctx,
+ const char *basedn,
+ struct keyval *kvs)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+ struct ldb_result *result = NULL;
+ int ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = build_mod_msg(tmp_ctx, ldb_test_ctx,
+ basedn, 0, kvs);
+ assert_non_null(msg);
+
+ ret = ldb_add(ldb_test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_search(ldb_test_ctx->ldb, tmp_ctx, &result, msg->dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+ ldb_dn_get_linearized(msg->dn));
+
+ talloc_free(tmp_ctx);
+}
+
+static void ldb_test_remove_data(TALLOC_CTX *mem_ctx,
+ struct ldbtest_ctx *ldb_test_ctx,
+ const char *strdn)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ int ret;
+ size_t count;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
+ "%s", strdn);
+ assert_non_null(basedn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, basedn);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_NO_SUCH_OBJECT);
+
+ count = base_search_count(ldb_test_ctx, ldb_dn_get_linearized(basedn));
+ assert_int_equal(count, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+static void mod_test_add_data(struct ldb_mod_test_ctx *mod_test_ctx,
+ struct keyval *kvs)
+{
+ ldb_test_add_data(mod_test_ctx,
+ mod_test_ctx->ldb_test_ctx,
+ mod_test_ctx->entry_dn,
+ kvs);
+}
+
+static void mod_test_remove_data(struct ldb_mod_test_ctx *mod_test_ctx)
+{
+ ldb_test_remove_data(mod_test_ctx,
+ mod_test_ctx->ldb_test_ctx,
+ mod_test_ctx->entry_dn);
+}
+
+static struct ldb_result *run_mod_test(struct ldb_mod_test_ctx *mod_test_ctx,
+ int modify_flags,
+ struct keyval *kvs)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ struct ldb_message *mod_msg;
+ struct ldb_dn *basedn;
+ struct ldbtest_ctx *ldb_test_ctx;
+ int ret;
+
+ ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+ tmp_ctx = talloc_new(mod_test_ctx);
+ assert_non_null(tmp_ctx);
+
+ mod_msg = build_mod_msg(tmp_ctx, ldb_test_ctx, mod_test_ctx->entry_dn,
+ modify_flags, kvs);
+ assert_non_null(mod_msg);
+
+ ret = ldb_modify(ldb_test_ctx->ldb, mod_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
+ "%s", mod_test_ctx->entry_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(ldb_test_ctx->ldb, mod_test_ctx, &res, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(res->msgs[0]->dn),
+ ldb_dn_get_linearized(mod_msg->dn));
+
+ talloc_free(tmp_ctx);
+ return res;
+}
+
+static int ldb_modify_test_setup(void **state)
+{
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct ldb_mod_test_ctx *mod_test_ctx;
+ struct keyval kvs[] = {
+ { "cn", "test_mod_cn" },
+ { NULL, NULL },
+ };
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ mod_test_ctx = talloc(ldb_test_ctx, struct ldb_mod_test_ctx);
+ assert_non_null(mod_test_ctx);
+
+ mod_test_ctx->entry_dn = "dc=mod_test_entry";
+ mod_test_ctx->ldb_test_ctx = ldb_test_ctx;
+
+ mod_test_remove_data(mod_test_ctx);
+ mod_test_add_data(mod_test_ctx, kvs);
+ *state = mod_test_ctx;
+ return 0;
+}
+
+static int ldb_modify_test_teardown(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldbtest_ctx *ldb_test_ctx;
+
+ ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+ mod_test_remove_data(mod_test_ctx);
+ talloc_free(mod_test_ctx);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_modify_add_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct keyval mod_kvs[] = {
+ { "name", "test_mod_name" },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_ADD, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn is intact and name was added */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal(el->values[0].data, "test_mod_cn");
+
+ el = ldb_msg_find_element(res->msgs[0], "name");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal(el->values[0].data, "test_mod_name");
+}
+
+static void test_ldb_modify_extend_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct keyval mod_kvs[] = {
+ { "cn", "test_mod_cn2" },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_ADD, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn was extended with another value */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 2);
+ assert_string_equal(el->values[0].data, "test_mod_cn");
+ assert_string_equal(el->values[1].data, "test_mod_cn2");
+}
+
+static void test_ldb_modify_add_key_noval(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message *mod_msg;
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct ldb_message_element *el;
+ int ret;
+
+ ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+ mod_msg = ldb_msg_new(mod_test_ctx);
+ assert_non_null(mod_msg);
+
+ mod_msg->dn = ldb_dn_new_fmt(mod_msg, ldb_test_ctx->ldb,
+ "%s", mod_test_ctx->entry_dn);
+ assert_non_null(mod_msg->dn);
+
+ el = talloc_zero(mod_msg, struct ldb_message_element);
+ el->flags = LDB_FLAG_MOD_ADD;
+ assert_non_null(el);
+ el->name = talloc_strdup(el, "cn");
+ assert_non_null(el->name);
+
+ mod_msg->elements = el;
+ mod_msg->num_elements = 1;
+
+ ret = ldb_modify(ldb_test_ctx->ldb, mod_msg);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+}
+
+static void test_ldb_modify_replace_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ const char *new_cn = "new_cn";
+ struct keyval mod_kvs[] = {
+ { "cn", new_cn },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn was replaced */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal(el->values[0].data, new_cn);
+}
+
+static void test_ldb_modify_replace_noexist_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct keyval mod_kvs[] = {
+ { "name", "name_val" },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn is intact and name was added */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal(el->values[0].data, "test_mod_cn");
+
+ el = ldb_msg_find_element(res->msgs[0], mod_kvs[0].key);
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal(el->values[0].data, mod_kvs[0].val);
+}
+
+static void test_ldb_modify_replace_zero_vals(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "cn", NULL },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, kvs);
+ assert_non_null(res);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_null(el);
+}
+
+static void test_ldb_modify_replace_noexist_key_zero_vals(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "noexist_key", NULL },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, kvs);
+ assert_non_null(res);
+
+ /* cn should be intact */
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+}
+
+static void test_ldb_modify_del_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "cn", NULL },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_DELETE, kvs);
+ assert_non_null(res);
+
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_null(el);
+}
+
+static void test_ldb_modify_del_keyval(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "cn", "test_mod_cn" },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_DELETE, kvs);
+ assert_non_null(res);
+
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_null(el);
+}
+
+struct search_test_ctx {
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *base_dn;
+};
+
+static char *get_full_dn(TALLOC_CTX *mem_ctx,
+ struct search_test_ctx *search_test_ctx,
+ const char *rdn)
+{
+ char *full_dn;
+
+ full_dn = talloc_asprintf(mem_ctx,
+ "%s,%s", rdn, search_test_ctx->base_dn);
+ assert_non_null(full_dn);
+
+ return full_dn;
+}
+
+static void search_test_add_data(struct search_test_ctx *search_test_ctx,
+ const char *rdn,
+ struct keyval *kvs)
+{
+ char *full_dn;
+
+ full_dn = get_full_dn(search_test_ctx, search_test_ctx, rdn);
+
+ ldb_test_add_data(search_test_ctx,
+ search_test_ctx->ldb_test_ctx,
+ full_dn,
+ kvs);
+}
+
+static void search_test_remove_data(struct search_test_ctx *search_test_ctx,
+ const char *rdn)
+{
+ char *full_dn;
+
+ full_dn = talloc_asprintf(search_test_ctx,
+ "%s,%s", rdn, search_test_ctx->base_dn);
+ assert_non_null(full_dn);
+
+ ldb_test_remove_data(search_test_ctx,
+ search_test_ctx->ldb_test_ctx,
+ full_dn);
+}
+
+static int ldb_search_test_setup(void **state)
+{
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct search_test_ctx *search_test_ctx;
+ struct keyval kvs[] = {
+ { "cn", "test_search_cn" },
+ { "cn", "test_search_cn2" },
+ { "uid", "test_search_uid" },
+ { "uid", "test_search_uid2" },
+ { NULL, NULL },
+ };
+ struct keyval kvs2[] = {
+ { "cn", "test_search_2_cn" },
+ { "cn", "test_search_2_cn2" },
+ { "uid", "test_search_2_uid" },
+ { "uid", "test_search_2_uid2" },
+ { NULL, NULL },
+ };
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ search_test_ctx = talloc(ldb_test_ctx, struct search_test_ctx);
+ assert_non_null(search_test_ctx);
+
+ search_test_ctx->base_dn = "dc=search_test_entry";
+ search_test_ctx->ldb_test_ctx = ldb_test_ctx;
+
+ search_test_remove_data(search_test_ctx, "cn=test_search_cn");
+ search_test_add_data(search_test_ctx, "cn=test_search_cn", kvs);
+
+ search_test_remove_data(search_test_ctx, "cn=test_search_2_cn");
+ search_test_add_data(search_test_ctx, "cn=test_search_2_cn", kvs2);
+
+ *state = search_test_ctx;
+ return 0;
+}
+
+static int ldb_search_test_teardown(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct ldbtest_ctx *ldb_test_ctx;
+
+ ldb_test_ctx = search_test_ctx->ldb_test_ctx;
+
+ search_test_remove_data(search_test_ctx, "cn=test_search_cn");
+ search_test_remove_data(search_test_ctx, "cn=test_search_2_cn");
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void assert_attr_has_vals(struct ldb_message *msg,
+ const char *attr,
+ const char *vals[],
+ const size_t nvals)
+{
+ struct ldb_message_element *el;
+ size_t i;
+
+ el = ldb_msg_find_element(msg, attr);
+ assert_non_null(el);
+
+ assert_int_equal(el->num_values, nvals);
+ for (i = 0; i < nvals; i++) {
+ assert_string_equal(el->values[i].data,
+ vals[i]);
+ }
+}
+
+static void assert_has_no_attr(struct ldb_message *msg,
+ const char *attr)
+{
+ struct ldb_message_element *el;
+
+ el = ldb_msg_find_element(msg, attr);
+ assert_null(el);
+}
+
+static bool has_dn(struct ldb_message *msg, const char *dn)
+{
+ const char *msgdn;
+
+ msgdn = ldb_dn_get_linearized(msg->dn);
+ if (strcmp(dn, msgdn) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static void test_search_match_none(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ size_t count;
+
+ count = base_search_count(search_test_ctx->ldb_test_ctx,
+ "dc=no_such_entry");
+ assert_int_equal(count, 0);
+}
+
+static void test_search_match_one(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ const char *cn_vals[] = { "test_search_cn",
+ "test_search_cn2" };
+ const char *uid_vals[] = { "test_search_uid",
+ "test_search_uid2" };
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=test_search_cn");
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+
+ assert_attr_has_vals(result->msgs[0], "cn", cn_vals, 2);
+ assert_attr_has_vals(result->msgs[0], "uid", uid_vals, 2);
+}
+
+static void test_search_match_filter(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ const char *cn_vals[] = { "test_search_cn",
+ "test_search_cn2" };
+ const char *attrs[] = { "cn", NULL };
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ attrs,
+ "cn=test_search_cn");
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+
+ assert_attr_has_vals(result->msgs[0], "cn", cn_vals, 2);
+ assert_has_no_attr(result->msgs[0], "uid");
+}
+
+static void assert_expected(struct search_test_ctx *search_test_ctx,
+ struct ldb_message *msg)
+{
+ char *full_dn1;
+ char *full_dn2;
+ const char *cn_vals[] = { "test_search_cn",
+ "test_search_cn2" };
+ const char *uid_vals[] = { "test_search_uid",
+ "test_search_uid2" };
+ const char *cn2_vals[] = { "test_search_2_cn",
+ "test_search_2_cn2" };
+ const char *uid2_vals[] = { "test_search_2_uid",
+ "test_search_2_uid2" };
+
+ full_dn1 = get_full_dn(search_test_ctx,
+ search_test_ctx,
+ "cn=test_search_cn");
+
+ full_dn2 = get_full_dn(search_test_ctx,
+ search_test_ctx,
+ "cn=test_search_2_cn");
+
+ if (has_dn(msg, full_dn1) == true) {
+ assert_attr_has_vals(msg, "cn", cn_vals, 2);
+ assert_attr_has_vals(msg, "uid", uid_vals, 2);
+ } else if (has_dn(msg, full_dn2) == true) {
+ assert_attr_has_vals(msg, "cn", cn2_vals, 2);
+ assert_attr_has_vals(msg, "uid", uid2_vals, 2);
+ } else {
+ fail();
+ }
+}
+
+static void test_search_match_both(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=test_search_*");
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 2);
+
+ assert_expected(search_test_ctx, result->msgs[0]);
+ assert_expected(search_test_ctx, result->msgs[1]);
+}
+
+static void test_search_match_basedn(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ struct ldb_message *msg;
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "dc=nosuchdn");
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=*");
+ assert_int_equal(ret, 0);
+
+ /* Add 'checkBaseOnSearch' to @OPTIONS */
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "@OPTIONS");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "checkBaseOnSearch", "TRUE");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ /* Search again */
+ /* The search should return LDB_ERR_NO_SUCH_OBJECT */
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=*");
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+ ret = ldb_delete(search_test_ctx->ldb_test_ctx->ldb, msg->dn);
+ assert_int_equal(ret, 0);
+}
+
+
+/*
+ * This test is complex.
+ * The purpose is to test for a deadlock detected between ldb_search()
+ * and ldb_transaction_commit(). The deadlock happens if in process
+ * (1) and (2):
+ * - (1) the all-record lock is taken in ltdb_search()
+ * - (2) the ldb_transaction_start() call is made
+ * - (1) an un-indexed search starts (forced here by doing it in
+ * the callback
+ * - (2) the ldb_transaction_commit() is called.
+ * This returns LDB_ERR_BUSY if the deadlock is detected
+ *
+ * With ldb 1.1.31 and tdb 1.3.12 we avoid this only due to a missing
+ * lock call in ltdb_search() due to a refcounting bug in
+ * ltdb_lock_read()
+ */
+
+struct search_against_transaction_ctx {
+ struct ldbtest_ctx *test_ctx;
+ int res_count;
+ pid_t child_pid;
+ struct ldb_dn *basedn;
+};
+
+static int test_ldb_search_against_transaction_callback2(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct search_against_transaction_ctx *ctx = req->context;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ctx->res_count++;
+ if (ctx->res_count != 1) {
+ return LDB_SUCCESS;
+ }
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ break;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ return 0;
+
+}
+
+/*
+ * This purpose of this callback is to trigger a transaction in
+ * the child process while the all-record lock is held, but before
+ * we take any locks in the tdb_traverse_read() handler.
+ *
+ * In tdb 1.3.12 tdb_traverse_read() take the read transaction lock
+ * however in ldb 1.1.31 ltdb_search() forgets to take the all-record
+ * lock (except the very first time) due to a ref-counting bug.
+ *
+ */
+
+static int test_ldb_search_against_transaction_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret, ret2;
+ int pipes[2];
+ char buf[2];
+ struct search_against_transaction_ctx *ctx = req->context;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ ctx->child_pid = fork();
+ if (ctx->child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "dc=test");
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_add(ctx->test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+ }
+
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ /* This search must be unindexed (ie traverse in tdb) */
+ ret = ldb_build_search_req(&req,
+ ctx->test_ctx->ldb,
+ ctx->test_ctx,
+ ctx->basedn,
+ LDB_SCOPE_SUBTREE,
+ "cn=*", NULL,
+ NULL,
+ ctx,
+ test_ldb_search_against_transaction_callback2,
+ NULL);
+ /*
+ * we don't assert on these return codes until after the search is
+ * finished, or the clean up will fail because we hold locks.
+ */
+
+ ret2 = ldb_request(ctx->test_ctx->ldb, req);
+
+ if (ret2 == LDB_SUCCESS) {
+ ret2 = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+ assert_int_equal(ret2, 0);
+ assert_int_equal(ctx->res_count, 2);
+
+ return LDB_SUCCESS;
+}
+
+static void test_ldb_search_against_transaction(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct search_against_transaction_ctx
+ ctx =
+ { .res_count = 0,
+ .test_ctx = search_test_ctx->ldb_test_ctx
+ };
+
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *base_search_dn;
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ base_search_dn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,%s",
+ search_test_ctx->base_dn);
+ assert_non_null(base_search_dn);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /* This search must be indexed (ie no traverse in tdb) */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ base_search_dn,
+ LDB_SCOPE_BASE,
+ "cn=*", NULL,
+ NULL,
+ &ctx,
+ test_ldb_search_against_transaction_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+ assert_int_equal(ctx.res_count, 2);
+
+ pid = waitpid(ctx.child_pid, &wstatus, 0);
+ assert_int_equal(pid, ctx.child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+
+}
+
+/*
+ * This test is also complex.
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * This would be a failure if if in process
+ * (1) and (2):
+ * - (1) ltdb_search() starts and calls back for one entry
+ * - (2) one of the entries to be matched is modified
+ * - (1) the indexed search tries to return the modified entry, but
+ * it is no longer found, either:
+ * - despite it still matching (dn changed)
+ * - it no longer matching (attrs changed)
+ *
+ * We also try un-indexed to show that the behaviour differs on this
+ * point, which it should not (an index should only impact search
+ * speed).
+ */
+
+struct modify_during_search_test_ctx {
+ struct ldbtest_ctx *test_ctx;
+ int res_count;
+ pid_t child_pid;
+ struct ldb_dn *basedn;
+ bool got_cn;
+ bool got_2_cn;
+ bool rename;
+};
+
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process while a search is in progress.
+ *
+ * In tdb 1.3.12 tdb_traverse_read() take the read transaction lock
+ * however in ldb 1.1.31 ltdb_search() forgets to take the all-record
+ * lock (except the very first time) due to a ref-counting bug.
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
+
+static int test_ldb_modify_during_search_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ int pipes[2];
+ char buf[2];
+ struct modify_during_search_test_ctx *ctx = req->context;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ {
+ const struct ldb_val *cn_val
+ = ldb_dn_get_component_val(ares->message->dn, 0);
+ const char *cn = (char *)cn_val->data;
+ ctx->res_count++;
+ if (strcmp(cn, "test_search_cn") == 0) {
+ ctx->got_cn = true;
+ } else if (strcmp(cn, "test_search_2_cn") == 0) {
+ ctx->got_2_cn = true;
+ }
+ if (ctx->res_count == 2) {
+ return LDB_SUCCESS;
+ }
+ break;
+ }
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ ctx->child_pid = fork();
+ if (ctx->child_pid == 0 && ctx->rename) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *dn, *new_dn;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ctx->got_cn) {
+ /* Modify the other one */
+ dn = ldb_dn_new_fmt(tmp_ctx, ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,"
+ "dc=search_test_entry");
+ } else {
+ dn = ldb_dn_new_fmt(tmp_ctx, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ }
+ if (dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ new_dn = ldb_dn_new_fmt(tmp_ctx, ctx->test_ctx->ldb,
+ "cn=test_search_cn_renamed,"
+ "dc=search_test_entry");
+ if (new_dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_rename(ctx->test_ctx->ldb, dn, new_dn);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+
+ } else if (ctx->child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ctx->got_cn) {
+ /* Modify the other one */
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,"
+ "dc=search_test_entry");
+ } else {
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ }
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(ctx->test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+ }
+
+ /*
+ * With TDB 1.3.13 and before "tdb: Remove locking from tdb_traverse_read()"
+ * we will hang here because the child process can not proceed to
+ * sending the "GO" as it is blocked at ldb_transaction_start().
+ */
+
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ return LDB_SUCCESS;
+}
+
+static void test_ldb_modify_during_search(void **state, bool add_index,
+ bool rename)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct modify_during_search_test_ctx
+ ctx =
+ { .res_count = 0,
+ .test_ctx = search_test_ctx->ldb_test_ctx,
+ .rename = rename
+ };
+
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+
+ if (add_index) {
+ struct ldb_message *msg;
+ struct ldb_dn *indexlist = ldb_dn_new(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(indexlist);
+
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = indexlist;
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "cn");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /*
+ * This search must be over multiple items, and should include
+ * the new name after a rename, to show that it would match
+ * both before and after that modify
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ ctx.basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(|(cn=test_search_cn_renamed)"
+ "(cn=test_search_cn)"
+ "(cn=test_search_2_cn)"
+ "))",
+ NULL,
+ NULL,
+ &ctx,
+ test_ldb_modify_during_search_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+ assert_int_equal(ctx.res_count, 2);
+ assert_int_equal(ctx.got_cn, true);
+ assert_int_equal(ctx.got_2_cn, true);
+
+ pid = waitpid(ctx.child_pid, &wstatus, 0);
+ assert_int_equal(pid, ctx.child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+
+}
+
+static void test_ldb_modify_during_indexed_search(void **state)
+{
+ return test_ldb_modify_during_search(state, true, false);
+}
+
+static void test_ldb_modify_during_unindexed_search(void **state)
+{
+ return test_ldb_modify_during_search(state, false, false);
+}
+
+static void test_ldb_rename_during_indexed_search(void **state)
+{
+ return test_ldb_modify_during_search(state, true, true);
+}
+
+static void test_ldb_rename_during_unindexed_search(void **state)
+{
+ return test_ldb_modify_during_search(state, false, true);
+}
+
+/*
+ * This test is also complex.
+ *
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * before the end of the callback
+ *
+ * This would be a failure if if in process
+ * (1) and (2):
+ * - (1) ldb_search() starts and calls back for a number of entries
+ * - (2) an entry in the DB is allowed to change before the callback returns
+ * - (1) the callback can see the modification
+ *
+ */
+
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process while a search DONE callback is in progress.
+ *
+ * In ldb 1.1.31 ldb_search() omitted to take a all-record
+ * lock for the full duration of the search and callbacks
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
+
+static int test_ldb_modify_during_whole_search_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ int pipes[2];
+ char buf[2];
+ struct modify_during_search_test_ctx *ctx = req->context;
+ struct ldb_dn *search_dn;
+ struct ldb_result *res2;
+ unsigned res_count;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ break;
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ ctx->child_pid = fork();
+ if (ctx->child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(ctx->test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+ }
+
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ /*
+ * If writes are not blocked until after this function, we
+ * will be able to successfully search for this modification
+ * here
+ */
+
+ search_dn = ldb_dn_new_fmt(ares, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(ctx->test_ctx->ldb, ares,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+
+ /*
+ * We do this in an unusual order, because if we fail an assert before
+ * ldb_request_done(), we will also fail to clean up as we hold locks.
+ */
+
+ res_count = res2->count;
+ ldb_request_done(req, LDB_SUCCESS);
+ assert_int_equal(ret, 0);
+
+ /* We should not have got the result */
+ assert_int_equal(res_count, 0);
+
+ return ret;
+}
+
+static void test_ldb_modify_during_whole_search(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct modify_during_search_test_ctx
+ ctx =
+ {
+ .test_ctx = search_test_ctx->ldb_test_ctx,
+ };
+
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *search_dn;
+ struct ldb_result *res2;
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /*
+ * The search just needs to call DONE, we don't care about the
+ * contents of the search for this test
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ ctx.basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(cn=test_search_cn))",
+ NULL,
+ NULL,
+ &ctx,
+ test_ldb_modify_during_whole_search_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+
+ pid = waitpid(ctx.child_pid, &wstatus, 0);
+ assert_int_equal(pid, ctx.child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ /*
+ * If writes are blocked until after the search function, we
+ * will be able to successfully search for this modification
+ * now
+ */
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+ assert_int_equal(ret, 0);
+
+ /* We got the result */
+ assert_int_equal(res2->count, 1);
+}
+
+/*
+ * This test is also complex.
+ *
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * before the request is destroyed with TALLOC_FREE()
+ *
+ * This would be a failure if in process
+ * (1) and (2):
+ * - (1) ldb_search() starts and waits
+ * - (2) an entry in the DB is allowed to change before the ldb_wait() is called
+ * - (1) the original process can see the modification before the TALLOC_FREE()
+ * also we check that
+ * - (1) the original process can see the modification after the TALLOC_FREE()
+ *
+ */
+
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process before the ldb_wait() is called
+ *
+ * In ldb 1.1.31 ldb_search() omitted to take a all-record
+ * lock for the full duration of the search and callbacks
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
+
+static int test_ldb_modify_before_ldb_wait_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ break;
+ }
+
+ return ldb_request_done(req, LDB_SUCCESS);
+}
+
+static void test_ldb_modify_before_ldb_wait(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *search_dn;
+ struct ldb_dn *basedn;
+ struct ldb_result *res2;
+ int pipes[2];
+ char buf[2];
+ pid_t child_pid;
+ unsigned res_count;
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ assert_non_null(search_dn);
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ /*
+ * The search just needs to call DONE, we don't care about the
+ * contents of the search for this test
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(cn=test_search_cn))",
+ NULL,
+ NULL,
+ NULL,
+ test_ldb_modify_before_ldb_wait_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(search_test_ctx->ldb_test_ctx->ldb);
+ TALLOC_FREE(search_test_ctx->ldb_test_ctx->ev);
+ search_test_ctx->ldb_test_ctx->ev = tevent_context_init(search_test_ctx->ldb_test_ctx);
+ if (search_test_ctx->ldb_test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ search_test_ctx->ldb_test_ctx->ldb = ldb_init(search_test_ctx->ldb_test_ctx,
+ search_test_ctx->ldb_test_ctx->ev);
+ if (search_test_ctx->ldb_test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx->ldb_test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(search_test_ctx->ldb_test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * We must re-create this DN from a string to ensure
+ * it does not reference the now-gone LDB context of
+ * the parent
+ */
+ msg->dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_transaction_start(search_test_ctx->ldb_test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(search_test_ctx->ldb_test_ctx->ldb);
+ exit(ret);
+ }
+
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ /*
+ * If writes are not blocked until after the (never called) ldb_wait(), we
+ * will be able to successfully search for this modification
+ * here
+ */
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb, search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+
+ /*
+ * We avoid making assertions before TALLOC_FREE()ing the request,
+ * lest the assert fail and mess with the clean-up because we still
+ * have locks.
+ */
+ res_count = res2->count;
+ TALLOC_FREE(req);
+
+ /* We should not have got the result */
+ assert_int_equal(res_count, 0);
+ assert_int_equal(ret, 0);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ /*
+ * If writes are blocked until after the search request was freed, we
+ * will be able to successfully search for this modification
+ * now
+ */
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+ assert_int_equal(ret, 0);
+
+ /* We got the result */
+ assert_int_equal(res2->count, 1);
+}
+
+static int ldb_case_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: CASE_INSENSITIVE\n"
+ "\n";
+ struct keyval kvs[] = {
+ { "cn", "CaseInsensitiveValue" },
+ { "uid", "CaseSensitiveValue" },
+ { NULL, NULL },
+ };
+
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ ldb_test_add_data(ldb_test_ctx,
+ ldb_test_ctx,
+ "cn=CaseInsensitiveValue",
+ kvs);
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_case_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@ATTRIBUTES");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldb_test_remove_data(ldb_test_ctx, ldb_test_ctx,
+ "cn=CaseInsensitiveValue");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_attrs_case_insensitive(void **state)
+{
+ int cnt;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ /* cn matches exact case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=CaseInsensitiveValue");
+ assert_int_equal(cnt, 1);
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ /* uid matches exact case */
+ cnt = sub_search_count(ldb_test_ctx, "", "uid=CaseSensitiveValue");
+ assert_int_equal(cnt, 1);
+
+ /* uid does not match lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "uid=casesensitivevalue");
+ assert_int_equal(cnt, 0);
+}
+
+static struct ldb_schema_attribute cn_attr_1;
+static struct ldb_schema_attribute cn_attr_2;
+static struct ldb_schema_attribute default_attr;
+
+/*
+ override the name to attribute handler function
+ */
+static const struct ldb_schema_attribute *ldb_test_attribute_handler_override(struct ldb_context *ldb,
+ void *private_data,
+ const char *name)
+{
+ if (private_data != NULL && ldb_attr_cmp(name, "cn") == 0) {
+ return &cn_attr_1;
+ } else if (private_data == NULL && ldb_attr_cmp(name, "cn") == 0) {
+ return &cn_attr_2;
+ } else if (ldb_attr_cmp(name, "uid") == 0) {
+ return &cn_attr_2;
+ }
+ return &default_attr;
+}
+
+static void test_ldb_attrs_case_handler(void **state)
+{
+ int cnt;
+ int ret;
+ const struct ldb_schema_syntax *syntax;
+
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_context *ldb = ldb_test_ctx->ldb;
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "*", 0,
+ syntax, &default_attr);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", 0,
+ syntax, &cn_attr_1);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Set an attribute handler, which will fail to match as we
+ * force case sensitive
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ (void *)1);
+
+ /* cn does not matche lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 0);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_DIRECTORY_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", 0,
+ syntax, &cn_attr_2);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Set an attribute handler, which will match as we
+ * force case insensitive
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ NULL);
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+}
+
+
+static void test_ldb_attrs_index_handler(void **state)
+{
+ int cnt;
+ int ret;
+ const struct ldb_schema_syntax *syntax;
+ struct ldb_ldif *ldif;
+
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "\n";
+
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_context *ldb = ldb_test_ctx->ldb;
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", 0,
+ syntax, &cn_attr_1);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_DIRECTORY_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", LDB_ATTR_FLAG_INDEXED,
+ syntax, &cn_attr_2);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Set an attribute handler
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ NULL);
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ /* Add the index (actually any modify will do) */
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ ldb_schema_set_override_indexlist(ldb, false);
+
+ /* cn does match as there is an index now */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ /*
+ * Set an attribute handler, which will later fail to match as we
+ * didn't re-index the DB
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ (void *)1);
+
+ /*
+ * cn does not match as we changed the case sensitivity, but
+ * didn't re-index
+ *
+ * This shows that the override is in control
+ */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 0);
+
+}
+
+static int ldb_case_attrs_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ ldb_case_test_teardown(state);
+ return 0;
+}
+
+
+struct rename_test_ctx {
+ struct ldbtest_ctx *ldb_test_ctx;
+
+ struct ldb_dn *basedn;
+ const char *str_basedn;
+
+ const char *teardown_dn;
+};
+
+static int ldb_rename_test_setup(void **state)
+{
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct rename_test_ctx *rename_test_ctx;
+ const char *strdn = "dc=rename_test_entry_from";
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ rename_test_ctx = talloc(ldb_test_ctx, struct rename_test_ctx);
+ assert_non_null(rename_test_ctx);
+ rename_test_ctx->ldb_test_ctx = ldb_test_ctx;
+ assert_non_null(rename_test_ctx->ldb_test_ctx);
+
+ rename_test_ctx->basedn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", strdn);
+ assert_non_null(rename_test_ctx->basedn);
+
+ rename_test_ctx->str_basedn = strdn;
+ rename_test_ctx->teardown_dn = strdn;
+
+ add_dn_with_cn(ldb_test_ctx,
+ rename_test_ctx->basedn,
+ "test_rename_cn_val");
+
+ *state = rename_test_ctx;
+ return 0;
+}
+
+static int ldb_rename_test_teardown(void **state)
+{
+ int ret;
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(*state,
+ struct rename_test_ctx);
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct ldb_dn *del_dn;
+
+ ldb_test_ctx = rename_test_ctx->ldb_test_ctx;
+
+ del_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", rename_test_ctx->teardown_dn);
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ rename_test_ctx->teardown_dn);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_rename(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx =
+ talloc_get_type_abort(*state, struct rename_test_ctx);
+ int ret;
+ const char *str_new_dn = "dc=rename_test_entry_to";
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ new_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx, str_new_dn);
+ assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+ rename_test_ctx->teardown_dn = str_new_dn;
+
+ /* FIXME - test the values which didn't change */
+}
+
+static void test_ldb_rename_from_doesnt_exist(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+ const char *str_new_dn = "dc=rename_test_entry_to";
+ const char *str_bad_old_dn = "dc=rename_test_no_such_entry";
+ struct ldb_dn *new_dn;
+ struct ldb_dn *bad_old_dn;
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ bad_old_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_bad_old_dn);
+ assert_non_null(bad_old_dn);
+
+ assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+ str_bad_old_dn);
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ bad_old_dn, new_dn);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+ assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+ str_new_dn);
+}
+
+static void test_ldb_rename_to_exists(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+ const char *str_new_dn = "dc=rename_test_already_exists";
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ add_dn_with_cn(rename_test_ctx->ldb_test_ctx,
+ new_dn,
+ "test_rename_cn_val");
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ new_dn);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ /* Old object must still exist */
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+
+ ret = ldb_delete(rename_test_ctx->ldb_test_ctx->ldb,
+ new_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->teardown_dn);
+}
+
+static void test_ldb_rename_self(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+
+ /* Oddly enough, this is a success in ldb.. */
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ rename_test_ctx->basedn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* Old object must still exist */
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+}
+
+static void test_ldb_rename_dn_case_change(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+ char *str_new_dn;
+ struct ldb_dn *new_dn;
+ unsigned i;
+
+ str_new_dn = talloc_strdup(rename_test_ctx, rename_test_ctx->str_basedn);
+ assert_non_null(str_new_dn);
+ for (i = 0; str_new_dn[i]; i++) {
+ str_new_dn[i] = toupper(str_new_dn[i]);
+ }
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ new_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* DNs are case insensitive, so both searches will match */
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx, str_new_dn);
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+ /* FIXME - test the values didn't change */
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_connect,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldif_message,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldif_message_redacted,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_add,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_search,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_del,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_del_noexist,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_handle,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_build_search_req,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_transactions,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_add_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_extend_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_add_key_noval,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_noexist_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_zero_vals,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_noexist_key_zero_vals,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_del_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_del_keyval,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_none,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_one,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_filter,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_both,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_basedn,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_search_against_transaction,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_whole_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_before_ldb_wait,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_attrs_case_insensitive,
+ ldb_case_test_setup,
+ ldb_case_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_attrs_case_handler,
+ ldb_case_test_setup,
+ ldb_case_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_attrs_index_handler,
+ ldb_case_test_setup,
+ ldb_case_attrs_index_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_from_doesnt_exist,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_to_exists,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_self,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_dn_case_change,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/ldb_msg.c b/tests/ldb_msg.c
new file mode 100644
index 0000000..f8de418
--- /dev/null
+++ b/tests/ldb_msg.c
@@ -0,0 +1,379 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#include <ldb.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+struct test_ctx {
+ struct ldb_message *msg;
+};
+
+static int ldb_msg_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->msg = ldb_msg_new(test_ctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldb_msg_teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ talloc_free(test_ctx);
+ return 0;
+}
+
+
+static void add_uint_value(struct test_ctx *test_ctx,
+ struct ldb_message *msg,
+ const char *attr,
+ unsigned int x)
+{
+ int ret;
+ struct ldb_val v, v_dup;
+ char s[5];
+ snprintf(s, sizeof(s), "%04x", x);
+ v.data = (uint8_t *)s;
+ v.length = 4;
+ v_dup = ldb_val_dup(test_ctx, &v);
+ assert_non_null(v_dup.data);
+ assert_ptr_not_equal(v_dup.data, v.data);
+ assert_int_equal(v_dup.length, 4);
+
+ ret = ldb_msg_add_value(msg, attr, &v_dup, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+}
+
+
+static void test_ldb_msg_find_duplicate_val(void **state)
+{
+ int ret;
+ unsigned int i;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_message *msg = test_ctx->msg;
+ struct ldb_message_element *el;
+ struct ldb_val dummy;
+ struct ldb_val *dupe = &dummy; /* so we can tell it was modified to NULL, not left as NULL */
+
+ ret = ldb_msg_add_empty(msg, "el1", 0, &el);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* An empty message contains no duplicates */
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+
+ for (i = 0; i < 5; i++) {
+ add_uint_value(test_ctx, msg, "el1", i);
+ }
+ /* at this point there are no duplicates, and the check uses the naive
+ quadratic path */
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+
+ /* add a duplicate, still using quadratric path */
+ add_uint_value(test_ctx, msg, "el1", 3);
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(dupe);
+ assert_int_equal(dupe->length, 4);
+ assert_memory_equal(dupe->data, "0003", 4);
+
+ /* add some more, triggering algorithmic jump */
+ for (i = 2; i < 11; i++) {
+ add_uint_value(test_ctx, msg, "el1", i);
+ }
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(dupe);
+ assert_int_equal(dupe->length, 4);
+ /*XXX not really guaranteed by the API */
+ assert_memory_equal(dupe->data, "0002", 4);
+
+ /* start a new element without duplicates, for the clever algorithm */
+ ldb_msg_add_empty(msg, "el2", 0, &el);
+ for (i = 0; i < 12; i++) {
+ add_uint_value(test_ctx, msg, "el2", i);
+ }
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+}
+
+
+static struct ldb_message_element *new_msg_element(TALLOC_CTX *mem_ctx,
+ const char *name,
+ unsigned int value_offset,
+ unsigned int num_values)
+{
+ unsigned int i, x;
+ struct ldb_message_element *el = talloc_zero(mem_ctx,
+ struct ldb_message_element);
+
+ el->values = talloc_array(el, struct ldb_val, num_values);
+ for (i = 0; i < num_values; i++) {
+ struct ldb_val v;
+ char s[50];
+ v.data = (uint8_t *)s;
+ /* % 3 is to ensure the values list is unsorted */
+ x = i + value_offset;
+ v.length = snprintf(s, sizeof(s), "%u %u", x % 3, x);
+ el->values[i] = ldb_val_dup(mem_ctx, &v);
+ }
+ el->name = name;
+ el->num_values = num_values;
+ return el;
+}
+
+static void _assert_element_equal(struct ldb_message_element *a,
+ struct ldb_message_element *b,
+ const char * const file,
+ const int line)
+{
+ unsigned int i;
+ _assert_int_equal(a->num_values, b->num_values, file, line);
+ _assert_int_equal(a->flags, b->flags, file, line);
+ _assert_string_equal(a->name, b->name, file, line);
+ for (i = 0; i < a->num_values; i++) {
+ struct ldb_val *v1 = &a->values[i];
+ struct ldb_val *v2 = &b->values[i];
+ _assert_int_equal(v1->length, v2->length, file, line);
+ _assert_memory_equal(v1->data, v2->data, v1->length,
+ file, line);
+ }
+}
+
+#define assert_element_equal(a, b) \
+ _assert_element_equal((a), (b), \
+ __FILE__, __LINE__)
+
+
+static void test_ldb_msg_find_common_values(void **state)
+{
+ /* we only use the state as a talloc context */
+ struct ldb_message_element *el, *el2, *el3, *el4, *el2b, *empty;
+ struct ldb_message_element *orig, *orig2, *orig3, *orig4;
+ int ret;
+ const uint32_t remove_dupes = LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+ el = new_msg_element(*state, "test", 0, 4);
+ el2 = new_msg_element(*state, "test", 4, 4);
+ el3 = new_msg_element(*state, "test", 6, 4);
+ empty = new_msg_element(*state, "test", 0, 0);
+ orig = new_msg_element(*state, "test", 0, 4);
+ orig2 = new_msg_element(*state, "test", 4, 4);
+ orig3 = new_msg_element(*state, "test", 6, 4);
+
+ /* first round is with short value arrays, using quadratic method */
+ /* we expect no collisions here */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*or here */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* the same elements in reverse order */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* 6, 7 collide */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ /* and again */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ /* make sure the arrays haven't changed */
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el3, orig3);
+
+ /* now with the control permisive flag, the first element should be
+ modified to remove the overlap.*/
+
+ /* 6, 7 collide, so el2 will only have 4 and 5 */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el3, orig3);
+ assert_int_not_equal(el2->num_values, orig2->num_values);
+ assert_int_equal(el2->num_values, 2);
+ el2b = new_msg_element(*state, "test", 4, 2);
+ assert_element_equal(el2, el2b);
+
+ /* now try the same things with a long and a short value list.
+ this should still trigger the quadratic path.
+ */
+ el2 = new_msg_element(*state, "test", 4, 10);
+ orig2 = new_msg_element(*state, "test", 4, 10);
+
+ /* no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el3, orig3);
+
+ /*collisions with permissive flag*/
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el2, orig2);
+ assert_int_equal(el3->num_values, 0);
+
+ /* permutations involving empty elements.
+ everything should succeed. */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(el2->num_values, orig2->num_values);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(el2->num_values, orig2->num_values);
+ assert_int_equal(el3->num_values, 0); /* el3 is now empty */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el, orig);
+ assert_int_equal(el3->num_values, 0);
+
+ /* now with two large value lists */
+ el = new_msg_element(*state, "test", 0, 12);
+ orig = new_msg_element(*state, "test", 0, 12);
+ el4 = new_msg_element(*state, "test", 12, 12);
+ orig4 = new_msg_element(*state, "test", 12, 12);
+
+ /* no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el4, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el4, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el4, orig4);
+
+ /* with permissive control, but no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el4, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el4, orig4);
+
+ /* now with collisions, thus modifications.
+ At this stage:
+ el is 0-11 (inclusive)
+ e2 is 4-13
+ el3 is empty
+ el4 is 12-23
+ */
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el2, orig2);
+ assert_int_not_equal(el4->num_values, orig4->num_values);
+ /* 4 should start at 14 */
+ orig4 = new_msg_element(*state, "test", 14, 10);
+ assert_element_equal(el4, orig4);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el, orig);
+ assert_int_not_equal(el2->num_values, orig2->num_values);
+ orig2 = new_msg_element(*state, "test", 12, 2);
+ assert_element_equal(el2, orig2);
+
+ /* test the empty el against the full elements */
+ ret = ldb_msg_find_common_values(NULL, *state, el, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el, empty, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el, orig);
+ assert_element_equal(empty, el3);
+
+ /* make sure an identical element with a different name is rejected */
+ el2 = new_msg_element(*state, "fish", 12, 2);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
+ assert_int_equal(ret, LDB_ERR_INAPPROPRIATE_MATCHING);
+}
+
+
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_ldb_msg_find_duplicate_val,
+ ldb_msg_setup,
+ ldb_msg_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_msg_find_common_values,
+ ldb_msg_setup,
+ ldb_msg_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/python/api.py b/tests/python/api.py
index c2b3c89..b95266b 100755
--- a/tests/python/api.py
+++ b/tests/python/api.py
@@ -5,19 +5,21 @@
import os
from unittest import TestCase
import sys
-
+import gc
+import time
import ldb
+import shutil
PY3 = sys.version_info > (3, 0)
-def filename():
+def tempdir():
import tempfile
try:
dir_prefix = os.path.join(os.environ["SELFTEST_PREFIX"], "tmp")
except KeyError:
dir_prefix = None
- return tempfile.mktemp(dir=dir_prefix)
+ return tempfile.mkdtemp(dir=dir_prefix)
class NoContextTests(TestCase):
@@ -44,15 +46,25 @@ class NoContextTests(TestCase):
class SimpleLdb(TestCase):
+ def setUp(self):
+ super(SimpleLdb, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.filename)
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(SimpleLdb, self).tearDown()
+
def test_connect(self):
- ldb.Ldb(filename())
+ ldb.Ldb(self.filename)
def test_connect_none(self):
ldb.Ldb()
def test_connect_later(self):
x = ldb.Ldb()
- x.connect(filename())
+ x.connect(self.filename)
def test_repr(self):
x = ldb.Ldb()
@@ -67,7 +79,7 @@ class SimpleLdb(TestCase):
self.assertEqual([], x.modules())
def test_modules_tdb(self):
- x = ldb.Ldb(filename())
+ x = ldb.Ldb(self.filename)
self.assertEqual("[<ldb module 'tdb'>]", repr(x.modules()))
def test_firstmodule_none(self):
@@ -75,48 +87,53 @@ class SimpleLdb(TestCase):
self.assertEqual(x.firstmodule, None)
def test_firstmodule_tdb(self):
- x = ldb.Ldb(filename())
+ x = ldb.Ldb(self.filename)
mod = x.firstmodule
self.assertEqual(repr(mod), "<ldb module 'tdb'>")
def test_search(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(len(l.search()), 0)
def test_search_controls(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(len(l.search(controls=["paged_results:0:5"])), 0)
def test_search_attrs(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
def test_search_string_dn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(len(l.search("", ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
def test_search_attr_string(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertRaises(TypeError, l.search, attrs="dc")
self.assertRaises(TypeError, l.search, attrs=b"dc")
def test_opaque(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
l.set_opaque("my_opaque", l)
self.assertTrue(l.get_opaque("my_opaque") is not None)
self.assertEqual(None, l.get_opaque("unknown"))
- def test_search_scope_base(self):
- l = ldb.Ldb(filename())
+ def test_search_scope_base_empty_db(self):
+ l = ldb.Ldb(self.filename)
+ self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
+ ldb.SCOPE_BASE)), 0)
+
+ def test_search_scope_onelevel_empty_db(self):
+ l = ldb.Ldb(self.filename)
self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
ldb.SCOPE_ONELEVEL)), 0)
def test_delete(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertRaises(ldb.LdbError, lambda: l.delete(ldb.Dn(l, "dc=foo2")))
def test_delete_w_unhandled_ctrl(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=foo1")
m["b"] = [b"a"]
@@ -125,7 +142,7 @@ class SimpleLdb(TestCase):
l.delete(m.dn)
def test_contains(self):
- name = filename()
+ name = self.filename
l = ldb.Ldb(name)
self.assertFalse(ldb.Dn(l, "dc=foo3") in l)
l = ldb.Ldb(name)
@@ -140,23 +157,23 @@ class SimpleLdb(TestCase):
l.delete(m.dn)
def test_get_config_basedn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(None, l.get_config_basedn())
def test_get_root_basedn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(None, l.get_root_basedn())
def test_get_schema_basedn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(None, l.get_schema_basedn())
def test_get_default_basedn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(None, l.get_default_basedn())
def test_add(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=foo4")
m["bla"] = b"bla"
@@ -168,7 +185,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo4"))
def test_search_iterator(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
s = l.search_iterator()
s.abandon()
try:
@@ -268,7 +285,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo5"))
def test_add_text(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=foo4")
m["bla"] = "bla"
@@ -280,7 +297,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo4"))
def test_add_w_unhandled_ctrl(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=foo4")
m["bla"] = b"bla"
@@ -288,7 +305,7 @@ class SimpleLdb(TestCase):
self.assertRaises(ldb.LdbError, lambda: l.add(m,["search_options:1:2"]))
def test_add_dict(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = {"dn": ldb.Dn(l, "dc=foo5"),
"bla": b"bla"}
self.assertEqual(len(l.search()), 0)
@@ -299,7 +316,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo5"))
def test_add_dict_text(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = {"dn": ldb.Dn(l, "dc=foo5"),
"bla": "bla"}
self.assertEqual(len(l.search()), 0)
@@ -310,7 +327,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo5"))
def test_add_dict_string_dn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = {"dn": "dc=foo6", "bla": b"bla"}
self.assertEqual(len(l.search()), 0)
l.add(m)
@@ -320,7 +337,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo6"))
def test_add_dict_bytes_dn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = {"dn": b"dc=foo6", "bla": b"bla"}
self.assertEqual(len(l.search()), 0)
l.add(m)
@@ -330,7 +347,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=foo6"))
def test_rename(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=foo7")
m["bla"] = b"bla"
@@ -343,7 +360,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=bar"))
def test_rename_string_dns(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=foo8")
m["bla"] = b"bla"
@@ -357,7 +374,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=bar"))
def test_empty_dn(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertEqual(0, len(l.search()))
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=empty")
@@ -374,7 +391,7 @@ class SimpleLdb(TestCase):
self.assertEqual(0, len(rm[0]))
def test_modify_delete(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=modifydelete")
m["bla"] = [b"1234"]
@@ -397,7 +414,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=modifydelete"))
def test_modify_delete_text(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=modifydelete")
m.text["bla"] = ["1234"]
@@ -420,7 +437,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=modifydelete"))
def test_modify_add(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=add")
m["bla"] = [b"1234"]
@@ -438,7 +455,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=add"))
def test_modify_add_text(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=add")
m.text["bla"] = ["1234"]
@@ -456,7 +473,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=add"))
def test_modify_replace(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=modify2")
m["bla"] = [b"1234", b"456"]
@@ -476,7 +493,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=modify2"))
def test_modify_replace_text(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=modify2")
m.text["bla"] = ["1234", "456"]
@@ -496,7 +513,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=modify2"))
def test_modify_flags_change(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=add")
m["bla"] = [b"1234"]
@@ -522,7 +539,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=add"))
def test_modify_flags_change_text(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
m = ldb.Message()
m.dn = ldb.Dn(l, "dc=add")
m.text["bla"] = ["1234"]
@@ -548,7 +565,7 @@ class SimpleLdb(TestCase):
l.delete(ldb.Dn(l, "dc=add"))
def test_transaction_commit(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
l.transaction_start()
m = ldb.Message(ldb.Dn(l, "dc=foo9"))
m["foo"] = [b"bar"]
@@ -557,7 +574,7 @@ class SimpleLdb(TestCase):
l.delete(m.dn)
def test_transaction_cancel(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
l.transaction_start()
m = ldb.Message(ldb.Dn(l, "dc=foo10"))
m["foo"] = [b"bar"]
@@ -568,12 +585,12 @@ class SimpleLdb(TestCase):
def test_set_debug(self):
def my_report_fn(level, text):
pass
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
l.set_debug(my_report_fn)
def test_zero_byte_string(self):
"""Testing we do not get trapped in the \0 byte in a property string."""
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
l.add({
"dn" : b"dc=somedn",
"objectclass" : b"user",
@@ -585,15 +602,320 @@ class SimpleLdb(TestCase):
self.assertEqual(b"foo\0bar", res[0]["displayname"][0])
def test_no_crash_broken_expr(self):
- l = ldb.Ldb(filename())
+ l = ldb.Ldb(self.filename)
self.assertRaises(ldb.LdbError,lambda: l.search("", ldb.SCOPE_SUBTREE, "&(dc=*)(dn=*)", ["dc"]))
+class SearchTests(TestCase):
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(SearchTests, self).tearDown()
+
+ def setUp(self):
+ super(SearchTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "search_test.ldb")
+ self.l = ldb.Ldb(self.filename, options=["modules:rdn_name"])
+
+ self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": b"samba.org"})
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a"})
+ self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG",
+ "name": b"Users",
+ "x": "z", "y": "a"})
+ self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG",
+ "name": b"OU #1",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG",
+ "name": b"OU #2",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG",
+ "name": b"OU #3",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG",
+ "name": b"OU #4",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG",
+ "name": b"OU #5",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG",
+ "name": b"OU #6",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG",
+ "name": b"OU #7",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG",
+ "name": b"OU #8",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG",
+ "name": b"OU #9",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "y", "y": "a"})
+ self.l.add({"dn": "OU=OU12,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "y", "y": "b"})
+ self.l.add({"dn": "OU=OU13,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU14,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU15,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU16,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU17,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU18,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU19,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU20,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b"})
+ self.l.add({"dn": "OU=OU21,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "c"})
+ self.l.add({"dn": "OU=OU22,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "c"})
+
+ def test_base(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ def test_base_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 1)
+
+ def test_base_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 1)
+
+ def test_base_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(&(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_base_and2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(&(x=y)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_base_false(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou13)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_check_base_false(self):
+ """Testing a search"""
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou13)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_check_base_error(self):
+ """Testing a search"""
+ self.l.add({"dn": "@OPTIONS", "checkBaseOnSearch": b"TRUE"})
+
+ try:
+ res11 = self.l.search(base="OU=OU11x,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou13)(ou=ou12))")
+ self.fail("Should have failed on missing base")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ def test_subtree_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(x=y)(|(y=b)(y=c)))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 2)
+
+ def test_subtree_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 20)
+
+ def test_subtree_or3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(x=y)(y=b)(y=c))")
+ self.assertEqual(len(res11), 22)
+
+ def test_one_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_one_and2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=y)(y=b))")
+ self.assertEqual(len(res11), 1)
+
+ def test_one_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 2)
+
+ def test_one_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 20)
+
+ def test_subtree_and_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_or3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_subtree_and_or4(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_subtree_and_or5(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_or_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 10)
+
+ def test_subtree_large_and_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(ou=ou10)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_and_none(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+
+class IndexedSearchTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+ def setUp(self):
+ super(IndexedSearchTests, self).setUp()
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"]})
+
+
class DnTests(TestCase):
def setUp(self):
super(DnTests, self).setUp()
- self.ldb = ldb.Ldb(filename())
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.filename)
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(DnTests, self).tearDown()
def test_set_dn_invalid(self):
x = ldb.Message()
@@ -828,6 +1150,12 @@ class LdbMsgTests(TestCase):
def setUp(self):
super(LdbMsgTests, self).setUp()
self.msg = ldb.Message()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(LdbMsgTests, self).tearDown()
def test_init_dn(self):
self.msg = ldb.Message(ldb.Dn(ldb.Ldb(), "dc=foo27"))
@@ -835,11 +1163,11 @@ class LdbMsgTests(TestCase):
def test_iter_items(self):
self.assertEqual(0, len(self.msg.items()))
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "dc=foo28")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "dc=foo28")
self.assertEqual(1, len(self.msg.items()))
def test_repr(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "dc=foo29")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "dc=foo29")
self.msg["dc"] = b"foo"
if PY3:
self.assertIn(repr(self.msg), [
@@ -917,37 +1245,37 @@ class LdbMsgTests(TestCase):
self.assertEqual(["bar"], list(self.msg.text["foo"]))
def test_keys(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.msg["foo"] = [b"bla"]
self.msg["bar"] = [b"bla"]
self.assertEqual(["dn", "foo", "bar"], self.msg.keys())
def test_keys_text(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.msg["foo"] = ["bla"]
self.msg["bar"] = ["bla"]
self.assertEqual(["dn", "foo", "bar"], self.msg.text.keys())
def test_dn(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.assertEqual("@BASEINFO", self.msg.dn.__str__())
def test_get_dn(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.assertEqual("@BASEINFO", self.msg.get("dn").__str__())
def test_dn_text(self):
- self.msg.text.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.text.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.assertEqual("@BASEINFO", str(self.msg.dn))
self.assertEqual("@BASEINFO", str(self.msg.text.dn))
def test_get_dn_text(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.assertEqual("@BASEINFO", str(self.msg.get("dn")))
self.assertEqual("@BASEINFO", str(self.msg.text.get("dn")))
def test_get_invalid(self):
- self.msg.dn = ldb.Dn(ldb.Ldb(filename()), "@BASEINFO")
+ self.msg.dn = ldb.Dn(ldb.Ldb(self.filename), "@BASEINFO")
self.assertRaises(TypeError, self.msg.get, 42)
def test_get_other(self):
@@ -995,7 +1323,7 @@ class LdbMsgTests(TestCase):
self.assertEqual(msg1, msg2)
def test_equal_simplel(self):
- db = ldb.Ldb(filename())
+ db = ldb.Ldb(self.filename)
msg1 = ldb.Message()
msg1.dn = ldb.Dn(db, "foo=bar")
msg2 = ldb.Message()
@@ -1154,6 +1482,16 @@ class MessageElementTests(TestCase):
class ModuleTests(TestCase):
+ def setUp(self):
+ super(ModuleTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.filename)
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(ModuleTests, self).setUp()
+
def test_register_module(self):
class ExampleModule:
name = "example"
@@ -1174,25 +1512,20 @@ class ModuleTests(TestCase):
def request(self, *args, **kwargs):
pass
- name = filename()
ldb.register_module(ExampleModule)
- if os.path.exists(name):
- os.unlink(name)
- l = ldb.Ldb(name)
+ l = ldb.Ldb(self.filename)
l.add({"dn": "@MODULES", "@LIST": "bla"})
self.assertEqual([], ops)
- l = ldb.Ldb(name)
+ l = ldb.Ldb(self.filename)
self.assertEqual(["init"], ops)
class LdbResultTests(TestCase):
def setUp(self):
super(LdbResultTests, self).setUp()
- name = filename()
- self.name = name
- if os.path.exists(name):
- os.unlink(name)
- self.l = ldb.Ldb(name)
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.l = ldb.Ldb(self.filename)
self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": b"samba.org"})
self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG", "name": b"Admins"})
self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG", "name": b"Users"})
@@ -1208,9 +1541,8 @@ class LdbResultTests(TestCase):
self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG", "name": b"OU #10"})
def tearDown(self):
+ shutil.rmtree(self.testdir)
super(LdbResultTests, self).tearDown()
- if os.path.exists(self.name):
- os.unlink(self.name)
def test_return_type(self):
res = self.l.search()
@@ -1254,7 +1586,7 @@ class LdbResultTests(TestCase):
res = self.l.search().referals
it = iter(res)
- def test_iter_as_sequence_msgs(self):
+ def test_search_sequence_msgs(self):
found = False
res = self.l.search().msgs
@@ -1264,17 +1596,178 @@ class LdbResultTests(TestCase):
found = True
self.assertTrue(found)
- def test_iter_as_sequence(self):
+ def test_search_as_iter(self):
found = False
res = self.l.search()
- for i in range(0, len(res)):
- l = res[i]
+ for l in res:
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ self.assertTrue(found)
+
+ def test_search_iter(self):
+ found = False
+ res = self.l.search_iterator()
+
+ for l in res:
if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
found = True
self.assertTrue(found)
+ # Show that search results can't see into a transaction
+ def test_search_against_trans(self):
+ found11 = False
+
+ (r1, w1) = os.pipe()
+
+ (r2, w2) = os.pipe()
+
+ # For the first element, fork a child that will
+ # write to the DB
+ pid = os.fork()
+ if pid == 0:
+ # In the child, re-open
+ del(self.l)
+ gc.collect()
+
+ child_ldb = ldb.Ldb(self.filename)
+ # start a transaction
+ child_ldb.transaction_start()
+
+ # write to it
+ child_ldb.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
+ "name": b"samba.org"})
+
+ os.write(w1, b"added")
+
+ # Now wait for the search to be done
+ os.read(r2, 6)
+
+ # and commit
+ try:
+ child_ldb.transaction_commit()
+ except LdbError as err:
+ # We print this here to see what went wrong in the child
+ print(err)
+ os._exit(1)
+
+ os.write(w1, b"transaction")
+ os._exit(0)
+
+ self.assertEqual(os.read(r1, 5), b"added")
+
+ # This should not turn up until the transaction is concluded
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 0)
+
+ os.write(w2, b"search")
+
+ # Now wait for the transaction to be done. This should
+ # deadlock, but the search doesn't hold a read lock for the
+ # iterator lifetime currently.
+ self.assertEqual(os.read(r1, 11), b"transaction")
+
+ # This should now turn up, as the transaction is over
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ self.assertFalse(found11)
+
+ (got_pid, status) = os.waitpid(pid, 0)
+ self.assertEqual(got_pid, pid)
+
+
+ def test_search_iter_against_trans(self):
+ found = False
+ found11 = False
+
+ # We need to hold this iterator open to hold the all-record
+ # lock
+ res = self.l.search_iterator()
+
+ (r1, w1) = os.pipe()
+
+ (r2, w2) = os.pipe()
+
+ # For the first element, with the sequence open (which
+ # means with ldb locks held), fork a child that will
+ # write to the DB
+ pid = os.fork()
+ if pid == 0:
+ # In the child, re-open
+ del(res)
+ del(self.l)
+ gc.collect()
+
+ child_ldb = ldb.Ldb(self.filename)
+ # start a transaction
+ child_ldb.transaction_start()
+
+ # write to it
+ child_ldb.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
+ "name": b"samba.org"})
+
+ os.write(w1, b"added")
+
+ # Now wait for the search to be done
+ os.read(r2, 6)
+
+ # and commit
+ try:
+ child_ldb.transaction_commit()
+ except LdbError as err:
+ # We print this here to see what went wrong in the child
+ print(err)
+ os._exit(1)
+
+ os.write(w1, b"transaction")
+ os._exit(0)
+
+ self.assertEqual(os.read(r1, 5), b"added")
+
+ # This should not turn up until the transaction is concluded
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 0)
+
+ os.write(w2, b"search")
+
+ # allow the transaction to start
+ time.sleep(1)
+
+ # This should not turn up until the search finishes and
+ # removed the read lock, but for ldb_tdb that happened as soon
+ # as we called the first res.next()
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 0)
+
+ # These results are all collected at the first next(res) call
+ for l in res:
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ if str(l.dn) == "OU=OU11,DC=SAMBA,DC=ORG":
+ found11 = True
+
+ # Now wait for the transaction to be done.
+ self.assertEqual(os.read(r1, 11), b"transaction")
+
+ # This should now turn up, as the transaction is over and all
+ # read locks are gone
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ self.assertTrue(found)
+ self.assertFalse(found11)
+
+ (got_pid, status) = os.waitpid(pid, 0)
+ self.assertEqual(got_pid, pid)
+
+
class BadTypeTests(TestCase):
def test_control(self):
l = ldb.Ldb()
diff --git a/third_party/cmocka/cmocka.c b/third_party/cmocka/cmocka.c
new file mode 100644
index 0000000..14b2765
--- /dev/null
+++ b/third_party/cmocka/cmocka.c
@@ -0,0 +1,3306 @@
+/*
+ * Copyright 2008 Google Inc.
+ * Copyright 2014-2015 Andreas Schneider <asn@cryptomilk.org>
+ * Copyright 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/*
+ * This allows to add a platform specific header file. Some embedded platforms
+ * sometimes miss certain types and definitions.
+ *
+ * Example:
+ *
+ * typedef unsigned long int uintptr_t
+ * #define _UINTPTR_T 1
+ * #define _UINTPTR_T_DEFINED 1
+ */
+#ifdef CMOCKA_PLATFORM_INCLUDE
+# include "cmocka_platform.h"
+#endif /* CMOCKA_PLATFORM_INCLUDE */
+
+#include <cmocka.h>
+#include <cmocka_private.h>
+
+/* Size of guard bytes around dynamically allocated blocks. */
+#define MALLOC_GUARD_SIZE 16
+/* Pattern used to initialize guard blocks. */
+#define MALLOC_GUARD_PATTERN 0xEF
+/* Pattern used to initialize memory allocated with test_malloc(). */
+#define MALLOC_ALLOC_PATTERN 0xBA
+#define MALLOC_FREE_PATTERN 0xCD
+/* Alignment of allocated blocks. NOTE: This must be base2. */
+#define MALLOC_ALIGNMENT sizeof(size_t)
+
+/* Printf formatting for source code locations. */
+#define SOURCE_LOCATION_FORMAT "%s:%u"
+
+#if defined(HAVE_GCC_THREAD_LOCAL_STORAGE)
+# define CMOCKA_THREAD __thread
+#elif defined(HAVE_MSVC_THREAD_LOCAL_STORAGE)
+# define CMOCKA_THREAD __declspec(thread)
+#else
+# define CMOCKA_THREAD
+#endif
+
+#ifdef HAVE_CLOCK_REALTIME
+#define CMOCKA_CLOCK_GETTIME(clock_id, ts) clock_gettime((clock_id), (ts))
+#else
+#define CMOCKA_CLOCK_GETTIME(clock_id, ts)
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+/**
+ * POSIX has sigsetjmp/siglongjmp, while Windows only has setjmp/longjmp.
+ */
+#ifdef HAVE_SIGLONGJMP
+# define cm_jmp_buf sigjmp_buf
+# define cm_setjmp(env) sigsetjmp(env, 1)
+# define cm_longjmp(env, val) siglongjmp(env, val)
+#else
+# define cm_jmp_buf jmp_buf
+# define cm_setjmp(env) setjmp(env)
+# define cm_longjmp(env, val) longjmp(env, val)
+#endif
+
+
+/*
+ * Declare and initialize the pointer member of ValuePointer variable name
+ * with ptr.
+ */
+#define declare_initialize_value_pointer_pointer(name, ptr) \
+ ValuePointer name ; \
+ name.value = 0; \
+ name.x.pointer = (void*)(ptr)
+
+/*
+ * Declare and initialize the value member of ValuePointer variable name
+ * with val.
+ */
+#define declare_initialize_value_pointer_value(name, val) \
+ ValuePointer name ; \
+ name.value = val
+
+/* Cast a LargestIntegralType to pointer_type via a ValuePointer. */
+#define cast_largest_integral_type_to_pointer( \
+ pointer_type, largest_integral_type) \
+ ((pointer_type)((ValuePointer*)&(largest_integral_type))->x.pointer)
+
+/* Used to cast LargetIntegralType to void* and vice versa. */
+typedef union ValuePointer {
+ LargestIntegralType value;
+ struct {
+#if defined(WORDS_BIGENDIAN) && (WORDS_SIZEOF_VOID_P == 4)
+ unsigned int padding;
+#endif
+ void *pointer;
+ } x;
+} ValuePointer;
+
+/* Doubly linked list node. */
+typedef struct ListNode {
+ const void *value;
+ int refcount;
+ struct ListNode *next;
+ struct ListNode *prev;
+} ListNode;
+
+/* Debug information for malloc(). */
+typedef struct MallocBlockInfo {
+ void* block; /* Address of the block returned by malloc(). */
+ size_t allocated_size; /* Total size of the allocated block. */
+ size_t size; /* Request block size. */
+ SourceLocation location; /* Where the block was allocated. */
+ ListNode node; /* Node within list of all allocated blocks. */
+} MallocBlockInfo;
+
+/* State of each test. */
+typedef struct TestState {
+ const ListNode *check_point; /* Check point of the test if there's a */
+ /* setup function. */
+ void *state; /* State associated with the test. */
+} TestState;
+
+/* Determines whether two values are the same. */
+typedef int (*EqualityFunction)(const void *left, const void *right);
+
+/* Value of a symbol and the place it was declared. */
+typedef struct SymbolValue {
+ SourceLocation location;
+ LargestIntegralType value;
+} SymbolValue;
+
+/*
+ * Contains a list of values for a symbol.
+ * NOTE: Each structure referenced by symbol_values_list_head must have a
+ * SourceLocation as its' first member.
+ */
+typedef struct SymbolMapValue {
+ const char *symbol_name;
+ ListNode symbol_values_list_head;
+} SymbolMapValue;
+
+/* Where a particular ordering was located and its symbol name */
+typedef struct FuncOrderingValue {
+ SourceLocation location;
+ const char * function;
+} FuncOrderingValue;
+
+/* Used by list_free() to deallocate values referenced by list nodes. */
+typedef void (*CleanupListValue)(const void *value, void *cleanup_value_data);
+
+/* Structure used to check the range of integer types.a */
+typedef struct CheckIntegerRange {
+ CheckParameterEvent event;
+ LargestIntegralType minimum;
+ LargestIntegralType maximum;
+} CheckIntegerRange;
+
+/* Structure used to check whether an integer value is in a set. */
+typedef struct CheckIntegerSet {
+ CheckParameterEvent event;
+ const LargestIntegralType *set;
+ size_t size_of_set;
+} CheckIntegerSet;
+
+/* Used to check whether a parameter matches the area of memory referenced by
+ * this structure. */
+typedef struct CheckMemoryData {
+ CheckParameterEvent event;
+ const void *memory;
+ size_t size;
+} CheckMemoryData;
+
+static ListNode* list_initialize(ListNode * const node);
+static ListNode* list_add(ListNode * const head, ListNode *new_node);
+static ListNode* list_add_value(ListNode * const head, const void *value,
+ const int count);
+static ListNode* list_remove(
+ ListNode * const node, const CleanupListValue cleanup_value,
+ void * const cleanup_value_data);
+static void list_remove_free(
+ ListNode * const node, const CleanupListValue cleanup_value,
+ void * const cleanup_value_data);
+static int list_empty(const ListNode * const head);
+static int list_find(
+ ListNode * const head, const void *value,
+ const EqualityFunction equal_func, ListNode **output);
+static int list_first(ListNode * const head, ListNode **output);
+static ListNode* list_free(
+ ListNode * const head, const CleanupListValue cleanup_value,
+ void * const cleanup_value_data);
+
+static void add_symbol_value(
+ ListNode * const symbol_map_head, const char * const symbol_names[],
+ const size_t number_of_symbol_names, const void* value, const int count);
+static int get_symbol_value(
+ ListNode * const symbol_map_head, const char * const symbol_names[],
+ const size_t number_of_symbol_names, void **output);
+static void free_value(const void *value, void *cleanup_value_data);
+static void free_symbol_map_value(
+ const void *value, void *cleanup_value_data);
+static void remove_always_return_values(ListNode * const map_head,
+ const size_t number_of_symbol_names);
+
+static int check_for_leftover_values_list(const ListNode * head,
+ const char * const error_message);
+
+static int check_for_leftover_values(
+ const ListNode * const map_head, const char * const error_message,
+ const size_t number_of_symbol_names);
+
+static void remove_always_return_values_from_list(ListNode * const map_head);
+
+/*
+ * This must be called at the beginning of a test to initialize some data
+ * structures.
+ */
+static void initialize_testing(const char *test_name);
+
+/* This must be called at the end of a test to free() allocated structures. */
+static void teardown_testing(const char *test_name);
+
+static enum cm_message_output cm_get_output(void);
+
+static int cm_error_message_enabled = 1;
+static CMOCKA_THREAD char *cm_error_message;
+
+void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2);
+
+/*
+ * Keeps track of the calling context returned by setenv() so that the fail()
+ * method can jump out of a test.
+ */
+static CMOCKA_THREAD cm_jmp_buf global_run_test_env;
+static CMOCKA_THREAD int global_running_test = 0;
+
+/* Keeps track of the calling context returned by setenv() so that */
+/* mock_assert() can optionally jump back to expect_assert_failure(). */
+jmp_buf global_expect_assert_env;
+int global_expecting_assert = 0;
+const char *global_last_failed_assert = NULL;
+static int global_skip_test;
+
+/* Keeps a map of the values that functions will have to return to provide */
+/* mocked interfaces. */
+static CMOCKA_THREAD ListNode global_function_result_map_head;
+/* Location of the last mock value returned was declared. */
+static CMOCKA_THREAD SourceLocation global_last_mock_value_location;
+
+/* Keeps a map of the values that functions expect as parameters to their
+ * mocked interfaces. */
+static CMOCKA_THREAD ListNode global_function_parameter_map_head;
+/* Location of last parameter value checked was declared. */
+static CMOCKA_THREAD SourceLocation global_last_parameter_location;
+
+/* List (acting as FIFO) of call ordering. */
+static CMOCKA_THREAD ListNode global_call_ordering_head;
+/* Location of last call ordering that was declared. */
+static CMOCKA_THREAD SourceLocation global_last_call_ordering_location;
+
+/* List of all currently allocated blocks. */
+static CMOCKA_THREAD ListNode global_allocated_blocks;
+
+static enum cm_message_output global_msg_output = CM_OUTPUT_STDOUT;
+
+#ifndef _WIN32
+/* Signals caught by exception_handler(). */
+static const int exception_signals[] = {
+ SIGFPE,
+ SIGILL,
+ SIGSEGV,
+#ifdef SIGBUS
+ SIGBUS,
+#endif
+#ifdef SIGSYS
+ SIGSYS,
+#endif
+};
+
+/* Default signal functions that should be restored after a test is complete. */
+typedef void (*SignalFunction)(int signal);
+static SignalFunction default_signal_functions[
+ ARRAY_SIZE(exception_signals)];
+
+#else /* _WIN32 */
+
+/* The default exception filter. */
+static LPTOP_LEVEL_EXCEPTION_FILTER previous_exception_filter;
+
+/* Fatal exceptions. */
+typedef struct ExceptionCodeInfo {
+ DWORD code;
+ const char* description;
+} ExceptionCodeInfo;
+
+#define EXCEPTION_CODE_INFO(exception_code) {exception_code, #exception_code}
+
+static const ExceptionCodeInfo exception_codes[] = {
+ EXCEPTION_CODE_INFO(EXCEPTION_ACCESS_VIOLATION),
+ EXCEPTION_CODE_INFO(EXCEPTION_ARRAY_BOUNDS_EXCEEDED),
+ EXCEPTION_CODE_INFO(EXCEPTION_DATATYPE_MISALIGNMENT),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_DENORMAL_OPERAND),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_DIVIDE_BY_ZERO),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_INEXACT_RESULT),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_INVALID_OPERATION),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_OVERFLOW),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_STACK_CHECK),
+ EXCEPTION_CODE_INFO(EXCEPTION_FLT_UNDERFLOW),
+ EXCEPTION_CODE_INFO(EXCEPTION_GUARD_PAGE),
+ EXCEPTION_CODE_INFO(EXCEPTION_ILLEGAL_INSTRUCTION),
+ EXCEPTION_CODE_INFO(EXCEPTION_INT_DIVIDE_BY_ZERO),
+ EXCEPTION_CODE_INFO(EXCEPTION_INT_OVERFLOW),
+ EXCEPTION_CODE_INFO(EXCEPTION_INVALID_DISPOSITION),
+ EXCEPTION_CODE_INFO(EXCEPTION_INVALID_HANDLE),
+ EXCEPTION_CODE_INFO(EXCEPTION_IN_PAGE_ERROR),
+ EXCEPTION_CODE_INFO(EXCEPTION_NONCONTINUABLE_EXCEPTION),
+ EXCEPTION_CODE_INFO(EXCEPTION_PRIV_INSTRUCTION),
+ EXCEPTION_CODE_INFO(EXCEPTION_STACK_OVERFLOW),
+};
+#endif /* !_WIN32 */
+
+enum CMUnitTestStatus {
+ CM_TEST_NOT_STARTED,
+ CM_TEST_PASSED,
+ CM_TEST_FAILED,
+ CM_TEST_ERROR,
+ CM_TEST_SKIPPED,
+};
+
+struct CMUnitTestState {
+ const ListNode *check_point; /* Check point of the test if there's a setup function. */
+ const struct CMUnitTest *test; /* Point to array element in the tests we get passed */
+ void *state; /* State associated with the test */
+ const char *error_message; /* The error messages by the test */
+ enum CMUnitTestStatus status; /* PASSED, FAILED, ABORT ... */
+ double runtime; /* Time calculations */
+};
+
+/* Exit the currently executing test. */
+static void exit_test(const int quit_application)
+{
+ const char *abort_test = getenv("CMOCKA_TEST_ABORT");
+
+ if (abort_test != NULL && abort_test[0] == '1') {
+ print_error("%s", cm_error_message);
+ abort();
+ } else if (global_running_test) {
+ cm_longjmp(global_run_test_env, 1);
+ } else if (quit_application) {
+ exit(-1);
+ }
+}
+
+void _skip(const char * const file, const int line)
+{
+ cm_print_error(SOURCE_LOCATION_FORMAT ": Skipped!\n", file, line);
+ global_skip_test = 1;
+ exit_test(1);
+}
+
+/* Initialize a SourceLocation structure. */
+static void initialize_source_location(SourceLocation * const location) {
+ assert_non_null(location);
+ location->file = NULL;
+ location->line = 0;
+}
+
+
+/* Determine whether a source location is currently set. */
+static int source_location_is_set(const SourceLocation * const location) {
+ assert_non_null(location);
+ return location->file && location->line;
+}
+
+
+/* Set a source location. */
+static void set_source_location(
+ SourceLocation * const location, const char * const file,
+ const int line) {
+ assert_non_null(location);
+ location->file = file;
+ location->line = line;
+}
+
+
+static int c_strreplace(char *src,
+ size_t src_len,
+ const char *pattern,
+ const char *repl,
+ int *str_replaced)
+{
+ char *p = NULL;
+
+ p = strstr(src, pattern);
+ if (p == NULL) {
+ return -1;
+ }
+
+ do {
+ size_t of = p - src;
+ size_t l = strlen(src);
+ size_t pl = strlen(pattern);
+ size_t rl = strlen(repl);
+
+ /* overflow check */
+ if (src_len <= l + MAX(pl, rl) + 1) {
+ return -1;
+ }
+
+ if (rl != pl) {
+ memmove(src + of + rl, src + of + pl, l - of - pl + 1);
+ }
+
+ strncpy(src + of, repl, rl);
+
+ if (str_replaced != NULL) {
+ *str_replaced = 1;
+ }
+ p = strstr(src, pattern);
+ } while (p != NULL);
+
+ return 0;
+}
+
+/* Create function results and expected parameter lists. */
+void initialize_testing(const char *test_name) {
+ (void)test_name;
+ list_initialize(&global_function_result_map_head);
+ initialize_source_location(&global_last_mock_value_location);
+ list_initialize(&global_function_parameter_map_head);
+ initialize_source_location(&global_last_parameter_location);
+ list_initialize(&global_call_ordering_head);
+ initialize_source_location(&global_last_parameter_location);
+}
+
+
+static void fail_if_leftover_values(const char *test_name) {
+ int error_occurred = 0;
+ (void)test_name;
+ remove_always_return_values(&global_function_result_map_head, 1);
+ if (check_for_leftover_values(
+ &global_function_result_map_head,
+ "%s() has remaining non-returned values.\n", 1)) {
+ error_occurred = 1;
+ }
+
+ remove_always_return_values(&global_function_parameter_map_head, 2);
+ if (check_for_leftover_values(
+ &global_function_parameter_map_head,
+ "%s parameter still has values that haven't been checked.\n", 2)) {
+ error_occurred = 1;
+ }
+
+ remove_always_return_values_from_list(&global_call_ordering_head);
+ if (check_for_leftover_values_list(&global_call_ordering_head,
+ "%s function was expected to be called but was not not.\n")) {
+ error_occurred = 1;
+ }
+ if (error_occurred) {
+ exit_test(1);
+ }
+}
+
+
+static void teardown_testing(const char *test_name) {
+ (void)test_name;
+ list_free(&global_function_result_map_head, free_symbol_map_value,
+ (void*)0);
+ initialize_source_location(&global_last_mock_value_location);
+ list_free(&global_function_parameter_map_head, free_symbol_map_value,
+ (void*)1);
+ initialize_source_location(&global_last_parameter_location);
+ list_free(&global_call_ordering_head, free_value,
+ (void*)0);
+ initialize_source_location(&global_last_call_ordering_location);
+}
+
+/* Initialize a list node. */
+static ListNode* list_initialize(ListNode * const node) {
+ node->value = NULL;
+ node->next = node;
+ node->prev = node;
+ node->refcount = 1;
+ return node;
+}
+
+
+/*
+ * Adds a value at the tail of a given list.
+ * The node referencing the value is allocated from the heap.
+ */
+static ListNode* list_add_value(ListNode * const head, const void *value,
+ const int refcount) {
+ ListNode * const new_node = (ListNode*)malloc(sizeof(ListNode));
+ assert_non_null(head);
+ assert_non_null(value);
+ new_node->value = value;
+ new_node->refcount = refcount;
+ return list_add(head, new_node);
+}
+
+
+/* Add new_node to the end of the list. */
+static ListNode* list_add(ListNode * const head, ListNode *new_node) {
+ assert_non_null(head);
+ assert_non_null(new_node);
+ new_node->next = head;
+ new_node->prev = head->prev;
+ head->prev->next = new_node;
+ head->prev = new_node;
+ return new_node;
+}
+
+
+/* Remove a node from a list. */
+static ListNode* list_remove(
+ ListNode * const node, const CleanupListValue cleanup_value,
+ void * const cleanup_value_data) {
+ assert_non_null(node);
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ if (cleanup_value) {
+ cleanup_value(node->value, cleanup_value_data);
+ }
+ return node;
+}
+
+
+/* Remove a list node from a list and free the node. */
+static void list_remove_free(
+ ListNode * const node, const CleanupListValue cleanup_value,
+ void * const cleanup_value_data) {
+ assert_non_null(node);
+ free(list_remove(node, cleanup_value, cleanup_value_data));
+}
+
+
+/*
+ * Frees memory kept by a linked list The cleanup_value function is called for
+ * every "value" field of nodes in the list, except for the head. In addition
+ * to each list value, cleanup_value_data is passed to each call to
+ * cleanup_value. The head of the list is not deallocated.
+ */
+static ListNode* list_free(
+ ListNode * const head, const CleanupListValue cleanup_value,
+ void * const cleanup_value_data) {
+ assert_non_null(head);
+ while (!list_empty(head)) {
+ list_remove_free(head->next, cleanup_value, cleanup_value_data);
+ }
+ return head;
+}
+
+
+/* Determine whether a list is empty. */
+static int list_empty(const ListNode * const head) {
+ assert_non_null(head);
+ return head->next == head;
+}
+
+
+/*
+ * Find a value in the list using the equal_func to compare each node with the
+ * value.
+ */
+static int list_find(ListNode * const head, const void *value,
+ const EqualityFunction equal_func, ListNode **output) {
+ ListNode *current;
+ assert_non_null(head);
+ for (current = head->next; current != head; current = current->next) {
+ if (equal_func(current->value, value)) {
+ *output = current;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Returns the first node of a list */
+static int list_first(ListNode * const head, ListNode **output) {
+ ListNode *target_node;
+ assert_non_null(head);
+ if (list_empty(head)) {
+ return 0;
+ }
+ target_node = head->next;
+ *output = target_node;
+ return 1;
+}
+
+
+/* Deallocate a value referenced by a list. */
+static void free_value(const void *value, void *cleanup_value_data) {
+ (void)cleanup_value_data;
+ assert_non_null(value);
+ free((void*)value);
+}
+
+
+/* Releases memory associated to a symbol_map_value. */
+static void free_symbol_map_value(const void *value,
+ void *cleanup_value_data) {
+ SymbolMapValue * const map_value = (SymbolMapValue*)value;
+ const LargestIntegralType children = cast_ptr_to_largest_integral_type(cleanup_value_data);
+ assert_non_null(value);
+ list_free(&map_value->symbol_values_list_head,
+ children ? free_symbol_map_value : free_value,
+ (void *) ((uintptr_t)children - 1));
+ free(map_value);
+}
+
+
+/*
+ * Determine whether a symbol name referenced by a symbol_map_value matches the
+ * specified function name.
+ */
+static int symbol_names_match(const void *map_value, const void *symbol) {
+ return !strcmp(((SymbolMapValue*)map_value)->symbol_name,
+ (const char*)symbol);
+}
+
+/*
+ * Adds a value to the queue of values associated with the given hierarchy of
+ * symbols. It's assumed value is allocated from the heap.
+ */
+static void add_symbol_value(ListNode * const symbol_map_head,
+ const char * const symbol_names[],
+ const size_t number_of_symbol_names,
+ const void* value, const int refcount) {
+ const char* symbol_name;
+ ListNode *target_node;
+ SymbolMapValue *target_map_value;
+ assert_non_null(symbol_map_head);
+ assert_non_null(symbol_names);
+ assert_true(number_of_symbol_names);
+ symbol_name = symbol_names[0];
+
+ if (!list_find(symbol_map_head, symbol_name, symbol_names_match,
+ &target_node)) {
+ SymbolMapValue * const new_symbol_map_value =
+ (SymbolMapValue*)malloc(sizeof(*new_symbol_map_value));
+ new_symbol_map_value->symbol_name = symbol_name;
+ list_initialize(&new_symbol_map_value->symbol_values_list_head);
+ target_node = list_add_value(symbol_map_head, new_symbol_map_value,
+ 1);
+ }
+
+ target_map_value = (SymbolMapValue*)target_node->value;
+ if (number_of_symbol_names == 1) {
+ list_add_value(&target_map_value->symbol_values_list_head,
+ value, refcount);
+ } else {
+ add_symbol_value(&target_map_value->symbol_values_list_head,
+ &symbol_names[1], number_of_symbol_names - 1, value,
+ refcount);
+ }
+}
+
+
+/*
+ * Gets the next value associated with the given hierarchy of symbols.
+ * The value is returned as an output parameter with the function returning the
+ * node's old refcount value if a value is found, 0 otherwise. This means that
+ * a return value of 1 indicates the node was just removed from the list.
+ */
+static int get_symbol_value(
+ ListNode * const head, const char * const symbol_names[],
+ const size_t number_of_symbol_names, void **output) {
+ const char* symbol_name;
+ ListNode *target_node;
+ assert_non_null(head);
+ assert_non_null(symbol_names);
+ assert_true(number_of_symbol_names);
+ assert_non_null(output);
+ symbol_name = symbol_names[0];
+
+ if (list_find(head, symbol_name, symbol_names_match, &target_node)) {
+ SymbolMapValue *map_value;
+ ListNode *child_list;
+ int return_value = 0;
+ assert_non_null(target_node);
+ assert_non_null(target_node->value);
+
+ map_value = (SymbolMapValue*)target_node->value;
+ child_list = &map_value->symbol_values_list_head;
+
+ if (number_of_symbol_names == 1) {
+ ListNode *value_node = NULL;
+ return_value = list_first(child_list, &value_node);
+ assert_true(return_value);
+ *output = (void*) value_node->value;
+ return_value = value_node->refcount;
+ if (value_node->refcount - 1 == 0) {
+ list_remove_free(value_node, NULL, NULL);
+ } else if (value_node->refcount > WILL_RETURN_ONCE) {
+ --value_node->refcount;
+ }
+ } else {
+ return_value = get_symbol_value(
+ child_list, &symbol_names[1], number_of_symbol_names - 1,
+ output);
+ }
+ if (list_empty(child_list)) {
+ list_remove_free(target_node, free_symbol_map_value, (void*)0);
+ }
+ return return_value;
+ } else {
+ cm_print_error("No entries for symbol %s.\n", symbol_name);
+ }
+ return 0;
+}
+
+/**
+ * Taverse a list of nodes and remove first symbol value in list that has a
+ * refcount < -1 (i.e. should always be returned and has been returned at
+ * least once).
+ */
+
+static void remove_always_return_values_from_list(ListNode * const map_head)
+{
+ ListNode * current = NULL;
+ ListNode * next = NULL;
+ assert_non_null(map_head);
+
+ for (current = map_head->next, next = current->next;
+ current != map_head;
+ current = next, next = current->next) {
+ if (current->refcount < -1) {
+ list_remove_free(current, free_value, NULL);
+ }
+ }
+}
+
+/*
+ * Traverse down a tree of symbol values and remove the first symbol value
+ * in each branch that has a refcount < -1 (i.e should always be returned
+ * and has been returned at least once).
+ */
+static void remove_always_return_values(ListNode * const map_head,
+ const size_t number_of_symbol_names) {
+ ListNode *current;
+ assert_non_null(map_head);
+ assert_true(number_of_symbol_names);
+ current = map_head->next;
+ while (current != map_head) {
+ SymbolMapValue * const value = (SymbolMapValue*)current->value;
+ ListNode * const next = current->next;
+ ListNode *child_list;
+ assert_non_null(value);
+ child_list = &value->symbol_values_list_head;
+
+ if (!list_empty(child_list)) {
+ if (number_of_symbol_names == 1) {
+ ListNode * const child_node = child_list->next;
+ /* If this item has been returned more than once, free it. */
+ if (child_node->refcount < -1) {
+ list_remove_free(child_node, free_value, NULL);
+ }
+ } else {
+ remove_always_return_values(child_list,
+ number_of_symbol_names - 1);
+ }
+ }
+
+ if (list_empty(child_list)) {
+ list_remove_free(current, free_value, NULL);
+ }
+ current = next;
+ }
+}
+
+static int check_for_leftover_values_list(const ListNode * head,
+ const char * const error_message)
+{
+ ListNode *child_node;
+ int leftover_count = 0;
+ if (!list_empty(head))
+ {
+ for (child_node = head->next; child_node != head;
+ child_node = child_node->next, ++leftover_count) {
+ const FuncOrderingValue *const o =
+ (const FuncOrderingValue*) child_node->value;
+ cm_print_error(error_message, o->function);
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": note: remaining item was declared here\n",
+ o->location.file, o->location.line);
+ }
+ }
+ return leftover_count;
+}
+
+/*
+ * Checks if there are any leftover values set up by the test that were never
+ * retrieved through execution, and fail the test if that is the case.
+ */
+static int check_for_leftover_values(
+ const ListNode * const map_head, const char * const error_message,
+ const size_t number_of_symbol_names) {
+ const ListNode *current;
+ int symbols_with_leftover_values = 0;
+ assert_non_null(map_head);
+ assert_true(number_of_symbol_names);
+
+ for (current = map_head->next; current != map_head;
+ current = current->next) {
+ const SymbolMapValue * const value =
+ (SymbolMapValue*)current->value;
+ const ListNode *child_list;
+ assert_non_null(value);
+ child_list = &value->symbol_values_list_head;
+
+ if (!list_empty(child_list)) {
+ if (number_of_symbol_names == 1) {
+ const ListNode *child_node;
+ cm_print_error(error_message, value->symbol_name);
+
+ for (child_node = child_list->next; child_node != child_list;
+ child_node = child_node->next) {
+ const SourceLocation * const location =
+ (const SourceLocation*)child_node->value;
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": note: remaining item was declared here\n",
+ location->file, location->line);
+ }
+ } else {
+ cm_print_error("%s.", value->symbol_name);
+ check_for_leftover_values(child_list, error_message,
+ number_of_symbol_names - 1);
+ }
+ symbols_with_leftover_values ++;
+ }
+ }
+ return symbols_with_leftover_values;
+}
+
+
+/* Get the next return value for the specified mock function. */
+LargestIntegralType _mock(const char * const function, const char* const file,
+ const int line) {
+ void *result;
+ const int rc = get_symbol_value(&global_function_result_map_head,
+ &function, 1, &result);
+ if (rc) {
+ SymbolValue * const symbol = (SymbolValue*)result;
+ const LargestIntegralType value = symbol->value;
+ global_last_mock_value_location = symbol->location;
+ if (rc == 1) {
+ free(symbol);
+ }
+ return value;
+ } else {
+ cm_print_error(SOURCE_LOCATION_FORMAT ": error: Could not get value "
+ "to mock function %s\n", file, line, function);
+ if (source_location_is_set(&global_last_mock_value_location)) {
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": note: Previously returned mock value was declared here\n",
+ global_last_mock_value_location.file,
+ global_last_mock_value_location.line);
+ } else {
+ cm_print_error("There were no previously returned mock values for "
+ "this test.\n");
+ }
+ exit_test(1);
+ }
+ return 0;
+}
+
+/* Ensure that function is being called in proper order */
+void _function_called(const char *const function,
+ const char *const file,
+ const int line)
+{
+ ListNode *first_value_node = NULL;
+ ListNode *value_node = NULL;
+ int rc;
+
+ rc = list_first(&global_call_ordering_head, &value_node);
+ first_value_node = value_node;
+ if (rc) {
+ FuncOrderingValue *expected_call;
+ int cmp;
+
+ expected_call = (FuncOrderingValue *)value_node->value;
+
+ cmp = strcmp(expected_call->function, function);
+ if (value_node->refcount < -1) {
+ /*
+ * Search through value nodes until either function is found or
+ * encounter a non-zero refcount greater than -2
+ */
+ if (cmp != 0) {
+ value_node = value_node->next;
+ expected_call = (FuncOrderingValue *)value_node->value;
+
+ cmp = strcmp(expected_call->function, function);
+ while (value_node->refcount < -1 &&
+ cmp != 0 &&
+ value_node != first_value_node->prev) {
+ value_node = value_node->next;
+ if (value_node == NULL) {
+ break;
+ }
+ expected_call = (FuncOrderingValue *)value_node->value;
+ if (expected_call == NULL) {
+ continue;
+ }
+ cmp = strcmp(expected_call->function, function);
+ }
+
+ if (expected_call == NULL || value_node == first_value_node->prev) {
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": error: No expected mock calls matching "
+ "called() invocation in %s",
+ file, line,
+ function);
+ exit_test(1);
+ }
+ }
+ }
+
+ if (cmp == 0) {
+ if (value_node->refcount > -2 && --value_node->refcount == 0) {
+ list_remove_free(value_node, free_value, NULL);
+ }
+ } else {
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": error: Expected call to %s but received called() "
+ "in %s\n",
+ file, line,
+ expected_call->function,
+ function);
+ exit_test(1);
+ }
+ } else {
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": error: No mock calls expected but called() was "
+ "invoked in %s\n",
+ file, line,
+ function);
+ exit_test(1);
+ }
+}
+
+/* Add a return value for the specified mock function name. */
+void _will_return(const char * const function_name, const char * const file,
+ const int line, const LargestIntegralType value,
+ const int count) {
+ SymbolValue * const return_value =
+ (SymbolValue*)malloc(sizeof(*return_value));
+ assert_true(count != 0);
+ return_value->value = value;
+ set_source_location(&return_value->location, file, line);
+ add_symbol_value(&global_function_result_map_head, &function_name, 1,
+ return_value, count);
+}
+
+
+/*
+ * Add a custom parameter checking function. If the event parameter is NULL
+ * the event structure is allocated internally by this function. If event
+ * parameter is provided it must be allocated on the heap and doesn't need to
+ * be deallocated by the caller.
+ */
+void _expect_check(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const CheckParameterValue check_function,
+ const LargestIntegralType check_data,
+ CheckParameterEvent * const event, const int count) {
+ CheckParameterEvent * const check =
+ event ? event : (CheckParameterEvent*)malloc(sizeof(*check));
+ const char* symbols[] = {function, parameter};
+ check->parameter_name = parameter;
+ check->check_value = check_function;
+ check->check_value_data = check_data;
+ set_source_location(&check->location, file, line);
+ add_symbol_value(&global_function_parameter_map_head, symbols, 2, check,
+ count);
+}
+
+/*
+ * Add an call expectations that a particular function is called correctly.
+ * This is used for code under test that makes calls to several functions
+ * in depended upon components (mocks).
+ */
+
+void _expect_function_call(
+ const char * const function_name,
+ const char * const file,
+ const int line,
+ const int count)
+{
+ FuncOrderingValue *ordering;
+
+ assert_non_null(function_name);
+ assert_non_null(file);
+ assert_true(count != 0);
+
+ ordering = (FuncOrderingValue *)malloc(sizeof(*ordering));
+
+ set_source_location(&ordering->location, file, line);
+ ordering->function = function_name;
+
+ list_add_value(&global_call_ordering_head, ordering, count);
+}
+
+/* Returns 1 if the specified values are equal. If the values are not equal
+ * an error is displayed and 0 is returned. */
+static int values_equal_display_error(const LargestIntegralType left,
+ const LargestIntegralType right) {
+ const int equal = left == right;
+ if (!equal) {
+ cm_print_error(LargestIntegralTypePrintfFormat " != "
+ LargestIntegralTypePrintfFormat "\n", left, right);
+ }
+ return equal;
+}
+
+/*
+ * Returns 1 if the specified values are not equal. If the values are equal
+ * an error is displayed and 0 is returned. */
+static int values_not_equal_display_error(const LargestIntegralType left,
+ const LargestIntegralType right) {
+ const int not_equal = left != right;
+ if (!not_equal) {
+ cm_print_error(LargestIntegralTypePrintfFormat " == "
+ LargestIntegralTypePrintfFormat "\n", left, right);
+ }
+ return not_equal;
+}
+
+
+/*
+ * Determine whether value is contained within check_integer_set.
+ * If invert is 0 and the value is in the set 1 is returned, otherwise 0 is
+ * returned and an error is displayed. If invert is 1 and the value is not
+ * in the set 1 is returned, otherwise 0 is returned and an error is
+ * displayed.
+ */
+static int value_in_set_display_error(
+ const LargestIntegralType value,
+ const CheckIntegerSet * const check_integer_set, const int invert) {
+ int succeeded = invert;
+ assert_non_null(check_integer_set);
+ {
+ const LargestIntegralType * const set = check_integer_set->set;
+ const size_t size_of_set = check_integer_set->size_of_set;
+ size_t i;
+ for (i = 0; i < size_of_set; i++) {
+ if (set[i] == value) {
+ /* If invert = 0 and item is found, succeeded = 1. */
+ /* If invert = 1 and item is found, succeeded = 0. */
+ succeeded = !succeeded;
+ break;
+ }
+ }
+ if (succeeded) {
+ return 1;
+ }
+ cm_print_error(LargestIntegralTypePrintfFormatDecimal
+ " is %sin the set (",
+ value, invert ? "" : "not ");
+ for (i = 0; i < size_of_set; i++) {
+ cm_print_error(LargestIntegralTypePrintfFormat ", ", set[i]);
+ }
+ cm_print_error(")\n");
+ }
+ return 0;
+}
+
+
+/*
+ * Determine whether a value is within the specified range. If the value is
+ * within the specified range 1 is returned. If the value isn't within the
+ * specified range an error is displayed and 0 is returned.
+ */
+static int integer_in_range_display_error(
+ const LargestIntegralType value, const LargestIntegralType range_min,
+ const LargestIntegralType range_max) {
+ if (value >= range_min && value <= range_max) {
+ return 1;
+ }
+ cm_print_error(LargestIntegralTypePrintfFormatDecimal
+ " is not within the range "
+ LargestIntegralTypePrintfFormatDecimal "-"
+ LargestIntegralTypePrintfFormatDecimal "\n",
+ value, range_min, range_max);
+ return 0;
+}
+
+
+/*
+ * Determine whether a value is within the specified range. If the value
+ * is not within the range 1 is returned. If the value is within the
+ * specified range an error is displayed and zero is returned.
+ */
+static int integer_not_in_range_display_error(
+ const LargestIntegralType value, const LargestIntegralType range_min,
+ const LargestIntegralType range_max) {
+ if (value < range_min || value > range_max) {
+ return 1;
+ }
+ cm_print_error(LargestIntegralTypePrintfFormatDecimal
+ " is within the range "
+ LargestIntegralTypePrintfFormatDecimal "-"
+ LargestIntegralTypePrintfFormatDecimal "\n",
+ value, range_min, range_max);
+ return 0;
+}
+
+
+/*
+ * Determine whether the specified strings are equal. If the strings are equal
+ * 1 is returned. If they're not equal an error is displayed and 0 is
+ * returned.
+ */
+static int string_equal_display_error(
+ const char * const left, const char * const right) {
+ if (strcmp(left, right) == 0) {
+ return 1;
+ }
+ cm_print_error("\"%s\" != \"%s\"\n", left, right);
+ return 0;
+}
+
+
+/*
+ * Determine whether the specified strings are equal. If the strings are not
+ * equal 1 is returned. If they're not equal an error is displayed and 0 is
+ * returned
+ */
+static int string_not_equal_display_error(
+ const char * const left, const char * const right) {
+ if (strcmp(left, right) != 0) {
+ return 1;
+ }
+ cm_print_error("\"%s\" == \"%s\"\n", left, right);
+ return 0;
+}
+
+
+/*
+ * Determine whether the specified areas of memory are equal. If they're equal
+ * 1 is returned otherwise an error is displayed and 0 is returned.
+ */
+static int memory_equal_display_error(const char* const a, const char* const b,
+ const size_t size) {
+ int differences = 0;
+ size_t i;
+ for (i = 0; i < size; i++) {
+ const char l = a[i];
+ const char r = b[i];
+ if (l != r) {
+ cm_print_error("difference at offset %" PRIdS " 0x%02x 0x%02x\n",
+ i, l, r);
+ differences ++;
+ }
+ }
+ if (differences) {
+ cm_print_error("%d bytes of %p and %p differ\n",
+ differences, (void *)a, (void *)b);
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * Determine whether the specified areas of memory are not equal. If they're
+ * not equal 1 is returned otherwise an error is displayed and 0 is
+ * returned.
+ */
+static int memory_not_equal_display_error(
+ const char* const a, const char* const b, const size_t size) {
+ size_t same = 0;
+ size_t i;
+ for (i = 0; i < size; i++) {
+ const char l = a[i];
+ const char r = b[i];
+ if (l == r) {
+ same ++;
+ }
+ }
+ if (same == size) {
+ cm_print_error("%"PRIdS "bytes of %p and %p the same\n",
+ same, (void *)a, (void *)b);
+ return 0;
+ }
+ return 1;
+}
+
+
+/* CheckParameterValue callback to check whether a value is within a set. */
+static int check_in_set(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ return value_in_set_display_error(value,
+ cast_largest_integral_type_to_pointer(CheckIntegerSet*,
+ check_value_data), 0);
+}
+
+
+/* CheckParameterValue callback to check whether a value isn't within a set. */
+static int check_not_in_set(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ return value_in_set_display_error(value,
+ cast_largest_integral_type_to_pointer(CheckIntegerSet*,
+ check_value_data), 1);
+}
+
+
+/* Create the callback data for check_in_set() or check_not_in_set() and
+ * register a check event. */
+static void expect_set(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType values[], const size_t number_of_values,
+ const CheckParameterValue check_function, const int count) {
+ CheckIntegerSet * const check_integer_set =
+ (CheckIntegerSet*)malloc(sizeof(*check_integer_set) +
+ (sizeof(values[0]) * number_of_values));
+ LargestIntegralType * const set = (LargestIntegralType*)(
+ check_integer_set + 1);
+ declare_initialize_value_pointer_pointer(check_data, check_integer_set);
+ assert_non_null(values);
+ assert_true(number_of_values);
+ memcpy(set, values, number_of_values * sizeof(values[0]));
+ check_integer_set->set = set;
+ check_integer_set->size_of_set = number_of_values;
+ _expect_check(
+ function, parameter, file, line, check_function,
+ check_data.value, &check_integer_set->event, count);
+}
+
+
+/* Add an event to check whether a value is in a set. */
+void _expect_in_set(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType values[], const size_t number_of_values,
+ const int count) {
+ expect_set(function, parameter, file, line, values, number_of_values,
+ check_in_set, count);
+}
+
+
+/* Add an event to check whether a value isn't in a set. */
+void _expect_not_in_set(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType values[], const size_t number_of_values,
+ const int count) {
+ expect_set(function, parameter, file, line, values, number_of_values,
+ check_not_in_set, count);
+}
+
+
+/* CheckParameterValue callback to check whether a value is within a range. */
+static int check_in_range(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ CheckIntegerRange * const check_integer_range =
+ cast_largest_integral_type_to_pointer(CheckIntegerRange*,
+ check_value_data);
+ assert_non_null(check_integer_range);
+ return integer_in_range_display_error(value, check_integer_range->minimum,
+ check_integer_range->maximum);
+}
+
+
+/* CheckParameterValue callback to check whether a value is not within a range. */
+static int check_not_in_range(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ CheckIntegerRange * const check_integer_range =
+ cast_largest_integral_type_to_pointer(CheckIntegerRange*,
+ check_value_data);
+ assert_non_null(check_integer_range);
+ return integer_not_in_range_display_error(
+ value, check_integer_range->minimum, check_integer_range->maximum);
+}
+
+
+/* Create the callback data for check_in_range() or check_not_in_range() and
+ * register a check event. */
+static void expect_range(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType minimum, const LargestIntegralType maximum,
+ const CheckParameterValue check_function, const int count) {
+ CheckIntegerRange * const check_integer_range =
+ (CheckIntegerRange*)malloc(sizeof(*check_integer_range));
+ declare_initialize_value_pointer_pointer(check_data, check_integer_range);
+ check_integer_range->minimum = minimum;
+ check_integer_range->maximum = maximum;
+ _expect_check(function, parameter, file, line, check_function,
+ check_data.value, &check_integer_range->event, count);
+}
+
+
+/* Add an event to determine whether a parameter is within a range. */
+void _expect_in_range(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType minimum, const LargestIntegralType maximum,
+ const int count) {
+ expect_range(function, parameter, file, line, minimum, maximum,
+ check_in_range, count);
+}
+
+
+/* Add an event to determine whether a parameter is not within a range. */
+void _expect_not_in_range(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType minimum, const LargestIntegralType maximum,
+ const int count) {
+ expect_range(function, parameter, file, line, minimum, maximum,
+ check_not_in_range, count);
+}
+
+
+/* CheckParameterValue callback to check whether a value is equal to an
+ * expected value. */
+static int check_value(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ return values_equal_display_error(value, check_value_data);
+}
+
+
+/* Add an event to check a parameter equals an expected value. */
+void _expect_value(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType value, const int count) {
+ _expect_check(function, parameter, file, line, check_value, value, NULL,
+ count);
+}
+
+
+/* CheckParameterValue callback to check whether a value is not equal to an
+ * expected value. */
+static int check_not_value(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ return values_not_equal_display_error(value, check_value_data);
+}
+
+
+/* Add an event to check a parameter is not equal to an expected value. */
+void _expect_not_value(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const LargestIntegralType value, const int count) {
+ _expect_check(function, parameter, file, line, check_not_value, value,
+ NULL, count);
+}
+
+
+/* CheckParameterValue callback to check whether a parameter equals a string. */
+static int check_string(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ return string_equal_display_error(
+ cast_largest_integral_type_to_pointer(char*, value),
+ cast_largest_integral_type_to_pointer(char*, check_value_data));
+}
+
+
+/* Add an event to check whether a parameter is equal to a string. */
+void _expect_string(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line, const char* string,
+ const int count) {
+ declare_initialize_value_pointer_pointer(string_pointer,
+ discard_const(string));
+ _expect_check(function, parameter, file, line, check_string,
+ string_pointer.value, NULL, count);
+}
+
+
+/* CheckParameterValue callback to check whether a parameter is not equals to
+ * a string. */
+static int check_not_string(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ return string_not_equal_display_error(
+ cast_largest_integral_type_to_pointer(char*, value),
+ cast_largest_integral_type_to_pointer(char*, check_value_data));
+}
+
+
+/* Add an event to check whether a parameter is not equal to a string. */
+void _expect_not_string(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line, const char* string,
+ const int count) {
+ declare_initialize_value_pointer_pointer(string_pointer,
+ discard_const(string));
+ _expect_check(function, parameter, file, line, check_not_string,
+ string_pointer.value, NULL, count);
+}
+
+/* CheckParameterValue callback to check whether a parameter equals an area of
+ * memory. */
+static int check_memory(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ CheckMemoryData * const check = cast_largest_integral_type_to_pointer(
+ CheckMemoryData*, check_value_data);
+ assert_non_null(check);
+ return memory_equal_display_error(
+ cast_largest_integral_type_to_pointer(const char*, value),
+ (const char*)check->memory, check->size);
+}
+
+
+/* Create the callback data for check_memory() or check_not_memory() and
+ * register a check event. */
+static void expect_memory_setup(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line,
+ const void * const memory, const size_t size,
+ const CheckParameterValue check_function, const int count) {
+ CheckMemoryData * const check_data =
+ (CheckMemoryData*)malloc(sizeof(*check_data) + size);
+ void * const mem = (void*)(check_data + 1);
+ declare_initialize_value_pointer_pointer(check_data_pointer, check_data);
+ assert_non_null(memory);
+ assert_true(size);
+ memcpy(mem, memory, size);
+ check_data->memory = mem;
+ check_data->size = size;
+ _expect_check(function, parameter, file, line, check_function,
+ check_data_pointer.value, &check_data->event, count);
+}
+
+
+/* Add an event to check whether a parameter matches an area of memory. */
+void _expect_memory(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line, const void* const memory,
+ const size_t size, const int count) {
+ expect_memory_setup(function, parameter, file, line, memory, size,
+ check_memory, count);
+}
+
+
+/* CheckParameterValue callback to check whether a parameter is not equal to
+ * an area of memory. */
+static int check_not_memory(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ CheckMemoryData * const check = cast_largest_integral_type_to_pointer(
+ CheckMemoryData*, check_value_data);
+ assert_non_null(check);
+ return memory_not_equal_display_error(
+ cast_largest_integral_type_to_pointer(const char*, value),
+ (const char*)check->memory,
+ check->size);
+}
+
+
+/* Add an event to check whether a parameter doesn't match an area of memory. */
+void _expect_not_memory(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line, const void* const memory,
+ const size_t size, const int count) {
+ expect_memory_setup(function, parameter, file, line, memory, size,
+ check_not_memory, count);
+}
+
+
+/* CheckParameterValue callback that always returns 1. */
+static int check_any(const LargestIntegralType value,
+ const LargestIntegralType check_value_data) {
+ (void)value;
+ (void)check_value_data;
+ return 1;
+}
+
+
+/* Add an event to allow any value for a parameter. */
+void _expect_any(
+ const char* const function, const char* const parameter,
+ const char* const file, const int line, const int count) {
+ _expect_check(function, parameter, file, line, check_any, 0, NULL,
+ count);
+}
+
+
+void _check_expected(
+ const char * const function_name, const char * const parameter_name,
+ const char* file, const int line, const LargestIntegralType value) {
+ void *result;
+ const char* symbols[] = {function_name, parameter_name};
+ const int rc = get_symbol_value(&global_function_parameter_map_head,
+ symbols, 2, &result);
+ if (rc) {
+ CheckParameterEvent * const check = (CheckParameterEvent*)result;
+ int check_succeeded;
+ global_last_parameter_location = check->location;
+ check_succeeded = check->check_value(value, check->check_value_data);
+ if (rc == 1) {
+ free(check);
+ }
+ if (!check_succeeded) {
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": error: Check of parameter %s, function %s failed\n"
+ SOURCE_LOCATION_FORMAT
+ ": note: Expected parameter declared here\n",
+ file, line,
+ parameter_name, function_name,
+ global_last_parameter_location.file,
+ global_last_parameter_location.line);
+ _fail(file, line);
+ }
+ } else {
+ cm_print_error(SOURCE_LOCATION_FORMAT ": error: Could not get value "
+ "to check parameter %s of function %s\n", file, line,
+ parameter_name, function_name);
+ if (source_location_is_set(&global_last_parameter_location)) {
+ cm_print_error(SOURCE_LOCATION_FORMAT
+ ": note: Previously declared parameter value was declared here\n",
+ global_last_parameter_location.file,
+ global_last_parameter_location.line);
+ } else {
+ cm_print_error("There were no previously declared parameter values "
+ "for this test.\n");
+ }
+ exit_test(1);
+ }
+}
+
+
+/* Replacement for assert. */
+void mock_assert(const int result, const char* const expression,
+ const char* const file, const int line) {
+ if (!result) {
+ if (global_expecting_assert) {
+ global_last_failed_assert = expression;
+ longjmp(global_expect_assert_env, result);
+ } else {
+ cm_print_error("ASSERT: %s\n", expression);
+ _fail(file, line);
+ }
+ }
+}
+
+
+void _assert_true(const LargestIntegralType result,
+ const char * const expression,
+ const char * const file, const int line) {
+ if (!result) {
+ cm_print_error("%s\n", expression);
+ _fail(file, line);
+ }
+}
+
+void _assert_return_code(const LargestIntegralType result,
+ size_t rlen,
+ const LargestIntegralType error,
+ const char * const expression,
+ const char * const file,
+ const int line)
+{
+ LargestIntegralType valmax;
+
+
+ switch (rlen) {
+ case 1:
+ valmax = 255;
+ break;
+ case 2:
+ valmax = 32767;
+ break;
+ case 4:
+ valmax = 2147483647;
+ break;
+ case 8:
+ default:
+ if (rlen > sizeof(valmax)) {
+ valmax = 2147483647;
+ } else {
+ valmax = 9223372036854775807L;
+ }
+ break;
+ }
+
+ if (result > valmax - 1) {
+ if (error > 0) {
+ cm_print_error("%s < 0, errno("
+ LargestIntegralTypePrintfFormatDecimal "): %s\n",
+ expression, error, strerror((int)error));
+ } else {
+ cm_print_error("%s < 0\n", expression);
+ }
+ _fail(file, line);
+ }
+}
+
+void _assert_int_equal(
+ const LargestIntegralType a, const LargestIntegralType b,
+ const char * const file, const int line) {
+ if (!values_equal_display_error(a, b)) {
+ _fail(file, line);
+ }
+}
+
+
+void _assert_int_not_equal(
+ const LargestIntegralType a, const LargestIntegralType b,
+ const char * const file, const int line) {
+ if (!values_not_equal_display_error(a, b)) {
+ _fail(file, line);
+ }
+}
+
+
+void _assert_string_equal(const char * const a, const char * const b,
+ const char * const file, const int line) {
+ if (!string_equal_display_error(a, b)) {
+ _fail(file, line);
+ }
+}
+
+
+void _assert_string_not_equal(const char * const a, const char * const b,
+ const char *file, const int line) {
+ if (!string_not_equal_display_error(a, b)) {
+ _fail(file, line);
+ }
+}
+
+
+void _assert_memory_equal(const void * const a, const void * const b,
+ const size_t size, const char* const file,
+ const int line) {
+ if (!memory_equal_display_error((const char*)a, (const char*)b, size)) {
+ _fail(file, line);
+ }
+}
+
+
+void _assert_memory_not_equal(const void * const a, const void * const b,
+ const size_t size, const char* const file,
+ const int line) {
+ if (!memory_not_equal_display_error((const char*)a, (const char*)b,
+ size)) {
+ _fail(file, line);
+ }
+}
+
+
+void _assert_in_range(
+ const LargestIntegralType value, const LargestIntegralType minimum,
+ const LargestIntegralType maximum, const char* const file,
+ const int line) {
+ if (!integer_in_range_display_error(value, minimum, maximum)) {
+ _fail(file, line);
+ }
+}
+
+void _assert_not_in_range(
+ const LargestIntegralType value, const LargestIntegralType minimum,
+ const LargestIntegralType maximum, const char* const file,
+ const int line) {
+ if (!integer_not_in_range_display_error(value, minimum, maximum)) {
+ _fail(file, line);
+ }
+}
+
+void _assert_in_set(const LargestIntegralType value,
+ const LargestIntegralType values[],
+ const size_t number_of_values, const char* const file,
+ const int line) {
+ CheckIntegerSet check_integer_set;
+ check_integer_set.set = values;
+ check_integer_set.size_of_set = number_of_values;
+ if (!value_in_set_display_error(value, &check_integer_set, 0)) {
+ _fail(file, line);
+ }