LCOV - code coverage report
Current view: top level - lib/tdb - pytdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 302 384 78.6 %
Date: 2024-02-28 12:06:22 Functions: 40 45 88.9 %

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

Generated by: LCOV version 1.14