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