ndr: Add support for pulling/printing an ipv6address type
[samba.git] / lib / tdb / pytdb.c
index d6d0625686f1dc31ec0360e35d2f898548d59e69..b857438e16ec0ef6185be78f0a28275be512f6a1 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
 
-   Swig interface to tdb.
+   Python interface to tdb.
 
    Copyright (C) 2004-2006 Tim Potter <tpot@samba.org>
    Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
 */
 
 #include <Python.h>
-#ifdef HAVE_FSTAT
-#undef HAVE_FSTAT
+#include "replace.h"
+#include "system/filesys.h"
+
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
 #endif
 
 /* Include tdb headers */
-#include <stdint.h>
-#include <signal.h>
 #include <tdb.h>
-#include <fcntl.h>
 
 typedef struct {
        PyObject_HEAD
        TDB_CONTEXT *ctx;
+       bool closed;
 } PyTdbObject;
 
 PyAPI_DATA(PyTypeObject) PyTdb;
@@ -59,7 +60,7 @@ static TDB_DATA PyString_AsTDB_DATA(PyObject *data)
 static PyObject *PyString_FromTDB_DATA(TDB_DATA data)
 {
        if (data.dptr == NULL && data.dsize == 0) {
-               return Py_None;
+               Py_RETURN_NONE;
        } else {
                PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr, 
                                                                                                   data.dsize);
@@ -76,15 +77,19 @@ static PyObject *PyString_FromTDB_DATA(TDB_DATA data)
 
 static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
-       char *name;
+       char *name = NULL;
        int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600;
        TDB_CONTEXT *ctx;
        PyTdbObject *ret;
        const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
                return NULL;
 
+       if (name == NULL) {
+               tdb_flags |= TDB_INTERNAL;
+       }
+
        ctx = tdb_open(name, hash_size, tdb_flags, flags, mode);
        if (ctx == NULL) {
                PyErr_SetFromErrno(PyExc_IOError);
@@ -92,7 +97,13 @@ static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwarg
        }
 
        ret = PyObject_New(PyTdbObject, &PyTdb);
+       if (!ret) {
+               tdb_close(ctx);
+               return NULL;
+       }
+
        ret->ctx = ctx;
+       ret->closed = false;
        return (PyObject *)ret;
 }
 
@@ -100,70 +111,74 @@ static PyObject *obj_transaction_cancel(PyTdbObject *self)
 {
        int ret = tdb_transaction_cancel(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_transaction_commit(PyTdbObject *self)
 {
        int ret = tdb_transaction_commit(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
-static PyObject *obj_transaction_recover(PyTdbObject *self)
+static PyObject *obj_transaction_prepare_commit(PyTdbObject *self)
 {
-       int ret = tdb_transaction_recover(self->ctx);
+       int ret = tdb_transaction_prepare_commit(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_transaction_start(PyTdbObject *self)
 {
        int ret = tdb_transaction_start(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_reopen(PyTdbObject *self)
 {
        int ret = tdb_reopen(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_lockall(PyTdbObject *self)
 {
        int ret = tdb_lockall(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_unlockall(PyTdbObject *self)
 {
        int ret = tdb_unlockall(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_lockall_read(PyTdbObject *self)
 {
        int ret = tdb_lockall_read(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_unlockall_read(PyTdbObject *self)
 {
        int ret = tdb_unlockall_read(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_close(PyTdbObject *self)
 {
-       int ret = tdb_close(self->ctx);
+       int ret;
+       if (self->closed)
+               Py_RETURN_NONE;
+       ret = tdb_close(self->ctx);
+       self->closed = true;
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_get(PyTdbObject *self, PyObject *args)
@@ -191,7 +206,7 @@ static PyObject *obj_append(PyTdbObject *self, PyObject *args)
 
        ret = tdb_append(self->ctx, key, data);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_firstkey(PyTdbObject *self)
@@ -222,7 +237,7 @@ static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
        key = PyString_AsTDB_DATA(py_key);
        ret = tdb_delete(self->ctx, key);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
@@ -257,9 +272,30 @@ static PyObject *obj_store(PyTdbObject *self, PyObject *args)
 
        ret = tdb_store(self->ctx, key, value, flag);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
+}
+
+static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
+{
+       unsigned flags;
+
+       if (!PyArg_ParseTuple(args, "I", &flags))
+               return NULL;
+
+       tdb_add_flags(self->ctx, flags);
+       Py_RETURN_NONE;
 }
 
+static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
+{
+       unsigned flags;
+
+       if (!PyArg_ParseTuple(args, "I", &flags))
+               return NULL;
+
+       tdb_remove_flags(self->ctx, flags);
+       Py_RETURN_NONE;
+}
 
 typedef struct {
        PyObject_HEAD
@@ -299,6 +335,8 @@ static PyObject *tdb_object_iter(PyTdbObject *self)
        PyTdbIteratorObject *ret;       
 
        ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
+       if (!ret)
+               return NULL;
        ret->current = tdb_firstkey(self->ctx);
        ret->iteratee = self;
        Py_INCREF(self);
@@ -309,7 +347,26 @@ static PyObject *obj_clear(PyTdbObject *self)
 {
        int ret = tdb_wipe_all(self->ctx);
        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
-       return Py_None;
+       Py_RETURN_NONE;
+}
+
+static PyObject *obj_repack(PyTdbObject *self)
+{
+       int ret = tdb_repack(self->ctx);
+       PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+       Py_RETURN_NONE;
+}
+
+static PyObject *obj_enable_seqnum(PyTdbObject *self)
+{
+       tdb_enable_seqnum(self->ctx);
+       Py_RETURN_NONE;
+}
+
+static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self)
+{
+       tdb_increment_seqnum_nonblock(self->ctx);
+       Py_RETURN_NONE;
 }
 
 static PyMethodDef tdb_object_methods[] = {
@@ -319,9 +376,9 @@ static PyMethodDef tdb_object_methods[] = {
        { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS,
                "S.transaction_commit() -> None\n"
                "Commit the currently active transaction." },
-       { "transaction_recover", (PyCFunction)obj_transaction_recover, METH_NOARGS,
-               "S.transaction_recover() -> None\n"
-               "Recover the currently active transaction." },
+       { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
+               "S.transaction_prepare_commit() -> None\n"
+               "Prepare to commit the currently active transaction" },
        { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
                "S.transaction_start() -> None\n"
                "Start a new transaction." },
@@ -331,7 +388,7 @@ static PyMethodDef tdb_object_methods[] = {
        { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL },
        { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL },
        { "close", (PyCFunction)obj_close, METH_NOARGS, NULL },
-       { "get", (PyCFunction)obj_get, METH_VARARGS, "S.fetch(key) -> value\n"
+       { "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n"
                "Fetch a value." },
        { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n"
                "Append data to an existing key." },
@@ -345,9 +402,17 @@ static PyMethodDef tdb_object_methods[] = {
                "Check whether key exists in this database." },
        { "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" },
        { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
        { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
                "Wipe the entire database." },
+       { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
+               "Repack the entire database." },
+       { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
+               "S.enable_seqnum() -> None" },
+       { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
+               "S.increment_seqnum_nonblock() -> None" },
        { NULL }
 };
 
@@ -369,6 +434,11 @@ static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
        return PyInt_FromLong(tdb_map_size(self->ctx));
 }
 
+static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
+{
+       return PyInt_FromLong(tdb_freelist_size(self->ctx));
+}
+
 static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
 {
        return PyInt_FromLong(tdb_get_flags(self->ctx));
@@ -379,23 +449,36 @@ static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
        return PyString_FromString(tdb_name(self->ctx));
 }
 
+static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
+{
+       return PyInt_FromLong(tdb_get_seqnum(self->ctx));
+}
+
+
 static PyGetSetDef tdb_object_getsetters[] = {
        { (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL },
        { (char *)"map_size", (getter)obj_get_map_size, NULL, NULL },
+       { (char *)"freelist_size", (getter)obj_get_freelist_size, NULL, NULL },
        { (char *)"flags", (getter)obj_get_flags, NULL, NULL },
        { (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL },
        { (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."},
+       { (char *)"seqnum", (getter)obj_get_seqnum, NULL, NULL },
        { NULL }
 };
 
 static PyObject *tdb_object_repr(PyTdbObject *self)
 {
-       return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
+       if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
+               return PyString_FromString("Tdb(<internal>)");
+       } else {
+               return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
+       }
 }
 
 static void tdb_object_dealloc(PyTdbObject *self)
 {
-       tdb_close(self->ctx);
+       if (!self->closed)
+               tdb_close(self->ctx);
        PyObject_Del(self);
 }
 
@@ -500,8 +583,17 @@ void inittdb(void)
        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_AddObject(m, "__docformat__", PyString_FromString("restructuredText"));
 
+       PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
+
        Py_INCREF(&PyTdb);
        PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);