LCOV - code coverage report
Current view: top level - lib/tdb - pytdb.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 259 341 76.0 %
Date: 2024-06-13 04:01:37 Functions: 39 45 86.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Python interface to tdb.
       5             : 
       6             :    Copyright (C) 2004-2006 Tim Potter <tpot@samba.org>
       7             :    Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
       8             : 
       9             :      ** NOTE! The following LGPL license applies to the tdb
      10             :      ** library. This does NOT imply that all of Samba is released
      11             :      ** under the LGPL
      12             : 
      13             :    This library is free software; you can redistribute it and/or
      14             :    modify it under the terms of the GNU Lesser General Public
      15             :    License as published by the Free Software Foundation; either
      16             :    version 3 of the License, or (at your option) any later version.
      17             : 
      18             :    This library is distributed in the hope that it will be useful,
      19             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      20             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      21             :    Lesser General Public License for more details.
      22             : 
      23             :    You should have received a copy of the GNU Lesser General Public
      24             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      25             : */
      26             : 
      27             : #include <Python.h>
      28             : #include "replace.h"
      29             : #include "system/filesys.h"
      30             : 
      31             : /* Include tdb headers */
      32             : #include <tdb.h>
      33             : 
      34             : #if PY_MAJOR_VERSION >= 3
      35             : #define Py_TPFLAGS_HAVE_ITER 0
      36             : #endif
      37             : 
      38             : /* discard signature of 'func' in favour of 'target_sig' */
      39             : #define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
      40             : 
      41             : typedef struct {
      42             :         PyObject_HEAD
      43             :         TDB_CONTEXT *ctx;
      44             :         bool closed;
      45             : } PyTdbObject;
      46             : 
      47             : static PyTypeObject PyTdb;
      48             : 
      49           0 : static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
      50             : {
      51           0 :         PyErr_SetObject(PyExc_RuntimeError, 
      52           0 :                 Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb)));
      53           0 : }
      54             : 
      55          97 : static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data)
      56             : {
      57             :         TDB_DATA ret;
      58          97 :         ret.dptr = (unsigned char *)PyBytes_AsString(data);
      59          97 :         ret.dsize = PyBytes_Size(data);
      60          97 :         return ret;
      61             : }
      62             : 
      63          29 : static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data)
      64             : {
      65          29 :         if (data.dptr == NULL && data.dsize == 0) {
      66           2 :                 Py_RETURN_NONE;
      67             :         } else {
      68          27 :                 PyObject *ret = PyBytes_FromStringAndSize((const char *)data.dptr,
      69          27 :                                                                                                   data.dsize);
      70          27 :                 free(data.dptr);
      71          27 :                 return ret;
      72             :     }
      73             : }
      74             : 
      75             : #define PyErr_TDB_ERROR_IS_ERR_RAISE(ret, tdb) \
      76             :         if (ret != 0) { \
      77             :                 PyErr_SetTDBError(tdb); \
      78             :                 return NULL; \
      79             :         }
      80             : 
      81             : #define PyErr_TDB_RAISE_IF_CLOSED(self) \
      82             :         if (self->closed) {                                          \
      83             :                 PyErr_SetObject(PyExc_RuntimeError,                             \
      84             :                                 Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
      85             :                 return NULL;                                            \
      86             :         }
      87             : 
      88             : #define PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self) \
      89             :         if (self->closed) {                                          \
      90             :                 PyErr_SetObject(PyExc_RuntimeError,                             \
      91             :                                 Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
      92             :                 return -1;                                              \
      93             :         }
      94             : 
      95          65 : static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
      96             : {
      97          65 :         char *name = NULL;
      98          65 :         int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600;
      99             :         TDB_CONTEXT *ctx;
     100             :         PyTdbObject *ret;
     101          65 :         const char *_kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
     102          65 :         char **kwnames = discard_const_p(char *, _kwnames);
     103             : 
     104          65 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
     105           0 :                 return NULL;
     106             : 
     107          65 :         if (name == NULL) {
     108           1 :                 tdb_flags |= TDB_INTERNAL;
     109             :         }
     110             : 
     111          65 :         ctx = tdb_open(name, hash_size, tdb_flags, flags, mode);
     112          65 :         if (ctx == NULL) {
     113          10 :                 PyErr_SetFromErrno(PyExc_IOError);
     114          10 :                 return NULL;
     115             :         }
     116             : 
     117          55 :         ret = PyObject_New(PyTdbObject, &PyTdb);
     118          55 :         if (!ret) {
     119           0 :                 tdb_close(ctx);
     120           0 :                 return NULL;
     121             :         }
     122             : 
     123          55 :         ret->ctx = ctx;
     124          55 :         ret->closed = false;
     125          55 :         return (PyObject *)ret;
     126             : }
     127             : 
     128           2 : static PyObject *obj_transaction_cancel(PyTdbObject *self,
     129             :                 PyObject *Py_UNUSED(ignored))
     130             : {
     131             :         int ret;
     132             : 
     133           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     134             : 
     135           2 :         ret = tdb_transaction_cancel(self->ctx);
     136           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     137           2 :         Py_RETURN_NONE;
     138             : }
     139             : 
     140           4 : static PyObject *obj_transaction_commit(PyTdbObject *self,
     141             :                 PyObject *Py_UNUSED(ignored))
     142             : {
     143             :         int ret;
     144           4 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     145           4 :         ret = tdb_transaction_commit(self->ctx);
     146           4 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     147           4 :         Py_RETURN_NONE;
     148             : }
     149             : 
     150           2 : static PyObject *obj_transaction_prepare_commit(PyTdbObject *self,
     151             :                 PyObject *Py_UNUSED(ignored))
     152             : {
     153             :         int ret;
     154           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     155           2 :         ret = tdb_transaction_prepare_commit(self->ctx);
     156           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     157           2 :         Py_RETURN_NONE;
     158             : }
     159             : 
     160           7 : static PyObject *obj_transaction_start(PyTdbObject *self,
     161             :                 PyObject *Py_UNUSED(ignored))
     162             : {
     163             :         int ret;
     164           7 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     165           6 :         ret = tdb_transaction_start(self->ctx);
     166           6 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     167           6 :         Py_RETURN_NONE;
     168             : }
     169             : 
     170           4 : static PyObject *obj_reopen(PyTdbObject *self,
     171             :                 PyObject *Py_UNUSED(ignored))
     172             : {
     173             :         int ret;
     174           4 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     175           4 :         ret = tdb_reopen(self->ctx);
     176           4 :         if (ret != 0) {
     177           0 :                 self->closed = true;
     178           0 :                 PyErr_SetObject(PyExc_RuntimeError,
     179             :                                 Py_BuildValue("(i,s)",
     180             :                                               TDB_ERR_IO,
     181             :                                               "Failed to reopen database"));
     182           0 :                 return NULL;
     183             :         }
     184           4 :         Py_RETURN_NONE;
     185             : }
     186             : 
     187           4 : static PyObject *obj_lockall(PyTdbObject *self,
     188             :                 PyObject *Py_UNUSED(ignored))
     189             : {
     190             :         int ret;
     191           4 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     192           4 :         ret = tdb_lockall(self->ctx);
     193           4 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     194           4 :         Py_RETURN_NONE;
     195             : }
     196             : 
     197           2 : static PyObject *obj_unlockall(PyTdbObject *self,
     198             :                 PyObject *Py_UNUSED(ignored))
     199             : {
     200             :         int ret;
     201           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     202           2 :         ret = tdb_unlockall(self->ctx);
     203           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     204           2 :         Py_RETURN_NONE;
     205             : }
     206             : 
     207           2 : static PyObject *obj_lockall_read(PyTdbObject *self,
     208             :                 PyObject *Py_UNUSED(ignored))
     209             : {
     210             :         int ret;
     211           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     212           2 :         ret = tdb_lockall_read(self->ctx);
     213           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     214           2 :         Py_RETURN_NONE;
     215             : }
     216             : 
     217           2 : static PyObject *obj_unlockall_read(PyTdbObject *self,
     218             :                 PyObject *Py_UNUSED(ignored))
     219             : {
     220           2 :         int ret = tdb_unlockall_read(self->ctx);
     221           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     222           2 :         Py_RETURN_NONE;
     223             : }
     224             : 
     225           4 : static PyObject *obj_close(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
     226             : {
     227             :         int ret;
     228           4 :         if (self->closed)
     229           1 :                 Py_RETURN_NONE;
     230           3 :         ret = tdb_close(self->ctx);
     231           3 :         self->closed = true;
     232           3 :         if (ret != 0) {
     233           0 :                 PyErr_SetObject(PyExc_RuntimeError,
     234             :                                 Py_BuildValue("(i,s)",
     235             :                                               TDB_ERR_IO,
     236             :                                               "Failed to close database"));
     237           0 :                 return NULL;
     238             :         }
     239           3 :         Py_RETURN_NONE;
     240             : }
     241             : 
     242           5 : static PyObject *obj_get(PyTdbObject *self, PyObject *args)
     243             : {
     244             :         TDB_DATA key;
     245             :         PyObject *py_key;
     246             : 
     247           5 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     248             : 
     249           5 :         if (!PyArg_ParseTuple(args, "O", &py_key))
     250           0 :                 return NULL;
     251             : 
     252           5 :         key = PyBytes_AsTDB_DATA(py_key);
     253           5 :         if (!key.dptr)
     254           0 :                 return NULL;
     255             : 
     256           5 :         return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key));
     257             : }
     258             : 
     259           0 : static PyObject *obj_append(PyTdbObject *self, PyObject *args)
     260             : {
     261             :         TDB_DATA key, data;
     262             :         PyObject *py_key, *py_data;
     263             :         int ret;
     264             : 
     265           0 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     266             : 
     267           0 :         if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
     268           0 :                 return NULL;
     269             : 
     270           0 :         key = PyBytes_AsTDB_DATA(py_key);
     271           0 :         if (!key.dptr)
     272           0 :                 return NULL;
     273           0 :         data = PyBytes_AsTDB_DATA(py_data);
     274           0 :         if (!data.dptr)
     275           0 :                 return NULL;
     276             : 
     277           0 :         ret = tdb_append(self->ctx, key, data);
     278           0 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     279           0 :         Py_RETURN_NONE;
     280             : }
     281             : 
     282           0 : static PyObject *obj_firstkey(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
     283             : {
     284           0 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     285             : 
     286           0 :         return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx));
     287             : }
     288             : 
     289           0 : static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
     290             : {
     291             :         TDB_DATA key;
     292             :         PyObject *py_key;
     293           0 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     294             : 
     295           0 :         if (!PyArg_ParseTuple(args, "O", &py_key))
     296           0 :                 return NULL;
     297             : 
     298           0 :         key = PyBytes_AsTDB_DATA(py_key);
     299           0 :         if (!key.dptr)
     300           0 :                 return NULL;
     301             :         
     302           0 :         return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key));
     303             : }
     304             : 
     305           0 : static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
     306             : {
     307             :         TDB_DATA key;
     308             :         PyObject *py_key;
     309             :         int ret;
     310           0 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     311             : 
     312           0 :         if (!PyArg_ParseTuple(args, "O", &py_key))
     313           0 :                 return NULL;
     314             : 
     315           0 :         key = PyBytes_AsTDB_DATA(py_key);
     316           0 :         if (!key.dptr)
     317           0 :                 return NULL;
     318           0 :         ret = tdb_delete(self->ctx, key);
     319           0 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     320           0 :         Py_RETURN_NONE;
     321             : }
     322             : 
     323           4 : static int obj_contains(PyTdbObject *self, PyObject *py_key)
     324             : {
     325             :         TDB_DATA key;
     326             :         int ret;
     327           4 :         PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
     328             : 
     329           4 :         key = PyBytes_AsTDB_DATA(py_key);
     330           4 :         if (!key.dptr) {
     331           0 :                 PyErr_BadArgument();
     332           0 :                 return -1;
     333             :         }
     334           4 :         ret = tdb_exists(self->ctx, key);
     335           4 :         if (ret)
     336           2 :                 return 1;
     337           2 :         return 0;
     338             : }
     339             : 
     340             : #if PY_MAJOR_VERSION < 3
     341             : static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
     342             : {
     343             :         int ret;
     344             :         PyObject *py_key;
     345             :         PyErr_TDB_RAISE_IF_CLOSED(self);
     346             : 
     347             :         if (!PyArg_ParseTuple(args, "O", &py_key))
     348             :                 return NULL;
     349             : 
     350             :         ret = obj_contains(self, py_key);
     351             :         if (ret == -1)
     352             :                 return NULL;
     353             :         if (ret)
     354             :                 Py_RETURN_TRUE;
     355             :         Py_RETURN_FALSE;
     356             : 
     357             : }
     358             : #endif
     359             : 
     360           2 : static PyObject *obj_store(PyTdbObject *self, PyObject *args)
     361             : {
     362             :         TDB_DATA key, value;
     363             :         int ret;
     364           2 :         int flag = TDB_REPLACE;
     365             :         PyObject *py_key, *py_value;
     366             : 
     367           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     368             : 
     369           2 :         if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
     370           0 :                 return NULL;
     371             : 
     372           2 :         key = PyBytes_AsTDB_DATA(py_key);
     373           2 :         if (!key.dptr)
     374           0 :                 return NULL;
     375           2 :         value = PyBytes_AsTDB_DATA(py_value);
     376           2 :         if (!value.dptr)
     377           0 :                 return NULL;
     378             : 
     379           2 :         ret = tdb_store(self->ctx, key, value, flag);
     380           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     381           2 :         Py_RETURN_NONE;
     382             : }
     383             : 
     384           1 : static PyObject *obj_storev(PyTdbObject *self, PyObject *args)
     385             : {
     386             :         TDB_DATA key, *values, value;
     387             :         int ret;
     388           1 :         int flag = TDB_REPLACE;
     389             :         Py_ssize_t num_values, i;
     390             :         PyObject *py_key, *py_values, *py_value;
     391             : 
     392           1 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     393             : 
     394           1 :         if (!PyArg_ParseTuple(
     395             :                     args, "OO!|i", &py_key, &PyList_Type, &py_values, &flag)) {
     396           0 :                 return NULL;
     397             :         }
     398             : 
     399           1 :         num_values = PyList_Size(py_values);
     400             : 
     401           1 :         key = PyBytes_AsTDB_DATA(py_key);
     402           1 :         if (key.dptr == NULL) {
     403           0 :                 return NULL;
     404             :         }
     405             : 
     406           1 :         if (SSIZE_MAX/sizeof(TDB_DATA) < num_values) {
     407           0 :                 PyErr_SetFromErrno(PyExc_OverflowError);
     408           0 :                 return NULL;
     409             :         }
     410           1 :         values = malloc(sizeof(TDB_DATA) * num_values);
     411           1 :         if (values == NULL) {
     412           0 :                 PyErr_NoMemory();
     413           0 :                 return NULL;
     414             :         }
     415           4 :         for (i=0; i<num_values; i++) {
     416           3 :                 py_value = PyList_GetItem(py_values, i);
     417           3 :                 value = PyBytes_AsTDB_DATA(py_value);
     418           3 :                 if (!value.dptr) {
     419           0 :                         free(values);
     420           0 :                         return NULL;
     421             :                 }
     422           3 :                 values[i] = value;
     423             :         }
     424             : 
     425           1 :         ret = tdb_storev(self->ctx, key, values, num_values, flag);
     426           1 :         free(values);
     427           1 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     428           1 :         Py_RETURN_NONE;
     429             : }
     430             : 
     431           2 : static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
     432             : {
     433             :         unsigned flags;
     434             : 
     435           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     436             : 
     437           2 :         if (!PyArg_ParseTuple(args, "I", &flags))
     438           0 :                 return NULL;
     439             : 
     440           2 :         tdb_add_flags(self->ctx, flags);
     441           2 :         Py_RETURN_NONE;
     442             : }
     443             : 
     444           2 : static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
     445             : {
     446             :         unsigned flags;
     447             : 
     448           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     449             : 
     450           2 :         if (!PyArg_ParseTuple(args, "I", &flags))
     451           0 :                 return NULL;
     452             : 
     453           2 :         tdb_remove_flags(self->ctx, flags);
     454           2 :         Py_RETURN_NONE;
     455             : }
     456             : 
     457             : typedef struct {
     458             :         PyObject_HEAD
     459             :         TDB_DATA current;
     460             :         PyTdbObject *iteratee;
     461             : } PyTdbIteratorObject;
     462             : 
     463          24 : static PyObject *tdb_iter_next(PyTdbIteratorObject *self)
     464             : {
     465             :         TDB_DATA current;
     466             :         PyObject *ret;
     467          24 :         if (self->current.dptr == NULL && self->current.dsize == 0)
     468          10 :                 return NULL;
     469          14 :         current = self->current;
     470          14 :         self->current = tdb_nextkey(self->iteratee->ctx, self->current);
     471          14 :         ret = PyBytes_FromTDB_DATA(current);
     472          14 :         return ret;
     473             : }
     474             : 
     475          12 : static void tdb_iter_dealloc(PyTdbIteratorObject *self)
     476             : {
     477          12 :         Py_DECREF(self->iteratee);
     478          12 :         PyObject_Del(self);
     479          12 : }
     480             : 
     481             : PyTypeObject PyTdbIterator = {
     482             :         .tp_name = "Iterator",
     483             :         .tp_basicsize = sizeof(PyTdbIteratorObject),
     484             :         .tp_iternext = (iternextfunc)tdb_iter_next,
     485             :         .tp_dealloc = (destructor)tdb_iter_dealloc,
     486             :         .tp_flags = Py_TPFLAGS_DEFAULT,
     487             :         .tp_iter = PyObject_SelfIter,
     488             : };
     489             : 
     490          12 : static PyObject *tdb_object_iter(PyTdbObject *self,
     491             :                 PyObject *Py_UNUSED(ignored))
     492             : {
     493             :         PyTdbIteratorObject *ret;       
     494             : 
     495          12 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     496             : 
     497          12 :         ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
     498          12 :         if (!ret)
     499           0 :                 return NULL;
     500          12 :         ret->current = tdb_firstkey(self->ctx);
     501          12 :         ret->iteratee = self;
     502          12 :         Py_INCREF(self);
     503          12 :         return (PyObject *)ret;
     504             : }
     505             : 
     506           2 : static PyObject *obj_clear(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
     507             : {
     508             :         int ret;
     509           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     510           2 :         ret = tdb_wipe_all(self->ctx);
     511           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     512           2 :         Py_RETURN_NONE;
     513             : }
     514             : 
     515           2 : static PyObject *obj_repack(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
     516             : {
     517             :         int ret;
     518           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     519           2 :         ret = tdb_repack(self->ctx);
     520           2 :         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     521           2 :         Py_RETURN_NONE;
     522             : }
     523             : 
     524           1 : static PyObject *obj_enable_seqnum(PyTdbObject *self,
     525             :                 PyObject *Py_UNUSED(ignored))
     526             : {
     527           1 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     528           1 :         tdb_enable_seqnum(self->ctx);
     529           1 :         Py_RETURN_NONE;
     530             : }
     531             : 
     532           1 : static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self,
     533             :                 PyObject *Py_UNUSED(ignored))
     534             : {
     535           1 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     536           1 :         tdb_increment_seqnum_nonblock(self->ctx);
     537           1 :         Py_RETURN_NONE;
     538             : }
     539             : 
     540             : static PyMethodDef tdb_object_methods[] = {
     541             :         { "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS, 
     542             :                 "S.transaction_cancel() -> None\n"
     543             :                 "Cancel the currently active transaction." },
     544             :         { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS,
     545             :                 "S.transaction_commit() -> None\n"
     546             :                 "Commit the currently active transaction." },
     547             :         { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
     548             :                 "S.transaction_prepare_commit() -> None\n"
     549             :                 "Prepare to commit the currently active transaction" },
     550             :         { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
     551             :                 "S.transaction_start() -> None\n"
     552             :                 "Start a new transaction." },
     553             :         { "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." },
     554             :         { "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL },
     555             :         { "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL },
     556             :         { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL },
     557             :         { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL },
     558             :         { "close", (PyCFunction)obj_close, METH_NOARGS, NULL },
     559             :         { "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n"
     560             :                 "Fetch a value." },
     561             :         { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n"
     562             :                 "Append data to an existing key." },
     563             :         { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n"
     564             :                 "Return the first key in this database." },
     565             :         { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n"
     566             :                 "Return the next key in this database." },
     567             :         { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
     568             :                 "Delete an entry." },
     569             : #if PY_MAJOR_VERSION < 3
     570             :         { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n"
     571             :                 "Check whether key exists in this database." },
     572             : #endif
     573             :         { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
     574             :                 "Store data." },
     575             :         { "storev", (PyCFunction)obj_storev, METH_VARARGS, "S.storev(key, data, flag=REPLACE) -> None"
     576             :                 "Store several data." },
     577             :         { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
     578             :         { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
     579             : #if PY_MAJOR_VERSION >= 3
     580             :         { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.keys() -> iterator" },
     581             : #else
     582             :         { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
     583             : #endif
     584             :         { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
     585             :                 "Wipe the entire database." },
     586             :         { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
     587             :                 "Repack the entire database." },
     588             :         { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
     589             :                 "S.enable_seqnum() -> None" },
     590             :         { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
     591             :                 "S.increment_seqnum_nonblock() -> None" },
     592             :         {0}
     593             : };
     594             : 
     595           2 : static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure)
     596             : {
     597           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     598           2 :         return PyLong_FromLong(tdb_hash_size(self->ctx));
     599             : }
     600             : 
     601           2 : static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure)
     602             : {
     603           2 :         PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
     604           2 :         if (!PyLong_Check(max_dead))
     605           0 :                 return -1;
     606           2 :         tdb_set_max_dead(self->ctx, PyLong_AsLong(max_dead));
     607           2 :         return 0;
     608             : }
     609             : 
     610           2 : static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
     611             : {
     612           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     613           2 :         return PyLong_FromLong(tdb_map_size(self->ctx));
     614             : }
     615             : 
     616           2 : static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
     617             : {
     618           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     619           2 :         return PyLong_FromLong(tdb_freelist_size(self->ctx));
     620             : }
     621             : 
     622           0 : static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
     623             : {
     624           0 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     625           0 :         return PyLong_FromLong(tdb_get_flags(self->ctx));
     626             : }
     627             : 
     628           2 : static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
     629             : {
     630           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     631           2 :         return PyBytes_FromString(tdb_name(self->ctx));
     632             : }
     633             : 
     634           2 : static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
     635             : {
     636           2 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     637           2 :         return PyLong_FromLong(tdb_get_seqnum(self->ctx));
     638             : }
     639             : 
     640          47 : static PyObject *obj_get_text(PyTdbObject *self, void *closure)
     641             : {
     642             :         PyObject *mod, *cls, *inst;
     643          47 :         mod = PyImport_ImportModule("_tdb_text");
     644          47 :         if (mod == NULL)
     645           0 :                 return NULL;
     646          47 :         cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
     647          47 :         if (cls == NULL) {
     648           0 :                 Py_DECREF(mod);
     649           0 :                 return NULL;
     650             :         }
     651          47 :         inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
     652          47 :         Py_DECREF(mod);
     653          47 :         Py_DECREF(cls);
     654          47 :         return inst;
     655             : }
     656             : 
     657             : static PyGetSetDef tdb_object_getsetters[] = {
     658             :         {
     659             :                 .name    = discard_const_p(char, "hash_size"),
     660             :                 .get     = (getter)obj_get_hash_size,
     661             :         },
     662             :         {
     663             :                 .name    = discard_const_p(char, "map_size"),
     664             :                 .get     = (getter)obj_get_map_size,
     665             :         },
     666             :         {
     667             :                 .name    = discard_const_p(char, "freelist_size"),
     668             :                 .get     = (getter)obj_get_freelist_size,
     669             :         },
     670             :         {
     671             :                 .name    = discard_const_p(char, "flags"),
     672             :                 .get     = (getter)obj_get_flags,
     673             :         },
     674             :         {
     675             :                 .name    = discard_const_p(char, "max_dead"),
     676             :                 .set     = (setter)obj_set_max_dead,
     677             :         },
     678             :         {
     679             :                 .name    = discard_const_p(char, "filename"),
     680             :                 .get     = (getter)obj_get_filename,
     681             :                 .doc     = discard_const_p(char, "The filename of this TDB file."),
     682             :         },
     683             :         {
     684             :                 .name    = discard_const_p(char, "seqnum"),
     685             :                 .get     = (getter)obj_get_seqnum,
     686             :         },
     687             :         {
     688             :                 .name    = discard_const_p(char, "text"),
     689             :                 .get     = (getter)obj_get_text,
     690             :         },
     691             :         { .name = NULL }
     692             : };
     693             : 
     694           3 : static PyObject *tdb_object_repr(PyTdbObject *self)
     695             : {
     696           3 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     697           3 :         if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
     698           1 :                 return PyUnicode_FromString("Tdb(<internal>)");
     699             :         } else {
     700           2 :                 return PyUnicode_FromFormat("Tdb('%s')", tdb_name(self->ctx));
     701             :         }
     702             : }
     703             : 
     704          55 : static void tdb_object_dealloc(PyTdbObject *self)
     705             : {
     706          55 :         if (!self->closed)
     707          52 :                 tdb_close(self->ctx);
     708          55 :         Py_TYPE(self)->tp_free(self);
     709          55 : }
     710             : 
     711          15 : static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
     712             : {
     713             :         TDB_DATA tkey, val;
     714          15 :         PyErr_TDB_RAISE_IF_CLOSED(self);
     715          14 :         if (!PyBytes_Check(key)) {
     716           0 :                 PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
     717           0 :                 return NULL;
     718             :         }
     719             : 
     720          14 :         tkey.dptr = (unsigned char *)PyBytes_AsString(key);
     721          14 :         tkey.dsize = PyBytes_Size(key);
     722             : 
     723          14 :         val = tdb_fetch(self->ctx, tkey);
     724          14 :         if (val.dptr == NULL) {
     725             :                 /*
     726             :                  * if the key doesn't exist raise KeyError(key) to be
     727             :                  * consistent with python dict
     728             :                  */
     729           4 :                 PyErr_SetObject(PyExc_KeyError, key);
     730           4 :                 return NULL;
     731             :         } else {
     732          10 :                 return PyBytes_FromTDB_DATA(val);
     733             :         }
     734             : }
     735             : 
     736          42 : static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value)
     737             : {
     738             :         TDB_DATA tkey, tval;
     739             :         int ret;
     740          42 :         PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
     741          42 :         if (!PyBytes_Check(key)) {
     742           0 :                 PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
     743           0 :                 return -1;
     744             :         }
     745             : 
     746          42 :         tkey = PyBytes_AsTDB_DATA(key);
     747             : 
     748          42 :         if (value == NULL) { 
     749           4 :                 ret = tdb_delete(self->ctx, tkey);
     750             :         } else { 
     751          38 :                 if (!PyBytes_Check(value)) {
     752           0 :                         PyErr_SetString(PyExc_TypeError, "Expected string as value");
     753           0 :                         return -1;
     754             :                 }
     755             : 
     756          38 :                 tval = PyBytes_AsTDB_DATA(value);
     757             : 
     758          38 :                 ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
     759             :         }
     760             : 
     761          42 :         if (ret != 0) {
     762           0 :                 PyErr_SetTDBError(self->ctx);
     763           0 :                 return -1;
     764             :         } 
     765             : 
     766          42 :         return ret;
     767             : }
     768             : 
     769             : static PyMappingMethods tdb_object_mapping = {
     770             :         .mp_subscript = (binaryfunc)obj_getitem,
     771             :         .mp_ass_subscript = (objobjargproc)obj_setitem,
     772             : };
     773             : static PySequenceMethods tdb_object_seq = {
     774             :         .sq_contains = (objobjproc)obj_contains,
     775             : };
     776             : static PyTypeObject PyTdb = {
     777             :         .tp_name = "tdb.Tdb",
     778             :         .tp_basicsize = sizeof(PyTdbObject),
     779             :         .tp_methods = tdb_object_methods,
     780             :         .tp_getset = tdb_object_getsetters,
     781             :         .tp_new = py_tdb_open,
     782             :         .tp_doc = "A TDB file",
     783             :         .tp_repr = (reprfunc)tdb_object_repr,
     784             :         .tp_dealloc = (destructor)tdb_object_dealloc,
     785             :         .tp_as_mapping = &tdb_object_mapping,
     786             :         .tp_as_sequence = &tdb_object_seq,
     787             :         .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER,
     788             :         .tp_iter = PY_DISCARD_FUNC_SIG(getiterfunc,tdb_object_iter),
     789             : };
     790             : 
     791             : static PyMethodDef tdb_methods[] = {
     792             :         {
     793             :                 .ml_name  = "open",
     794             :                 .ml_meth  = PY_DISCARD_FUNC_SIG(PyCFunction, py_tdb_open),
     795             :                 .ml_flags = METH_VARARGS|METH_KEYWORDS,
     796             :                 .ml_doc   = "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, "
     797             :                             "flags=O_RDWR, mode=0600)\nOpen a TDB file."
     798             :         },
     799             :         { .ml_name = NULL }
     800             : };
     801             : 
     802             : #define MODULE_DOC "simple key-value database that supports multiple writers."
     803             : 
     804             : #if PY_MAJOR_VERSION >= 3
     805             : static struct PyModuleDef moduledef = {
     806             :     PyModuleDef_HEAD_INIT,
     807             :     .m_name = "tdb",
     808             :     .m_doc = MODULE_DOC,
     809             :     .m_size = -1,
     810             :     .m_methods = tdb_methods,
     811             : };
     812             : #endif
     813             : 
     814             : PyObject* module_init(void);
     815        1206 : PyObject* module_init(void)
     816             : {
     817             :         PyObject *m;
     818             : 
     819        1206 :         if (PyType_Ready(&PyTdb) < 0)
     820           0 :                 return NULL;
     821             : 
     822        1206 :         if (PyType_Ready(&PyTdbIterator) < 0)
     823           0 :                 return NULL;
     824             : 
     825             : #if PY_MAJOR_VERSION >= 3
     826        1206 :         m = PyModule_Create(&moduledef);
     827             : #else
     828             :         m = Py_InitModule3("tdb", tdb_methods, MODULE_DOC);
     829             : #endif
     830        1206 :         if (m == NULL)
     831           0 :                 return NULL;
     832             : 
     833        1206 :         PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
     834        1206 :         PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
     835        1206 :         PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
     836             : 
     837        1206 :         PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
     838        1206 :         PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
     839        1206 :         PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
     840        1206 :         PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
     841        1206 :         PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
     842        1206 :         PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
     843        1206 :         PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
     844        1206 :         PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
     845        1206 :         PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
     846        1206 :         PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
     847        1206 :         PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
     848        1206 :         PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
     849        1206 :         PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
     850             : 
     851        1206 :         PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
     852             : 
     853        1206 :         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
     854             : 
     855        1206 :         Py_INCREF(&PyTdb);
     856        1206 :         PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
     857             : 
     858        1206 :         Py_INCREF(&PyTdbIterator);
     859             : 
     860        1206 :     return m;
     861             : }
     862             : 
     863             : 
     864             : #if PY_MAJOR_VERSION >= 3
     865             : PyMODINIT_FUNC PyInit_tdb(void);
     866        1206 : PyMODINIT_FUNC PyInit_tdb(void)
     867             : {
     868        1206 :     return module_init();
     869             : }
     870             : #else
     871             : void inittdb(void);
     872             : void inittdb(void)
     873             : {
     874             :     module_init();
     875             : }
     876             : #endif

Generated by: LCOV version 1.13