LCOV - code coverage report
Current view: | top level - Modules - _gdbmmodule.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 30 | 288 | 10.4 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 6 | 26 | 23.1 %
|  |  | Branches: | 14 | 147 | 9.5 %

               Branch data     Line data    Source code
           1                 :            :
           2                 :            : /* GDBM module using dictionary interface */
           3                 :            : /* Author: Anthony Baxter, after dbmmodule.c */
           4                 :            : /* Doc strings: Mitch Chapman */
           5                 :            :
           6                 :            : #define PY_SSIZE_T_CLEAN
           7                 :            : #include "Python.h"
           8                 :            : #include "gdbm.h"
           9                 :            :
          10                 :            : #include <fcntl.h>
          11                 :            : #include <stdlib.h>               // free()
          12                 :            : #include <sys/stat.h>
          13                 :            : #include <sys/types.h>
          14                 :            :
          15                 :            : #if defined(WIN32) && !defined(__CYGWIN__)
          16                 :            : #include "gdbmerrno.h"
          17                 :            : extern const char * gdbm_strerror(gdbm_error);
          18                 :            : #endif
          19                 :            :
          20                 :            : typedef struct {
          21                 :            :     PyTypeObject *gdbm_type;
          22                 :            :     PyObject *gdbm_error;
          23                 :            : } _gdbm_state;
          24                 :            :
          25                 :            : static inline _gdbm_state*
          26                 :         11 : get_gdbm_state(PyObject *module)
          27                 :            : {
          28                 :         11 :     void *state = PyModule_GetState(module);
          29                 :            :     assert(state != NULL);
          30                 :         11 :     return (_gdbm_state *)state;
          31                 :            : }
          32                 :            :
          33                 :            : /*[clinic input]
          34                 :            : module _gdbm
          35                 :            : class _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
          36                 :            : [clinic start generated code]*/
          37                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
          38                 :            :
          39                 :            : PyDoc_STRVAR(gdbmmodule__doc__,
          40                 :            : "This module provides an interface to the GNU DBM (GDBM) library.\n\
          41                 :            : \n\
          42                 :            : This module is quite similar to the dbm module, but uses GDBM instead to\n\
          43                 :            : provide some additional functionality.  Please note that the file formats\n\
          44                 :            : created by GDBM and dbm are incompatible.\n\
          45                 :            : \n\
          46                 :            : GDBM objects behave like mappings (dictionaries), except that keys and\n\
          47                 :            : values are always immutable bytes-like objects or strings.  Printing\n\
          48                 :            : a GDBM object doesn't print the keys and values, and the items() and\n\
          49                 :            : values() methods are not supported.");
          50                 :            :
          51                 :            : typedef struct {
          52                 :            :     PyObject_HEAD
          53                 :            :     Py_ssize_t di_size;        /* -1 means recompute */
          54                 :            :     GDBM_FILE di_dbm;
          55                 :            : } gdbmobject;
          56                 :            :
          57                 :            : #include "clinic/_gdbmmodule.c.h"
          58                 :            :
          59                 :            : #define check_gdbmobject_open(v, err)                                 \
          60                 :            :     if ((v)->di_dbm == NULL) {                                       \
          61                 :            :         PyErr_SetString(err, "GDBM object has already been closed"); \
          62                 :            :         return NULL;                                                 \
          63                 :            :     }
          64                 :            :
          65                 :            : PyDoc_STRVAR(gdbm_object__doc__,
          66                 :            : "This object represents a GDBM database.\n\
          67                 :            : GDBM objects behave like mappings (dictionaries), except that keys and\n\
          68                 :            : values are always immutable bytes-like objects or strings.  Printing\n\
          69                 :            : a GDBM object doesn't print the keys and values, and the items() and\n\
          70                 :            : values() methods are not supported.\n\
          71                 :            : \n\
          72                 :            : GDBM objects also support additional operations such as firstkey,\n\
          73                 :            : nextkey, reorganize, and sync.");
          74                 :            :
          75                 :            : static PyObject *
          76                 :          0 : newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
          77                 :            : {
          78                 :          0 :     gdbmobject *dp = PyObject_GC_New(gdbmobject, state->gdbm_type);
          79         [ #  # ]:          0 :     if (dp == NULL) {
          80                 :          0 :         return NULL;
          81                 :            :     }
          82                 :          0 :     dp->di_size = -1;
          83                 :          0 :     errno = 0;
          84                 :          0 :     PyObject_GC_Track(dp);
          85                 :            :
          86         [ #  # ]:          0 :     if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
          87         [ #  # ]:          0 :         if (errno != 0) {
          88                 :          0 :             PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
          89                 :            :         }
          90                 :            :         else {
          91                 :          0 :             PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
          92                 :            :         }
          93                 :          0 :         Py_DECREF(dp);
          94                 :          0 :         return NULL;
          95                 :            :     }
          96                 :          0 :     return (PyObject *)dp;
          97                 :            : }
          98                 :            :
          99                 :            : /* Methods */
         100                 :            : static int
         101                 :          0 : gdbm_traverse(gdbmobject *dp, visitproc visit, void *arg)
         102                 :            : {
         103   [ #  #  #  # ]:          0 :     Py_VISIT(Py_TYPE(dp));
         104                 :          0 :     return 0;
         105                 :            : }
         106                 :            :
         107                 :            : static void
         108                 :          0 : gdbm_dealloc(gdbmobject *dp)
         109                 :            : {
         110                 :          0 :     PyObject_GC_UnTrack(dp);
         111         [ #  # ]:          0 :     if (dp->di_dbm) {
         112                 :          0 :         gdbm_close(dp->di_dbm);
         113                 :            :     }
         114                 :          0 :     PyTypeObject *tp = Py_TYPE(dp);
         115                 :          0 :     tp->tp_free(dp);
         116                 :          0 :     Py_DECREF(tp);
         117                 :          0 : }
         118                 :            :
         119                 :            : static Py_ssize_t
         120                 :          0 : gdbm_length(gdbmobject *dp)
         121                 :            : {
         122                 :          0 :     _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
         123         [ #  # ]:          0 :     if (dp->di_dbm == NULL) {
         124                 :          0 :         PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
         125                 :          0 :         return -1;
         126                 :            :     }
         127         [ #  # ]:          0 :     if (dp->di_size < 0) {
         128                 :            : #if GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11
         129                 :          0 :         errno = 0;
         130                 :            :         gdbm_count_t count;
         131         [ #  # ]:          0 :         if (gdbm_count(dp->di_dbm, &count) == -1) {
         132         [ #  # ]:          0 :             if (errno != 0) {
         133                 :          0 :                 PyErr_SetFromErrno(state->gdbm_error);
         134                 :            :             }
         135                 :            :             else {
         136                 :          0 :                 PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
         137                 :            :             }
         138                 :          0 :             return -1;
         139                 :            :         }
         140         [ #  # ]:          0 :         if (count > PY_SSIZE_T_MAX) {
         141                 :          0 :             PyErr_SetString(PyExc_OverflowError, "count exceeds PY_SSIZE_T_MAX");
         142                 :          0 :             return -1;
         143                 :            :         }
         144                 :          0 :         dp->di_size = count;
         145                 :            : #else
         146                 :            :         datum key,okey;
         147                 :            :         okey.dsize=0;
         148                 :            :         okey.dptr=NULL;
         149                 :            :
         150                 :            :         Py_ssize_t size = 0;
         151                 :            :         for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
         152                 :            :              key = gdbm_nextkey(dp->di_dbm,okey)) {
         153                 :            :             size++;
         154                 :            :             if (okey.dsize) {
         155                 :            :                 free(okey.dptr);
         156                 :            :             }
         157                 :            :             okey=key;
         158                 :            :         }
         159                 :            :         dp->di_size = size;
         160                 :            : #endif
         161                 :            :     }
         162                 :          0 :     return dp->di_size;
         163                 :            : }
         164                 :            :
         165                 :            : static int
         166                 :          0 : gdbm_bool(gdbmobject *dp)
         167                 :            : {
         168                 :          0 :     _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
         169         [ #  # ]:          0 :     if (dp->di_dbm == NULL) {
         170                 :          0 :         PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
         171                 :          0 :         return -1;
         172                 :            :     }
         173         [ #  # ]:          0 :     if (dp->di_size > 0) {
         174                 :            :         /* Known non-zero size. */
         175                 :          0 :         return 1;
         176                 :            :     }
         177         [ #  # ]:          0 :     if (dp->di_size == 0) {
         178                 :            :         /* Known zero size. */
         179                 :          0 :         return 0;
         180                 :            :     }
         181                 :            :     /* Unknown size.  Ensure DBM object has an entry. */
         182                 :          0 :     datum key = gdbm_firstkey(dp->di_dbm);
         183         [ #  # ]:          0 :     if (key.dptr == NULL) {
         184                 :            :         /* Empty. Cache this fact. */
         185                 :          0 :         dp->di_size = 0;
         186                 :          0 :         return 0;
         187                 :            :     }
         188                 :            :
         189                 :            :     /* Non-empty. Don't cache the length since we don't know. */
         190                 :          0 :     free(key.dptr);
         191                 :          0 :     return 1;
         192                 :            : }
         193                 :            :
         194                 :            : // Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
         195                 :            : // This function is needed to support PY_SSIZE_T_CLEAN.
         196                 :            : // Return 1 on success, same to PyArg_Parse().
         197                 :            : static int
         198                 :          0 : parse_datum(PyObject *o, datum *d, const char *failmsg)
         199                 :            : {
         200                 :            :     Py_ssize_t size;
         201         [ #  # ]:          0 :     if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
         202         [ #  # ]:          0 :         if (failmsg != NULL) {
         203                 :          0 :             PyErr_SetString(PyExc_TypeError, failmsg);
         204                 :            :         }
         205                 :          0 :         return 0;
         206                 :            :     }
         207         [ #  # ]:          0 :     if (INT_MAX < size) {
         208                 :          0 :         PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
         209                 :          0 :         return 0;
         210                 :            :     }
         211                 :          0 :     d->dsize = size;
         212                 :          0 :     return 1;
         213                 :            : }
         214                 :            :
         215                 :            : static PyObject *
         216                 :          0 : gdbm_subscript(gdbmobject *dp, PyObject *key)
         217                 :            : {
         218                 :            :     PyObject *v;
         219                 :            :     datum drec, krec;
         220                 :          0 :     _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
         221                 :            :
         222         [ #  # ]:          0 :     if (!parse_datum(key, &krec, NULL)) {
         223                 :          0 :         return NULL;
         224                 :            :     }
         225         [ #  # ]:          0 :     if (dp->di_dbm == NULL) {
         226                 :          0 :         PyErr_SetString(state->gdbm_error,
         227                 :            :                         "GDBM object has already been closed");
         228                 :          0 :         return NULL;
         229                 :            :     }
         230                 :          0 :     drec = gdbm_fetch(dp->di_dbm, krec);
         231         [ #  # ]:          0 :     if (drec.dptr == 0) {
         232                 :          0 :         PyErr_SetObject(PyExc_KeyError, key);
         233                 :          0 :         return NULL;
         234                 :            :     }
         235                 :          0 :     v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
         236                 :          0 :     free(drec.dptr);
         237                 :          0 :     return v;
         238                 :            : }
         239                 :            :
         240                 :            : /*[clinic input]
         241                 :            : _gdbm.gdbm.get
         242                 :            :
         243                 :            :     key: object
         244                 :            :     default: object = None
         245                 :            :     /
         246                 :            :
         247                 :            : Get the value for key, or default if not present.
         248                 :            : [clinic start generated code]*/
         249                 :            :
         250                 :            : static PyObject *
         251                 :          0 : _gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
         252                 :            : /*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
         253                 :            : {
         254                 :            :     PyObject *res;
         255                 :            :
         256                 :          0 :     res = gdbm_subscript(self, key);
         257   [ #  #  #  # ]:          0 :     if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
         258                 :          0 :         PyErr_Clear();
         259                 :          0 :         return Py_NewRef(default_value);
         260                 :            :     }
         261                 :          0 :     return res;
         262                 :            : }
         263                 :            :
         264                 :            : static int
         265                 :          0 : gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
         266                 :            : {
         267                 :            :     datum krec, drec;
         268                 :          0 :     const char *failmsg = "gdbm mappings have bytes or string indices only";
         269                 :          0 :     _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
         270                 :            :
         271         [ #  # ]:          0 :     if (!parse_datum(v, &krec, failmsg)) {
         272                 :          0 :         return -1;
         273                 :            :     }
         274         [ #  # ]:          0 :     if (dp->di_dbm == NULL) {
         275                 :          0 :         PyErr_SetString(state->gdbm_error,
         276                 :            :                         "GDBM object has already been closed");
         277                 :          0 :         return -1;
         278                 :            :     }
         279                 :          0 :     dp->di_size = -1;
         280         [ #  # ]:          0 :     if (w == NULL) {
         281         [ #  # ]:          0 :         if (gdbm_delete(dp->di_dbm, krec) < 0) {
         282         [ #  # ]:          0 :             if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
         283                 :          0 :                 PyErr_SetObject(PyExc_KeyError, v);
         284                 :            :             }
         285                 :            :             else {
         286                 :          0 :                 PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
         287                 :            :             }
         288                 :          0 :             return -1;
         289                 :            :         }
         290                 :            :     }
         291                 :            :     else {
         292         [ #  # ]:          0 :         if (!parse_datum(w, &drec, failmsg)) {
         293                 :          0 :             return -1;
         294                 :            :         }
         295                 :          0 :         errno = 0;
         296         [ #  # ]:          0 :         if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
         297         [ #  # ]:          0 :             if (errno != 0)
         298                 :          0 :                 PyErr_SetFromErrno(state->gdbm_error);
         299                 :            :             else
         300                 :          0 :                 PyErr_SetString(state->gdbm_error,
         301                 :          0 :                                 gdbm_strerror(gdbm_errno));
         302                 :          0 :             return -1;
         303                 :            :         }
         304                 :            :     }
         305                 :          0 :     return 0;
         306                 :            : }
         307                 :            :
         308                 :            : /*[clinic input]
         309                 :            : _gdbm.gdbm.setdefault
         310                 :            :
         311                 :            :     key: object
         312                 :            :     default: object = None
         313                 :            :     /
         314                 :            :
         315                 :            : Get value for key, or set it to default and return default if not present.
         316                 :            : [clinic start generated code]*/
         317                 :            :
         318                 :            : static PyObject *
         319                 :          0 : _gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
         320                 :            :                            PyObject *default_value)
         321                 :            : /*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
         322                 :            : {
         323                 :            :     PyObject *res;
         324                 :            :
         325                 :          0 :     res = gdbm_subscript(self, key);
         326   [ #  #  #  # ]:          0 :     if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
         327                 :          0 :         PyErr_Clear();
         328         [ #  # ]:          0 :         if (gdbm_ass_sub(self, key, default_value) < 0)
         329                 :          0 :             return NULL;
         330                 :          0 :         return gdbm_subscript(self, key);
         331                 :            :     }
         332                 :          0 :     return res;
         333                 :            : }
         334                 :            :
         335                 :            : /*[clinic input]
         336                 :            : _gdbm.gdbm.close
         337                 :            :
         338                 :            : Close the database.
         339                 :            : [clinic start generated code]*/
         340                 :            :
         341                 :            : static PyObject *
         342                 :          0 : _gdbm_gdbm_close_impl(gdbmobject *self)
         343                 :            : /*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
         344                 :            : {
         345         [ #  # ]:          0 :     if (self->di_dbm) {
         346                 :          0 :         gdbm_close(self->di_dbm);
         347                 :            :     }
         348                 :          0 :     self->di_dbm = NULL;
         349                 :          0 :     Py_RETURN_NONE;
         350                 :            : }
         351                 :            :
         352                 :            : /* XXX Should return a set or a set view */
         353                 :            : /*[clinic input]
         354                 :            : _gdbm.gdbm.keys
         355                 :            :
         356                 :            :     cls: defining_class
         357                 :            :
         358                 :            : Get a list of all keys in the database.
         359                 :            : [clinic start generated code]*/
         360                 :            :
         361                 :            : static PyObject *
         362                 :          0 : _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
         363                 :            : /*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
         364                 :            : {
         365                 :            :     PyObject *v, *item;
         366                 :            :     datum key, nextkey;
         367                 :            :     int err;
         368                 :            :
         369                 :          0 :     _gdbm_state *state = PyType_GetModuleState(cls);
         370                 :            :     assert(state != NULL);
         371                 :            :
         372   [ #  #  #  # ]:          0 :     if (self == NULL || !Py_IS_TYPE(self, state->gdbm_type)) {
         373                 :          0 :         PyErr_BadInternalCall();
         374                 :          0 :         return NULL;
         375                 :            :     }
         376         [ #  # ]:          0 :     check_gdbmobject_open(self, state->gdbm_error);
         377                 :            :
         378                 :          0 :     v = PyList_New(0);
         379         [ #  # ]:          0 :     if (v == NULL)
         380                 :          0 :         return NULL;
         381                 :            :
         382                 :          0 :     key = gdbm_firstkey(self->di_dbm);
         383         [ #  # ]:          0 :     while (key.dptr) {
         384                 :          0 :         item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
         385         [ #  # ]:          0 :         if (item == NULL) {
         386                 :          0 :             free(key.dptr);
         387                 :          0 :             Py_DECREF(v);
         388                 :          0 :             return NULL;
         389                 :            :         }
         390                 :          0 :         err = PyList_Append(v, item);
         391                 :          0 :         Py_DECREF(item);
         392         [ #  # ]:          0 :         if (err != 0) {
         393                 :          0 :             free(key.dptr);
         394                 :          0 :             Py_DECREF(v);
         395                 :          0 :             return NULL;
         396                 :            :         }
         397                 :          0 :         nextkey = gdbm_nextkey(self->di_dbm, key);
         398                 :          0 :         free(key.dptr);
         399                 :          0 :         key = nextkey;
         400                 :            :     }
         401                 :          0 :     return v;
         402                 :            : }
         403                 :            :
         404                 :            : static int
         405                 :          0 : gdbm_contains(PyObject *self, PyObject *arg)
         406                 :            : {
         407                 :          0 :     gdbmobject *dp = (gdbmobject *)self;
         408                 :            :     datum key;
         409                 :            :     Py_ssize_t size;
         410                 :          0 :     _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
         411                 :            :
         412         [ #  # ]:          0 :     if ((dp)->di_dbm == NULL) {
         413                 :          0 :         PyErr_SetString(state->gdbm_error,
         414                 :            :                         "GDBM object has already been closed");
         415                 :          0 :         return -1;
         416                 :            :     }
         417         [ #  # ]:          0 :     if (PyUnicode_Check(arg)) {
         418                 :          0 :         key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
         419                 :          0 :         key.dsize = size;
         420         [ #  # ]:          0 :         if (key.dptr == NULL)
         421                 :          0 :             return -1;
         422                 :            :     }
         423         [ #  # ]:          0 :     else if (!PyBytes_Check(arg)) {
         424                 :          0 :         PyErr_Format(PyExc_TypeError,
         425                 :            :                      "gdbm key must be bytes or string, not %.100s",
         426                 :          0 :                      Py_TYPE(arg)->tp_name);
         427                 :          0 :         return -1;
         428                 :            :     }
         429                 :            :     else {
         430                 :          0 :         key.dptr = PyBytes_AS_STRING(arg);
         431                 :          0 :         key.dsize = PyBytes_GET_SIZE(arg);
         432                 :            :     }
         433                 :          0 :     return gdbm_exists(dp->di_dbm, key);
         434                 :            : }
         435                 :            :
         436                 :            : /*[clinic input]
         437                 :            : _gdbm.gdbm.firstkey
         438                 :            :
         439                 :            :     cls: defining_class
         440                 :            :
         441                 :            : Return the starting key for the traversal.
         442                 :            :
         443                 :            : It's possible to loop over every key in the database using this method
         444                 :            : and the nextkey() method.  The traversal is ordered by GDBM's internal
         445                 :            : hash values, and won't be sorted by the key values.
         446                 :            : [clinic start generated code]*/
         447                 :            :
         448                 :            : static PyObject *
         449                 :          0 : _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
         450                 :            : /*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
         451                 :            : {
         452                 :            :     PyObject *v;
         453                 :            :     datum key;
         454                 :          0 :     _gdbm_state *state = PyType_GetModuleState(cls);
         455                 :            :     assert(state != NULL);
         456                 :            :
         457         [ #  # ]:          0 :     check_gdbmobject_open(self, state->gdbm_error);
         458                 :          0 :     key = gdbm_firstkey(self->di_dbm);
         459         [ #  # ]:          0 :     if (key.dptr) {
         460                 :          0 :         v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
         461                 :          0 :         free(key.dptr);
         462                 :          0 :         return v;
         463                 :            :     }
         464                 :            :     else {
         465                 :          0 :         Py_RETURN_NONE;
         466                 :            :     }
         467                 :            : }
         468                 :            :
         469                 :            : /*[clinic input]
         470                 :            : _gdbm.gdbm.nextkey
         471                 :            :
         472                 :            :     cls: defining_class
         473                 :            :     key: str(accept={str, robuffer}, zeroes=True)
         474                 :            :     /
         475                 :            :
         476                 :            : Returns the key that follows key in the traversal.
         477                 :            :
         478                 :            : The following code prints every key in the database db, without having
         479                 :            : to create a list in memory that contains them all:
         480                 :            :
         481                 :            :       k = db.firstkey()
         482                 :            :       while k is not None:
         483                 :            :           print(k)
         484                 :            :           k = db.nextkey(k)
         485                 :            : [clinic start generated code]*/
         486                 :            :
         487                 :            : static PyObject *
         488                 :          0 : _gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
         489                 :            :                         Py_ssize_t key_length)
         490                 :            : /*[clinic end generated code: output=c81a69300ef41766 input=365e297bc0b3db48]*/
         491                 :            : {
         492                 :            :     PyObject *v;
         493                 :            :     datum dbm_key, nextkey;
         494                 :          0 :     _gdbm_state *state = PyType_GetModuleState(cls);
         495                 :            :     assert(state != NULL);
         496                 :            :
         497                 :          0 :     dbm_key.dptr = (char *)key;
         498                 :          0 :     dbm_key.dsize = key_length;
         499         [ #  # ]:          0 :     check_gdbmobject_open(self, state->gdbm_error);
         500                 :          0 :     nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
         501         [ #  # ]:          0 :     if (nextkey.dptr) {
         502                 :          0 :         v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
         503                 :          0 :         free(nextkey.dptr);
         504                 :          0 :         return v;
         505                 :            :     }
         506                 :            :     else {
         507                 :          0 :         Py_RETURN_NONE;
         508                 :            :     }
         509                 :            : }
         510                 :            :
         511                 :            : /*[clinic input]
         512                 :            : _gdbm.gdbm.reorganize
         513                 :            :
         514                 :            :     cls: defining_class
         515                 :            :
         516                 :            : Reorganize the database.
         517                 :            :
         518                 :            : If you have carried out a lot of deletions and would like to shrink
         519                 :            : the space used by the GDBM file, this routine will reorganize the
         520                 :            : database.  GDBM will not shorten the length of a database file except
         521                 :            : by using this reorganization; otherwise, deleted file space will be
         522                 :            : kept and reused as new (key,value) pairs are added.
         523                 :            : [clinic start generated code]*/
         524                 :            :
         525                 :            : static PyObject *
         526                 :          0 : _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
         527                 :            : /*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
         528                 :            : {
         529                 :          0 :     _gdbm_state *state = PyType_GetModuleState(cls);
         530                 :            :     assert(state != NULL);
         531         [ #  # ]:          0 :     check_gdbmobject_open(self, state->gdbm_error);
         532                 :          0 :     errno = 0;
         533         [ #  # ]:          0 :     if (gdbm_reorganize(self->di_dbm) < 0) {
         534         [ #  # ]:          0 :         if (errno != 0)
         535                 :          0 :             PyErr_SetFromErrno(state->gdbm_error);
         536                 :            :         else
         537                 :          0 :             PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
         538                 :          0 :         return NULL;
         539                 :            :     }
         540                 :          0 :     Py_RETURN_NONE;
         541                 :            : }
         542                 :            :
         543                 :            : /*[clinic input]
         544                 :            : _gdbm.gdbm.sync
         545                 :            :
         546                 :            :     cls: defining_class
         547                 :            :
         548                 :            : Flush the database to the disk file.
         549                 :            :
         550                 :            : When the database has been opened in fast mode, this method forces
         551                 :            : any unwritten data to be written to the disk.
         552                 :            : [clinic start generated code]*/
         553                 :            :
         554                 :            : static PyObject *
         555                 :          0 : _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
         556                 :            : /*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
         557                 :            : {
         558                 :          0 :     _gdbm_state *state = PyType_GetModuleState(cls);
         559                 :            :     assert(state != NULL);
         560         [ #  # ]:          0 :     check_gdbmobject_open(self, state->gdbm_error);
         561                 :          0 :     gdbm_sync(self->di_dbm);
         562                 :          0 :     Py_RETURN_NONE;
         563                 :            : }
         564                 :            :
         565                 :            : static PyObject *
         566                 :          0 : gdbm__enter__(PyObject *self, PyObject *args)
         567                 :            : {
         568                 :          0 :     return Py_NewRef(self);
         569                 :            : }
         570                 :            :
         571                 :            : static PyObject *
         572                 :          0 : gdbm__exit__(PyObject *self, PyObject *args)
         573                 :            : {
         574                 :          0 :     return _gdbm_gdbm_close_impl((gdbmobject *)self);
         575                 :            : }
         576                 :            :
         577                 :            : static PyMethodDef gdbm_methods[] = {
         578                 :            :     _GDBM_GDBM_CLOSE_METHODDEF
         579                 :            :     _GDBM_GDBM_KEYS_METHODDEF
         580                 :            :     _GDBM_GDBM_FIRSTKEY_METHODDEF
         581                 :            :     _GDBM_GDBM_NEXTKEY_METHODDEF
         582                 :            :     _GDBM_GDBM_REORGANIZE_METHODDEF
         583                 :            :     _GDBM_GDBM_SYNC_METHODDEF
         584                 :            :     _GDBM_GDBM_GET_METHODDEF
         585                 :            :     _GDBM_GDBM_SETDEFAULT_METHODDEF
         586                 :            :     {"__enter__", gdbm__enter__, METH_NOARGS, NULL},
         587                 :            :     {"__exit__",  gdbm__exit__, METH_VARARGS, NULL},
         588                 :            :     {NULL,              NULL}           /* sentinel */
         589                 :            : };
         590                 :            :
         591                 :            : static PyType_Slot gdbmtype_spec_slots[] = {
         592                 :            :     {Py_tp_dealloc, gdbm_dealloc},
         593                 :            :     {Py_tp_traverse, gdbm_traverse},
         594                 :            :     {Py_tp_methods, gdbm_methods},
         595                 :            :     {Py_sq_contains, gdbm_contains},
         596                 :            :     {Py_mp_length, gdbm_length},
         597                 :            :     {Py_mp_subscript, gdbm_subscript},
         598                 :            :     {Py_mp_ass_subscript, gdbm_ass_sub},
         599                 :            :     {Py_nb_bool, gdbm_bool},
         600                 :            :     {Py_tp_doc, (char*)gdbm_object__doc__},
         601                 :            :     {0, 0}
         602                 :            : };
         603                 :            :
         604                 :            : static PyType_Spec gdbmtype_spec = {
         605                 :            :     .name = "_gdbm.gdbm",
         606                 :            :     .basicsize = sizeof(gdbmobject),
         607                 :            :     // Calling PyType_GetModuleState() on a subclass is not safe.
         608                 :            :     // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
         609                 :            :     // which prevents to create a subclass.
         610                 :            :     // So calling PyType_GetModuleState() in this file is always safe.
         611                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
         612                 :            :               Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
         613                 :            :     .slots = gdbmtype_spec_slots,
         614                 :            : };
         615                 :            :
         616                 :            : /* ----------------------------------------------------------------- */
         617                 :            :
         618                 :            : /*[clinic input]
         619                 :            : _gdbm.open as dbmopen
         620                 :            :
         621                 :            :     filename: object
         622                 :            :     flags: str="r"
         623                 :            :     mode: int(py_default="0o666") = 0o666
         624                 :            :     /
         625                 :            :
         626                 :            : Open a dbm database and return a dbm object.
         627                 :            :
         628                 :            : The filename argument is the name of the database file.
         629                 :            :
         630                 :            : The optional flags argument can be 'r' (to open an existing database
         631                 :            : for reading only -- default), 'w' (to open an existing database for
         632                 :            : reading and writing), 'c' (which creates the database if it doesn't
         633                 :            : exist), or 'n' (which always creates a new empty database).
         634                 :            :
         635                 :            : Some versions of gdbm support additional flags which must be
         636                 :            : appended to one of the flags described above.  The module constant
         637                 :            : 'open_flags' is a string of valid additional flags.  The 'f' flag
         638                 :            : opens the database in fast mode; altered data will not automatically
         639                 :            : be written to the disk after every change.  This results in faster
         640                 :            : writes to the database, but may result in an inconsistent database
         641                 :            : if the program crashes while the database is still open.  Use the
         642                 :            : sync() method to force any unwritten data to be written to the disk.
         643                 :            : The 's' flag causes all database operations to be synchronized to
         644                 :            : disk.  The 'u' flag disables locking of the database file.
         645                 :            :
         646                 :            : The optional mode argument is the Unix mode of the file, used only
         647                 :            : when the database has to be created.  It defaults to octal 0o666.
         648                 :            : [clinic start generated code]*/
         649                 :            :
         650                 :            : static PyObject *
         651                 :          0 : dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
         652                 :            :              int mode)
         653                 :            : /*[clinic end generated code: output=9527750f5df90764 input=bca6ec81dc49292c]*/
         654                 :            : {
         655                 :            :     int iflags;
         656                 :          0 :     _gdbm_state *state = get_gdbm_state(module);
         657                 :            :     assert(state != NULL);
         658                 :            :
         659   [ #  #  #  #  :          0 :     switch (flags[0]) {
                          # ]
         660                 :          0 :     case 'r':
         661                 :          0 :         iflags = GDBM_READER;
         662                 :          0 :         break;
         663                 :          0 :     case 'w':
         664                 :          0 :         iflags = GDBM_WRITER;
         665                 :          0 :         break;
         666                 :          0 :     case 'c':
         667                 :          0 :         iflags = GDBM_WRCREAT;
         668                 :          0 :         break;
         669                 :          0 :     case 'n':
         670                 :          0 :         iflags = GDBM_NEWDB;
         671                 :          0 :         break;
         672                 :          0 :     default:
         673                 :          0 :         PyErr_SetString(state->gdbm_error,
         674                 :            :                         "First flag must be one of 'r', 'w', 'c' or 'n'");
         675                 :          0 :         return NULL;
         676                 :            :     }
         677         [ #  # ]:          0 :     for (flags++; *flags != '\0'; flags++) {
         678   [ #  #  #  # ]:          0 :         switch (*flags) {
         679                 :            : #ifdef GDBM_FAST
         680                 :          0 :             case 'f':
         681                 :          0 :                 iflags |= GDBM_FAST;
         682                 :          0 :                 break;
         683                 :            : #endif
         684                 :            : #ifdef GDBM_SYNC
         685                 :          0 :             case 's':
         686                 :          0 :                 iflags |= GDBM_SYNC;
         687                 :          0 :                 break;
         688                 :            : #endif
         689                 :            : #ifdef GDBM_NOLOCK
         690                 :          0 :             case 'u':
         691                 :          0 :                 iflags |= GDBM_NOLOCK;
         692                 :          0 :                 break;
         693                 :            : #endif
         694                 :          0 :             default:
         695                 :          0 :                 PyErr_Format(state->gdbm_error,
         696                 :          0 :                              "Flag '%c' is not supported.", (unsigned char)*flags);
         697                 :          0 :                 return NULL;
         698                 :            :         }
         699                 :            :     }
         700                 :            :
         701                 :            :     PyObject *filenamebytes;
         702         [ #  # ]:          0 :     if (!PyUnicode_FSConverter(filename, &filenamebytes)) {
         703                 :          0 :         return NULL;
         704                 :            :     }
         705                 :            :
         706                 :          0 :     const char *name = PyBytes_AS_STRING(filenamebytes);
         707         [ #  # ]:          0 :     if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
         708                 :          0 :         Py_DECREF(filenamebytes);
         709                 :          0 :         PyErr_SetString(PyExc_ValueError, "embedded null character");
         710                 :          0 :         return NULL;
         711                 :            :     }
         712                 :          0 :     PyObject *self = newgdbmobject(state, name, iflags, mode);
         713                 :          0 :     Py_DECREF(filenamebytes);
         714                 :          0 :     return self;
         715                 :            : }
         716                 :            :
         717                 :            : static const char gdbmmodule_open_flags[] = "rwcn"
         718                 :            : #ifdef GDBM_FAST
         719                 :            :                                      "f"
         720                 :            : #endif
         721                 :            : #ifdef GDBM_SYNC
         722                 :            :                                      "s"
         723                 :            : #endif
         724                 :            : #ifdef GDBM_NOLOCK
         725                 :            :                                      "u"
         726                 :            : #endif
         727                 :            :                                      ;
         728                 :            :
         729                 :            : static PyMethodDef _gdbm_module_methods[] = {
         730                 :            :     DBMOPEN_METHODDEF
         731                 :            :     { 0, 0 },
         732                 :            : };
         733                 :            :
         734                 :            : static int
         735                 :          1 : _gdbm_exec(PyObject *module)
         736                 :            : {
         737                 :          1 :     _gdbm_state *state = get_gdbm_state(module);
         738                 :          1 :     state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
         739                 :            :                                                         &gdbmtype_spec, NULL);
         740         [ -  + ]:          1 :     if (state->gdbm_type == NULL) {
         741                 :          0 :         return -1;
         742                 :            :     }
         743                 :          1 :     state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
         744         [ -  + ]:          1 :     if (state->gdbm_error == NULL) {
         745                 :          0 :         return -1;
         746                 :            :     }
         747         [ -  + ]:          1 :     if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
         748                 :          0 :         return -1;
         749                 :            :     }
         750         [ -  + ]:          1 :     if (PyModule_AddStringConstant(module, "open_flags",
         751                 :            :                                    gdbmmodule_open_flags) < 0) {
         752                 :          0 :         return -1;
         753                 :            :     }
         754                 :            :
         755                 :            : #if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
         756                 :            :     defined(GDBM_VERSION_PATCH)
         757                 :          1 :     PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
         758                 :            :                                   GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
         759         [ -  + ]:          1 :     if (obj == NULL) {
         760                 :          0 :         return -1;
         761                 :            :     }
         762         [ -  + ]:          1 :     if (PyModule_AddObject(module, "_GDBM_VERSION", obj) < 0) {
         763                 :          0 :         Py_DECREF(obj);
         764                 :          0 :         return -1;
         765                 :            :     }
         766                 :            : #endif
         767                 :          1 :     return 0;
         768                 :            : }
         769                 :            :
         770                 :            : static int
         771                 :          8 : _gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
         772                 :            : {
         773                 :          8 :     _gdbm_state *state = get_gdbm_state(module);
         774   [ +  -  -  + ]:          8 :     Py_VISIT(state->gdbm_error);
         775   [ +  -  -  + ]:          8 :     Py_VISIT(state->gdbm_type);
         776                 :          8 :     return 0;
         777                 :            : }
         778                 :            :
         779                 :            : static int
         780                 :          2 : _gdbm_module_clear(PyObject *module)
         781                 :            : {
         782                 :          2 :     _gdbm_state *state = get_gdbm_state(module);
         783         [ +  + ]:          2 :     Py_CLEAR(state->gdbm_error);
         784         [ +  + ]:          2 :     Py_CLEAR(state->gdbm_type);
         785                 :          2 :     return 0;
         786                 :            : }
         787                 :            :
         788                 :            : static void
         789                 :          1 : _gdbm_module_free(void *module)
         790                 :            : {
         791                 :          1 :     _gdbm_module_clear((PyObject *)module);
         792                 :          1 : }
         793                 :            :
         794                 :            : static PyModuleDef_Slot _gdbm_module_slots[] = {
         795                 :            :     {Py_mod_exec, _gdbm_exec},
         796                 :            :     {0, NULL}
         797                 :            : };
         798                 :            :
         799                 :            : static struct PyModuleDef _gdbmmodule = {
         800                 :            :     PyModuleDef_HEAD_INIT,
         801                 :            :     .m_name = "_gdbm",
         802                 :            :     .m_doc = gdbmmodule__doc__,
         803                 :            :     .m_size = sizeof(_gdbm_state),
         804                 :            :     .m_methods = _gdbm_module_methods,
         805                 :            :     .m_slots = _gdbm_module_slots,
         806                 :            :     .m_traverse = _gdbm_module_traverse,
         807                 :            :     .m_clear = _gdbm_module_clear,
         808                 :            :     .m_free = _gdbm_module_free,
         809                 :            : };
         810                 :            :
         811                 :            : PyMODINIT_FUNC
         812                 :          1 : PyInit__gdbm(void)
         813                 :            : {
         814                 :          1 :     return PyModuleDef_Init(&_gdbmmodule);
         815                 :            : }

Generated by: LCOV version 1.14