Hello community,

here is the log from the commit of package tdb for openSUSE:Factory checked in 
at 2015-07-27 09:09:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tdb (Old)
 and      /work/SRC/openSUSE:Factory/.tdb.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tdb"

Changes:
--------
--- /work/SRC/openSUSE:Factory/tdb/tdb.changes  2015-07-05 17:53:14.000000000 
+0200
+++ /work/SRC/openSUSE:Factory/.tdb.new/tdb.changes     2015-07-27 
09:09:34.000000000 +0200
@@ -1,0 +2,8 @@
+Wed Jul 22 07:37:56 UTC 2015 - [email protected]
+
+- Update to version 1.3.7.
+  + first fix deadlock in the interaction between fcntl and mutex locking;
+    (bso#11381)
+  + improved python3 bindings
+
+-------------------------------------------------------------------

Old:
----
  tdb-1.3.6.tar.asc
  tdb-1.3.6.tar.gz

New:
----
  tdb-1.3.7.tar.asc
  tdb-1.3.7.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ tdb.spec ++++++
--- /var/tmp/diff_new_pack.TvP3Xg/_old  2015-07-27 09:09:35.000000000 +0200
+++ /var/tmp/diff_new_pack.TvP3Xg/_new  2015-07-27 09:09:35.000000000 +0200
@@ -34,7 +34,7 @@
 %endif
 BuildRequires:  python-devel
 Url:            http://tdb.samba.org/
-Version:        1.3.6
+Version:        1.3.7
 Release:        0
 Summary:        Samba Trivial Database
 License:        GPL-3.0+
@@ -178,5 +178,6 @@
 %files -n python-tdb
 %defattr(-,root,root,-)
 %{python_sitearch}/tdb.so
+%{python_sitearch}/_tdb_text.py*
 
 %changelog

++++++ tdb-1.3.6.tar.gz -> tdb-1.3.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/ABI/tdb-1.3.7.sigs 
new/tdb-1.3.7/ABI/tdb-1.3.7.sigs
--- old/tdb-1.3.6/ABI/tdb-1.3.7.sigs    1970-01-01 01:00:00.000000000 +0100
+++ new/tdb-1.3.7/ABI/tdb-1.3.7.sigs    2015-07-21 22:35:18.000000000 +0200
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), 
void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const 
struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, 
TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), 
void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct 
tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/_tdb_text.py new/tdb-1.3.7/_tdb_text.py
--- old/tdb-1.3.6/_tdb_text.py  1970-01-01 01:00:00.000000000 +0100
+++ new/tdb-1.3.7/_tdb_text.py  2015-07-21 22:32:32.000000000 +0200
@@ -0,0 +1,138 @@
+# Text wrapper for tdb bindings
+#
+# Copyright (C) 2015 Petr Viktorin <[email protected]>
+# Published under the GNU LGPLv3 or later
+
+import sys
+import functools
+
+import tdb
+
+
+class TdbTextWrapper(object):
+    """Text interface for a TDB file"""
+
+    def __init__(self, tdb):
+        self._tdb = tdb
+
+    @property
+    def raw(self):
+        return self._tdb
+
+    def get(self, key):
+        key = key.encode('utf-8')
+        result = self._tdb.get(key)
+        if result is not None:
+            return result.decode('utf-8')
+
+    def append(self, key, value):
+        key = key.encode('utf-8')
+        value = value.encode('utf-8')
+        self._tdb.append(key, value)
+
+    def firstkey(self):
+        result = self._tdb.firstkey()
+        if result:
+            return result.decode('utf-8')
+
+    def nextkey(self, key):
+        key = key.encode('utf-8')
+        result = self._tdb.nextkey(key)
+        if result is not None:
+            return result.decode('utf-8')
+
+    def delete(self, key):
+        key = key.encode('utf-8')
+        self._tdb.delete(key)
+
+    def store(self, key, value):
+        key = key.encode('utf-8')
+        value = value.encode('utf-8')
+        self._tdb.store(key, value)
+
+    def __iter__(self):
+        for key in iter(self._tdb):
+            yield key.decode('utf-8')
+
+    def __getitem__(self, key):
+        key = key.encode('utf-8')
+        result = self._tdb[key]
+        return result.decode('utf-8')
+
+    def __contains__(self, key):
+        key = key.encode('utf-8')
+        return key in self._tdb
+
+    def __repr__(self):
+        return '<TdbTextWrapper for %r>' % self._tdb
+
+    def __setitem__(self, key, value):
+        key = key.encode('utf-8')
+        value = value.encode('utf-8')
+        self._tdb[key] = value
+
+    def __delitem__(self, key):
+        key = key.encode('utf-8')
+        del self._tdb[key]
+
+    if sys.version_info > (3, 0):
+        keys = __iter__
+    else:
+        iterkeys = __iter__
+        has_key = __contains__
+
+
+## Add wrappers for functions and getters that don't deal with text
+
+def _add_wrapper(name):
+    orig = getattr(tdb.Tdb, name)
+
+    def wrapper(self, *args, **kwargs):
+        return orig(self._tdb, *args, **kwargs)
+    wrapper.__name__ = orig.__name__
+    wrapper.__doc__ = orig.__doc__
+
+    setattr(TdbTextWrapper, name, wrapper)
+
+for name in ("transaction_cancel",
+             "transaction_commit",
+             "transaction_prepare_commit",
+             "transaction_start",
+             "reopen",
+             "lock_all",
+             "unlock_all",
+             "read_lock_all",
+             "read_unlock_all",
+             "close",
+             "add_flags",
+             "remove_flags",
+             "clear",
+             "repack",
+             "enable_seqnum",
+             "increment_seqnum_nonblock",
+            ):
+    _add_wrapper(name)
+
+
+def _add_getter(name):
+    orig = getattr(tdb.Tdb, name)
+    doc = orig.__doc__
+
+    def getter(self):
+        return getattr(self._tdb, name)
+
+    def setter(self, value):
+        return setattr(self._tdb, name, value)
+
+    setattr(TdbTextWrapper, name, property(getter, setter, doc=doc))
+
+for name in ("hash_size",
+             "map_size",
+             "freelist_size",
+             "flags",
+             "max_dead",
+             "filename",
+             "seqnum",
+             "text",
+            ):
+    _add_getter(name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/samba_bundled.py 
new/tdb-1.3.7/buildtools/wafsamba/samba_bundled.py
--- old/tdb-1.3.6/buildtools/wafsamba/samba_bundled.py  2014-12-22 
09:17:09.000000000 +0100
+++ new/tdb-1.3.7/buildtools/wafsamba/samba_bundled.py  2015-07-21 
22:32:32.000000000 +0200
@@ -190,7 +190,7 @@
         pkg = libname
 
     # try pkgconfig first
-    if (conf.check_cfg(package=pkg,
+    if (conf.CHECK_CFG(package=pkg,
                       args='"%s >= %s" --cflags --libs' % (pkg, minversion),
                       msg=msg, uselib_store=uselib_store) and
         check_functions_headers_code()):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/samba_deps.py 
new/tdb-1.3.7/buildtools/wafsamba/samba_deps.py
--- old/tdb-1.3.6/buildtools/wafsamba/samba_deps.py     2014-11-29 
11:30:57.000000000 +0100
+++ new/tdb-1.3.7/buildtools/wafsamba/samba_deps.py     2015-07-21 
22:32:32.000000000 +0200
@@ -964,7 +964,8 @@
 savedeps_inputs  = ['samba_deps', 'samba_includes', 'local_include', 
'local_include_first', 'samba_cflags',
                     'source', 'grouping_library', 'samba_ldflags', 
'allow_undefined_symbols',
                     'use_global_deps', 'global_include' ]
-savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 
'ccflags', 'ldflags', 'samba_deps_extended']
+savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes',
+                    'ccflags', 'ldflags', 'samba_deps_extended', 'final_libs']
 savedeps_outenv  = ['INC_PATHS']
 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 
'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
 savedeps_caches  = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 
'SYSLIB_DEPS']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/samba_python.py 
new/tdb-1.3.7/buildtools/wafsamba/samba_python.py
--- old/tdb-1.3.6/buildtools/wafsamba/samba_python.py   2015-06-13 
03:01:31.000000000 +0200
+++ new/tdb-1.3.7/buildtools/wafsamba/samba_python.py   2015-07-21 
22:32:32.000000000 +0200
@@ -9,6 +9,10 @@
 @conf
 def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
     # enable tool to build python extensions
+    if conf.env.HAVE_PYTHON_H:
+        conf.check_python_version(version)
+        return
+
     interpreters = []
 
     if conf.env['EXTRA_PYTHON']:
@@ -21,7 +25,7 @@
         try:
             conf.check_python_version((3, 3, 0))
         except Exception:
-            warn('extra-python needs to be Python 3.3 or later')
+            Logs.warn('extra-python needs to be Python 3.3 or later')
             raise
         interpreters.append(conf.env['PYTHON'])
         conf.setenv('default')
@@ -55,6 +59,10 @@
     else:
         conf.msg("python headers", "using cache")
 
+    # we don't want PYTHONDIR in config.h, as otherwise changing
+    # --prefix causes a complete rebuild
+    del(conf.env.defines['PYTHONDIR'])
+    del(conf.env.defines['PYTHONARCHDIR'])
 
 def _check_python_headers(conf, mandatory):
     conf.check_python_headers(mandatory=mandatory)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/wafsamba.py 
new/tdb-1.3.7/buildtools/wafsamba/wafsamba.py
--- old/tdb-1.3.6/buildtools/wafsamba/wafsamba.py       2015-06-13 
03:00:10.000000000 +0200
+++ new/tdb-1.3.7/buildtools/wafsamba/wafsamba.py       2015-07-21 
22:32:32.000000000 +0200
@@ -242,6 +242,8 @@
                                     bundled_extension, private_library)
 
     ldflags = TO_LIST(ldflags)
+    if bld.env['ENABLE_RELRO'] is True:
+        ldflags.extend(TO_LIST('-Wl,-z,relro,-z,now'))
 
     features = 'cc cshlib symlink_lib install_lib'
     if pyext:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/common/traverse.c 
new/tdb-1.3.7/common/traverse.c
--- old/tdb-1.3.6/common/traverse.c     2014-10-01 11:22:21.000000000 +0200
+++ new/tdb-1.3.7/common/traverse.c     2015-07-21 22:32:32.000000000 +0200
@@ -245,13 +245,25 @@
                 tdb_traverse_func fn, void *private_data)
 {
        struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
+       enum tdb_lock_flags lock_flags;
        int ret;
 
        if (tdb->read_only || tdb->traverse_read) {
                return tdb_traverse_read(tdb, fn, private_data);
        }
 
-       if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) {
+       lock_flags = TDB_LOCK_WAIT;
+
+       if (tdb->allrecord_lock.count != 0) {
+               /*
+                * This avoids a deadlock between tdb_lockall() and
+                * tdb_traverse(). See
+                * https://bugzilla.samba.org/show_bug.cgi?id=11381
+                */
+               lock_flags = TDB_LOCK_NOWAIT;
+       }
+
+       if (tdb_transaction_lock(tdb, F_WRLCK, lock_flags)) {
                return -1;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/lib/replace/replace.c 
new/tdb-1.3.7/lib/replace/replace.c
--- old/tdb-1.3.6/lib/replace/replace.c 2015-04-29 11:20:16.000000000 +0200
+++ new/tdb-1.3.7/lib/replace/replace.c 2015-07-21 22:32:32.000000000 +0200
@@ -518,11 +518,10 @@
 }
 #else
 #ifdef HAVE_BSD_STRTOLL
-#ifdef HAVE_STRTOQ
 long long int rep_strtoll(const char *str, char **endptr, int base)
 {
-       long long int nb = strtoq(str, endptr, base);
-       /* In linux EINVAL is only returned if base is not ok */
+       long long int nb = strtoll(str, endptr, base);
+       /* With glibc EINVAL is only returned if base is not ok */
        if (errno == EINVAL) {
                if (base == 0 || (base >1 && base <37)) {
                        /* Base was ok so it's because we were not
@@ -534,9 +533,6 @@
        }
        return nb;
 }
-#else
-#error "You need the strtoq function"
-#endif /* HAVE_STRTOQ */
 #endif /* HAVE_BSD_STRTOLL */
 #endif /* HAVE_STRTOLL */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/pytdb.c new/tdb-1.3.7/pytdb.c
--- old/tdb-1.3.6/pytdb.c       2014-09-16 20:04:31.000000000 +0200
+++ new/tdb-1.3.7/pytdb.c       2015-07-21 22:32:32.000000000 +0200
@@ -31,13 +31,25 @@
 /* Include tdb headers */
 #include <tdb.h>
 
+#if PY_MAJOR_VERSION >= 3
+#define PyStr_FromString PyUnicode_FromString
+#define PyStr_FromFormat PyUnicode_FromFormat
+#define PyInt_FromLong PyLong_FromLong
+#define PyInt_Check PyLong_Check
+#define PyInt_AsLong PyLong_AsLong
+#define Py_TPFLAGS_HAVE_ITER 0
+#else
+#define PyStr_FromString PyString_FromString
+#define PyStr_FromFormat PyString_FromFormat
+#endif
+
 typedef struct {
        PyObject_HEAD
        TDB_CONTEXT *ctx;
        bool closed;
 } PyTdbObject;
 
-staticforward PyTypeObject PyTdb;
+static PyTypeObject PyTdb;
 
 static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
 {
@@ -45,21 +57,21 @@
                Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb)));
 }
 
-static TDB_DATA PyString_AsTDB_DATA(PyObject *data)
+static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data)
 {
        TDB_DATA ret;
-       ret.dptr = (unsigned char *)PyString_AsString(data);
-       ret.dsize = PyString_Size(data);
+       ret.dptr = (unsigned char *)PyBytes_AsString(data);
+       ret.dsize = PyBytes_Size(data);
        return ret;
 }
 
-static PyObject *PyString_FromTDB_DATA(TDB_DATA data)
+static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data)
 {
        if (data.dptr == NULL && data.dsize == 0) {
                Py_RETURN_NONE;
        } else {
-               PyObject *ret = PyString_FromStringAndSize((const char 
*)data.dptr, 
-                                                                               
                   data.dsize);
+               PyObject *ret = PyBytes_FromStringAndSize((const char 
*)data.dptr,
+                                                                               
                  data.dsize);
                free(data.dptr);
                return ret;
     }
@@ -233,11 +245,11 @@
        if (!PyArg_ParseTuple(args, "O", &py_key))
                return NULL;
 
-       key = PyString_AsTDB_DATA(py_key);
+       key = PyBytes_AsTDB_DATA(py_key);
        if (!key.dptr)
                return NULL;
 
-       return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key));
+       return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key));
 }
 
 static PyObject *obj_append(PyTdbObject *self, PyObject *args)
@@ -251,10 +263,10 @@
        if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
                return NULL;
 
-       key = PyString_AsTDB_DATA(py_key);
+       key = PyBytes_AsTDB_DATA(py_key);
        if (!key.dptr)
                return NULL;
-       data = PyString_AsTDB_DATA(py_data);
+       data = PyBytes_AsTDB_DATA(py_data);
        if (!data.dptr)
                return NULL;
 
@@ -267,7 +279,7 @@
 {
        PyErr_TDB_RAISE_IF_CLOSED(self);
 
-       return PyString_FromTDB_DATA(tdb_firstkey(self->ctx));
+       return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx));
 }
 
 static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
@@ -279,11 +291,11 @@
        if (!PyArg_ParseTuple(args, "O", &py_key))
                return NULL;
 
-       key = PyString_AsTDB_DATA(py_key);
+       key = PyBytes_AsTDB_DATA(py_key);
        if (!key.dptr)
                return NULL;
        
-       return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key));
+       return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key));
 }
 
 static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
@@ -296,7 +308,7 @@
        if (!PyArg_ParseTuple(args, "O", &py_key))
                return NULL;
 
-       key = PyString_AsTDB_DATA(py_key);
+       key = PyBytes_AsTDB_DATA(py_key);
        if (!key.dptr)
                return NULL;
        ret = tdb_delete(self->ctx, key);
@@ -304,26 +316,42 @@
        Py_RETURN_NONE;
 }
 
-static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
+static int obj_contains(PyTdbObject *self, PyObject *py_key)
 {
        TDB_DATA key;
        int ret;
+       PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
+
+       key = PyBytes_AsTDB_DATA(py_key);
+       if (!key.dptr) {
+               PyErr_BadArgument();
+               return -1;
+       }
+       ret = tdb_exists(self->ctx, key);
+       if (ret)
+               return 1;
+       return 0;
+}
+
+#if PY_MAJOR_VERSION < 3
+static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
+{
+       int ret;
        PyObject *py_key;
        PyErr_TDB_RAISE_IF_CLOSED(self);
 
        if (!PyArg_ParseTuple(args, "O", &py_key))
                return NULL;
 
-       key = PyString_AsTDB_DATA(py_key);
-       if (!key.dptr)
+       ret = obj_contains(self, py_key);
+       if (ret == -1)
                return NULL;
-       ret = tdb_exists(self->ctx, key);
-       if (ret != TDB_ERR_NOEXIST) {
-               PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       }
+       if (ret)
+               Py_RETURN_TRUE;
+       Py_RETURN_FALSE;
 
-       return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True;
 }
+#endif
 
 static PyObject *obj_store(PyTdbObject *self, PyObject *args)
 {
@@ -337,10 +365,10 @@
        if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
                return NULL;
 
-       key = PyString_AsTDB_DATA(py_key);
+       key = PyBytes_AsTDB_DATA(py_key);
        if (!key.dptr)
                return NULL;
-       value = PyString_AsTDB_DATA(py_value);
+       value = PyBytes_AsTDB_DATA(py_value);
        if (!value.dptr)
                return NULL;
 
@@ -389,7 +417,7 @@
                return NULL;
        current = self->current;
        self->current = tdb_nextkey(self->iteratee->ctx, self->current);
-       ret = PyString_FromTDB_DATA(current);
+       ret = PyBytes_FromTDB_DATA(current);
        return ret;
 }
 
@@ -480,17 +508,23 @@
                "Append data to an existing key." },
        { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> 
data\n"
                "Return the first key in this database." },
-       { "nextkey", (PyCFunction)obj_nextkey, METH_NOARGS, "S.nextkey(key) -> 
data\n"
+       { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> 
data\n"
                "Return the next key in this database." },
        { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> 
None\n"
                "Delete an entry." },
+#if PY_MAJOR_VERSION < 3
        { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> 
None\n"
                "Check whether key exists in this database." },
+#endif
        { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, 
flag=REPLACE) -> None"
                "Store data." },
        { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, 
"S.add_flags(flags) -> None" },
        { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, 
"S.remove_flags(flags) -> None" },
+#if PY_MAJOR_VERSION >= 3
+       { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> 
iterator" },
+#else
        { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() 
-> iterator" },
+#endif
        { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
                "Wipe the entire database." },
        { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
@@ -538,7 +572,7 @@
 static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
 {
        PyErr_TDB_RAISE_IF_CLOSED(self);
-       return PyString_FromString(tdb_name(self->ctx));
+       return PyBytes_FromString(tdb_name(self->ctx));
 }
 
 static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
@@ -547,6 +581,22 @@
        return PyInt_FromLong(tdb_get_seqnum(self->ctx));
 }
 
+static PyObject *obj_get_text(PyTdbObject *self, void *closure)
+{
+       PyObject *mod, *cls, *inst;
+       mod = PyImport_ImportModule("_tdb_text");
+       if (mod == NULL)
+               return NULL;
+       cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
+       if (cls == NULL) {
+               Py_DECREF(mod);
+               return NULL;
+       }
+       inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
+       Py_DECREF(mod);
+       Py_DECREF(cls);
+       return inst;
+}
 
 static PyGetSetDef tdb_object_getsetters[] = {
        { discard_const_p(char, "hash_size"),
@@ -564,6 +614,8 @@
          discard_const_p(char, "The filename of this TDB file.") },
        { discard_const_p(char, "seqnum"),
          (getter)obj_get_seqnum, NULL, NULL },
+       { discard_const_p(char, "text"),
+         (getter)obj_get_text, NULL, NULL },
        { NULL }
 };
 
@@ -571,9 +623,9 @@
 {
        PyErr_TDB_RAISE_IF_CLOSED(self);
        if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
-               return PyString_FromString("Tdb(<internal>)");
+               return PyStr_FromString("Tdb(<internal>)");
        } else {
-               return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
+               return PyStr_FromFormat("Tdb('%s')", tdb_name(self->ctx));
        }
 }
 
@@ -581,27 +633,31 @@
 {
        if (!self->closed)
                tdb_close(self->ctx);
-       self->ob_type->tp_free(self);
+       Py_TYPE(self)->tp_free(self);
 }
 
 static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
 {
        TDB_DATA tkey, val;
        PyErr_TDB_RAISE_IF_CLOSED(self);
-       if (!PyString_Check(key)) {
-               PyErr_SetString(PyExc_TypeError, "Expected string as key");
+       if (!PyBytes_Check(key)) {
+               PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
                return NULL;
        }
 
-       tkey.dptr = (unsigned char *)PyString_AsString(key);
-       tkey.dsize = PyString_Size(key);
+       tkey.dptr = (unsigned char *)PyBytes_AsString(key);
+       tkey.dsize = PyBytes_Size(key);
 
        val = tdb_fetch(self->ctx, tkey);
        if (val.dptr == NULL) {
-               PyErr_SetString(PyExc_KeyError, "No such TDB entry");
+               /*
+                * if the key doesn't exist raise KeyError(key) to be
+                * consistent with python dict
+                */
+               PyErr_SetObject(PyExc_KeyError, key);
                return NULL;
        } else {
-               return PyString_FromTDB_DATA(val);
+               return PyBytes_FromTDB_DATA(val);
        }
 }
 
@@ -610,22 +666,22 @@
        TDB_DATA tkey, tval;
        int ret;
        PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
-       if (!PyString_Check(key)) {
-               PyErr_SetString(PyExc_TypeError, "Expected string as key");
+       if (!PyBytes_Check(key)) {
+               PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
                return -1;
        }
 
-       tkey = PyString_AsTDB_DATA(key);
+       tkey = PyBytes_AsTDB_DATA(key);
 
        if (value == NULL) { 
                ret = tdb_delete(self->ctx, tkey);
        } else { 
-               if (!PyString_Check(value)) {
+               if (!PyBytes_Check(value)) {
                        PyErr_SetString(PyExc_TypeError, "Expected string as 
value");
                        return -1;
                }
 
-               tval = PyString_AsTDB_DATA(value);
+               tval = PyBytes_AsTDB_DATA(value);
 
                ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
        }
@@ -642,6 +698,9 @@
        .mp_subscript = (binaryfunc)obj_getitem,
        .mp_ass_subscript = (objobjargproc)obj_setitem,
 };
+static PySequenceMethods tdb_object_seq = {
+       .sq_contains = (objobjproc)obj_contains,
+};
 static PyTypeObject PyTdb = {
        .tp_name = "tdb.Tdb",
        .tp_basicsize = sizeof(PyTdbObject),
@@ -652,6 +711,7 @@
        .tp_repr = (reprfunc)tdb_object_repr,
        .tp_dealloc = (destructor)tdb_object_dealloc,
        .tp_as_mapping = &tdb_object_mapping,
+       .tp_as_sequence = &tdb_object_seq,
        .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER,
        .tp_iter = (getiterfunc)tdb_object_iter,
 };
@@ -662,46 +722,78 @@
        { NULL }
 };
 
-void inittdb(void);
-void inittdb(void)
+#define MODULE_DOC "simple key-value database that supports multiple writers."
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "tdb",
+    .m_doc = MODULE_DOC,
+    .m_size = -1,
+    .m_methods = tdb_methods,
+};
+#endif
+
+PyObject* module_init(void);
+PyObject* module_init(void)
 {
        PyObject *m;
 
        if (PyType_Ready(&PyTdb) < 0)
-               return;
+               return NULL;
 
        if (PyType_Ready(&PyTdbIterator) < 0)
-               return;
+               return NULL;
 
-       m = Py_InitModule3("tdb", tdb_methods,
-               "simple key-value database that supports multiple writers.");
+#if PY_MAJOR_VERSION >= 3
+       m = PyModule_Create(&moduledef);
+#else
+       m = Py_InitModule3("tdb", tdb_methods, MODULE_DOC);
+#endif
        if (m == NULL)
-               return;
+               return NULL;
 
-       PyModule_AddObject(m, "REPLACE", PyInt_FromLong(TDB_REPLACE));
-       PyModule_AddObject(m, "INSERT", PyInt_FromLong(TDB_INSERT));
-       PyModule_AddObject(m, "MODIFY", PyInt_FromLong(TDB_MODIFY));
-
-       PyModule_AddObject(m, "DEFAULT", PyInt_FromLong(TDB_DEFAULT));
-       PyModule_AddObject(m, "CLEAR_IF_FIRST", 
PyInt_FromLong(TDB_CLEAR_IF_FIRST));
-       PyModule_AddObject(m, "INTERNAL", PyInt_FromLong(TDB_INTERNAL));
-       PyModule_AddObject(m, "NOLOCK", PyInt_FromLong(TDB_NOLOCK));
-       PyModule_AddObject(m, "NOMMAP", PyInt_FromLong(TDB_NOMMAP));
-       PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT));
-       PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN));
-       PyModule_AddObject(m, "NOSYNC", PyInt_FromLong(TDB_NOSYNC));
-       PyModule_AddObject(m, "SEQNUM", PyInt_FromLong(TDB_SEQNUM));
-       PyModule_AddObject(m, "VOLATILE", PyInt_FromLong(TDB_VOLATILE));
-       PyModule_AddObject(m, "ALLOW_NESTING", 
PyInt_FromLong(TDB_ALLOW_NESTING));
-       PyModule_AddObject(m, "DISALLOW_NESTING", 
PyInt_FromLong(TDB_DISALLOW_NESTING));
-       PyModule_AddObject(m, "INCOMPATIBLE_HASH", 
PyInt_FromLong(TDB_INCOMPATIBLE_HASH));
+       PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
+       PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
+       PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
+
+       PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
+       PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
+       PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
+       PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
+       PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
+       PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
+       PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
+       PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
+       PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
+       PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
+       PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
+       PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
+       PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
 
-       PyModule_AddObject(m, "__docformat__", 
PyString_FromString("restructuredText"));
+       PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
 
-       PyModule_AddObject(m, "__version__", 
PyString_FromString(PACKAGE_VERSION));
+       PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
 
        Py_INCREF(&PyTdb);
        PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
 
        Py_INCREF(&PyTdbIterator);
+
+    return m;
+}
+
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit_tdb(void);
+PyMODINIT_FUNC PyInit_tdb(void)
+{
+    return module_init();
+}
+#else
+void inittdb(void);
+void inittdb(void)
+{
+    module_init();
 }
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/python/tests/simple.py 
new/tdb-1.3.7/python/tests/simple.py
--- old/tdb-1.3.6/python/tests/simple.py        2014-09-16 20:04:31.000000000 
+0200
+++ new/tdb-1.3.7/python/tests/simple.py        2015-07-21 22:32:32.000000000 
+0200
@@ -6,9 +6,12 @@
 # Copyright (C) 2007-2008 Jelmer Vernooij <[email protected]>
 # Published under the GNU LGPLv3 or later
 
-import tdb
+import sys
+import os
+import tempfile
 from unittest import TestCase
-import os, tempfile
+
+import tdb
 
 
 class OpenTdbTests(TestCase):
@@ -43,19 +46,18 @@
         self.assertEquals(repr(self.tdb), "Tdb(<internal>)")
 
 
-class SimpleTdbTests(TestCase):
+class CommonTdbTests(TestCase):
+    """Tests common to both the text & bytes interfaces"""
+
+    use_text = False
 
     def setUp(self):
-        super(SimpleTdbTests, self).setUp()
+        super(CommonTdbTests, self).setUp()
         self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
                            os.O_CREAT|os.O_RDWR)
         self.assertNotEqual(None, self.tdb)
-
-    def tearDown(self):
-        del self.tdb
-
-    def test_repr(self):
-        self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+        if self.use_text:
+            self.tdb = self.tdb.text
 
     def test_lockall(self):
         self.tdb.lock_all()
@@ -74,27 +76,6 @@
     def test_reopen(self):
         self.tdb.reopen()
 
-    def test_store(self):
-        self.tdb.store("bar", "bla")
-        self.assertEquals("bla", self.tdb.get("bar"))
-
-    def test_getitem(self):
-        self.tdb["bar"] = "foo"
-        self.tdb.reopen()
-        self.assertEquals("foo", self.tdb["bar"])
-
-    def test_delete(self):
-        self.tdb["bar"] = "foo"
-        del self.tdb["bar"]
-        self.assertRaises(KeyError, lambda: self.tdb["bar"])
-
-    def test_contains(self):
-        self.tdb["bla"] = "bloe"
-        self.assertTrue("bla" in self.tdb)
-
-    def test_keyerror(self):
-        self.assertRaises(KeyError, lambda: self.tdb["bla"])
-
     def test_hash_size(self):
         self.tdb.hash_size
 
@@ -107,52 +88,101 @@
     def test_name(self):
         self.tdb.filename
 
+    def test_add_flags(self):
+        self.tdb.add_flags(tdb.NOMMAP)
+        self.tdb.remove_flags(tdb.NOMMAP)
+
+
+class TextCommonTdbTests(CommonTdbTests):
+
+    use_text = True
+
+
+class SimpleTdbTests(TestCase):
+
+    def setUp(self):
+        super(SimpleTdbTests, self).setUp()
+        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+                           os.O_CREAT|os.O_RDWR)
+        self.assertNotEqual(None, self.tdb)
+
+    def test_repr(self):
+        self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+    def test_store(self):
+        self.tdb.store(b"bar", b"bla")
+        self.assertEquals(b"bla", self.tdb.get(b"bar"))
+
+    def test_getitem(self):
+        self.tdb[b"bar"] = b"foo"
+        self.tdb.reopen()
+        self.assertEquals(b"foo", self.tdb[b"bar"])
+
+    def test_delete(self):
+        self.tdb[b"bar"] = b"foo"
+        del self.tdb[b"bar"]
+        self.assertRaises(KeyError, lambda: self.tdb[b"bar"])
+
+    def test_contains(self):
+        self.tdb[b"bla"] = b"bloe"
+        self.assertTrue(b"bla" in self.tdb)
+        self.assertFalse(b"qwertyuiop" in self.tdb)
+        if sys.version_info < (3, 0):
+            self.assertTrue(self.tdb.has_key(b"bla"))
+            self.assertFalse(self.tdb.has_key(b"qwertyuiop"))
+
+    def test_keyerror(self):
+        self.assertRaises(KeyError, lambda: self.tdb[b"bla"])
+
     def test_iterator(self):
-        self.tdb["bla"] = "1"
-        self.tdb["brainslug"] = "2"
+        self.tdb[b"bla"] = b"1"
+        self.tdb[b"brainslug"] = b"2"
         l = list(self.tdb)
         l.sort()
-        self.assertEquals(["bla", "brainslug"], l)
+        self.assertEquals([b"bla", b"brainslug"], l)
 
     def test_transaction_cancel(self):
-        self.tdb["bloe"] = "2"
+        self.tdb[b"bloe"] = b"2"
         self.tdb.transaction_start()
-        self.tdb["bloe"] = "1"
+        self.tdb[b"bloe"] = b"1"
         self.tdb.transaction_cancel()
-        self.assertEquals("2", self.tdb["bloe"])
+        self.assertEquals(b"2", self.tdb[b"bloe"])
 
     def test_transaction_commit(self):
-        self.tdb["bloe"] = "2"
+        self.tdb[b"bloe"] = b"2"
         self.tdb.transaction_start()
-        self.tdb["bloe"] = "1"
+        self.tdb[b"bloe"] = b"1"
         self.tdb.transaction_commit()
-        self.assertEquals("1", self.tdb["bloe"])
+        self.assertEquals(b"1", self.tdb[b"bloe"])
 
     def test_transaction_prepare_commit(self):
-        self.tdb["bloe"] = "2"
+        self.tdb[b"bloe"] = b"2"
         self.tdb.transaction_start()
-        self.tdb["bloe"] = "1"
+        self.tdb[b"bloe"] = b"1"
         self.tdb.transaction_prepare_commit()
         self.tdb.transaction_commit()
-        self.assertEquals("1", self.tdb["bloe"])
+        self.assertEquals(b"1", self.tdb[b"bloe"])
 
     def test_iterkeys(self):
-        self.tdb["bloe"] = "2"
-        self.tdb["bla"] = "25"
-        i = self.tdb.iterkeys()
-        self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()]))
+        self.tdb[b"bloe"] = b"2"
+        self.tdb[b"bla"] = b"25"
+        if sys.version_info >= (3, 0):
+            i = self.tdb.keys()
+        else:
+            i = self.tdb.iterkeys()
+        self.assertEquals(set([b"bloe", b"bla"]), set([next(i), next(i)]))
 
     def test_clear(self):
-        self.tdb["bloe"] = "2"
-        self.tdb["bla"] = "25"
+        self.tdb[b"bloe"] = b"2"
+        self.tdb[b"bla"] = b"25"
         self.assertEquals(2, len(list(self.tdb)))
         self.tdb.clear()
         self.assertEquals(0, len(list(self.tdb)))
 
     def test_repack(self):
-        self.tdb["foo"] = "abc"
-        self.tdb["bar"] = "def"
-        del self.tdb["foo"]
+        self.tdb[b"foo"] = b"abc"
+        self.tdb[b"bar"] = b"def"
+        del self.tdb[b"foo"]
         self.tdb.repack()
 
     def test_seqnum(self):
@@ -164,12 +194,110 @@
 
     def test_len(self):
         self.assertEquals(0, len(list(self.tdb)))
-        self.tdb["entry"] = "value"
+        self.tdb[b"entry"] = b"value"
         self.assertEquals(1, len(list(self.tdb)))
 
-    def test_add_flags(self):
-        self.tdb.add_flags(tdb.NOMMAP)
-        self.tdb.remove_flags(tdb.NOMMAP)
+
+class TdbTextTests(TestCase):
+
+    def setUp(self):
+        super(TdbTextTests, self).setUp()
+        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+                           os.O_CREAT|os.O_RDWR)
+        self.assertNotEqual(None, self.tdb)
+
+    def test_repr(self):
+        self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+    def test_store(self):
+        self.tdb.text.store("bar", "bla")
+        self.assertEquals("bla", self.tdb.text.get("bar"))
+
+    def test_getitem(self):
+        self.tdb.text["bar"] = "foo"
+        self.tdb.reopen()
+        self.assertEquals("foo", self.tdb.text["bar"])
+
+    def test_delete(self):
+        self.tdb.text["bar"] = "foo"
+        del self.tdb.text["bar"]
+        self.assertRaises(KeyError, lambda: self.tdb.text["bar"])
+
+    def test_contains(self):
+        self.tdb.text["bla"] = "bloe"
+        self.assertTrue("bla" in self.tdb.text)
+        self.assertFalse("qwertyuiop" in self.tdb.text)
+        if sys.version_info < (3, 0):
+            self.assertTrue(self.tdb.text.has_key("bla"))
+            self.assertFalse(self.tdb.text.has_key("qwertyuiop"))
+
+    def test_keyerror(self):
+        self.assertRaises(KeyError, lambda: self.tdb.text["bla"])
+
+    def test_iterator(self):
+        self.tdb.text["bla"] = "1"
+        self.tdb.text["brainslug"] = "2"
+        l = list(self.tdb.text)
+        l.sort()
+        self.assertEquals(["bla", "brainslug"], l)
+
+    def test_transaction_cancel(self):
+        self.tdb.text["bloe"] = "2"
+        self.tdb.transaction_start()
+        self.tdb.text["bloe"] = "1"
+        self.tdb.transaction_cancel()
+        self.assertEquals("2", self.tdb.text["bloe"])
+
+    def test_transaction_commit(self):
+        self.tdb.text["bloe"] = "2"
+        self.tdb.transaction_start()
+        self.tdb.text["bloe"] = "1"
+        self.tdb.transaction_commit()
+        self.assertEquals("1", self.tdb.text["bloe"])
+
+    def test_transaction_prepare_commit(self):
+        self.tdb.text["bloe"] = "2"
+        self.tdb.transaction_start()
+        self.tdb.text["bloe"] = "1"
+        self.tdb.transaction_prepare_commit()
+        self.tdb.transaction_commit()
+        self.assertEquals("1", self.tdb.text["bloe"])
+
+    def test_iterkeys(self):
+        self.tdb.text["bloe"] = "2"
+        self.tdb.text["bla"] = "25"
+        if sys.version_info >= (3, 0):
+            i = self.tdb.text.keys()
+        else:
+            i = self.tdb.text.iterkeys()
+        self.assertEquals(set(["bloe", "bla"]), set([next(i), next(i)]))
+
+    def test_clear(self):
+        self.tdb.text["bloe"] = "2"
+        self.tdb.text["bla"] = "25"
+        self.assertEquals(2, len(list(self.tdb)))
+        self.tdb.clear()
+        self.assertEquals(0, len(list(self.tdb)))
+
+    def test_repack(self):
+        self.tdb.text["foo"] = "abc"
+        self.tdb.text["bar"] = "def"
+        del self.tdb.text["foo"]
+        self.tdb.repack()
+
+    def test_len(self):
+        self.assertEquals(0, len(list(self.tdb.text)))
+        self.tdb.text["entry"] = "value"
+        self.assertEquals(1, len(list(self.tdb.text)))
+
+    def test_text_and_binary(self):
+        text = u'\xfa\u0148\xef\xe7\xf8\xf0\xea'
+        bytestr = text.encode('utf-8')
+        self.tdb[b"entry"] = bytestr
+        self.tdb.text[u"entry2"] = text
+        self.assertEquals(self.tdb.text["entry"], text)
+        self.assertEquals(self.tdb[b"entry2"], bytestr)
+        assert self.tdb.text.raw == self.tdb
 
 
 class VersionTests(TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/test/run-allrecord-traverse-deadlock.c 
new/tdb-1.3.7/test/run-allrecord-traverse-deadlock.c
--- old/tdb-1.3.6/test/run-allrecord-traverse-deadlock.c        1970-01-01 
01:00:00.000000000 +0100
+++ new/tdb-1.3.7/test/run-allrecord-traverse-deadlock.c        2015-07-21 
22:32:32.000000000 +0200
@@ -0,0 +1,203 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+#include "logging.h"
+
+static void do_allrecord_lock(const char *name, int tdb_flags, int up,
+                             int down)
+{
+       struct tdb_context *tdb;
+       int ret;
+       ssize_t nread, nwritten;
+       char c = 0;
+
+       tdb = tdb_open_ex(name, 3, tdb_flags,
+                         O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+       ok(tdb, "tdb_open_ex should succeed");
+
+       ret = tdb_lockall(tdb);
+       ok(ret == 0, "tdb_lockall should succeed");
+
+       nwritten = write(up, &c, sizeof(c));
+       ok(nwritten == sizeof(c), "write should succeed");
+
+       nread = read(down, &c, sizeof(c));
+       ok(nread == sizeof(c), "read should succeed");
+
+       ret = tdb_traverse(tdb, NULL, NULL);
+       ok(ret == -1, "do_allrecord_lock: traverse should fail");
+
+       nwritten = write(up, &c, sizeof(c));
+       ok(nwritten == sizeof(c), "write should succeed");
+
+       exit(0);
+}
+
+static void do_traverse(const char *name, int tdb_flags, int up, int down)
+{
+       struct tdb_context *tdb;
+       int ret;
+       ssize_t nread, nwritten;
+       char c = 0;
+
+       tdb = tdb_open_ex(name, 3, tdb_flags,
+                         O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+       ok(tdb, "tdb_open_ex should succeed");
+
+       ret = tdb_traverse(tdb, NULL, NULL);
+       ok(ret == 1, "do_traverse: tdb_traverse should return 1 record");
+
+       nwritten = write(up, &c, sizeof(c));
+       ok(nwritten == sizeof(c), "write should succeed");
+
+       nread = read(down, &c, sizeof(c));
+       ok(nread == sizeof(c), "read should succeed");
+
+       exit(0);
+}
+
+/*
+ * Process 1: get the allrecord_lock on a tdb.
+ * Process 2: start a traverse, this will stall waiting for the
+ *            first chainlock: That is taken by the allrecord_lock
+ * Process 1: start a traverse: This will get EDEADLK in trying to
+ *            get the TRANSACTION_LOCK. It will deadlock for mutexes,
+ *            which don't have built-in deadlock detection.
+ */
+
+static int do_tests(const char *name, int tdb_flags)
+{
+       struct tdb_context *tdb;
+       int ret;
+       pid_t traverse_child, allrecord_child;
+       int traverse_down[2];
+       int traverse_up[2];
+       int allrecord_down[2];
+       int allrecord_up[2];
+       char c;
+       ssize_t nread, nwritten;
+       TDB_DATA key, data;
+
+       key.dsize = strlen("hi");
+       key.dptr = discard_const_p(uint8_t, "hi");
+       data.dsize = strlen("world");
+       data.dptr = discard_const_p(uint8_t, "world");
+
+       tdb = tdb_open_ex(name, 3, tdb_flags,
+                         O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+       ok(tdb, "tdb_open_ex should succeed");
+
+       ret = tdb_store(tdb, key, data, TDB_INSERT);
+       ok(ret == 0, "tdb_store should succeed");
+
+       ret = pipe(traverse_down);
+       ok(ret == 0, "pipe should succeed");
+
+       ret = pipe(traverse_up);
+       ok(ret == 0, "pipe should succeed");
+
+       ret = pipe(allrecord_down);
+       ok(ret == 0, "pipe should succeed");
+
+       ret = pipe(allrecord_up);
+       ok(ret == 0, "pipe should succeed");
+
+       allrecord_child = fork();
+       ok(allrecord_child != -1, "fork should succeed");
+
+       if (allrecord_child == 0) {
+               tdb_close(tdb);
+               close(traverse_up[0]);
+               close(traverse_up[1]);
+               close(traverse_down[0]);
+               close(traverse_down[1]);
+               close(allrecord_up[0]);
+               close(allrecord_down[1]);
+               do_allrecord_lock(name, tdb_flags,
+                                 allrecord_up[1], allrecord_down[0]);
+               exit(0);
+       }
+       close(allrecord_up[1]);
+       close(allrecord_down[0]);
+
+       nread = read(allrecord_up[0], &c, sizeof(c));
+       ok(nread == sizeof(c), "read should succeed");
+
+       traverse_child = fork();
+       ok(traverse_child != -1, "fork should succeed");
+
+       if (traverse_child == 0) {
+               tdb_close(tdb);
+               close(traverse_up[0]);
+               close(traverse_down[1]);
+               close(allrecord_up[0]);
+               close(allrecord_down[1]);
+               do_traverse(name, tdb_flags,
+                           traverse_up[1], traverse_down[0]);
+               exit(0);
+       }
+       close(traverse_up[1]);
+       close(traverse_down[0]);
+
+       poll(NULL, 0, 1000);
+
+       nwritten = write(allrecord_down[1], &c, sizeof(c));
+       ok(nwritten == sizeof(c), "write should succeed");
+
+       nread = read(traverse_up[0], &c, sizeof(c));
+       ok(nread == sizeof(c), "read should succeed");
+
+       nwritten = write(traverse_down[1], &c, sizeof(c));
+       ok(nwritten == sizeof(c), "write should succeed");
+
+       nread = read(allrecord_up[0], &c, sizeof(c));
+       ok(nread == sizeof(c), "ret should succeed");
+
+       close(traverse_up[0]);
+       close(traverse_down[1]);
+       close(allrecord_up[0]);
+       close(allrecord_down[1]);
+       diag("%s tests done", name);
+       return exit_status();
+}
+
+int main(int argc, char *argv[])
+{
+       int ret;
+       bool mutex_support;
+
+       mutex_support = tdb_runtime_check_for_robust_mutexes();
+
+       ret = do_tests("marklock-deadlock-fcntl.tdb",
+                      TDB_CLEAR_IF_FIRST |
+                      TDB_INCOMPATIBLE_HASH);
+       ok(ret == 0, "marklock-deadlock-fcntl.tdb tests should succeed");
+
+       if (!mutex_support) {
+               skip(1, "No robust mutex support, "
+                       "skipping marklock-deadlock-mutex.tdb tests");
+               return exit_status();
+       }
+
+       ret = do_tests("marklock-deadlock-mutex.tdb",
+                      TDB_CLEAR_IF_FIRST |
+                      TDB_MUTEX_LOCKING |
+                      TDB_INCOMPATIBLE_HASH);
+       ok(ret == 0, "marklock-deadlock-mutex.tdb tests should succeed");
+
+       return exit_status();
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/tools/tdbrestore.c 
new/tdb-1.3.7/tools/tdbrestore.c
--- old/tdb-1.3.6/tools/tdbrestore.c    2014-09-16 20:04:31.000000000 +0200
+++ new/tdb-1.3.7/tools/tdbrestore.c    2015-07-21 22:32:32.000000000 +0200
@@ -17,8 +17,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <assert.h>
 #include "replace.h"
+#include <assert.h>
 #include "system/locale.h"
 #include "system/time.h"
 #include "system/filesys.h"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tdb-1.3.6/wscript new/tdb-1.3.7/wscript
--- old/tdb-1.3.6/wscript       2015-06-13 03:01:31.000000000 +0200
+++ new/tdb-1.3.7/wscript       2015-07-21 22:35:18.000000000 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'tdb'
-VERSION = '1.3.6'
+VERSION = '1.3.7'
 
 blddir = 'bin'
 
@@ -41,6 +41,7 @@
     'run-wronghash-fail',
     'run-zero-append',
     'run-marklock-deadlock',
+    'run-allrecord-traverse-deadlock',
     'run-mutex-openflags2',
     'run-mutex-trylock',
     'run-mutex-allrecord-bench',
@@ -95,8 +96,7 @@
 
     if not conf.env.disable_python:
         # also disable if we don't have the python libs installed
-        conf.find_program('python', var='PYTHON')
-        conf.check_tool('python')
+        conf.SAMBA_CHECK_PYTHON(mandatory=False)
         conf.check_python_version((2,4,2))
         conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False)
         if not conf.env.HAVE_PYTHON_H:
@@ -179,12 +179,20 @@
                                  includes='include', install=False)
 
     if not bld.CONFIG_SET('USING_SYSTEM_PYTDB'):
-        bld.SAMBA_PYTHON('pytdb',
-                         'pytdb.c',
-                         deps='tdb',
-                         enabled=not bld.env.disable_python,
-                         realname='tdb.so',
-                         cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+        for env in bld.gen_python_environments(['PKGCONFIGDIR']):
+            bld.SAMBA_PYTHON('pytdb',
+                             'pytdb.c',
+                             deps='tdb',
+                             enabled=not bld.env.disable_python,
+                             realname='tdb.so',
+                             cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+
+        for env in bld.gen_python_environments(['PKGCONFIGDIR']):
+            bld.SAMBA_SCRIPT('_tdb_text.py',
+                             pattern='_tdb_text.py',
+                             installdir='python')
+
+            bld.INSTALL_FILES('${PYTHONARCHDIR}', '_tdb_text.py')
 
 def testonly(ctx):
     '''run tdb testsuite'''
@@ -224,7 +232,10 @@
         print("testsuite returned %d" % ret)
         if ret != 0:
             ecode = ret
-    sys.exit(ecode)
+
+    pyret = samba_utils.RUN_PYTHON_TESTS(['python/tests/simple.py'])
+    print("python testsuite returned %d" % pyret)
+    sys.exit(ecode or pyret)
 
 # WAF doesn't build the unit tests for this, maybe because they don't link 
with tdb?
 # This forces it



Reply via email to