Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-python
authorJelmer Vernooij <jelmer@samba.org>
Tue, 22 Jan 2008 15:39:56 +0000 (16:39 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Tue, 22 Jan 2008 15:39:56 +0000 (16:39 +0100)
201 files changed:
.gitignore
howto.txt
source/VERSION
source/auth/credentials/credentials.i
source/auth/credentials/credentials_wrap.c
source/auth/gensec/spnego_parse.c
source/auth/kerberos/gssapi_parse.c
source/build/m4/env.m4
source/build/m4/public.m4
source/build/smb_build/config_mk.pm
source/build/smb_build/makefile.pm
source/dsdb/samdb/ldb_modules/config.mk
source/dsdb/samdb/ldb_modules/instancetype.c [new file with mode: 0644]
source/dsdb/samdb/ldb_modules/linked_attributes.c
source/dsdb/samdb/ldb_modules/normalise.c [new file with mode: 0644]
source/dsdb/samdb/ldb_modules/objectclass.c
source/dsdb/samdb/ldb_modules/partition.c
source/dsdb/samdb/ldb_modules/samba3sam.c
source/dsdb/samdb/ldb_modules/simple_ldap_map.c
source/dsdb/samdb/samdb.c
source/headermap.txt
source/heimdal/lib/com_err/lex.c
source/heimdal_build/config.mk
source/ldap_server/ldap_server.c
source/lib/ldb/include/ldb.h
source/lib/ldb/ldb.i
source/lib/ldb/ldb.py
source/lib/ldb/ldb_map/ldb_map.c
source/lib/ldb/ldb_map/ldb_map.h
source/lib/ldb/ldb_wrap.c
source/lib/ldb/python.mk
source/lib/ldb/tests/python/api.py
source/lib/ldb/tests/python/ldap.py
source/lib/ldb/tools/ldbsearch.c
source/lib/nss_wrapper/config.mk
source/lib/policy/config.mk
source/lib/registry/dir.c
source/lib/registry/hive.c
source/lib/registry/ldb.c
source/lib/registry/local.c
source/lib/registry/patchfile.c
source/lib/registry/regf.c
source/lib/registry/samba.c
source/lib/registry/tests/hive.c
source/lib/registry/tests/registry.c
source/lib/replace/getpass.m4
source/lib/replace/libreplace.m4
source/lib/replace/libreplace_ld.m4
source/lib/replace/replace.c
source/lib/replace/replace.h
source/lib/replace/system/config.m4
source/lib/replace/system/network.h
source/lib/replace/system/passwd.h
source/lib/samba3/config.mk
source/lib/socket_wrapper/config.mk
source/lib/tdb/common/freelist.c
source/lib/tdb/common/io.c
source/lib/tdb/common/lock.c
source/lib/tdb/common/open.c
source/lib/tdb/common/tdb.c
source/lib/tdb/common/tdb_private.h
source/lib/tdb/common/transaction.c
source/lib/tdb/common/traverse.c
source/lib/tdb/docs/README
source/lib/tdb/include/tdb.h
source/lib/tdb/python/tdbdump.py [new file with mode: 0644]
source/lib/tdb/tools/tdbtool.c
source/lib/tdr/config.mk
source/lib/util/asn1.c [moved from source/libcli/util/asn1.c with 99% similarity]
source/lib/util/asn1.h [moved from source/libcli/util/asn_1.h with 97% similarity]
source/lib/util/config.mk
source/libcli/cldap/cldap.h
source/libcli/config.mk
source/libcli/ldap/ldap.c
source/libcli/ldap/ldap_client.c
source/libcli/ldap/ldap_controls.c
source/libcli/swig/libcli_nbt.i
source/libcli/swig/libcli_nbt.py
source/libcli/swig/libcli_nbt_wrap.c
source/libcli/swig/libcli_smb.i
source/libcli/swig/libcli_smb.py
source/libcli/swig/libcli_smb_wrap.c
source/libnet/config.mk
source/libnet/libnet_join.c
source/libnet/net_wrap.c
source/librpc/config.mk
source/librpc/idl/drsblobs.idl
source/librpc/idl/drsuapi.idl
source/librpc/idl/lsa.idl
source/librpc/idl/mgmt.idl
source/librpc/idl/nbt.idl
source/librpc/idl/netlogon.idl
source/librpc/idl/samr.idl
source/librpc/idl/spoolss.idl
source/librpc/idl/srvsvc.idl
source/librpc/idl/svcctl.idl
source/librpc/idl/winbind.idl
source/librpc/idl/winreg.idl
source/librpc/idl/wkssvc.idl
source/librpc/ndr/ndr_compression.c
source/librpc/ndr/ndr_drsuapi.c
source/librpc/rpc/dcerpc.i
source/librpc/rpc/dcerpc.py
source/librpc/rpc/dcerpc_wrap.c
source/nsswitch/config.mk
source/nsswitch/wbinfo.c
source/ntptr/config.mk
source/ntvfs/config.mk
source/param/config.mk
source/param/param.i
source/param/param_wrap.c
source/pidl/MANIFEST
source/pidl/META.yml [new file with mode: 0644]
source/pidl/README
source/pidl/TODO
source/pidl/idl.yp
source/pidl/lib/Parse/Pidl.pm
source/pidl/lib/Parse/Pidl/CUtil.pm [new file with mode: 0644]
source/pidl/lib/Parse/Pidl/Compat.pm
source/pidl/lib/Parse/Pidl/IDL.pm
source/pidl/lib/Parse/Pidl/NDR.pm
source/pidl/lib/Parse/Pidl/Samba3/ClientNDR.pm
source/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm
source/pidl/lib/Parse/Pidl/Samba4.pm
source/pidl/lib/Parse/Pidl/Samba4/EJS.pm
source/pidl/lib/Parse/Pidl/Samba4/Header.pm
source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
source/pidl/lib/Parse/Pidl/Samba4/Python.pm
source/pidl/lib/Parse/Pidl/Typelist.pm
source/pidl/pidl
source/pidl/smb_interfaces.pm [deleted file]
source/pidl/smb_interfaces.yp [deleted file]
source/pidl/tests/cutil.pl [new file with mode: 0755]
source/pidl/tests/header.pl
source/pidl/tests/ndr.pl
source/pidl/tests/parse_idl.pl
source/pidl/tests/samba-ejs.pl
source/pidl/tests/samba-ndr.pl
source/pidl/tests/samba3-cli.pl
source/pidl/tests/samba3-srv.pl [new file with mode: 0644]
source/pidl/tests/typelist.pl
source/rpc_server/netlogon/dcerpc_netlogon.c
source/rpc_server/samr/dcesrv_samr.c
source/samba4-skip
source/script/mkversion.sh
source/scripting/bin/epdump.py [new file with mode: 0644]
source/scripting/bin/winreg.py [changed mode: 0644->0755]
source/scripting/ejs/config.mk
source/scripting/ejs/ejsnet/net_user.c
source/scripting/libjs/provision.js
source/scripting/python/STATUS
source/scripting/python/config.m4
source/scripting/python/config.mk
source/scripting/python/modules.c
source/scripting/python/pyrpc.h [new file with mode: 0644]
source/scripting/python/pytalloc.c [new file with mode: 0644]
source/scripting/python/pytalloc.h [new file with mode: 0644]
source/scripting/python/samba/__init__.py
source/scripting/python/samba/provision.py
source/scripting/python/samba/samdb.py
source/scripting/python/samba/tests/dcerpc/__init__.py [new file with mode: 0644]
source/scripting/python/samba/tests/dcerpc/registry.py [new file with mode: 0644]
source/scripting/python/samba/tests/dcerpc/rpcecho.py [new file with mode: 0644]
source/scripting/python/samba/tests/dcerpc/sam.py [new file with mode: 0644]
source/scripting/python/uuidmodule.c
source/selftest/README
source/selftest/samba4_tests.sh
source/selftest/selftest.pl
source/selftest/target/Samba3.pm [moved from source/selftest/env/Samba3.pm with 100% similarity]
source/selftest/target/Samba4.pm [moved from source/selftest/env/Samba4.pm with 98% similarity]
source/selftest/target/Windows.pm [moved from source/selftest/env/Windows.pm with 100% similarity]
source/setup/display_specifiers.ldif
source/setup/fedorads-partitions.ldif
source/setup/provision
source/setup/provision-backend
source/setup/provision.ldif
source/setup/provision.py
source/setup/provision_basedn.ldif
source/setup/provision_computers_modify.ldif
source/setup/provision_configuration.ldif
source/setup/provision_configuration_basedn.ldif
source/setup/provision_configuration_basedn_modify.ldif
source/setup/provision_schema_basedn.ldif
source/setup/provision_schema_basedn_modify.ldif
source/setup/provision_self_join.ldif
source/setup/provision_templates.ldif
source/setup/provision_users.ldif
source/setup/provision_users_modify.ldif
source/setup/schema-map-fedora-ds-1.0
source/setup/schema_samba4.ldif
source/setup/slapd.conf
source/smbd/config.mk
source/smbd/process_model.mk
source/torture/gentest.c
source/torture/libnet/libnet.c
source/torture/raw/streams.c
source/torture/rpc/netlogon.c
source/torture/rpc/samba3rpc.c
testprogs/blackbox/test_ldb.sh
testprogs/blackbox/test_smbclient.sh
testprogs/ejs/ldap.js

index 8af28d01af724792db40ca83d1e58004ee6c8f2f..9ed0334ea13a80cb4219e91843b306887fb46ea6 100644 (file)
@@ -1,3 +1,4 @@
+source/test-results
 source/lib/gencache/gencache.h
 source/lib/ldb/bin
 *.pc
@@ -7,6 +8,7 @@ autom4te.cache
 *.x
 *.hd
 *.ho
+*.pyc
 Makefile
 configure
 source/bin/*
@@ -65,6 +67,7 @@ source/lib/util/pidfile.h
 source/lib/util/unix_privs.h
 source/lib/util/util_proto.h
 source/lib/util/wrap_xattr.h
+source/lib/util/asn1_proto.h
 source/libcli/finddcs.h
 source/libcli/libcli_proto.h
 source/libcli/auth/proto.h
@@ -77,7 +80,6 @@ source/libcli/resolve/proto.h
 source/libcli/security/proto.h
 source/libcli/smb2/smb2_proto.h
 source/libcli/smb_composite/proto.h
-source/libcli/util/asn1_proto.h
 source/libcli/util/clilsa.h
 source/libcli/util/proto.h
 source/libcli/wrepl/winsrepl_proto.h
@@ -179,3 +181,15 @@ source/lib/registry/tools/common.h
 source/librpc/ndr/ndr_table.h
 source/rpc_server/lsa/proto.h
 source/torture/winbind/proto.h
+*~
+source/auth/auth_sam_reply.h
+source/auth/session_proto.h
+source/auth/system_session_proto.h
+source/dsdb/common/proto.h
+source/dsdb/schema/proto.h
+source/lib/crypto/test_proto.h
+source/lib/registry/tests/proto.h
+source/lib/util/apidocs
+source/lib/util/util_ldb.h
+source/libcli/ldap/ldap_ndr.h
+source/libcli/resolve/lp_proto.h
index 7b10b5960a4571933ea191b7828c894b47ba7d34..654ad658c8b795c3116840b0f4774a9eaa90b2bd 100644 (file)
--- a/howto.txt
+++ b/howto.txt
@@ -1,9 +1,8 @@
 Samba4 developer howto
-----------------------
+======================
 
 tridge@samba.org, December 2004
 
-
 A more up to date version of this howto can be found in the wiki 
 at http://wiki.samba.org/index.php/Samba4/HOWTO.
 
@@ -12,31 +11,32 @@ server. This is aimed at developers who are already familiar with
 Samba3 and wish to participate in Samba4 development. This is not
 aimed at production use of Samba4.
 
+.. contents::
 
 Step 1: download Samba4
 -----------------------
 
 There are 2 methods of doing this:
 
-  method 1:  "rsync -avz samba.org::ftp/unpacked/samba4 ."
+  method 1:  "rsync -avz samba.org::ftp/unpacked/samba_4_0_test/ samba4"
 
-  method 2:  "svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0 samba4"
+  method 2:  "git clone git://git.samba.org/samba.git samba4; cd samba4; git checkout v4-0-test; cd .."
 
 both methods will create a directory called "samba4" in the current
-directory. If you don't have rsync or svn then install one of them. 
+directory. If you don't have rsync or git then install one of them. 
 
 Since only released versions of Samba contain a pregenerated configure script, 
-you will have to generate it by hand:
+you will have to generate it by hand::
 
  $ cd samba4/source
  $ ./autogen.sh
 
-Note that the above rsync command will give you a checked out svn
-repository. So if you also have svn you can update it to the latest
-version at some future date using:
+Note that the above rsync command will give you a checked out git
+repository. So if you also have git you can update it to the latest
+version at some future date using::
 
   $ cd samba4
-  $ svn up
+  $ git pull origin v4-0-test
 
 Step 2: compile Samba4
 ----------------------
@@ -46,7 +46,7 @@ Recommended optional development libraries:
 - gnutls
 - readline
 
-Run this:
+Run this::
 
   $ cd samba4/source
   $ ./configure
@@ -61,6 +61,8 @@ Step 3: install Samba4
 Run this as a user who have permission to write to the install
 directory (defaults to /usr/local/samba). Use --prefix option to
 configure above to change this.
+
+::
  
   # make install
 
@@ -73,6 +75,8 @@ binary is installed in a directory listed in your PATH environment variable.
 It is presumed it's available just like any other commands from your shell.
 Must be run as a user with permission to write to the install directory.
 
+::
+
   # cd source
   # ./setup/provision --realm=YOUR.REALM --domain=YOURDOM \
   #  --adminpass=SOMEPASSWORD --server-role='domain controller'
@@ -89,7 +93,7 @@ Step 5: Create a simple smb.conf
 
 The provisioning will create a very simple smb.conf with no shares by
 default. You will need to update it to add at least one share. For
-example:
+example::
 
   [test]
        path = /data/test
@@ -100,7 +104,7 @@ Step 6: starting Samba4
 -----------------------
 
 The simplest is to just run "smbd", but as a developer you may find
-the following more useful:
+the following more useful::
 
    # smbd -i -M single
 
@@ -119,11 +123,13 @@ in your $PATH. Make sure you run the right version!
 Step 7: testing Samba4
 ----------------------
 
-try these commands:
+try these commands::
 
-     $ smbclient //localhost/test -Uadministrator%SOMEPASSWORD
-    or
-     $ ./script/tests/test_posix.sh //localhost/test administrator SOMEPASSWORD
+  $ smbclient //localhost/test -Uadministrator%SOMEPASSWORD
+
+or::
+
+  $ ./script/tests/test_posix.sh //localhost/test administrator SOMEPASSWORD
 
 
 NOTE about filesystem support
@@ -133,23 +139,23 @@ To use the advanced features of Samba4 you need a filesystem that
 supports both the "user" and "system" xattr namespaces.
 
 If you run Linux with a 2.6 kernel and ext3 this means you need to
-include the option "user_xattr" in your /etc/fstab. For example:
+include the option "user_xattr" in your /etc/fstab. For example::
 
-/dev/hda3              /home                   ext3    user_xattr     1 1
+   /dev/hda3           /home                   ext3    user_xattr     1 1
 
 You also need to compile your kernel with the XATTR and SECURITY
-options for your filesystem. For ext3 that means you need:
+options for your filesystem. For ext3 that means you need::
 
    CONFIG_EXT3_FS_XATTR=y
    CONFIG_EXT3_FS_SECURITY=y
 
 If you are running a Linux 2.6 kernel with CONFIG_IKCONFIG_PROC
-defined you can check this with the following command:
+defined you can check this with the following command::
 
    $ zgrep CONFIG_EXT3_FS /proc/config.gz
 
 If you don't have a filesystem with xattr support, then you can
-simulate it by using the option:
+simulate it by using the option::
 
    posix:eadb = /usr/local/samba/eadb.tdb
 
@@ -161,7 +167,7 @@ Testing your filesystem
 -----------------------
 
 To test your filesystem support, install the 'attr' package and run
-the following 4 commands as root:
+the following 4 commands as root::
 
   # touch test.txt
   # setfattr -n user.test -v test test.txt
@@ -169,11 +175,11 @@ the following 4 commands as root:
   # getfattr -d test.txt
   # getfattr -n security.test -d test.txt
 
-You should see output like this:
+You should see output like this::
 
   # file: test.txt
   user.test="test"
-
+  
   # file: test.txt
   security.test="test2"
 
@@ -184,4 +190,5 @@ with the right options.
 If you get any "Operation not permitted" errors then it probably means
 you didn't try the test as root.
 
-
+..
+       vim: ft=rest
index 2f5f7009de51aec524333cb859dec1e979d19d68..29ff51638e3b94809a474dd7e8029f0dece36b65 100644 (file)
@@ -89,7 +89,7 @@ SAMBA_VERSION_RC_RELEASE=
 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes               #
 #  ->  "3.0.0-SVN-build-199"                           #
 ########################################################
-SAMBA_VERSION_IS_SVN_SNAPSHOT=yes
+SAMBA_VERSION_IS_GIT_SNAPSHOT=yes
 
 ########################################################
 # This is for specifying a release nickname            #
index 8f09ff4b185903e1e9ec7ce4b5e8e5fabc711683..ee09b43a753d46eedc929c8f5242a21681f27227 100644 (file)
@@ -95,3 +95,20 @@ typedef struct cli_credentials {
         bool wrong_password(void);
     }
 } cli_credentials;
+
+%{
+struct cli_credentials *cli_credentials_from_py_object(PyObject *py_obj)
+{
+    struct cli_credentials *ret;
+
+    if (py_obj == Py_None) {
+        return cli_credentials_init_anon(NULL);
+    }
+
+    if (SWIG_ConvertPtr(py_obj, (void *)&ret, SWIGTYPE_p_cli_credentials, 0 |  0 ) < 0) {
+        return NULL; 
+    }
+    return ret;
+}
+
+%}
index ebf7162c5bb178c55fc4cef74892d3aa2030aaf1..146a81abafaa71894bc81a53744b4641a84d68cd 100644 (file)
@@ -2774,6 +2774,22 @@ SWIGINTERNINLINE PyObject*
 }
 
 SWIGINTERN void delete_cli_credentials(cli_credentials *self){ talloc_free(self); }
+
+struct cli_credentials *cli_credentials_from_py_object(PyObject *py_obj)
+{
+    struct cli_credentials *ret;
+
+    if (py_obj == Py_None) {
+        return cli_credentials_init_anon(NULL);
+    }
+
+    if (SWIG_ConvertPtr(py_obj, (void *)&ret, SWIGTYPE_p_cli_credentials, 0 |  0 ) < 0) {
+        return NULL; 
+    }
+    return ret;
+}
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
index 37f4f12278ad85964f873ab4a3eb6403fe0b8e31..8012a83ba8d59149e9d49355f90e89bb5696828a 100644 (file)
@@ -23,7 +23,7 @@
 #include "includes.h"
 #include "auth/gensec/spnego.h"
 #include "auth/gensec/gensec.h"
-#include "libcli/util/asn_1.h"
+#include "lib/util/asn1.h"
 
 static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
                              struct spnego_negTokenInit *token)
index 4b1b178238773fd8b49479eda0ba67f77577df50..77e907d3fae6217a766b6aee0650f64ca77aa0a0 100644 (file)
@@ -22,7 +22,7 @@
 */
 
 #include "includes.h"
-#include "libcli/util/asn_1.h"
+#include "lib/util/asn1.h"
 #include "auth/gensec/gensec.h"
 
 /*
index 7556f16ce2a4965b3dd286c38ade25f01f90d27e..9510a8ee0d0bb0ecdf6bb44ae2a138412aa7a6d2 100644 (file)
@@ -19,9 +19,20 @@ AC_SUBST(datarootdir)
 SMB_VERSION_STRING=`cat ${srcdir}/version.h | grep 'SAMBA_VERSION_OFFICIAL_STRING' | cut -d '"' -f2`
 echo "SAMBA VERSION: ${SMB_VERSION_STRING}"
 
-SAMBA_VERSION_SVN_REVISION=`cat ${srcdir}/version.h | grep 'SAMBA_VERSION_SVN_REVISION' | cut -d ' ' -f3-`
-if test -n "${SAMBA_VERSION_SVN_REVISION}";then
-       echo "BUILD REVISION: ${SAMBA_VERSION_SVN_REVISION}"
+SAMBA_VERSION_GIT_COMMIT_FULLREV=`cat ${srcdir}/version.h | grep 'SAMBA_VERSION_GIT_COMMIT_FULLREV' | cut -d ' ' -f3- | cut -d '"' -f2`
+if test -n "${SAMBA_VERSION_GIT_COMMIT_FULLREV}";then
+       echo "BUILD COMMIT REVISION: ${SAMBA_VERSION_GIT_COMMIT_FULLREV}"
+fi
+SAMBA_VERSION_GIT_COMMIT_DATE=`cat ${srcdir}/version.h | grep 'SAMBA_VERSION_GIT_COMMIT_DATE' | cut -d ' ' -f3-`
+if test -n "${SAMBA_VERSION_GIT_COMMIT_DATE}";then
+       echo "BUILD COMMIT DATE: ${SAMBA_VERSION_GIT_COMMIT_DATE}"
+fi
+SAMBA_VERSION_GIT_COMMIT_TIME=`cat ${srcdir}/version.h | grep 'SAMBA_VERSION_GIT_COMMIT_TIME' | cut -d ' ' -f3-`
+if test -n "${SAMBA_VERSION_GIT_COMMIT_TIME}";then
+       echo "BUILD COMMIT TIME: ${SAMBA_VERSION_GIT_COMMIT_TIME}"
+
+       # just to keep the build-farm gui happy for now...
+       echo "BUILD REVISION: ${SAMBA_VERSION_GIT_COMMIT_TIME}"
 fi
 
 m4_include(build/m4/check_path.m4)
index 9e82e6aaf199e7c7e2e47d8dae1aa83123deb4bc..6d693eaeeea9a5fbf4a2958a6cb250f2e4044ad0 100644 (file)
@@ -8,7 +8,7 @@ dnl SMB_SUBSYSTEM(name,obj_files,required_subsystems)
 dnl
 dnl SMB_EXT_LIB_FROM_PKGCONFIG(name,pkg-config name,[ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
 dnl
-dnl SMB_EXT_LIB(name,libs,cflags,cppflags,ldflags)
+dnl SMB_EXT_LIB(name,libs,cflags,cppflags,ldflags,pcname)
 dnl
 dnl SMB_ENABLE(name,default_build)
 dnl
@@ -34,7 +34,7 @@ ENABLE = YES
 "
 ])
 
-dnl SMB_LIBRARY(name,description,obj_files,required_subsystems,version,so_version,cflags,ldflags)
+dnl SMB_LIBRARY(name,description,obj_files,required_subsystems,version,so_version,cflags,ldflags,pcname)
 AC_DEFUN([SMB_LIBRARY],
 [
 SMB_INFO_LIBRARIES="$SMB_INFO_LIBRARIES
@@ -48,6 +48,7 @@ VERSION = $5
 SO_VERSION = $6 
 CFLAGS = $7
 LDFLAGS = $8
+PC_NAME = $9
 ENABLE = YES
 # End Library $1
 ###################################
@@ -93,7 +94,8 @@ AC_DEFUN([SMB_EXT_LIB_FROM_PKGCONFIG],
                                        [`$PKG_CONFIG --libs-only-l '$2'`], 
                                        [`$PKG_CONFIG --cflags-only-other '$2'`],
                                        [`$PKG_CONFIG --cflags-only-I '$2'`],
-                                       [`$PKG_CONFIG --libs-only-other '$2'` `$PKG_CONFIG --libs-only-L '$2'`])
+                                       [`$PKG_CONFIG --libs-only-other '$2'` `$PKG_CONFIG --libs-only-L '$2'`],
+                                       [ $2 ])
                                ac_cv_$1_found=yes
 
                        else
@@ -125,7 +127,7 @@ include $1
 "
 ])
 
-dnl SMB_EXT_LIB(name,libs,cflags,cppflags,ldflags)
+dnl SMB_EXT_LIB(name,libs,cflags,cppflags,ldflags,pcname)
 AC_DEFUN([SMB_EXT_LIB],
 [
 
@@ -137,6 +139,7 @@ LIBS = $2
 CFLAGS = $3
 CPPFLAGS = $4
 LDFLAGS = $5
+PC_NAME = $6
 # End Ext Lib $1
 ###################################
 "
index 7ad6600a8c4510053d215830dc49734c462612ed..d07660ba1d826365c39a06f8bd3b7e9bdbc26a76 100644 (file)
@@ -18,6 +18,7 @@ my $section_types = {
                "CFLAGS"                => "list",
                "CPPFLAGS"              => "list",
                "LDFLAGS"               => "list",
+               "PC_NAME" => "string",
                },
        "PYTHON" => {
                SWIG_FILE => "string",
@@ -26,6 +27,7 @@ my $section_types = {
                "OBJ_FILES" => "list",
                "ENABLE"                => "bool",
                "LDFLAGS"               => "list",
+               "CFLAGS"                => "list",
        },
        "SUBSYSTEM" => {
                "OBJ_FILES"             => "list",
@@ -87,6 +89,8 @@ my $section_types = {
                "VERSION"               => "string",
                "SO_VERSION"            => "string",
                "LIBRARY_REALNAME" => "string",
+
+               "PC_NAME" => "string",
                
                "INIT_FUNCTION_TYPE"    => "string",
                "INIT_FUNCTION_SENTINEL" => "string",
index 0e7771c3f2a337786abcc17d9b19fcdfc641dbbd..7e715b47eb349db20413b0f2d78a90b52d473b70 100644 (file)
@@ -27,6 +27,7 @@ sub new($$$)
        $self->{torture_progs} = [];
        $self->{static_libs} = [];
        $self->{python_dsos} = [];
+       $self->{python_pys} = [];
        $self->{shared_libs} = [];
        $self->{installable_shared_libs} = [];
        $self->{headers} = [];
@@ -345,7 +346,7 @@ sub SharedModule($$)
 
        push(@{$self->{all_objs}}, "\$($ctx->{TYPE}_$ctx->{NAME}_FULL_OBJ_LIST)");
 
-       if (defined($ctx->{INIT_FUNCTION})) {
+       if (defined($ctx->{INIT_FUNCTION}) and $ctx->{TYPE} ne "PYTHON") {
                my $init_fn = $ctx->{INIT_FUNCTION_TYPE};
                $init_fn =~ s/\(\*\)/init_module/;
                my $proto_fn = $ctx->{INIT_FUNCTION_TYPE};
@@ -539,7 +540,7 @@ sub PythonFiles($$)
                $self->output("$target: $source\n" .
                                          "\tmkdir -p \$(builddir)/bin/python\n" .
                              "\tcp $source \$@\n\n");
-               push (@{$self->{python_dsos}}, $target);
+               push (@{$self->{python_pys}}, $target);
        }
 }
 
@@ -569,24 +570,21 @@ sub PkgConfig($$$)
        my $pubs;
        my $privs;
        my $privlibs;
+       my $publibs = "";
 
        if (defined($ctx->{PUBLIC_DEPENDENCIES})) {
                foreach (@{$ctx->{PUBLIC_DEPENDENCIES}}) {
                        next if ($other->{$_}->{ENABLE} eq "NO");
-                       if ($other->{$_}->{TYPE} eq "EXT_LIB") {
+                       if (defined($other->{$_}->{PC_NAME})) {
+                               $pubs .= "$other->{$_}->{PC_NAME} ";
+                       } elsif ($other->{$_}->{TYPE} eq "EXT_LIB") {
                                my $e = $other->{$_};
-
                                my $ldflags = join(" ", @{$e->{LDFLAGS}});
                                $ldflags .= " " unless $ldflags eq "";
                                my $libs = join(" ", @{$e->{LIBS}});
                                $libs .= " " unless $libs eq "";
 
-                               $pubs .= $ldflags.$libs;
-                       } elsif ($other->{$_}->{TYPE} eq "LIBRARY") {
-                               s/^LIB//g;
-                               $_ = lc($_);
-
-                               $pubs .= "$_ ";
+                               $publibs .= $ldflags.$libs;
                        } else {
                                s/^LIB//g;
                                $_ = lc($_);
@@ -625,7 +623,7 @@ sub PkgConfig($$$)
        smb_build::env::PkgConfig($self,
                $path,
                $link_name,
-               "-L\${libdir} -l$link_name",
+               "-L\${libdir} -l$link_name $publibs",
                $privlibs,
                "",
                "$ctx->{VERSION}",
@@ -714,6 +712,7 @@ sub write($$)
        $self->output("STATIC_LIBS = " . array2oneperline($self->{static_libs}) . "\n");
        $self->output("SHARED_LIBS = " . array2oneperline($self->{shared_libs}) . "\n");
        $self->output("PYTHON_DSOS = " . array2oneperline($self->{python_dsos}) . "\n");
+       $self->output("PYTHON_PYS = " . array2oneperline($self->{python_pys}) . "\n");
        $self->output("INSTALLABLE_SHARED_LIBS = " . array2oneperline($self->{installable_shared_libs}) . "\n");
        $self->output("PUBLIC_HEADERS = " . array2oneperline($self->{headers}) . "\n");
        $self->output("PC_FILES = " . array2oneperline($self->{pc_files}) . "\n");
index 95bb7de06cdc6149ee87413bf92bcb70e9d3824b..dc407fbd8a9a049b0c8618dc86941d6ff7547852 100644 (file)
@@ -320,3 +320,29 @@ OBJ_FILES = \
 # End MODULE ldb_anr
 ################################################
 
+################################################
+# Start MODULE ldb_normalise
+[MODULE::ldb_normalise]
+INIT_FUNCTION = ldb_normalise_init
+CFLAGS = -Ilib/ldb/include
+OUTPUT_TYPE = SHARED_LIBRARY
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBSAMBA-UTIL SAMDB
+SUBSYSTEM = LIBLDB
+OBJ_FILES = \
+               normalise.o
+# End MODULE ldb_normalise
+################################################
+
+################################################
+# Start MODULE ldb_instancetype
+[MODULE::ldb_instancetype]
+INIT_FUNCTION = ldb_instancetype_init
+CFLAGS = -Ilib/ldb/include
+OUTPUT_TYPE = SHARED_LIBRARY
+PRIVATE_DEPENDENCIES = LIBTALLOC
+SUBSYSTEM = LIBLDB
+OBJ_FILES = \
+               instancetype.o
+# End MODULE ldb_instancetype
+################################################
+
diff --git a/source/dsdb/samdb/ldb_modules/instancetype.c b/source/dsdb/samdb/ldb_modules/instancetype.c
new file mode 100644 (file)
index 0000000..064c28e
--- /dev/null
@@ -0,0 +1,128 @@
+/* 
+   ldb database library
+
+   Copyright (C) Simo Sorce  2004-2006
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+
+     ** NOTE! The following LGPL license applies to the ldb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb instancetype module
+ *
+ *  Description: add an instanceType onto every new record
+ *
+ *  Author: Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb_includes.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/flags.h"
+
+/* add_record: add instancetype attribute */
+static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_request *down_req;
+       struct ldb_message *msg;
+       uint32_t instance_type;
+       int ret;
+       const struct ldb_control *partition_ctrl;
+       const struct dsdb_control_current_partition *partition;
+
+       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "instancetype_add_record\n");
+
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.add.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
+       if (!partition_ctrl) {
+               ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
+                             "instancetype_add: no current partition control found");
+               return LDB_ERR_CONSTRAINT_VIOLATION;
+       }
+
+       partition = talloc_get_type(partition_ctrl->data,
+                                   struct dsdb_control_current_partition);
+       SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
+
+       down_req = talloc(req, struct ldb_request);
+       if (down_req == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       *down_req = *req;
+
+       /* we have to copy the message as the caller might have it as a const */
+       down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+       if (msg == NULL) {
+               talloc_free(down_req);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /*
+        * TODO: calculate correct instance type
+        */
+       instance_type = INSTANCE_TYPE_WRITE;
+       if (ldb_dn_compare(partition->dn, msg->dn) == 0) {
+               instance_type |= INSTANCE_TYPE_IS_NC_HEAD;
+               if (ldb_dn_compare(msg->dn, samdb_base_dn(module->ldb)) != 0) {
+                       instance_type |= INSTANCE_TYPE_NC_ABOVE;
+               }
+       }
+
+       ret = ldb_msg_add_fmt(msg, "instanceType", "%u", instance_type);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(down_req);
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+
+       /* go on with the call chain */
+       ret = ldb_next_request(module, down_req);
+
+       /* do not free down_req as the call results may be linked to it,
+        * it will be freed when the upper level request get freed */
+       if (ret == LDB_SUCCESS) {
+               req->handle = down_req->handle;
+       }
+
+       return ret;
+}
+
+static const struct ldb_module_ops instancetype_ops = {
+       .name          = "instancetype",
+       .add           = instancetype_add,
+};
+
+
+int ldb_instancetype_init(void)
+{
+       return ldb_register_module(&instancetype_ops);
+}
index 803d24e34ea79db557e5bf6698273ad07d1c60c2..b3fdffe5669f6c88cb02eb8f408bba2958ed947d 100644 (file)
@@ -279,6 +279,27 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
        return setup_modifies(module->ldb, ac, ac, req->op.add.message, NULL, req->op.add.message->dn);
 }
 
+struct merge {
+       struct ldb_dn *dn;
+       bool add;
+       bool ignore;
+};
+
+static int merge_cmp(struct merge *merge1, struct merge *merge2) {
+       int ret;
+       ret = ldb_dn_compare(merge1->dn, merge2->dn);
+       if (ret == 0) {
+               if (merge1->add == merge2->add) {
+                       return 0;
+               }
+               if (merge1->add == true) {
+                       return 1;
+               }
+               return -1;
+       }
+       return ret;
+}
+
 static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
 {
        struct replace_context *ac2 = talloc_get_type(context, struct replace_context);
@@ -296,16 +317,63 @@ static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb
                
                /* See if this element already exists */
                if (search_el) {
-                       int ret;
+
+                       struct merge *merged_list = NULL;
+
+                       int ret, size = 0, i;
                        struct ldb_message *msg = ldb_msg_new(ac);
                        if (!msg) {
                                ldb_oom(ac->module->ldb);
                                return LDB_ERR_OPERATIONS_ERROR;
                        }
 
-                       /* Lazy option:  Delete and add the elements on all members */
-                       msg->num_elements = 1;
-                       msg->elements = search_el;
+                       /* Add all the existing elements, marking as 'proposed for delete' by setting .add = false */
+                       for (i=0; i < search_el->num_values; i++) {
+                               merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1);
+                               merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)search_el->values[i].data);
+                               merged_list[size].add = false;
+                               merged_list[size].ignore = false;
+                               size++;
+                       }
+
+                       /* Add all the new replacement elements, marking as 'proposed for add' by setting .add = true */
+                       for (i=0; i < ac2->el->num_values; i++) {
+                               merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1);
+                               merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)ac2->el->values[i].data);
+                               merged_list[size].add = true;
+                               merged_list[size].ignore = false;
+                               size++;
+                       }
+
+                       /* Sort the list, so we can pick out an add and delete for the same DN, and eliminate them */
+                       qsort(merged_list, size,
+                             sizeof(*merged_list),
+                             (comparison_fn_t)merge_cmp);
+
+                       /* Now things are sorted, it is trivial to mark pairs of DNs as 'ignore' */
+                       for (i=0; i + 1 < size; i++) {
+                               if (ldb_dn_compare(merged_list[i].dn, 
+                                                  merged_list[i+1].dn) == 0 
+                                   /* Fortunetly the sort also sorts 'add == false' first */
+                                   && merged_list[i].add == false
+                                   && merged_list[i+1].add == true) {
+
+                                       /* Mark as ignore, so we include neither in the actual operations */
+                                       merged_list[i].ignore = true;
+                                       merged_list[i+1].ignore = true;
+                               }
+                       }
+
+                       /* Arrange to delete anything the search found that we don't re-add */
+                       for (i=0; i < size; i++) {
+                               if (merged_list[i].ignore == false
+                                   && merged_list[i].add == false) {
+                                       ldb_msg_add_steal_string(msg, search_el->name, 
+                                                                ldb_dn_get_linearized(merged_list[i].dn));
+                               }
+                       }
+
+                       /* The DN to set on the linked attributes is the original DN of the modify message */
                        msg->dn = ac->orig_req->op.mod.message->dn;
                        
                        ret = setup_modifies(ac->module->ldb, ac2, ac, msg, ares->message->dn, NULL);
@@ -313,13 +381,21 @@ static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb
                                return ret;
                        }
 
-                       msg->elements = ac2->el;
+                       /* Now add links for all the actually new elements */
+                       for (i=0; i < size; i++) {
+                               if (merged_list[i].ignore == false && merged_list[i].add == true) {
+                                       ldb_msg_add_steal_string(msg, search_el->name, 
+                                                                ldb_dn_get_linearized(merged_list[i].dn));
+                               }
+                       }
 
                        ret = setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ares->message->dn);
                        if (ret != LDB_SUCCESS) {
                                return ret;
                        }
                        
+                       talloc_free(merged_list);
+
                } else {
                        /* Looks like it doesn't exist, process like an 'add' */
                        struct ldb_message *msg = ldb_msg_new(ac);
@@ -411,6 +487,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                        return LDB_ERR_OBJECT_CLASS_VIOLATION;                  
                }
 
+               /* Replace with new set of values */
                if (((el->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_REPLACE)
                    && el->num_values > 0) {
                        struct replace_context *ac2 = talloc(ac, struct replace_context);
@@ -461,6 +538,8 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                        }
                        
                        continue;
+
+                       /* Delete all values case */
                } else if (((el->flags & LDB_FLAG_MOD_MASK) & (LDB_FLAG_MOD_DELETE|LDB_FLAG_MOD_REPLACE)) 
                           && el->num_values == 0) {
                        const char **attrs = talloc_array(ac, const char *, 2);
@@ -508,7 +587,8 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                        
                        continue;
                }
-               /* Prepare the modify (mod element) on the targets */
+
+               /* Prepare the modify (mod element) on the targets, for a normal modify request */
 
                /* For each value being moded, we need to setup the modify */
                for (j=0; j < el->num_values; j++) {
diff --git a/source/dsdb/samdb/ldb_modules/normalise.c b/source/dsdb/samdb/ldb_modules/normalise.c
new file mode 100644 (file)
index 0000000..efc9bb2
--- /dev/null
@@ -0,0 +1,166 @@
+/* 
+   ldb database library
+
+   Copyright (C) Amdrew Bartlett <abartlet@samba.org> 2007-2008
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb normalisation module
+ *
+ *  Description: module to ensure all DNs and attribute names are normalised
+ *
+ *  Author: Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+#include "dsdb/samdb/samdb.h"
+
+/* Fix up the DN to be in the standard form, taking particular care to match the parent DN
+
+   This should mean that if the parent is:
+    CN=Users,DC=samba,DC=example,DC=com
+   and a proposed child is
+    cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
+
+   The resulting DN should be:
+
+    CN=Admins,CN=Users,DC=samba,DC=example,DC=com
+   
+ */
+static int fix_dn(struct ldb_dn *dn) 
+{
+       int i, ret;
+       char *upper_rdn_attr;
+
+       for (i=0; i < ldb_dn_get_comp_num(dn); i++) {
+               /* We need the attribute name in upper case */
+               upper_rdn_attr = strupper_talloc(dn,
+                                                ldb_dn_get_component_name(dn, i));
+               if (!upper_rdn_attr) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               
+               /* And replace it with CN=foo (we need the attribute in upper case */
+               ret = ldb_dn_set_component(dn, i, upper_rdn_attr,
+                                          *ldb_dn_get_component_val(dn, i));
+               talloc_free(upper_rdn_attr);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+       return LDB_SUCCESS;
+}
+
+static int normalise_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
+{
+       const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+       struct ldb_request *orig_req = talloc_get_type(context, struct ldb_request);
+       TALLOC_CTX *mem_ctx;
+       int i, j, ret;
+
+       /* Only entries are interesting, and we handle the case of the parent seperatly */
+       if (ares->type != LDB_REPLY_ENTRY) {
+               return orig_req->callback(ldb, orig_req->context, ares);
+       }
+
+       if (!schema) {
+               return orig_req->callback(ldb, orig_req->context, ares);
+       }
+
+       mem_ctx = talloc_new(ares);
+       if (!mem_ctx) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* OK, we have one of *many* search results passing by here,
+        * but we should get them one at a time */
+
+       ret = fix_dn(ares->message->dn);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(mem_ctx);
+               return ret;
+       }
+
+       for (i = 0; i < ares->message->num_elements; i++) {
+               const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
+               if (!attribute) {
+                       continue;
+               }
+               if ((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") != 0) &&
+                   (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") != 0)) {
+                       continue;
+               }
+               for (j = 0; j < ares->message->elements[i].num_values; j++) {
+                       const char *dn_str;
+                       struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, (const char *)ares->message->elements[i].values[j].data);
+                       if (!dn) {
+                               talloc_free(mem_ctx);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       ret = fix_dn(ares->message->dn);
+                       if (ret != LDB_SUCCESS) {
+                               talloc_free(mem_ctx);
+                               return ret;
+                       }
+                       dn_str = talloc_steal(ares->message->elements[i].values, ldb_dn_get_linearized(dn));
+                       ares->message->elements[i].values[j] = data_blob_string_const(dn_str);
+                       talloc_free(dn);
+               }
+       }
+       talloc_free(mem_ctx);
+       return orig_req->callback(ldb, orig_req->context, ares);
+}
+
+/* search */
+static int normalise_search(struct ldb_module *module, struct ldb_request *req)
+{
+       int ret;
+       struct ldb_request *down_req = talloc(req, struct ldb_request);
+       if (!down_req) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       *down_req = *req;
+       down_req->context = req;
+       down_req->callback = normalise_search_callback;
+
+       ret = ldb_next_request(module, down_req);
+
+       /* do not free down_req as the call results may be linked to it,
+        * it will be freed when the upper level request get freed */
+       if (ret == LDB_SUCCESS) {
+               req->handle = down_req->handle;
+       }
+       return ret;
+}
+
+
+static const struct ldb_module_ops normalise_ops = {
+       .name              = "normalise",
+       .search            = normalise_search,
+};
+
+int ldb_normalise_init(void)
+{
+       return ldb_register_module(&normalise_ops);
+}
index d3beedc689ccb488d1c81f2ef921c19206de0ca9..737475ca78b24693bcfb7fd82e6a01b5a7fd9e40 100644 (file)
@@ -532,6 +532,10 @@ static int objectclass_do_add(struct ldb_handle *h)
                                        ldb_msg_add_string(msg, "objectCategory", 
                                                           current->objectclass->defaultObjectCategory);
                                }
+                               if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
+                                       ldb_msg_add_string(msg, "showInAdvancedViewOnly", 
+                                                          "TRUE");
+                               }
                                if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) {
                                        DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass);
                                        ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd);
index 4586810d9643606e9e58fd3277aae11cf1f2021b..61b64441a749ac817d3e593719d9099b52341a94 100644 (file)
@@ -169,13 +169,12 @@ static int partition_other_callback(struct ldb_context *ldb, void *context, stru
 }
 
 
-static int partition_send_request(struct partition_context *ac, struct ldb_control *remove_control, 
+static int partition_send_request(struct partition_context *ac, 
                                  struct dsdb_control_current_partition *partition)
 {
        int ret;
        struct ldb_module *backend;
        struct ldb_request *req;
-       struct ldb_control **saved_controls;
 
        if (partition) {
                backend = make_module_for_next_request(ac, ac->module->ldb, partition->module);
@@ -225,12 +224,6 @@ static int partition_send_request(struct partition_context *ac, struct ldb_contr
                req->context = ac;
        }
 
-       /* Remove a control, so we don't confuse a backend server */
-       if (remove_control && !save_controls(remove_control, req, &saved_controls)) {
-               ldb_oom(ac->module->ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
        if (partition) {
                ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);
                if (ret != LDB_SUCCESS) {
@@ -253,18 +246,17 @@ static int partition_send_request(struct partition_context *ac, struct ldb_contr
  */
 static int partition_send_all(struct ldb_module *module, 
                              struct partition_context *ac, 
-                             struct ldb_control *remove_control, 
                              struct ldb_request *req) 
 {
        int i;
        struct partition_private_data *data = talloc_get_type(module->private_data, 
                                                              struct partition_private_data);
-       int ret = partition_send_request(ac, remove_control, NULL);
+       int ret = partition_send_request(ac, NULL);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
        for (i=0; data && data->partitions && data->partitions[i]; i++) {
-               ret = partition_send_request(ac, remove_control, data->partitions[i]);
+               ret = partition_send_request(ac, data->partitions[i]);
                if (ret != LDB_SUCCESS) {
                        return ret;
                }
@@ -297,7 +289,7 @@ static int partition_replicate(struct ldb_module *module, struct ldb_request *re
                                        return LDB_ERR_OPERATIONS_ERROR;
                                }
                                
-                               return partition_send_all(module, ac, NULL, req);
+                               return partition_send_all(module, ac, req);
                        }
                }
        }
@@ -314,6 +306,7 @@ static int partition_replicate(struct ldb_module *module, struct ldb_request *re
                 * TODO: we should maybe return an error here
                 *       if it's not a special dn
                 */
+
                return ldb_next_request(module, req);
        }
 
@@ -334,6 +327,8 @@ static int partition_replicate(struct ldb_module *module, struct ldb_request *re
 /* search */
 static int partition_search(struct ldb_module *module, struct ldb_request *req)
 {
+       struct ldb_control **saved_controls;
+       
        /* Find backend */
        struct partition_private_data *data = talloc_get_type(module->private_data, 
                                                              struct partition_private_data);
@@ -342,19 +337,34 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
        /* (later) consider if we should be searching multiple
         * partitions (for 'invisible' partition behaviour */
        struct ldb_control *search_control = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
+       struct ldb_control *domain_scope_control = ldb_request_get_control(req, LDB_CONTROL_DOMAIN_SCOPE_OID);
        
        struct ldb_search_options_control *search_options = NULL;
        if (search_control) {
                search_options = talloc_get_type(search_control->data, struct ldb_search_options_control);
        }
 
+       /* Remove the domain_scope control, so we don't confuse a backend server */
+       if (domain_scope_control && !save_controls(domain_scope_control, req, &saved_controls)) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* TODO:
+          Generate referrals (look for a partition under this DN) if we don't have the above control specified
+       */
+       
        if (search_options && (search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
                int ret, i;
                struct partition_context *ac;
-               struct ldb_control *remove_control = NULL;
                if ((search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
                        /* We have processed this flag, so we are done with this control now */
-                       remove_control = search_control;
+
+                       /* Remove search control, so we don't confuse a backend server */
+                       if (search_control && !save_controls(search_control, req, &saved_controls)) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
                }
                ac = partition_init_handle(req, module);
                if (!ac) {
@@ -363,12 +373,12 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
 
                /* Search from the base DN */
                if (!req->op.search.base || ldb_dn_is_null(req->op.search.base)) {
-                       return partition_send_all(module, ac, remove_control, req);
+                       return partition_send_all(module, ac, req);
                }
                for (i=0; data && data->partitions && data->partitions[i]; i++) {
                        /* Find all partitions under the search base */
                        if (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->dn) == 0) {
-                               ret = partition_send_request(ac, remove_control, data->partitions[i]);
+                               ret = partition_send_request(ac, data->partitions[i]);
                                if (ret != LDB_SUCCESS) {
                                        return ret;
                                }
@@ -384,6 +394,16 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
                return LDB_SUCCESS;
        } else {
                /* Handle this like all other requests */
+               if (search_control && (search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
+                       /* We have processed this flag, so we are done with this control now */
+
+                       /* Remove search control, so we don't confuse a backend server */
+                       if (search_control && !save_controls(search_control, req, &saved_controls)) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+               }
+
                return partition_replicate(module, req, req->op.search.base);
        }
 }
@@ -693,7 +713,7 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req
                return LDB_ERR_OPERATIONS_ERROR;
        }
                        
-       return partition_send_all(module, ac, NULL, req);
+       return partition_send_all(module, ac, req);
 }
 
 static int sort_compare(void *void1,
index 0bfc9a3dae98543e7d9c8b2c17d621ddcb1ff8b6..3a666b5380fd1be42f35043a6fecc65a3cdc8035 100644 (file)
@@ -918,7 +918,7 @@ static int samba3sam_init(struct ldb_module *module)
 {
        int ret;
 
-       ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, NULL, "samba3sam");
+       ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, NULL, NULL, "samba3sam");
        if (ret != LDB_SUCCESS)
                return ret;
 
index 91001d43d7a078f9f45e5409782243ad7547e8a9..acf2fd622cc29ddb04134ec055d5dba6e5d53b99 100644 (file)
@@ -375,15 +375,6 @@ static const struct ldb_map_attribute entryuuid_attributes[] =
                         }
                }
        },
-       {
-               .local_name = "dn",
-               .type = MAP_RENAME,
-               .u = {
-                       .rename = {
-                                .remote_name = "entryDN"
-                        }
-               }
-       },
        {
                .local_name = "groupType",
                .type = MAP_CONVERT,
@@ -457,6 +448,7 @@ static const char * const entryuuid_wildcard_attributes[] = {
        "whenChanged",
        "usnCreated",
        "usnChanged",
+       "memberOf",
        NULL
 };
 
@@ -533,15 +525,6 @@ static const struct ldb_map_attribute nsuniqueid_attributes[] =
                         }
                }
        },
-       {
-               .local_name = "dn",
-               .type = MAP_RENAME,
-               .u = {
-                       .rename = {
-                                .remote_name = "entryDN"
-                        }
-               }
-       },
        {
                .local_name = "groupType",
                .type = MAP_CONVERT,
@@ -685,7 +668,7 @@ static int entryuuid_init(struct ldb_module *module)
        struct map_private *map_private;
        struct entryuuid_private *entryuuid_private;
 
-       ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, NULL);
+       ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "extensibleObject", NULL);
         if (ret != LDB_SUCCESS)
                 return ret;
 
@@ -706,7 +689,7 @@ static int nsuniqueid_init(struct ldb_module *module)
        struct map_private *map_private;
        struct entryuuid_private *entryuuid_private;
 
-       ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, NULL);
+       ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
         if (ret != LDB_SUCCESS)
                 return ret;
 
index b042d1d3b7bcd0ccaffc717740adb43edc637f33..c11eea1757c99a0649c6f79251d6aba413eeb010 100644 (file)
@@ -134,7 +134,7 @@ int samdb_copy_template(struct ldb_context *ldb,
        }
        
        /* pull the template record */
-       ret = ldb_search(templates_ldb, basedn, LDB_SCOPE_BASE, "(dn=*)", NULL, &res);  
+       ret = ldb_search(templates_ldb, basedn, LDB_SCOPE_BASE, "distinguishedName=*", NULL, &res);     
        talloc_free(basedn);
        if (ret != LDB_SUCCESS) {
                *errstring = talloc_steal(msg, ldb_errstring(templates_ldb));
index 6ace20519f1f06e69a33d485289f8602ec9d4ae7..acbe81328e2026138d9ea97437a63c9bc8b1b16f 100644 (file)
@@ -103,8 +103,8 @@ dsdb/samdb/samdb_proto.h: samdb/proto.h
 dsdb/schema/schema.h: samdb/schema.h
 dsdb/schema/proto.h: samdb/schema_proto.h
 dsdb/common/proto.h: samdb/common_proto.h
-libcli/util/asn_1.h: samba/asn1.h
-libcli/util/asn1_proto.h: samba/asn1/proto.h
+lib/util/asn1.h: samba/asn1.h
+lib/util/asn1_proto.h: samba/asn1/proto.h
 libcli/util/error.h: core/error.h
 libcli/util/proto.h: core/error_proto.h
 lib/tdb_wrap.h: tdb_wrap.h
index 77e79d4eae6791bf813c7ec94b7d36ae537c4ce6..7a85b302a11bcb80cab551a11c2ebe2acf9bbb88 100644 (file)
@@ -343,6 +343,9 @@ FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
 typedef int yy_state_type;
 
 extern int yylineno;
+
+int yylineno = 1;
+
 extern char *yytext;
 #define yytext_ptr yytext
 
@@ -530,7 +533,7 @@ static int getstring(void);
 
 #undef ECHO
 
-#line 533 "heimdal/lib/com_err/lex.c"
+#line 536 "heimdal/lib/com_err/lex.c"
 
 #define INITIAL 0
 
@@ -685,7 +688,7 @@ YY_DECL
     
 #line 59 "lex.l"
 
-#line 688 "heimdal/lib/com_err/lex.c"
+#line 691 "heimdal/lib/com_err/lex.c"
 
        if ( !(yy_init) )
                {
@@ -849,7 +852,7 @@ YY_RULE_SETUP
 #line 75 "lex.l"
 ECHO;
        YY_BREAK
-#line 852 "heimdal/lib/com_err/lex.c"
+#line 855 "heimdal/lib/com_err/lex.c"
 case YY_STATE_EOF(INITIAL):
        yyterminate();
 
@@ -1080,7 +1083,7 @@ static int yy_get_next_buffer (void)
 
                /* Read in more data. */
                YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-                       (yy_n_chars), num_to_read );
+                       (yy_n_chars), (size_t) num_to_read );
 
                YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
                }
@@ -1581,7 +1584,7 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
 
 /** Setup the input buffer state to scan a string. The next call to yylex() will
  * scan from a @e copy of @a str.
- * @param str a NUL-terminated string to scan
+ * @param yystr a NUL-terminated string to scan
  * 
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
@@ -1659,6 +1662,15 @@ static void yy_fatal_error (yyconst char* msg )
 
 /* Accessor  methods (get/set functions) to struct members. */
 
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
+
 /** Get the input stream.
  * 
  */
@@ -1692,6 +1704,16 @@ char *yyget_text  (void)
         return yytext;
 }
 
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
+
 /** Set the input stream. This does not discard the current
  * input buffer.
  * @param in_str A readable stream.
index b534c9bc9f66aa65528294f5eac78e7ac7487dd5..604516ccf640a88d16d4b7c08fd2fc3195e80b12 100644 (file)
@@ -543,9 +543,7 @@ clean::
 
 #######################
 # Start SUBSYSTEM HEIMDAL
-[LIBRARY::HEIMDAL]
-VERSION = 0.0.1
-SO_VERSION = 0
+[SUBSYSTEM::HEIMDAL]
 CFLAGS = -Iheimdal_build
 OBJ_FILES = ../heimdal/lib/vers/print_version.o
 PUBLIC_DEPENDENCIES = \
index fcc9435ead11a0ab65eb11b0879a261db754a5b2..8380775c287dfd6a580ab88b390733c0a4dee981 100644 (file)
@@ -27,7 +27,7 @@
 #include "auth/credentials/credentials.h"
 #include "librpc/gen_ndr/ndr_samr.h"
 #include "lib/util/dlinklist.h"
-#include "libcli/util/asn_1.h"
+#include "lib/util/asn1.h"
 #include "ldap_server/ldap_server.h"
 #include "smbd/service_task.h"
 #include "smbd/service_stream.h"
index e2ff8c6f98c53412144c9ac8ed8bd0c8c347887b..2e54920c17eaa7f25ea1906bc26af47cf1a21e7a 100644 (file)
@@ -705,7 +705,7 @@ struct ldb_handle {
 struct ldb_search {
        struct ldb_dn *base;
        enum ldb_scope scope;
-       const struct ldb_parse_tree *tree;
+       struct ldb_parse_tree *tree;
        const char * const *attrs;
        struct ldb_result *res;
 };
index 57cb6b5f47d36d2a73c71f0b9fd68a19ac81e4b1..560142eb6deb0822a566501d32a499cd4b642616 100644 (file)
@@ -50,6 +50,15 @@ typedef int ldb_error;
 %include "exception.i"
 %import "stdint.i"
 
+/* Don't expose talloc contexts in Python code. Python does reference 
+   counting for us, so just create a new top-level talloc context.
+ */
+%typemap(in, numinputs=0, noblock=1) TALLOC_CTX * {
+    $1 = NULL;
+}
+
+
+
 %constant int SCOPE_DEFAULT = LDB_SCOPE_DEFAULT;
 %constant int SCOPE_BASE = LDB_SCOPE_BASE;
 %constant int SCOPE_ONELEVEL = LDB_SCOPE_ONELEVEL;
@@ -115,7 +124,7 @@ typedef int ldb_error;
     }
 }
 
-%typemap(in,noblock=1,numinputs=1) const char * const *attrs {
+%typemap(in,noblock=1,numinputs=1) const char * const *NULL_STR_LIST {
     if ($input == Py_None) {
         $1 = NULL;
     } else if (PySequence_Check($input)) {
@@ -129,9 +138,13 @@ typedef int ldb_error;
     }
 }
 
-%typemap(freearg,noblock=1) const char * const *attrs {
+%typemap(freearg,noblock=1) const char * const *NULL_STR_LIST {
     talloc_free($1);
 }
+
+%apply const char * const *NULL_STR_LIST { const char * const *attrs }
+%apply const char * const *NULL_STR_LIST { const char * const *control_strings }
+
 #endif
 
 %types(struct ldb_result *);
@@ -188,6 +201,14 @@ fail:
 
         /* FIXME: implement __getslice__ */
 #endif
+    %pythoncode {
+        def __eq__(self, other):
+            if isinstance(other, self.__class__):
+                return self.__cmp__(other) == 0
+            if isinstance(other, str):
+                return str(self) == other
+            return False
+    }
     }
 } ldb_dn;
 
@@ -278,18 +299,43 @@ typedef struct ldb_message_element {
         {
             return ldb_msg_element_from_pyobject(NULL, set_obj, flags, name);
         }
+
+        int __len__()
+        {
+            return $self->num_values;
+        }
 #endif
+
+        PyObject *get(int i)
+        {
+            if (i < 0 || i >= $self->num_values)
+                return Py_None;
+
+            return PyString_FromStringAndSize(
+                        (const char *)$self->values[i].data, 
+                        $self->values[i].length);
+        }
+
         ~ldb_msg_element() { talloc_free($self); }
         int compare(ldb_msg_element *);
     }
     %pythoncode {
+        def __getitem__(self, i):
+            ret = self.get(i)
+            if ret is None:
+                raise KeyError("no such value")
+            return ret
+
         def __eq__(self, other):
-            if (isinstance(other, str) and 
-                len(set(self)) == 1 and 
-                set(self).pop() == other):
+            if (len(self) == 1 and self.get(0) == other):
                 return True
-            return self.__cmp__(other) == 0
-                
+            if isinstance(other, self.__class__):
+                return self.__cmp__(other) == 0
+            o = iter(other)
+            for i in range(len(self)):
+                if self.get(i) != o.next():
+                    return False
+            return True
     }
 } ldb_msg_element;
 
@@ -447,6 +493,14 @@ PyObject *PyExc_LdbError;
     $result = Py_None;
 };
 
+%typemap(out,noblock=1) struct ldb_control ** {
+    if ($1 == NULL) {
+        PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(s)", ldb_errstring(arg1)));
+        SWIG_fail;
+    }
+    $result = SWIG_NewPointerObj($1, $1_descriptor, 0);
+}
+
 %rename(Ldb) ldb_context;
 
 %typemap(in,noblock=1) struct ldb_dn * {
@@ -468,13 +522,53 @@ typedef struct ldb_context {
             const char *options[] = NULL);
 
         ~ldb() { talloc_free($self); }
-        ldb_error search(ldb_dn *base = NULL, 
+        ldb_error search_ex(TALLOC_CTX *mem_ctx,
+                   ldb_dn *base = NULL, 
                    enum ldb_scope scope = LDB_SCOPE_DEFAULT, 
                    const char *expression = NULL, 
-                   const char * const *attrs = NULL, 
-                   struct ldb_result **OUT);
+                   const char *const *attrs = NULL, 
+                   struct ldb_control **controls = NULL,
+                   struct ldb_result **OUT) {
+            int ret;
+            struct ldb_result *res;
+            struct ldb_request *req;
+            res = talloc_zero(mem_ctx, struct ldb_result);
+            if (!res) {
+                return LDB_ERR_OPERATIONS_ERROR;
+            }
+
+            ret = ldb_build_search_req(&req, $self, mem_ctx,
+                           base?base:ldb_get_default_basedn($self),
+                           scope,
+                           expression,
+                           attrs,
+                           controls,
+                           res,
+                           ldb_search_default_callback);
+
+            if (ret != LDB_SUCCESS) {
+                talloc_free(res);
+                return ret;
+            }
+
+            ldb_set_timeout($self, req, 0); /* use default timeout */
+                
+            ret = ldb_request($self, req);
+                
+            if (ret == LDB_SUCCESS) {
+                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+            }
+
+            talloc_free(req);
+
+            *OUT = res;
+            return ret;
+        }
+
         ldb_error delete(ldb_dn *dn);
         ldb_error rename(ldb_dn *olddn, ldb_dn *newdn);
+        struct ldb_control **parse_control_strings(TALLOC_CTX *mem_ctx, 
+                                                   const char * const*control_strings);
         ldb_error add(ldb_msg *add_msg);
         ldb_error add(PyObject *py_msg) 
         {
@@ -567,6 +661,14 @@ typedef struct ldb_context {
             _ldb.Ldb_swiginit(self,_ldb.new_Ldb())
             if url is not None:
                 self.connect(url, flags, options)
+
+        def search(self, base=None, scope=SCOPE_DEFAULT, expression=None, 
+                   attrs=None, controls=None):
+            parsed_controls = None
+            if controls is not None:
+                parsed_controls = self.parse_control_strings(controls)
+            return self.search_ex(base, scope, expression, attrs, 
+                                  parsed_controls)
     }
 
 } ldb;
index ebf8f6025a0002b84e010ec26376c2cb36bf90f9..ab2a68a4b31c986cf520188ab6d6edc7e256c3ae 100644 (file)
@@ -71,6 +71,13 @@ class Dn(object):
     def __init__(self, *args, **kwargs): 
         _ldb.Dn_swiginit(self,_ldb.new_Dn(*args, **kwargs))
     __swig_destroy__ = _ldb.delete_Dn
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.__cmp__(other) == 0
+        if isinstance(other, str):
+            return str(self) == other
+        return False
+
 Dn.validate = new_instancemethod(_ldb.Dn_validate,None,Dn)
 Dn.get_casefold = new_instancemethod(_ldb.Dn_get_casefold,None,Dn)
 Dn.__str__ = new_instancemethod(_ldb.Dn___str__,None,Dn)
@@ -94,16 +101,27 @@ class ldb_msg_element(object):
     def __init__(self): raise AttributeError, "No constructor defined"
     __repr__ = _swig_repr
     __swig_destroy__ = _ldb.delete_ldb_msg_element
+    def __getitem__(self, i):
+        ret = self.get(i)
+        if ret is None:
+            raise KeyError("no such value")
+        return ret
+
     def __eq__(self, other):
-        if (isinstance(other, str) and 
-            len(set(self)) == 1 and 
-            set(self).pop() == other):
+        if (len(self) == 1 and self.get(0) == other):
             return True
-        return self.__cmp__(other) == 0
-            
+        if isinstance(other, self.__class__):
+            return self.__cmp__(other) == 0
+        o = iter(other)
+        for i in range(len(self)):
+            if self.get(i) != o.next():
+                return False
+        return True
 
 ldb_msg_element.__iter__ = new_instancemethod(_ldb.ldb_msg_element___iter__,None,ldb_msg_element)
 ldb_msg_element.__set__ = new_instancemethod(_ldb.ldb_msg_element___set__,None,ldb_msg_element)
+ldb_msg_element.__len__ = new_instancemethod(_ldb.ldb_msg_element___len__,None,ldb_msg_element)
+ldb_msg_element.get = new_instancemethod(_ldb.ldb_msg_element_get,None,ldb_msg_element)
 ldb_msg_element.__cmp__ = new_instancemethod(_ldb.ldb_msg_element___cmp__,None,ldb_msg_element)
 ldb_msg_element_swigregister = _ldb.ldb_msg_element_swigregister
 ldb_msg_element_swigregister(ldb_msg_element)
@@ -181,10 +199,19 @@ class Ldb(object):
         if url is not None:
             self.connect(url, flags, options)
 
+    def search(self, base=None, scope=SCOPE_DEFAULT, expression=None, 
+               attrs=None, controls=None):
+        parsed_controls = None
+        if controls is not None:
+            parsed_controls = self.parse_control_strings(controls)
+        return self.search_ex(base, scope, expression, attrs, 
+                              parsed_controls)
+
 Ldb.connect = new_instancemethod(_ldb.Ldb_connect,None,Ldb)
-Ldb.search = new_instancemethod(_ldb.Ldb_search,None,Ldb)
+Ldb.search_ex = new_instancemethod(_ldb.Ldb_search_ex,None,Ldb)
 Ldb.delete = new_instancemethod(_ldb.Ldb_delete,None,Ldb)
 Ldb.rename = new_instancemethod(_ldb.Ldb_rename,None,Ldb)
+Ldb.parse_control_strings = new_instancemethod(_ldb.Ldb_parse_control_strings,None,Ldb)
 Ldb.add = new_instancemethod(_ldb.Ldb_add,None,Ldb)
 Ldb.modify = new_instancemethod(_ldb.Ldb_modify,None,Ldb)
 Ldb.get_config_basedn = new_instancemethod(_ldb.Ldb_get_config_basedn,None,Ldb)
index 39df427c2c2d3105fcdef8f09fde39c20b6503c4..9582f3613098bf6d5f02926d2841f16316480c90 100644 (file)
@@ -737,6 +737,7 @@ static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, v
 /* Generate a remote message with a mapped objectClass. */
 static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local)
 {
+       const struct ldb_map_context *data = map_get_context(module);
        struct ldb_message_element *el, *oc;
        struct ldb_val val;
        bool found_extensibleObject = false;
@@ -770,16 +771,16 @@ static void map_objectclass_generate_remote(struct ldb_module *module, const cha
        /* Convert all local objectClasses */
        for (i = 0; i < el->num_values - 1; i++) {
                el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
-               if (ldb_attr_cmp((char *)el->values[i].data, "extensibleObject") == 0) {
+               if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) {
                        found_extensibleObject = true;
                }
        }
 
        if (!found_extensibleObject) {
-               val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject");
+               val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
                val.length = strlen((char *)val.data);
 
-               /* Append additional objectClass "extensibleObject" */
+               /* Append additional objectClass data->add_objectclass */
                el->values[i] = val;
        } else {
                el->num_values--;
@@ -860,6 +861,19 @@ static struct ldb_message_element *map_objectclass_generate_local(struct ldb_mod
        return el;
 }
 
+static const struct ldb_map_attribute objectclass_convert_map = {
+       .local_name = "objectClass",
+       .type = MAP_CONVERT,
+       .u = {
+               .convert = {
+                       .remote_name = "objectClass",
+                       .convert_local = map_objectclass_convert_local,
+                       .convert_remote = map_objectclass_convert_remote,
+               },
+       },
+};
+
+
 /* Mappings for searches on objectClass= assuming a one-to-one
  * mapping.  Needed because this is a generate operator for the
  * add/modify code */
@@ -867,19 +881,7 @@ static int map_objectclass_convert_operator(struct ldb_module *module, void *mem
                                            struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) 
 {
        
-       static const struct ldb_map_attribute objectclass_map = {
-               .local_name = "objectClass",
-               .type = MAP_CONVERT,
-               .u = {
-                       .convert = {
-                                .remote_name = "objectClass",
-                                .convert_local = map_objectclass_convert_local,
-                                .convert_remote = map_objectclass_convert_remote,
-                        },
-               },
-       };
-
-       return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_map);
+       return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map);
 }
 
 /* Auxiliary request construction
@@ -1221,23 +1223,25 @@ static const struct ldb_map_attribute builtin_attribute_maps[] = {
                         },
                },
        },
-       {
-               .local_name = "objectClass",
-               .type = MAP_GENERATE,
-               .convert_operator = map_objectclass_convert_operator,
-               .u = {
-                       .generate = {
-                                .remote_names = { "objectClass", NULL },
-                                .generate_local = map_objectclass_generate_local,
-                                .generate_remote = map_objectclass_generate_remote,
-                        },
-               },
-       },
        {
                .local_name = NULL,
        }
 };
 
+static const struct ldb_map_attribute objectclass_attribute_map        = {
+       .local_name = "objectClass",
+       .type = MAP_GENERATE,
+       .convert_operator = map_objectclass_convert_operator,
+       .u = {
+               .generate = {
+                       .remote_names = { "objectClass", NULL },
+                       .generate_local = map_objectclass_generate_local,
+                       .generate_remote = map_objectclass_generate_remote,
+               },
+       },
+};
+
+
 /* Find the special 'MAP_DN_NAME' record and store local and remote
  * base DNs in private data. */
 static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
@@ -1302,7 +1306,7 @@ static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data
        for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
 
        /* Store list of attribute maps */
-       data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+1);
+       data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2);
        if (data->attribute_maps == NULL) {
                map_oom(module);
                return LDB_ERR_OPERATIONS_ERROR;
@@ -1320,6 +1324,15 @@ static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data
                last++;
        }
 
+       if (data->add_objectclass) {
+               /* ObjectClass one is very last, if required */
+               data->attribute_maps[last] = objectclass_attribute_map;
+               last++;
+       } else if (ocls) {
+               data->attribute_maps[last] = objectclass_convert_map;
+               last++;
+       }
+
        /* Ensure 'local_name == NULL' for the last entry */
        memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
 
@@ -1339,9 +1352,10 @@ _PUBLIC_ struct ldb_module_ops ldb_map_get_ops(void)
 
 /* Initialize global private data. */
 _PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, 
-                const struct ldb_map_objectclass *ocls,
-                const char * const *wildcard_attributes,
-                const char *name)
+                         const struct ldb_map_objectclass *ocls,
+                         const char * const *wildcard_attributes,
+                         const char *add_objectclass,
+                         const char *name)
 {
        struct map_private *data;
        int ret;
@@ -1368,6 +1382,8 @@ _PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attrib
                return ret;
        }
 
+       data->context->add_objectclass = add_objectclass;
+
        /* Store list of attribute and objectClass maps */
        ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
        if (ret != LDB_SUCCESS) {
index 7fe9c223b8a5af3d1009536282640107a3716ef5..ef4da4e6546e4e5eb71ad1b2640f87928b60b36b 100644 (file)
@@ -134,6 +134,9 @@ struct ldb_map_context {
         * to any wildcard search */
        const char * const *wildcard_attributes;
 
+       /* ObjectClass (if any) to be added to remote attributes on add */
+       const char *add_objectclass;
+
        /* struct ldb_context *mapped_ldb; */
        struct ldb_dn *local_base_dn;
        struct ldb_dn *remote_base_dn;
@@ -149,6 +152,7 @@ struct map_private {
 int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, 
                 const struct ldb_map_objectclass *ocls,
                 const char * const *wildcard_attributes,
+                const char *add_objectclass,
                 const char *name);
 
 /* get copy of map_ops */
index 7368d7f0587a294aa34f5fa1c3abb68fb6e96a82..c833246ead01514310c24ec976dba098ac1f971e 100644 (file)
@@ -2459,29 +2459,31 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)
 
 /* -------- TYPES TABLE (BEGIN) -------- */
 
-#define SWIGTYPE_p_char swig_types[0]
-#define SWIGTYPE_p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void swig_types[1]
-#define SWIGTYPE_p_int swig_types[2]
-#define SWIGTYPE_p_ldb_context swig_types[3]
-#define SWIGTYPE_p_ldb_dn swig_types[4]
-#define SWIGTYPE_p_ldb_ldif swig_types[5]
-#define SWIGTYPE_p_ldb_message swig_types[6]
-#define SWIGTYPE_p_ldb_message_element swig_types[7]
-#define SWIGTYPE_p_ldb_module_ops swig_types[8]
-#define SWIGTYPE_p_ldb_result swig_types[9]
-#define SWIGTYPE_p_long_long swig_types[10]
-#define SWIGTYPE_p_p_char swig_types[11]
-#define SWIGTYPE_p_p_ldb_result swig_types[12]
-#define SWIGTYPE_p_short swig_types[13]
-#define SWIGTYPE_p_signed_char swig_types[14]
-#define SWIGTYPE_p_unsigned_char swig_types[15]
-#define SWIGTYPE_p_unsigned_int swig_types[16]
-#define SWIGTYPE_p_unsigned_long swig_types[17]
-#define SWIGTYPE_p_unsigned_long_long swig_types[18]
-#define SWIGTYPE_p_unsigned_short swig_types[19]
-#define SWIGTYPE_p_void swig_types[20]
-static swig_type_info *swig_types[22];
-static swig_module_info swig_module = {swig_types, 21, 0, 0, 0, 0};
+#define SWIGTYPE_p_TALLOC_CTX swig_types[0]
+#define SWIGTYPE_p_char swig_types[1]
+#define SWIGTYPE_p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void swig_types[2]
+#define SWIGTYPE_p_int swig_types[3]
+#define SWIGTYPE_p_ldb_context swig_types[4]
+#define SWIGTYPE_p_ldb_dn swig_types[5]
+#define SWIGTYPE_p_ldb_ldif swig_types[6]
+#define SWIGTYPE_p_ldb_message swig_types[7]
+#define SWIGTYPE_p_ldb_message_element swig_types[8]
+#define SWIGTYPE_p_ldb_module_ops swig_types[9]
+#define SWIGTYPE_p_ldb_result swig_types[10]
+#define SWIGTYPE_p_long_long swig_types[11]
+#define SWIGTYPE_p_p_char swig_types[12]
+#define SWIGTYPE_p_p_ldb_control swig_types[13]
+#define SWIGTYPE_p_p_ldb_result swig_types[14]
+#define SWIGTYPE_p_short swig_types[15]
+#define SWIGTYPE_p_signed_char swig_types[16]
+#define SWIGTYPE_p_unsigned_char swig_types[17]
+#define SWIGTYPE_p_unsigned_int swig_types[18]
+#define SWIGTYPE_p_unsigned_long swig_types[19]
+#define SWIGTYPE_p_unsigned_long_long swig_types[20]
+#define SWIGTYPE_p_unsigned_short swig_types[21]
+#define SWIGTYPE_p_void swig_types[22]
+static swig_type_info *swig_types[24];
+static swig_module_info swig_module = {swig_types, 23, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -2889,6 +2891,17 @@ SWIG_AsVal_int (PyObject * obj, int *val)
 SWIGINTERN ldb_msg_element *new_ldb_msg_element(PyObject *set_obj,int flags,char const *name){
             return ldb_msg_element_from_pyobject(NULL, set_obj, flags, name);
         }
+SWIGINTERN int ldb_msg_element___len__(ldb_msg_element *self){
+            return self->num_values;
+        }
+SWIGINTERN PyObject *ldb_msg_element_get(ldb_msg_element *self,int i){
+            if (i < 0 || i >= self->num_values)
+                return Py_None;
+
+            return PyString_FromStringAndSize(
+                        (const char *)self->values[i].data, 
+                        self->values[i].length);
+        }
 SWIGINTERN void delete_ldb_msg_element(ldb_msg_element *self){ talloc_free(self); }
 
     PyObject *ldb_msg_list_elements(ldb_msg *msg)
@@ -3034,6 +3047,42 @@ SWIG_AsVal_unsigned_SS_int (PyObject * obj, unsigned int *val)
 }
 
 SWIGINTERN void delete_ldb(ldb *self){ talloc_free(self); }
+SWIGINTERN ldb_error ldb_search_ex(ldb *self,TALLOC_CTX *mem_ctx,ldb_dn *base,enum ldb_scope scope,char const *expression,char const *const *attrs,struct ldb_control **controls,struct ldb_result **OUT){
+            int ret;
+            struct ldb_result *res;
+            struct ldb_request *req;
+            res = talloc_zero(mem_ctx, struct ldb_result);
+            if (!res) {
+                return 1;
+            }
+
+            ret = ldb_build_search_req(&req, self, mem_ctx,
+                           base?base:ldb_get_default_basedn(self),
+                           scope,
+                           expression,
+                           attrs,
+                           controls,
+                           res,
+                           ldb_search_default_callback);
+
+            if (ret != 0) {
+                talloc_free(res);
+                return ret;
+            }
+
+            ldb_set_timeout(self, req, 0); /* use default timeout */
+                
+            ret = ldb_request(self, req);
+                
+            if (ret == 0) {
+                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+            }
+
+            talloc_free(req);
+
+            *OUT = res;
+            return ret;
+        }
 SWIGINTERN ldb_error ldb_add__SWIG_1(ldb *self,PyObject *py_msg){
             ldb_error ret;
             int dict_pos, msg_pos;
@@ -3671,6 +3720,63 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_ldb_msg_element___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ldb_msg_element *arg1 = (ldb_msg_element *) 0 ;
+  int result;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message_element, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_msg_element___len__" "', argument " "1"" of type '" "ldb_msg_element *""'"); 
+  }
+  arg1 = (ldb_msg_element *)(argp1);
+  result = (int)ldb_msg_element___len__(arg1);
+  resultobj = SWIG_From_int((int)(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_ldb_msg_element_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  ldb_msg_element *arg1 = (ldb_msg_element *) 0 ;
+  int arg2 ;
+  PyObject *result = 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "i", NULL 
+  };
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:ldb_msg_element_get",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message_element, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_msg_element_get" "', argument " "1"" of type '" "ldb_msg_element *""'"); 
+  }
+  arg1 = (ldb_msg_element *)(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ldb_msg_element_get" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = (int)(val2);
+  result = (PyObject *)ldb_msg_element_get(arg1,arg2);
+  resultobj = result;
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_delete_ldb_msg_element(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_msg_element *arg1 = (ldb_msg_element *) 0 ;
@@ -4284,95 +4390,108 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Ldb_search(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Ldb_search_ex(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
-  ldb_dn *arg2 = (ldb_dn *) NULL ;
-  enum ldb_scope arg3 = (enum ldb_scope) LDB_SCOPE_DEFAULT ;
-  char *arg4 = (char *) NULL ;
-  char **arg5 = (char **) NULL ;
-  struct ldb_result **arg6 = (struct ldb_result **) 0 ;
+  TALLOC_CTX *arg2 = (TALLOC_CTX *) 0 ;
+  ldb_dn *arg3 = (ldb_dn *) NULL ;
+  enum ldb_scope arg4 = (enum ldb_scope) LDB_SCOPE_DEFAULT ;
+  char *arg5 = (char *) NULL ;
+  char **arg6 = (char **) NULL ;
+  struct ldb_control **arg7 = (struct ldb_control **) NULL ;
+  struct ldb_result **arg8 = (struct ldb_result **) 0 ;
   ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
-  int res4 ;
-  char *buf4 = 0 ;
-  int alloc4 = 0 ;
-  struct ldb_result *temp_ldb_result6 ;
-  int i6 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int res5 ;
+  char *buf5 = 0 ;
+  int alloc5 = 0 ;
+  void *argp7 = 0 ;
+  int res7 = 0 ;
+  struct ldb_result *temp_ldb_result8 ;
+  int i8 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
   PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "base",(char *) "scope",(char *) "expression",(char *) "attrs", NULL 
+    (char *) "self",(char *) "base",(char *) "scope",(char *) "expression",(char *) "attrs",(char *) "controls", NULL 
   };
   
-  arg6 = &temp_ldb_result6;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:Ldb_search",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
+  arg2 = NULL;
+  arg8 = &temp_ldb_result8;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOOO:Ldb_search_ex",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_search" "', argument " "1"" of type '" "ldb *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_search_ex" "', argument " "1"" of type '" "ldb *""'"); 
   }
   arg1 = (ldb *)(argp1);
   if (obj1) {
-    if (ldb_dn_from_pyobject(NULL, obj1, arg1, &arg2) != 0) {
+    if (ldb_dn_from_pyobject(NULL, obj1, arg1, &arg3) != 0) {
       SWIG_fail;
     }
   }
   if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Ldb_search" "', argument " "3"" of type '" "enum ldb_scope""'");
+    ecode4 = SWIG_AsVal_int(obj2, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Ldb_search_ex" "', argument " "4"" of type '" "enum ldb_scope""'");
     } 
-    arg3 = (enum ldb_scope)(val3);
+    arg4 = (enum ldb_scope)(val4);
   }
   if (obj3) {
-    res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
-    if (!SWIG_IsOK(res4)) {
-      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Ldb_search" "', argument " "4"" of type '" "char const *""'");
+    res5 = SWIG_AsCharPtrAndSize(obj3, &buf5, NULL, &alloc5);
+    if (!SWIG_IsOK(res5)) {
+      SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "Ldb_search_ex" "', argument " "5"" of type '" "char const *""'");
     }
-    arg4 = (char *)(buf4);
+    arg5 = (char *)(buf5);
   }
   if (obj4) {
     if (obj4 == Py_None) {
-      arg5 = NULL;
+      arg6 = NULL;
     } else if (PySequence_Check(obj4)) {
       int i;
-      arg5 = talloc_array(NULL, char *, PySequence_Size(obj4)+1);
+      arg6 = talloc_array(NULL, char *, PySequence_Size(obj4)+1);
       for(i = 0; i < PySequence_Size(obj4); i++)
-      arg5[i] = PyString_AsString(PySequence_GetItem(obj4, i));
-      arg5[i] = NULL;
+      arg6[i] = PyString_AsString(PySequence_GetItem(obj4, i));
+      arg6[i] = NULL;
     } else {
       SWIG_exception(SWIG_TypeError, "expected sequence");
     }
   }
+  if (obj5) {
+    res7 = SWIG_ConvertPtr(obj5, &argp7,SWIGTYPE_p_p_ldb_control, 0 |  0 );
+    if (!SWIG_IsOK(res7)) {
+      SWIG_exception_fail(SWIG_ArgError(res7), "in method '" "Ldb_search_ex" "', argument " "7"" of type '" "struct ldb_control **""'"); 
+    }
+    arg7 = (struct ldb_control **)(argp7);
+  }
   if (arg1 == NULL)
   SWIG_exception(SWIG_ValueError, 
     "ldb context must be non-NULL");
-  result = ldb_search(arg1,arg2,arg3,(char const *)arg4,(char const *const *)arg5,arg6);
+  result = ldb_search_ex(arg1,arg2,arg3,arg4,(char const *)arg5,(char const *const *)arg6,arg7,arg8);
   if (result != 0) {
     PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_strerror(result)));
     SWIG_fail;
   }
   resultobj = Py_None;
-  resultobj = PyList_New((*arg6)->count);
-  for (i6 = 0; i6 < (*arg6)->count; i6++) {
-    PyList_SetItem(resultobj, i6
-      SWIG_NewPointerObj((*arg6)->msgs[i6], SWIGTYPE_p_ldb_message, 0)
+  resultobj = PyList_New((*arg8)->count);
+  for (i8 = 0; i8 < (*arg8)->count; i8++) {
+    PyList_SetItem(resultobj, i8
+      SWIG_NewPointerObj((*arg8)->msgs[i8], SWIGTYPE_p_ldb_message, 0)
       );
   }
-  talloc_free(arg2);
-  if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
-  talloc_free(arg5);
+  talloc_free(arg3);
+  if (alloc5 == SWIG_NEWOBJ) free((char*)buf5);
+  talloc_free(arg6);
   return resultobj;
 fail:
-  talloc_free(arg2);
-  if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
-  talloc_free(arg5);
+  talloc_free(arg3);
+  if (alloc5 == SWIG_NEWOBJ) free((char*)buf5);
+  talloc_free(arg6);
   return NULL;
 }
 
@@ -4462,6 +4581,55 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Ldb_parse_control_strings(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  ldb *arg1 = (ldb *) 0 ;
+  TALLOC_CTX *arg2 = (TALLOC_CTX *) 0 ;
+  char **arg3 = (char **) 0 ;
+  struct ldb_control **result = 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "control_strings", NULL 
+  };
+  
+  arg2 = NULL;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_parse_control_strings",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_parse_control_strings" "', argument " "1"" of type '" "ldb *""'"); 
+  }
+  arg1 = (ldb *)(argp1);
+  if (obj1 == Py_None) {
+    arg3 = NULL;
+  } else if (PySequence_Check(obj1)) {
+    int i;
+    arg3 = talloc_array(NULL, char *, PySequence_Size(obj1)+1);
+    for(i = 0; i < PySequence_Size(obj1); i++)
+    arg3[i] = PyString_AsString(PySequence_GetItem(obj1, i));
+    arg3[i] = NULL;
+  } else {
+    SWIG_exception(SWIG_TypeError, "expected sequence");
+  }
+  if (arg1 == NULL)
+  SWIG_exception(SWIG_ValueError, 
+    "ldb context must be non-NULL");
+  result = (struct ldb_control **)ldb_parse_control_strings(arg1,arg2,(char const *const *)arg3);
+  if (result == NULL) {
+    PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(s)", ldb_errstring(arg1)));
+    SWIG_fail;
+  }
+  resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_p_ldb_control, 0);
+  talloc_free(arg3);
+  return resultobj;
+fail:
+  talloc_free(arg3);
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_Ldb_add__SWIG_0(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
@@ -5254,6 +5422,8 @@ static PyMethodDef SwigMethods[] = {
         { (char *)"ldb_msg_element___iter__", (PyCFunction)_wrap_ldb_msg_element___iter__, METH_O, NULL},
         { (char *)"ldb_msg_element___set__", (PyCFunction)_wrap_ldb_msg_element___set__, METH_O, NULL},
         { (char *)"new_MessageElement", (PyCFunction) _wrap_new_MessageElement, METH_VARARGS | METH_KEYWORDS, NULL},
+        { (char *)"ldb_msg_element___len__", (PyCFunction)_wrap_ldb_msg_element___len__, METH_O, NULL},
+        { (char *)"ldb_msg_element_get", (PyCFunction) _wrap_ldb_msg_element_get, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"delete_ldb_msg_element", (PyCFunction)_wrap_delete_ldb_msg_element, METH_O, NULL},
         { (char *)"ldb_msg_element___cmp__", (PyCFunction) _wrap_ldb_msg_element___cmp__, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"ldb_msg_element_swigregister", ldb_msg_element_swigregister, METH_VARARGS, NULL},
@@ -5274,9 +5444,10 @@ static PyMethodDef SwigMethods[] = {
         { (char *)"new_Ldb", (PyCFunction)_wrap_new_Ldb, METH_NOARGS, NULL},
         { (char *)"Ldb_connect", (PyCFunction) _wrap_Ldb_connect, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"delete_Ldb", (PyCFunction)_wrap_delete_Ldb, METH_O, NULL},
-        { (char *)"Ldb_search", (PyCFunction) _wrap_Ldb_search, METH_VARARGS | METH_KEYWORDS, NULL},
+        { (char *)"Ldb_search_ex", (PyCFunction) _wrap_Ldb_search_ex, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"Ldb_delete", (PyCFunction) _wrap_Ldb_delete, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"Ldb_rename", (PyCFunction) _wrap_Ldb_rename, METH_VARARGS | METH_KEYWORDS, NULL},
+        { (char *)"Ldb_parse_control_strings", (PyCFunction) _wrap_Ldb_parse_control_strings, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"Ldb_add", _wrap_Ldb_add, METH_VARARGS, NULL},
         { (char *)"Ldb_modify", (PyCFunction) _wrap_Ldb_modify, METH_VARARGS | METH_KEYWORDS, NULL},
         { (char *)"Ldb_get_config_basedn", (PyCFunction)_wrap_Ldb_get_config_basedn, METH_O, NULL},
@@ -5306,6 +5477,7 @@ static PyMethodDef SwigMethods[] = {
 
 /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
 
+static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void = {"_p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void", "void (*)(void *,enum ldb_debug_level,char const *,va_list)", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0};
@@ -5318,6 +5490,7 @@ static swig_type_info _swigt__p_ldb_module_ops = {"_p_ldb_module_ops", "struct l
 static swig_type_info _swigt__p_ldb_result = {"_p_ldb_result", "struct ldb_result *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_p_ldb_control = {"_p_p_ldb_control", "struct ldb_control **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_ldb_result = {"_p_p_ldb_result", "struct ldb_result **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0};
@@ -5329,6 +5502,7 @@ static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned
 static swig_type_info _swigt__p_void = {"_p_void", "void *", 0, 0, (void*)0, 0};
 
 static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_TALLOC_CTX,
   &_swigt__p_char,
   &_swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void,
   &_swigt__p_int,
@@ -5341,6 +5515,7 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_ldb_result,
   &_swigt__p_long_long,
   &_swigt__p_p_char,
+  &_swigt__p_p_ldb_control,
   &_swigt__p_p_ldb_result,
   &_swigt__p_short,
   &_swigt__p_signed_char,
@@ -5352,6 +5527,7 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_void,
 };
 
+static swig_cast_info _swigc__p_TALLOC_CTX[] = {  {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void[] = {  {&_swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
@@ -5364,6 +5540,7 @@ static swig_cast_info _swigc__p_ldb_module_ops[] = {  {&_swigt__p_ldb_module_ops
 static swig_cast_info _swigc__p_ldb_result[] = {  {&_swigt__p_ldb_result, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_long_long[] = {  {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_ldb_control[] = {  {&_swigt__p_p_ldb_control, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_ldb_result[] = {  {&_swigt__p_p_ldb_result, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_short[] = {  {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_signed_char[] = {  {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}};
@@ -5375,6 +5552,7 @@ static swig_cast_info _swigc__p_unsigned_short[] = {  {&_swigt__p_unsigned_short
 static swig_cast_info _swigc__p_void[] = {  {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}};
 
 static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_TALLOC_CTX,
   _swigc__p_char,
   _swigc__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void,
   _swigc__p_int,
@@ -5387,6 +5565,7 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_ldb_result,
   _swigc__p_long_long,
   _swigc__p_p_char,
+  _swigc__p_p_ldb_control,
   _swigc__p_p_ldb_result,
   _swigc__p_short,
   _swigc__p_signed_char,
index f81c2e3e16a7ff53839a589841158c0b6699004d..bbd4c1c5ebdc772baad3e28bc783d5645b8d58c8 100644 (file)
@@ -1,7 +1,4 @@
-#######################
-# Start LIBRARY swig_ldb
 [PYTHON::swig_ldb]
 PUBLIC_DEPENDENCIES = LIBLDB
+CFLAGS = -Ilib/ldb/include
 SWIG_FILE = ldb.i
-# End LIBRARY swig_ldb
-#######################
index d9dfce87187fceff5ede1f5428147abb18f3d9f4..d5346c30b09a244fcd1c892caa58298557b49f79 100755 (executable)
@@ -48,6 +48,10 @@ class SimpleLdb(unittest.TestCase):
         l = ldb.Ldb("foo.tdb")
         self.assertEquals(len(l.search()), 1)
 
+    def test_search_controls(self):
+        l = ldb.Ldb("foo.tdb")
+        self.assertEquals(len(l.search(controls=["paged_results:1:5"])), 1)
+
     def test_search_attrs(self):
         l = ldb.Ldb("foo.tdb")
         self.assertEquals(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
@@ -62,6 +66,11 @@ class SimpleLdb(unittest.TestCase):
         self.assertTrue(l.get_opaque("my_opaque") is not None)
         self.assertEquals(None, l.get_opaque("unknown"))
 
+    def test_parse_control_strings(self):
+        l = ldb.Ldb("foo.tdb")
+        self.assertRaises(ldb.LdbError, l.parse_control_strings, ["foo", "bar"])
+        self.assertTrue(l.parse_control_strings(["paged_results:1:5"]) is not None)
+
     def test_search_scope_base(self):
         l = ldb.Ldb("foo.tdb")
         self.assertEquals(len(l.search(ldb.Dn(l, "dc=foo"), 
@@ -162,54 +171,54 @@ class SimpleLdb(unittest.TestCase):
     def test_modify_delete(self):
         l = ldb.Ldb("foo.tdb")
         m = ldb.Message()
-        m.dn = ldb.Dn(l, "dc=modify")
+        m.dn = ldb.Dn(l, "dc=modifydelete")
         m["bla"] = ["1234"]
         l.add(m)
         rm = l.search(m.dn)[0]
         self.assertEquals(["1234"], list(rm["bla"]))
         try:
             m = ldb.Message()
-            m.dn = ldb.Dn(l, "dc=modify")
+            m.dn = ldb.Dn(l, "dc=modifydelete")
             m["bla"] = ldb.MessageElement([], ldb.CHANGETYPE_DELETE, "bla")
             l.modify(m)
             rm = l.search(m.dn)[0]
             self.assertEquals(1, len(rm))
         finally:
-            l.delete(ldb.Dn(l, "dc=modify"))
+            l.delete(ldb.Dn(l, "dc=modifydelete"))
 
     def test_modify_add(self):
         l = ldb.Ldb("foo.tdb")
         m = ldb.Message()
-        m.dn = ldb.Dn(l, "dc=modify")
+        m.dn = ldb.Dn(l, "dc=add")
         m["bla"] = ["1234"]
         l.add(m)
         try:
             m = ldb.Message()
-            m.dn = ldb.Dn(l, "dc=modify")
+            m.dn = ldb.Dn(l, "dc=add")
             m["bla"] = ldb.MessageElement(["456"], ldb.CHANGETYPE_ADD, "bla")
             l.modify(m)
             rm = l.search(m.dn)[0]
             self.assertEquals(2, len(rm))
             self.assertEquals(["1234", "456"], list(rm["bla"]))
         finally:
-            l.delete(ldb.Dn(l, "dc=modify"))
+            l.delete(ldb.Dn(l, "dc=add"))
 
     def test_modify_modify(self):
         l = ldb.Ldb("foo.tdb")
         m = ldb.Message()
-        m.dn = ldb.Dn(l, "dc=modify")
+        m.dn = ldb.Dn(l, "dc=modify2")
         m["bla"] = ["1234", "456"]
         l.add(m)
         try:
             m = ldb.Message()
-            m.dn = ldb.Dn(l, "dc=modify")
+            m.dn = ldb.Dn(l, "dc=modify2")
             m["bla"] = ldb.MessageElement(["456"], ldb.CHANGETYPE_MODIFY, "bla")
             l.modify(m)
             rm = l.search(m.dn)[0]
             self.assertEquals(2, len(rm))
             self.assertEquals(["1234"], list(rm["bla"]))
         finally:
-            l.delete(ldb.Dn(l, "dc=modify"))
+            l.delete(ldb.Dn(l, "dc=modify2"))
 
     def test_transaction_commit(self):
         l = ldb.Ldb("foo.tdb")
@@ -240,6 +249,10 @@ class DnTests(unittest.TestCase):
     def setUp(self):
         self.ldb = ldb.Ldb("foo.tdb")
 
+    def test_eq_str(self):
+        x = ldb.Dn(self.ldb, "dc=foo,bar=bloe")
+        self.assertEquals("dc=foo,bar=bloe", x)
+
     def test_str(self):
         x = ldb.Dn(self.ldb, "dc=foo,bar=bloe")
         self.assertEquals(x.__str__(), "dc=foo,bar=bloe")
@@ -382,6 +395,22 @@ class MessageElementTests(unittest.TestCase):
         x = ldb.MessageElement(["foo"])
         self.assertEquals(["foo"], list(x))
 
+    def test_get_item(self):
+        x = ldb.MessageElement(["foo", "bar"])
+        self.assertEquals("foo", x[0])
+        self.assertEquals("bar", x[1])
+        self.assertRaises(KeyError, lambda: x[-1])
+
+    def test_len(self):
+        x = ldb.MessageElement(["foo", "bar"])
+        self.assertEquals(2, len(x))
+
+    def test_eq(self):
+        x = ldb.MessageElement(["foo", "bar"])
+        self.assertEquals(["foo", "bar"], x)
+        x = ldb.MessageElement(["foo"])
+        self.assertEquals("foo", x)
+
 class ExampleModule:
     name = "example"
 
index 3f70ef9b43ca9b511bf73a1c020c3d0f47142837..01b66a389041f5eabe59a14cdaef45042650e179 100755 (executable)
@@ -11,6 +11,10 @@ sys.path.append("scripting/python")
 import samba.getopt as options
 
 from auth import system_session
+from ldb import (SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError,
+                 LDB_ERR_NO_SUCH_OBJECT, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
+                 LDB_ERR_ENTRY_ALREADY_EXISTS, LDB_ERR_UNWILLING_TO_PERFORM,
+                 LDB_ERR_NOT_ALLOWED_ON_NON_LEAF)
 from samba import Ldb
 import param
 
@@ -33,14 +37,21 @@ lp = param.LoadParm()
 if opts.configfile:
     lp.load(opts.configfile)
 
+def delete_force(ldb, dn):
+    try:
+        ldb.delete(dn)
+    except LdbError, (num, _): 
+        if num != LDB_ERR_NO_SUCH_OBJECT:
+            assert False
+
 def assertEquals(a1, a2):
-    assert a1 == a2
+    assert a1 == a2, "Expected %r == %r" % (a1, a2)
 
 def basic_tests(ldb, gc_ldb, base_dn, configuration_dn, schema_dn):
     print "Running basic tests"
 
-    ldb.delete("cn=ldaptestuser,cn=users," + base_dn)
-    ldb.delete("cn=ldaptestgroup,cn=users," + base_dn)
+    delete_force(ldb, "cn=ldaptestuser,cn=users," + base_dn)
+    delete_force(ldb, "cn=ldaptestgroup,cn=users," + base_dn)
 
     print "Testing group add with invalid member"
     try:
@@ -48,8 +59,9 @@ def basic_tests(ldb, gc_ldb, base_dn, configuration_dn, schema_dn):
         "dn": "cn=ldaptestgroup,cn=uSers," + base_dn,
         "objectclass": "group",
         "member": "cn=ldaptestuser,cn=useRs," + base_dn})
-    except LdbError, (num, _):
-        assert error == 32 # LDAP_NO_SUCH_OBJECT
+    except LdbError, (num, _): 
+        if num != LDB_ERR_NO_SUCH_OBJECT:
+            assert False
     else:
         assert False
 
@@ -113,8 +125,7 @@ servicePrincipalName: host/ldaptest2computer
 servicePrincipalName: cifs/ldaptest2computer
 """)
     except LdbError, (num, msg):
-        #LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
-        assert num == 20, "Expected error LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS, got : %s" % msg
+        assert num == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
 
         ldb.modify_ldif("""
 dn: cn=ldaptest2computer,cn=computers,""" + base_dn + """
@@ -131,7 +142,7 @@ add: servicePrincipalName
 servicePrincipalName: host/ldaptest2computer
 """)
         except LdbError, (num, msg):
-            assert num == 20, "Expected error LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS, got :" + msg
+            assert num == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
         
         print "Testing ranged results"
         ldb.modify_ldif("""
@@ -176,59 +187,53 @@ servicePrincipalName: host/ldaptest2computer28
 servicePrincipalName: host/ldaptest2computer29
 """)
 
-        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=ldb.SCOPE_SUBTREE, 
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, 
                          attrs=["servicePrincipalName;range=0-*"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-#        print res[0]["servicePrincipalName;range=0-*"].length
-        assertEquals(res[0]["servicePrincipalName;range=0-*"].length, 30)
+        #print len(res[0]["servicePrincipalName;range=0-*"])
+        assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
 
-        attrs = ["servicePrincipalName;range=0-19"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
 #        print res[0]["servicePrincipalName;range=0-19"].length
-        assertEquals(res[0]["servicePrincipalName;range=0-19"].length, 20)
+        assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
 
-        attrs = ["servicePrincipalName;range=0-30"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-        assertEquals(res[0]["servicePrincipalName;range=0-*"].length, 30)
+        assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
 
-        attrs = ["servicePrincipalName;range=0-40"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-        assertEquals(res[0]["servicePrincipalName;range=0-*"].length, 30)
+        assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
 
-        attrs = ["servicePrincipalName;range=30-40"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-        assertEquals(res[0]["servicePrincipalName;range=30-*"].length, 0)
+        assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
 
-        attrs = ["servicePrincipalName;range=10-40"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-        assertEquals(res[0]["servicePrincipalName;range=10-*"].length, 20)
+        assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
 #        pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
 
-        attrs = ["servicePrincipalName;range=11-40"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-        assertEquals(res[0]["servicePrincipalName;range=11-*"].length, 19)
+        assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
 #        print res[0]["servicePrincipalName;range=11-*"][18]
 #        print pos_11
 #        assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11)
 
-        attrs = ["servicePrincipalName;range=11-15"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
-        assertEquals(res[0]["servicePrincipalName;range=11-15"].length, 5)
+        assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
 #        assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11)
 
-        attrs = ["servicePrincipalName"]
-        res = ldb.search("(cn=ldaptest2computer))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+        res = ldb.search(base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
         assert len(res) == 1, "Could not find (cn=ldaptest2computer)"
 #        print res[0]["servicePrincipalName"][18]
 #        print pos_11
-        assertEquals(res[0]["servicePrincipalName"].length, 30)
+        assertEquals(len(res[0]["servicePrincipalName"]), 30)
 #        assertEquals(res[0]["servicePrincipalName"][18], pos_11)
 
     try:
@@ -249,79 +254,79 @@ servicePrincipalName: host/ldaptest2computer29
 
     print "Testing Ambigious Name Resolution"
 #   Testing ldb.search for (&(anr=ldap testy)(objectClass=user))
-    res = ldb.search("(&(anr=ldap testy)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))")
     assert len(res) == 3, "Could not find (&(anr=ldap testy)(objectClass=user))"
 
 #   Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
-    res = ldb.search("(&(anr=testy ldap)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
     assert len(res) == 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res)
 
 #   Testing ldb.search for (&(anr=ldap)(objectClass=user))
-    res = ldb.search("(&(anr=ldap)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=ldap)(objectClass=user))")
     assert len(res) == 4, "Found only %d for (&(anr=ldap)(objectClass=user))" % len(res)
 
 #   Testing ldb.search for (&(anr==ldap)(objectClass=user))
-    res = ldb.search("(&(anr==ldap)(objectClass=user))")
+    res = ldb.search(expression="(&(anr==ldap)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(anr==ldap)(objectClass=user)). Found only %d for (&(anr=ldap)(objectClass=user))" % len(res)
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser")
-    assertEquals(res[0].name, "ldaptestuser")
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"][0], "ldaptestuser")
+    assertEquals(res[0]["name"], "ldaptestuser")
 
 #   Testing ldb.search for (&(anr=testy)(objectClass=user))
-    res = ldb.search("(&(anr=testy)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=testy)(objectClass=user))")
     assert len(res) == 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res)
 
 #   Testing ldb.search for (&(anr=ldap testy)(objectClass=user))
-    res = ldb.search("(&(anr=testy ldap)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
     assert len(res) == 2, "Found only %d for (&(anr=ldap testy)(objectClass=user))" % len(res)
 
 #   Testing ldb.search for (&(anr==ldap testy)(objectClass=user))
-    res = ldb.search("(&(anr==testy ldap)(objectClass=user))")
+    res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
     assert len(res) == 1, "Found only %d for (&(anr==ldap testy)(objectClass=user))" % len(res)
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser")
-    assertEquals(res[0].name, "ldaptestuser")
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"][0], "ldaptestuser")
+    assertEquals(res[0]["name"][0], "ldaptestuser")
 
 # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
-    res = ldb.search("(&(anr==testy ldap)(objectClass=user))")
+    res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(anr==testy ldap)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser")
-    assertEquals(res[0].name, "ldaptestuser")
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"][0], "ldaptestuser")
+    assertEquals(res[0]["name"][0], "ldaptestuser")
 
     # Testing ldb.search for (&(anr=testy ldap user)(objectClass=user))
-    res = ldb.search("(&(anr=testy ldap user)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=testy ldap user)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(anr=testy ldap user)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser2,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser2")
-    assertEquals(res[0].name, "ldaptestuser2")
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestuser2")
+    assertEquals(res[0]["name"], "ldaptestuser2")
 
     # Testing ldb.search for (&(anr==testy ldap user2)(objectClass=user))
-    res = ldb.search("(&(anr==testy ldap user2)(objectClass=user))")
+    res = ldb.search(expression="(&(anr==testy ldap user2)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(anr==testy ldap user2)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser2,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser2")
-    assertEquals(res[0].name, "ldaptestuser2")
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestuser2")
+    assertEquals(res[0]["name"], "ldaptestuser2")
 
     # Testing ldb.search for (&(anr==ldap user2)(objectClass=user))
-    res = ldb.search("(&(anr==ldap user2)(objectClass=user))")
+    res = ldb.search(expression="(&(anr==ldap user2)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(anr==ldap user2)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser2,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser2")
-    assertEquals(res[0].name, "ldaptestuser2")
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestuser2")
+    assertEquals(res[0]["name"], "ldaptestuser2")
 
     # Testing ldb.search for (&(anr==not ldap user2)(objectClass=user))
-    res = ldb.search("(&(anr==not ldap user2)(objectClass=user))")
+    res = ldb.search(expression="(&(anr==not ldap user2)(objectClass=user))")
     assert len(res) == 0, "Must not find (&(anr==not ldap user2)(objectClass=user))"
 
     # Testing ldb.search for (&(anr=not ldap user2)(objectClass=user))
-    res = ldb.search("(&(anr=not ldap user2)(objectClass=user))")
+    res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))")
     assert len(res) == 0, "Must not find (&(anr=not ldap user2)(objectClass=user))"
 
     print "Testing Group Modifies"
@@ -333,7 +338,7 @@ member: cn=ldaptestuser2,cn=users,""" + base_dn + """
 member: cn=ldaptestcomputer,cn=computers,""" + base_dn + """
 """)
 
-    ldb.delete("cn=ldaptestuser3,cn=users," + base_dn)
+    delete_force(ldb, "cn=ldaptestuser3,cn=users," + base_dn)
 
     print "Testing adding non-existent user to a group"
     try:
@@ -344,7 +349,7 @@ add: member
 member: cn=ldaptestuser3,cn=users,""" + base_dn + """
 """)
     except LdbError, (num, _):
-        assert num == 32
+        assert num == LDB_ERR_NO_SUCH_OBJECT
     else:
         assert False
 
@@ -354,22 +359,21 @@ member: cn=ldaptestuser3,cn=users,""" + base_dn + """
 
     ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestuser3,cn=users," + base_dn)
 
-    ok = ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestUSER3,cn=users," + base_dn)
+    ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestUSER3,cn=users," + base_dn)
 
     print "Testing ldb.search for (&(cn=ldaptestuser3)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestuser3)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestuser3)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptestuser3)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestUSER3")
-    assertEquals(res[0].name, "ldaptestUSER3")
+    assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestUSER3")
+    assertEquals(res[0]["name"], "ldaptestUSER3")
 
 # This is a Samba special, and does not exist in real AD
 #    print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")"
 #    res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")")
 #    if (res.error != 0 || len(res) != 1) {
 #        print "Could not find (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")"
-#        assertEquals(res.error, 0)
 #        assertEquals(len(res), 1)
 #    }
 #    assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + base_dn))
@@ -377,11 +381,11 @@ member: cn=ldaptestuser3,cn=users,""" + base_dn + """
 #    assertEquals(res[0].name, "ldaptestUSER3")
 
     print "Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + base_dn + ")"
-    res = ldb.search("(distinguishedName=CN=ldaptestUSER3,CN=Users," + base_dn + ")")
+    res = ldb.search(expression="(distinguishedName=CN=ldaptestUSER3,CN=Users," + base_dn + ")")
     assert len(res) == 1, "Could not find (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")"
-    assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestUSER3")
-    assertEquals(res[0].name, "ldaptestUSER3")
+    assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestUSER3")
+    assertEquals(res[0]["name"], "ldaptestUSER3")
 
     # ensure we cannot add it again
     try:
@@ -389,7 +393,7 @@ member: cn=ldaptestuser3,cn=users,""" + base_dn + """
                   "objectClass": ["person", "user"],
                   "cn": "LDAPtestUSER3"})
     except LdbError, (num, _):
-        assert num == 68 #LDB_ERR_ENTRY_ALREADY_EXISTS
+        assert num == LDB_ERR_ENTRY_ALREADY_EXISTS
     else:
         assert False
 
@@ -397,12 +401,15 @@ member: cn=ldaptestuser3,cn=users,""" + base_dn + """
     ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestuser2,cn=users," + base_dn)
 
     # ensure we cannnot rename it twice
-    ok = ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestuser2,cn=users," + base_dn)
-#LDB_ERR_NO_SUCH_OBJECT
-    assertEquals(ok.error, 32)
+    try:
+        ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestuser2,cn=users," + base_dn)
+    except LdbError, (num, _): 
+        assert num == LDB_ERR_NO_SUCH_OBJECT
+    else:
+        assert False
 
     # ensure can now use that name
-    ok = ldb.add({"dn": "cn=ldaptestuser3,cn=users," + base_dn,
+    ldb.add({"dn": "cn=ldaptestuser3,cn=users," + base_dn,
                   "objectClass": ["person", "user"],
                   "cn": "LDAPtestUSER3"})
     
@@ -410,12 +417,11 @@ member: cn=ldaptestuser3,cn=users,""" + base_dn + """
     try:
         ldb.rename("cn=ldaptestuser2,cn=users," + base_dn, "cn=ldaptestuser3,cn=users," + base_dn)
     except LdbError, (num, _):
-        assert num == 68 #LDB_ERR_ENTRY_ALREADY_EXISTS
+        assert num == LDB_ERR_ENTRY_ALREADY_EXISTS
     else:
         assert False
-    assertEquals(ok.error, 68)
     try:
-        ok = ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestuser3,cn=configuration," + base_dn)
+        ldb.rename("cn=ldaptestuser3,cn=users," + base_dn, "cn=ldaptestuser3,cn=configuration," + base_dn)
     except LdbError, (num, _):
         assert num in (71, 64)
     else:
@@ -425,13 +431,14 @@ member: cn=ldaptestuser3,cn=users,""" + base_dn + """
 
     ldb.delete("cn=ldaptestuser5,cn=users," + base_dn)
 
-    ldb.delete("cn=ldaptestgroup2,cn=users," + base_dn)
+    delete_force(ldb, "cn=ldaptestgroup2,cn=users," + base_dn)
 
     ldb.rename("cn=ldaptestgroup,cn=users," + base_dn, "cn=ldaptestgroup2,cn=users," + base_dn)
 
     print "Testing subtree Renames"
 
-    ldb.add({"dn": "cn=ldaptestcontainer," + base_dn, "objectClass": "container"})
+    ldb.add({"dn": "cn=ldaptestcontainer," + base_dn, 
+             "objectClass": "container"})
     
     try:
         ldb.add({"dn": "CN=ldaptestuser4,CN=ldaptestcontainer," + base_dn, 
@@ -454,41 +461,43 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + base_dn + """
     ldb.rename("CN=ldaptestcontainer," + base_dn, "CN=ldaptestcontainer2," + base_dn)
 
     print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestuser4)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user))"
 
     print "Testing subtree ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + base_dn
     try:
-        res = ldb.search("(&(cn=ldaptestuser4)(objectClass=user))", "cn=ldaptestcontainer," + base_dn, ldb.SCOPE_SUBTREE)
+        ldb.search("cn=ldaptestcontainer," + base_dn, 
+                expression="(&(cn=ldaptestuser4)(objectClass=user))", 
+                scope=SCOPE_SUBTREE)
     except LdbError, (num, _):
-        assert num == 32
+        assert num == LDB_ERR_NO_SUCH_OBJECT
     else:
         assert False
 
     print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + base_dn
     try:
-        res = ldb.search("(&(cn=ldaptestuser4)(objectClass=user))", "cn=ldaptestcontainer," + base_dn, ldb.SCOPE_ONELEVEL)
+        res = ldb.search("cn=ldaptestcontainer," + base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_ONELEVEL)
     except LdbError, (num, _):
-        assert num == 32
+        assert num == LDB_ERR_NO_SUCH_OBJECT
     else:
         assert False
 
     print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in renamed container"
-    res = ldb.search("(&(cn=ldaptestuser4)(objectClass=user))", "cn=ldaptestcontainer2," + base_dn, ldb.SCOPE_SUBTREE)
+    res = ldb.search("cn=ldaptestcontainer2," + base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_SUBTREE)
     assert len(res) == 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user)) under cn=ldaptestcontainer2," + base_dn
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn))
-    assertEquals(strupper(res[0].memberOf[0]), strupper(("CN=ldaptestgroup2,CN=Users," + base_dn)))
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn))
+    assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + base_dn).upper())
 
     print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"
-    res = ldb.search("(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group))", base_dn, ldb.SCOPE_SUBTREE)
+    res = ldb.search(base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE)
     assert len(res) == 1, "Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group)), perhaps linked attributes are not conistant with subtree renames?"
 
     print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + base_dn
     try:
-        ok = ldb.rename("cn=ldaptestcontainer2," + base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + base_dn)
+        ldb.rename("cn=ldaptestcontainer2," + base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + base_dn)
     except LdbError, (num, _):
-        assert num != 53 # LDAP_UNWILLING_TO_PERFORM
+        assert num == LDB_ERR_UNWILLING_TO_PERFORM
     else:
         assert False
 
@@ -502,25 +511,25 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + base_dn + """
 
     print "Testing delete (should fail, not a leaf node) of renamed cn=ldaptestcontainer2," + base_dn
     try:
-        ok = ldb.delete("cn=ldaptestcontainer2," + base_dn)
+        ldb.delete("cn=ldaptestcontainer2," + base_dn)
     except LdbError, (num, _):
-        assert num == 66
+        assert num == LDB_ERR_NOT_ALLOWED_ON_NON_LEAF
     else:
         assert False
 
     print "Testing base ldb.search for CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn
-    res = ldb.search("(objectclass=*)", ("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn), ldb.SCOPE_BASE)
+    res = ldb.search(expression="(objectclass=*)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn), scope=SCOPE_BASE)
     assert len(res) == 1
-    res = ldb.search("(cn=ldaptestuser40)", ("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn), ldb.SCOPE_BASE)
+    res = ldb.search(expression="(cn=ldaptestuser40)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn), scope=SCOPE_BASE)
     assert len(res) == 0
 
     print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + base_dn
-    res = ldb.search("(&(cn=ldaptestuser4)(objectClass=user))", "cn=ldaptestcontainer2," + base_dn, ldb.SCOPE_ONELEVEL)
-    assert len(res) == 0
+    res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base="cn=ldaptestcontainer2," + base_dn, scope=SCOPE_ONELEVEL)
+    # FIXME: assert len(res) == 0
 
     print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + base_dn
-    res = ldb.search("(&(cn=ldaptestuser4)(objectClass=user))", "cn=ldaptestcontainer2," + base_dn, ldb.SCOPE_SUBTREE)
-    assert len(res) == 0
+    res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base="cn=ldaptestcontainer2," + base_dn, scope=SCOPE_SUBTREE)
+    #FIXME: assert len(res) == 0
 
     print "Testing delete of subtree renamed "+("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn)
     ldb.delete(("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn))
@@ -541,172 +550,155 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + base_dn + """
                   "objectClass": "user"})
 
     print "Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestuser)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestuser)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestuser,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser")
-    assertEquals(res[0].name, "ldaptestuser")
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "person")
-    assertEquals(res[0].objectClass[2], "organizationalPerson")
-    assertEquals(res[0].objectClass[3], "user")
-    assert(res[0].objectGUID != undefined)
-    assert(res[0].whenCreated != undefined)
-    assertEquals(res[0].objectCategory, ("CN=Person,CN=Schema,CN=Configuration," + base_dn))
-    assertEquals(res[0].sAMAccountType, 805306368)
+    assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestuser")
+    assertEquals(res[0]["name"], "ldaptestuser")
+    assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"])
+    assert("objectGUID" in res[0])
+    assert("whenCreated" in res[0])
+    assertEquals(res[0]["objectCategory"], ("CN=Person,CN=Schema,CN=Configuration," + base_dn))
+    assertEquals(int(res[0]["sAMAccountType"][0]), 805306368)
 #    assertEquals(res[0].userAccountControl, 546)
-    assertEquals(res[0].memberOf[0], ("CN=ldaptestgroup2,CN=Users," + base_dn))
-    assertEquals(res[0].memberOf.length, 1)
+    assertEquals(res[0]["memberOf"][0], ("CN=ldaptestgroup2,CN=Users," + base_dn))
+    assertEquals(len(res[0]["memberOf"]), 1)
  
     print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + base_dn + "))"
-    res2 = ldb.search("(&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + base_dn + "))")
+    res2 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + base_dn + "))")
     assert len(res2) == 1, "Could not find (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + base_dn + "))"
 
-    assertEquals(res[0].dn, res2.msgs[0].dn)
+    assertEquals(res[0].dn, res2[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon))"
-    res3 = ldb.search("(&(cn=ldaptestuser)(objectCategory=PerSon))")
+    res3 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
     assert len(res3) == 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)): matched " + len(res3)
 
-    assertEquals(res[0].dn, res3.msgs[0].dn)
+    assertEquals(res[0].dn, res3[0].dn)
 
     if gc_ldb is not None:
         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog"
-        res3gc = gc_ldb.search("(&(cn=ldaptestuser)(objectCategory=PerSon))")
+        res3gc = gc_ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
         assert len(res3gc) == 1
     
-        assertEquals(res[0].dn, res3gc.msgs[0].dn)
+        assertEquals(res[0].dn, res3gc[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in with 'phantom root' control"
-    attrs = ["cn"]
-    controls = ["search_options:1:2"]
-    res3control = gc_ldb.search("(&(cn=ldaptestuser)(objectCategory=PerSon))", base_dn, ldb.SCOPE_SUBTREE, attrs, controls)
+    
+    res3control = gc_ldb.search(base_dn, expression="(&(cn=ldaptestuser)(objectCategory=PerSon))", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
     assert len(res3control) == 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog"
     
-    assertEquals(res[0].dn, res3control.msgs[0].dn)
+    assertEquals(res[0].dn, res3control[0].dn)
 
     ldb.delete(res[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestcomputer)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestcomputer)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))"
 
-    assertEquals(res[0].dn, ("CN=ldaptestcomputer,CN=Computers," + base_dn))
-    assertEquals(res[0].cn, "ldaptestcomputer")
-    assertEquals(res[0].name, "ldaptestcomputer")
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "person")
-    assertEquals(res[0].objectClass[2], "organizationalPerson")
-    assertEquals(res[0].objectClass[3], "user")
-    assertEquals(res[0].objectClass[4], "computer")
-    assert(res[0].objectGUID != undefined)
-    assert(res[0].whenCreated != undefined)
-    assertEquals(res[0].objectCategory, ("CN=Computer,CN=Schema,CN=Configuration," + base_dn))
-    assertEquals(res[0].primaryGroupID, 513)
+    assertEquals(str(res[0].dn), ("CN=ldaptestcomputer,CN=Computers," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestcomputer")
+    assertEquals(res[0]["name"], "ldaptestcomputer")
+    assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user", "computer"])
+    assert("objectGUID" in res[0])
+    assert("whenCreated" in res[0])
+    assertEquals(res[0]["objectCategory"], ("CN=Computer,CN=Schema,CN=Configuration," + base_dn))
+    assertEquals(int(res[0]["primaryGroupID"][0]), 513)
 #    assertEquals(res[0].sAMAccountType, 805306368)
 #    assertEquals(res[0].userAccountControl, 546)
-    assertEquals(res[0].memberOf[0], ("CN=ldaptestgroup2,CN=Users," + base_dn))
-    assertEquals(res[0].memberOf.length, 1)
+    assertEquals(res[0]["memberOf"][0], "CN=ldaptestgroup2,CN=Users," + base_dn)
+    assertEquals(len(res[0]["memberOf"]), 1)
 
     print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))"
-    res2 = ldb.search("(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))")
+    res2 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))")
     assert len(res2) == 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))"
 
-    assertEquals(res[0].dn, res2.msgs[0].dn)
+    assertEquals(res[0].dn, res2[0].dn)
 
     if gc_ldb is not None:
         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + ")) in Global Catlog"
-        res2gc = gc_ldb.search("(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))")
+        res2gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + "))")
         assert len(res2gc) == 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + base_dn + ")) in Global Catlog"
 
-        assertEquals(res[0].dn, res2gc.msgs[0].dn)
+        assertEquals(res[0].dn, res2gc[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER))"
-    res3 = ldb.search("(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
+    res3 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
     assert len(res3) == 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER))"
 
-    assertEquals(res[0].dn, res3.msgs[0].dn)
+    assertEquals(res[0].dn, res3[0].dn)
 
     if gc_ldb is not None:
         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog"
-        res3gc = gc_ldb.search("(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
+        res3gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
         assert len(res3gc) == 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog"
 
-        assertEquals(res[0].dn, res3gc.msgs[0].dn)
+        assertEquals(res[0].dn, res3gc[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestcomp*r)(objectCategory=compuTER))"
-    res4 = ldb.search("(&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
+    res4 = ldb.search(expression="(&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
     assert len(res4) == 1, "Could not find (&(cn=ldaptestcomp*r)(objectCategory=compuTER))"
 
-    assertEquals(res[0].dn, res4.msgs[0].dn)
+    assertEquals(res[0].dn, res4[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestcomput*)(objectCategory=compuTER))"
-    res5 = ldb.search("(&(cn=ldaptestcomput*)(objectCategory=compuTER))")
+    res5 = ldb.search(expression="(&(cn=ldaptestcomput*)(objectCategory=compuTER))")
     assert len(res5) == 1, "Could not find (&(cn=ldaptestcomput*)(objectCategory=compuTER))"
 
-    assertEquals(res[0].dn, res5.msgs[0].dn)
+    assertEquals(res[0].dn, res5[0].dn)
 
     print "Testing ldb.search for (&(cn=*daptestcomputer)(objectCategory=compuTER))"
-    res6 = ldb.search("(&(cn=*daptestcomputer)(objectCategory=compuTER))")
+    res6 = ldb.search(expression="(&(cn=*daptestcomputer)(objectCategory=compuTER))")
     assert len(res6) == 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))"
 
-    assertEquals(res[0].dn, res6.msgs[0].dn)
+    assertEquals(res[0].dn, res6[0].dn)
 
     ldb.delete(res[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptest2computer)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptest2computer)(objectClass=user))"
 
     assertEquals(res[0].dn, ("CN=ldaptest2computer,CN=Computers," + base_dn))
-    assertEquals(res[0].cn, "ldaptest2computer")
-    assertEquals(res[0].name, "ldaptest2computer")
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "person")
-    assertEquals(res[0].objectClass[2], "organizationalPerson")
-    assertEquals(res[0].objectClass[3], "user")
-    assertEquals(res[0].objectClass[4], "computer")
-    assert(res[0].objectGUID != undefined)
-    assert(res[0].whenCreated != undefined)
-    assertEquals(res[0].objectCategory, "cn=Computer,cn=Schema,cn=Configuration," + base_dn)
-    assertEquals(res[0].sAMAccountType, 805306369)
+    assertEquals(res[0]["cn"], "ldaptest2computer")
+    assertEquals(res[0]["name"], "ldaptest2computer")
+    assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user", "computer"])
+    assert("objectGUID" in res[0])
+    assert("whenCreated" in res[0])
+    assertEquals(res[0]["objectCategory"][0], "CN=Computer,CN=Schema,CN=Configuration," + base_dn)
+    assertEquals(int(res[0]["sAMAccountType"][0]), 805306369)
 #    assertEquals(res[0].userAccountControl, 4098)
 
     ldb.delete(res[0].dn)
 
     attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "memberOf"]
     print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
-    res = ldb.search(base_dn, "(&(cn=ldaptestUSer2)(objectClass=user))", ldb.SCOPE_SUBTREE, attrs)
+    res = ldb.search(base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
     assert len(res) == 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))"
 
     assertEquals(res[0].dn, ("CN=ldaptestuser2,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestuser2")
-    assertEquals(res[0].name, "ldaptestuser2")
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "person")
-    assertEquals(res[0].objectClass[2], "organizationalPerson")
-    assertEquals(res[0].objectClass[3], "user")
-    assert(res[0].objectGUID != undefined)
-    assert(res[0].whenCreated != undefined)
-    assert(res[0].nTSecurityDescriptor != undefined)
-    assertEquals(res[0].memberOf[0], ("CN=ldaptestgroup2,CN=Users," + base_dn))
+    assertEquals(res[0]["cn"], "ldaptestuser2")
+    assertEquals(res[0]["name"], "ldaptestuser2")
+    assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"])
+    assert("objectGUID" in res[0])
+    assert("whenCreated" in res[0])
+    assert("nTSecurityDescriptor" in res[0])
+    assertEquals(res[0]["memberOf"][0], ("CN=ldaptestgroup2,CN=Users," + base_dn))
 
     attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]
     print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))"
-    res = ldb.search("(&(cn=ldaptestgroup2)(objectClass=group))", base_dn, ldb.SCOPE_SUBTREE, attrs)
+    res = ldb.search(base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
     assert len(res) == 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))"
 
     assertEquals(res[0].dn, ("CN=ldaptestgroup2,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestgroup2")
-    assertEquals(res[0].name, "ldaptestgroup2")
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "group")
-    assert(res[0].objectGUID != undefined)
-    assert(res[0].whenCreated != undefined)
-    assert(res[0].nTSecurityDescriptor != undefined)
-    assertEquals(res[0].member[0], ("CN=ldaptestuser2,CN=Users," + base_dn))
-    assertEquals(res[0].member.length, 1)
+    assertEquals(res[0]["cn"], "ldaptestgroup2")
+    assertEquals(res[0]["name"], "ldaptestgroup2")
+    assertEquals(res[0]["objectClass"], ["top", "group"])
+    assert("objectGuid" not in res[0])
+    assert("whenCreated" in res[0])
+    assert("nTSecurityDescriptor" in res[0])
+    assertEquals(res[0]["member"], ["CN=ldaptestuser2,CN=Users," + base_dn])
 
     ldb.modify_ldif("""
 dn: cn=ldaptestgroup2,cn=users,""" + base_dn + """
@@ -752,41 +744,38 @@ delete: member
 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + base_dn + """
 """)
     
-    res = ldb.search("(&(cn=ldaptestgroup2)(objectClass=group))", base_dn, ldb.SCOPE_SUBTREE, attrs)
-    assert len(res) != 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))"
+    res = ldb.search(base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
+    assert len(res) == 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))"
 
     assertEquals(res[0].dn, ("CN=ldaptestgroup2,CN=Users," + base_dn))
-    assertEquals(res[0].member[0], ("CN=ldaptestuser2,CN=Users," + base_dn))
-    assertEquals(res[0].member.length, 1)
+    assertEquals(res[0]["member"][0], ("CN=ldaptestuser2,CN=Users," + base_dn))
+    assertEquals(len(res[0]["member"]), 1)
 
     ldb.delete(("CN=ldaptestuser2,CN=Users," + base_dn))
 
     attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]
     print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
-    res = ldb.search("(&(cn=ldaptestgroup2)(objectClass=group))", base_dn, ldb.SCOPE_SUBTREE, attrs)
-    assert len(res) != 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
+    res = ldb.search(base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
+    assert len(res) == 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
 
     assertEquals(res[0].dn, ("CN=ldaptestgroup2,CN=Users," + base_dn))
-    assertEquals(res[0].member, undefined)
+    assert("member" not in res[0])
 
     print "Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))"
 
     assertEquals(res[0].dn, ("CN=ldaptestutf8user èùéìòà,CN=Users," + base_dn))
-    assertEquals(res[0].cn, "ldaptestutf8user èùéìòà")
-    assertEquals(res[0].name, "ldaptestutf8user èùéìòà")
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "person")
-    assertEquals(res[0].objectClass[2], "organizationalPerson")
-    assertEquals(res[0].objectClass[3], "user")
-    assert(res[0].objectGUID != undefined)
-    assert(res[0].whenCreated != undefined)
+    assertEquals(res[0]["cn"], "ldaptestutf8user èùéìòà")
+    assertEquals(res[0]["name"], "ldaptestutf8user èùéìòà")
+    assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"])
+    assert("objectGUID" in res[0])
+    assert("whenCreated" in res[0])
 
     ldb.delete(res[0].dn)
 
     print "Testing ldb.search for (&(cn=ldaptestutf8user2*)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestutf8user2*)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestutf8user2*)(objectClass=user))")
     assert len(res) == 1, "Could not find (&(cn=ldaptestutf8user2*)(objectClass=user))"
 
     ldb.delete(res[0].dn)
@@ -794,174 +783,127 @@ member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + base_dn + """
     ldb.delete(("CN=ldaptestgroup2,CN=Users," + base_dn))
 
     print "Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))"
-    res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
+    res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
 
-    assert len(res) == 1, "Could not find (expect space collapse, win2k3 fails) (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))"
+    #FIXME: assert len(res) == 1, "Could not find (expect space collapse, win2k3 fails) (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))"
 
     print "Testing that we can't get at the configuration DN from the main search base"
-    attrs = ["cn"]
-    res = ldb.search("objectClass=crossRef", base_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
     assert len(res) == 0, "Got configuration DN " + res[0].dn + " which should not be able to be seen from main search base"
     assertEquals(len(res), 0)
 
     print "Testing that we can get at the configuration DN from the main search base on the LDAP port with the 'phantom root' search_options control"
-    attrs = ["cn"]
-    controls = ["search_options:1:2"]
-    res = ldb.search("objectClass=crossRef", base_dn, ldb.SCOPE_SUBTREE, attrs, controls)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
     assert(len(res) > 0)
 
     if gc_ldb is not None:
         print "Testing that we can get at the configuration DN from the main search base on the GC port with the search_options control == 0"
-        attrs = ["cn"]
-        controls = ["search_options:1:0"]
-        res = gc_ldb.search("objectClass=crossRef", base_dn, gc_ldb.SCOPE_SUBTREE, attrs, controls)
-        assertEquals(res.error, 0)
+        
+        res = gc_ldb.search(base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:0"])
         assert(len(res) > 0)
 
         print "Testing that we do find configuration elements in the global catlog"
-        attrs = ["cn"]
-        res = gc_ldb.search("objectClass=crossRef", base_dn, ldb.SCOPE_SUBTREE, attrs)
-        assertEquals(res.error, 0)
+        res = gc_ldb.search(base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
         assert (len(res) > 0)
     
         print "Testing that we do find configuration elements and user elements at the same time"
-        attrs = ["cn"]
-        res = gc_ldb.search("(|(objectClass=crossRef)(objectClass=person))", base_dn, ldb.SCOPE_SUBTREE, attrs)
-        assertEquals(res.error, 0)
+        res = gc_ldb.search(base_dn, expression="(|(objectClass=crossRef)(objectClass=person))", scope=SCOPE_SUBTREE, attrs=["cn"])
         assert (len(res) > 0)
 
         print "Testing that we do find configuration elements in the global catlog, with the configuration basedn"
-        attrs = ["cn"]
-        res = gc_ldb.search("objectClass=crossRef", configuration_dn, ldb.SCOPE_SUBTREE, attrs)
-        assertEquals(res.error, 0)
+        res = gc_ldb.search(configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
         assert (len(res) > 0)
 
     print "Testing that we can get at the configuration DN on the main LDAP port"
-    attrs = ["cn"]
-    res = ldb.search("objectClass=crossRef", configuration_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
     assert (len(res) > 0)
 
     print "Testing objectCategory canonacolisation"
-    attrs = ["cn"]
-    res = ldb.search("objectCategory=ntDsDSA", configuration_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(configuration_dn, expression="objectCategory=ntDsDSA", scope=SCOPE_SUBTREE, attrs=["cn"])
     assert len(res) > 0, "Didn't find any records with objectCategory=ntDsDSA"
     assert(len(res) != 0)
     
-    attrs = ["cn"]
-    res = ldb.search("objectCategory=CN=ntDs-DSA," + schema_dn, configuration_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(configuration_dn, expression="objectCategory=CN=ntDs-DSA," + schema_dn, scope=SCOPE_SUBTREE, attrs=["cn"])
     assert len(res) > 0, "Didn't find any records with objectCategory=CN=ntDs-DSA," + schema_dn
     assert(len(res) != 0)
     
     print "Testing objectClass attribute order on "+ base_dn
-    attrs = ["objectClass"]
-    res = ldb.search("objectClass=domain", base_dn, ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(expression="objectClass=domain", base=base_dn, 
+                     scope=SCOPE_BASE, attrs=["objectClass"])
     assertEquals(len(res), 1)
 
-    assertEquals(res[0].objectClass[0], "top")
-    assertEquals(res[0].objectClass[1], "domain")
-    assertEquals(res[0].objectClass[2], "domainDNS")
+    assertEquals(res[0]["objectClass"], ["top", "domain", "domainDNS"])
 
 #  check enumeration
 
-    attrs = ["cn"]
     print "Testing ldb.search for objectCategory=person"
-    res = ldb.search("objectCategory=person", base_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"])
     assert(len(res) > 0)
 
-    attrs = ["cn"]
-    controls = ["domain_scope:1"]
     print "Testing ldb.search for objectCategory=person with domain scope control"
-    res = ldb.search("objectCategory=person", base_dn, ldb.SCOPE_SUBTREE, attrs, controls)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
     assert(len(res) > 0)
  
-    attrs = ["cn"]
     print "Testing ldb.search for objectCategory=user"
-    res = ldb.search("objectCategory=user", base_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"])
     assert(len(res) > 0)
 
-    attrs = ["cn"]
-    controls = ["domain_scope:1"]
+    
     print "Testing ldb.search for objectCategory=user with domain scope control"
-    res = ldb.search("objectCategory=user", base_dn, ldb.SCOPE_SUBTREE, attrs, controls)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
     assert(len(res) > 0)
     
-    attrs = ["cn"]
     print "Testing ldb.search for objectCategory=group"
-    res = ldb.search("objectCategory=group", base_dn, ldb.SCOPE_SUBTREE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"])
     assert(len(res) > 0)
 
-    attrs = ["cn"]
-    controls = ["domain_scope:1"]
     print "Testing ldb.search for objectCategory=group with domain scope control"
-    res = ldb.search("objectCategory=group", base_dn, ldb.SCOPE_SUBTREE, attrs, controls)
-    assertEquals(res.error, 0)
+    res = ldb.search(base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
     assert(len(res) > 0)
 
 def basedn_tests(ldb, gc_ldb):
     print "Testing for all rootDSE attributes"
-    attrs = []
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(scope=SCOPE_BASE, attrs=[])
     assertEquals(len(res), 1)
 
     print "Testing for highestCommittedUSN"
-    attrs = ["highestCommittedUSN"]
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search("", scope=SCOPE_BASE, attrs=["highestCommittedUSN"])
     assertEquals(len(res), 1)
-    assert(res[0].highestCommittedUSN != undefined)
-    assert(res[0].highestCommittedUSN != 0)
+    assert(int(res[0]["highestCommittedUSN"][0]) != 0)
 
     print "Testing for netlogon via LDAP"
-    attrs = ["netlogon"]
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search("", scope=SCOPE_BASE, attrs=["netlogon"])
     assertEquals(len(res), 0)
 
     print "Testing for netlogon and highestCommittedUSN via LDAP"
-    attrs = ["netlogon", "highestCommittedUSN"]
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search("", scope=SCOPE_BASE, 
+            attrs=["netlogon", "highestCommittedUSN"])
     assertEquals(len(res), 0)
 
+
 def find_basedn(ldb):
-    attrs = ["defaultNamingContext"]
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(base="", expression="", scope=SCOPE_BASE, 
+                     attrs=["defaultNamingContext"])
     assertEquals(len(res), 1)
-    return res[0].defaultNamingContext
+    return res[0]["defaultNamingContext"][0]
+
 
 def find_configurationdn(ldb):
-    attrs = ["configurationNamingContext"]
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs)
-    assertEquals(res.error, 0)
+    res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["configurationNamingContext"])
     assertEquals(len(res), 1)
-    return res[0].configurationNamingContext
+    return res[0]["configurationNamingContext"][0]
+
 
 def find_schemadn(ldb):
-    res = ldb.search("", "", ldb.SCOPE_BASE, attrs=["schemaNamingContext"])
-    assertEquals(res.error, 0)
+    res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
     assertEquals(len(res), 1)
-    return res[0].schemaNamingContext
+    return res[0]["schemaNamingContext"][0]
 
 if not "://" in host:
     host = "ldap://%s" % host
 
-ldb = Ldb(host, credentials=creds, session_info=system_session(), 
-          lp=lp)
+ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
 base_dn = find_basedn(ldb)
-
 configuration_dn = find_configurationdn(ldb)
 schema_dn = find_schemadn(ldb)
 
index c33cba1d77e725585ab18705d1922a1ffb065167..24ceb309639d6b81dc7c29f1cd113d4418aa2e12 100644 (file)
@@ -61,6 +61,7 @@ struct search_context {
        int sort;
        int num_stored;
        struct ldb_message **store;
+       int refs_stored;
        char **refs_store;
 
        int entries;
@@ -87,15 +88,15 @@ static int store_message(struct ldb_message *msg, struct search_context *sctx) {
 
 static int store_referral(char *referral, struct search_context *sctx) {
 
-       sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs + 2);
+       sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2);
        if (!sctx->refs_store) {
                fprintf(stderr, "talloc_realloc failed while storing referrals\n");
                return -1;
        }
 
-       sctx->refs_store[sctx->refs] = talloc_move(sctx->refs_store, &referral);
-       sctx->refs++;
-       sctx->refs_store[sctx->refs] = NULL;
+       sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral);
+       sctx->refs_stored++;
+       sctx->refs_store[sctx->refs_stored] = NULL;
 
        return 0;
 }
@@ -199,6 +200,7 @@ static int do_search(struct ldb_context *ldb,
 
        sctx->sort = options->sorted;
        sctx->num_stored = 0;
+       sctx->refs_stored = 0;
        sctx->store = NULL;
        sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls);
        if (options->controls != NULL &&  sctx->req_ctrls== NULL) {
@@ -241,22 +243,18 @@ again:
        if (sctx->pending)
                goto again;
 
-       if (sctx->sort && sctx->num_stored != 0) {
+       if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) {
                int i;
 
-               ldb_qsort(sctx->store, ret, sizeof(struct ldb_message *),
-                         ldb, (ldb_qsort_cmp_fn_t)do_compare_msg);
-
-               if (ret != 0) {
-                       fprintf(stderr, "An error occurred while sorting messages\n");
-                       exit(1);
+               if (sctx->num_stored) {
+                       ldb_qsort(sctx->store, sctx->num_stored, sizeof(struct ldb_message *),
+                                 ldb, (ldb_qsort_cmp_fn_t)do_compare_msg);
                }
-
                for (i = 0; i < sctx->num_stored; i++) {
                        display_message(ldb, sctx->store[i], sctx);
                }
 
-               for (i = 0; i < sctx->refs; i++) {
+               for (i = 0; i < sctx->refs_stored; i++) {
                        display_referral(sctx->refs_store[i], sctx);
                }
        }
index 9751d2bf7349f14fc3b4049990f2e181bc2d13ae..b46f7c3ee7a2fa1cac6985f5b920efce6e3a6036 100644 (file)
@@ -1,9 +1,6 @@
 ##############################
 # Start SUBSYSTEM NSS_WRAPPER
-[LIBRARY::NSS_WRAPPER]
-VERSION = 0.0.1
-SO_VERSION = 0
-DESCRIPTION = Wrapper library for testing nss calls without being root
+[SUBSYSTEM::NSS_WRAPPER]
 PUBLIC_HEADERS = nss_wrapper.h
 OBJ_FILES = nss_wrapper.o
 # End SUBSYSTEM NSS_WRAPPER
index f404d58377394124fa23e01b7218c8caa242a58d..aae98b86b2e899c0c4abea7954ddc2f23a7e3cb6 100644 (file)
@@ -1,4 +1,4 @@
-[LIBRARY::LIBPOLICY]
+[SUBSYSTEM::LIBPOLICY]
 CFLAGS = -Iheimdal/lib/roken
 OBJ_FILES = lex.o parse_adm.o 
 PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSAMBA-CONFIG LIBTALLOC CHARSET 
index a13e3753b7f0bac4010c0f351d6b76efdccd7a83..27cae8c49062ed9ba1ba670f47f3bc594b422763 100644 (file)
@@ -64,7 +64,7 @@ static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
        if (rmdir(child) == 0)
                ret = WERR_OK;
        else if (errno == ENOENT)
-               ret = WERR_NOT_FOUND;
+               ret = WERR_BADFILE;
        else
                ret = WERR_GENERAL_FAILURE;
 
@@ -282,7 +282,7 @@ static WERROR reg_dir_get_value(TALLOC_CTX *mem_ctx,
        contents = file_load(path, &size, mem_ctx);
        talloc_free(path);
        if (contents == NULL)
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
 
        if (type != NULL)
                *type = 4; /* FIXME */
@@ -339,7 +339,7 @@ static WERROR reg_dir_del_value (struct hive_key *key, const char *name)
        if (unlink(path) < 0) {
                talloc_free(path);
                if (errno == ENOENT)
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
                return WERR_GENERAL_FAILURE;
        }
        talloc_free(path);
index bbe510772cc9a714e90b631ef81229f261fc5ce7..5d56a30b3e14edaacfcaf4c80801cae9adaca9df 100644 (file)
@@ -41,7 +41,7 @@ _PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location,
        fd = open(location, O_RDWR);
        if (fd == -1) {
                if (errno == ENOENT)
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
                return WERR_BADFILE;
        }
 
index 259315cc3955d93f87e776b9b8433084642c0af6..262859f64b4302395d04cf41f0d0e47b27a4cde1 100644 (file)
@@ -111,6 +111,15 @@ static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx,
        return msg;
 }
 
+static char *reg_ldb_escape(TALLOC_CTX *mem_ctx, const char *value)
+{
+       struct ldb_val val;
+
+       val.data = discard_const_p(uint8_t, value);
+       val.length = strlen(value);
+
+       return ldb_dn_escape_value(mem_ctx, val);
+}
 
 static int reg_close_ldb_key(struct ldb_key_data *key)
 {
@@ -159,7 +168,13 @@ static struct ldb_dn *reg_path_to_ldb(TALLOC_CTX *mem_ctx,
                else keyname = mypath;
 
                if(strlen(keyname)) {
-                       ldb_dn_add_base_fmt(ret, "key=%s", keyname);
+                       if (!ldb_dn_add_base_fmt(ret, "key=%s",
+                                                reg_ldb_escape(local_ctx,
+                                                               keyname)))
+                       {
+                               talloc_free(local_ctx);
+                               return NULL;
+                       }
                }
 
                if(begin) {
@@ -293,7 +308,7 @@ static WERROR ldb_get_value(TALLOC_CTX *mem_ctx, struct hive_key *k,
        }
 
        if (res->count == 0)
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
 
        reg_ldb_unpack_value(mem_ctx, res->msgs[0], NULL, data_type, data);
 
@@ -322,7 +337,7 @@ static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, const struct hive_key *h,
                DEBUG(3, ("Key '%s' not found\n",
                        ldb_dn_get_linearized(ldap_path)));
                talloc_free(res);
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
        }
 
        newkd = talloc_zero(mem_ctx, struct ldb_key_data);
@@ -385,7 +400,7 @@ static WERROR ldb_add_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
                          struct security_descriptor *sd,
                          struct hive_key **newkey)
 {
-       const struct ldb_key_data *parentkd = (const struct ldb_key_data *)parent;
+       struct ldb_key_data *parentkd = (const struct ldb_key_data *)parent;
        struct ldb_message *msg;
        struct ldb_key_data *newkd;
        int ret;
@@ -400,8 +415,12 @@ static WERROR ldb_add_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
                                   talloc_strdup(mem_ctx, classname));
 
        ret = ldb_add(parentkd->ldb, msg);
-       if (ret < 0) {
-               DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(parentkd->ldb)));
+       if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+               return WERR_ALREADY_EXISTS;
+       }
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(1, ("ldb_add: %s\n", ldb_errstring(parentkd->ldb)));
                return WERR_FOOBAR;
        }
 
@@ -414,29 +433,37 @@ static WERROR ldb_add_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
 
        *newkey = (struct hive_key *)newkd;
 
+       /* reset cache */
+       talloc_free(parentkd->subkeys);
+       parentkd->subkeys = NULL;
+
        return WERR_OK;
 }
 
-static WERROR ldb_del_key(const struct hive_key *key, const char *child)
+static WERROR ldb_del_key(const struct hive_key *key, const char *name)
 {
        int ret;
        struct ldb_key_data *parentkd = talloc_get_type(key, struct ldb_key_data);
-       struct ldb_dn *childdn;
+       struct ldb_dn *ldap_path;
+       TALLOC_CTX *mem_ctx = talloc_init("ldb_del_key");
 
-       childdn = ldb_dn_copy(parentkd->ldb, parentkd->dn);
-       ldb_dn_add_child_fmt(childdn, "key=%s", child);
+       ldap_path = reg_path_to_ldb(mem_ctx, key, name, NULL);
 
-       ret = ldb_delete(parentkd->ldb, childdn);
+       ret = ldb_delete(parentkd->ldb, ldap_path);
 
-       talloc_free(childdn);
+       talloc_free(mem_ctx);
 
        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
-               return WERR_NOT_FOUND;
-       } else if (ret < 0) {
+               return WERR_BADFILE;
+       } else if (ret != LDB_SUCCESS) {
                DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(parentkd->ldb)));
                return WERR_FOOBAR;
        }
 
+       /* reset cache */
+       talloc_free(parentkd->subkeys);
+       parentkd->subkeys = NULL;
+
        return WERR_OK;
 }
 
@@ -447,19 +474,28 @@ static WERROR ldb_del_value (struct hive_key *key, const char *child)
        struct ldb_dn *childdn;
 
        childdn = ldb_dn_copy(kd->ldb, kd->dn);
-       ldb_dn_add_child_fmt(childdn, "value=%s", child);
+       if (!ldb_dn_add_child_fmt(childdn, "value=%s",
+                                 reg_ldb_escape(childdn, child)))
+       {
+               talloc_free(childdn);
+               return WERR_FOOBAR;
+       }
 
        ret = ldb_delete(kd->ldb, childdn);
 
        talloc_free(childdn);
 
        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
-               return WERR_NOT_FOUND;
-       } else if (ret < 0) {
+               return WERR_BADFILE;
+       } else if (ret != LDB_SUCCESS) {
                DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb)));
                return WERR_FOOBAR;
        }
 
+       /* reset cache */
+       talloc_free(kd->values);
+       kd->values = NULL;
+
        return WERR_OK;
 }
 
@@ -475,18 +511,32 @@ static WERROR ldb_set_value(struct hive_key *parent,
        msg = reg_ldb_pack_value(kd->ldb, mem_ctx, name, type, data);
 
        msg->dn = ldb_dn_copy(msg, kd->dn);
-       ldb_dn_add_child_fmt(msg->dn, "value=%s", name);
+       if (!ldb_dn_add_child_fmt(msg->dn, "value=%s",
+                                 reg_ldb_escape(mem_ctx, name)))
+       {
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
 
        ret = ldb_add(kd->ldb, msg);
-       if (ret < 0) {
-               ret = ldb_modify(kd->ldb, msg);
-               if (ret < 0) {
-                       DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(kd->ldb)));
-                       talloc_free(mem_ctx);
-                       return WERR_FOOBAR;
+       if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+               int i;
+               for (i = 0; i < msg->num_elements; i++) {
+                       msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
                }
+               ret = ldb_modify(kd->ldb, msg);
+       }
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(kd->ldb)));
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
        }
 
+       /* reset cache */
+       talloc_free(kd->values);
+       kd->values = NULL;
+
        talloc_free(mem_ctx);
        return WERR_OK;
 }
@@ -503,17 +553,23 @@ static WERROR ldb_get_key_info(TALLOC_CTX *mem_ctx,
 {
        struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
 
+       if (kd->subkeys == NULL) {
+               W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
+       }
+
+       if (kd->values == NULL) {
+               W_ERROR_NOT_OK_RETURN(cache_values(kd));
+       }
+
        /* FIXME */
        if (classname != NULL)
                *classname = NULL;
 
        if (num_subkeys != NULL) {
-               W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
                *num_subkeys = kd->subkey_count;
        }
 
        if (num_values != NULL) {
-               W_ERROR_NOT_OK_RETURN(cache_values(kd));
                *num_values = kd->value_count;
        }
 
@@ -523,7 +579,6 @@ static WERROR ldb_get_key_info(TALLOC_CTX *mem_ctx,
        if (max_subkeynamelen != NULL) {
                int i;
                struct ldb_message_element *el;
-               W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
 
                *max_subkeynamelen = 0;
 
index fa59f255966c0154fd870f2f0499efd0dc9d86e6..3e463100c9cb80380f02066cfd3b6a45010f8c91 100644 (file)
@@ -140,7 +140,7 @@ WERROR local_get_predefined_key(struct registry_context *ctx,
        }
 
        if (mp == NULL)
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
 
        *key = reg_import_hive_key(ctx, mp->key,
                                   mp->path.predefined_key,
index b6ad7dfb1099c72eed4ccdbcd20f8ee80547e7f4..fa1367bbd2cd38f37a8c359e254ec6e84d747269 100644 (file)
@@ -82,11 +82,11 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                        if (W_ERROR_IS_OK(error2))
                                continue;
                } else {
-                       error2 = WERR_DEST_NOT_FOUND;
+                       error2 = WERR_BADFILE;
                        t2 = NULL;
                }
 
-               if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
+               if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
                        DEBUG(0, ("Error occured while getting subkey by name: %s\n",
                                win_errstr(error2)));
                        talloc_free(mem_ctx);
@@ -132,10 +132,10 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                                continue;
                } else {
                        t1 = NULL;
-                       error2 = WERR_DEST_NOT_FOUND;
+                       error2 = WERR_BADFILE;
                }
 
-               if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
+               if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
                        DEBUG(0, ("Error occured while getting subkey by name: %s\n",
                                win_errstr(error2)));
                        talloc_free(mem_ctx);
@@ -174,10 +174,10 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                                                           name, &type2,
                                                           &contents2);
                } else
-                       error2 = WERR_DEST_NOT_FOUND;
+                       error2 = WERR_BADFILE;
 
                if(!W_ERROR_IS_OK(error2) &&
-                  !W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
+                  !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
                        DEBUG(0, ("Error occured while getting value by name: %s\n",
                                win_errstr(error2)));
                        talloc_free(mem_ctx);
@@ -210,7 +210,7 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                if (W_ERROR_IS_OK(error2))
                        continue;
 
-               if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
+               if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
                        DEBUG(0, ("Error occured while getting value by name: %s\n",
                                win_errstr(error2)));
                        return error2;
@@ -238,14 +238,14 @@ _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
                struct registry_key *r1 = NULL, *r2 = NULL;
                error = reg_get_predefined_key(ctx1, i, &r1);
                if (!W_ERROR_IS_OK(error) &&
-                   !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
+                   !W_ERROR_EQUAL(error, WERR_BADFILE)) {
                        DEBUG(0, ("Unable to open hive %s for backend 1\n",
                                reg_get_predef_name(i)));
                }
 
                error = reg_get_predefined_key(ctx2, i, &r2);
                if (!W_ERROR_IS_OK(error) &&
-                   !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
+                   !W_ERROR_EQUAL(error, WERR_BADFILE)) {
                        DEBUG(0, ("Unable to open hive %s for backend 2\n",
                                reg_get_predef_name(i)));
                }
@@ -356,7 +356,7 @@ static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
        /* Open key */
        error = reg_open_key_abs(ctx, ctx, path, &tmp);
 
-       if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
+       if (W_ERROR_EQUAL(error, WERR_BADFILE)) {
                DEBUG(0, ("Error opening key '%s'\n", path));
                return error;
        }
index 9b126cc8084fe4d08748c6ce000ee5138dd3e224..15b60745f05612dea2b5d9ebdd06b6d161743d03 100644 (file)
@@ -575,7 +575,7 @@ static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx,
        }
 
        if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
 
        return error;
 }
@@ -870,7 +870,7 @@ static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
                                break;
                }
                if (key_off == 0)
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
        } else if (!strncmp((char *)data.data, "lf", 2)) {
                struct lf_block lf;
                struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
@@ -905,7 +905,7 @@ static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
                                break;
                }
                if (key_off == 0)
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
        } else if (!strncmp((char *)data.data, "lh", 2)) {
                struct lh_block lh;
                struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
@@ -942,7 +942,7 @@ static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
                                break;
                }
                if (key_off == 0)
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
        } else if (!strncmp((char *)data.data, "ri", 2)) {
                struct ri_block ri;
                struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
@@ -1022,7 +1022,7 @@ static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
                }
                talloc_free(pull);
                if (!key_off)
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
        } else {
                DEBUG(0, ("Unknown subkey list type.\n"));
                return WERR_GENERAL_FAILURE;
@@ -1419,7 +1419,7 @@ static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
                }
                if (!found_offset) {
                        DEBUG(2, ("Subkey not found\n"));
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
                }
                li.key_count--;
 
@@ -1464,7 +1464,7 @@ static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
                }
                if (!found_offset) {
                        DEBUG(2, ("Subkey not found\n"));
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
                }
                lf.key_count--;
 
@@ -1510,7 +1510,7 @@ static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
                }
                if (!found_offset) {
                        DEBUG(0, ("Subkey not found\n"));
-                       return WERR_NOT_FOUND;
+                       return WERR_BADFILE;
                }
                lh.key_count--;
 
@@ -1548,7 +1548,7 @@ static WERROR regf_del_value (struct hive_key *key, const char *name)
        uint32_t i;
 
        if (nk->values_offset == -1) {
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
        }
 
        values = hbin_get(regf, nk->values_offset);
@@ -1572,7 +1572,7 @@ static WERROR regf_del_value (struct hive_key *key, const char *name)
                }
        }
        if (!found_offset) {
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
        } else {
                nk->num_values--;
                values.length = (nk->num_values)*4;
@@ -1608,14 +1608,14 @@ static WERROR regf_del_key(const struct hive_key *parent, const char *name)
 
        if (parent_nk->subkeys_offset == -1) {
                DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
        }
 
        /* Find the key */
        if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
                                                   (struct hive_key **)&key))) {
                DEBUG(2, ("Key '%s' not found\n", name));
-               return WERR_NOT_FOUND;
+               return WERR_BADFILE;
        }
 
        if (key->nk->subkeys_offset != -1 ||
index 02f3363bab97366e806eaf393425c5e1854cb7bf..599385e73c210819a59d539aae946966fe4421ed 100644 (file)
@@ -42,7 +42,7 @@ static WERROR mount_samba_hive(struct registry_context *ctx,
 
        error = reg_open_hive(ctx, location, auth_info, creds, lp_ctx, &hive);
 
-       if (W_ERROR_EQUAL(error, WERR_NOT_FOUND))
+       if (W_ERROR_EQUAL(error, WERR_BADFILE))
                error = reg_open_ldb_file(ctx, location, auth_info,
                                          creds, lp_ctx, &hive);
 
index 22b4785222567f0b71238e32a4204f12e4930bfb..4d27e83a74747375a245906f48b7e369318f5ad4 100644 (file)
@@ -31,7 +31,7 @@ static bool test_del_nonexistant_key(struct torture_context *tctx,
 {
        const struct hive_key *root = (const struct hive_key *)test_data;
        WERROR error = hive_key_del(root, "bla");
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "invalid return code");
 
        return true;
@@ -134,7 +134,7 @@ static bool test_del_key(struct torture_context *tctx, const void *test_data)
        torture_assert_werr_ok(tctx, error, "reg_key_del");
 
        error = hive_key_del(root, "Nested Key");
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "reg_key_del");
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE, "reg_key_del");
 
        return true;
 }
@@ -174,7 +174,7 @@ static bool test_get_value(struct torture_context *tctx, const void *test_data)
        torture_assert_werr_ok(tctx, error, "hive_key_add_name");
 
        error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "getting missing value");
 
        error = hive_key_set_value(subkey, "Answer", REG_DWORD,
@@ -215,10 +215,10 @@ static bool test_del_value(struct torture_context *tctx, const void *test_data)
        torture_assert_werr_ok(tctx, error, "deleting value");
 
        error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "getting value");
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE, "getting value");
 
        error = hive_key_del_value(subkey, "Answer");
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "deleting value");
 
        return true;
index 75fbe1cbea8bca48d2815d97b84e5387d132ac17..7d14b3a4121d4c5d5246ed98daf094d537960d2b 100644 (file)
@@ -53,7 +53,7 @@ static bool test_get_predefined_unknown(struct torture_context *tctx,
        WERROR error;
 
        error = reg_get_predefined_key(rctx, 1337, &root);
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "getting predefined key failed");
        return true;
 }
@@ -195,16 +195,16 @@ static bool test_del_key(struct torture_context *tctx, void *_data)
        torture_assert_werr_ok(tctx, error,
                               "getting predefined key failed");
 
-       error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL, &newkey);
+       error = reg_key_add_name(rctx, root, "Polen", NULL, NULL, &newkey);
 
        torture_assert_werr_ok(tctx, error, "Creating key return code");
        torture_assert(tctx, newkey != NULL, "Creating new key");
 
-       error = reg_key_del(root, "Hamburg");
+       error = reg_key_del(root, "Polen");
        torture_assert_werr_ok(tctx, error, "Delete key");
 
-       error = reg_key_del(root, "Hamburg");
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       error = reg_key_del(root, "Polen");
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "Delete missing key");
 
        return true;
@@ -239,7 +239,7 @@ static bool test_flush_key(struct torture_context *tctx, void *_data)
        struct registry_key *root, *subkey;
        WERROR error;
 
-       if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
+       if (!create_test_key(tctx, rctx, "Bremen", &root, &subkey))
                return false;
 
        error = reg_key_flush(subkey);
@@ -416,7 +416,7 @@ static bool test_get_value(struct torture_context *tctx, void *_data)
 
        error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
                                          &data);
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "getting missing value");
 
        error = reg_val_set(subkey, __FUNCTION__, REG_DWORD,
@@ -447,12 +447,12 @@ static bool test_del_value(struct torture_context *tctx, void *_data)
        uint32_t value = 42;
        uint32_t type;
 
-       if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
+       if (!create_test_key(tctx, rctx, "Warschau", &root, &subkey))
                return false;
 
        error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
                                          &data);
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "getting missing value");
 
        error = reg_val_set(subkey, __FUNCTION__, REG_DWORD,
@@ -464,7 +464,7 @@ static bool test_del_value(struct torture_context *tctx, void *_data)
 
        error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__,
                                          &type, &data);
-       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+       torture_assert_werr_equal(tctx, error, WERR_BADFILE,
                                  "getting missing value");
 
        return true;
index 17dfdf7bf5b5384d7ce904bcfd2f0c67be50d738..c4da9aae593112aea4d2141b45692db0715a3ddb 100644 (file)
@@ -1,3 +1,11 @@
+AC_CHECK_FUNC(getpass, samba_cv_HAVE_GETPASS=yes)
+AC_CHECK_FUNC(getpassphrase, samba_cv_HAVE_GETPASSPHRASE=yes)
+if test x"$samba_cv_HAVE_GETPASS" = x"yes" -a x"$samba_cv_HAVE_GETPASSPHRASE" = x"yes"; then
+        AC_DEFINE(REPLACE_GETPASS_BY_GETPASSPHRASE, 1, [getpass returns <9 chars where getpassphrase returns <265 chars])
+       AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced])
+       LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o"
+else
+
 AC_CACHE_CHECK([whether getpass should be replaced],samba_cv_REPLACE_GETPASS,[
 SAVE_CPPFLAGS="$CPPFLAGS"
 CPPFLAGS="$CPPFLAGS -I$libreplacedir/"
@@ -12,3 +20,5 @@ if test x"$samba_cv_REPLACE_GETPASS" = x"yes"; then
        AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced])
        LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o"
 fi
+
+fi
index a577285639d7fc549ebc660d326bd90dfead8588..6d1d6b8afc23e15194e71468b723d3393714ad77 100644 (file)
@@ -100,6 +100,7 @@ AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h)
 AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
 AC_CHECK_HEADERS(sys/sockio.h sys/un.h)
 AC_CHECK_HEADERS(sys/mount.h mntent.h)
+AC_CHECK_HEADERS(stropts.h)
 
 dnl we need to check that net/if.h really can be used, to cope with hpux
 dnl where including it always fails
index cb8e21434e9de5b2d031ce9eb457ef9042c42fb2..2aec69896702500a159b858de2dcca4863a045e8 100644 (file)
@@ -265,7 +265,7 @@ AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG],
                        LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,--allow-shlib-undefined"
                        ;;
                *osf*)
-                       LD_SHLIB_ALLOW_UNDEF_FLAG="-expect_unresolved '*'"
+                       LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-expect_unresolved,\"*\""
                        ;;
                *darwin*)
                        LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup"
index cec158be313e16a7b52a5c5130cfb2cafb57fe52..b2a240e8ab4ad2c70eb30d94741dc2ee2bb84bbc 100644 (file)
@@ -218,7 +218,7 @@ long nap(long milliseconds) {
 #ifndef HAVE_MEMMOVE
 /*******************************************************************
 safely copies memory, ensuring no overlap problems.
-this is only used if the machine does not have it's own memmove().
+this is only used if the machine does not have its own memmove().
 this is not the fastest algorithm in town, but it will do for our
 needs.
 ********************************************************************/
index f8a89a7213b7dfd6a14d134a3a0df15a1d1937d3..3f91544e9782f914c1d898ebf7b5c8f50da5b843 100644 (file)
@@ -546,4 +546,12 @@ typedef int bool;
 #define QSORT_CAST (int (*)(const void *, const void *))
 #endif
 
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef MAX_DNS_NAME_LENGTH
+#define MAX_DNS_NAME_LENGTH 256 /* Actually 255 but +1 for terminating null. */
+#endif
+
 #endif /* _LIBREPLACE_REPLACE_H */
index 799187af7d47d00eb914238a6a699a5207161165..1c05733126d81c208b30435ce04c3ed6e77f8b89 100644 (file)
@@ -73,6 +73,18 @@ AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf,
        #include <unistd.h>
        #include <pwd.h>
        ])
+AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)],
+       [
+       #ifndef HAVE_GETPWENT_R_DECL
+       #error missing getpwent_r prototype
+       #endif
+       return NULL;
+       ],[
+       AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r irix (similar to solaris) function prototype])
+       ],[],[
+       #include <unistd.h>
+       #include <pwd.h>
+       ])
 AC_CHECK_FUNCS(getgrnam_r getgrgid_r getgrent_r)
 AC_HAVE_DECL(getgrent_r, [
        #include <unistd.h>
@@ -91,6 +103,19 @@ AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, in
        #include <grp.h>
        ])
 
+AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, size_t buflen)],
+       [
+       #ifndef HAVE_GETGRENT_R_DECL
+       #error missing getgrent_r prototype
+       #endif
+       return NULL;
+       ],[
+       AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r irix (similar to solaris)  function prototype])
+       ],[],[
+       #include <unistd.h>
+       #include <grp.h>
+       ])
+
 # locale
 AC_CHECK_HEADERS(ctype.h locale.h)
 
index e2fad5f68670ebad193083cb4440ff863f828e94..53bef66d482a8e756076c502e6d481b96a486dc2 100644 (file)
 #include <sys/ioctl.h>
 #endif
 
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+
 #ifdef REPLACE_INET_NTOA
 /* define is in "replace.h" */
 char *rep_inet_ntoa(struct in_addr ip);
index 36fca7b4f8bcf325eb1a625f62407ba5ce2bedc7..cad3197ccbac4cb5471787e5d36d580efa708018 100644 (file)
 #endif
 
 #ifdef REPLACE_GETPASS
+#if defined(REPLACE_GETPASS_BY_GETPASSPHRASE)
+#define getpass(prompt) getpassphrase(prompt)
+#else
 #define getpass(prompt) rep_getpass(prompt)
 char *rep_getpass(const char *prompt);
 #endif
+#endif
 
 #ifndef NGROUPS_MAX
 #define NGROUPS_MAX 32 /* Guess... */
index 76f1ce50967eda142cf5c2d9942369fe1e0d3c5d..705bdd40026a05a42c4bdde16b10cc32ec97fc84 100644 (file)
@@ -1,9 +1,6 @@
 ################################################
 # Start SUBSYSTEM LIBSAMBA3
-[LIBRARY::LIBSAMBA3]
-VERSION = 0.0.1
-SO_VERSION = 0
-DESCRIPTION = Library for reading Samba3 data files
+[SUBSYSTEM::LIBSAMBA3]
 PRIVATE_PROTO_HEADER = samba3_proto.h
 PUBLIC_HEADERS = samba3.h
 OBJ_FILES = tdbsam.o policy.o \
index 9e194230dc1ebd63a5e8ec028918783f431dd998..4c5cf9434855e563b71dae5ee9539c8a095d519d 100644 (file)
@@ -1,9 +1,6 @@
 ##############################
 # Start SUBSYSTEM SOCKET_WRAPPER
-[LIBRARY::SOCKET_WRAPPER]
-VERSION = 0.0.1
-SO_VERSION = 0
-DESCRIPTION = Wrapper library for testing TCP/IP connections using Unix Sockets
+[SUBSYSTEM::SOCKET_WRAPPER]
 PUBLIC_HEADERS = socket_wrapper.h
 OBJ_FILES = socket_wrapper.o
 PRIVATE_DEPENDENCIES = EXT_SOCKET
index b109643f23561790f7616a963551c7bf64c13385..2f2a4c379b0690399a9f4065b15960e667300bf0 100644 (file)
 
 #include "tdb_private.h"
 
+/* 'right' merges can involve O(n^2) cost when combined with a
+   traverse, so they are disabled until we find a way to do them in 
+   O(1) time
+*/
+#define USE_RIGHT_MERGES 0
+
 /* read a freelist record and check for simple errors */
 int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec)
 {
@@ -56,7 +62,7 @@ int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct
 }
 
 
-
+#if USE_RIGHT_MERGES
 /* Remove an element from the freelist.  Must have alloc lock. */
 static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_t next)
 {
@@ -75,6 +81,7 @@ static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_
        TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
        return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
 }
+#endif
 
 
 /* update a record tailer (must hold allocation lock) */
@@ -93,8 +100,6 @@ static int update_tailer(struct tdb_context *tdb, tdb_off_t offset,
    neccessary. */
 int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
 {
-       tdb_off_t right, left;
-
        /* Allocation and tailer lock */
        if (tdb_lock(tdb, -1, F_WRLCK) != 0)
                return -1;
@@ -105,9 +110,10 @@ int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
                goto fail;
        }
 
+#if USE_RIGHT_MERGES
        /* Look right first (I'm an Australian, dammit) */
-       right = offset + sizeof(*rec) + rec->rec_len;
-       if (right + sizeof(*rec) <= tdb->map_size) {
+       if (offset + sizeof(*rec) + rec->rec_len + sizeof(*rec) <= tdb->map_size) {
+               tdb_off_t right = offset + sizeof(*rec) + rec->rec_len;
                struct list_struct r;
 
                if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
@@ -122,13 +128,18 @@ int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
                                goto left;
                        }
                        rec->rec_len += sizeof(r) + r.rec_len;
+                       if (update_tailer(tdb, offset, rec) == -1) {
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+                               goto fail;
+                       }
                }
        }
-
 left:
+#endif
+
        /* Look left */
-       left = offset - sizeof(tdb_off_t);
-       if (left > TDB_DATA_START(tdb->header.hash_size)) {
+       if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) {
+               tdb_off_t left = offset - sizeof(tdb_off_t);
                struct list_struct l;
                tdb_off_t leftsize;
                
@@ -145,7 +156,12 @@ left:
 
                left = offset - leftsize;
 
-               /* Now read in record */
+               if (leftsize > offset ||
+                   left < TDB_DATA_START(tdb->header.hash_size)) {
+                       goto update;
+               }
+
+               /* Now read in the left record */
                if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
                        goto update;
@@ -153,21 +169,24 @@ left:
 
                /* If it's free, expand to include it. */
                if (l.magic == TDB_FREE_MAGIC) {
-                       if (remove_from_freelist(tdb, left, l.next) == -1) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left free failed at %u\n", left));
-                               goto update;
-                       } else {
-                               offset = left;
-                               rec->rec_len += leftsize;
+                       /* we now merge the new record into the left record, rather than the other 
+                          way around. This makes the operation O(1) instead of O(n). This change
+                          prevents traverse from being O(n^2) after a lot of deletes */
+                       l.rec_len += sizeof(*rec) + rec->rec_len;
+                       if (tdb_rec_write(tdb, left, &l) == -1) {
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left));
+                               goto fail;
+                       }
+                       if (update_tailer(tdb, left, &l) == -1) {
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+                               goto fail;
                        }
+                       tdb_unlock(tdb, -1, F_WRLCK);
+                       return 0;
                }
        }
 
 update:
-       if (update_tailer(tdb, offset, rec) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
-               goto fail;
-       }
 
        /* Now, prepend to free list */
        rec->magic = TDB_FREE_MAGIC;
@@ -189,62 +208,61 @@ update:
 }
 
 
+
 /* 
    the core of tdb_allocate - called when we have decided which
    free list entry to use
+
+   Note that we try to allocate by grabbing data from the end of an existing record,
+   not the beginning. This is so the left merge in a free is more likely to be
+   able to free up the record without fragmentation
  */
-static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, tdb_len_t length, tdb_off_t rec_ptr,
-                               struct list_struct *rec, tdb_off_t last_ptr)
+static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, 
+                                 tdb_len_t length, tdb_off_t rec_ptr,
+                                 struct list_struct *rec, tdb_off_t last_ptr)
 {
-       struct list_struct newrec;
-       tdb_off_t newrec_ptr;
+#define MIN_REC_SIZE (sizeof(struct list_struct) + sizeof(tdb_off_t) + 8)
 
-       memset(&newrec, '\0', sizeof(newrec));
+       if (rec->rec_len < length + MIN_REC_SIZE) {
+               /* we have to grab the whole record */
 
-       /* found it - now possibly split it up  */
-       if (rec->rec_len > length + MIN_REC_SIZE) {
-               /* Length of left piece */
-               length = TDB_ALIGN(length, TDB_ALIGNMENT);
-               
-               /* Right piece to go on free list */
-               newrec.rec_len = rec->rec_len - (sizeof(*rec) + length);
-               newrec_ptr = rec_ptr + sizeof(*rec) + length;
-               
-               /* And left record is shortened */
-               rec->rec_len = length;
-       } else {
-               newrec_ptr = 0;
+               /* unlink it from the previous record */
+               if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
+                       return 0;
+               }
+
+               /* mark it not free */
+               rec->magic = TDB_MAGIC;
+               if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+                       return 0;
+               }
+               return rec_ptr;
+       }
+
+       /* we're going to just shorten the existing record */
+       rec->rec_len -= (length + sizeof(*rec));
+       if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+               return 0;
        }
-       
-       /* Remove allocated record from the free list */
-       if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
+       if (update_tailer(tdb, rec_ptr, rec) == -1) {
                return 0;
        }
-       
-       /* Update header: do this before we drop alloc
-          lock, otherwise tdb_free() might try to
-          merge with us, thinking we're free.
-          (Thanks Jeremy Allison). */
+
+       /* and setup the new record */
+       rec_ptr += sizeof(*rec) + rec->rec_len; 
+
+       memset(rec, '\0', sizeof(*rec));
+       rec->rec_len = length;
        rec->magic = TDB_MAGIC;
+
        if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
                return 0;
        }
-       
-       /* Did we create new block? */
-       if (newrec_ptr) {
-               /* Update allocated record tailer (we
-                  shortened it). */
-               if (update_tailer(tdb, rec_ptr, rec) == -1) {
-                       return 0;
-               }
-               
-               /* Free new record */
-               if (tdb_free(tdb, newrec_ptr, &newrec) == -1) {
-                       return 0;
-               }
+
+       if (update_tailer(tdb, rec_ptr, rec) == -1) {
+               return 0;
        }
-       
-       /* all done - return the new record offset */
+
        return rec_ptr;
 }
 
@@ -261,12 +279,14 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_st
                tdb_off_t rec_ptr, last_ptr;
                tdb_len_t rec_len;
        } bestfit;
+       float multiplier = 1.0;
 
        if (tdb_lock(tdb, -1, F_WRLCK) == -1)
                return 0;
 
        /* Extra bytes required for tailer */
        length += sizeof(tdb_off_t);
+       length = TDB_ALIGN(length, TDB_ALIGNMENT);
 
  again:
        last_ptr = FREELIST_TOP;
@@ -295,18 +315,27 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_st
                                bestfit.rec_len = rec->rec_len;
                                bestfit.rec_ptr = rec_ptr;
                                bestfit.last_ptr = last_ptr;
-                               /* consider a fit to be good enough if
-                                  we aren't wasting more than half
-                                  the space */
-                               if (bestfit.rec_len < 2*length) {
-                                       break;
-                               }
                        }
                }
 
                /* move to the next record */
                last_ptr = rec_ptr;
                rec_ptr = rec->next;
+
+               /* if we've found a record that is big enough, then
+                  stop searching if its also not too big. The
+                  definition of 'too big' changes as we scan
+                  through */
+               if (bestfit.rec_len > 0 &&
+                   bestfit.rec_len < length * multiplier) {
+                       break;
+               }
+               
+               /* this multiplier means we only extremely rarely
+                  search more than 50 or so records. At 50 records we
+                  accept records up to 11 times larger than what we
+                  want */
+               multiplier *= 1.05;
        }
 
        if (bestfit.rec_ptr != 0) {
@@ -314,7 +343,8 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_st
                        goto fail;
                }
 
-               newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, rec, bestfit.last_ptr);
+               newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, 
+                                             rec, bestfit.last_ptr);
                tdb_unlock(tdb, -1, F_WRLCK);
                return newrec_ptr;
        }
@@ -328,3 +358,25 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_st
        return 0;
 }
 
+
+
+/* 
+   return the size of the freelist - used to decide if we should repack 
+*/
+int tdb_freelist_size(struct tdb_context *tdb)
+{
+       tdb_off_t ptr;
+       int count=0;
+
+       if (tdb_lock(tdb, -1, F_RDLCK) == -1) {
+               return -1;
+       }
+
+       ptr = FREELIST_TOP;
+       while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) {
+               count++;
+       }
+
+       tdb_unlock(tdb, -1, F_RDLCK);
+       return count;
+}
index 8ab0768883709467876939127a3dc6dddfeb4822..172ab69d8c9e69ae7f160071567c4d885ac7848c 100644 (file)
@@ -101,8 +101,8 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
                                         off+written);
                }
                if (written == -1) {
-                       /* Ensure ecode is set for log fn. */
-                       tdb->ecode = TDB_ERR_IO;
+               /* Ensure ecode is set for log fn. */
+               tdb->ecode = TDB_ERR_IO;
                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d "
                                 "len=%d (%s)\n", off, len, strerror(errno)));
                        return TDB_ERRCODE(TDB_ERR_IO, -1);
@@ -111,8 +111,8 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
                                 "write %d bytes at %d in two attempts\n",
                                 len, off));
                        errno = ENOSPC;
-                       return TDB_ERRCODE(TDB_ERR_IO, -1);
-               }
+               return TDB_ERRCODE(TDB_ERR_IO, -1);
+       }
        }
        return 0;
 }
@@ -230,7 +230,7 @@ void tdb_mmap(struct tdb_context *tdb)
   says to use for mmap expansion */
 static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
 {
-       char buf[1024];
+       char buf[8192];
 
        if (tdb->read_only || tdb->traverse_read) {
                tdb->ecode = TDB_ERR_RDONLY;
@@ -294,7 +294,7 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
 int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
 {
        struct list_struct rec;
-       tdb_off_t offset;
+       tdb_off_t offset, new_size;     
 
        if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
@@ -304,9 +304,11 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
        /* must know about any previous expansions by another process */
        tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
 
-       /* always make room for at least 10 more records, and round
-           the database up to a multiple of the page size */
-       size = TDB_ALIGN(tdb->map_size + size*10, tdb->page_size) - tdb->map_size;
+       /* always make room for at least 100 more records, and at
+           least 25% more space. Round the database up to a multiple
+           of the page size */
+       new_size = MAX(tdb->map_size + size*100, tdb->map_size * 1.25);
+       size = TDB_ALIGN(new_size, tdb->page_size) - tdb->map_size;
 
        if (!(tdb->flags & TDB_INTERNAL))
                tdb_munmap(tdb);
index e3fe888c465f357adb436b7230d8e3070f073a63..f156c0fa7b2e548640d47db23df71c9427ec73ce 100644 (file)
@@ -505,6 +505,9 @@ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
 /* record lock stops delete underneath */
 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
 {
+       if (tdb->global_lock.count) {
+               return 0;
+       }
        return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;
 }
 
@@ -537,6 +540,10 @@ int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
        struct tdb_traverse_lock *i;
        uint32_t count = 0;
 
+       if (tdb->global_lock.count) {
+               return 0;
+       }
+
        if (off == 0)
                return 0;
        for (i = &tdb->travlocks; i; i = i->next)
index 0bd1c91a5eec1333af91d949b17cf202a29540ef..b19e4cea293df769a588db89c71df25529d677ec 100644 (file)
@@ -35,7 +35,7 @@ static struct tdb_context *tdbs = NULL;
 static unsigned int default_tdb_hash(TDB_DATA *key)
 {
        uint32_t value; /* Used to compute the hash value.  */
-       uint32_t i;     /* Used to cycle through random values. */
+       uint32_t   i;   /* Used to cycle through random values. */
 
        /* Set the initial value from the key size. */
        for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
@@ -90,7 +90,7 @@ static int tdb_new_database(struct tdb_context *tdb, int hash_size)
                size -= written;
                written = write(tdb->fd, newdb+written, size);
                if (written == size) {
-                       ret = 0;
+               ret = 0;
                } else if (written >= 0) {
                        /* a second incomplete write - we give up.
                         * guessing the errno... */
@@ -152,6 +152,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        int rev = 0, locked = 0;
        unsigned char *vp;
        uint32_t vertest;
+       unsigned v;
 
        if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
                /* Can't log this */
@@ -178,9 +179,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                tdb->page_size = 0x2000;
        }
 
-       if (open_flags & TDB_VOLATILE) {
-               tdb->max_dead_records = 5;
-       }
+       tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0;
 
        if ((open_flags & O_ACCMODE) == O_WRONLY) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
@@ -215,6 +214,10 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                goto fail;      /* errno set by open(2) */
        }
 
+       /* on exec, don't inherit the fd */
+       v = fcntl(tdb->fd, F_GETFD, 0);
+        fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
+
        /* ensure there is only one process initialising at once */
        if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
@@ -224,6 +227,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
 
        /* we need to zero database if we are the only one with it open */
        if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
+           (!tdb->read_only) &&
            (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {
                open_flags |= O_CREAT;
                if (ftruncate(tdb->fd, 0) == -1) {
@@ -242,7 +246,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                /* its not a valid database - possibly initialise it */
                if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
                        if (errno == 0) {
-                               errno = EIO; /* ie bad format or something */
+                       errno = EIO; /* ie bad format or something */
                        }
                        goto fail;
                }
@@ -283,7 +287,6 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        tdb->map_size = st.st_size;
        tdb->device = st.st_dev;
        tdb->inode = st.st_ino;
-       tdb->max_dead_records = 0;
        tdb_mmap(tdb);
        if (locked) {
                if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
index 0e9d1dbd7412942634d982c92fe3bef57d7bf572..ea5d9ccc6014ff9cd205e42579b48ed1c3390093 100644 (file)
@@ -102,8 +102,7 @@ static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
 }
 
 /* As tdb_find, but if you succeed, keep the lock */
-tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, 
-                                                        uint32_t hash, int locktype,
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
                           struct list_struct *rec)
 {
        uint32_t rec_ptr;
@@ -237,14 +236,15 @@ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
 }
 
 /* actually delete an entry in the database given the offset */
-int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct*rec)
+int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec)
 {
        tdb_off_t last_ptr, i;
        struct list_struct lastrec;
 
        if (tdb->read_only || tdb->traverse_read) return -1;
 
-       if (tdb_write_lock_record(tdb, rec_ptr) == -1) {
+       if (tdb->traverse_write != 0 || 
+           tdb_write_lock_record(tdb, rec_ptr) == -1) {
                /* Someone traversing here: mark it as dead */
                rec->magic = TDB_DEAD_MAGIC;
                return tdb_rec_write(tdb, rec_ptr, rec);
@@ -666,6 +666,16 @@ int tdb_get_flags(struct tdb_context *tdb)
        return tdb->flags;
 }
 
+void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
+{
+       tdb->flags |= flags;
+}
+
+void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
+{
+       tdb->flags &= ~flags;
+}
+
 
 /*
   enable sequence number handling on an open tdb
@@ -674,3 +684,62 @@ void tdb_enable_seqnum(struct tdb_context *tdb)
 {
        tdb->flags |= TDB_SEQNUM;
 }
+
+
+/*
+  wipe the entire database, deleting all records. This can be done
+  very fast by using a global lock. The entire data portion of the
+  file becomes a single entry in the freelist.
+ */
+int tdb_wipe_all(struct tdb_context *tdb)
+{
+       int i;
+       tdb_off_t offset = 0;
+       ssize_t data_len;
+
+       if (tdb_lockall(tdb) != 0) {
+               return -1;
+       }
+
+       /* wipe the hashes */
+       for (i=0;i<tdb->header.hash_size;i++) {
+               if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
+                       goto failed;
+               }
+       }
+
+       /* wipe the freelist */
+       if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
+               goto failed;
+       }
+
+       if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &offset) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write recovery head\n"));
+               goto failed;            
+       }
+
+       /* add all the rest of the file to the freelist */
+       data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size)) - sizeof(struct list_struct);
+       if (data_len > 0) {
+               struct list_struct rec;
+               memset(&rec,'\0',sizeof(rec));
+               rec.rec_len = data_len;
+               if (tdb_free(tdb, TDB_DATA_START(tdb->header.hash_size), &rec) == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to add free record\n"));
+                       goto failed;
+               }
+       }
+
+       if (tdb_unlockall(tdb) != 0) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
+               goto failed;
+       }
+
+       return 0;
+
+failed:
+       tdb_unlockall(tdb);
+       return -1;
+}
index 00bd0eb537a61f3639e577bd55bb2d8465c2876b..ffac89ff0e315195b3defdebc35184ef7ab6a038 100644 (file)
 typedef uint32_t tdb_len_t;
 typedef uint32_t tdb_off_t;
 
+#ifndef offsetof
+#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
+#endif
+
 #define TDB_MAGIC_FOOD "TDB file\n"
 #define TDB_VERSION (0x26011967 + 6)
 #define TDB_MAGIC (0x26011999U)
@@ -45,7 +49,6 @@ typedef uint32_t tdb_off_t;
 #define TDB_DEAD_MAGIC (0xFEE1DEAD)
 #define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
 #define TDB_ALIGNMENT 4
-#define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGNMENT)
 #define DEFAULT_HASH_SIZE 131
 #define FREELIST_TOP (sizeof(struct tdb_header))
 #define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
@@ -54,7 +57,7 @@ typedef uint32_t tdb_off_t;
 #define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
 #define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t))
 #define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t))
-#define TDB_DATA_START(hash_size) TDB_HASH_TOP(hash_size-1)
+#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t))
 #define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start)
 #define TDB_SEQNUM_OFS    offsetof(struct tdb_header, sequence_number)
 #define TDB_PAD_BYTE 0x42
@@ -144,6 +147,7 @@ struct tdb_context {
        tdb_len_t map_size; /* how much space has been mapped */
        int read_only; /* opened read-only */
        int traverse_read; /* read-only traversal */
+       int traverse_write; /* read-write traversal */
        struct tdb_lock_type global_lock;
        int num_lockrecs;
        struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
@@ -173,6 +177,7 @@ struct tdb_context {
 int tdb_munmap(struct tdb_context *tdb);
 void tdb_mmap(struct tdb_context *tdb);
 int tdb_lock(struct tdb_context *tdb, int list, int ltype);
+int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
 int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len);
 int tdb_transaction_lock(struct tdb_context *tdb, int ltype);
index 7eaacf7a164fbad3052c8b211ca8f547af3ba3be..c3e7a4e2c065d55492fbc9ddb3c1ff6946bf7057 100644 (file)
 
 */
 
-struct tdb_transaction_el {
-       struct tdb_transaction_el *next, *prev;
-       tdb_off_t offset;
-       tdb_len_t length;
-       unsigned char *data;
-};
 
 /*
   hold the context of any current transaction
@@ -105,12 +99,12 @@ struct tdb_transaction {
        /* the original io methods - used to do IOs to the real db */
        const struct tdb_methods *io_methods;
 
-       /* the list of transaction elements. We use a doubly linked
-          list with a last pointer to allow us to keep the list
-          ordered, with first element at the front of the list. It
-          needs to be doubly linked as the read/write traversals need
-          to be backwards, while the commit needs to be forwards */
-       struct tdb_transaction_el *elements, *elements_last;
+       /* the list of transaction blocks. When a block is first
+          written to, it gets created in this list */
+       uint8_t **blocks;
+       uint32_t num_blocks;
+       uint32_t block_size;      /* bytes in each block */
+       uint32_t last_block_size; /* number of valid bytes in the last block */
 
        /* non-zero when an internal transaction error has
           occurred. All write operations will then fail until the
@@ -134,52 +128,48 @@ struct tdb_transaction {
 static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
                            tdb_len_t len, int cv)
 {
-       struct tdb_transaction_el *el;
-
-       /* we need to walk the list backwards to get the most recent data */
-       for (el=tdb->transaction->elements_last;el;el=el->prev) {
-               tdb_len_t partial;
+       uint32_t blk;
 
-               if (off+len <= el->offset) {
-                       continue;
-               }
-               if (off >= el->offset + el->length) {
-                       continue;
+       /* break it down into block sized ops */
+       while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+               tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+               if (transaction_read(tdb, off, buf, len2, cv) != 0) {
+                       return -1;
                }
+               len -= len2;
+               off += len2;
+               buf = (void *)(len2 + (char *)buf);
+       }
 
-               /* an overlapping read - needs to be split into up to
-                  2 reads and a memcpy */
-               if (off < el->offset) {
-                       partial = el->offset - off;
-                       if (transaction_read(tdb, off, buf, partial, cv) != 0) {
-                               goto fail;
-                       }
-                       len -= partial;
-                       off += partial;
-                       buf = (void *)(partial + (char *)buf);
-               }
-               if (off + len <= el->offset + el->length) {
-                       partial = len;
-               } else {
-                       partial = el->offset + el->length - off;
-               }
-               memcpy(buf, el->data + (off - el->offset), partial);
-               if (cv) {
-                       tdb_convert(buf, len);
-               }
-               len -= partial;
-               off += partial;
-               buf = (void *)(partial + (char *)buf);
-               
-               if (len != 0 && transaction_read(tdb, off, buf, len, cv) != 0) {
+       if (len == 0) {
+               return 0;
+       }
+
+       blk = off / tdb->transaction->block_size;
+
+       /* see if we have it in the block list */
+       if (tdb->transaction->num_blocks <= blk ||
+           tdb->transaction->blocks[blk] == NULL) {
+               /* nope, do a real read */
+               if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) {
                        goto fail;
                }
-
                return 0;
        }
 
-       /* its not in the transaction elements - do a real read */
-       return tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv);
+       /* it is in the block list. Now check for the last block */
+       if (blk == tdb->transaction->num_blocks-1) {
+               if (len > tdb->transaction->last_block_size) {
+                       goto fail;
+               }
+       }
+       
+       /* now copy it out of this block */
+       memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len);
+       if (cv) {
+               tdb_convert(buf, len);
+       }
+       return 0;
 
 fail:
        TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len));
@@ -195,12 +185,8 @@ fail:
 static int transaction_write(struct tdb_context *tdb, tdb_off_t off, 
                             const void *buf, tdb_len_t len)
 {
-       struct tdb_transaction_el *el, *best_el=NULL;
+       uint32_t blk;
 
-       if (len == 0) {
-               return 0;
-       }
-       
        /* if the write is to a hash head, then update the transaction
           hash heads */
        if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
@@ -209,110 +195,142 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
                memcpy(&tdb->transaction->hash_heads[chain], buf, len);
        }
 
-       /* first see if we can replace an existing entry */
-       for (el=tdb->transaction->elements_last;el;el=el->prev) {
-               tdb_len_t partial;
-
-               if (best_el == NULL && off == el->offset+el->length) {
-                       best_el = el;
-               }
-
-               if (off+len <= el->offset) {
-                       continue;
+       /* break it up into block sized chunks */
+       while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+               tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+               if (transaction_write(tdb, off, buf, len2) != 0) {
+                       return -1;
                }
-               if (off >= el->offset + el->length) {
-                       continue;
+               len -= len2;
+               off += len2;
+               if (buf != NULL) {
+                       buf = (const void *)(len2 + (const char *)buf);
                }
+       }
 
-               /* an overlapping write - needs to be split into up to
-                  2 writes and a memcpy */
-               if (off < el->offset) {
-                       partial = el->offset - off;
-                       if (transaction_write(tdb, off, buf, partial) != 0) {
-                               goto fail;
-                       }
-                       len -= partial;
-                       off += partial;
-                       buf = (const void *)(partial + (const char *)buf);
-               }
-               if (off + len <= el->offset + el->length) {
-                       partial = len;
+       if (len == 0) {
+               return 0;
+       }
+
+       blk = off / tdb->transaction->block_size;
+       off = off % tdb->transaction->block_size;
+
+       if (tdb->transaction->num_blocks <= blk) {
+               uint8_t **new_blocks;
+               /* expand the blocks array */
+               if (tdb->transaction->blocks == NULL) {
+                       new_blocks = (uint8_t **)malloc(
+                               (blk+1)*sizeof(uint8_t *));
                } else {
-                       partial = el->offset + el->length - off;
+                       new_blocks = (uint8_t **)realloc(
+                               tdb->transaction->blocks,
+                               (blk+1)*sizeof(uint8_t *));
                }
-               memcpy(el->data + (off - el->offset), buf, partial);
-               len -= partial;
-               off += partial;
-               buf = (const void *)(partial + (const char *)buf);
-               
-               if (len != 0 && transaction_write(tdb, off, buf, len) != 0) {
+               if (new_blocks == NULL) {
+                       tdb->ecode = TDB_ERR_OOM;
                        goto fail;
                }
-
-               return 0;
+               memset(&new_blocks[tdb->transaction->num_blocks], 0, 
+                      (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *));
+               tdb->transaction->blocks = new_blocks;
+               tdb->transaction->num_blocks = blk+1;
+               tdb->transaction->last_block_size = 0;
        }
 
-       /* see if we can append the new entry to an existing entry */
-       if (best_el && best_el->offset + best_el->length == off && 
-           (off+len < tdb->transaction->old_map_size ||
-            off > tdb->transaction->old_map_size)) {
-               unsigned char *data = best_el->data;
-               el = best_el;
-               el->data = (unsigned char *)realloc(el->data,
-                                                   el->length + len);
-               if (el->data == NULL) {
+       /* allocate and fill a block? */
+       if (tdb->transaction->blocks[blk] == NULL) {
+               tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1);
+               if (tdb->transaction->blocks[blk] == NULL) {
                        tdb->ecode = TDB_ERR_OOM;
                        tdb->transaction->transaction_error = 1;
-                       el->data = data;
-                       return -1;
+                       return -1;                      
                }
-               if (buf) {
-                       memcpy(el->data + el->length, buf, len);
-               } else {
-                       memset(el->data + el->length, TDB_PAD_BYTE, len);
+               if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) {
+                       tdb_len_t len2 = tdb->transaction->block_size;
+                       if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) {
+                               len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size);
+                       }
+                       if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size, 
+                                                                  tdb->transaction->blocks[blk], 
+                                                                  len2, 0) != 0) {
+                               SAFE_FREE(tdb->transaction->blocks[blk]);                               
+                               tdb->ecode = TDB_ERR_IO;
+                               goto fail;
+                       }
+                       if (blk == tdb->transaction->num_blocks-1) {
+                               tdb->transaction->last_block_size = len2;
+                       }                       
                }
-               el->length += len;
-               return 0;
-       }
-
-       /* add a new entry at the end of the list */
-       el = (struct tdb_transaction_el *)malloc(sizeof(*el));
-       if (el == NULL) {
-               tdb->ecode = TDB_ERR_OOM;
-               tdb->transaction->transaction_error = 1;                
-               return -1;
-       }
-       el->next = NULL;
-       el->prev = tdb->transaction->elements_last;
-       el->offset = off;
-       el->length = len;
-       el->data = (unsigned char *)malloc(len);
-       if (el->data == NULL) {
-               free(el);
-               tdb->ecode = TDB_ERR_OOM;
-               tdb->transaction->transaction_error = 1;                
-               return -1;
        }
-       if (buf) {
-               memcpy(el->data, buf, len);
+       
+       /* overwrite part of an existing block */
+       if (buf == NULL) {
+               memset(tdb->transaction->blocks[blk] + off, 0, len);
        } else {
-               memset(el->data, TDB_PAD_BYTE, len);
+               memcpy(tdb->transaction->blocks[blk] + off, buf, len);
        }
-       if (el->prev) {
-               el->prev->next = el;
-       } else {
-               tdb->transaction->elements = el;
+       if (blk == tdb->transaction->num_blocks-1) {
+               if (len + off > tdb->transaction->last_block_size) {
+                       tdb->transaction->last_block_size = len + off;
+               }
        }
-       tdb->transaction->elements_last = el;
+
        return 0;
 
 fail:
-       TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", off, len));
-       tdb->ecode = TDB_ERR_IO;
+       TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", 
+                (blk*tdb->transaction->block_size) + off, len));
        tdb->transaction->transaction_error = 1;
        return -1;
 }
 
+
+/*
+  write while in a transaction - this varient never expands the transaction blocks, it only
+  updates existing blocks. This means it cannot change the recovery size
+*/
+static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off, 
+                                     const void *buf, tdb_len_t len)
+{
+       uint32_t blk;
+
+       /* break it up into block sized chunks */
+       while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+               tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+               if (transaction_write_existing(tdb, off, buf, len2) != 0) {
+                       return -1;
+               }
+               len -= len2;
+               off += len2;
+               if (buf != NULL) {
+                       buf = (const void *)(len2 + (const char *)buf);
+               }
+       }
+
+       if (len == 0) {
+               return 0;
+       }
+
+       blk = off / tdb->transaction->block_size;
+       off = off % tdb->transaction->block_size;
+
+       if (tdb->transaction->num_blocks <= blk ||
+           tdb->transaction->blocks[blk] == NULL) {
+               return 0;
+       }
+
+       if (blk == tdb->transaction->num_blocks-1 &&
+           off + len > tdb->transaction->last_block_size) {
+               len = tdb->transaction->last_block_size - off;
+       }
+
+       /* overwrite part of an existing block */
+       memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+
+       return 0;
+}
+
+
 /*
   accelerated hash chain head search, using the cached hash heads
 */
@@ -419,10 +437,14 @@ int tdb_transaction_start(struct tdb_context *tdb)
                return -1;
        }
 
+       /* a page at a time seems like a reasonable compromise between compactness and efficiency */
+       tdb->transaction->block_size = tdb->page_size;
+
        /* get the transaction write lock. This is a blocking lock. As
           discussed with Volker, there are a number of ways we could
           make this async, which we will probably do in the future */
        if (tdb_transaction_lock(tdb, F_WRLCK) == -1) {
+               SAFE_FREE(tdb->transaction->blocks);
                SAFE_FREE(tdb->transaction);
                return -1;
        }
@@ -460,21 +482,12 @@ int tdb_transaction_start(struct tdb_context *tdb)
        tdb->transaction->io_methods = tdb->methods;
        tdb->methods = &transaction_methods;
 
-       /* by calling this transaction write here, we ensure that we don't grow the
-          transaction linked list due to hash table updates */
-       if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads, 
-                             TDB_HASHTABLE_SIZE(tdb)) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to prime hash table\n"));
-               tdb->ecode = TDB_ERR_IO;
-               tdb->methods = tdb->transaction->io_methods;
-               goto fail;
-       }
-
        return 0;
        
 fail:
        tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
        tdb_transaction_unlock(tdb);
+       SAFE_FREE(tdb->transaction->blocks);
        SAFE_FREE(tdb->transaction->hash_heads);
        SAFE_FREE(tdb->transaction);
        return -1;
@@ -486,6 +499,8 @@ fail:
 */
 int tdb_transaction_cancel(struct tdb_context *tdb)
 {      
+       int i;
+
        if (tdb->transaction == NULL) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
                return -1;
@@ -499,13 +514,13 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
 
        tdb->map_size = tdb->transaction->old_map_size;
 
-       /* free all the transaction elements */
-       while (tdb->transaction->elements) {
-               struct tdb_transaction_el *el = tdb->transaction->elements;
-               tdb->transaction->elements = el->next;
-               free(el->data);
-               free(el);
+       /* free all the transaction blocks */
+       for (i=0;i<tdb->transaction->num_blocks;i++) {
+               if (tdb->transaction->blocks[i] != NULL) {
+                       free(tdb->transaction->blocks[i]);
+               }
        }
+       SAFE_FREE(tdb->transaction->blocks);
 
        /* remove any global lock created during the transaction */
        if (tdb->global_lock.count != 0) {
@@ -515,7 +530,6 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
 
        /* remove any locks created during the transaction */
        if (tdb->num_locks != 0) {
-               int i;
                for (i=0;i<tdb->num_lockrecs;i++) {
                        tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list,
                                   F_UNLCK,F_SETLKW, 0, 1);
@@ -567,16 +581,24 @@ static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t
 */
 static tdb_len_t tdb_recovery_size(struct tdb_context *tdb)
 {
-       struct tdb_transaction_el *el;
        tdb_len_t recovery_size = 0;
+       int i;
 
        recovery_size = sizeof(uint32_t);
-       for (el=tdb->transaction->elements;el;el=el->next) {
-               if (el->offset >= tdb->transaction->old_map_size) {
+       for (i=0;i<tdb->transaction->num_blocks;i++) {
+               if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) {
+                       break;
+               }
+               if (tdb->transaction->blocks[i] == NULL) {
                        continue;
                }
-               recovery_size += 2*sizeof(tdb_off_t) + el->length;
-       }
+               recovery_size += 2*sizeof(tdb_off_t);
+               if (i == tdb->transaction->num_blocks-1) {
+                       recovery_size += tdb->transaction->last_block_size;
+               } else {
+                       recovery_size += tdb->transaction->block_size;
+               }
+       }       
 
        return recovery_size;
 }
@@ -658,6 +680,10 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
                return -1;
        }
+       if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+               return -1;
+       }
 
        return 0;
 }
@@ -669,7 +695,6 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
 static int transaction_setup_recovery(struct tdb_context *tdb, 
                                      tdb_off_t *magic_offset)
 {
-       struct tdb_transaction_el *el;
        tdb_len_t recovery_size;
        unsigned char *data, *p;
        const struct tdb_methods *methods = tdb->transaction->io_methods;
@@ -677,6 +702,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
        tdb_off_t recovery_offset, recovery_max_size;
        tdb_off_t old_map_size = tdb->transaction->old_map_size;
        uint32_t magic, tailer;
+       int i;
 
        /*
          check that the recovery area has enough space
@@ -704,30 +730,43 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
        /* build the recovery data into a single blob to allow us to do a single
           large write, which should be more efficient */
        p = data + sizeof(*rec);
-       for (el=tdb->transaction->elements;el;el=el->next) {
-               if (el->offset >= old_map_size) {
+       for (i=0;i<tdb->transaction->num_blocks;i++) {
+               tdb_off_t offset;
+               tdb_len_t length;
+
+               if (tdb->transaction->blocks[i] == NULL) {
+                       continue;
+               }
+
+               offset = i * tdb->transaction->block_size;
+               length = tdb->transaction->block_size;
+               if (i == tdb->transaction->num_blocks-1) {
+                       length = tdb->transaction->last_block_size;
+               }
+               
+               if (offset >= old_map_size) {
                        continue;
                }
-               if (el->offset + el->length > tdb->transaction->old_map_size) {
+               if (offset + length > tdb->transaction->old_map_size) {
                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n"));
                        free(data);
                        tdb->ecode = TDB_ERR_CORRUPT;
                        return -1;
                }
-               memcpy(p, &el->offset, 4);
-               memcpy(p+4, &el->length, 4);
+               memcpy(p, &offset, 4);
+               memcpy(p+4, &length, 4);
                if (DOCONV()) {
                        tdb_convert(p, 8);
                }
                /* the recovery area contains the old data, not the
                   new data, so we have to call the original tdb_read
                   method to get it */
-               if (methods->tdb_read(tdb, el->offset, p + 8, el->length, 0) != 0) {
+               if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) {
                        free(data);
                        tdb->ecode = TDB_ERR_IO;
                        return -1;
                }
-               p += 8 + el->length;
+               p += 8 + length;
        }
 
        /* and the tailer */
@@ -742,6 +781,12 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
+       if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n"));
+               free(data);
+               tdb->ecode = TDB_ERR_IO;
+               return -1;
+       }
 
        /* as we don't have ordered writes, we have to sync the recovery
           data before we update the magic to indicate that the recovery
@@ -763,6 +808,11 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
+       if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n"));
+               tdb->ecode = TDB_ERR_IO;
+               return -1;
+       }
 
        /* ensure the recovery magic marker is on disk */
        if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) {
@@ -780,6 +830,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        const struct tdb_methods *methods;
        tdb_off_t magic_offset = 0;
        uint32_t zero = 0;
+       int i;
 
        if (tdb->transaction == NULL) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
@@ -793,13 +844,14 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                return -1;
        }
 
+
        if (tdb->transaction->nesting != 0) {
                tdb->transaction->nesting--;
                return 0;
        }               
 
        /* check for a null transaction */
-       if (tdb->transaction->elements == NULL) {
+       if (tdb->transaction->blocks == NULL) {
                tdb_transaction_cancel(tdb);
                return 0;
        }
@@ -858,10 +910,21 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        }
 
        /* perform all the writes */
-       while (tdb->transaction->elements) {
-               struct tdb_transaction_el *el = tdb->transaction->elements;
+       for (i=0;i<tdb->transaction->num_blocks;i++) {
+               tdb_off_t offset;
+               tdb_len_t length;
+
+               if (tdb->transaction->blocks[i] == NULL) {
+                       continue;
+               }
 
-               if (methods->tdb_write(tdb, el->offset, el->data, el->length) == -1) {
+               offset = i * tdb->transaction->block_size;
+               length = tdb->transaction->block_size;
+               if (i == tdb->transaction->num_blocks-1) {
+                       length = tdb->transaction->last_block_size;
+               }
+
+               if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) {
                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
                        
                        /* we've overwritten part of the data and
@@ -876,11 +939,12 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
                        return -1;
                }
-               tdb->transaction->elements = el->next;
-               free(el->data); 
-               free(el);
+               SAFE_FREE(tdb->transaction->blocks[i]);
        } 
 
+       SAFE_FREE(tdb->transaction->blocks);
+       tdb->transaction->num_blocks = 0;
+
        if (!(tdb->flags & TDB_NOSYNC)) {
                /* ensure the new data is on disk */
                if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
@@ -919,6 +983,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        /* use a transaction cancel to free memory and remove the
           transaction locks */
        tdb_transaction_cancel(tdb);
+
        return 0;
 }
 
index 6fc576a55a324b942973356cc371a352a1cb88fb..07b0c238587eb85fe3945b61b71dbd9dd0729d58 100644 (file)
@@ -223,6 +223,9 @@ int tdb_traverse_read(struct tdb_context *tdb,
 /*
   a write style traverse - needs to get the transaction lock to
   prevent deadlocks
+
+  WARNING: The data buffer given to the callback fn does NOT meet the
+  alignment restrictions malloc gives you.
 */
 int tdb_traverse(struct tdb_context *tdb, 
                 tdb_traverse_func fn, void *private_data)
@@ -238,7 +241,9 @@ int tdb_traverse(struct tdb_context *tdb,
                return -1;
        }
 
+       tdb->traverse_write++;
        ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+       tdb->traverse_write--;
 
        tdb_transaction_unlock(tdb);
 
@@ -330,3 +335,4 @@ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
        return key;
 }
+
index b31ce36ab149b7416043990de4f2eda528e66637..63fcf5e049b13ef01fc3cae78c7326be332287a8 100644 (file)
@@ -130,6 +130,9 @@ int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
    a non-zero return value from fn() indicates that the traversal
    should stop. Traversal callbacks may not start transactions.
 
+   WARNING: The data buffer given to the callback fn does NOT meet the
+   alignment restrictions malloc gives you.
+
 ----------------------------------------------------------------------
 int tdb_traverse_read(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
                      TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
index 7de4c419a81ea0c67b6faadfc22b0208c44a0c6b..0008085de540b525bb02fc1ff178d06bc898a02d 100644 (file)
@@ -32,9 +32,9 @@ extern "C" {
 
 
 /* flags to tdb_store() */
-#define TDB_REPLACE 1
-#define TDB_INSERT 2
-#define TDB_MODIFY 3
+#define TDB_REPLACE 1          /* Unused */
+#define TDB_INSERT 2           /* Don't overwrite an existing entry */
+#define TDB_MODIFY 3           /* Don't create an existing entry    */
 
 /* flags for tdb_open() */
 #define TDB_DEFAULT 0 /* just a readability place holder */
@@ -135,6 +135,8 @@ int tdb_get_seqnum(struct tdb_context *tdb);
 int tdb_hash_size(struct tdb_context *tdb);
 size_t tdb_map_size(struct tdb_context *tdb);
 int tdb_get_flags(struct tdb_context *tdb);
+void tdb_add_flags(struct tdb_context *tdb, unsigned flag);
+void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
 void tdb_enable_seqnum(struct tdb_context *tdb);
 void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
 
@@ -153,6 +155,8 @@ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr)
 void tdb_dump_all(struct tdb_context *tdb);
 int tdb_printfreelist(struct tdb_context *tdb);
 int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
+int tdb_wipe_all(struct tdb_context *tdb);
+int tdb_freelist_size(struct tdb_context *tdb);
 
 extern TDB_DATA tdb_null;
 
diff --git a/source/lib/tdb/python/tdbdump.py b/source/lib/tdb/python/tdbdump.py
new file mode 100644 (file)
index 0000000..d759d77
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/python
<