blob: dd4c6b16f745cf01ef1c3ffbb4912e07a1eaa22d [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
Dong-hee Na87276642020-05-01 21:15:35 +090039 Py_ssize_t 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
Dong-hee Na1b55b652020-02-17 19:09:15 +090047#define is_dbmobject(v) Py_IS_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) {
Dong-hee Na87276642020-05-01 21:15:35 +0900105#if GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11
106 errno = 0;
107 gdbm_count_t count;
108 if (gdbm_count(dp->di_dbm, &count) == -1) {
109 if (errno != 0) {
110 PyErr_SetFromErrno(DbmError);
111 }
112 else {
113 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
114 }
115 return -1;
116 }
117 if (count > PY_SSIZE_T_MAX) {
118 PyErr_SetString(PyExc_OverflowError, "count exceeds PY_SSIZE_T_MAX");
119 return -1;
120 }
121 dp->di_size = count;
122#else
Fred Drakee3a41c62000-07-08 05:00:07 +0000123 datum key,okey;
Fred Drakee3a41c62000-07-08 05:00:07 +0000124 okey.dsize=0;
Thomas Woutersa5fa2a82006-03-01 22:54:36 +0000125 okey.dptr=NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000126
Dong-hee Na87276642020-05-01 21:15:35 +0900127 Py_ssize_t size = 0;
128 for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
Fred Drakee3a41c62000-07-08 05:00:07 +0000129 key = gdbm_nextkey(dp->di_dbm,okey)) {
130 size++;
Dong-hee Na87276642020-05-01 21:15:35 +0900131 if (okey.dsize) {
132 free(okey.dptr);
133 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000134 okey=key;
135 }
136 dp->di_size = size;
Dong-hee Na87276642020-05-01 21:15:35 +0900137#endif
Fred Drakee3a41c62000-07-08 05:00:07 +0000138 }
139 return dp->di_size;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000140}
141
Inada Naokic5a216e2019-03-20 19:01:55 +0900142// Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
143// This function is needed to support PY_SSIZE_T_CLEAN.
144// Return 1 on success, same to PyArg_Parse().
145static int
146parse_datum(PyObject *o, datum *d, const char *failmsg)
147{
148 Py_ssize_t size;
149 if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
150 if (failmsg != NULL) {
151 PyErr_SetString(PyExc_TypeError, failmsg);
152 }
153 return 0;
154 }
155 if (INT_MAX < size) {
156 PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
157 return 0;
158 }
159 d->dsize = size;
160 return 1;
161}
162
Roger E. Masseb15bef81996-12-17 19:55:33 +0000163static PyObject *
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200164dbm_subscript(dbmobject *dp, PyObject *key)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000165{
Fred Drakee3a41c62000-07-08 05:00:07 +0000166 PyObject *v;
167 datum drec, krec;
Fred Drakeda8d2162000-02-07 17:19:41 +0000168
Inada Naokic5a216e2019-03-20 19:01:55 +0900169 if (!parse_datum(key, &krec, NULL)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000170 return NULL;
Inada Naokic5a216e2019-03-20 19:01:55 +0900171 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000172 if (dp->di_dbm == NULL) {
173 PyErr_SetString(DbmError,
174 "GDBM object has already been closed");
175 return NULL;
176 }
177 drec = gdbm_fetch(dp->di_dbm, krec);
178 if (drec.dptr == 0) {
Guido van Rossum6252e102007-05-23 20:51:02 +0000179 PyErr_SetObject(PyExc_KeyError, key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000180 return NULL;
181 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000182 v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000183 free(drec.dptr);
184 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000185}
186
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300187/*[clinic input]
188_gdbm.gdbm.get
189
190 key: object
191 default: object = None
192 /
193
194Get the value for key, or default if not present.
195[clinic start generated code]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000196
197static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300198_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
199/*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000200{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300201 PyObject *res;
Georg Brandld9e833c2010-12-04 09:14:36 +0000202
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300203 res = dbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000204 if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
205 PyErr_Clear();
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300206 Py_INCREF(default_value);
207 return default_value;
Georg Brandld9e833c2010-12-04 09:14:36 +0000208 }
209 return res;
210}
211
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000212static int
Fred Drakee3a41c62000-07-08 05:00:07 +0000213dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000214{
Fred Drakee3a41c62000-07-08 05:00:07 +0000215 datum krec, drec;
Inada Naokic5a216e2019-03-20 19:01:55 +0900216 const char *failmsg = "gdbm mappings have bytes or string indices only";
Fred Drakee3a41c62000-07-08 05:00:07 +0000217
Inada Naokic5a216e2019-03-20 19:01:55 +0900218 if (!parse_datum(v, &krec, failmsg)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000219 return -1;
220 }
221 if (dp->di_dbm == NULL) {
222 PyErr_SetString(DbmError,
Guido van Rossum6252e102007-05-23 20:51:02 +0000223 "GDBM object has already been closed");
224 return -1;
Fred Drakee3a41c62000-07-08 05:00:07 +0000225 }
226 dp->di_size = -1;
227 if (w == NULL) {
228 if (gdbm_delete(dp->di_dbm, krec) < 0) {
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800229 if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
230 PyErr_SetObject(PyExc_KeyError, v);
231 }
232 else {
233 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
234 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000235 return -1;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000236 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000237 }
238 else {
Inada Naokic5a216e2019-03-20 19:01:55 +0900239 if (!parse_datum(w, &drec, failmsg)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000240 return -1;
241 }
242 errno = 0;
243 if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
244 if (errno != 0)
245 PyErr_SetFromErrno(DbmError);
246 else
247 PyErr_SetString(DbmError,
248 gdbm_strerror(gdbm_errno));
249 return -1;
250 }
251 }
252 return 0;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000253}
254
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300255/*[clinic input]
256_gdbm.gdbm.setdefault
257
258 key: object
259 default: object = None
260 /
261
262Get value for key, or set it to default and return default if not present.
263[clinic start generated code]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000264
265static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300266_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
267 PyObject *default_value)
268/*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000269{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300270 PyObject *res;
Georg Brandld9e833c2010-12-04 09:14:36 +0000271
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300272 res = dbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000273 if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
274 PyErr_Clear();
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300275 if (dbm_ass_sub(self, key, default_value) < 0)
Georg Brandld9e833c2010-12-04 09:14:36 +0000276 return NULL;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300277 return dbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000278 }
279 return res;
280}
281
Roger E. Masseb15bef81996-12-17 19:55:33 +0000282static PyMappingMethods dbm_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 (lenfunc)dbm_length, /*mp_length*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000284 (binaryfunc)dbm_subscript, /*mp_subscript*/
285 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000286};
287
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300288/*[clinic input]
289_gdbm.gdbm.close
290
291Close the database.
292[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000293
Roger E. Masseb15bef81996-12-17 19:55:33 +0000294static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300295_gdbm_gdbm_close_impl(dbmobject *self)
296/*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/
Guido van Rossum807b7be1995-07-07 22:37:11 +0000297{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300298 if (self->di_dbm)
299 gdbm_close(self->di_dbm);
300 self->di_dbm = NULL;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200301 Py_RETURN_NONE;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000302}
303
Guido van Rossum6252e102007-05-23 20:51:02 +0000304/* XXX Should return a set or a set view */
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300305/*[clinic input]
306_gdbm.gdbm.keys
307
308Get a list of all keys in the database.
309[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000310
Roger E. Masseb15bef81996-12-17 19:55:33 +0000311static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300312_gdbm_gdbm_keys_impl(dbmobject *self)
313/*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000314{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200315 PyObject *v, *item;
Fred Drakee3a41c62000-07-08 05:00:07 +0000316 datum key, nextkey;
317 int err;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000318
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300319 if (self == NULL || !is_dbmobject(self)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000320 PyErr_BadInternalCall();
321 return NULL;
322 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300323 check_dbmobject_open(self);
Guido van Rossum3be71401996-07-21 02:32:44 +0000324
Fred Drakee3a41c62000-07-08 05:00:07 +0000325 v = PyList_New(0);
326 if (v == NULL)
327 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000328
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300329 key = gdbm_firstkey(self->di_dbm);
Fred Drakee3a41c62000-07-08 05:00:07 +0000330 while (key.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000331 item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000332 if (item == NULL) {
333 free(key.dptr);
334 Py_DECREF(v);
335 return NULL;
336 }
337 err = PyList_Append(v, item);
338 Py_DECREF(item);
339 if (err != 0) {
340 free(key.dptr);
341 Py_DECREF(v);
342 return NULL;
343 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300344 nextkey = gdbm_nextkey(self->di_dbm, key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000345 free(key.dptr);
346 key = nextkey;
347 }
348 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000349}
350
Guido van Rossum0da7e032006-08-19 23:18:48 +0000351static int
352dbm_contains(PyObject *self, PyObject *arg)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000353{
Guido van Rossum0da7e032006-08-19 23:18:48 +0000354 dbmobject *dp = (dbmobject *)self;
Fred Drakee3a41c62000-07-08 05:00:07 +0000355 datum key;
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300356 Py_ssize_t size;
Fred Drakee3a41c62000-07-08 05:00:07 +0000357
Guido van Rossum0da7e032006-08-19 23:18:48 +0000358 if ((dp)->di_dbm == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 PyErr_SetString(DbmError,
360 "GDBM object has already been closed");
361 return -1;
Guido van Rossum0da7e032006-08-19 23:18:48 +0000362 }
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300363 if (PyUnicode_Check(arg)) {
Serhiy Storchaka2a404b62017-01-22 23:07:07 +0200364 key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300365 key.dsize = size;
366 if (key.dptr == NULL)
367 return -1;
368 }
369 else if (!PyBytes_Check(arg)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 PyErr_Format(PyExc_TypeError,
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300371 "gdbm key must be bytes or string, not %.100s",
Victor Stinnerdaa97562020-02-07 03:37:06 +0100372 Py_TYPE(arg)->tp_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 return -1;
Guido van Rossum0da7e032006-08-19 23:18:48 +0000374 }
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300375 else {
376 key.dptr = PyBytes_AS_STRING(arg);
377 key.dsize = PyBytes_GET_SIZE(arg);
378 }
Guido van Rossum0da7e032006-08-19 23:18:48 +0000379 return gdbm_exists(dp->di_dbm, key);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000380}
381
Guido van Rossum0da7e032006-08-19 23:18:48 +0000382static PySequenceMethods dbm_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 0, /* sq_length */
384 0, /* sq_concat */
385 0, /* sq_repeat */
386 0, /* sq_item */
387 0, /* sq_slice */
388 0, /* sq_ass_item */
389 0, /* sq_ass_slice */
390 dbm_contains, /* sq_contains */
391 0, /* sq_inplace_concat */
392 0, /* sq_inplace_repeat */
Guido van Rossum0da7e032006-08-19 23:18:48 +0000393};
394
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300395/*[clinic input]
396_gdbm.gdbm.firstkey
397
398Return the starting key for the traversal.
399
400It's possible to loop over every key in the database using this method
401and the nextkey() method. The traversal is ordered by GDBM's internal
402hash values, and won't be sorted by the key values.
403[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000404
Roger E. Masseb15bef81996-12-17 19:55:33 +0000405static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300406_gdbm_gdbm_firstkey_impl(dbmobject *self)
407/*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000408{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200409 PyObject *v;
Fred Drakee3a41c62000-07-08 05:00:07 +0000410 datum key;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000411
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300412 check_dbmobject_open(self);
413 key = gdbm_firstkey(self->di_dbm);
Fred Drakee3a41c62000-07-08 05:00:07 +0000414 if (key.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000415 v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000416 free(key.dptr);
417 return v;
418 }
419 else {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200420 Py_RETURN_NONE;
Fred Drakee3a41c62000-07-08 05:00:07 +0000421 }
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000422}
423
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300424/*[clinic input]
425_gdbm.gdbm.nextkey
426
Larry Hastings38337d12015-05-07 23:30:09 -0700427 key: str(accept={str, robuffer}, zeroes=True)
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300428 /
429
430Returns the key that follows key in the traversal.
431
432The following code prints every key in the database db, without having
433to create a list in memory that contains them all:
434
435 k = db.firstkey()
436 while k != None:
437 print(k)
438 k = db.nextkey(k)
439[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000440
Roger E. Masseb15bef81996-12-17 19:55:33 +0000441static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300442_gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
443 Py_ssize_clean_t key_length)
Larry Hastings38337d12015-05-07 23:30:09 -0700444/*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000445{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200446 PyObject *v;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300447 datum dbm_key, nextkey;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000448
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300449 dbm_key.dptr = (char *)key;
450 dbm_key.dsize = key_length;
451 check_dbmobject_open(self);
452 nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000453 if (nextkey.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000454 v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000455 free(nextkey.dptr);
456 return v;
457 }
458 else {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200459 Py_RETURN_NONE;
Fred Drakee3a41c62000-07-08 05:00:07 +0000460 }
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000461}
462
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300463/*[clinic input]
464_gdbm.gdbm.reorganize
465
466Reorganize the database.
467
468If you have carried out a lot of deletions and would like to shrink
469the space used by the GDBM file, this routine will reorganize the
470database. GDBM will not shorten the length of a database file except
471by using this reorganization; otherwise, deleted file space will be
472kept and reused as new (key,value) pairs are added.
473[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000474
Roger E. Masseb15bef81996-12-17 19:55:33 +0000475static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300476_gdbm_gdbm_reorganize_impl(dbmobject *self)
477/*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000478{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300479 check_dbmobject_open(self);
Fred Drakee3a41c62000-07-08 05:00:07 +0000480 errno = 0;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300481 if (gdbm_reorganize(self->di_dbm) < 0) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000482 if (errno != 0)
483 PyErr_SetFromErrno(DbmError);
484 else
485 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
486 return NULL;
487 }
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200488 Py_RETURN_NONE;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000489}
490
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300491/*[clinic input]
492_gdbm.gdbm.sync
493
494Flush the database to the disk file.
495
496When the database has been opened in fast mode, this method forces
497any unwritten data to be written to the disk.
498[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000499
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000500static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300501_gdbm_gdbm_sync_impl(dbmobject *self)
502/*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000503{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300504 check_dbmobject_open(self);
505 gdbm_sync(self->di_dbm);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200506 Py_RETURN_NONE;
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000507}
508
Nick Coghlanc610aba2013-11-17 15:59:51 +1000509static PyObject *
510dbm__enter__(PyObject *self, PyObject *args)
511{
512 Py_INCREF(self);
513 return self;
514}
515
516static PyObject *
517dbm__exit__(PyObject *self, PyObject *args)
518{
519 _Py_IDENTIFIER(close);
Jeroen Demeyer762f93f2019-07-08 10:19:25 +0200520 return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
Nick Coghlanc610aba2013-11-17 15:59:51 +1000521}
522
Roger E. Masseb15bef81996-12-17 19:55:33 +0000523static PyMethodDef dbm_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300524 _GDBM_GDBM_CLOSE_METHODDEF
525 _GDBM_GDBM_KEYS_METHODDEF
526 _GDBM_GDBM_FIRSTKEY_METHODDEF
527 _GDBM_GDBM_NEXTKEY_METHODDEF
528 _GDBM_GDBM_REORGANIZE_METHODDEF
529 _GDBM_GDBM_SYNC_METHODDEF
530 _GDBM_GDBM_GET_METHODDEF
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300531 _GDBM_GDBM_SETDEFAULT_METHODDEF
Nick Coghlanc610aba2013-11-17 15:59:51 +1000532 {"__enter__", dbm__enter__, METH_NOARGS, NULL},
533 {"__exit__", dbm__exit__, METH_VARARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000534 {NULL, NULL} /* sentinel */
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000535};
536
Roger E. Masseb15bef81996-12-17 19:55:33 +0000537static PyTypeObject Dbmtype = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000538 PyVarObject_HEAD_INIT(0, 0)
Georg Brandl0a7ac7d2008-05-26 10:29:35 +0000539 "_gdbm.gdbm",
Fred Drakee3a41c62000-07-08 05:00:07 +0000540 sizeof(dbmobject),
541 0,
542 (destructor)dbm_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200543 0, /*tp_vectorcall_offset*/
Amaury Forgeot d'Arc1f900f12008-07-02 22:38:47 +0000544 0, /*tp_getattr*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000545 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200546 0, /*tp_as_async*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000547 0, /*tp_repr*/
548 0, /*tp_as_number*/
Guido van Rossum0da7e032006-08-19 23:18:48 +0000549 &dbm_as_sequence, /*tp_as_sequence*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000550 &dbm_as_mapping, /*tp_as_mapping*/
551 0, /*tp_hash*/
552 0, /*tp_call*/
553 0, /*tp_str*/
554 0, /*tp_getattro*/
555 0, /*tp_setattro*/
556 0, /*tp_as_buffer*/
Christian Heimes836baa52008-02-26 08:18:30 +0000557 Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
Fred Drakee3a41c62000-07-08 05:00:07 +0000558 gdbm_object__doc__, /*tp_doc*/
Amaury Forgeot d'Arc1f900f12008-07-02 22:38:47 +0000559 0, /*tp_traverse*/
560 0, /*tp_clear*/
561 0, /*tp_richcompare*/
562 0, /*tp_weaklistoffset*/
563 0, /*tp_iter*/
564 0, /*tp_iternext*/
565 dbm_methods, /*tp_methods*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000566};
567
568/* ----------------------------------------------------------------- */
569
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300570/*[clinic input]
571_gdbm.open as dbmopen
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200572 filename: unicode
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300573 flags: str="r"
574 mode: int(py_default="0o666") = 0o666
575 /
576
577Open a dbm database and return a dbm object.
578
579The filename argument is the name of the database file.
580
581The optional flags argument can be 'r' (to open an existing database
582for reading only -- default), 'w' (to open an existing database for
583reading and writing), 'c' (which creates the database if it doesn't
584exist), or 'n' (which always creates a new empty database).
585
586Some versions of gdbm support additional flags which must be
587appended to one of the flags described above. The module constant
588'open_flags' is a string of valid additional flags. The 'f' flag
589opens the database in fast mode; altered data will not automatically
590be written to the disk after every change. This results in faster
591writes to the database, but may result in an inconsistent database
592if the program crashes while the database is still open. Use the
593sync() method to force any unwritten data to be written to the disk.
594The 's' flag causes all database operations to be synchronized to
595disk. The 'u' flag disables locking of the database file.
596
597The optional mode argument is the Unix mode of the file, used only
598when the database has to be created. It defaults to octal 0o666.
599[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000600
Roger E. Masseb15bef81996-12-17 19:55:33 +0000601static PyObject *
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200602dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
603 int mode)
604/*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000605{
Fred Drakee3a41c62000-07-08 05:00:07 +0000606 int iflags;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000607
Fred Drakee3a41c62000-07-08 05:00:07 +0000608 switch (flags[0]) {
609 case 'r':
610 iflags = GDBM_READER;
611 break;
612 case 'w':
613 iflags = GDBM_WRITER;
614 break;
615 case 'c':
616 iflags = GDBM_WRCREAT;
617 break;
618 case 'n':
619 iflags = GDBM_NEWDB;
620 break;
621 default:
622 PyErr_SetString(DbmError,
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000623 "First flag must be one of 'r', 'w', 'c' or 'n'");
Fred Drakee3a41c62000-07-08 05:00:07 +0000624 return NULL;
625 }
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000626 for (flags++; *flags != '\0'; flags++) {
627 char buf[40];
628 switch (*flags) {
629#ifdef GDBM_FAST
630 case 'f':
631 iflags |= GDBM_FAST;
632 break;
633#endif
634#ifdef GDBM_SYNC
635 case 's':
636 iflags |= GDBM_SYNC;
637 break;
638#endif
639#ifdef GDBM_NOLOCK
640 case 'u':
641 iflags |= GDBM_NOLOCK;
642 break;
643#endif
644 default:
Tim Peters885d4572001-11-28 20:27:42 +0000645 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000646 *flags);
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000647 PyErr_SetString(DbmError, buf);
648 return NULL;
649 }
650 }
651
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200652 PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
653 if (filenamebytes == NULL) {
654 return NULL;
655 }
656 const char *name = PyBytes_AS_STRING(filenamebytes);
657 if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
658 Py_DECREF(filenamebytes);
659 PyErr_SetString(PyExc_ValueError, "embedded null character");
660 return NULL;
661 }
662 PyObject *self = newdbmobject(name, iflags, mode);
663 Py_DECREF(filenamebytes);
664 return self;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000665}
666
Serhiy Storchaka2d06e842015-12-25 19:53:18 +0200667static const char dbmmodule_open_flags[] = "rwcn"
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000668#ifdef GDBM_FAST
669 "f"
670#endif
671#ifdef GDBM_SYNC
672 "s"
673#endif
674#ifdef GDBM_NOLOCK
675 "u"
676#endif
677 ;
678
Roger E. Masseb15bef81996-12-17 19:55:33 +0000679static PyMethodDef dbmmodule_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300680 DBMOPEN_METHODDEF
Fred Drakee3a41c62000-07-08 05:00:07 +0000681 { 0, 0 },
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000682};
683
Martin v. Löwis1a214512008-06-11 05:26:20 +0000684
685static struct PyModuleDef _gdbmmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000686 PyModuleDef_HEAD_INIT,
687 "_gdbm",
688 gdbmmodule__doc__,
689 -1,
690 dbmmodule_methods,
691 NULL,
692 NULL,
693 NULL,
694 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000695};
696
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000697PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000698PyInit__gdbm(void) {
Victor Stinner00f9edb2018-06-19 23:29:22 +0200699 PyObject *m;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000700
Guido van Rossum0da7e032006-08-19 23:18:48 +0000701 if (PyType_Ready(&Dbmtype) < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000702 return NULL;
Martin v. Löwis1a214512008-06-11 05:26:20 +0000703 m = PyModule_Create(&_gdbmmodule);
Victor Stinner00f9edb2018-06-19 23:29:22 +0200704 if (m == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000705 return NULL;
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000706 }
Victor Stinner00f9edb2018-06-19 23:29:22 +0200707
708 DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
709 if (DbmError == NULL) {
710 goto error;
711 }
712 Py_INCREF(DbmError);
713 if (PyModule_AddObject(m, "error", DbmError) < 0) {
714 Py_DECREF(DbmError);
715 goto error;
716 }
717
718 if (PyModule_AddStringConstant(m, "open_flags",
719 dbmmodule_open_flags) < 0) {
720 goto error;
721 }
722
Xiang Zhangb248e952018-06-20 21:23:30 +0800723#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
724 defined(GDBM_VERSION_PATCH)
Victor Stinner00f9edb2018-06-19 23:29:22 +0200725 PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
726 GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
727 if (obj == NULL) {
728 goto error;
729 }
730 if (PyModule_AddObject(m, "_GDBM_VERSION", obj) < 0) {
731 Py_DECREF(obj);
732 goto error;
733 }
Xiang Zhangb248e952018-06-20 21:23:30 +0800734#endif
Victor Stinner00f9edb2018-06-19 23:29:22 +0200735
Martin v. Löwis1a214512008-06-11 05:26:20 +0000736 return m;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200737
738error:
739 Py_DECREF(m);
740 return NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000741}