blob: 77e7887525069a3b407b21331f5300aefda79303 [file] [log] [blame]
Guido van Rossum4b4c6641994-08-08 08:06:37 +00001
2/* DBM module using dictionary interface */
Guido van Rossumbfc49e81998-03-03 22:02:24 +00003/* Author: Anthony Baxter, after dbmmodule.c */
4/* Doc strings: Mitch Chapman */
Guido van Rossum4b4c6641994-08-08 08:06:37 +00005
Inada Naokic5a216e2019-03-20 19:01:55 +09006#define PY_SSIZE_T_CLEAN
Roger E. Masseb15bef81996-12-17 19:55:33 +00007#include "Python.h"
Guido van Rossum4b4c6641994-08-08 08:06:37 +00008
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <fcntl.h>
12#include "gdbm.h"
13
Tim Peters5687ffe2001-02-28 16:44:18 +000014#if defined(WIN32) && !defined(__CYGWIN__)
Guido van Rossumb6e2a991998-10-03 05:13:27 +000015#include "gdbmerrno.h"
16extern const char * gdbm_strerror(gdbm_error);
17#endif
18
Serhiy Storchaka9260e772015-04-17 21:05:18 +030019/*[clinic input]
20module _gdbm
21class _gdbm.gdbm "dbmobject *" "&Dbmtype"
22[clinic start generated code]*/
23/*[clinic end generated code: output=da39a3ee5e6b4b0d input=113927c6170729b2]*/
24
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000025PyDoc_STRVAR(gdbmmodule__doc__,
26"This module provides an interface to the GNU DBM (GDBM) library.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000027\n\
28This module is quite similar to the dbm module, but uses GDBM instead to\n\
Serhiy Storchaka9260e772015-04-17 21:05:18 +030029provide some additional functionality. Please note that the file formats\n\
30created by GDBM and dbm are incompatible.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000031\n\
32GDBM objects behave like mappings (dictionaries), except that keys and\n\
Serhiy Storchaka9260e772015-04-17 21:05:18 +030033values are always immutable bytes-like objects or strings. Printing\n\
34a GDBM object doesn't print the keys and values, and the items() and\n\
35values() methods are not supported.");
Guido van Rossumbfc49e81998-03-03 22:02:24 +000036
Guido van Rossum4b4c6641994-08-08 08:06:37 +000037typedef struct {
Fred Drakee3a41c62000-07-08 05:00:07 +000038 PyObject_HEAD
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000039 int di_size; /* -1 means recompute */
Fred Drakee3a41c62000-07-08 05:00:07 +000040 GDBM_FILE di_dbm;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000041} dbmobject;
42
Jeremy Hylton938ace62002-07-17 16:30:39 +000043static PyTypeObject Dbmtype;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000044
Serhiy Storchaka9260e772015-04-17 21:05:18 +030045#include "clinic/_gdbmmodule.c.h"
46
Christian Heimes90aa7642007-12-19 02:45:37 +000047#define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
Guido van Rossum77eecfa1997-07-17 22:56:01 +000048#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
Fred Drakee3a41c62000-07-08 05:00:07 +000049 { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
50 return NULL; }
Guido van Rossum77eecfa1997-07-17 22:56:01 +000051
52
Guido van Rossum4b4c6641994-08-08 08:06:37 +000053
Roger E. Masseb15bef81996-12-17 19:55:33 +000054static PyObject *DbmError;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000055
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000056PyDoc_STRVAR(gdbm_object__doc__,
57"This object represents a GDBM database.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000058GDBM objects behave like mappings (dictionaries), except that keys and\n\
Serhiy Storchaka9260e772015-04-17 21:05:18 +030059values are always immutable bytes-like objects or strings. Printing\n\
60a GDBM object doesn't print the keys and values, and the items() and\n\
61values() methods are not supported.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000062\n\
63GDBM objects also support additional operations such as firstkey,\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000064nextkey, reorganize, and sync.");
Guido van Rossumbfc49e81998-03-03 22:02:24 +000065
Roger E. Masseb15bef81996-12-17 19:55:33 +000066static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +030067newdbmobject(const char *file, int flags, int mode)
Guido van Rossum4b4c6641994-08-08 08:06:37 +000068{
Fred Drakee3a41c62000-07-08 05:00:07 +000069 dbmobject *dp;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000070
Fred Drakee3a41c62000-07-08 05:00:07 +000071 dp = PyObject_New(dbmobject, &Dbmtype);
72 if (dp == NULL)
73 return NULL;
74 dp->di_size = -1;
75 errno = 0;
Serhiy Storchaka9260e772015-04-17 21:05:18 +030076 if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
Fred Drakee3a41c62000-07-08 05:00:07 +000077 if (errno != 0)
Zsolt Cserna9df346b2018-09-27 21:54:34 +020078 PyErr_SetFromErrnoWithFilename(DbmError, file);
Fred Drakee3a41c62000-07-08 05:00:07 +000079 else
80 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
81 Py_DECREF(dp);
82 return NULL;
83 }
84 return (PyObject *)dp;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000085}
86
87/* Methods */
88
89static void
Antoine Pitrou9ed5f272013-08-13 20:18:52 +020090dbm_dealloc(dbmobject *dp)
Guido van Rossum4b4c6641994-08-08 08:06:37 +000091{
Fred Drakee3a41c62000-07-08 05:00:07 +000092 if (dp->di_dbm)
93 gdbm_close(dp->di_dbm);
94 PyObject_Del(dp);
Guido van Rossum4b4c6641994-08-08 08:06:37 +000095}
96
Martin v. Löwis18e16552006-02-15 17:27:45 +000097static Py_ssize_t
Fred Drakee3a41c62000-07-08 05:00:07 +000098dbm_length(dbmobject *dp)
Guido van Rossum4b4c6641994-08-08 08:06:37 +000099{
Fred Drakee3a41c62000-07-08 05:00:07 +0000100 if (dp->di_dbm == NULL) {
Guido van Rossum6252e102007-05-23 20:51:02 +0000101 PyErr_SetString(DbmError, "GDBM object has already been closed");
102 return -1;
Fred Drakee3a41c62000-07-08 05:00:07 +0000103 }
104 if (dp->di_size < 0) {
105 datum key,okey;
106 int size;
107 okey.dsize=0;
Thomas Woutersa5fa2a82006-03-01 22:54:36 +0000108 okey.dptr=NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000109
Fred Drakee3a41c62000-07-08 05:00:07 +0000110 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;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000120}
121
Inada Naokic5a216e2019-03-20 19:01:55 +0900122// Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
123// This function is needed to support PY_SSIZE_T_CLEAN.
124// Return 1 on success, same to PyArg_Parse().
125static int
126parse_datum(PyObject *o, datum *d, const char *failmsg)
127{
128 Py_ssize_t size;
129 if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
130 if (failmsg != NULL) {
131 PyErr_SetString(PyExc_TypeError, failmsg);
132 }
133 return 0;
134 }
135 if (INT_MAX < size) {
136 PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
137 return 0;
138 }
139 d->dsize = size;
140 return 1;
141}
142
Roger E. Masseb15bef81996-12-17 19:55:33 +0000143static PyObject *
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200144dbm_subscript(dbmobject *dp, PyObject *key)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000145{
Fred Drakee3a41c62000-07-08 05:00:07 +0000146 PyObject *v;
147 datum drec, krec;
Fred Drakeda8d2162000-02-07 17:19:41 +0000148
Inada Naokic5a216e2019-03-20 19:01:55 +0900149 if (!parse_datum(key, &krec, NULL)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000150 return NULL;
Inada Naokic5a216e2019-03-20 19:01:55 +0900151 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000152 if (dp->di_dbm == NULL) {
153 PyErr_SetString(DbmError,
154 "GDBM object has already been closed");
155 return NULL;
156 }
157 drec = gdbm_fetch(dp->di_dbm, krec);
158 if (drec.dptr == 0) {
Guido van Rossum6252e102007-05-23 20:51:02 +0000159 PyErr_SetObject(PyExc_KeyError, key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000160 return NULL;
161 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000162 v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000163 free(drec.dptr);
164 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000165}
166
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300167/*[clinic input]
168_gdbm.gdbm.get
169
170 key: object
171 default: object = None
172 /
173
174Get the value for key, or default if not present.
175[clinic start generated code]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000176
177static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300178_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
179/*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000180{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300181 PyObject *res;
Georg Brandld9e833c2010-12-04 09:14:36 +0000182
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300183 res = dbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000184 if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
185 PyErr_Clear();
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300186 Py_INCREF(default_value);
187 return default_value;
Georg Brandld9e833c2010-12-04 09:14:36 +0000188 }
189 return res;
190}
191
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000192static int
Fred Drakee3a41c62000-07-08 05:00:07 +0000193dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000194{
Fred Drakee3a41c62000-07-08 05:00:07 +0000195 datum krec, drec;
Inada Naokic5a216e2019-03-20 19:01:55 +0900196 const char *failmsg = "gdbm mappings have bytes or string indices only";
Fred Drakee3a41c62000-07-08 05:00:07 +0000197
Inada Naokic5a216e2019-03-20 19:01:55 +0900198 if (!parse_datum(v, &krec, failmsg)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000199 return -1;
200 }
201 if (dp->di_dbm == NULL) {
202 PyErr_SetString(DbmError,
Guido van Rossum6252e102007-05-23 20:51:02 +0000203 "GDBM object has already been closed");
204 return -1;
Fred Drakee3a41c62000-07-08 05:00:07 +0000205 }
206 dp->di_size = -1;
207 if (w == NULL) {
208 if (gdbm_delete(dp->di_dbm, krec) < 0) {
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800209 if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
210 PyErr_SetObject(PyExc_KeyError, v);
211 }
212 else {
213 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
214 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000215 return -1;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000216 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000217 }
218 else {
Inada Naokic5a216e2019-03-20 19:01:55 +0900219 if (!parse_datum(w, &drec, failmsg)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000220 return -1;
221 }
222 errno = 0;
223 if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
224 if (errno != 0)
225 PyErr_SetFromErrno(DbmError);
226 else
227 PyErr_SetString(DbmError,
228 gdbm_strerror(gdbm_errno));
229 return -1;
230 }
231 }
232 return 0;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000233}
234
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300235/*[clinic input]
236_gdbm.gdbm.setdefault
237
238 key: object
239 default: object = None
240 /
241
242Get value for key, or set it to default and return default if not present.
243[clinic start generated code]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000244
245static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300246_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
247 PyObject *default_value)
248/*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000249{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300250 PyObject *res;
Georg Brandld9e833c2010-12-04 09:14:36 +0000251
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300252 res = dbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000253 if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
254 PyErr_Clear();
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300255 if (dbm_ass_sub(self, key, default_value) < 0)
Georg Brandld9e833c2010-12-04 09:14:36 +0000256 return NULL;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300257 return dbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000258 }
259 return res;
260}
261
Roger E. Masseb15bef81996-12-17 19:55:33 +0000262static PyMappingMethods dbm_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 (lenfunc)dbm_length, /*mp_length*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000264 (binaryfunc)dbm_subscript, /*mp_subscript*/
265 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000266};
267
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300268/*[clinic input]
269_gdbm.gdbm.close
270
271Close the database.
272[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000273
Roger E. Masseb15bef81996-12-17 19:55:33 +0000274static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300275_gdbm_gdbm_close_impl(dbmobject *self)
276/*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/
Guido van Rossum807b7be1995-07-07 22:37:11 +0000277{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300278 if (self->di_dbm)
279 gdbm_close(self->di_dbm);
280 self->di_dbm = NULL;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200281 Py_RETURN_NONE;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000282}
283
Guido van Rossum6252e102007-05-23 20:51:02 +0000284/* XXX Should return a set or a set view */
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300285/*[clinic input]
286_gdbm.gdbm.keys
287
288Get a list of all keys in the database.
289[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000290
Roger E. Masseb15bef81996-12-17 19:55:33 +0000291static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300292_gdbm_gdbm_keys_impl(dbmobject *self)
293/*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000294{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200295 PyObject *v, *item;
Fred Drakee3a41c62000-07-08 05:00:07 +0000296 datum key, nextkey;
297 int err;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000298
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300299 if (self == NULL || !is_dbmobject(self)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000300 PyErr_BadInternalCall();
301 return NULL;
302 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300303 check_dbmobject_open(self);
Guido van Rossum3be71401996-07-21 02:32:44 +0000304
Fred Drakee3a41c62000-07-08 05:00:07 +0000305 v = PyList_New(0);
306 if (v == NULL)
307 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000308
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300309 key = gdbm_firstkey(self->di_dbm);
Fred Drakee3a41c62000-07-08 05:00:07 +0000310 while (key.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000311 item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000312 if (item == NULL) {
313 free(key.dptr);
314 Py_DECREF(v);
315 return NULL;
316 }
317 err = PyList_Append(v, item);
318 Py_DECREF(item);
319 if (err != 0) {
320 free(key.dptr);
321 Py_DECREF(v);
322 return NULL;
323 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300324 nextkey = gdbm_nextkey(self->di_dbm, key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000325 free(key.dptr);
326 key = nextkey;
327 }
328 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000329}
330
Guido van Rossum0da7e032006-08-19 23:18:48 +0000331static int
332dbm_contains(PyObject *self, PyObject *arg)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000333{
Guido van Rossum0da7e032006-08-19 23:18:48 +0000334 dbmobject *dp = (dbmobject *)self;
Fred Drakee3a41c62000-07-08 05:00:07 +0000335 datum key;
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300336 Py_ssize_t size;
Fred Drakee3a41c62000-07-08 05:00:07 +0000337
Guido van Rossum0da7e032006-08-19 23:18:48 +0000338 if ((dp)->di_dbm == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 PyErr_SetString(DbmError,
340 "GDBM object has already been closed");
341 return -1;
Guido van Rossum0da7e032006-08-19 23:18:48 +0000342 }
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300343 if (PyUnicode_Check(arg)) {
Serhiy Storchaka2a404b62017-01-22 23:07:07 +0200344 key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300345 key.dsize = size;
346 if (key.dptr == NULL)
347 return -1;
348 }
349 else if (!PyBytes_Check(arg)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 PyErr_Format(PyExc_TypeError,
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300351 "gdbm key must be bytes or string, not %.100s",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 arg->ob_type->tp_name);
353 return -1;
Guido van Rossum0da7e032006-08-19 23:18:48 +0000354 }
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300355 else {
356 key.dptr = PyBytes_AS_STRING(arg);
357 key.dsize = PyBytes_GET_SIZE(arg);
358 }
Guido van Rossum0da7e032006-08-19 23:18:48 +0000359 return gdbm_exists(dp->di_dbm, key);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000360}
361
Guido van Rossum0da7e032006-08-19 23:18:48 +0000362static PySequenceMethods dbm_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000363 0, /* sq_length */
364 0, /* sq_concat */
365 0, /* sq_repeat */
366 0, /* sq_item */
367 0, /* sq_slice */
368 0, /* sq_ass_item */
369 0, /* sq_ass_slice */
370 dbm_contains, /* sq_contains */
371 0, /* sq_inplace_concat */
372 0, /* sq_inplace_repeat */
Guido van Rossum0da7e032006-08-19 23:18:48 +0000373};
374
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300375/*[clinic input]
376_gdbm.gdbm.firstkey
377
378Return the starting key for the traversal.
379
380It's possible to loop over every key in the database using this method
381and the nextkey() method. The traversal is ordered by GDBM's internal
382hash values, and won't be sorted by the key values.
383[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000384
Roger E. Masseb15bef81996-12-17 19:55:33 +0000385static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300386_gdbm_gdbm_firstkey_impl(dbmobject *self)
387/*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000388{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200389 PyObject *v;
Fred Drakee3a41c62000-07-08 05:00:07 +0000390 datum key;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000391
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300392 check_dbmobject_open(self);
393 key = gdbm_firstkey(self->di_dbm);
Fred Drakee3a41c62000-07-08 05:00:07 +0000394 if (key.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000395 v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000396 free(key.dptr);
397 return v;
398 }
399 else {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200400 Py_RETURN_NONE;
Fred Drakee3a41c62000-07-08 05:00:07 +0000401 }
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000402}
403
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300404/*[clinic input]
405_gdbm.gdbm.nextkey
406
Larry Hastings38337d12015-05-07 23:30:09 -0700407 key: str(accept={str, robuffer}, zeroes=True)
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300408 /
409
410Returns the key that follows key in the traversal.
411
412The following code prints every key in the database db, without having
413to create a list in memory that contains them all:
414
415 k = db.firstkey()
416 while k != None:
417 print(k)
418 k = db.nextkey(k)
419[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000420
Roger E. Masseb15bef81996-12-17 19:55:33 +0000421static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300422_gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
423 Py_ssize_clean_t key_length)
Larry Hastings38337d12015-05-07 23:30:09 -0700424/*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000425{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200426 PyObject *v;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300427 datum dbm_key, nextkey;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000428
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300429 dbm_key.dptr = (char *)key;
430 dbm_key.dsize = key_length;
431 check_dbmobject_open(self);
432 nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000433 if (nextkey.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000434 v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000435 free(nextkey.dptr);
436 return v;
437 }
438 else {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200439 Py_RETURN_NONE;
Fred Drakee3a41c62000-07-08 05:00:07 +0000440 }
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000441}
442
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300443/*[clinic input]
444_gdbm.gdbm.reorganize
445
446Reorganize the database.
447
448If you have carried out a lot of deletions and would like to shrink
449the space used by the GDBM file, this routine will reorganize the
450database. GDBM will not shorten the length of a database file except
451by using this reorganization; otherwise, deleted file space will be
452kept and reused as new (key,value) pairs are added.
453[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000454
Roger E. Masseb15bef81996-12-17 19:55:33 +0000455static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300456_gdbm_gdbm_reorganize_impl(dbmobject *self)
457/*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000458{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300459 check_dbmobject_open(self);
Fred Drakee3a41c62000-07-08 05:00:07 +0000460 errno = 0;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300461 if (gdbm_reorganize(self->di_dbm) < 0) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000462 if (errno != 0)
463 PyErr_SetFromErrno(DbmError);
464 else
465 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
466 return NULL;
467 }
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200468 Py_RETURN_NONE;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000469}
470
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300471/*[clinic input]
472_gdbm.gdbm.sync
473
474Flush the database to the disk file.
475
476When the database has been opened in fast mode, this method forces
477any unwritten data to be written to the disk.
478[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000479
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000480static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300481_gdbm_gdbm_sync_impl(dbmobject *self)
482/*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000483{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300484 check_dbmobject_open(self);
485 gdbm_sync(self->di_dbm);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200486 Py_RETURN_NONE;
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000487}
488
Nick Coghlanc610aba2013-11-17 15:59:51 +1000489static PyObject *
490dbm__enter__(PyObject *self, PyObject *args)
491{
492 Py_INCREF(self);
493 return self;
494}
495
496static PyObject *
497dbm__exit__(PyObject *self, PyObject *args)
498{
499 _Py_IDENTIFIER(close);
500 return _PyObject_CallMethodId(self, &PyId_close, NULL);
501}
502
Roger E. Masseb15bef81996-12-17 19:55:33 +0000503static PyMethodDef dbm_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300504 _GDBM_GDBM_CLOSE_METHODDEF
505 _GDBM_GDBM_KEYS_METHODDEF
506 _GDBM_GDBM_FIRSTKEY_METHODDEF
507 _GDBM_GDBM_NEXTKEY_METHODDEF
508 _GDBM_GDBM_REORGANIZE_METHODDEF
509 _GDBM_GDBM_SYNC_METHODDEF
510 _GDBM_GDBM_GET_METHODDEF
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300511 _GDBM_GDBM_SETDEFAULT_METHODDEF
Nick Coghlanc610aba2013-11-17 15:59:51 +1000512 {"__enter__", dbm__enter__, METH_NOARGS, NULL},
513 {"__exit__", dbm__exit__, METH_VARARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000514 {NULL, NULL} /* sentinel */
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000515};
516
Roger E. Masseb15bef81996-12-17 19:55:33 +0000517static PyTypeObject Dbmtype = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000518 PyVarObject_HEAD_INIT(0, 0)
Georg Brandl0a7ac7d2008-05-26 10:29:35 +0000519 "_gdbm.gdbm",
Fred Drakee3a41c62000-07-08 05:00:07 +0000520 sizeof(dbmobject),
521 0,
522 (destructor)dbm_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200523 0, /*tp_vectorcall_offset*/
Amaury Forgeot d'Arc1f900f12008-07-02 22:38:47 +0000524 0, /*tp_getattr*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000525 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200526 0, /*tp_as_async*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000527 0, /*tp_repr*/
528 0, /*tp_as_number*/
Guido van Rossum0da7e032006-08-19 23:18:48 +0000529 &dbm_as_sequence, /*tp_as_sequence*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000530 &dbm_as_mapping, /*tp_as_mapping*/
531 0, /*tp_hash*/
532 0, /*tp_call*/
533 0, /*tp_str*/
534 0, /*tp_getattro*/
535 0, /*tp_setattro*/
536 0, /*tp_as_buffer*/
Christian Heimes836baa52008-02-26 08:18:30 +0000537 Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000538 gdbm_object__doc__, /*tp_doc*/
Amaury Forgeot d'Arc1f900f12008-07-02 22:38:47 +0000539 0, /*tp_traverse*/
540 0, /*tp_clear*/
541 0, /*tp_richcompare*/
542 0, /*tp_weaklistoffset*/
543 0, /*tp_iter*/
544 0, /*tp_iternext*/
545 dbm_methods, /*tp_methods*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000546};
547
548/* ----------------------------------------------------------------- */
549
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300550/*[clinic input]
551_gdbm.open as dbmopen
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200552 filename: unicode
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300553 flags: str="r"
554 mode: int(py_default="0o666") = 0o666
555 /
556
557Open a dbm database and return a dbm object.
558
559The filename argument is the name of the database file.
560
561The optional flags argument can be 'r' (to open an existing database
562for reading only -- default), 'w' (to open an existing database for
563reading and writing), 'c' (which creates the database if it doesn't
564exist), or 'n' (which always creates a new empty database).
565
566Some versions of gdbm support additional flags which must be
567appended to one of the flags described above. The module constant
568'open_flags' is a string of valid additional flags. The 'f' flag
569opens the database in fast mode; altered data will not automatically
570be written to the disk after every change. This results in faster
571writes to the database, but may result in an inconsistent database
572if the program crashes while the database is still open. Use the
573sync() method to force any unwritten data to be written to the disk.
574The 's' flag causes all database operations to be synchronized to
575disk. The 'u' flag disables locking of the database file.
576
577The optional mode argument is the Unix mode of the file, used only
578when the database has to be created. It defaults to octal 0o666.
579[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000580
Roger E. Masseb15bef81996-12-17 19:55:33 +0000581static PyObject *
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200582dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
583 int mode)
584/*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000585{
Fred Drakee3a41c62000-07-08 05:00:07 +0000586 int iflags;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000587
Fred Drakee3a41c62000-07-08 05:00:07 +0000588 switch (flags[0]) {
589 case 'r':
590 iflags = GDBM_READER;
591 break;
592 case 'w':
593 iflags = GDBM_WRITER;
594 break;
595 case 'c':
596 iflags = GDBM_WRCREAT;
597 break;
598 case 'n':
599 iflags = GDBM_NEWDB;
600 break;
601 default:
602 PyErr_SetString(DbmError,
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000603 "First flag must be one of 'r', 'w', 'c' or 'n'");
Fred Drakee3a41c62000-07-08 05:00:07 +0000604 return NULL;
605 }
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000606 for (flags++; *flags != '\0'; flags++) {
607 char buf[40];
608 switch (*flags) {
609#ifdef GDBM_FAST
610 case 'f':
611 iflags |= GDBM_FAST;
612 break;
613#endif
614#ifdef GDBM_SYNC
615 case 's':
616 iflags |= GDBM_SYNC;
617 break;
618#endif
619#ifdef GDBM_NOLOCK
620 case 'u':
621 iflags |= GDBM_NOLOCK;
622 break;
623#endif
624 default:
Tim Peters885d4572001-11-28 20:27:42 +0000625 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000626 *flags);
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000627 PyErr_SetString(DbmError, buf);
628 return NULL;
629 }
630 }
631
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200632 PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
633 if (filenamebytes == NULL) {
634 return NULL;
635 }
636 const char *name = PyBytes_AS_STRING(filenamebytes);
637 if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
638 Py_DECREF(filenamebytes);
639 PyErr_SetString(PyExc_ValueError, "embedded null character");
640 return NULL;
641 }
642 PyObject *self = newdbmobject(name, iflags, mode);
643 Py_DECREF(filenamebytes);
644 return self;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000645}
646
Serhiy Storchaka2d06e842015-12-25 19:53:18 +0200647static const char dbmmodule_open_flags[] = "rwcn"
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000648#ifdef GDBM_FAST
649 "f"
650#endif
651#ifdef GDBM_SYNC
652 "s"
653#endif
654#ifdef GDBM_NOLOCK
655 "u"
656#endif
657 ;
658
Roger E. Masseb15bef81996-12-17 19:55:33 +0000659static PyMethodDef dbmmodule_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300660 DBMOPEN_METHODDEF
Fred Drakee3a41c62000-07-08 05:00:07 +0000661 { 0, 0 },
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000662};
663
Martin v. Löwis1a214512008-06-11 05:26:20 +0000664
665static struct PyModuleDef _gdbmmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000666 PyModuleDef_HEAD_INIT,
667 "_gdbm",
668 gdbmmodule__doc__,
669 -1,
670 dbmmodule_methods,
671 NULL,
672 NULL,
673 NULL,
674 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000675};
676
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000677PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000678PyInit__gdbm(void) {
Victor Stinner00f9edb2018-06-19 23:29:22 +0200679 PyObject *m;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000680
Guido van Rossum0da7e032006-08-19 23:18:48 +0000681 if (PyType_Ready(&Dbmtype) < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000682 return NULL;
Martin v. Löwis1a214512008-06-11 05:26:20 +0000683 m = PyModule_Create(&_gdbmmodule);
Victor Stinner00f9edb2018-06-19 23:29:22 +0200684 if (m == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000685 return NULL;
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000686 }
Victor Stinner00f9edb2018-06-19 23:29:22 +0200687
688 DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
689 if (DbmError == NULL) {
690 goto error;
691 }
692 Py_INCREF(DbmError);
693 if (PyModule_AddObject(m, "error", DbmError) < 0) {
694 Py_DECREF(DbmError);
695 goto error;
696 }
697
698 if (PyModule_AddStringConstant(m, "open_flags",
699 dbmmodule_open_flags) < 0) {
700 goto error;
701 }
702
Xiang Zhangb248e952018-06-20 21:23:30 +0800703#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
704 defined(GDBM_VERSION_PATCH)
Victor Stinner00f9edb2018-06-19 23:29:22 +0200705 PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
706 GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
707 if (obj == NULL) {
708 goto error;
709 }
710 if (PyModule_AddObject(m, "_GDBM_VERSION", obj) < 0) {
711 Py_DECREF(obj);
712 goto error;
713 }
Xiang Zhangb248e952018-06-20 21:23:30 +0800714#endif
Victor Stinner00f9edb2018-06-19 23:29:22 +0200715
Martin v. Löwis1a214512008-06-11 05:26:20 +0000716 return m;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200717
718error:
719 Py_DECREF(m);
720 return NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000721}