(root)/
Python-3.11.7/
Modules/
_dbmmodule.c
       1  
       2  /* DBM module using dictionary interface */
       3  
       4  
       5  #define PY_SSIZE_T_CLEAN
       6  #include "Python.h"
       7  
       8  #include <sys/types.h>
       9  #include <sys/stat.h>
      10  #include <fcntl.h>
      11  
      12  /* Some Linux systems install gdbm/ndbm.h, but not ndbm.h.  This supports
      13   * whichever configure was able to locate.
      14   */
      15  #if defined(USE_GDBM_COMPAT)
      16    #ifdef HAVE_GDBM_NDBM_H
      17      #include <gdbm/ndbm.h>
      18    #elif HAVE_GDBM_DASH_NDBM_H
      19      #include <gdbm-ndbm.h>
      20    #else
      21      #error "No gdbm/ndbm.h or gdbm-ndbm.h available"
      22    #endif
      23    static const char which_dbm[] = "GNU gdbm";
      24  #elif defined(USE_NDBM)
      25    #include <ndbm.h>
      26    static const char which_dbm[] = "GNU gdbm";
      27  #elif defined(USE_BERKDB)
      28    #ifndef DB_DBM_HSEARCH
      29      #define DB_DBM_HSEARCH 1
      30    #endif
      31    #include <db.h>
      32    static const char which_dbm[] = "Berkeley DB";
      33  #else
      34    #error "No ndbm.h available!"
      35  #endif
      36  
      37  typedef struct {
      38      PyTypeObject *dbm_type;
      39      PyObject *dbm_error;
      40  } _dbm_state;
      41  
      42  static inline _dbm_state*
      43  get_dbm_state(PyObject *module)
      44  {
      45      void *state = PyModule_GetState(module);
      46      assert(state != NULL);
      47      return (_dbm_state *)state;
      48  }
      49  
      50  /*[clinic input]
      51  module _dbm
      52  class _dbm.dbm "dbmobject *" "&Dbmtype"
      53  [clinic start generated code]*/
      54  /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9b1aa8756d16150e]*/
      55  
      56  typedef struct {
      57      PyObject_HEAD
      58      int flags;
      59      int di_size;        /* -1 means recompute */
      60      DBM *di_dbm;
      61  } dbmobject;
      62  
      63  #include "clinic/_dbmmodule.c.h"
      64  
      65  #define check_dbmobject_open(v, err)                                \
      66      if ((v)->di_dbm == NULL) {                                      \
      67          PyErr_SetString(err, "DBM object has already been closed"); \
      68          return NULL;                                                \
      69      }
      70  
      71  static PyObject *
      72  newdbmobject(_dbm_state *state, const char *file, int flags, int mode)
      73  {
      74      dbmobject *dp = PyObject_GC_New(dbmobject, state->dbm_type);
      75      if (dp == NULL) {
      76          return NULL;
      77      }
      78      dp->di_size = -1;
      79      dp->flags = flags;
      80      PyObject_GC_Track(dp);
      81  
      82      /* See issue #19296 */
      83      if ( (dp->di_dbm = dbm_open((char *)file, flags, mode)) == 0 ) {
      84          PyErr_SetFromErrnoWithFilename(state->dbm_error, file);
      85          Py_DECREF(dp);
      86          return NULL;
      87      }
      88      return (PyObject *)dp;
      89  }
      90  
      91  /* Methods */
      92  static int
      93  dbm_traverse(dbmobject *dp, visitproc visit, void *arg)
      94  {
      95      Py_VISIT(Py_TYPE(dp));
      96      return 0;
      97  }
      98  
      99  static void
     100  dbm_dealloc(dbmobject *dp)
     101  {
     102      PyObject_GC_UnTrack(dp);
     103      if (dp->di_dbm) {
     104          dbm_close(dp->di_dbm);
     105      }
     106      PyTypeObject *tp = Py_TYPE(dp);
     107      tp->tp_free(dp);
     108      Py_DECREF(tp);
     109  }
     110  
     111  static Py_ssize_t
     112  dbm_length(dbmobject *dp)
     113  {
     114      _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
     115      assert(state != NULL);
     116      if (dp->di_dbm == NULL) {
     117               PyErr_SetString(state->dbm_error, "DBM object has already been closed");
     118               return -1;
     119      }
     120      if ( dp->di_size < 0 ) {
     121          datum key;
     122          int size;
     123  
     124          size = 0;
     125          for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
     126                key = dbm_nextkey(dp->di_dbm))
     127              size++;
     128          dp->di_size = size;
     129      }
     130      return dp->di_size;
     131  }
     132  
     133  static PyObject *
     134  dbm_subscript(dbmobject *dp, PyObject *key)
     135  {
     136      datum drec, krec;
     137      Py_ssize_t tmp_size;
     138      _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
     139      assert(state != NULL);
     140      if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size)) {
     141          return NULL;
     142      }
     143  
     144      krec.dsize = tmp_size;
     145      check_dbmobject_open(dp, state->dbm_error);
     146      drec = dbm_fetch(dp->di_dbm, krec);
     147      if ( drec.dptr == 0 ) {
     148          PyErr_SetObject(PyExc_KeyError, key);
     149          return NULL;
     150      }
     151      if ( dbm_error(dp->di_dbm) ) {
     152          dbm_clearerr(dp->di_dbm);
     153          PyErr_SetString(state->dbm_error, "");
     154          return NULL;
     155      }
     156      return PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
     157  }
     158  
     159  static int
     160  dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
     161  {
     162      datum krec, drec;
     163      Py_ssize_t tmp_size;
     164  
     165      if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
     166          PyErr_SetString(PyExc_TypeError,
     167                          "dbm mappings have bytes or string keys only");
     168          return -1;
     169      }
     170      _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
     171      assert(state != NULL);
     172      krec.dsize = tmp_size;
     173      if (dp->di_dbm == NULL) {
     174               PyErr_SetString(state->dbm_error, "DBM object has already been closed");
     175               return -1;
     176      }
     177      dp->di_size = -1;
     178      if (w == NULL) {
     179          if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
     180              dbm_clearerr(dp->di_dbm);
     181              /* we might get a failure for reasons like file corrupted,
     182                 but we are not able to distinguish it */
     183              if (dp->flags & O_RDWR) {
     184                  PyErr_SetObject(PyExc_KeyError, v);
     185              }
     186              else {
     187                  PyErr_SetString(state->dbm_error, "cannot delete item from database");
     188              }
     189              return -1;
     190          }
     191      } else {
     192          if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
     193              PyErr_SetString(PyExc_TypeError,
     194                   "dbm mappings have bytes or string elements only");
     195              return -1;
     196          }
     197          drec.dsize = tmp_size;
     198          if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
     199              dbm_clearerr(dp->di_dbm);
     200              PyErr_SetString(state->dbm_error,
     201                              "cannot add item to database");
     202              return -1;
     203          }
     204      }
     205      if ( dbm_error(dp->di_dbm) ) {
     206          dbm_clearerr(dp->di_dbm);
     207          PyErr_SetString(state->dbm_error, "");
     208          return -1;
     209      }
     210      return 0;
     211  }
     212  
     213  /*[clinic input]
     214  _dbm.dbm.close
     215  
     216  Close the database.
     217  [clinic start generated code]*/
     218  
     219  static PyObject *
     220  _dbm_dbm_close_impl(dbmobject *self)
     221  /*[clinic end generated code: output=c8dc5b6709600b86 input=046db72377d51be8]*/
     222  {
     223      if (self->di_dbm) {
     224          dbm_close(self->di_dbm);
     225      }
     226      self->di_dbm = NULL;
     227      Py_RETURN_NONE;
     228  }
     229  
     230  /*[clinic input]
     231  _dbm.dbm.keys
     232  
     233      cls: defining_class
     234  
     235  Return a list of all keys in the database.
     236  [clinic start generated code]*/
     237  
     238  static PyObject *
     239  _dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls)
     240  /*[clinic end generated code: output=f2a593b3038e5996 input=d3706a28fc051097]*/
     241  {
     242      PyObject *v, *item;
     243      datum key;
     244      int err;
     245  
     246      _dbm_state *state = PyType_GetModuleState(cls);
     247      assert(state != NULL);
     248      check_dbmobject_open(self, state->dbm_error);
     249      v = PyList_New(0);
     250      if (v == NULL) {
     251          return NULL;
     252      }
     253      for (key = dbm_firstkey(self->di_dbm); key.dptr;
     254           key = dbm_nextkey(self->di_dbm)) {
     255          item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
     256          if (item == NULL) {
     257              Py_DECREF(v);
     258              return NULL;
     259          }
     260          err = PyList_Append(v, item);
     261          Py_DECREF(item);
     262          if (err != 0) {
     263              Py_DECREF(v);
     264              return NULL;
     265          }
     266      }
     267      return v;
     268  }
     269  
     270  static int
     271  dbm_contains(PyObject *self, PyObject *arg)
     272  {
     273      dbmobject *dp = (dbmobject *)self;
     274      datum key, val;
     275      Py_ssize_t size;
     276  
     277      _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
     278      assert(state != NULL);
     279      if ((dp)->di_dbm == NULL) {
     280          PyErr_SetString(state->dbm_error,
     281                          "DBM object has already been closed");
     282           return -1;
     283      }
     284      if (PyUnicode_Check(arg)) {
     285          key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
     286          key.dsize = size;
     287          if (key.dptr == NULL)
     288              return -1;
     289      }
     290      else if (!PyBytes_Check(arg)) {
     291          PyErr_Format(PyExc_TypeError,
     292                       "dbm key must be bytes or string, not %.100s",
     293                       Py_TYPE(arg)->tp_name);
     294          return -1;
     295      }
     296      else {
     297          key.dptr = PyBytes_AS_STRING(arg);
     298          key.dsize = PyBytes_GET_SIZE(arg);
     299      }
     300      val = dbm_fetch(dp->di_dbm, key);
     301      return val.dptr != NULL;
     302  }
     303  
     304  /*[clinic input]
     305  _dbm.dbm.get
     306      cls: defining_class
     307      key: str(accept={str, robuffer}, zeroes=True)
     308      default: object = None
     309      /
     310  
     311  Return the value for key if present, otherwise default.
     312  [clinic start generated code]*/
     313  
     314  static PyObject *
     315  _dbm_dbm_get_impl(dbmobject *self, PyTypeObject *cls, const char *key,
     316                    Py_ssize_t key_length, PyObject *default_value)
     317  /*[clinic end generated code: output=b4e55f8b6d482bc4 input=66b993b8349fa8c1]*/
     318  {
     319      datum dbm_key, val;
     320      _dbm_state *state = PyType_GetModuleState(cls);
     321      assert(state != NULL);
     322      dbm_key.dptr = (char *)key;
     323      dbm_key.dsize = key_length;
     324      check_dbmobject_open(self, state->dbm_error);
     325      val = dbm_fetch(self->di_dbm, dbm_key);
     326      if (val.dptr != NULL) {
     327          return PyBytes_FromStringAndSize(val.dptr, val.dsize);
     328      }
     329  
     330      Py_INCREF(default_value);
     331      return default_value;
     332  }
     333  
     334  /*[clinic input]
     335  _dbm.dbm.setdefault
     336      cls: defining_class
     337      key: str(accept={str, robuffer}, zeroes=True)
     338      default: object(c_default="NULL") = b''
     339      /
     340  
     341  Return the value for key if present, otherwise default.
     342  
     343  If key is not in the database, it is inserted with default as the value.
     344  [clinic start generated code]*/
     345  
     346  static PyObject *
     347  _dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key,
     348                           Py_ssize_t key_length, PyObject *default_value)
     349  /*[clinic end generated code: output=9c2f6ea6d0fb576c input=126a3ff15c5f8232]*/
     350  {
     351      datum dbm_key, val;
     352      Py_ssize_t tmp_size;
     353      _dbm_state *state = PyType_GetModuleState(cls);
     354      assert(state != NULL);
     355      dbm_key.dptr = (char *)key;
     356      dbm_key.dsize = key_length;
     357      check_dbmobject_open(self, state->dbm_error);
     358      val = dbm_fetch(self->di_dbm, dbm_key);
     359      if (val.dptr != NULL) {
     360          return PyBytes_FromStringAndSize(val.dptr, val.dsize);
     361      }
     362      if (default_value == NULL) {
     363          default_value = PyBytes_FromStringAndSize(NULL, 0);
     364          if (default_value == NULL) {
     365              return NULL;
     366          }
     367          val.dptr = NULL;
     368          val.dsize = 0;
     369      }
     370      else {
     371          if ( !PyArg_Parse(default_value, "s#", &val.dptr, &tmp_size) ) {
     372              PyErr_SetString(PyExc_TypeError,
     373                  "dbm mappings have bytes or string elements only");
     374              return NULL;
     375          }
     376          val.dsize = tmp_size;
     377          Py_INCREF(default_value);
     378      }
     379      if (dbm_store(self->di_dbm, dbm_key, val, DBM_INSERT) < 0) {
     380          dbm_clearerr(self->di_dbm);
     381          PyErr_SetString(state->dbm_error, "cannot add item to database");
     382          Py_DECREF(default_value);
     383          return NULL;
     384      }
     385      return default_value;
     386  }
     387  
     388  static PyObject *
     389  dbm__enter__(PyObject *self, PyObject *args)
     390  {
     391      Py_INCREF(self);
     392      return self;
     393  }
     394  
     395  static PyObject *
     396  dbm__exit__(PyObject *self, PyObject *args)
     397  {
     398      return _dbm_dbm_close_impl((dbmobject *)self);
     399  }
     400  
     401  static PyMethodDef dbm_methods[] = {
     402      _DBM_DBM_CLOSE_METHODDEF
     403      _DBM_DBM_KEYS_METHODDEF
     404      _DBM_DBM_GET_METHODDEF
     405      _DBM_DBM_SETDEFAULT_METHODDEF
     406      {"__enter__", dbm__enter__, METH_NOARGS, NULL},
     407      {"__exit__",  dbm__exit__, METH_VARARGS, NULL},
     408      {NULL,  NULL}           /* sentinel */
     409  };
     410  
     411  static PyType_Slot dbmtype_spec_slots[] = {
     412      {Py_tp_dealloc, dbm_dealloc},
     413      {Py_tp_traverse, dbm_traverse},
     414      {Py_tp_methods, dbm_methods},
     415      {Py_sq_contains, dbm_contains},
     416      {Py_mp_length, dbm_length},
     417      {Py_mp_subscript, dbm_subscript},
     418      {Py_mp_ass_subscript, dbm_ass_sub},
     419      {0, 0}
     420  };
     421  
     422  
     423  static PyType_Spec dbmtype_spec = {
     424      .name = "_dbm.dbm",
     425      .basicsize = sizeof(dbmobject),
     426      // Calling PyType_GetModuleState() on a subclass is not safe.
     427      // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
     428      // which prevents to create a subclass.
     429      // So calling PyType_GetModuleState() in this file is always safe.
     430      .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
     431                Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
     432      .slots = dbmtype_spec_slots,
     433  };
     434  
     435  /* ----------------------------------------------------------------- */
     436  
     437  /*[clinic input]
     438  
     439  _dbm.open as dbmopen
     440  
     441      filename: object
     442          The filename to open.
     443  
     444      flags: str="r"
     445          How to open the file.  "r" for reading, "w" for writing, etc.
     446  
     447      mode: int(py_default="0o666") = 0o666
     448          If creating a new file, the mode bits for the new file
     449          (e.g. os.O_RDWR).
     450  
     451      /
     452  
     453  Return a database object.
     454  
     455  [clinic start generated code]*/
     456  
     457  static PyObject *
     458  dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
     459               int mode)
     460  /*[clinic end generated code: output=9527750f5df90764 input=d8cf50a9f81218c8]*/
     461  {
     462      int iflags;
     463      _dbm_state *state =  get_dbm_state(module);
     464      assert(state != NULL);
     465      if (strcmp(flags, "r") == 0) {
     466          iflags = O_RDONLY;
     467      }
     468      else if (strcmp(flags, "w") == 0) {
     469          iflags = O_RDWR;
     470      }
     471      else if (strcmp(flags, "rw") == 0) {
     472          /* Backward compatibility */
     473          iflags = O_RDWR|O_CREAT;
     474      }
     475      else if (strcmp(flags, "c") == 0) {
     476          iflags = O_RDWR|O_CREAT;
     477      }
     478      else if (strcmp(flags, "n") == 0) {
     479          iflags = O_RDWR|O_CREAT|O_TRUNC;
     480      }
     481      else {
     482          PyErr_SetString(state->dbm_error,
     483                          "arg 2 to open should be 'r', 'w', 'c', or 'n'");
     484          return NULL;
     485      }
     486  
     487      PyObject *filenamebytes;
     488      if (!PyUnicode_FSConverter(filename, &filenamebytes)) {
     489          return NULL;
     490      }
     491  
     492      const char *name = PyBytes_AS_STRING(filenamebytes);
     493      if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
     494          Py_DECREF(filenamebytes);
     495          PyErr_SetString(PyExc_ValueError, "embedded null character");
     496          return NULL;
     497      }
     498      PyObject *self = newdbmobject(state, name, iflags, mode);
     499      Py_DECREF(filenamebytes);
     500      return self;
     501  }
     502  
     503  static PyMethodDef dbmmodule_methods[] = {
     504      DBMOPEN_METHODDEF
     505      { 0, 0 },
     506  };
     507  
     508  static int
     509  _dbm_exec(PyObject *module)
     510  {
     511      _dbm_state *state = get_dbm_state(module);
     512      state->dbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
     513                                                          &dbmtype_spec, NULL);
     514      if (state->dbm_type == NULL) {
     515          return -1;
     516      }
     517      state->dbm_error = PyErr_NewException("_dbm.error", PyExc_OSError, NULL);
     518      if (state->dbm_error == NULL) {
     519          return -1;
     520      }
     521      if (PyModule_AddStringConstant(module, "library", which_dbm) < 0) {
     522          return -1;
     523      }
     524      if (PyModule_AddType(module, (PyTypeObject *)state->dbm_error) < 0) {
     525          return -1;
     526      }
     527      return 0;
     528  }
     529  
     530  static int
     531  _dbm_module_traverse(PyObject *module, visitproc visit, void *arg)
     532  {
     533      _dbm_state *state = get_dbm_state(module);
     534      Py_VISIT(state->dbm_error);
     535      Py_VISIT(state->dbm_type);
     536      return 0;
     537  }
     538  
     539  static int
     540  _dbm_module_clear(PyObject *module)
     541  {
     542      _dbm_state *state = get_dbm_state(module);
     543      Py_CLEAR(state->dbm_error);
     544      Py_CLEAR(state->dbm_type);
     545      return 0;
     546  }
     547  
     548  static void
     549  _dbm_module_free(void *module)
     550  {
     551      _dbm_module_clear((PyObject *)module);
     552  }
     553  
     554  static PyModuleDef_Slot _dbmmodule_slots[] = {
     555      {Py_mod_exec, _dbm_exec},
     556      {0, NULL}
     557  };
     558  
     559  static struct PyModuleDef _dbmmodule = {
     560      PyModuleDef_HEAD_INIT,
     561      .m_name = "_dbm",
     562      .m_size = sizeof(_dbm_state),
     563      .m_methods = dbmmodule_methods,
     564      .m_slots = _dbmmodule_slots,
     565      .m_traverse = _dbm_module_traverse,
     566      .m_clear = _dbm_module_clear,
     567      .m_free = _dbm_module_free,
     568  };
     569  
     570  PyMODINIT_FUNC
     571  PyInit__dbm(void)
     572  {
     573      return PyModuleDef_Init(&_dbmmodule);
     574  }