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 : : }
|