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 *
newdbmobject(const char * file,int flags,int mode)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
dbm_dealloc(dbmobject * dp)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
dbm_length(dbmobject * dp)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 *
dbm_subscript(dbmobject * dp,PyObject * key)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 *
_gdbm_gdbm_get_impl(dbmobject * self,PyObject * key,PyObject * default_value)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
dbm_ass_sub(dbmobject * dp,PyObject * v,PyObject * w)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 *
_gdbm_gdbm_setdefault_impl(dbmobject * self,PyObject * key,PyObject * default_value)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 *
_gdbm_gdbm_close_impl(dbmobject * self)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 *
_gdbm_gdbm_keys_impl(dbmobject * self)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
dbm_contains(PyObject * self,PyObject * arg)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 *
_gdbm_gdbm_firstkey_impl(dbmobject * self)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 *
_gdbm_gdbm_nextkey_impl(dbmobject * self,const char * key,Py_ssize_clean_t key_length)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 *
_gdbm_gdbm_reorganize_impl(dbmobject * self)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 *
_gdbm_gdbm_sync_impl(dbmobject * self)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 *
dbm__enter__(PyObject * self,PyObject * args)472 dbm__enter__(PyObject *self, PyObject *args)
473 {
474 Py_INCREF(self);
475 return self;
476 }
477
478 static PyObject *
dbm__exit__(PyObject * self,PyObject * args)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 *
dbmopen_impl(PyObject * module,const char * name,const char * flags,int mode)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
PyInit__gdbm(void)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