blob: 9e843acbaa6ba5d78c48469f1bc58c605687ebf4 [file] [log] [blame]
Guido van Rossum4b4c6641994-08-08 08:06:37 +00001
Dong-hee Nac4862e32020-06-17 01:41:23 +09002/* GDBM 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
Dong-hee Nac4862e32020-06-17 01:41:23 +090019typedef struct {
20 PyTypeObject *gdbm_type;
21 PyObject *gdbm_error;
22} _gdbm_state;
23
24static inline _gdbm_state*
25get_gdbm_state(PyObject *module)
26{
27 void *state = PyModule_GetState(module);
28 assert(state != NULL);
29 return (_gdbm_state *)state;
30}
31
Serhiy Storchaka9260e772015-04-17 21:05:18 +030032/*[clinic input]
33module _gdbm
Dong-hee Nac4862e32020-06-17 01:41:23 +090034class _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
Serhiy Storchaka9260e772015-04-17 21:05:18 +030035[clinic start generated code]*/
Dong-hee Nac4862e32020-06-17 01:41:23 +090036/*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
Serhiy Storchaka9260e772015-04-17 21:05:18 +030037
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000038PyDoc_STRVAR(gdbmmodule__doc__,
39"This module provides an interface to the GNU DBM (GDBM) library.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000040\n\
41This module is quite similar to the dbm module, but uses GDBM instead to\n\
Serhiy Storchaka9260e772015-04-17 21:05:18 +030042provide some additional functionality. Please note that the file formats\n\
43created by GDBM and dbm are incompatible.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000044\n\
45GDBM objects behave like mappings (dictionaries), except that keys and\n\
Serhiy Storchaka9260e772015-04-17 21:05:18 +030046values are always immutable bytes-like objects or strings. Printing\n\
47a GDBM object doesn't print the keys and values, and the items() and\n\
48values() methods are not supported.");
Guido van Rossumbfc49e81998-03-03 22:02:24 +000049
Guido van Rossum4b4c6641994-08-08 08:06:37 +000050typedef struct {
Fred Drakee3a41c62000-07-08 05:00:07 +000051 PyObject_HEAD
Dong-hee Na87276642020-05-01 21:15:35 +090052 Py_ssize_t di_size; /* -1 means recompute */
Fred Drakee3a41c62000-07-08 05:00:07 +000053 GDBM_FILE di_dbm;
Dong-hee Nac4862e32020-06-17 01:41:23 +090054} gdbmobject;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000055
Serhiy Storchaka9260e772015-04-17 21:05:18 +030056#include "clinic/_gdbmmodule.c.h"
57
Dong-hee Nac4862e32020-06-17 01:41:23 +090058#define check_gdbmobject_open(v, err) \
59 if ((v)->di_dbm == NULL) { \
60 PyErr_SetString(err, "GDBM object has already been closed"); \
61 return NULL; \
62 }
Guido van Rossum4b4c6641994-08-08 08:06:37 +000063
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000064PyDoc_STRVAR(gdbm_object__doc__,
65"This object represents a GDBM database.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000066GDBM objects behave like mappings (dictionaries), except that keys and\n\
Serhiy Storchaka9260e772015-04-17 21:05:18 +030067values are always immutable bytes-like objects or strings. Printing\n\
68a GDBM object doesn't print the keys and values, and the items() and\n\
69values() methods are not supported.\n\
Guido van Rossumbfc49e81998-03-03 22:02:24 +000070\n\
71GDBM objects also support additional operations such as firstkey,\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000072nextkey, reorganize, and sync.");
Guido van Rossumbfc49e81998-03-03 22:02:24 +000073
Roger E. Masseb15bef81996-12-17 19:55:33 +000074static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +090075newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
Guido van Rossum4b4c6641994-08-08 08:06:37 +000076{
Dong-hee Nac4862e32020-06-17 01:41:23 +090077 gdbmobject *dp = PyObject_New(gdbmobject, state->gdbm_type);
78 if (dp == NULL) {
Fred Drakee3a41c62000-07-08 05:00:07 +000079 return NULL;
Dong-hee Nac4862e32020-06-17 01:41:23 +090080 }
Fred Drakee3a41c62000-07-08 05:00:07 +000081 dp->di_size = -1;
82 errno = 0;
Serhiy Storchaka9260e772015-04-17 21:05:18 +030083 if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
Dong-hee Nac4862e32020-06-17 01:41:23 +090084 if (errno != 0) {
85 PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
86 }
87 else {
88 PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
89 }
Fred Drakee3a41c62000-07-08 05:00:07 +000090 Py_DECREF(dp);
91 return NULL;
92 }
93 return (PyObject *)dp;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000094}
95
96/* Methods */
97
98static void
Dong-hee Nac4862e32020-06-17 01:41:23 +090099gdbm_dealloc(gdbmobject *dp)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000100{
Dong-hee Nac4862e32020-06-17 01:41:23 +0900101 if (dp->di_dbm) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000102 gdbm_close(dp->di_dbm);
Dong-hee Nac4862e32020-06-17 01:41:23 +0900103 }
104 PyTypeObject *tp = Py_TYPE(dp);
105 tp->tp_free(dp);
106 Py_DECREF(tp);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000107}
108
Martin v. Löwis18e16552006-02-15 17:27:45 +0000109static Py_ssize_t
Dong-hee Nac4862e32020-06-17 01:41:23 +0900110gdbm_length(gdbmobject *dp)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000111{
Dong-hee Nac4862e32020-06-17 01:41:23 +0900112 _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
Fred Drakee3a41c62000-07-08 05:00:07 +0000113 if (dp->di_dbm == NULL) {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900114 PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
Guido van Rossum6252e102007-05-23 20:51:02 +0000115 return -1;
Fred Drakee3a41c62000-07-08 05:00:07 +0000116 }
117 if (dp->di_size < 0) {
Dong-hee Na87276642020-05-01 21:15:35 +0900118#if GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11
119 errno = 0;
120 gdbm_count_t count;
121 if (gdbm_count(dp->di_dbm, &count) == -1) {
122 if (errno != 0) {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900123 PyErr_SetFromErrno(state->gdbm_error);
Dong-hee Na87276642020-05-01 21:15:35 +0900124 }
125 else {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900126 PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
Dong-hee Na87276642020-05-01 21:15:35 +0900127 }
128 return -1;
129 }
130 if (count > PY_SSIZE_T_MAX) {
131 PyErr_SetString(PyExc_OverflowError, "count exceeds PY_SSIZE_T_MAX");
132 return -1;
133 }
134 dp->di_size = count;
135#else
Fred Drakee3a41c62000-07-08 05:00:07 +0000136 datum key,okey;
Fred Drakee3a41c62000-07-08 05:00:07 +0000137 okey.dsize=0;
Thomas Woutersa5fa2a82006-03-01 22:54:36 +0000138 okey.dptr=NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000139
Dong-hee Na87276642020-05-01 21:15:35 +0900140 Py_ssize_t size = 0;
141 for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
Fred Drakee3a41c62000-07-08 05:00:07 +0000142 key = gdbm_nextkey(dp->di_dbm,okey)) {
143 size++;
Dong-hee Na87276642020-05-01 21:15:35 +0900144 if (okey.dsize) {
145 free(okey.dptr);
146 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000147 okey=key;
148 }
149 dp->di_size = size;
Dong-hee Na87276642020-05-01 21:15:35 +0900150#endif
Fred Drakee3a41c62000-07-08 05:00:07 +0000151 }
152 return dp->di_size;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000153}
154
Inada Naokic5a216e2019-03-20 19:01:55 +0900155// Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
156// This function is needed to support PY_SSIZE_T_CLEAN.
157// Return 1 on success, same to PyArg_Parse().
158static int
159parse_datum(PyObject *o, datum *d, const char *failmsg)
160{
161 Py_ssize_t size;
162 if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
163 if (failmsg != NULL) {
164 PyErr_SetString(PyExc_TypeError, failmsg);
165 }
166 return 0;
167 }
168 if (INT_MAX < size) {
169 PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
170 return 0;
171 }
172 d->dsize = size;
173 return 1;
174}
175
Roger E. Masseb15bef81996-12-17 19:55:33 +0000176static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900177gdbm_subscript(gdbmobject *dp, PyObject *key)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000178{
Fred Drakee3a41c62000-07-08 05:00:07 +0000179 PyObject *v;
180 datum drec, krec;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900181 _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
Fred Drakeda8d2162000-02-07 17:19:41 +0000182
Inada Naokic5a216e2019-03-20 19:01:55 +0900183 if (!parse_datum(key, &krec, NULL)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000184 return NULL;
Inada Naokic5a216e2019-03-20 19:01:55 +0900185 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000186 if (dp->di_dbm == NULL) {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900187 PyErr_SetString(state->gdbm_error,
Fred Drakee3a41c62000-07-08 05:00:07 +0000188 "GDBM object has already been closed");
189 return NULL;
190 }
191 drec = gdbm_fetch(dp->di_dbm, krec);
192 if (drec.dptr == 0) {
Guido van Rossum6252e102007-05-23 20:51:02 +0000193 PyErr_SetObject(PyExc_KeyError, key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000194 return NULL;
195 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000196 v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000197 free(drec.dptr);
198 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000199}
200
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300201/*[clinic input]
202_gdbm.gdbm.get
203
204 key: object
205 default: object = None
206 /
207
208Get the value for key, or default if not present.
209[clinic start generated code]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000210
211static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900212_gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
213/*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000214{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300215 PyObject *res;
Georg Brandld9e833c2010-12-04 09:14:36 +0000216
Dong-hee Nac4862e32020-06-17 01:41:23 +0900217 res = gdbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000218 if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
219 PyErr_Clear();
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300220 Py_INCREF(default_value);
221 return default_value;
Georg Brandld9e833c2010-12-04 09:14:36 +0000222 }
223 return res;
224}
225
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000226static int
Dong-hee Nac4862e32020-06-17 01:41:23 +0900227gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000228{
Fred Drakee3a41c62000-07-08 05:00:07 +0000229 datum krec, drec;
Inada Naokic5a216e2019-03-20 19:01:55 +0900230 const char *failmsg = "gdbm mappings have bytes or string indices only";
Dong-hee Nac4862e32020-06-17 01:41:23 +0900231 _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
Fred Drakee3a41c62000-07-08 05:00:07 +0000232
Inada Naokic5a216e2019-03-20 19:01:55 +0900233 if (!parse_datum(v, &krec, failmsg)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000234 return -1;
235 }
236 if (dp->di_dbm == NULL) {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900237 PyErr_SetString(state->gdbm_error,
Guido van Rossum6252e102007-05-23 20:51:02 +0000238 "GDBM object has already been closed");
239 return -1;
Fred Drakee3a41c62000-07-08 05:00:07 +0000240 }
241 dp->di_size = -1;
242 if (w == NULL) {
243 if (gdbm_delete(dp->di_dbm, krec) < 0) {
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800244 if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
245 PyErr_SetObject(PyExc_KeyError, v);
246 }
247 else {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900248 PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800249 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000250 return -1;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000251 }
Fred Drakee3a41c62000-07-08 05:00:07 +0000252 }
253 else {
Inada Naokic5a216e2019-03-20 19:01:55 +0900254 if (!parse_datum(w, &drec, failmsg)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000255 return -1;
256 }
257 errno = 0;
258 if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
259 if (errno != 0)
Dong-hee Nac4862e32020-06-17 01:41:23 +0900260 PyErr_SetFromErrno(state->gdbm_error);
Fred Drakee3a41c62000-07-08 05:00:07 +0000261 else
Dong-hee Nac4862e32020-06-17 01:41:23 +0900262 PyErr_SetString(state->gdbm_error,
Fred Drakee3a41c62000-07-08 05:00:07 +0000263 gdbm_strerror(gdbm_errno));
264 return -1;
265 }
266 }
267 return 0;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000268}
269
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300270/*[clinic input]
271_gdbm.gdbm.setdefault
272
273 key: object
274 default: object = None
275 /
276
277Get value for key, or set it to default and return default if not present.
278[clinic start generated code]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000279
280static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900281_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300282 PyObject *default_value)
Dong-hee Nac4862e32020-06-17 01:41:23 +0900283/*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
Georg Brandld9e833c2010-12-04 09:14:36 +0000284{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300285 PyObject *res;
Georg Brandld9e833c2010-12-04 09:14:36 +0000286
Dong-hee Nac4862e32020-06-17 01:41:23 +0900287 res = gdbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000288 if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
289 PyErr_Clear();
Dong-hee Nac4862e32020-06-17 01:41:23 +0900290 if (gdbm_ass_sub(self, key, default_value) < 0)
Georg Brandld9e833c2010-12-04 09:14:36 +0000291 return NULL;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900292 return gdbm_subscript(self, key);
Georg Brandld9e833c2010-12-04 09:14:36 +0000293 }
294 return res;
295}
296
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300297/*[clinic input]
298_gdbm.gdbm.close
299
300Close the database.
301[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000302
Roger E. Masseb15bef81996-12-17 19:55:33 +0000303static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900304_gdbm_gdbm_close_impl(gdbmobject *self)
305/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
Guido van Rossum807b7be1995-07-07 22:37:11 +0000306{
Dong-hee Nac4862e32020-06-17 01:41:23 +0900307 if (self->di_dbm) {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300308 gdbm_close(self->di_dbm);
Dong-hee Nac4862e32020-06-17 01:41:23 +0900309 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300310 self->di_dbm = NULL;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200311 Py_RETURN_NONE;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000312}
313
Guido van Rossum6252e102007-05-23 20:51:02 +0000314/* XXX Should return a set or a set view */
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300315/*[clinic input]
316_gdbm.gdbm.keys
317
Dong-hee Nac4862e32020-06-17 01:41:23 +0900318 cls: defining_class
319
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300320Get a list of all keys in the database.
321[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000322
Roger E. Masseb15bef81996-12-17 19:55:33 +0000323static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900324_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
325/*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000326{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200327 PyObject *v, *item;
Fred Drakee3a41c62000-07-08 05:00:07 +0000328 datum key, nextkey;
329 int err;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000330
Dong-hee Nac4862e32020-06-17 01:41:23 +0900331 _gdbm_state *state = PyType_GetModuleState(cls);
332 assert(state != NULL);
333
334 if (self == NULL || !Py_IS_TYPE(self, state->gdbm_type)) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000335 PyErr_BadInternalCall();
336 return NULL;
337 }
Dong-hee Nac4862e32020-06-17 01:41:23 +0900338 check_gdbmobject_open(self, state->gdbm_error);
Guido van Rossum3be71401996-07-21 02:32:44 +0000339
Fred Drakee3a41c62000-07-08 05:00:07 +0000340 v = PyList_New(0);
341 if (v == NULL)
342 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000343
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300344 key = gdbm_firstkey(self->di_dbm);
Fred Drakee3a41c62000-07-08 05:00:07 +0000345 while (key.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000346 item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000347 if (item == NULL) {
348 free(key.dptr);
349 Py_DECREF(v);
350 return NULL;
351 }
352 err = PyList_Append(v, item);
353 Py_DECREF(item);
354 if (err != 0) {
355 free(key.dptr);
356 Py_DECREF(v);
357 return NULL;
358 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300359 nextkey = gdbm_nextkey(self->di_dbm, key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000360 free(key.dptr);
361 key = nextkey;
362 }
363 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000364}
365
Guido van Rossum0da7e032006-08-19 23:18:48 +0000366static int
Dong-hee Nac4862e32020-06-17 01:41:23 +0900367gdbm_contains(PyObject *self, PyObject *arg)
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000368{
Dong-hee Nac4862e32020-06-17 01:41:23 +0900369 gdbmobject *dp = (gdbmobject *)self;
Fred Drakee3a41c62000-07-08 05:00:07 +0000370 datum key;
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300371 Py_ssize_t size;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900372 _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
Fred Drakee3a41c62000-07-08 05:00:07 +0000373
Guido van Rossum0da7e032006-08-19 23:18:48 +0000374 if ((dp)->di_dbm == NULL) {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900375 PyErr_SetString(state->gdbm_error,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000376 "GDBM object has already been closed");
377 return -1;
Guido van Rossum0da7e032006-08-19 23:18:48 +0000378 }
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300379 if (PyUnicode_Check(arg)) {
Serhiy Storchaka2a404b62017-01-22 23:07:07 +0200380 key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300381 key.dsize = size;
382 if (key.dptr == NULL)
383 return -1;
384 }
385 else if (!PyBytes_Check(arg)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 PyErr_Format(PyExc_TypeError,
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300387 "gdbm key must be bytes or string, not %.100s",
Victor Stinnerdaa97562020-02-07 03:37:06 +0100388 Py_TYPE(arg)->tp_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 return -1;
Guido van Rossum0da7e032006-08-19 23:18:48 +0000390 }
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +0300391 else {
392 key.dptr = PyBytes_AS_STRING(arg);
393 key.dsize = PyBytes_GET_SIZE(arg);
394 }
Guido van Rossum0da7e032006-08-19 23:18:48 +0000395 return gdbm_exists(dp->di_dbm, key);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000396}
397
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300398/*[clinic input]
399_gdbm.gdbm.firstkey
400
Dong-hee Nac4862e32020-06-17 01:41:23 +0900401 cls: defining_class
402
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300403Return the starting key for the traversal.
404
405It's possible to loop over every key in the database using this method
406and the nextkey() method. The traversal is ordered by GDBM's internal
407hash values, and won't be sorted by the key values.
408[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000409
Roger E. Masseb15bef81996-12-17 19:55:33 +0000410static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900411_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
412/*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000413{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200414 PyObject *v;
Fred Drakee3a41c62000-07-08 05:00:07 +0000415 datum key;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900416 _gdbm_state *state = PyType_GetModuleState(cls);
417 assert(state != NULL);
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000418
Dong-hee Nac4862e32020-06-17 01:41:23 +0900419 check_gdbmobject_open(self, state->gdbm_error);
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300420 key = gdbm_firstkey(self->di_dbm);
Fred Drakee3a41c62000-07-08 05:00:07 +0000421 if (key.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000422 v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000423 free(key.dptr);
424 return v;
425 }
426 else {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200427 Py_RETURN_NONE;
Fred Drakee3a41c62000-07-08 05:00:07 +0000428 }
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000429}
430
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300431/*[clinic input]
432_gdbm.gdbm.nextkey
433
Dong-hee Nac4862e32020-06-17 01:41:23 +0900434 cls: defining_class
Larry Hastings38337d12015-05-07 23:30:09 -0700435 key: str(accept={str, robuffer}, zeroes=True)
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300436 /
437
438Returns the key that follows key in the traversal.
439
440The following code prints every key in the database db, without having
441to create a list in memory that contains them all:
442
443 k = db.firstkey()
444 while k != None:
445 print(k)
446 k = db.nextkey(k)
447[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000448
Roger E. Masseb15bef81996-12-17 19:55:33 +0000449static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900450_gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300451 Py_ssize_clean_t key_length)
Dong-hee Nac4862e32020-06-17 01:41:23 +0900452/*[clinic end generated code: output=204964441fdbaf02 input=fcf6a51a96ce0172]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000453{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200454 PyObject *v;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300455 datum dbm_key, nextkey;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900456 _gdbm_state *state = PyType_GetModuleState(cls);
457 assert(state != NULL);
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000458
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300459 dbm_key.dptr = (char *)key;
460 dbm_key.dsize = key_length;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900461 check_gdbmobject_open(self, state->gdbm_error);
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300462 nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
Fred Drakee3a41c62000-07-08 05:00:07 +0000463 if (nextkey.dptr) {
Christian Heimes72b710a2008-05-26 13:28:38 +0000464 v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
Fred Drakee3a41c62000-07-08 05:00:07 +0000465 free(nextkey.dptr);
466 return v;
467 }
468 else {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200469 Py_RETURN_NONE;
Fred Drakee3a41c62000-07-08 05:00:07 +0000470 }
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000471}
472
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300473/*[clinic input]
474_gdbm.gdbm.reorganize
475
Dong-hee Nac4862e32020-06-17 01:41:23 +0900476 cls: defining_class
477
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300478Reorganize the database.
479
480If you have carried out a lot of deletions and would like to shrink
481the space used by the GDBM file, this routine will reorganize the
482database. GDBM will not shorten the length of a database file except
483by using this reorganization; otherwise, deleted file space will be
484kept and reused as new (key,value) pairs are added.
485[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000486
Roger E. Masseb15bef81996-12-17 19:55:33 +0000487static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900488_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
489/*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000490{
Dong-hee Nac4862e32020-06-17 01:41:23 +0900491 _gdbm_state *state = PyType_GetModuleState(cls);
492 assert(state != NULL);
493 check_gdbmobject_open(self, state->gdbm_error);
Fred Drakee3a41c62000-07-08 05:00:07 +0000494 errno = 0;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300495 if (gdbm_reorganize(self->di_dbm) < 0) {
Fred Drakee3a41c62000-07-08 05:00:07 +0000496 if (errno != 0)
Dong-hee Nac4862e32020-06-17 01:41:23 +0900497 PyErr_SetFromErrno(state->gdbm_error);
Fred Drakee3a41c62000-07-08 05:00:07 +0000498 else
Dong-hee Nac4862e32020-06-17 01:41:23 +0900499 PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
Fred Drakee3a41c62000-07-08 05:00:07 +0000500 return NULL;
501 }
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200502 Py_RETURN_NONE;
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000503}
504
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300505/*[clinic input]
506_gdbm.gdbm.sync
507
Dong-hee Nac4862e32020-06-17 01:41:23 +0900508 cls: defining_class
509
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300510Flush the database to the disk file.
511
512When the database has been opened in fast mode, this method forces
513any unwritten data to be written to the disk.
514[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000515
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000516static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900517_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
518/*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000519{
Dong-hee Nac4862e32020-06-17 01:41:23 +0900520 _gdbm_state *state = PyType_GetModuleState(cls);
521 assert(state != NULL);
522 check_gdbmobject_open(self, state->gdbm_error);
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300523 gdbm_sync(self->di_dbm);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200524 Py_RETURN_NONE;
Roger E. Massee5a9c8f1997-03-25 17:39:56 +0000525}
526
Nick Coghlanc610aba2013-11-17 15:59:51 +1000527static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900528gdbm__enter__(PyObject *self, PyObject *args)
Nick Coghlanc610aba2013-11-17 15:59:51 +1000529{
530 Py_INCREF(self);
531 return self;
532}
533
534static PyObject *
Dong-hee Nac4862e32020-06-17 01:41:23 +0900535gdbm__exit__(PyObject *self, PyObject *args)
Nick Coghlanc610aba2013-11-17 15:59:51 +1000536{
537 _Py_IDENTIFIER(close);
Jeroen Demeyer762f93f2019-07-08 10:19:25 +0200538 return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
Nick Coghlanc610aba2013-11-17 15:59:51 +1000539}
540
Dong-hee Nac4862e32020-06-17 01:41:23 +0900541static PyMethodDef gdbm_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300542 _GDBM_GDBM_CLOSE_METHODDEF
543 _GDBM_GDBM_KEYS_METHODDEF
544 _GDBM_GDBM_FIRSTKEY_METHODDEF
545 _GDBM_GDBM_NEXTKEY_METHODDEF
546 _GDBM_GDBM_REORGANIZE_METHODDEF
547 _GDBM_GDBM_SYNC_METHODDEF
548 _GDBM_GDBM_GET_METHODDEF
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300549 _GDBM_GDBM_SETDEFAULT_METHODDEF
Dong-hee Nac4862e32020-06-17 01:41:23 +0900550 {"__enter__", gdbm__enter__, METH_NOARGS, NULL},
551 {"__exit__", gdbm__exit__, METH_VARARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000552 {NULL, NULL} /* sentinel */
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000553};
554
Dong-hee Nac4862e32020-06-17 01:41:23 +0900555static PyType_Slot gdbmtype_spec_slots[] = {
556 {Py_tp_dealloc, gdbm_dealloc},
557 {Py_tp_methods, gdbm_methods},
558 {Py_sq_contains, gdbm_contains},
559 {Py_mp_length, gdbm_length},
560 {Py_mp_subscript, gdbm_subscript},
561 {Py_mp_ass_subscript, gdbm_ass_sub},
562 {Py_tp_doc, (char*)gdbm_object__doc__},
563 {0, 0}
564};
565
566static PyType_Spec gdbmtype_spec = {
567 .name = "_gdbm.gdbm",
568 .basicsize = sizeof(gdbmobject),
569 // Calling PyType_GetModuleState() on a subclass is not safe.
570 // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
571 // which prevents to create a subclass.
572 // So calling PyType_GetModuleState() in this file is always safe.
573 .flags = Py_TPFLAGS_DEFAULT,
574 .slots = gdbmtype_spec_slots,
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000575};
576
577/* ----------------------------------------------------------------- */
578
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300579/*[clinic input]
580_gdbm.open as dbmopen
Dong-hee Nac4862e32020-06-17 01:41:23 +0900581
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200582 filename: unicode
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300583 flags: str="r"
584 mode: int(py_default="0o666") = 0o666
585 /
586
587Open a dbm database and return a dbm object.
588
589The filename argument is the name of the database file.
590
591The optional flags argument can be 'r' (to open an existing database
592for reading only -- default), 'w' (to open an existing database for
593reading and writing), 'c' (which creates the database if it doesn't
594exist), or 'n' (which always creates a new empty database).
595
596Some versions of gdbm support additional flags which must be
597appended to one of the flags described above. The module constant
598'open_flags' is a string of valid additional flags. The 'f' flag
599opens the database in fast mode; altered data will not automatically
600be written to the disk after every change. This results in faster
601writes to the database, but may result in an inconsistent database
602if the program crashes while the database is still open. Use the
603sync() method to force any unwritten data to be written to the disk.
604The 's' flag causes all database operations to be synchronized to
605disk. The 'u' flag disables locking of the database file.
606
607The optional mode argument is the Unix mode of the file, used only
608when the database has to be created. It defaults to octal 0o666.
609[clinic start generated code]*/
Guido van Rossumbfc49e81998-03-03 22:02:24 +0000610
Roger E. Masseb15bef81996-12-17 19:55:33 +0000611static PyObject *
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200612dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
613 int mode)
Dong-hee Nac4862e32020-06-17 01:41:23 +0900614/*[clinic end generated code: output=9527750f5df90764 input=812b7d74399ceb0e]*/
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000615{
Fred Drakee3a41c62000-07-08 05:00:07 +0000616 int iflags;
Dong-hee Nac4862e32020-06-17 01:41:23 +0900617 _gdbm_state *state = get_gdbm_state(module);
618 assert(state != NULL);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000619
Fred Drakee3a41c62000-07-08 05:00:07 +0000620 switch (flags[0]) {
621 case 'r':
622 iflags = GDBM_READER;
623 break;
624 case 'w':
625 iflags = GDBM_WRITER;
626 break;
627 case 'c':
628 iflags = GDBM_WRCREAT;
629 break;
630 case 'n':
631 iflags = GDBM_NEWDB;
632 break;
633 default:
Dong-hee Nac4862e32020-06-17 01:41:23 +0900634 PyErr_SetString(state->gdbm_error,
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000635 "First flag must be one of 'r', 'w', 'c' or 'n'");
Fred Drakee3a41c62000-07-08 05:00:07 +0000636 return NULL;
637 }
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000638 for (flags++; *flags != '\0'; flags++) {
639 char buf[40];
640 switch (*flags) {
641#ifdef GDBM_FAST
642 case 'f':
643 iflags |= GDBM_FAST;
644 break;
645#endif
646#ifdef GDBM_SYNC
647 case 's':
648 iflags |= GDBM_SYNC;
649 break;
650#endif
651#ifdef GDBM_NOLOCK
652 case 'u':
653 iflags |= GDBM_NOLOCK;
654 break;
655#endif
656 default:
Tim Peters885d4572001-11-28 20:27:42 +0000657 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000658 *flags);
Dong-hee Nac4862e32020-06-17 01:41:23 +0900659 PyErr_SetString(state->gdbm_error, buf);
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000660 return NULL;
661 }
662 }
663
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200664 PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
665 if (filenamebytes == NULL) {
666 return NULL;
667 }
668 const char *name = PyBytes_AS_STRING(filenamebytes);
669 if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
670 Py_DECREF(filenamebytes);
671 PyErr_SetString(PyExc_ValueError, "embedded null character");
672 return NULL;
673 }
Dong-hee Nac4862e32020-06-17 01:41:23 +0900674 PyObject *self = newgdbmobject(state, name, iflags, mode);
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200675 Py_DECREF(filenamebytes);
676 return self;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000677}
678
Dong-hee Nac4862e32020-06-17 01:41:23 +0900679static const char gdbmmodule_open_flags[] = "rwcn"
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000680#ifdef GDBM_FAST
681 "f"
682#endif
683#ifdef GDBM_SYNC
684 "s"
685#endif
686#ifdef GDBM_NOLOCK
687 "u"
688#endif
689 ;
690
Dong-hee Nac4862e32020-06-17 01:41:23 +0900691static PyMethodDef _gdbm_module_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300692 DBMOPEN_METHODDEF
Fred Drakee3a41c62000-07-08 05:00:07 +0000693 { 0, 0 },
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000694};
695
Dong-hee Nac4862e32020-06-17 01:41:23 +0900696static int
697_gdbm_exec(PyObject *module)
698{
699 _gdbm_state *state = get_gdbm_state(module);
700 state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
701 &gdbmtype_spec, NULL);
702 if (state->gdbm_type == NULL) {
703 return -1;
Neil Schemenauere9e860f2000-12-17 07:14:13 +0000704 }
Dong-hee Nac4862e32020-06-17 01:41:23 +0900705 state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
706 if (state->gdbm_error == NULL) {
707 return -1;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200708 }
Dong-hee Nac4862e32020-06-17 01:41:23 +0900709 if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
710 return -1;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200711 }
Dong-hee Nac4862e32020-06-17 01:41:23 +0900712 if (PyModule_AddStringConstant(module, "open_flags",
713 gdbmmodule_open_flags) < 0) {
714 return -1;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200715 }
716
Xiang Zhangb248e952018-06-20 21:23:30 +0800717#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
718 defined(GDBM_VERSION_PATCH)
Victor Stinner00f9edb2018-06-19 23:29:22 +0200719 PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
720 GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
721 if (obj == NULL) {
Dong-hee Nac4862e32020-06-17 01:41:23 +0900722 return -1;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200723 }
Dong-hee Nac4862e32020-06-17 01:41:23 +0900724 if (PyModule_AddObject(module, "_GDBM_VERSION", obj) < 0) {
Victor Stinner00f9edb2018-06-19 23:29:22 +0200725 Py_DECREF(obj);
Dong-hee Nac4862e32020-06-17 01:41:23 +0900726 return -1;
Victor Stinner00f9edb2018-06-19 23:29:22 +0200727 }
Xiang Zhangb248e952018-06-20 21:23:30 +0800728#endif
Dong-hee Nac4862e32020-06-17 01:41:23 +0900729 return 0;
730}
Victor Stinner00f9edb2018-06-19 23:29:22 +0200731
Dong-hee Nac4862e32020-06-17 01:41:23 +0900732static int
733_gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
734{
735 _gdbm_state *state = get_gdbm_state(module);
736 Py_VISIT(state->gdbm_error);
737 Py_VISIT(state->gdbm_type);
738 return 0;
739}
Victor Stinner00f9edb2018-06-19 23:29:22 +0200740
Dong-hee Nac4862e32020-06-17 01:41:23 +0900741static int
742_gdbm_module_clear(PyObject *module)
743{
744 _gdbm_state *state = get_gdbm_state(module);
745 Py_CLEAR(state->gdbm_error);
746 Py_CLEAR(state->gdbm_type);
747 return 0;
748}
749
750static void
751_gdbm_module_free(void *module)
752{
753 _gdbm_module_clear((PyObject *)module);
754}
755
756static PyModuleDef_Slot _gdbm_module_slots[] = {
757 {Py_mod_exec, _gdbm_exec},
758 {0, NULL}
759};
760
761static struct PyModuleDef _gdbmmodule = {
762 PyModuleDef_HEAD_INIT,
763 .m_name = "_gdbm",
764 .m_doc = gdbmmodule__doc__,
765 .m_size = sizeof(_gdbm_state),
766 .m_methods = _gdbm_module_methods,
767 .m_slots = _gdbm_module_slots,
768 .m_traverse = _gdbm_module_traverse,
769 .m_clear = _gdbm_module_clear,
770 .m_free = _gdbm_module_free,
771};
772
773PyMODINIT_FUNC
774PyInit__gdbm(void)
775{
776 return PyModuleDef_Init(&_gdbmmodule);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000777}