Home | History | Annotate | Download | only in Modules
      1 
      2 /* DBM module using dictionary interface */
      3 /* Author: Anthony Baxter, after dbmmodule.c */
      4 /* Doc strings: Mitch Chapman */
      5 
      6 
      7 #include "Python.h"
      8 
      9 #include <sys/types.h>
     10 #include <sys/stat.h>
     11 #include <fcntl.h>
     12 #include "gdbm.h"
     13 
     14 #if defined(WIN32) && !defined(__CYGWIN__)
     15 #include "gdbmerrno.h"
     16 extern const char * gdbm_strerror(gdbm_error);
     17 #endif
     18 
     19 /*[clinic input]
     20 module _gdbm
     21 class _gdbm.gdbm "dbmobject *" "&Dbmtype"
     22 [clinic start generated code]*/
     23 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=113927c6170729b2]*/
     24 
     25 PyDoc_STRVAR(gdbmmodule__doc__,
     26 "This module provides an interface to the GNU DBM (GDBM) library.\n\
     27 \n\
     28 This module is quite similar to the dbm module, but uses GDBM instead to\n\
     29 provide some additional functionality.  Please note that the file formats\n\
     30 created by GDBM and dbm are incompatible.\n\
     31 \n\
     32 GDBM objects behave like mappings (dictionaries), except that keys and\n\
     33 values are always immutable bytes-like objects or strings.  Printing\n\
     34 a GDBM object doesn't print the keys and values, and the items() and\n\
     35 values() methods are not supported.");
     36 
     37 typedef struct {
     38     PyObject_HEAD
     39     int di_size;        /* -1 means recompute */
     40     GDBM_FILE di_dbm;
     41 } dbmobject;
     42 
     43 static PyTypeObject Dbmtype;
     44 
     45 #include "clinic/_gdbmmodule.c.h"
     46 
     47 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
     48 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
     49     { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
     50       return NULL; }
     51 
     52 
     53 
     54 static PyObject *DbmError;
     55 
     56 PyDoc_STRVAR(gdbm_object__doc__,
     57 "This object represents a GDBM database.\n\
     58 GDBM objects behave like mappings (dictionaries), except that keys and\n\
     59 values are always immutable bytes-like objects or strings.  Printing\n\
     60 a GDBM object doesn't print the keys and values, and the items() and\n\
     61 values() methods are not supported.\n\
     62 \n\
     63 GDBM objects also support additional operations such as firstkey,\n\
     64 nextkey, reorganize, and sync.");
     65 
     66 static PyObject *
     67 newdbmobject(const char *file, int flags, int mode)
     68 {
     69     dbmobject *dp;
     70 
     71     dp = PyObject_New(dbmobject, &Dbmtype);
     72     if (dp == NULL)
     73         return NULL;
     74     dp->di_size = -1;
     75     errno = 0;
     76     if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
     77         if (errno != 0)
     78             PyErr_SetFromErrno(DbmError);
     79         else
     80             PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
     81         Py_DECREF(dp);
     82         return NULL;
     83     }
     84     return (PyObject *)dp;
     85 }
     86 
     87 /* Methods */
     88 
     89 static void
     90 dbm_dealloc(dbmobject *dp)
     91 {
     92     if (dp->di_dbm)
     93         gdbm_close(dp->di_dbm);
     94     PyObject_Del(dp);
     95 }
     96 
     97 static Py_ssize_t
     98 dbm_length(dbmobject *dp)
     99 {
    100     if (dp->di_dbm == NULL) {
    101         PyErr_SetString(DbmError, "GDBM object has already been closed");
    102         return -1;
    103     }
    104     if (dp->di_size < 0) {
    105         datum key,okey;
    106         int size;
    107         okey.dsize=0;
    108         okey.dptr=NULL;
    109 
    110         size = 0;
    111         for (key=gdbm_firstkey(dp->di_dbm); key.dptr;
    112              key = gdbm_nextkey(dp->di_dbm,okey)) {
    113             size++;
    114             if(okey.dsize) free(okey.dptr);
    115             okey=key;
    116         }
    117         dp->di_size = size;
    118     }
    119     return dp->di_size;
    120 }
    121 
    122 static PyObject *
    123 dbm_subscript(dbmobject *dp, PyObject *key)
    124 {
    125     PyObject *v;
    126     datum drec, krec;
    127 
    128     if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
    129         return NULL;
    130 
    131     if (dp->di_dbm == NULL) {
    132         PyErr_SetString(DbmError,
    133                         "GDBM object has already been closed");
    134         return NULL;
    135     }
    136     drec = gdbm_fetch(dp->di_dbm, krec);
    137     if (drec.dptr == 0) {
    138         PyErr_SetObject(PyExc_KeyError, key);
    139         return NULL;
    140     }
    141     v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
    142     free(drec.dptr);
    143     return v;
    144 }
    145 
    146 /*[clinic input]
    147 _gdbm.gdbm.get
    148 
    149     key: object
    150     default: object = None
    151     /
    152 
    153 Get the value for key, or default if not present.
    154 [clinic start generated code]*/
    155 
    156 static PyObject *
    157 _gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
    158 /*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/
    159 {
    160     PyObject *res;
    161 
    162     res = dbm_subscript(self, key);
    163     if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
    164         PyErr_Clear();
    165         Py_INCREF(default_value);
    166         return default_value;
    167     }
    168     return res;
    169 }
    170 
    171 static int
    172 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
    173 {
    174     datum krec, drec;
    175 
    176     if (!PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
    177         PyErr_SetString(PyExc_TypeError,
    178                         "gdbm mappings have bytes or string indices only");
    179         return -1;
    180     }
    181     if (dp->di_dbm == NULL) {
    182         PyErr_SetString(DbmError,
    183                         "GDBM object has already been closed");
    184         return -1;
    185     }
    186     dp->di_size = -1;
    187     if (w == NULL) {
    188         if (gdbm_delete(dp->di_dbm, krec) < 0) {
    189             PyErr_SetObject(PyExc_KeyError, v);
    190             return -1;
    191         }
    192     }
    193     else {
    194         if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) {
    195             PyErr_SetString(PyExc_TypeError,
    196                             "gdbm mappings have byte or string elements only");
    197             return -1;
    198         }
    199         errno = 0;
    200         if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
    201             if (errno != 0)
    202                 PyErr_SetFromErrno(DbmError);
    203             else
    204                 PyErr_SetString(DbmError,
    205                                 gdbm_strerror(gdbm_errno));
    206             return -1;
    207         }
    208     }
    209     return 0;
    210 }
    211 
    212 /*[clinic input]
    213 _gdbm.gdbm.setdefault
    214 
    215     key: object
    216     default: object = None
    217     /
    218 
    219 Get value for key, or set it to default and return default if not present.
    220 [clinic start generated code]*/
    221 
    222 static PyObject *
    223 _gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
    224                            PyObject *default_value)
    225 /*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/
    226 {
    227     PyObject *res;
    228 
    229     res = dbm_subscript(self, key);
    230     if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
    231         PyErr_Clear();
    232         if (dbm_ass_sub(self, key, default_value) < 0)
    233             return NULL;
    234         return dbm_subscript(self, key);
    235     }
    236     return res;
    237 }
    238 
    239 static PyMappingMethods dbm_as_mapping = {
    240     (lenfunc)dbm_length,                /*mp_length*/
    241     (binaryfunc)dbm_subscript,          /*mp_subscript*/
    242     (objobjargproc)dbm_ass_sub,         /*mp_ass_subscript*/
    243 };
    244 
    245 /*[clinic input]
    246 _gdbm.gdbm.close
    247 
    248 Close the database.
    249 [clinic start generated code]*/
    250 
    251 static PyObject *
    252 _gdbm_gdbm_close_impl(dbmobject *self)
    253 /*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/
    254 {
    255     if (self->di_dbm)
    256         gdbm_close(self->di_dbm);
    257     self->di_dbm = NULL;
    258     Py_INCREF(Py_None);
    259     return Py_None;
    260 }
    261 
    262 /* XXX Should return a set or a set view */
    263 /*[clinic input]
    264 _gdbm.gdbm.keys
    265 
    266 Get a list of all keys in the database.
    267 [clinic start generated code]*/
    268 
    269 static PyObject *
    270 _gdbm_gdbm_keys_impl(dbmobject *self)
    271 /*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/
    272 {
    273     PyObject *v, *item;
    274     datum key, nextkey;
    275     int err;
    276 
    277     if (self == NULL || !is_dbmobject(self)) {
    278         PyErr_BadInternalCall();
    279         return NULL;
    280     }
    281     check_dbmobject_open(self);
    282 
    283     v = PyList_New(0);
    284     if (v == NULL)
    285         return NULL;
    286 
    287     key = gdbm_firstkey(self->di_dbm);
    288     while (key.dptr) {
    289         item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
    290         if (item == NULL) {
    291             free(key.dptr);
    292             Py_DECREF(v);
    293             return NULL;
    294         }
    295         err = PyList_Append(v, item);
    296         Py_DECREF(item);
    297         if (err != 0) {
    298             free(key.dptr);
    299             Py_DECREF(v);
    300             return NULL;
    301         }
    302         nextkey = gdbm_nextkey(self->di_dbm, key);
    303         free(key.dptr);
    304         key = nextkey;
    305     }
    306     return v;
    307 }
    308 
    309 static int
    310 dbm_contains(PyObject *self, PyObject *arg)
    311 {
    312     dbmobject *dp = (dbmobject *)self;
    313     datum key;
    314     Py_ssize_t size;
    315 
    316     if ((dp)->di_dbm == NULL) {
    317         PyErr_SetString(DbmError,
    318                         "GDBM object has already been closed");
    319         return -1;
    320     }
    321     if (PyUnicode_Check(arg)) {
    322         key.dptr = PyUnicode_AsUTF8AndSize(arg, &size);
    323         key.dsize = size;
    324         if (key.dptr == NULL)
    325             return -1;
    326     }
    327     else if (!PyBytes_Check(arg)) {
    328         PyErr_Format(PyExc_TypeError,
    329                      "gdbm key must be bytes or string, not %.100s",
    330                      arg->ob_type->tp_name);
    331         return -1;
    332     }
    333     else {
    334         key.dptr = PyBytes_AS_STRING(arg);
    335         key.dsize = PyBytes_GET_SIZE(arg);
    336     }
    337     return gdbm_exists(dp->di_dbm, key);
    338 }
    339 
    340 static PySequenceMethods dbm_as_sequence = {
    341         0,                      /* sq_length */
    342         0,                      /* sq_concat */
    343         0,                      /* sq_repeat */
    344         0,                      /* sq_item */
    345         0,                      /* sq_slice */
    346         0,                      /* sq_ass_item */
    347         0,                      /* sq_ass_slice */
    348         dbm_contains,           /* sq_contains */
    349         0,                      /* sq_inplace_concat */
    350         0,                      /* sq_inplace_repeat */
    351 };
    352 
    353 /*[clinic input]
    354 _gdbm.gdbm.firstkey
    355 
    356 Return the starting key for the traversal.
    357 
    358 It's possible to loop over every key in the database using this method
    359 and the nextkey() method.  The traversal is ordered by GDBM's internal
    360 hash values, and won't be sorted by the key values.
    361 [clinic start generated code]*/
    362 
    363 static PyObject *
    364 _gdbm_gdbm_firstkey_impl(dbmobject *self)
    365 /*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/
    366 {
    367     PyObject *v;
    368     datum key;
    369 
    370     check_dbmobject_open(self);
    371     key = gdbm_firstkey(self->di_dbm);
    372     if (key.dptr) {
    373         v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
    374         free(key.dptr);
    375         return v;
    376     }
    377     else {
    378         Py_INCREF(Py_None);
    379         return Py_None;
    380     }
    381 }
    382 
    383 /*[clinic input]
    384 _gdbm.gdbm.nextkey
    385 
    386     key: str(accept={str, robuffer}, zeroes=True)
    387     /
    388 
    389 Returns the key that follows key in the traversal.
    390 
    391 The following code prints every key in the database db, without having
    392 to create a list in memory that contains them all:
    393 
    394       k = db.firstkey()
    395       while k != None:
    396           print(k)
    397           k = db.nextkey(k)
    398 [clinic start generated code]*/
    399 
    400 static PyObject *
    401 _gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
    402                         Py_ssize_clean_t key_length)
    403 /*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/
    404 {
    405     PyObject *v;
    406     datum dbm_key, nextkey;
    407 
    408     dbm_key.dptr = (char *)key;
    409     dbm_key.dsize = key_length;
    410     check_dbmobject_open(self);
    411     nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
    412     if (nextkey.dptr) {
    413         v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
    414         free(nextkey.dptr);
    415         return v;
    416     }
    417     else {
    418         Py_INCREF(Py_None);
    419         return Py_None;
    420     }
    421 }
    422 
    423 /*[clinic input]
    424 _gdbm.gdbm.reorganize
    425 
    426 Reorganize the database.
    427 
    428 If you have carried out a lot of deletions and would like to shrink
    429 the space used by the GDBM file, this routine will reorganize the
    430 database.  GDBM will not shorten the length of a database file except
    431 by using this reorganization; otherwise, deleted file space will be
    432 kept and reused as new (key,value) pairs are added.
    433 [clinic start generated code]*/
    434 
    435 static PyObject *
    436 _gdbm_gdbm_reorganize_impl(dbmobject *self)
    437 /*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/
    438 {
    439     check_dbmobject_open(self);
    440     errno = 0;
    441     if (gdbm_reorganize(self->di_dbm) < 0) {
    442         if (errno != 0)
    443             PyErr_SetFromErrno(DbmError);
    444         else
    445             PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
    446         return NULL;
    447     }
    448     Py_INCREF(Py_None);
    449     return Py_None;
    450 }
    451 
    452 /*[clinic input]
    453 _gdbm.gdbm.sync
    454 
    455 Flush the database to the disk file.
    456 
    457 When the database has been opened in fast mode, this method forces
    458 any unwritten data to be written to the disk.
    459 [clinic start generated code]*/
    460 
    461 static PyObject *
    462 _gdbm_gdbm_sync_impl(dbmobject *self)
    463 /*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/
    464 {
    465     check_dbmobject_open(self);
    466     gdbm_sync(self->di_dbm);
    467     Py_INCREF(Py_None);
    468     return Py_None;
    469 }
    470 
    471 static PyObject *
    472 dbm__enter__(PyObject *self, PyObject *args)
    473 {
    474     Py_INCREF(self);
    475     return self;
    476 }
    477 
    478 static PyObject *
    479 dbm__exit__(PyObject *self, PyObject *args)
    480 {
    481     _Py_IDENTIFIER(close);
    482     return _PyObject_CallMethodId(self, &PyId_close, NULL);
    483 }
    484 
    485 static PyMethodDef dbm_methods[] = {
    486     _GDBM_GDBM_CLOSE_METHODDEF
    487     _GDBM_GDBM_KEYS_METHODDEF
    488     _GDBM_GDBM_FIRSTKEY_METHODDEF
    489     _GDBM_GDBM_NEXTKEY_METHODDEF
    490     _GDBM_GDBM_REORGANIZE_METHODDEF
    491     _GDBM_GDBM_SYNC_METHODDEF
    492     _GDBM_GDBM_GET_METHODDEF
    493     _GDBM_GDBM_GET_METHODDEF
    494     _GDBM_GDBM_SETDEFAULT_METHODDEF
    495     {"__enter__", dbm__enter__, METH_NOARGS, NULL},
    496     {"__exit__",  dbm__exit__, METH_VARARGS, NULL},
    497     {NULL,              NULL}           /* sentinel */
    498 };
    499 
    500 static PyTypeObject Dbmtype = {
    501     PyVarObject_HEAD_INIT(0, 0)
    502     "_gdbm.gdbm",
    503     sizeof(dbmobject),
    504     0,
    505     (destructor)dbm_dealloc,            /*tp_dealloc*/
    506     0,                                  /*tp_print*/
    507     0,                                  /*tp_getattr*/
    508     0,                                  /*tp_setattr*/
    509     0,                                  /*tp_reserved*/
    510     0,                                  /*tp_repr*/
    511     0,                                  /*tp_as_number*/
    512     &dbm_as_sequence,                   /*tp_as_sequence*/
    513     &dbm_as_mapping,                    /*tp_as_mapping*/
    514     0,                                  /*tp_hash*/
    515     0,                                  /*tp_call*/
    516     0,                                  /*tp_str*/
    517     0,                                  /*tp_getattro*/
    518     0,                                  /*tp_setattro*/
    519     0,                                  /*tp_as_buffer*/
    520     Py_TPFLAGS_DEFAULT,                 /*tp_xxx4*/
    521     gdbm_object__doc__,                 /*tp_doc*/
    522     0,                                  /*tp_traverse*/
    523     0,                                  /*tp_clear*/
    524     0,                                  /*tp_richcompare*/
    525     0,                                  /*tp_weaklistoffset*/
    526     0,                                  /*tp_iter*/
    527     0,                                  /*tp_iternext*/
    528     dbm_methods,                        /*tp_methods*/
    529 };
    530 
    531 /* ----------------------------------------------------------------- */
    532 
    533 /*[clinic input]
    534 _gdbm.open as dbmopen
    535     filename as name: str
    536     flags: str="r"
    537     mode: int(py_default="0o666") = 0o666
    538     /
    539 
    540 Open a dbm database and return a dbm object.
    541 
    542 The filename argument is the name of the database file.
    543 
    544 The optional flags argument can be 'r' (to open an existing database
    545 for reading only -- default), 'w' (to open an existing database for
    546 reading and writing), 'c' (which creates the database if it doesn't
    547 exist), or 'n' (which always creates a new empty database).
    548 
    549 Some versions of gdbm support additional flags which must be
    550 appended to one of the flags described above.  The module constant
    551 'open_flags' is a string of valid additional flags.  The 'f' flag
    552 opens the database in fast mode; altered data will not automatically
    553 be written to the disk after every change.  This results in faster
    554 writes to the database, but may result in an inconsistent database
    555 if the program crashes while the database is still open.  Use the
    556 sync() method to force any unwritten data to be written to the disk.
    557 The 's' flag causes all database operations to be synchronized to
    558 disk.  The 'u' flag disables locking of the database file.
    559 
    560 The optional mode argument is the Unix mode of the file, used only
    561 when the database has to be created.  It defaults to octal 0o666.
    562 [clinic start generated code]*/
    563 
    564 static PyObject *
    565 dbmopen_impl(PyObject *module, const char *name, const char *flags, int mode)
    566 /*[clinic end generated code: output=31aa1bafdf5da688 input=55563cd60e51984a]*/
    567 {
    568     int iflags;
    569 
    570     switch (flags[0]) {
    571     case 'r':
    572         iflags = GDBM_READER;
    573         break;
    574     case 'w':
    575         iflags = GDBM_WRITER;
    576         break;
    577     case 'c':
    578         iflags = GDBM_WRCREAT;
    579         break;
    580     case 'n':
    581         iflags = GDBM_NEWDB;
    582         break;
    583     default:
    584         PyErr_SetString(DbmError,
    585                         "First flag must be one of 'r', 'w', 'c' or 'n'");
    586         return NULL;
    587     }
    588     for (flags++; *flags != '\0'; flags++) {
    589         char buf[40];
    590         switch (*flags) {
    591 #ifdef GDBM_FAST
    592             case 'f':
    593                 iflags |= GDBM_FAST;
    594                 break;
    595 #endif
    596 #ifdef GDBM_SYNC
    597             case 's':
    598                 iflags |= GDBM_SYNC;
    599                 break;
    600 #endif
    601 #ifdef GDBM_NOLOCK
    602             case 'u':
    603                 iflags |= GDBM_NOLOCK;
    604                 break;
    605 #endif
    606             default:
    607                 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
    608                               *flags);
    609                 PyErr_SetString(DbmError, buf);
    610                 return NULL;
    611         }
    612     }
    613 
    614     return newdbmobject(name, iflags, mode);
    615 }
    616 
    617 static const char dbmmodule_open_flags[] = "rwcn"
    618 #ifdef GDBM_FAST
    619                                      "f"
    620 #endif
    621 #ifdef GDBM_SYNC
    622                                      "s"
    623 #endif
    624 #ifdef GDBM_NOLOCK
    625                                      "u"
    626 #endif
    627                                      ;
    628 
    629 static PyMethodDef dbmmodule_methods[] = {
    630     DBMOPEN_METHODDEF
    631     { 0, 0 },
    632 };
    633 
    634 
    635 static struct PyModuleDef _gdbmmodule = {
    636         PyModuleDef_HEAD_INIT,
    637         "_gdbm",
    638         gdbmmodule__doc__,
    639         -1,
    640         dbmmodule_methods,
    641         NULL,
    642         NULL,
    643         NULL,
    644         NULL
    645 };
    646 
    647 PyMODINIT_FUNC
    648 PyInit__gdbm(void) {
    649     PyObject *m, *d, *s;
    650 
    651     if (PyType_Ready(&Dbmtype) < 0)
    652             return NULL;
    653     m = PyModule_Create(&_gdbmmodule);
    654     if (m == NULL)
    655         return NULL;
    656     d = PyModule_GetDict(m);
    657     DbmError = PyErr_NewException("_gdbm.error", PyExc_IOError, NULL);
    658     if (DbmError != NULL) {
    659         PyDict_SetItemString(d, "error", DbmError);
    660         s = PyUnicode_FromString(dbmmodule_open_flags);
    661         PyDict_SetItemString(d, "open_flags", s);
    662         Py_DECREF(s);
    663     }
    664     return m;
    665 }
    666