summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@jelmer.uk>2017-01-15 15:19:34 +0000
committerJelmer Vernooij <jelmer@jelmer.uk>2017-01-15 15:20:34 +0000
commitebc781f304c6f41a89b975fecb053272aed01d55 (patch)
tree0b29e0a1097ba216973c396997aa83447ac20f35
parenta23a97c63ca5c780e5bded2b3383caae4031957a (diff)
parentbe03fa6817ca42e35691dc88a03f0b92b51741dd (diff)
Merge tag 'upstream/1.1.29'
Upstream version 1.1.29
-rw-r--r--ABI/ldb-1.1.28.sigs266
-rw-r--r--ABI/ldb-1.1.29.sigs268
-rw-r--r--ABI/pyldb-util-1.1.28.sigs2
-rw-r--r--ABI/pyldb-util-1.1.29.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.1.28.sigs2
-rw-r--r--ABI/pyldb-util.py3-1.1.29.sigs2
-rw-r--r--buildtools/wafsamba/samba_autoconf.py1
-rw-r--r--buildtools/wafsamba/samba_perl.py3
-rw-r--r--common/ldb_attributes.c68
-rw-r--r--common/ldb_dn.c6
-rw-r--r--common/ldb_match.c4
-rw-r--r--common/ldb_modules.c7
-rw-r--r--common/ldb_pack.c30
-rw-r--r--include/ldb.h12
-rw-r--r--include/ldb_module.h16
-rw-r--r--include/ldb_private.h12
-rw-r--r--ldb_map/ldb_map_outbound.c2
-rw-r--r--ldb_tdb/ldb_cache.c138
-rw-r--r--ldb_tdb/ldb_index.c15
-rw-r--r--ldb_tdb/ldb_search.c157
-rw-r--r--ldb_tdb/ldb_tdb.h5
-rw-r--r--lib/replace/wscript3
-rw-r--r--lib/talloc/talloc.c40
-rw-r--r--lib/talloc/testsuite.c36
-rw-r--r--lib/tdb/ABI/tdb-1.3.11.sigs70
-rw-r--r--lib/tdb/ABI/tdb-1.3.12.sigs70
-rw-r--r--lib/tdb/common/mutex.c16
-rw-r--r--lib/tdb/common/tdb.c222
-rw-r--r--lib/tdb/common/tdb_private.h5
-rw-r--r--lib/tdb/include/tdb.h26
-rw-r--r--lib/tdb/tools/tdbdump.c3
-rw-r--r--lib/tdb/wscript2
-rw-r--r--lib/tevent/ABI/tevent-0.9.30.sigs96
-rw-r--r--lib/tevent/ABI/tevent-0.9.31.sigs99
-rw-r--r--lib/tevent/doc/tevent_context.dox2
-rw-r--r--lib/tevent/doc/tevent_queue.dox5
-rw-r--r--lib/tevent/doc/tevent_thread.dox4
-rw-r--r--lib/tevent/testsuite.c99
-rw-r--r--lib/tevent/tevent.c330
-rw-r--r--lib/tevent/tevent.h101
-rw-r--r--lib/tevent/tevent_epoll.c4
-rw-r--r--lib/tevent/tevent_internal.h51
-rw-r--r--lib/tevent/tevent_poll.c9
-rw-r--r--lib/tevent/tevent_port.c4
-rw-r--r--lib/tevent/tevent_queue.c2
-rw-r--r--lib/tevent/tevent_req.c5
-rw-r--r--lib/tevent/tevent_select.c4
-rw-r--r--lib/tevent/tevent_signal.c60
-rw-r--r--lib/tevent/tevent_threads.c155
-rw-r--r--lib/tevent/tevent_timed.c88
-rwxr-xr-xlib/tevent/wscript8
-rw-r--r--modules/rdn_name.c155
-rw-r--r--pyldb.h5
-rw-r--r--tests/test-tdb-features.sh13
-rw-r--r--tools/ldbdump.c3
-rw-r--r--tools/ldbutil.h2
-rwxr-xr-xwscript2
57 files changed, 2508 insertions, 309 deletions
diff --git a/ABI/ldb-1.1.28.sigs b/ABI/ldb-1.1.28.sigs
new file mode 100644
index 0000000..4fa30d8
--- /dev/null
+++ b/ABI/ldb-1.1.28.sigs
@@ -0,0 +1,266 @@
+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_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+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_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+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_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.29.sigs b/ABI/ldb-1.1.29.sigs
new file mode 100644
index 0000000..0ea968d
--- /dev/null
+++ b/ABI/ldb-1.1.29.sigs
@@ -0,0 +1,268 @@
+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_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+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_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_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.28.sigs b/ABI/pyldb-util-1.1.28.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.1.28.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.29.sigs b/ABI/pyldb-util-1.1.29.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util-1.1.29.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.28.sigs b/ABI/pyldb-util.py3-1.1.28.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.1.28.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.29.sigs b/ABI/pyldb-util.py3-1.1.29.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/ABI/pyldb-util.py3-1.1.29.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/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
index 5f35d77..795d130 100644
--- a/buildtools/wafsamba/samba_autoconf.py
+++ b/buildtools/wafsamba/samba_autoconf.py
@@ -708,6 +708,7 @@ def SAMBA_CONFIG_H(conf, path=None):
testflags=True)
conf.ADD_CFLAGS('-Wformat=2 -Wno-format-y2k', testflags=True)
+ conf.ADD_CFLAGS('-Werror=format-security -Wformat-security', testflags=True)
# This check is because for ldb_search(), a NULL format string
# is not an error, but some compilers complain about that.
if CHECK_CFLAGS(conf, ["-Werror=format", "-Wformat=2"], '''
diff --git a/buildtools/wafsamba/samba_perl.py b/buildtools/wafsamba/samba_perl.py
index f2f176d..2e9a53a 100644
--- a/buildtools/wafsamba/samba_perl.py
+++ b/buildtools/wafsamba/samba_perl.py
@@ -49,7 +49,8 @@ def SAMBA_CHECK_PERL(conf, mandatory=True, version=(5,0,0)):
conf.env.PERL_LIB_INSTALL_DIR = perl_lib_install_dir
perl_inc = read_perl_config_var('print "@INC"')
- perl_inc.remove('.')
+ if '.' in perl_inc:
+ perl_inc.remove('.')
conf.start_msg("PERL_INC: ")
conf.end_msg("%s" % (perl_inc), 'GREEN')
conf.env.PERL_INC = perl_inc
diff --git a/common/ldb_attributes.c b/common/ldb_attributes.c
index 767f69c..2021a0b 100644
--- a/common/ldb_attributes.c
+++ b/common/ldb_attributes.c
@@ -32,6 +32,41 @@
#include "ldb_handlers.h"
/*
+ fill in an attribute to the ldb_schema into the supplied buffer
+
+ if flags contains LDB_ATTR_FLAG_ALLOCATED
+ the attribute name string will be copied using
+ talloc_strdup(), otherwise it needs to be a static const
+ string at least with a lifetime longer than the ldb struct!
+
+ the ldb_schema_syntax structure should be a pointer
+ to a static const struct or at least it needs to be
+ a struct with a longer lifetime than the ldb context!
+
+*/
+int ldb_schema_attribute_fill_with_syntax(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *attribute,
+ unsigned flags,
+ const struct ldb_schema_syntax *syntax,
+ struct ldb_schema_attribute *a)
+{
+ a->name = attribute;
+ a->flags = flags;
+ a->syntax = syntax;
+
+ if (a->flags & LDB_ATTR_FLAG_ALLOCATED) {
+ a->name = talloc_strdup(mem_ctx, a->name);
+ if (a->name == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
add a attribute to the ldb_schema
if flags contains LDB_ATTR_FLAG_ALLOCATED
@@ -216,6 +251,39 @@ void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name)
}
/*
+ remove attributes with a specified flag (eg LDB_ATTR_FLAG_FROM_DB) for this ldb context
+
+ This is to permit correct reloads
+*/
+void ldb_schema_attribute_remove_flagged(struct ldb_context *ldb, unsigned int flag)
+{
+ ptrdiff_t i;
+
+ for (i = 0; i < ldb->schema.num_attributes;) {
+ const struct ldb_schema_attribute *a
+ = &ldb->schema.attributes[i];
+ /* FIXED attributes are never removed */
+ if (a->flags & LDB_ATTR_FLAG_FIXED) {
+ i++;
+ continue;
+ }
+ if ((a->flags & flag) == 0) {
+ i++;
+ continue;
+ }
+ if (a->flags & LDB_ATTR_FLAG_ALLOCATED) {
+ talloc_free(discard_const_p(char, a->name));
+ }
+ if (i < ldb->schema.num_attributes - 1) {
+ memmove(&ldb->schema.attributes[i],
+ a+1, sizeof(*a) * (ldb->schema.num_attributes-(i+1)));
+ }
+
+ ldb->schema.num_attributes--;
+ }
+}
+
+/*
setup a attribute handler using a standard syntax
*/
int ldb_schema_attribute_add(struct ldb_context *ldb,
diff --git a/common/ldb_dn.c b/common/ldb_dn.c
index 3fa5ab5..b23ee17 100644
--- a/common/ldb_dn.c
+++ b/common/ldb_dn.c
@@ -1699,7 +1699,7 @@ bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num)
*/
bool ldb_dn_replace_components(struct ldb_dn *dn, struct ldb_dn *new_dn)
{
- int i;
+ unsigned int i;
if ( ! ldb_dn_validate(dn) || ! ldb_dn_validate(new_dn)) {
return false;
@@ -1904,11 +1904,11 @@ int ldb_dn_set_component(struct ldb_dn *dn, int num,
return LDB_ERR_OTHER;
}
- if (num >= dn->comp_num) {
+ if (num < 0) {
return LDB_ERR_OTHER;
}
- if (num < 0) {
+ if ((unsigned)num >= dn->comp_num) {
return LDB_ERR_OTHER;
}
diff --git a/common/ldb_match.c b/common/ldb_match.c
index e83ad63..1415fac 100644
--- a/common/ldb_match.c
+++ b/common/ldb_match.c
@@ -693,9 +693,7 @@ _PRIVATE_ int ldb_register_extended_match_rules(struct ldb_context *ldb)
}
/*
- register a new ldb backend
-
- if override is true, then override any existing backend for this prefix
+ register a new ldb extended matching rule
*/
int ldb_register_extended_match_rule(struct ldb_context *ldb,
const struct ldb_extended_match_rule *rule)
diff --git a/common/ldb_modules.c b/common/ldb_modules.c
index 2105966..62f20af 100644
--- a/common/ldb_modules.c
+++ b/common/ldb_modules.c
@@ -901,7 +901,10 @@ static int ldb_modules_load_path(const char *path, const char *version)
} *loaded;
struct loaded *le;
int dlopen_flags;
+
+#ifdef RTLD_DEEPBIND
bool deepbind_enabled = (getenv("LDB_MODULES_DISABLE_DEEPBIND") == NULL);
+#endif
ret = stat(path, &st);
if (ret != 0) {
@@ -937,13 +940,13 @@ static int ldb_modules_load_path(const char *path, const char *version)
#ifdef RTLD_DEEPBIND
/*
* use deepbind if possible, to avoid issues with different
- * system library varients, for example ldb modules may be linked
+ * system library variants, for example ldb modules may be linked
* against Heimdal while the application may use MIT kerberos.
*
* See the dlopen manpage for details.
*
* One typical user is the bind_dlz module of Samba,
- * but symbol versioniong might be enough...
+ * but symbol versioning might be enough...
*
* We need a way to disable this in order to allow the
* ldb_*ldap modules to work with a preloaded socket wrapper.
diff --git a/common/ldb_pack.c b/common/ldb_pack.c
index cc3a552..a63dd58 100644
--- a/common/ldb_pack.c
+++ b/common/ldb_pack.c
@@ -185,8 +185,7 @@ static bool ldb_consume_element_data(uint8_t **pp, size_t *premaining)
unsigned int remaining = *premaining;
uint8_t *p = *pp;
uint32_t num_values = pull_uint32(p, 0);
- uint32_t len;
- int j;
+ uint32_t j, len;
p += 4;
if (remaining < 4) {
@@ -234,6 +233,7 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
unsigned int nelem = 0;
size_t len;
unsigned int found = 0;
+ struct ldb_val *ldb_val_single_array = NULL;
if (list == NULL) {
list_size = 0;
@@ -314,6 +314,26 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
goto failed;
}
+ /*
+ * In typical use, most values are single-valued. This makes
+ * it quite expensive to allocate an array of ldb_val for each
+ * of these, just to then hold the pointer to the data buffer
+ * (in the LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC we don't
+ * allocate the data). So with
+ * LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC we allocate this ahead
+ * of time and use it for the single values where possible.
+ * (This is used the the normal search case, but not in the
+ * index case because of caller requirements).
+ */
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) {
+ ldb_val_single_array = talloc_array(message->elements, struct ldb_val,
+ message->num_elements);
+ if (ldb_val_single_array == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+
for (i=0;i<message->num_elements;i++) {
const char *attr = NULL;
size_t attr_len;
@@ -348,7 +368,7 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
*/
if (list_size != 0) {
bool keep = false;
- int h;
+ unsigned int h;
/*
* We know that p has a \0 terminator before the
@@ -397,7 +417,9 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
p += attr_len + 1;
element->num_values = pull_uint32(p, 0);
element->values = NULL;
- if (element->num_values != 0) {
+ if ((flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) && element->num_values == 1) {
+ element->values = &ldb_val_single_array[nelem];
+ } else if (element->num_values != 0) {
element->values = talloc_array(message->elements,
struct ldb_val,
element->num_values);
diff --git a/include/ldb.h b/include/ldb.h
index 7422d46..397f994 100644
--- a/include/ldb.h
+++ b/include/ldb.h
@@ -427,6 +427,11 @@ const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_c
*/
#define LDB_ATTR_FLAG_FORCE_BASE64_LDIF (1<<5)
+/*
+ * The attribute was loaded from a DB, rather than via the C API
+ */
+#define LDB_ATTR_FLAG_FROM_DB (1<<6)
+
/**
LDAP attribute syntax for a DN
@@ -499,6 +504,13 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
#define LDB_CONTROL_BYPASS_OPERATIONAL_NAME "bypassoperational"
/**
+ OID for recalculate RDN (rdn attribute and 'name') control. This control forces
+ the rdn_name module to the recalculate the rdn and name attributes as if the
+ object was just created.
+*/
+#define LDB_CONTROL_RECALCULATE_RDN_OID "1.3.6.1.4.1.7165.4.3.30"
+
+/**
OID for recalculate SD control. This control force the
dsdb code to recalculate the SD of the object as if the
object was just created.
diff --git a/include/ldb_module.h b/include/ldb_module.h
index 1c48590..833d5a8 100644
--- a/include/ldb_module.h
+++ b/include/ldb_module.h
@@ -412,8 +412,15 @@ int ldb_unpack_data(struct ldb_context *ldb,
* Giving a NULL list (or a list_size of 0) unpacks all the attributes.
*
* Flags allow control of allocation, so that if
- * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC is specified, then values are
- * not allocate, instead they point into the supplier constant buffer.
+ * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC is specified, then data in values are
+ * not allocated, instead they point into the supplier constant buffer.
+ *
+ * If LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC is specified, then values
+ * array are not allocated individually (for single-valued
+ * attributes), instead they point into a single buffer per message.
+ *
+ * LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC is only valid when
+ * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC is also specified.
*
* Likewise if LDB_UNPACK_DATA_FLAG_NO_DN is specified, the DN is omitted.
*/
@@ -425,7 +432,8 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
unsigned int flags,
unsigned int *nb_elements_in_db);
-#define LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC 0x0001
-#define LDB_UNPACK_DATA_FLAG_NO_DN 0x0002
+#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
#endif
diff --git a/include/ldb_private.h b/include/ldb_private.h
index 26a9d42..644d49c 100644
--- a/include/ldb_private.h
+++ b/include/ldb_private.h
@@ -163,6 +163,18 @@ extern const struct ldb_backend_ops ldb_ldapi_backend_ops;
extern const struct ldb_backend_ops ldb_ldaps_backend_ops;
int ldb_setup_wellknown_attributes(struct ldb_context *ldb);
+/*
+ remove attributes with a specified flag (eg LDB_ATTR_FLAG_FROM_DB) for this ldb context
+
+ This is to permit correct reloads
+*/
+void ldb_schema_attribute_remove_flagged(struct ldb_context *ldb, unsigned int flag);
+int ldb_schema_attribute_fill_with_syntax(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *attribute,
+ unsigned flags,
+ const struct ldb_schema_syntax *syntax,
+ struct ldb_schema_attribute *a);
const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname);
void ldb_subclass_remove(struct ldb_context *ldb, const char *classname);
diff --git a/ldb_map/ldb_map_outbound.c b/ldb_map/ldb_map_outbound.c
index e755b7e..fd25c36 100644
--- a/ldb_map/ldb_map_outbound.c
+++ b/ldb_map/ldb_map_outbound.c
@@ -190,7 +190,7 @@ static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const c
static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
{
struct ldb_message_element *old;
- int j;
+ unsigned j;
old = ldb_msg_find_element(msg, el->name);
/* no local result, add as new element */
diff --git a/ldb_tdb/ldb_cache.c b/ldb_tdb/ldb_cache.c
index 2f19d27..5ea09d6 100644
--- a/ldb_tdb/ldb_cache.c
+++ b/ldb_tdb/ldb_cache.c
@@ -56,26 +56,10 @@ static const struct {
*/
static void ltdb_attributes_unload(struct ldb_module *module)
{
- struct ldb_context *ldb;
- void *data = ldb_module_get_private(module);
- struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- struct ldb_message *msg;
- unsigned int i;
-
- ldb = ldb_module_get_ctx(module);
-
- if (ltdb->cache->attributes == NULL) {
- /* no previously loaded attributes */
- return;
- }
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
- msg = ltdb->cache->attributes;
- for (i=0;i<msg->num_elements;i++) {
- ldb_schema_attribute_remove(ldb, msg->elements[i].name);
- }
+ ldb_schema_attribute_remove_flagged(ldb, LDB_ATTR_FLAG_FROM_DB);
- talloc_free(ltdb->cache->attributes);
- ltdb->cache->attributes = NULL;
}
/*
@@ -102,17 +86,24 @@ static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
return 0;
}
+static int ldb_schema_attribute_compare(const void *p1, const void *p2)
+{
+ const struct ldb_schema_attribute *sa1 = (const struct ldb_schema_attribute *)p1;
+ const struct ldb_schema_attribute *sa2 = (const struct ldb_schema_attribute *)p2;
+ return ldb_attr_cmp(sa1->name, sa2->name);
+}
+
/*
register any special handlers from @ATTRIBUTES
*/
static int ltdb_attributes_load(struct ldb_module *module)
{
+ struct ldb_schema_attribute *attrs;
struct ldb_context *ldb;
- void *data = ldb_module_get_private(module);
- struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- struct ldb_message *msg = ltdb->cache->attributes;
+ struct ldb_message *attrs_msg = NULL;
struct ldb_dn *dn;
unsigned int i;
+ unsigned int num_loaded_attrs = 0;
int r;
ldb = ldb_module_get_ctx(module);
@@ -123,26 +114,57 @@ static int ltdb_attributes_load(struct ldb_module *module)
return 0;
}
+ attrs_msg = ldb_msg_new(module);
+ if (attrs_msg == NULL) {
+ goto failed;
+ }
+
dn = ldb_dn_new(module, ldb, LTDB_ATTRIBUTES);
if (dn == NULL) goto failed;
- r = ltdb_search_dn1(module, dn, msg, 0);
+ r = ltdb_search_dn1(module, dn, attrs_msg,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC
+ |LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC
+ |LDB_UNPACK_DATA_FLAG_NO_DN);
talloc_free(dn);
if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
goto failed;
}
- if (r == LDB_ERR_NO_SUCH_OBJECT) {
+ if (r == LDB_ERR_NO_SUCH_OBJECT || attrs_msg->num_elements == 0) {
+ TALLOC_FREE(attrs_msg);
return 0;
}
+
+ attrs = talloc_array(attrs_msg,
+ struct ldb_schema_attribute,
+ attrs_msg->num_elements
+ + ldb->schema.num_attributes);
+ if (attrs == NULL) {
+ goto failed;
+ }
+
+ memcpy(attrs,
+ ldb->schema.attributes,
+ sizeof(ldb->schema.attributes[0]) * ldb->schema.num_attributes);
+
/* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
but its close enough for now */
- for (i=0;i<msg->num_elements;i++) {
+ for (i=0;i<attrs_msg->num_elements;i++) {
unsigned flags;
const char *syntax;
const struct ldb_schema_syntax *s;
+ const struct ldb_schema_attribute *a =
+ ldb_schema_attribute_by_name(ldb,
+ attrs_msg->elements[i].name);
+ if (a != NULL && a->flags & LDB_ATTR_FLAG_FIXED) {
+ /* Must already be set in the array, and kept */
+ continue;
+ }
- if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'", msg->elements[i].name);
+ if (ltdb_attributes_flags(&attrs_msg->elements[i], &flags) != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Invalid @ATTRIBUTES element for '%s'",
+ attrs_msg->elements[i].name);
goto failed;
}
switch (flags & ~LTDB_FLAG_HIDDEN) {
@@ -157,27 +179,50 @@ static int ltdb_attributes_load(struct ldb_module *module)
break;
default:
ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES",
- flags, msg->elements[i].name);
+ "Invalid flag combination 0x%x for '%s' "
+ "in @ATTRIBUTES",
+ flags, attrs_msg->elements[i].name);
goto failed;
}
s = ldb_standard_syntax_by_name(ldb, syntax);
if (s == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES",
- syntax, msg->elements[i].name);
+ "Invalid attribute syntax '%s' for '%s' "
+ "in @ATTRIBUTES",
+ syntax, attrs_msg->elements[i].name);
goto failed;
}
- flags |= LDB_ATTR_FLAG_ALLOCATED;
- if (ldb_schema_attribute_add_with_syntax(ldb, msg->elements[i].name, flags, s) != 0) {
+ flags |= LDB_ATTR_FLAG_ALLOCATED | LDB_ATTR_FLAG_FROM_DB;
+
+ r = ldb_schema_attribute_fill_with_syntax(ldb,
+ attrs,
+ attrs_msg->elements[i].name,
+ flags, s,
+ &attrs[num_loaded_attrs + ldb->schema.num_attributes]);
+ if (r != 0) {
goto failed;
}
+ num_loaded_attrs++;
}
+ attrs = talloc_realloc(attrs_msg,
+ attrs, struct ldb_schema_attribute,
+ num_loaded_attrs + ldb->schema.num_attributes);
+ if (attrs == NULL) {
+ goto failed;
+ }
+ TYPESAFE_QSORT(attrs, num_loaded_attrs + ldb->schema.num_attributes,
+ ldb_schema_attribute_compare);
+ talloc_unlink(ldb, ldb->schema.attributes);
+ ldb->schema.attributes = talloc_steal(ldb, attrs);
+ ldb->schema.num_attributes = num_loaded_attrs + ldb->schema.num_attributes;
+ TALLOC_FREE(attrs_msg);
+
return 0;
failed:
+ TALLOC_FREE(attrs_msg);
return -1;
}
@@ -288,9 +333,7 @@ int ltdb_cache_load(struct ldb_module *module)
ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
if (ltdb->cache == NULL) goto failed;
ltdb->cache->indexlist = ldb_msg_new(ltdb->cache);
- ltdb->cache->attributes = ldb_msg_new(ltdb->cache);
- if (ltdb->cache->indexlist == NULL ||
- ltdb->cache->attributes == NULL) {
+ if (ltdb->cache->indexlist == NULL) {
goto failed;
}
}
@@ -360,12 +403,17 @@ int ltdb_cache_load(struct ldb_module *module)
}
talloc_free(ltdb->cache->indexlist);
- ltdb_attributes_unload(module); /* calls internally "talloc_free" */
-
+ /*
+ * ltdb_attributes_unload() calls internally talloc_free() on
+ * any non-fixed elemnts in ldb->schema.attributes.
+ *
+ * NOTE WELL: This is per-ldb, not per module, so overwrites
+ * the handlers across all databases when used under Samba's
+ * partition module.
+ */
+ ltdb_attributes_unload(module);
ltdb->cache->indexlist = ldb_msg_new(ltdb->cache);
- ltdb->cache->attributes = ldb_msg_new(ltdb->cache);
- if (ltdb->cache->indexlist == NULL ||
- ltdb->cache->attributes == NULL) {
+ if (ltdb->cache->indexlist == NULL) {
goto failed;
}
ltdb->cache->one_level_indexes = false;
@@ -374,7 +422,10 @@ int ltdb_cache_load(struct ldb_module *module)
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, 0);
+ 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) {
goto failed;
}
@@ -386,6 +437,11 @@ int ltdb_cache_load(struct ldb_module *module)
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
+ * partition module.
+ */
if (ltdb_attributes_load(module) == -1) {
goto failed;
}
diff --git a/ldb_tdb/ldb_index.c b/ldb_tdb/ldb_index.c
index 392b4a7..53fcde5 100644
--- a/ldb_tdb/ldb_index.c
+++ b/ldb_tdb/ldb_index.c
@@ -931,6 +931,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
{
struct ldb_context *ldb;
struct ldb_message *msg;
+ struct ldb_message *filtered_msg;
unsigned int i;
ldb = ldb_module_get_ctx(ac->module);
@@ -951,7 +952,9 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ltdb_search_dn1(ac->module, dn, msg, 0);
+ ret = ltdb_search_dn1(ac->module, dn, msg,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
talloc_free(dn);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* the record has disappeared? yes, this can happen */
@@ -977,14 +980,15 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
}
/* filter the attributes that the user wants */
- ret = ltdb_filter_attrs(msg, ac->attrs);
+ ret = ltdb_filter_attrs(ac, msg, ac->attrs, &filtered_msg);
+
+ talloc_free(msg);
if (ret == -1) {
- talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_module_send_entry(ac->req, msg, NULL);
+ ret = ldb_module_send_entry(ac->req, filtered_msg, NULL);
if (ret != LDB_SUCCESS) {
/* Regardless of success or failure, the msg
* is the callbacks responsiblity, and should
@@ -1206,7 +1210,8 @@ static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
add index entries for all elements in a message
*/
static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
- struct ldb_message_element *elements, int num_el,
+ struct ldb_message_element *elements,
+ unsigned int num_el,
bool is_new)
{
struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
diff --git a/ldb_tdb/ldb_search.c b/ldb_tdb/ldb_search.c
index 133e5d4..373855f 100644
--- a/ldb_tdb/ldb_search.c
+++ b/ldb_tdb/ldb_search.c
@@ -385,81 +385,144 @@ int ltdb_add_attr_results(struct ldb_module *module,
/*
filter the specified list of attributes from a message
- removing not requested attrs.
+ removing not requested attrs from the new message constructed.
+
+ The reason this makes a new message is that the old one may not be
+ individually allocated, which is what our callers expect.
+
*/
-int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
+int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg, const char * const *attrs,
+ struct ldb_message **filtered_msg)
{
unsigned int i;
- int keep_all = 0;
- struct ldb_message_element *el2;
+ bool keep_all = false;
+ bool add_dn = false;
uint32_t num_elements;
+ uint32_t elements_size;
+ struct ldb_message *msg2;
+
+ msg2 = ldb_msg_new(mem_ctx);
+ if (msg2 == NULL) {
+ goto failed;
+ }
+
+ msg2->dn = ldb_dn_copy(msg2, msg->dn);
+ if (msg2->dn == NULL) {
+ goto failed;
+ }
if (attrs) {
/* check for special attrs */
for (i = 0; attrs[i]; i++) {
- if (strcmp(attrs[i], "*") == 0) {
- keep_all = 1;
+ int cmp = strcmp(attrs[i], "*");
+ if (cmp == 0) {
+ keep_all = true;
break;
}
-
- if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
- if (msg_add_distinguished_name(msg) != 0) {
- return -1;
- }
+ cmp = ldb_attr_cmp(attrs[i], "distinguishedName");
+ if (cmp == 0) {
+ add_dn = true;
}
}
} else {
- keep_all = 1;
+ keep_all = true;
}
-
+
if (keep_all) {
- if (msg_add_distinguished_name(msg) != 0) {
+ add_dn = true;
+ elements_size = msg->num_elements + 1;
+
+ /* Shortcuts for the simple cases */
+ } else if (add_dn && i == 1) {
+ if (msg_add_distinguished_name(msg2) != 0) {
return -1;
}
+ *filtered_msg = msg2;
+ return 0;
+ } else if (i == 0) {
+ *filtered_msg = msg2;
return 0;
- }
- el2 = talloc_array(msg, struct ldb_message_element, msg->num_elements);
- if (el2 == NULL) {
- return -1;
+ /* Otherwise we are copying at most as many element as we have attributes */
+ } else {
+ elements_size = i;
}
+
+ msg2->elements = talloc_array(msg2, struct ldb_message_element,
+ elements_size);
+ if (msg2->elements == NULL) goto failed;
+
num_elements = 0;
for (i = 0; i < msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ struct ldb_message_element *el2 = &msg2->elements[num_elements];
unsigned int j;
- int found = 0;
-
- for (j = 0; attrs[j]; j++) {
- if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
- found = 1;
- break;
+
+ if (keep_all == false) {
+ bool found = false;
+ for (j = 0; attrs[j]; j++) {
+ int cmp = ldb_attr_cmp(el->name, attrs[j]);
+ if (cmp == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (found == false) {
+ continue;
+ }
+ }
+ *el2 = *el;
+ el2->name = talloc_strdup(msg2->elements, el->name);
+ if (el2->name == NULL) {
+ goto failed;
+ }
+ el2->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
+ if (el2->values == NULL) {
+ goto failed;
+ }
+ for (j=0;j<el->num_values;j++) {
+ el2->values[j] = ldb_val_dup(el2->values, &el->values[j]);
+ if (el2->values[j].data == NULL && el->values[j].length != 0) {
+ goto failed;
}
}
+ num_elements++;
- if (found) {
- el2[num_elements] = msg->elements[i];
- talloc_steal(el2, el2[num_elements].name);
- talloc_steal(el2, el2[num_elements].values);
- num_elements++;
+ /* Pidginhole principle: we can't have more elements
+ * than the number of attributes if they are unique in
+ * the DB */
+ if (num_elements > elements_size) {
+ goto failed;
}
}
- talloc_free(msg->elements);
+ msg2->num_elements = num_elements;
- if (num_elements > 0) {
- msg->elements = talloc_realloc(msg, el2, struct ldb_message_element,
- num_elements);
- } else {
- msg->elements = talloc_array(msg, struct ldb_message_element, 0);
- talloc_free(el2);
+ if (add_dn) {
+ if (msg_add_distinguished_name(msg2) != 0) {
+ return -1;
+ }
}
- if (msg->elements == NULL) {
- return -1;
+
+ if (msg2->num_elements > 0) {
+ msg2->elements = talloc_realloc(msg2, msg2->elements,
+ struct ldb_message_element,
+ msg2->num_elements);
+ if (msg2->elements == NULL) {
+ return -1;
+ }
+ } else {
+ talloc_free(msg2->elements);
+ msg2->elements = NULL;
}
- msg->num_elements = num_elements;
+ *filtered_msg = msg2;
return 0;
+failed:
+ return -1;
}
/*
@@ -469,13 +532,14 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
{
struct ldb_context *ldb;
struct ltdb_context *ac;
- struct ldb_message *msg;
+ struct ldb_message *msg, *filtered_msg;
const struct ldb_val val = {
.data = data.dptr,
.length = data.dsize,
};
int ret;
bool matched;
+ unsigned int nb_elements_in_db;
ac = talloc_get_type(state, struct ltdb_context);
ldb = ldb_module_get_ctx(ac->module);
@@ -492,7 +556,12 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
}
/* unpack the record */
- ret = ldb_unpack_data(ldb, &val, msg);
+ ret = ldb_unpack_data_only_attr_list_flags(ldb, &val,
+ msg,
+ NULL, 0,
+ LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC,
+ &nb_elements_in_db);
if (ret == -1) {
talloc_free(msg);
ac->error = LDB_ERR_OPERATIONS_ERROR;
@@ -523,15 +592,15 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
}
/* filter the attributes that the user wants */
- ret = ltdb_filter_attrs(msg, ac->attrs);
+ ret = ltdb_filter_attrs(ac, msg, ac->attrs, &filtered_msg);
+ talloc_free(msg);
if (ret == -1) {
- talloc_free(msg);
ac->error = LDB_ERR_OPERATIONS_ERROR;
return -1;
}
- ret = ldb_module_send_entry(ac->req, msg, NULL);
+ ret = ldb_module_send_entry(ac->req, filtered_msg, NULL);
if (ret != LDB_SUCCESS) {
ac->request_terminated = true;
/* the callback failed, abort the operation */
diff --git a/ldb_tdb/ldb_tdb.h b/ldb_tdb/ldb_tdb.h
index 7390a04..7caedeb 100644
--- a/ldb_tdb/ldb_tdb.h
+++ b/ldb_tdb/ldb_tdb.h
@@ -18,7 +18,6 @@ struct ltdb_private {
struct ltdb_cache {
struct ldb_message *indexlist;
- struct ldb_message *attributes;
bool one_level_indexes;
bool attribute_indexes;
} *cache;
@@ -109,7 +108,9 @@ int ltdb_add_attr_results(struct ldb_module *module,
const char * const attrs[],
unsigned int *count,
struct ldb_message ***res);
-int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs);
+int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg, const char * const *attrs,
+ struct ldb_message **filtered_msg);
int ltdb_search(struct ltdb_context *ctx);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 145300d..1dfd902 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -483,6 +483,9 @@ removeea setea
if conf.CONFIG_SET('HAVE_PORT_CREATE') and conf.CONFIG_SET('HAVE_PORT_H'):
conf.DEFINE('HAVE_SOLARIS_PORTS', 1)
+ if conf.CHECK_FUNCS('eventfd', headers='sys/eventfd.h'):
+ conf.DEFINE('HAVE_EVENTFD', 1)
+
conf.CHECK_HEADERS('poll.h')
conf.CHECK_FUNCS('poll')
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 09318e9..279021c 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -80,9 +80,10 @@
#define TALLOC_MAGIC_BASE 0xe814ec70
static unsigned int talloc_magic = (
- TALLOC_MAGIC_BASE +
- (TALLOC_VERSION_MAJOR << 12) +
- (TALLOC_VERSION_MINOR << 4));
+ ~TALLOC_FLAG_MASK & (
+ TALLOC_MAGIC_BASE +
+ (TALLOC_VERSION_MAJOR << 12) +
+ (TALLOC_VERSION_MINOR << 4)));
/* by default we abort when given a bad pointer (such as when talloc_free() is called
on a pointer that came from malloc() */
@@ -263,7 +264,32 @@ typedef int (*talloc_destructor_t)(void *);
struct talloc_pool_hdr;
struct talloc_chunk {
+ /*
+ * flags includes the talloc magic, which is randomised to
+ * make overwrite attacks harder
+ */
unsigned flags;
+
+ /*
+ * If you have a logical tree like:
+ *
+ * <parent>
+ * / | \
+ * / | \
+ * / | \
+ * <child 1> <child 2> <child 3>
+ *
+ * The actual talloc tree is:
+ *
+ * <parent>
+ * |
+ * <child 1> - <child 2> - <child 3>
+ *
+ * The children are linked with next/prev pointers, and
+ * child 1 is linked to the parent with parent/child
+ * pointers.
+ */
+
struct talloc_chunk *next, *prev;
struct talloc_chunk *parent, *child;
struct talloc_reference_handle *refs;
@@ -2476,8 +2502,12 @@ _PUBLIC_ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
#endif
static struct talloc_chunk *_vasprintf_tc(const void *t,
- const char *fmt,
- va_list ap)
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static struct talloc_chunk *_vasprintf_tc(const void *t,
+ const char *fmt,
+ va_list ap)
{
int len;
char *ret;
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index 8fe5d90..835d38b 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -34,6 +34,12 @@
#include <unistd.h>
#include <sys/wait.h>
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+
#include "talloc_testsuite.h"
static struct timeval private_timeval_current(void)
@@ -604,7 +610,7 @@ static bool test_realloc_child(void)
void *root;
struct el2 {
const char *name;
- } *el2;
+ } *el2, *el2_2, *el2_3;
struct el1 {
int count;
struct el2 **list, **list2, **list3;
@@ -628,13 +634,22 @@ static bool test_realloc_child(void)
el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
el2 = talloc(el1->list, struct el2);
- el2 = talloc(el1->list2, struct el2);
- el2 = talloc(el1->list3, struct el2);
- (void)el2;
+ CHECK_PARENT("el2", el2, el1->list);
+ el2_2 = talloc(el1->list2, struct el2);
+ CHECK_PARENT("el2", el2_2, el1->list2);
+ el2_3 = talloc(el1->list3, struct el2);
+ CHECK_PARENT("el2", el2_3, el1->list3);
el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+ 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);
el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
+ CHECK_PARENT("el1_after_realloc", el1->list3, el1);
+
+ CHECK_PARENT("el2", el2, el1->list);
+ CHECK_PARENT("el2", el2_2, el1->list2);
+ CHECK_PARENT("el2", el2_3, el1->list3);
talloc_free(root);
@@ -1750,7 +1765,8 @@ static void *thread_fn(void *arg)
ret = pthread_cond_wait(&condvar, &mtx);
if (ret != 0) {
talloc_free(top_ctx);
- pthread_mutex_unlock(&mtx);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
return NULL;
}
}
@@ -1760,7 +1776,8 @@ static void *thread_fn(void *arg)
/* Tell the main thread it's ready for pickup. */
pthread_cond_broadcast(&condvar);
- pthread_mutex_unlock(&mtx);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
talloc_free(top_ctx);
return NULL;
@@ -1831,8 +1848,8 @@ static bool test_pthread_talloc_passing(void)
printf("pthread_cond_wait %d failed (%d)\n", i,
ret);
talloc_free(mem_ctx);
- pthread_mutex_unlock(&mtx);
- return false;
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
}
}
@@ -1841,7 +1858,8 @@ static bool test_pthread_talloc_passing(void)
/* Tell the sub-threads we're ready for another. */
pthread_cond_broadcast(&condvar);
- pthread_mutex_unlock(&mtx);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
}
CHECK_SIZE("pthread_talloc_passing", mem_ctx, NUM_THREADS * 100);
diff --git a/lib/tdb/ABI/tdb-1.3.11.sigs b/lib/tdb/ABI/tdb-1.3.11.sigs
new file mode 100644
index 0000000..48f4278
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.11.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.12.sigs b/lib/tdb/ABI/tdb-1.3.12.sigs
new file mode 100644
index 0000000..48f4278
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.12.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/common/mutex.c b/lib/tdb/common/mutex.c
index 280dec1..cac3916 100644
--- a/lib/tdb/common/mutex.c
+++ b/lib/tdb/common/mutex.c
@@ -603,12 +603,13 @@ int tdb_mutex_init(struct tdb_context *tdb)
fail:
pthread_mutexattr_destroy(&ma);
fail_munmap:
- tdb_mutex_munmap(tdb);
if (ret == 0) {
return 0;
}
+ tdb_mutex_munmap(tdb);
+
errno = ret;
return -1;
}
@@ -623,6 +624,10 @@ int tdb_mutex_mmap(struct tdb_context *tdb)
return 0;
}
+ if (tdb->mutexes != NULL) {
+ return 0;
+ }
+
ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE,
tdb->fd, 0);
if (ptr == MAP_FAILED) {
@@ -636,13 +641,20 @@ int tdb_mutex_mmap(struct tdb_context *tdb)
int tdb_mutex_munmap(struct tdb_context *tdb)
{
size_t len;
+ int ret;
len = tdb_mutex_size(tdb);
if (len == 0) {
return 0;
}
- return munmap(tdb->mutexes, len);
+ ret = munmap(tdb->mutexes, len);
+ if (ret == -1) {
+ return -1;
+ }
+ tdb->mutexes = NULL;
+
+ return 0;
}
static bool tdb_mutex_locking_cached;
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index dd93680..a67d8fb 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -129,16 +129,32 @@ tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t has
static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+struct tdb_update_hash_state {
+ const TDB_DATA *dbufs;
+ int num_dbufs;
+ tdb_len_t dbufs_len;
+};
+
static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
{
- TDB_DATA *dbuf = (TDB_DATA *)private_data;
+ struct tdb_update_hash_state *state = private_data;
+ unsigned char *dptr = data.dptr;
+ int i;
- if (dbuf->dsize != data.dsize) {
+ if (state->dbufs_len != data.dsize) {
return -1;
}
- if (memcmp(dbuf->dptr, data.dptr, data.dsize) != 0) {
- return -1;
+
+ for (i=0; i<state->num_dbufs; i++) {
+ TDB_DATA dbuf = state->dbufs[i];
+ int ret;
+ ret = memcmp(dptr, dbuf.dptr, dbuf.dsize);
+ if (ret != 0) {
+ return -1;
+ }
+ dptr += dbuf.dsize;
}
+
return 0;
}
@@ -146,10 +162,14 @@ static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
is <= the old data size and the key exists.
on failure return -1.
*/
-static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
+static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key,
+ uint32_t hash,
+ const TDB_DATA *dbufs, int num_dbufs,
+ tdb_len_t dbufs_len)
{
struct tdb_record rec;
- tdb_off_t rec_ptr;
+ tdb_off_t rec_ptr, ofs;
+ int i;
/* find entry */
if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
@@ -157,26 +177,41 @@ static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
/* it could be an exact duplicate of what is there - this is
* surprisingly common (eg. with a ldb re-index). */
- if (rec.key_len == key.dsize &&
- rec.data_len == dbuf.dsize &&
- rec.full_hash == hash &&
- tdb_parse_record(tdb, key, tdb_update_hash_cmp, &dbuf) == 0) {
- return 0;
+ if (rec.data_len == dbufs_len) {
+ struct tdb_update_hash_state state = {
+ .dbufs = dbufs, .num_dbufs = num_dbufs,
+ .dbufs_len = dbufs_len
+ };
+ int ret;
+
+ ret = tdb_parse_record(tdb, key, tdb_update_hash_cmp, &state);
+ if (ret == 0) {
+ return 0;
+ }
}
/* must be long enough key, data and tailer */
- if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
+ if (rec.rec_len < key.dsize + dbufs_len + sizeof(tdb_off_t)) {
tdb->ecode = TDB_SUCCESS; /* Not really an error */
return -1;
}
- if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
- dbuf.dptr, dbuf.dsize) == -1)
- return -1;
+ ofs = rec_ptr + sizeof(rec) + rec.key_len;
+
+ for (i=0; i<num_dbufs; i++) {
+ TDB_DATA dbuf = dbufs[i];
+ int ret;
- if (dbuf.dsize != rec.data_len) {
+ ret = tdb->methods->tdb_write(tdb, ofs, dbuf.dptr, dbuf.dsize);
+ if (ret == -1) {
+ return -1;
+ }
+ ofs += dbuf.dsize;
+ }
+
+ if (dbufs_len != rec.data_len) {
/* update size */
- rec.data_len = dbuf.dsize;
+ rec.data_len = dbufs_len;
return tdb_rec_write(tdb, rec_ptr, &rec);
}
@@ -491,13 +526,34 @@ tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
return best_rec_ptr;
}
-static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
- TDB_DATA dbuf, int flag, uint32_t hash)
+static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
+ const TDB_DATA *dbufs, int num_dbufs,
+ int flag, uint32_t hash)
{
struct tdb_record rec;
- tdb_off_t rec_ptr;
+ tdb_off_t rec_ptr, ofs;
+ tdb_len_t rec_len, dbufs_len;
+ int i;
int ret = -1;
+ dbufs_len = 0;
+
+ for (i=0; i<num_dbufs; i++) {
+ size_t dsize = dbufs[i].dsize;
+
+ dbufs_len += dsize;
+ if (dbufs_len < dsize) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ }
+
+ rec_len = key.dsize + dbufs_len;
+ if ((rec_len < key.dsize) || (rec_len < dbufs_len)) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
/* check for it existing, on insert. */
if (flag == TDB_INSERT) {
if (tdb_exists_hash(tdb, key, hash)) {
@@ -506,7 +562,8 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
}
} else {
/* first try in-place update, on modify or replace. */
- if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
+ if (tdb_update_hash(tdb, key, hash, dbufs, num_dbufs,
+ dbufs_len) == 0) {
goto done;
}
if (tdb->ecode == TDB_ERR_NOEXIST &&
@@ -526,7 +583,7 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
tdb_delete_hash(tdb, key, hash);
/* we have to allocate some space */
- rec_ptr = tdb_allocate(tdb, hash, key.dsize + dbuf.dsize, &rec);
+ rec_ptr = tdb_allocate(tdb, hash, rec_len, &rec);
if (rec_ptr == 0) {
goto fail;
@@ -537,17 +594,36 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
goto fail;
rec.key_len = key.dsize;
- rec.data_len = dbuf.dsize;
+ rec.data_len = dbufs_len;
rec.full_hash = hash;
rec.magic = TDB_MAGIC;
+ ofs = rec_ptr;
+
/* write out and point the top of the hash chain at it */
- if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
- || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec),
- key.dptr, key.dsize) == -1
- || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec)+key.dsize,
- dbuf.dptr, dbuf.dsize) == -1
- || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+ ret = tdb_rec_write(tdb, ofs, &rec);
+ if (ret == -1) {
+ goto fail;
+ }
+ ofs += sizeof(rec);
+
+ ret = tdb->methods->tdb_write(tdb, ofs, key.dptr, key.dsize);
+ if (ret == -1) {
+ goto fail;
+ }
+ ofs += key.dsize;
+
+ for (i=0; i<num_dbufs; i++) {
+ ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
+ dbufs[i].dsize);
+ if (ret == -1) {
+ goto fail;
+ }
+ ofs += dbufs[i].dsize;
+ }
+
+ ret = tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr);
+ if (ret == -1) {
/* Need to tdb_unallocate() here */
goto fail;
}
@@ -561,6 +637,12 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
return ret;
}
+static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
+ TDB_DATA dbuf, int flag, uint32_t hash)
+{
+ return _tdb_storev(tdb, key, &dbuf, 1, flag, hash);
+}
+
/* store an element in the database, replacing any existing element
with the same key
@@ -588,50 +670,51 @@ _PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int
return ret;
}
-/* Append to an entry. Create if not exist. */
-_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+_PUBLIC_ int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
+ const TDB_DATA *dbufs, int num_dbufs, int flag)
{
uint32_t hash;
- TDB_DATA dbuf;
- int ret = -1;
+ int ret;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
+ dbufs, num_dbufs, flag, -1);
+ return -1;
+ }
/* find which hash bucket it is in */
hash = tdb->hash_fn(&key);
if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
return -1;
- dbuf = _tdb_fetch(tdb, key);
+ ret = _tdb_storev(tdb, key, dbufs, num_dbufs, flag, hash);
+ tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
+ dbufs, num_dbufs, flag, -1);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+}
- if (dbuf.dptr == NULL) {
- dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
- } else {
- unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
- unsigned char *new_dptr;
-
- /* realloc '0' is special: don't do that. */
- if (new_len == 0)
- new_len = 1;
- new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
- if (new_dptr == NULL) {
- free(dbuf.dptr);
- }
- dbuf.dptr = new_dptr;
- }
+/* Append to an entry. Create if not exist. */
+_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+ uint32_t hash;
+ TDB_DATA dbufs[2];
+ int ret = -1;
- if (dbuf.dptr == NULL) {
- tdb->ecode = TDB_ERR_OOM;
- goto failed;
- }
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
- memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
- dbuf.dsize += new_dbuf.dsize;
+ dbufs[0] = _tdb_fetch(tdb, key);
+ dbufs[1] = new_dbuf;
- ret = _tdb_store(tdb, key, dbuf, 0, hash);
- tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
+ ret = _tdb_storev(tdb, key, dbufs, 2, 0, hash);
+ tdb_trace_2rec_retrec(tdb, "tdb_append", key, dbufs[0], dbufs[1]);
-failed:
tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
- SAFE_FREE(dbuf.dptr);
+ SAFE_FREE(dbufs[0].dptr);
return ret;
}
@@ -790,7 +873,7 @@ static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t le
*/
_PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb)
{
- int i;
+ uint32_t i;
tdb_off_t offset = 0;
ssize_t data_len;
tdb_off_t recovery_head;
@@ -1132,6 +1215,25 @@ void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
tdb_trace_end_ret(tdb, ret);
}
+void tdb_trace_1plusn_rec_flag_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec,
+ const TDB_DATA *recs, int num_recs,
+ unsigned flag, int ret)
+{
+ char msg[1 + sizeof(ret) * 4];
+ int i;
+
+ snprintf(msg, sizeof(msg), " %#x", flag);
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec);
+ for (i=0; i<num_recs; i++) {
+ tdb_trace_record(tdb, recs[i]);
+ }
+ tdb_trace_write(tdb, msg);
+ tdb_trace_end_ret(tdb, ret);
+}
+
void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
{
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
index de8d9e6..7ff29aa 100644
--- a/lib/tdb/common/tdb_private.h
+++ b/lib/tdb/common/tdb_private.h
@@ -96,6 +96,10 @@ void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
int ret);
+void tdb_trace_1plusn_rec_flag_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec,
+ const TDB_DATA *recs, int num_recs,
+ unsigned flag, int ret);
void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret);
#else
@@ -108,6 +112,7 @@ void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
#define tdb_trace_1rec_ret(tdb, op, rec, ret)
#define tdb_trace_1rec_retrec(tdb, op, rec, ret)
#define tdb_trace_2rec_flag_ret(tdb, op, rec1, rec2, flag, ret)
+#define tdb_trace_1plusn_rec_flag_ret(tdb, op, rec, recs, num_recs, flag, ret);
#define tdb_trace_2rec_retrec(tdb, op, rec1, rec2, ret)
#endif /* !TDB_TRACE */
diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h
index 8478ca2..e86d267 100644
--- a/lib/tdb/include/tdb.h
+++ b/lib/tdb/include/tdb.h
@@ -357,6 +357,32 @@ int tdb_delete(struct tdb_context *tdb, TDB_DATA key);
*/
int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+
+/**
+ * @brief Store an element in the database.
+ *
+ * This replaces any existing element with the same key.
+ *
+ * @param[in] tdb The tdb to store the entry.
+ *
+ * @param[in] key The key to use to store the entry.
+ *
+ * @param[in] dbufs A vector of memory chunks to write
+ *
+ * @param[in] num_dbufs Length of the dbufs vector
+ *
+ * @param[in] flag The flags to store the key:\n\n
+ * TDB_INSERT: Don't overwrite an existing entry.\n
+ * TDB_MODIFY: Don't create a new entry\n
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
+ const TDB_DATA *dbufs, int num_dbufs, int flag);
+
/**
* @brief Append data to an entry.
*
diff --git a/lib/tdb/tools/tdbdump.c b/lib/tdb/tools/tdbdump.c
index 9a0a7fe..8cf3146 100644
--- a/lib/tdb/tools/tdbdump.c
+++ b/lib/tdb/tools/tdbdump.c
@@ -52,6 +52,9 @@ static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *stat
}
static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
const char *fmt, ...)
{
va_list ap;
diff --git a/lib/tdb/wscript b/lib/tdb/wscript
index c854a21..34058e4 100644
--- a/lib/tdb/wscript
+++ b/lib/tdb/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tdb'
-VERSION = '1.3.10'
+VERSION = '1.3.12'
blddir = 'bin'
diff --git a/lib/tevent/ABI/tevent-0.9.30.sigs b/lib/tevent/ABI/tevent-0.9.30.sigs
new file mode 100644
index 0000000..9b8bfa1
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.30.sigs
@@ -0,0 +1,96 @@
+_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_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_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_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.31.sigs b/lib/tevent/ABI/tevent-0.9.31.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.31.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/doc/tevent_context.dox b/lib/tevent/doc/tevent_context.dox
index 1036d3c..39eb85e 100644
--- a/lib/tevent/doc/tevent_context.dox
+++ b/lib/tevent/doc/tevent_context.dox
@@ -67,7 +67,7 @@ event again. There are 2 types of loop available for use in tevent library:
<li>int tevent_loop_once()</li>
</ul>
-Both of functions accept just one parametr (tevent context) and the only
+Both of functions accept just one parameter (tevent context) and the only
difference lies in the fact that the first loop can theoretically last for ever
but the second one will wait just for a single one event to catch and then the
loop breaks and the program continue.
diff --git a/lib/tevent/doc/tevent_queue.dox b/lib/tevent/doc/tevent_queue.dox
index fef98c8..9c247e5 100644
--- a/lib/tevent/doc/tevent_queue.dox
+++ b/lib/tevent/doc/tevent_queue.dox
@@ -11,7 +11,8 @@ beginning of the queue as fast as possible. In tevent library it is
similar, but the queue is not automatically set for any event. The queue has to
be created on purpose, and events which should follow the order of the FIFO
queue have to be explicitly pinpointed. Creating such a queue is crucial in
-situations when sequential processing is absolutely essential for the succesful
+situations when sequential processing is absolutely essential for the
+successful
completion of a task, e.g. for a large quantity of data that are about to be
written from a buffer into a socket. The tevent library has its own queue
structure that is ready to use after it has been initialized and started up
@@ -20,7 +21,7 @@ once.
@subsection cr_queue Creation of Queues
The first and most important step is the creation of the tevent queue
-(represented by struct tevent queue), which will then be in running mode.
+(represented by struct tevent_queue), which will then be in running mode.
@code
struct tevent_queue* tevent_queue_create (TALLOC_CTX *mem_ctx, const char *name)
diff --git a/lib/tevent/doc/tevent_thread.dox b/lib/tevent/doc/tevent_thread.dox
index 7b45820..875dae8 100644
--- a/lib/tevent/doc/tevent_thread.dox
+++ b/lib/tevent/doc/tevent_thread.dox
@@ -1,7 +1,7 @@
/**
-@page tevent_context Chapter 6: Tevent with threads
+@page tevent_thread Chapter 6: Tevent with threads
-@section context Tevent with threads
+@section threads Tevent with threads
In order to use tevent with threads, you must first understand
how to use the talloc library in threaded programs. For more
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index b37c7b1..4783ab4 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -1148,6 +1148,101 @@ static bool test_multi_tevent_threaded_1(struct torture_context *test,
talloc_free(master_ev);
return true;
}
+
+struct threaded_test_2 {
+ struct tevent_threaded_context *tctx;
+ struct tevent_immediate *im;
+ pthread_t thread_id;
+};
+
+static void master_callback_2(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void *thread_fn_2(void *private_data)
+{
+ struct threaded_test_2 *state = private_data;
+
+ state->thread_id = pthread_self();
+
+ usleep(random() % 7000);
+
+ tevent_threaded_schedule_immediate(
+ state->tctx, state->im, master_callback_2, state);
+
+ return NULL;
+}
+
+static void master_callback_2(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct threaded_test_2 *state = private_data;
+ int i;
+
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ if (pthread_equal(state->thread_id, thread_map[i])) {
+ break;
+ }
+ }
+ torture_comment(thread_test_ctx,
+ "Callback_2 %u from thread %u\n",
+ thread_counter,
+ i);
+ thread_counter++;
+}
+
+static bool test_multi_tevent_threaded_2(struct torture_context *test,
+ const void *test_data)
+{
+ unsigned i;
+
+ struct tevent_context *ev;
+ struct tevent_threaded_context *tctx;
+ int ret;
+
+ thread_test_ctx = test;
+ thread_counter = 0;
+
+ ev = tevent_context_init(test);
+ torture_assert(test, ev != NULL, "tevent_context_init failed");
+
+ tctx = tevent_threaded_context_create(ev, ev);
+ torture_assert(test, tctx != NULL,
+ "tevent_threaded_context_create failed");
+
+ for (i=0; i<NUM_TEVENT_THREADS; i++) {
+ struct threaded_test_2 *state;
+
+ state = talloc(ev, struct threaded_test_2);
+ torture_assert(test, state != NULL, "talloc failed");
+
+ state->tctx = tctx;
+ state->im = tevent_create_immediate(state);
+ torture_assert(test, state->im != NULL,
+ "tevent_create_immediate failed");
+
+ ret = pthread_create(&thread_map[i], NULL, thread_fn_2, state);
+ torture_assert(test, ret == 0, "pthread_create failed");
+ }
+
+ while (thread_counter < NUM_TEVENT_THREADS) {
+ ret = tevent_loop_once(ev);
+ torture_assert(test, ret == 0, "tevent_loop_once failed");
+ }
+
+ /* Wait for all the threads to finish - join 'em. */
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ void *retval;
+ ret = pthread_join(thread_map[i], &retval);
+ torture_assert(test, ret == 0, "pthread_join failed");
+ /* Free the child thread event context. */
+ }
+
+ talloc_free(tctx);
+ talloc_free(ev);
+ return true;
+}
#endif
struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
@@ -1190,6 +1285,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
test_multi_tevent_threaded_1,
NULL);
+ torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_2",
+ test_multi_tevent_threaded_2,
+ NULL);
+
#endif
return suite;
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 843cf05..65b101f 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -59,10 +59,18 @@
*/
#include "replace.h"
#include "system/filesys.h"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#endif
#define TEVENT_DEPRECATED 1
#include "tevent.h"
#include "tevent_internal.h"
#include "tevent_util.h"
+#ifdef HAVE_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+static void tevent_abort(struct tevent_context *ev, const char *reason);
struct tevent_ops_list {
struct tevent_ops_list *next, *prev;
@@ -173,6 +181,120 @@ const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
return list;
}
+static void tevent_common_wakeup_fini(struct tevent_context *ev);
+
+#ifdef HAVE_PTHREAD
+
+static pthread_mutex_t tevent_contexts_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct tevent_context *tevent_contexts = NULL;
+static pthread_once_t tevent_atfork_initialized = PTHREAD_ONCE_INIT;
+
+static void tevent_atfork_prepare(void)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ ret = pthread_mutex_lock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ for (ev = tevent_contexts; ev != NULL; ev = ev->next) {
+ struct tevent_threaded_context *tctx;
+
+ for (tctx = ev->threaded_contexts; tctx != NULL;
+ tctx = tctx->next) {
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_lock failed");
+ }
+ }
+
+ ret = pthread_mutex_lock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_lock failed");
+ }
+ }
+}
+
+static void tevent_atfork_parent(void)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
+ ev = DLIST_PREV(ev)) {
+ struct tevent_threaded_context *tctx;
+
+ ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_unlock failed");
+ }
+
+ for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
+ tctx = DLIST_PREV(tctx)) {
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ tevent_abort(
+ ev, "pthread_mutex_unlock failed");
+ }
+ }
+ }
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+}
+
+static void tevent_atfork_child(void)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
+ ev = DLIST_PREV(ev)) {
+ struct tevent_threaded_context *tctx;
+
+ for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
+ tctx = DLIST_PREV(tctx)) {
+ tctx->event_ctx = NULL;
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ tevent_abort(
+ ev, "pthread_mutex_unlock failed");
+ }
+ }
+
+ ev->threaded_contexts = NULL;
+
+ ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_unlock failed");
+ }
+ }
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+}
+
+static void tevent_prep_atfork(void)
+{
+ int ret;
+
+ ret = pthread_atfork(tevent_atfork_prepare,
+ tevent_atfork_parent,
+ tevent_atfork_child);
+ if (ret != 0) {
+ abort();
+ }
+}
+
+#endif
+
int tevent_common_context_destructor(struct tevent_context *ev)
{
struct tevent_fd *fd, *fn;
@@ -180,13 +302,49 @@ int tevent_common_context_destructor(struct tevent_context *ev)
struct tevent_immediate *ie, *in;
struct tevent_signal *se, *sn;
- if (ev->pipe_fde) {
- talloc_free(ev->pipe_fde);
- close(ev->pipe_fds[0]);
- close(ev->pipe_fds[1]);
- ev->pipe_fde = NULL;
+#ifdef HAVE_PTHREAD
+ int ret;
+
+ ret = pthread_mutex_lock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
}
+ DLIST_REMOVE(tevent_contexts, ev);
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ while (ev->threaded_contexts != NULL) {
+ struct tevent_threaded_context *tctx = ev->threaded_contexts;
+
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ /*
+ * Indicate to the thread that the tevent_context is
+ * gone. The counterpart of this is in
+ * _tevent_threaded_schedule_immediate, there we read
+ * this under the threaded_context's mutex.
+ */
+
+ tctx->event_ctx = NULL;
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_REMOVE(ev->threaded_contexts, tctx);
+ }
+#endif
+
+ tevent_common_wakeup_fini(ev);
+
for (fd = ev->fd_events; fd; fd = fn) {
fn = fd->next;
fd->event_ctx = NULL;
@@ -255,6 +413,36 @@ struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
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;
+ }
+
+ ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
+ if (ret != 0) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ ret = pthread_mutex_lock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ pthread_mutex_destroy(&ev->scheduled_mutex);
+ talloc_free(ev);
+ return NULL;
+ }
+
+ DLIST_ADD(tevent_contexts, ev);
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+#endif
+
talloc_set_destructor(ev, tevent_common_context_destructor);
ev->ops = ops;
@@ -620,6 +808,28 @@ done:
return ret;
}
+bool tevent_common_have_events(struct tevent_context *ev)
+{
+ if (ev->fd_events != NULL) {
+ if (ev->fd_events != ev->wakeup_fde) {
+ return true;
+ }
+ if (ev->fd_events->next != NULL) {
+ return true;
+ }
+
+ /*
+ * At this point we just have the wakeup pipe event as
+ * the only fd_event. That one does not count as a
+ * regular event, so look at the other event types.
+ */
+ }
+
+ return ((ev->timer_events != NULL) ||
+ (ev->immediate_events != NULL) ||
+ (ev->signal_events != NULL));
+}
+
/*
return on failure or (with 0) if all fd events are removed
*/
@@ -629,10 +839,7 @@ int tevent_common_loop_wait(struct tevent_context *ev,
/*
* loop as long as we have events pending
*/
- while (ev->fd_events ||
- ev->timer_events ||
- ev->immediate_events ||
- ev->signal_events) {
+ while (tevent_common_have_events(ev)) {
int ret;
ret = _tevent_loop_once(ev, location);
if (ret != 0) {
@@ -670,3 +877,108 @@ int tevent_re_initialise(struct tevent_context *ev)
return ev->ops->context_init(ev);
}
+
+static void wakeup_pipe_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *_private)
+{
+ ssize_t ret;
+
+ do {
+ /*
+ * This is the boilerplate for eventfd, but it works
+ * for pipes too. And as we don't care about the data
+ * we read, we're fine.
+ */
+ uint64_t val;
+ ret = read(fde->fd, &val, sizeof(val));
+ } while (ret == -1 && errno == EINTR);
+}
+
+/*
+ * Initialize the wakeup pipe and pipe fde
+ */
+
+int tevent_common_wakeup_init(struct tevent_context *ev)
+{
+ int ret, read_fd;
+
+ if (ev->wakeup_fde != NULL) {
+ return 0;
+ }
+
+#ifdef HAVE_EVENTFD
+ ret = eventfd(0, EFD_NONBLOCK);
+ if (ret == -1) {
+ return errno;
+ }
+ read_fd = ev->wakeup_fd = ret;
+#else
+ {
+ int pipe_fds[2];
+ ret = pipe(pipe_fds);
+ if (ret == -1) {
+ return errno;
+ }
+ ev->wakeup_fd = pipe_fds[1];
+ ev->wakeup_read_fd = pipe_fds[0];
+
+ ev_set_blocking(ev->wakeup_fd, false);
+ ev_set_blocking(ev->wakeup_read_fd, false);
+
+ read_fd = ev->wakeup_read_fd;
+ }
+#endif
+
+ ev->wakeup_fde = tevent_add_fd(ev, ev, read_fd, TEVENT_FD_READ,
+ wakeup_pipe_handler, NULL);
+ if (ev->wakeup_fde == NULL) {
+ close(ev->wakeup_fd);
+#ifndef HAVE_EVENTFD
+ close(ev->wakeup_read_fd);
+#endif
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+int tevent_common_wakeup_fd(int fd)
+{
+ ssize_t ret;
+
+ do {
+#ifdef HAVE_EVENTFD
+ uint64_t val = 1;
+ ret = write(fd, &val, sizeof(val));
+#else
+ char c = '\0';
+ ret = write(fd, &c, 1);
+#endif
+ } while ((ret == -1) && (errno == EINTR));
+
+ return 0;
+}
+
+int tevent_common_wakeup(struct tevent_context *ev)
+{
+ if (ev->wakeup_fde == NULL) {
+ return ENOTCONN;
+ }
+
+ return tevent_common_wakeup_fd(ev->wakeup_fd);
+}
+
+static void tevent_common_wakeup_fini(struct tevent_context *ev)
+{
+ if (ev->wakeup_fde == NULL) {
+ return;
+ }
+
+ TALLOC_FREE(ev->wakeup_fde);
+
+ close(ev->wakeup_fd);
+#ifndef HAVE_EVENTFD
+ close(ev->wakeup_read_fd);
+#endif
+}
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 1c1271b..ba4bb4d 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -40,6 +40,7 @@ struct tevent_timer;
struct tevent_immediate;
struct tevent_signal;
struct tevent_thread_proxy;
+struct tevent_threaded_context;
/**
* @defgroup tevent The tevent API
@@ -251,6 +252,16 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
#handler, __location__)
#endif
+/**
+ * @brief Set the time a tevent_timer fires
+ *
+ * @param[in] te The timer event to reset
+ *
+ * @param[in] next_event Timeval specifying the absolute time to fire this
+ * event. This is not an offset.
+ */
+void tevent_update_timer(struct tevent_timer *te, struct timeval next_event);
+
#ifdef DOXYGEN
/**
* Initialize an immediate event object
@@ -464,11 +475,11 @@ void tevent_set_abort_fn(void (*abort_fn)(const char *reason));
/* bits for file descriptor event flags */
/**
- * Monitor a file descriptor for write availability
+ * Monitor a file descriptor for data to be read
*/
#define TEVENT_FD_READ 1
/**
- * Monitor a file descriptor for data to be read
+ * Monitor a file descriptor for writeability
*/
#define TEVENT_FD_WRITE 2
@@ -1029,6 +1040,13 @@ bool tevent_req_set_endtime(struct tevent_req *req,
struct tevent_context *ev,
struct timeval endtime);
+/**
+ * @brief Reset the timer set by tevent_req_set_endtime.
+ *
+ * @param[in] req The request to reset the timeout for
+ */
+void tevent_req_reset_endtime(struct tevent_req *req);
+
#ifdef DOXYGEN
/**
* @brief Call the notify callback of the given tevent request manually.
@@ -1392,16 +1410,16 @@ int tevent_timeval_compare(const struct timeval *tv1,
const struct timeval *tv2);
/**
- * @brief Get a zero timval value.
+ * @brief Get a zero timeval value.
*
- * @return A zero timval value.
+ * @return A zero timeval value.
*/
struct timeval tevent_timeval_zero(void);
/**
* @brief Get a timeval value for the current time.
*
- * @return A timval value with the current time.
+ * @return A timeval value with the current time.
*/
struct timeval tevent_timeval_current(void);
@@ -1750,6 +1768,79 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
tevent_immediate_handler_t handler,
void *pp_private_data);
+/*
+ * @brief Create a context for threaded activation of immediates
+ *
+ * A tevent_treaded_context provides a link into an event
+ * context. Using tevent_threaded_schedule_immediate, it is possible
+ * to activate an immediate event from within a thread.
+ *
+ * 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
+ * with an active tevent_threaded_context.
+ *
+ * If tevent is build without pthread support, this always returns
+ * NULL with errno=ENOSYS.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ * @param[in] ev The event context to link this to.
+ * @return The threaded context, or NULL with errno set.
+ *
+ * @see tevent_threaded_schedule_immediate()
+ *
+ * @note Available as of tevent 0.9.30
+ */
+struct tevent_threaded_context *tevent_threaded_context_create(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev);
+
+#ifdef DOXYGEN
+/*
+ * @brief Activate an immediate from a thread
+ *
+ * Activate an immediate from within a thread.
+ *
+ * This routine does not watch out for talloc hierarchies. This means
+ * that it is highly recommended to create the tevent_immediate in the
+ * thread owning tctx, allocate a threaded job description for the
+ * thread, hand over both pointers to a helper thread and not touch it
+ * in the main thread at all anymore.
+ *
+ * tevent_threaded_schedule_immediate is intended as a job completion
+ * indicator for simple threaded helpers.
+ *
+ * Please be aware that tevent_threaded_schedule_immediate is very
+ * picky about its arguments: An immediate may not already be
+ * activated and the handler must exist. With
+ * tevent_threaded_schedule_immediate memory ownership is transferred
+ * to the main thread holding the tevent context behind tctx, the
+ * helper thread can't access it anymore.
+ *
+ * @param[in] tctx The threaded context to go through
+ * @param[in] im The immediate event to activate
+ * @param[in] handler The immediate handler to call in the main thread
+ * @param[in] private_data Pointer for the immediate handler
+ *
+ * @see tevent_threaded_context_create()
+ *
+ * @note Available as of tevent 0.9.30
+ */
+void tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
+ struct tevent_immediate *im,
+ tevent_immediate_handler_t handler,
+ void *private_data);
+#else
+void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
+ struct tevent_immediate *im,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_threaded_schedule_immediate(tctx, im, handler, private_data) \
+ _tevent_threaded_schedule_immediate(tctx, im, handler, private_data, \
+ #handler, __location__);
+#endif
+
#ifdef TEVENT_DEPRECATED
#ifndef _DEPRECATED_
#ifdef HAVE___ATTRIBUTE__
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 507ea5c..4147c67 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -903,6 +903,10 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location
return 0;
}
+ if (ev->threaded_contexts != NULL) {
+ tevent_common_threaded_activate_immediate(ev);
+ }
+
if (ev->immediate_events &&
tevent_common_loop_immediate(ev)) {
return 0;
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 10cc4a4..a5f1ebd 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -228,6 +228,16 @@ struct tevent_signal {
void *additional_data;
};
+struct tevent_threaded_context {
+ struct tevent_threaded_context *next, *prev;
+
+#ifdef HAVE_PTHREAD
+ pthread_mutex_t event_ctx_mutex;
+#endif
+ struct tevent_context *event_ctx;
+ int wakeup_fd;
+};
+
struct tevent_debug_ops {
void (*debug)(void *context, enum tevent_debug_level level,
const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
@@ -241,24 +251,41 @@ struct tevent_context {
/* the specific events implementation */
const struct tevent_ops *ops;
+ /*
+ * The following three pointers are queried on every loop_once
+ * in the order in which they appear here. Not measured, but
+ * hopefully putting them at the top together with "ops"
+ * should make tevent a *bit* more cache-friendly than before.
+ */
+
+ /* list of signal events - used by common code */
+ struct tevent_signal *signal_events;
+
+ /* List of threaded job indicators */
+ struct tevent_threaded_context *threaded_contexts;
+
+ /* list of immediate events - used by common code */
+ struct tevent_immediate *immediate_events;
+
/* list of fd events - used by common code */
struct tevent_fd *fd_events;
/* list of timed events - used by common code */
struct tevent_timer *timer_events;
- /* list of immediate events - used by common code */
- struct tevent_immediate *immediate_events;
-
- /* list of signal events - used by common code */
- struct tevent_signal *signal_events;
+ /* List of scheduled immediates */
+ pthread_mutex_t scheduled_mutex;
+ struct tevent_immediate *scheduled_immediates;
/* this is private for the events_ops implementation */
void *additional_data;
/* pipe hack used with signal handlers */
- struct tevent_fd *pipe_fde;
- int pipe_fds[2];
+ struct tevent_fd *wakeup_fde;
+ int wakeup_fd; /* fd to write into */
+#ifndef HAVE_EVENT_FD
+ int wakeup_read_fd;
+#endif
/* debugging operations */
struct tevent_debug_ops debug_ops;
@@ -282,6 +309,10 @@ struct tevent_context {
* tevent_common_add_timer_v2()
*/
struct tevent_timer *last_zero_timer;
+
+#ifdef HAVE_PTHREAD
+ struct tevent_context *prev, *next;
+#endif
};
const struct tevent_ops *tevent_find_ops_byname(const char *name);
@@ -327,6 +358,12 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
const char *handler_name,
const char *location);
bool tevent_common_loop_immediate(struct tevent_context *ev);
+void tevent_common_threaded_activate_immediate(struct tevent_context *ev);
+
+bool tevent_common_have_events(struct tevent_context *ev);
+int tevent_common_wakeup_init(struct tevent_context *ev);
+int tevent_common_wakeup_fd(int fd);
+int tevent_common_wakeup(struct tevent_context *ev);
struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
TALLOC_CTX *mem_ctx,
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index e1c305d..09d85fa 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -645,6 +645,10 @@ static int poll_event_loop_once(struct tevent_context *ev,
return 0;
}
+ if (ev->threaded_contexts != NULL) {
+ tevent_common_threaded_activate_immediate(ev);
+ }
+
if (ev->immediate_events &&
tevent_common_loop_immediate(ev)) {
return 0;
@@ -667,10 +671,7 @@ static int poll_event_loop_wait(struct tevent_context *ev,
/*
* loop as long as we have events pending
*/
- while (ev->fd_events ||
- ev->timer_events ||
- ev->immediate_events ||
- ev->signal_events ||
+ while (tevent_common_have_events(ev) ||
poll_ev->fresh ||
poll_ev->disabled) {
int ret;
diff --git a/lib/tevent/tevent_port.c b/lib/tevent/tevent_port.c
index 4b524df..8cf9fd1 100644
--- a/lib/tevent/tevent_port.c
+++ b/lib/tevent/tevent_port.c
@@ -760,6 +760,10 @@ static int port_event_loop_once(struct tevent_context *ev, const char *location)
return 0;
}
+ if (ev->threaded_contexts != NULL) {
+ tevent_common_threaded_activate_immediate(ev);
+ }
+
if (ev->immediate_events &&
tevent_common_loop_immediate(ev)) {
return 0;
diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index cefe91a..5516c6c 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -187,7 +187,7 @@ static struct tevent_queue_entry *tevent_queue_add_internal(
if (req->async.fn != NULL) {
/*
- * If the callers wants to optimize for the
+ * If the caller wants to optimize for the
* empty queue case, call the trigger only
* if there is no callback defined for the
* request yet.
diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
index e2b7104..e309c3d 100644
--- a/lib/tevent/tevent_req.c
+++ b/lib/tevent/tevent_req.c
@@ -313,6 +313,11 @@ bool tevent_req_set_endtime(struct tevent_req *req,
return true;
}
+void tevent_req_reset_endtime(struct tevent_req *req)
+{
+ TALLOC_FREE(req->internal.timer);
+}
+
void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
{
req->async.fn = fn;
diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c
index ec7565d..55dd0b6 100644
--- a/lib/tevent/tevent_select.c
+++ b/lib/tevent/tevent_select.c
@@ -244,6 +244,10 @@ static int select_event_loop_once(struct tevent_context *ev, const char *locatio
return 0;
}
+ if (ev->threaded_contexts != NULL) {
+ tevent_common_threaded_activate_immediate(ev);
+ }
+
if (ev->immediate_events &&
tevent_common_loop_immediate(ev)) {
return 0;
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 635a7a1..c85e1c5 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -95,7 +95,6 @@ static uint32_t tevent_sig_count(struct tevent_sigcounter s)
*/
static void tevent_common_signal_handler(int signum)
{
- char c = 0;
struct tevent_common_signal_list *sl;
struct tevent_context *ev = NULL;
int saved_errno = errno;
@@ -106,13 +105,8 @@ static void tevent_common_signal_handler(int signum)
/* Write to each unique event context. */
for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
if (sl->se->event_ctx && sl->se->event_ctx != ev) {
- ssize_t ret;
-
ev = sl->se->event_ctx;
- /* doesn't matter if this pipe overflows */
- do {
- ret = write(ev->pipe_fds[1], &c, 1);
- } while (ret == -1 && errno == EINTR);
+ tevent_common_wakeup(ev);
}
}
@@ -198,16 +192,6 @@ static int tevent_signal_destructor(struct tevent_signal *se)
struct tevent_context *ev = se->event_ctx;
DLIST_REMOVE(ev->signal_events, se);
-
- if (ev->signal_events == NULL && ev->pipe_fde != NULL) {
- /*
- * This was the last signal. Destroy the pipe.
- */
- TALLOC_FREE(ev->pipe_fde);
-
- close(ev->pipe_fds[0]);
- close(ev->pipe_fds[1]);
- }
}
talloc_free(sl);
@@ -233,21 +217,6 @@ static int tevent_signal_destructor(struct tevent_signal *se)
}
/*
- this is part of the pipe hack needed to avoid the signal race condition
-*/
-static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
- uint16_t flags, void *_private)
-{
- ssize_t ret;
-
- char c[16];
- /* its non-blocking, doesn't matter if we read too much */
- do {
- ret = read(fde->fd, c, sizeof(c));
- } while (ret == -1 && errno == EINTR);
-}
-
-/*
add a signal event
return NULL on failure (memory allocation error)
*/
@@ -263,6 +232,13 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
struct tevent_signal *se;
struct tevent_common_signal_list *sl;
sigset_t set, oldset;
+ int ret;
+
+ ret = tevent_common_wakeup_init(ev);
+ if (ret != 0) {
+ errno = ret;
+ return NULL;
+ }
if (signum >= TEVENT_NUM_SIGNALS) {
errno = EINVAL;
@@ -304,26 +280,6 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
return NULL;
}
- /* we need to setup the pipe hack handler if not already
- setup */
- if (ev->pipe_fde == NULL) {
- if (pipe(ev->pipe_fds) == -1) {
- talloc_free(se);
- return NULL;
- }
- ev_set_blocking(ev->pipe_fds[0], false);
- ev_set_blocking(ev->pipe_fds[1], false);
- ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
- TEVENT_FD_READ,
- signal_pipe_handler, NULL);
- if (!ev->pipe_fde) {
- close(ev->pipe_fds[0]);
- close(ev->pipe_fds[1]);
- talloc_free(se);
- return NULL;
- }
- }
-
/* only install a signal handler if not already installed */
if (sig_state->sig_handlers[signum] == NULL) {
struct sigaction act;
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 15882e4..8197323 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -108,7 +108,7 @@ static void schedule_immediate_functions(struct tevent_thread_proxy *tp)
if (tp->tofree_im_list != NULL) {
/*
* Once the current immediate events
- * are processed, we need to reshedule
+ * are processed, we need to reschedule
* ourselves to free them. This works
* as tevent_schedule_immediate()
* always adds events to the *END* of
@@ -371,3 +371,156 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
;
}
#endif
+
+static int tevent_threaded_context_destructor(
+ struct tevent_threaded_context *tctx)
+{
+ int ret;
+
+ if (tctx->event_ctx != NULL) {
+ DLIST_REMOVE(tctx->event_ctx->threaded_contexts, tctx);
+ }
+
+ ret = pthread_mutex_destroy(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ return 0;
+}
+
+struct tevent_threaded_context *tevent_threaded_context_create(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev)
+{
+#ifdef HAVE_PTHREAD
+ struct tevent_threaded_context *tctx;
+ int ret;
+
+ ret = tevent_common_wakeup_init(ev);
+ if (ret != 0) {
+ errno = ret;
+ return NULL;
+ }
+
+ tctx = talloc(mem_ctx, struct tevent_threaded_context);
+ if (tctx == NULL) {
+ return NULL;
+ }
+ tctx->event_ctx = ev;
+ tctx->wakeup_fd = ev->wakeup_fd;
+
+ ret = pthread_mutex_init(&tctx->event_ctx_mutex, NULL);
+ if (ret != 0) {
+ TALLOC_FREE(tctx);
+ return NULL;
+ }
+
+ DLIST_ADD(ev->threaded_contexts, tctx);
+ talloc_set_destructor(tctx, tevent_threaded_context_destructor);
+
+ return tctx;
+#else
+ errno = ENOSYS;
+ return NULL;
+#endif
+}
+
+void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
+ struct tevent_immediate *im,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+#ifdef HAVE_PTHREAD
+ struct tevent_context *ev;
+ int ret;
+
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ 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.
+ */
+ return;
+ }
+
+ if ((im->event_ctx != NULL) || (handler == NULL)) {
+ abort();
+ }
+
+ im->event_ctx = ev;
+ im->handler = handler;
+ im->private_data = private_data;
+ im->handler_name = handler_name;
+ im->schedule_location = location;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ ret = pthread_mutex_lock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_ADD_END(ev->scheduled_immediates, im);
+
+ ret = pthread_mutex_unlock(&ev->scheduled_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
+ * with 1c4284c7395f23. This is not exactly the same, as the
+ * wakeup is only a last-resort thing in case the main thread
+ * is sleeping. Doing the wakeup under the lock can easily
+ * lead to a contended mutex, which is much more expensive
+ * than a noncontended one. So I'd opt for the lower footprint
+ * initially. Maybe we have to change that later.
+ */
+ tevent_common_wakeup_fd(tctx->wakeup_fd);
+#else
+ /*
+ * tevent_threaded_context_create() returned NULL with ENOSYS...
+ */
+ abort();
+#endif
+}
+
+void tevent_common_threaded_activate_immediate(struct tevent_context *ev)
+{
+#ifdef HAVE_PTHREAD
+ int ret;
+ ret = pthread_mutex_lock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ while (ev->scheduled_immediates != NULL) {
+ struct tevent_immediate *im = ev->scheduled_immediates;
+ DLIST_REMOVE(ev->scheduled_immediates, im);
+ DLIST_ADD_END(ev->immediate_events, im);
+ }
+
+ ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+#else
+ /*
+ * tevent_threaded_context_create() returned NULL with ENOSYS...
+ */
+ abort();
+#endif
+}
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index 920d39f..92f3ed1 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -154,39 +154,13 @@ static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
return -1;
}
-/*
- add a timed event
- return NULL on failure (memory allocation error)
-*/
-static struct tevent_timer *tevent_common_add_timer_internal(
- struct tevent_context *ev,
- TALLOC_CTX *mem_ctx,
- struct timeval next_event,
- tevent_timer_handler_t handler,
- void *private_data,
- const char *handler_name,
- const char *location,
- bool optimize_zero)
+static void tevent_common_insert_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ bool optimize_zero)
{
- struct tevent_timer *te, *prev_te, *cur_te;
-
- te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
- if (te == NULL) return NULL;
-
- te->event_ctx = ev;
- te->next_event = next_event;
- te->handler = handler;
- te->private_data = private_data;
- te->handler_name = handler_name;
- te->location = location;
- te->additional_data = NULL;
-
- if (ev->timer_events == NULL) {
- ev->last_zero_timer = NULL;
- }
+ struct tevent_timer *prev_te = NULL;
/* keep the list ordered */
- prev_te = NULL;
if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) {
/*
* Some callers use zero tevent_timer
@@ -199,6 +173,8 @@ static struct tevent_timer *tevent_common_add_timer_internal(
prev_te = ev->last_zero_timer;
ev->last_zero_timer = te;
} else {
+ struct tevent_timer *cur_te;
+
/*
* we traverse the list from the tail
* because it's much more likely that
@@ -227,6 +203,40 @@ static struct tevent_timer *tevent_common_add_timer_internal(
}
DLIST_ADD_AFTER(ev->timer_events, te, prev_te);
+}
+
+/*
+ add a timed event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_timer *tevent_common_add_timer_internal(
+ struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location,
+ bool optimize_zero)
+{
+ struct tevent_timer *te;
+
+ te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
+ if (te == NULL) return NULL;
+
+ te->event_ctx = ev;
+ te->next_event = next_event;
+ te->handler = handler;
+ te->private_data = private_data;
+ te->handler_name = handler_name;
+ te->location = location;
+ te->additional_data = NULL;
+
+ if (ev->timer_events == NULL) {
+ ev->last_zero_timer = NULL;
+ }
+
+ tevent_common_insert_timer(ev, te, optimize_zero);
talloc_set_destructor(te, tevent_common_timed_destructor);
@@ -274,6 +284,24 @@ struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
true);
}
+void tevent_update_timer(struct tevent_timer *te, struct timeval next_event)
+{
+ struct tevent_context *ev = te->event_ctx;
+
+ if (ev->last_zero_timer == te) {
+ te->event_ctx->last_zero_timer = DLIST_PREV(te);
+ }
+ DLIST_REMOVE(ev->timer_events, te);
+
+ te->next_event = next_event;
+
+ /*
+ * Not doing the zero_timer optimization. This is for new code
+ * that should know about immediates.
+ */
+ tevent_common_insert_timer(ev, te, false);
+}
+
/*
do a single event loop using the events defined in ev
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 71b9475..580ca4d 100755
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tevent'
-VERSION = '0.9.29'
+VERSION = '0.9.31'
blddir = 'bin'
@@ -99,9 +99,13 @@ def build(bld):
private_library = True
if not bld.CONFIG_SET('USING_SYSTEM_TEVENT'):
+ tevent_deps = 'replace talloc'
+ if bld.CONFIG_SET('HAVE_PTHREAD'):
+ tevent_deps += ' pthread'
+
bld.SAMBA_LIBRARY('tevent',
SRC,
- deps='replace talloc',
+ deps=tevent_deps,
enabled= not bld.CONFIG_SET('USING_SYSTEM_TEVENT'),
includes='.',
abi_directory='ABI',
diff --git a/modules/rdn_name.c b/modules/rdn_name.c
index f44ea71..e69ad93 100644
--- a/modules/rdn_name.c
+++ b/modules/rdn_name.c
@@ -144,7 +144,7 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
attribute = ldb_msg_find_element(msg, rdn_name);
if (!attribute) {
/* add entry with normalised RDN information if possible */
- if (a->name != NULL) {
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
ret = ldb_msg_add_value(msg, a->name, &rdn_val, NULL);
} else {
ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL);
@@ -154,7 +154,7 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
}
} else {
/* normalise attribute name if possible */
- if (a->name != NULL) {
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
attribute->name = a->name;
}
/* normalise attribute value */
@@ -243,6 +243,7 @@ static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
struct rename_context *ac;
struct ldb_request *mod_req;
const char *rdn_name;
+ const struct ldb_schema_attribute *a = NULL;
const struct ldb_val *rdn_val_p;
struct ldb_val rdn_val;
struct ldb_message *msg;
@@ -286,6 +287,15 @@ static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
goto error;
}
+ a = ldb_schema_attribute_by_name(ldb, rdn_name);
+ if (a == NULL) {
+ goto error;
+ }
+
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
+ rdn_name = a->name;
+ }
+
rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
if (rdn_val_p == NULL) {
goto error;
@@ -367,11 +377,20 @@ static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, down_req);
}
+static int rdn_recalculate_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
+
+ talloc_steal(up_req, req);
+ return up_req->callback(up_req, ares);
+}
+
static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb;
const struct ldb_val *rdn_val_p;
struct ldb_message_element *e = NULL;
+ struct ldb_control *recalculate_rdn_control = NULL;
ldb = ldb_module_get_ctx(module);
@@ -380,6 +399,138 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
+ recalculate_rdn_control = ldb_request_get_control(req,
+ LDB_CONTROL_RECALCULATE_RDN_OID);
+ if (recalculate_rdn_control != NULL) {
+ struct ldb_message *msg = NULL;
+ const char *rdn_name = NULL;
+ struct ldb_val rdn_val;
+ const struct ldb_schema_attribute *a = NULL;
+ struct ldb_request *mod_req = NULL;
+ int ret;
+ struct ldb_message_element *rdn_del = NULL;
+ struct ldb_message_element *name_del = NULL;
+
+ recalculate_rdn_control->critical = false;
+
+ msg = ldb_msg_copy_shallow(req, req->op.mod.message);
+ if (msg == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ /*
+ * The caller must pass a dummy 'name' attribute
+ * in order to bypass some high level checks.
+ *
+ * We just remove it and check nothing is left.
+ */
+ ldb_msg_remove_attr(msg, "name");
+
+ if (msg->num_elements != 0) {
+ return ldb_module_operr(module);
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(msg->dn);
+ if (rdn_name == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, rdn_name);
+ if (a == NULL) {
+ return ldb_module_operr(module);
+ }
+
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
+ rdn_name = a->name;
+ }
+
+ rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
+ if (rdn_val_p == NULL) {
+ return ldb_module_oom(module);
+ }
+ rdn_val = ldb_val_dup(msg, rdn_val_p);
+ if (rdn_val.length == 0) {
+ return ldb_module_oom(module);
+ }
+
+ /*
+ * This is a bit tricky:
+ *
+ * We want _DELETE elements (as "rdn_del" and "name_del" without
+ * values) first, followed by _ADD (with the real names)
+ * elements (with values). Then we fix up the "rdn_del" and
+ * "name_del" attributes.
+ */
+
+ ret = ldb_msg_add_empty(msg, "rdn_del", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+ ret = ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_ADD, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+ ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+
+ ret = ldb_msg_add_empty(msg, "name_del", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+ ret = ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+ ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+
+ rdn_del = ldb_msg_find_element(msg, "rdn_del");
+ if (rdn_del == NULL) {
+ return ldb_module_operr(module);
+ }
+ rdn_del->name = talloc_strdup(msg->elements, rdn_name);
+ if (rdn_del->name == NULL) {
+ return ldb_module_oom(module);
+ }
+ name_del = ldb_msg_find_element(msg, "name_del");
+ if (name_del == NULL) {
+ return ldb_module_operr(module);
+ }
+ name_del->name = talloc_strdup(msg->elements, "name");
+ if (name_del->name == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ ret = ldb_build_mod_req(&mod_req, ldb,
+ req, msg, NULL,
+ req, rdn_recalculate_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+ talloc_steal(mod_req, msg);
+
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_RECALCULATE_RDN_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_PERMISSIVE_MODIFY_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+
+ /* go on with the call chain */
+ return ldb_next_request(module, mod_req);
+ }
+
rdn_val_p = ldb_dn_get_rdn_val(req->op.mod.message->dn);
if (rdn_val_p == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
diff --git a/pyldb.h b/pyldb.h
index e0cce1e..4fc89ec 100644
--- a/pyldb.h
+++ b/pyldb.h
@@ -95,11 +95,12 @@ typedef struct {
struct ldb_control *data;
} PyLdbControlObject;
-#define PyErr_LDB_ERROR_IS_ERR_RAISE(err,ret,ldb) \
+#define PyErr_LDB_ERROR_IS_ERR_RAISE(err,ret,ldb) do { \
if (ret != LDB_SUCCESS) { \
PyErr_SetLdbError(err, ret, ldb); \
return NULL; \
- }
+ } \
+} while(0)
/* Picked out of thin air. To do this properly, we should probably have some part of the
* errors in LDB be allocated to bindings ? */
diff --git a/tests/test-tdb-features.sh b/tests/test-tdb-features.sh
index 59e61ee..a9cd6b3 100644
--- a/tests/test-tdb-features.sh
+++ b/tests/test-tdb-features.sh
@@ -4,6 +4,11 @@ echo "Running tdb feature tests"
mv $LDB_URL $LDB_URL.2
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: rdn_name
+EOF
+
checkcount() {
count=$1
expression="$2"
@@ -25,6 +30,7 @@ EOF
checkcount 1 '(test=foo)'
checkcount 0 '(test=FOO)'
checkcount 0 '(test=FO*)'
+checkcount 1 '(cn=t1)'
echo "Making case insensitive"
cat <<EOF | $VALGRIND ldbmodify || exit 1
@@ -79,6 +85,13 @@ EOF
checkcount 1 '(j=0x100)'
checkcount 1 '(j=256)'
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: num=1
+EOF
+
+echo "Testing search for attribute after change to use wildcard"
+checkcount 1 '(num=1)'
+
echo "Testing class search"
checkcount 0 '(objectClass=otherclass)'
checkcount 1 '(objectClass=testclass)'
diff --git a/tools/ldbdump.c b/tools/ldbdump.c
index 3197d19..33f853d 100644
--- a/tools/ldbdump.c
+++ b/tools/ldbdump.c
@@ -110,6 +110,9 @@ static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *sta
}
static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
const char *fmt, ...)
{
va_list ap;
diff --git a/tools/ldbutil.h b/tools/ldbutil.h
index f8d3f3a..6723863 100644
--- a/tools/ldbutil.h
+++ b/tools/ldbutil.h
@@ -43,4 +43,4 @@ int ldb_search_ctrl(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
struct ldb_result **result, struct ldb_dn *base,
enum ldb_scope scope, const char * const *attrs,
struct ldb_control **controls,
- const char *exp_fmt, ...);
+ const char *exp_fmt, ...) PRINTF_ATTRIBUTE(8,9);
diff --git a/wscript b/wscript
index 13f1d93..7f05db3 100755
--- a/wscript
+++ b/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'ldb'
-VERSION = '1.1.27'
+VERSION = '1.1.29'
blddir = 'bin'