blob: 97772a04d08fe08d587d1f8ed5603d9dcde3a451 [file] [log] [blame]
Guido van Rossumdd9ed831992-06-29 17:10:40 +00001
2/* DBM module using dictionary interface */
3
4
Mark Dickinsonfdaa3a32009-01-16 19:31:13 +00005#define PY_SSIZE_T_CLEAN
Roger E. Masseb0dfe961996-12-10 00:07:00 +00006#include "Python.h"
Guido van Rossumdd9ed831992-06-29 17:10:40 +00007
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
Fred Draked94f7072000-09-14 15:48:06 +000011
12/* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports
13 * whichever configure was able to locate.
14 */
15#if defined(HAVE_NDBM_H)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000016#include <ndbm.h>
Serhiy Storchaka2d06e842015-12-25 19:53:18 +020017static const char which_dbm[] = "GNU gdbm"; /* EMX port of GDBM */
Fred Draked94f7072000-09-14 15:48:06 +000018#elif defined(HAVE_GDBM_NDBM_H)
19#include <gdbm/ndbm.h>
Serhiy Storchaka2d06e842015-12-25 19:53:18 +020020static const char which_dbm[] = "GNU gdbm";
Skip Montanaroc1ce2862008-12-06 17:25:02 +000021#elif defined(HAVE_GDBM_DASH_NDBM_H)
22#include <gdbm-ndbm.h>
Serhiy Storchaka2d06e842015-12-25 19:53:18 +020023static const char which_dbm[] = "GNU gdbm";
Skip Montanaro71ffc5c2002-08-02 17:13:01 +000024#elif defined(HAVE_BERKDB_H)
25#include <db.h>
Serhiy Storchaka2d06e842015-12-25 19:53:18 +020026static const char which_dbm[] = "Berkeley DB";
Fred Draked94f7072000-09-14 15:48:06 +000027#else
28#error "No ndbm.h available!"
29#endif
Guido van Rossumdd9ed831992-06-29 17:10:40 +000030
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090031typedef struct {
32 PyTypeObject *dbm_type;
33 PyObject *dbm_error;
34} _dbm_state;
35
36static inline _dbm_state*
37get_dbm_state(PyObject *module)
38{
39 void *state = PyModule_GetState(module);
40 assert(state != NULL);
41 return (_dbm_state *)state;
42}
43
Larry Hastings61272b72014-01-07 12:41:53 -080044/*[clinic input]
Serhiy Storchaka9260e772015-04-17 21:05:18 +030045module _dbm
46class _dbm.dbm "dbmobject *" "&Dbmtype"
Larry Hastings61272b72014-01-07 12:41:53 -080047[clinic start generated code]*/
Serhiy Storchaka9260e772015-04-17 21:05:18 +030048/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9b1aa8756d16150e]*/
Larry Hastings44e2eaa2013-11-23 15:37:55 -080049
Guido van Rossumdd9ed831992-06-29 17:10:40 +000050typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000051 PyObject_HEAD
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +080052 int flags;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000053 int di_size; /* -1 means recompute */
54 DBM *di_dbm;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000055} dbmobject;
56
Serhiy Storchaka1009bf12015-04-03 23:53:51 +030057#include "clinic/_dbmmodule.c.h"
58
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090059#define check_dbmobject_open(v, err) \
60 if ((v)->di_dbm == NULL) { \
61 PyErr_SetString(err, "DBM object has already been closed"); \
62 return NULL; \
63 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +000064
Roger E. Masseb0dfe961996-12-10 00:07:00 +000065static PyObject *
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090066newdbmobject(_dbm_state *state, const char *file, int flags, int mode)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000067{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 dbmobject *dp;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000069
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090070 dp = PyObject_New(dbmobject, state->dbm_type);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 if (dp == NULL)
72 return NULL;
73 dp->di_size = -1;
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +080074 dp->flags = flags;
Christian Heimes8ff6f3e2013-12-06 00:20:00 +010075 /* See issue #19296 */
76 if ( (dp->di_dbm = dbm_open((char *)file, flags, mode)) == 0 ) {
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090077 PyErr_SetFromErrnoWithFilename(state->dbm_error, file);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 Py_DECREF(dp);
79 return NULL;
80 }
81 return (PyObject *)dp;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000082}
83
84/* Methods */
85
86static void
Antoine Pitrou9ed5f272013-08-13 20:18:52 +020087dbm_dealloc(dbmobject *dp)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000088{
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090089 if (dp->di_dbm) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 dbm_close(dp->di_dbm);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +090091 }
92 PyTypeObject *tp = Py_TYPE(dp);
93 tp->tp_free(dp);
94 Py_DECREF(tp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000095}
96
Martin v. Löwis18e16552006-02-15 17:27:45 +000097static Py_ssize_t
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000098dbm_length(dbmobject *dp)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000099{
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900100 _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
101 assert(state != NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 if (dp->di_dbm == NULL) {
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900103 PyErr_SetString(state->dbm_error, "DBM object has already been closed");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 return -1;
105 }
106 if ( dp->di_size < 0 ) {
107 datum key;
108 int size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000109
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 size = 0;
111 for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
112 key = dbm_nextkey(dp->di_dbm))
113 size++;
114 dp->di_size = size;
115 }
116 return dp->di_size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000117}
118
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000119static PyObject *
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200120dbm_subscript(dbmobject *dp, PyObject *key)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000121{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000122 datum drec, krec;
123 Py_ssize_t tmp_size;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900124 _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
125 assert(state != NULL);
126 if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 return NULL;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900128 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129
130 krec.dsize = tmp_size;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900131 check_dbmobject_open(dp, state->dbm_error);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 drec = dbm_fetch(dp->di_dbm, krec);
133 if ( drec.dptr == 0 ) {
134 PyErr_SetObject(PyExc_KeyError, key);
135 return NULL;
136 }
137 if ( dbm_error(dp->di_dbm) ) {
138 dbm_clearerr(dp->di_dbm);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900139 PyErr_SetString(state->dbm_error, "");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000140 return NULL;
141 }
142 return PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000143}
144
145static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000146dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000147{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000148 datum krec, drec;
149 Py_ssize_t tmp_size;
150
151 if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
152 PyErr_SetString(PyExc_TypeError,
153 "dbm mappings have bytes or string keys only");
154 return -1;
155 }
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900156 _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
157 assert(state != NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 krec.dsize = tmp_size;
159 if (dp->di_dbm == NULL) {
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900160 PyErr_SetString(state->dbm_error, "DBM object has already been closed");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000161 return -1;
162 }
163 dp->di_size = -1;
164 if (w == NULL) {
165 if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
166 dbm_clearerr(dp->di_dbm);
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800167 /* we might get a failure for reasons like file corrupted,
168 but we are not able to distinguish it */
169 if (dp->flags & O_RDWR) {
170 PyErr_SetObject(PyExc_KeyError, v);
171 }
172 else {
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900173 PyErr_SetString(state->dbm_error, "cannot delete item from database");
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800174 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 return -1;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000176 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 } else {
178 if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
179 PyErr_SetString(PyExc_TypeError,
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800180 "dbm mappings have bytes or string elements only");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 return -1;
182 }
183 drec.dsize = tmp_size;
184 if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
185 dbm_clearerr(dp->di_dbm);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900186 PyErr_SetString(state->dbm_error,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 "cannot add item to database");
188 return -1;
189 }
190 }
191 if ( dbm_error(dp->di_dbm) ) {
192 dbm_clearerr(dp->di_dbm);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900193 PyErr_SetString(state->dbm_error, "");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194 return -1;
195 }
196 return 0;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000197}
198
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300199/*[clinic input]
200_dbm.dbm.close
201
202Close the database.
203[clinic start generated code]*/
204
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000205static PyObject *
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300206_dbm_dbm_close_impl(dbmobject *self)
207/*[clinic end generated code: output=c8dc5b6709600b86 input=046db72377d51be8]*/
Guido van Rossum807b7be1995-07-07 22:37:11 +0000208{
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900209 if (self->di_dbm) {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300210 dbm_close(self->di_dbm);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900211 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300212 self->di_dbm = NULL;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200213 Py_RETURN_NONE;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000214}
215
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300216/*[clinic input]
217_dbm.dbm.keys
218
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900219 cls: defining_class
220
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300221Return a list of all keys in the database.
222[clinic start generated code]*/
223
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000224static PyObject *
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900225_dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls)
226/*[clinic end generated code: output=f2a593b3038e5996 input=d3706a28fc051097]*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000227{
Antoine Pitrou9ed5f272013-08-13 20:18:52 +0200228 PyObject *v, *item;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000229 datum key;
230 int err;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000231
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900232 _dbm_state *state = PyType_GetModuleState(cls);
233 assert(state != NULL);
234 check_dbmobject_open(self, state->dbm_error);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 v = PyList_New(0);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900236 if (v == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 return NULL;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900238 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300239 for (key = dbm_firstkey(self->di_dbm); key.dptr;
240 key = dbm_nextkey(self->di_dbm)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
242 if (item == NULL) {
243 Py_DECREF(v);
244 return NULL;
245 }
246 err = PyList_Append(v, item);
247 Py_DECREF(item);
248 if (err != 0) {
249 Py_DECREF(v);
250 return NULL;
251 }
252 }
253 return v;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000254}
255
Guido van Rossumef671112006-08-19 23:11:47 +0000256static int
257dbm_contains(PyObject *self, PyObject *arg)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000258{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 dbmobject *dp = (dbmobject *)self;
260 datum key, val;
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200261 Py_ssize_t size;
Guido van Rossumef671112006-08-19 23:11:47 +0000262
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900263 _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
264 assert(state != NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000265 if ((dp)->di_dbm == NULL) {
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900266 PyErr_SetString(state->dbm_error,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 "DBM object has already been closed");
268 return -1;
269 }
270 if (PyUnicode_Check(arg)) {
Serhiy Storchaka2a404b62017-01-22 23:07:07 +0200271 key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200272 key.dsize = size;
273 if (key.dptr == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 return -1;
275 }
Serhiy Storchaka9da33ab2013-10-24 23:59:28 +0300276 else if (!PyBytes_Check(arg)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 PyErr_Format(PyExc_TypeError,
Serhiy Storchaka9da33ab2013-10-24 23:59:28 +0300278 "dbm key must be bytes or string, not %.100s",
Victor Stinnerdaa97562020-02-07 03:37:06 +0100279 Py_TYPE(arg)->tp_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 return -1;
281 }
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200282 else {
283 key.dptr = PyBytes_AS_STRING(arg);
284 key.dsize = PyBytes_GET_SIZE(arg);
285 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 val = dbm_fetch(dp->di_dbm, key);
287 return val.dptr != NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000288}
289
Larry Hastings61272b72014-01-07 12:41:53 -0800290/*[clinic input]
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300291_dbm.dbm.get
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900292 cls: defining_class
Larry Hastings38337d12015-05-07 23:30:09 -0700293 key: str(accept={str, robuffer}, zeroes=True)
Serhiy Storchaka2e38cc32018-04-29 12:38:06 +0300294 default: object = None
Larry Hastingsebdcb502013-11-23 14:54:00 -0800295 /
296
297Return the value for key if present, otherwise default.
Larry Hastings61272b72014-01-07 12:41:53 -0800298[clinic start generated code]*/
Larry Hastingsebdcb502013-11-23 14:54:00 -0800299
Larry Hastingsebdcb502013-11-23 14:54:00 -0800300static PyObject *
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900301_dbm_dbm_get_impl(dbmobject *self, PyTypeObject *cls, const char *key,
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300302 Py_ssize_clean_t key_length, PyObject *default_value)
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900303/*[clinic end generated code: output=34851b5dc1c664dc input=66b993b8349fa8c1]*/
Larry Hastingsebdcb502013-11-23 14:54:00 -0800304{
305 datum dbm_key, val;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900306 _dbm_state *state = PyType_GetModuleState(cls);
307 assert(state != NULL);
Larry Hastingsebdcb502013-11-23 14:54:00 -0800308 dbm_key.dptr = (char *)key;
309 dbm_key.dsize = key_length;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900310 check_dbmobject_open(self, state->dbm_error);
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300311 val = dbm_fetch(self->di_dbm, dbm_key);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900312 if (val.dptr != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000313 return PyBytes_FromStringAndSize(val.dptr, val.dsize);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900314 }
Larry Hastingsebdcb502013-11-23 14:54:00 -0800315
316 Py_INCREF(default_value);
317 return default_value;
Fred Drake1ac526d2000-09-15 21:35:14 +0000318}
319
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300320/*[clinic input]
321_dbm.dbm.setdefault
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900322 cls: defining_class
Larry Hastings38337d12015-05-07 23:30:09 -0700323 key: str(accept={str, robuffer}, zeroes=True)
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300324 default: object(c_default="NULL") = b''
325 /
326
327Return the value for key if present, otherwise default.
328
329If key is not in the database, it is inserted with default as the value.
330[clinic start generated code]*/
331
Fred Drake1ac526d2000-09-15 21:35:14 +0000332static PyObject *
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900333_dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key,
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300334 Py_ssize_clean_t key_length,
335 PyObject *default_value)
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900336/*[clinic end generated code: output=d5c68fe673886767 input=126a3ff15c5f8232]*/
Fred Drake1ac526d2000-09-15 21:35:14 +0000337{
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300338 datum dbm_key, val;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 Py_ssize_t tmp_size;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900340 _dbm_state *state = PyType_GetModuleState(cls);
341 assert(state != NULL);
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300342 dbm_key.dptr = (char *)key;
343 dbm_key.dsize = key_length;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900344 check_dbmobject_open(self, state->dbm_error);
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300345 val = dbm_fetch(self->di_dbm, dbm_key);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900346 if (val.dptr != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 return PyBytes_FromStringAndSize(val.dptr, val.dsize);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900348 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300349 if (default_value == NULL) {
350 default_value = PyBytes_FromStringAndSize(NULL, 0);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900351 if (default_value == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 return NULL;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900353 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 val.dptr = NULL;
355 val.dsize = 0;
356 }
357 else {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300358 if ( !PyArg_Parse(default_value, "s#", &val.dptr, &tmp_size) ) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 PyErr_SetString(PyExc_TypeError,
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800360 "dbm mappings have bytes or string elements only");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000361 return NULL;
362 }
363 val.dsize = tmp_size;
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300364 Py_INCREF(default_value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300366 if (dbm_store(self->di_dbm, dbm_key, val, DBM_INSERT) < 0) {
367 dbm_clearerr(self->di_dbm);
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900368 PyErr_SetString(state->dbm_error, "cannot add item to database");
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300369 Py_DECREF(default_value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 return NULL;
371 }
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300372 return default_value;
Fred Drake1ac526d2000-09-15 21:35:14 +0000373}
374
Nick Coghlanc610aba2013-11-17 15:59:51 +1000375static PyObject *
376dbm__enter__(PyObject *self, PyObject *args)
377{
378 Py_INCREF(self);
379 return self;
380}
381
382static PyObject *
383dbm__exit__(PyObject *self, PyObject *args)
384{
385 _Py_IDENTIFIER(close);
Jeroen Demeyer762f93f2019-07-08 10:19:25 +0200386 return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
Nick Coghlanc610aba2013-11-17 15:59:51 +1000387}
388
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000389static PyMethodDef dbm_methods[] = {
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300390 _DBM_DBM_CLOSE_METHODDEF
391 _DBM_DBM_KEYS_METHODDEF
392 _DBM_DBM_GET_METHODDEF
393 _DBM_DBM_SETDEFAULT_METHODDEF
Nick Coghlanc610aba2013-11-17 15:59:51 +1000394 {"__enter__", dbm__enter__, METH_NOARGS, NULL},
395 {"__exit__", dbm__exit__, METH_VARARGS, NULL},
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900396 {NULL, NULL} /* sentinel */
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000397};
398
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900399static PyType_Slot dbmtype_spec_slots[] = {
400 {Py_tp_dealloc, dbm_dealloc},
401 {Py_tp_methods, dbm_methods},
402 {Py_sq_contains, dbm_contains},
403 {Py_mp_length, dbm_length},
404 {Py_mp_subscript, dbm_subscript},
405 {Py_mp_ass_subscript, dbm_ass_sub},
406 {0, 0}
407};
408
409
410static PyType_Spec dbmtype_spec = {
411 .name = "_dbm.dbm",
412 .basicsize = sizeof(dbmobject),
413 // Calling PyType_GetModuleState() on a subclass is not safe.
414 // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
415 // which prevents to create a subclass.
416 // So calling PyType_GetModuleState() in this file is always safe.
417 .flags = Py_TPFLAGS_DEFAULT,
418 .slots = dbmtype_spec_slots,
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000419};
420
421/* ----------------------------------------------------------------- */
422
Larry Hastings61272b72014-01-07 12:41:53 -0800423/*[clinic input]
Larry Hastings31826802013-10-19 00:09:25 -0700424
Serhiy Storchaka9260e772015-04-17 21:05:18 +0300425_dbm.open as dbmopen
Larry Hastings31826802013-10-19 00:09:25 -0700426
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200427 filename: unicode
Larry Hastings31826802013-10-19 00:09:25 -0700428 The filename to open.
429
430 flags: str="r"
431 How to open the file. "r" for reading, "w" for writing, etc.
432
Larry Hastings2a727912014-01-16 11:32:01 -0800433 mode: int(py_default="0o666") = 0o666
Larry Hastings31826802013-10-19 00:09:25 -0700434 If creating a new file, the mode bits for the new file
435 (e.g. os.O_RDWR).
436
437 /
438
439Return a database object.
440
Larry Hastings61272b72014-01-07 12:41:53 -0800441[clinic start generated code]*/
Larry Hastings31826802013-10-19 00:09:25 -0700442
Larry Hastings31826802013-10-19 00:09:25 -0700443static PyObject *
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200444dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
Larry Hastings89964c42015-04-14 18:07:59 -0400445 int mode)
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200446/*[clinic end generated code: output=9527750f5df90764 input=376a9d903a50df59]*/
Larry Hastings31826802013-10-19 00:09:25 -0700447{
448 int iflags;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900449 _dbm_state *state = get_dbm_state(module);
450 assert(state != NULL);
451 if (strcmp(flags, "r") == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 iflags = O_RDONLY;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900453 }
454 else if (strcmp(flags, "w") == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000455 iflags = O_RDWR;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900456 }
457 else if (strcmp(flags, "rw") == 0) {
458 /* Backward compatibility */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000459 iflags = O_RDWR|O_CREAT;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900460 }
461 else if (strcmp(flags, "c") == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 iflags = O_RDWR|O_CREAT;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900463 }
464 else if (strcmp(flags, "n") == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 iflags = O_RDWR|O_CREAT|O_TRUNC;
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900466 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000467 else {
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900468 PyErr_SetString(state->dbm_error,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000469 "arg 2 to open should be 'r', 'w', 'c', or 'n'");
470 return NULL;
471 }
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200472
473 PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
474 if (filenamebytes == NULL) {
475 return NULL;
476 }
477 const char *name = PyBytes_AS_STRING(filenamebytes);
478 if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
479 Py_DECREF(filenamebytes);
480 PyErr_SetString(PyExc_ValueError, "embedded null character");
481 return NULL;
482 }
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900483 PyObject *self = newdbmobject(state, name, iflags, mode);
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200484 Py_DECREF(filenamebytes);
485 return self;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000486}
487
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000488static PyMethodDef dbmmodule_methods[] = {
Larry Hastings31826802013-10-19 00:09:25 -0700489 DBMOPEN_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000490 { 0, 0 },
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000491};
492
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900493static int
494_dbm_exec(PyObject *module)
495{
496 _dbm_state *state = get_dbm_state(module);
497 state->dbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
498 &dbmtype_spec, NULL);
499 if (state->dbm_type == NULL) {
500 return -1;
501 }
502 state->dbm_error = PyErr_NewException("_dbm.error", PyExc_OSError, NULL);
503 if (state->dbm_error == NULL) {
504 return -1;
505 }
506 if (PyModule_AddStringConstant(module, "library", which_dbm) < 0) {
507 return -1;
508 }
509 if (PyModule_AddType(module, (PyTypeObject *)state->dbm_error) < 0) {
510 return -1;
511 }
512 return 0;
513}
514
515static int
516_dbm_module_traverse(PyObject *module, visitproc visit, void *arg)
517{
518 _dbm_state *state = get_dbm_state(module);
519 Py_VISIT(state->dbm_error);
520 Py_VISIT(state->dbm_type);
521 return 0;
522}
523
524static int
525_dbm_module_clear(PyObject *module)
526{
527 _dbm_state *state = get_dbm_state(module);
528 Py_CLEAR(state->dbm_error);
529 Py_CLEAR(state->dbm_type);
530 return 0;
531}
532
533static void
534_dbm_module_free(void *module)
535{
536 _dbm_module_clear((PyObject *)module);
537}
538
539static PyModuleDef_Slot _dbmmodule_slots[] = {
540 {Py_mod_exec, _dbm_exec},
541 {0, NULL}
542};
Martin v. Löwis1a214512008-06-11 05:26:20 +0000543
544static struct PyModuleDef _dbmmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000545 PyModuleDef_HEAD_INIT,
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900546 .m_name = "_dbm",
547 .m_size = sizeof(_dbm_state),
548 .m_methods = dbmmodule_methods,
549 .m_slots = _dbmmodule_slots,
550 .m_traverse = _dbm_module_traverse,
551 .m_clear = _dbm_module_clear,
552 .m_free = _dbm_module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +0000553};
554
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000555PyMODINIT_FUNC
Dong-hee Nabf69a8f2020-06-16 01:20:54 +0900556PyInit__dbm(void)
557{
558 return PyModuleDef_Init(&_dbmmodule);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000559}