Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Python interface to tdb.
5 :
6 : Copyright (C) 2004-2006 Tim Potter <tpot@samba.org>
7 : Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
8 :
9 : ** NOTE! The following LGPL license applies to the tdb
10 : ** library. This does NOT imply that all of Samba is released
11 : ** under the LGPL
12 :
13 : This library is free software; you can redistribute it and/or
14 : modify it under the terms of the GNU Lesser General Public
15 : License as published by the Free Software Foundation; either
16 : version 3 of the License, or (at your option) any later version.
17 :
18 : This library is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 : Lesser General Public License for more details.
22 :
23 : You should have received a copy of the GNU Lesser General Public
24 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 : */
26 :
27 : #include <Python.h>
28 : #include "replace.h"
29 : #include "system/filesys.h"
30 :
31 : /* Include tdb headers */
32 : #include <tdb.h>
33 :
34 : #if PY_MAJOR_VERSION >= 3
35 : #define Py_TPFLAGS_HAVE_ITER 0
36 : #endif
37 :
38 : /* discard signature of 'func' in favour of 'target_sig' */
39 : #define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
40 :
41 : typedef struct {
42 : PyObject_HEAD
43 : TDB_CONTEXT *ctx;
44 : bool closed;
45 : } PyTdbObject;
46 :
47 : static PyTypeObject PyTdb;
48 :
49 0 : static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
50 : {
51 0 : PyErr_SetObject(PyExc_RuntimeError,
52 0 : Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb)));
53 0 : }
54 :
55 97 : static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data)
56 : {
57 : TDB_DATA ret;
58 97 : ret.dptr = (unsigned char *)PyBytes_AsString(data);
59 97 : ret.dsize = PyBytes_Size(data);
60 97 : return ret;
61 : }
62 :
63 29 : static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data)
64 : {
65 29 : if (data.dptr == NULL && data.dsize == 0) {
66 2 : Py_RETURN_NONE;
67 : } else {
68 27 : PyObject *ret = PyBytes_FromStringAndSize((const char *)data.dptr,
69 27 : data.dsize);
70 27 : free(data.dptr);
71 27 : return ret;
72 : }
73 : }
74 :
75 : #define PyErr_TDB_ERROR_IS_ERR_RAISE(ret, tdb) \
76 : if (ret != 0) { \
77 : PyErr_SetTDBError(tdb); \
78 : return NULL; \
79 : }
80 :
81 : #define PyErr_TDB_RAISE_IF_CLOSED(self) \
82 : if (self->closed) { \
83 : PyErr_SetObject(PyExc_RuntimeError, \
84 : Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
85 : return NULL; \
86 : }
87 :
88 : #define PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self) \
89 : if (self->closed) { \
90 : PyErr_SetObject(PyExc_RuntimeError, \
91 : Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
92 : return -1; \
93 : }
94 :
95 65 : static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
96 : {
97 65 : char *name = NULL;
98 65 : int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600;
99 : TDB_CONTEXT *ctx;
100 : PyTdbObject *ret;
101 65 : const char *_kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
102 65 : char **kwnames = discard_const_p(char *, _kwnames);
103 :
104 65 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
105 0 : return NULL;
106 :
107 65 : if (name == NULL) {
108 1 : tdb_flags |= TDB_INTERNAL;
109 : }
110 :
111 65 : ctx = tdb_open(name, hash_size, tdb_flags, flags, mode);
112 65 : if (ctx == NULL) {
113 10 : PyErr_SetFromErrno(PyExc_IOError);
114 10 : return NULL;
115 : }
116 :
117 55 : ret = PyObject_New(PyTdbObject, &PyTdb);
118 55 : if (!ret) {
119 0 : tdb_close(ctx);
120 0 : return NULL;
121 : }
122 :
123 55 : ret->ctx = ctx;
124 55 : ret->closed = false;
125 55 : return (PyObject *)ret;
126 : }
127 :
128 2 : static PyObject *obj_transaction_cancel(PyTdbObject *self,
129 : PyObject *Py_UNUSED(ignored))
130 : {
131 : int ret;
132 :
133 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
134 :
135 2 : ret = tdb_transaction_cancel(self->ctx);
136 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
137 2 : Py_RETURN_NONE;
138 : }
139 :
140 4 : static PyObject *obj_transaction_commit(PyTdbObject *self,
141 : PyObject *Py_UNUSED(ignored))
142 : {
143 : int ret;
144 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
145 4 : ret = tdb_transaction_commit(self->ctx);
146 4 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
147 4 : Py_RETURN_NONE;
148 : }
149 :
150 2 : static PyObject *obj_transaction_prepare_commit(PyTdbObject *self,
151 : PyObject *Py_UNUSED(ignored))
152 : {
153 : int ret;
154 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
155 2 : ret = tdb_transaction_prepare_commit(self->ctx);
156 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
157 2 : Py_RETURN_NONE;
158 : }
159 :
160 7 : static PyObject *obj_transaction_start(PyTdbObject *self,
161 : PyObject *Py_UNUSED(ignored))
162 : {
163 : int ret;
164 7 : PyErr_TDB_RAISE_IF_CLOSED(self);
165 6 : ret = tdb_transaction_start(self->ctx);
166 6 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
167 6 : Py_RETURN_NONE;
168 : }
169 :
170 4 : static PyObject *obj_reopen(PyTdbObject *self,
171 : PyObject *Py_UNUSED(ignored))
172 : {
173 : int ret;
174 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
175 4 : ret = tdb_reopen(self->ctx);
176 4 : if (ret != 0) {
177 0 : self->closed = true;
178 0 : PyErr_SetObject(PyExc_RuntimeError,
179 : Py_BuildValue("(i,s)",
180 : TDB_ERR_IO,
181 : "Failed to reopen database"));
182 0 : return NULL;
183 : }
184 4 : Py_RETURN_NONE;
185 : }
186 :
187 4 : static PyObject *obj_lockall(PyTdbObject *self,
188 : PyObject *Py_UNUSED(ignored))
189 : {
190 : int ret;
191 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
192 4 : ret = tdb_lockall(self->ctx);
193 4 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
194 4 : Py_RETURN_NONE;
195 : }
196 :
197 2 : static PyObject *obj_unlockall(PyTdbObject *self,
198 : PyObject *Py_UNUSED(ignored))
199 : {
200 : int ret;
201 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
202 2 : ret = tdb_unlockall(self->ctx);
203 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
204 2 : Py_RETURN_NONE;
205 : }
206 :
207 2 : static PyObject *obj_lockall_read(PyTdbObject *self,
208 : PyObject *Py_UNUSED(ignored))
209 : {
210 : int ret;
211 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
212 2 : ret = tdb_lockall_read(self->ctx);
213 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
214 2 : Py_RETURN_NONE;
215 : }
216 :
217 2 : static PyObject *obj_unlockall_read(PyTdbObject *self,
218 : PyObject *Py_UNUSED(ignored))
219 : {
220 2 : int ret = tdb_unlockall_read(self->ctx);
221 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
222 2 : Py_RETURN_NONE;
223 : }
224 :
225 4 : static PyObject *obj_close(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
226 : {
227 : int ret;
228 4 : if (self->closed)
229 1 : Py_RETURN_NONE;
230 3 : ret = tdb_close(self->ctx);
231 3 : self->closed = true;
232 3 : if (ret != 0) {
233 0 : PyErr_SetObject(PyExc_RuntimeError,
234 : Py_BuildValue("(i,s)",
235 : TDB_ERR_IO,
236 : "Failed to close database"));
237 0 : return NULL;
238 : }
239 3 : Py_RETURN_NONE;
240 : }
241 :
242 5 : static PyObject *obj_get(PyTdbObject *self, PyObject *args)
243 : {
244 : TDB_DATA key;
245 : PyObject *py_key;
246 :
247 5 : PyErr_TDB_RAISE_IF_CLOSED(self);
248 :
249 5 : if (!PyArg_ParseTuple(args, "O", &py_key))
250 0 : return NULL;
251 :
252 5 : key = PyBytes_AsTDB_DATA(py_key);
253 5 : if (!key.dptr)
254 0 : return NULL;
255 :
256 5 : return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key));
257 : }
258 :
259 0 : static PyObject *obj_append(PyTdbObject *self, PyObject *args)
260 : {
261 : TDB_DATA key, data;
262 : PyObject *py_key, *py_data;
263 : int ret;
264 :
265 0 : PyErr_TDB_RAISE_IF_CLOSED(self);
266 :
267 0 : if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
268 0 : return NULL;
269 :
270 0 : key = PyBytes_AsTDB_DATA(py_key);
271 0 : if (!key.dptr)
272 0 : return NULL;
273 0 : data = PyBytes_AsTDB_DATA(py_data);
274 0 : if (!data.dptr)
275 0 : return NULL;
276 :
277 0 : ret = tdb_append(self->ctx, key, data);
278 0 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
279 0 : Py_RETURN_NONE;
280 : }
281 :
282 0 : static PyObject *obj_firstkey(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
283 : {
284 0 : PyErr_TDB_RAISE_IF_CLOSED(self);
285 :
286 0 : return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx));
287 : }
288 :
289 0 : static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
290 : {
291 : TDB_DATA key;
292 : PyObject *py_key;
293 0 : PyErr_TDB_RAISE_IF_CLOSED(self);
294 :
295 0 : if (!PyArg_ParseTuple(args, "O", &py_key))
296 0 : return NULL;
297 :
298 0 : key = PyBytes_AsTDB_DATA(py_key);
299 0 : if (!key.dptr)
300 0 : return NULL;
301 :
302 0 : return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key));
303 : }
304 :
305 0 : static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
306 : {
307 : TDB_DATA key;
308 : PyObject *py_key;
309 : int ret;
310 0 : PyErr_TDB_RAISE_IF_CLOSED(self);
311 :
312 0 : if (!PyArg_ParseTuple(args, "O", &py_key))
313 0 : return NULL;
314 :
315 0 : key = PyBytes_AsTDB_DATA(py_key);
316 0 : if (!key.dptr)
317 0 : return NULL;
318 0 : ret = tdb_delete(self->ctx, key);
319 0 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
320 0 : Py_RETURN_NONE;
321 : }
322 :
323 4 : static int obj_contains(PyTdbObject *self, PyObject *py_key)
324 : {
325 : TDB_DATA key;
326 : int ret;
327 4 : PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
328 :
329 4 : key = PyBytes_AsTDB_DATA(py_key);
330 4 : if (!key.dptr) {
331 0 : PyErr_BadArgument();
332 0 : return -1;
333 : }
334 4 : ret = tdb_exists(self->ctx, key);
335 4 : if (ret)
336 2 : return 1;
337 2 : return 0;
338 : }
339 :
340 : #if PY_MAJOR_VERSION < 3
341 : static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
342 : {
343 : int ret;
344 : PyObject *py_key;
345 : PyErr_TDB_RAISE_IF_CLOSED(self);
346 :
347 : if (!PyArg_ParseTuple(args, "O", &py_key))
348 : return NULL;
349 :
350 : ret = obj_contains(self, py_key);
351 : if (ret == -1)
352 : return NULL;
353 : if (ret)
354 : Py_RETURN_TRUE;
355 : Py_RETURN_FALSE;
356 :
357 : }
358 : #endif
359 :
360 2 : static PyObject *obj_store(PyTdbObject *self, PyObject *args)
361 : {
362 : TDB_DATA key, value;
363 : int ret;
364 2 : int flag = TDB_REPLACE;
365 : PyObject *py_key, *py_value;
366 :
367 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
368 :
369 2 : if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
370 0 : return NULL;
371 :
372 2 : key = PyBytes_AsTDB_DATA(py_key);
373 2 : if (!key.dptr)
374 0 : return NULL;
375 2 : value = PyBytes_AsTDB_DATA(py_value);
376 2 : if (!value.dptr)
377 0 : return NULL;
378 :
379 2 : ret = tdb_store(self->ctx, key, value, flag);
380 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
381 2 : Py_RETURN_NONE;
382 : }
383 :
384 1 : static PyObject *obj_storev(PyTdbObject *self, PyObject *args)
385 : {
386 : TDB_DATA key, *values, value;
387 : int ret;
388 1 : int flag = TDB_REPLACE;
389 : Py_ssize_t num_values, i;
390 : PyObject *py_key, *py_values, *py_value;
391 :
392 1 : PyErr_TDB_RAISE_IF_CLOSED(self);
393 :
394 1 : if (!PyArg_ParseTuple(
395 : args, "OO!|i", &py_key, &PyList_Type, &py_values, &flag)) {
396 0 : return NULL;
397 : }
398 :
399 1 : num_values = PyList_Size(py_values);
400 :
401 1 : key = PyBytes_AsTDB_DATA(py_key);
402 1 : if (key.dptr == NULL) {
403 0 : return NULL;
404 : }
405 :
406 1 : if (SSIZE_MAX/sizeof(TDB_DATA) < num_values) {
407 0 : PyErr_SetFromErrno(PyExc_OverflowError);
408 0 : return NULL;
409 : }
410 1 : values = malloc(sizeof(TDB_DATA) * num_values);
411 1 : if (values == NULL) {
412 0 : PyErr_NoMemory();
413 0 : return NULL;
414 : }
415 4 : for (i=0; i<num_values; i++) {
416 3 : py_value = PyList_GetItem(py_values, i);
417 3 : value = PyBytes_AsTDB_DATA(py_value);
418 3 : if (!value.dptr) {
419 0 : free(values);
420 0 : return NULL;
421 : }
422 3 : values[i] = value;
423 : }
424 :
425 1 : ret = tdb_storev(self->ctx, key, values, num_values, flag);
426 1 : free(values);
427 1 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
428 1 : Py_RETURN_NONE;
429 : }
430 :
431 2 : static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
432 : {
433 : unsigned flags;
434 :
435 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
436 :
437 2 : if (!PyArg_ParseTuple(args, "I", &flags))
438 0 : return NULL;
439 :
440 2 : tdb_add_flags(self->ctx, flags);
441 2 : Py_RETURN_NONE;
442 : }
443 :
444 2 : static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
445 : {
446 : unsigned flags;
447 :
448 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
449 :
450 2 : if (!PyArg_ParseTuple(args, "I", &flags))
451 0 : return NULL;
452 :
453 2 : tdb_remove_flags(self->ctx, flags);
454 2 : Py_RETURN_NONE;
455 : }
456 :
457 : typedef struct {
458 : PyObject_HEAD
459 : TDB_DATA current;
460 : PyTdbObject *iteratee;
461 : } PyTdbIteratorObject;
462 :
463 24 : static PyObject *tdb_iter_next(PyTdbIteratorObject *self)
464 : {
465 : TDB_DATA current;
466 : PyObject *ret;
467 24 : if (self->current.dptr == NULL && self->current.dsize == 0)
468 10 : return NULL;
469 14 : current = self->current;
470 14 : self->current = tdb_nextkey(self->iteratee->ctx, self->current);
471 14 : ret = PyBytes_FromTDB_DATA(current);
472 14 : return ret;
473 : }
474 :
475 12 : static void tdb_iter_dealloc(PyTdbIteratorObject *self)
476 : {
477 12 : Py_DECREF(self->iteratee);
478 12 : PyObject_Del(self);
479 12 : }
480 :
481 : PyTypeObject PyTdbIterator = {
482 : .tp_name = "Iterator",
483 : .tp_basicsize = sizeof(PyTdbIteratorObject),
484 : .tp_iternext = (iternextfunc)tdb_iter_next,
485 : .tp_dealloc = (destructor)tdb_iter_dealloc,
486 : .tp_flags = Py_TPFLAGS_DEFAULT,
487 : .tp_iter = PyObject_SelfIter,
488 : };
489 :
490 12 : static PyObject *tdb_object_iter(PyTdbObject *self,
491 : PyObject *Py_UNUSED(ignored))
492 : {
493 : PyTdbIteratorObject *ret;
494 :
495 12 : PyErr_TDB_RAISE_IF_CLOSED(self);
496 :
497 12 : ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
498 12 : if (!ret)
499 0 : return NULL;
500 12 : ret->current = tdb_firstkey(self->ctx);
501 12 : ret->iteratee = self;
502 12 : Py_INCREF(self);
503 12 : return (PyObject *)ret;
504 : }
505 :
506 2 : static PyObject *obj_clear(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
507 : {
508 : int ret;
509 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
510 2 : ret = tdb_wipe_all(self->ctx);
511 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
512 2 : Py_RETURN_NONE;
513 : }
514 :
515 2 : static PyObject *obj_repack(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
516 : {
517 : int ret;
518 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
519 2 : ret = tdb_repack(self->ctx);
520 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
521 2 : Py_RETURN_NONE;
522 : }
523 :
524 1 : static PyObject *obj_enable_seqnum(PyTdbObject *self,
525 : PyObject *Py_UNUSED(ignored))
526 : {
527 1 : PyErr_TDB_RAISE_IF_CLOSED(self);
528 1 : tdb_enable_seqnum(self->ctx);
529 1 : Py_RETURN_NONE;
530 : }
531 :
532 1 : static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self,
533 : PyObject *Py_UNUSED(ignored))
534 : {
535 1 : PyErr_TDB_RAISE_IF_CLOSED(self);
536 1 : tdb_increment_seqnum_nonblock(self->ctx);
537 1 : Py_RETURN_NONE;
538 : }
539 :
540 : static PyMethodDef tdb_object_methods[] = {
541 : { "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS,
542 : "S.transaction_cancel() -> None\n"
543 : "Cancel the currently active transaction." },
544 : { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS,
545 : "S.transaction_commit() -> None\n"
546 : "Commit the currently active transaction." },
547 : { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
548 : "S.transaction_prepare_commit() -> None\n"
549 : "Prepare to commit the currently active transaction" },
550 : { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
551 : "S.transaction_start() -> None\n"
552 : "Start a new transaction." },
553 : { "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." },
554 : { "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL },
555 : { "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL },
556 : { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL },
557 : { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL },
558 : { "close", (PyCFunction)obj_close, METH_NOARGS, NULL },
559 : { "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n"
560 : "Fetch a value." },
561 : { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n"
562 : "Append data to an existing key." },
563 : { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n"
564 : "Return the first key in this database." },
565 : { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n"
566 : "Return the next key in this database." },
567 : { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
568 : "Delete an entry." },
569 : #if PY_MAJOR_VERSION < 3
570 : { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n"
571 : "Check whether key exists in this database." },
572 : #endif
573 : { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
574 : "Store data." },
575 : { "storev", (PyCFunction)obj_storev, METH_VARARGS, "S.storev(key, data, flag=REPLACE) -> None"
576 : "Store several data." },
577 : { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
578 : { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
579 : #if PY_MAJOR_VERSION >= 3
580 : { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.keys() -> iterator" },
581 : #else
582 : { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
583 : #endif
584 : { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
585 : "Wipe the entire database." },
586 : { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
587 : "Repack the entire database." },
588 : { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
589 : "S.enable_seqnum() -> None" },
590 : { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
591 : "S.increment_seqnum_nonblock() -> None" },
592 : {0}
593 : };
594 :
595 2 : static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure)
596 : {
597 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
598 2 : return PyLong_FromLong(tdb_hash_size(self->ctx));
599 : }
600 :
601 2 : static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure)
602 : {
603 2 : PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
604 2 : if (!PyLong_Check(max_dead))
605 0 : return -1;
606 2 : tdb_set_max_dead(self->ctx, PyLong_AsLong(max_dead));
607 2 : return 0;
608 : }
609 :
610 2 : static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
611 : {
612 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
613 2 : return PyLong_FromLong(tdb_map_size(self->ctx));
614 : }
615 :
616 2 : static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
617 : {
618 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
619 2 : return PyLong_FromLong(tdb_freelist_size(self->ctx));
620 : }
621 :
622 0 : static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
623 : {
624 0 : PyErr_TDB_RAISE_IF_CLOSED(self);
625 0 : return PyLong_FromLong(tdb_get_flags(self->ctx));
626 : }
627 :
628 2 : static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
629 : {
630 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
631 2 : return PyBytes_FromString(tdb_name(self->ctx));
632 : }
633 :
634 2 : static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
635 : {
636 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
637 2 : return PyLong_FromLong(tdb_get_seqnum(self->ctx));
638 : }
639 :
640 47 : static PyObject *obj_get_text(PyTdbObject *self, void *closure)
641 : {
642 : PyObject *mod, *cls, *inst;
643 47 : mod = PyImport_ImportModule("_tdb_text");
644 47 : if (mod == NULL)
645 0 : return NULL;
646 47 : cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
647 47 : if (cls == NULL) {
648 0 : Py_DECREF(mod);
649 0 : return NULL;
650 : }
651 47 : inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
652 47 : Py_DECREF(mod);
653 47 : Py_DECREF(cls);
654 47 : return inst;
655 : }
656 :
657 : static PyGetSetDef tdb_object_getsetters[] = {
658 : {
659 : .name = discard_const_p(char, "hash_size"),
660 : .get = (getter)obj_get_hash_size,
661 : },
662 : {
663 : .name = discard_const_p(char, "map_size"),
664 : .get = (getter)obj_get_map_size,
665 : },
666 : {
667 : .name = discard_const_p(char, "freelist_size"),
668 : .get = (getter)obj_get_freelist_size,
669 : },
670 : {
671 : .name = discard_const_p(char, "flags"),
672 : .get = (getter)obj_get_flags,
673 : },
674 : {
675 : .name = discard_const_p(char, "max_dead"),
676 : .set = (setter)obj_set_max_dead,
677 : },
678 : {
679 : .name = discard_const_p(char, "filename"),
680 : .get = (getter)obj_get_filename,
681 : .doc = discard_const_p(char, "The filename of this TDB file."),
682 : },
683 : {
684 : .name = discard_const_p(char, "seqnum"),
685 : .get = (getter)obj_get_seqnum,
686 : },
687 : {
688 : .name = discard_const_p(char, "text"),
689 : .get = (getter)obj_get_text,
690 : },
691 : { .name = NULL }
692 : };
693 :
694 3 : static PyObject *tdb_object_repr(PyTdbObject *self)
695 : {
696 3 : PyErr_TDB_RAISE_IF_CLOSED(self);
697 3 : if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
698 1 : return PyUnicode_FromString("Tdb(<internal>)");
699 : } else {
700 2 : return PyUnicode_FromFormat("Tdb('%s')", tdb_name(self->ctx));
701 : }
702 : }
703 :
704 55 : static void tdb_object_dealloc(PyTdbObject *self)
705 : {
706 55 : if (!self->closed)
707 52 : tdb_close(self->ctx);
708 55 : Py_TYPE(self)->tp_free(self);
709 55 : }
710 :
711 15 : static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
712 : {
713 : TDB_DATA tkey, val;
714 15 : PyErr_TDB_RAISE_IF_CLOSED(self);
715 14 : if (!PyBytes_Check(key)) {
716 0 : PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
717 0 : return NULL;
718 : }
719 :
720 14 : tkey.dptr = (unsigned char *)PyBytes_AsString(key);
721 14 : tkey.dsize = PyBytes_Size(key);
722 :
723 14 : val = tdb_fetch(self->ctx, tkey);
724 14 : if (val.dptr == NULL) {
725 : /*
726 : * if the key doesn't exist raise KeyError(key) to be
727 : * consistent with python dict
728 : */
729 4 : PyErr_SetObject(PyExc_KeyError, key);
730 4 : return NULL;
731 : } else {
732 10 : return PyBytes_FromTDB_DATA(val);
733 : }
734 : }
735 :
736 42 : static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value)
737 : {
738 : TDB_DATA tkey, tval;
739 : int ret;
740 42 : PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
741 42 : if (!PyBytes_Check(key)) {
742 0 : PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
743 0 : return -1;
744 : }
745 :
746 42 : tkey = PyBytes_AsTDB_DATA(key);
747 :
748 42 : if (value == NULL) {
749 4 : ret = tdb_delete(self->ctx, tkey);
750 : } else {
751 38 : if (!PyBytes_Check(value)) {
752 0 : PyErr_SetString(PyExc_TypeError, "Expected string as value");
753 0 : return -1;
754 : }
755 :
756 38 : tval = PyBytes_AsTDB_DATA(value);
757 :
758 38 : ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
759 : }
760 :
761 42 : if (ret != 0) {
762 0 : PyErr_SetTDBError(self->ctx);
763 0 : return -1;
764 : }
765 :
766 42 : return ret;
767 : }
768 :
769 : static PyMappingMethods tdb_object_mapping = {
770 : .mp_subscript = (binaryfunc)obj_getitem,
771 : .mp_ass_subscript = (objobjargproc)obj_setitem,
772 : };
773 : static PySequenceMethods tdb_object_seq = {
774 : .sq_contains = (objobjproc)obj_contains,
775 : };
776 : static PyTypeObject PyTdb = {
777 : .tp_name = "tdb.Tdb",
778 : .tp_basicsize = sizeof(PyTdbObject),
779 : .tp_methods = tdb_object_methods,
780 : .tp_getset = tdb_object_getsetters,
781 : .tp_new = py_tdb_open,
782 : .tp_doc = "A TDB file",
783 : .tp_repr = (reprfunc)tdb_object_repr,
784 : .tp_dealloc = (destructor)tdb_object_dealloc,
785 : .tp_as_mapping = &tdb_object_mapping,
786 : .tp_as_sequence = &tdb_object_seq,
787 : .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER,
788 : .tp_iter = PY_DISCARD_FUNC_SIG(getiterfunc,tdb_object_iter),
789 : };
790 :
791 : static PyMethodDef tdb_methods[] = {
792 : {
793 : .ml_name = "open",
794 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, py_tdb_open),
795 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
796 : .ml_doc = "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, "
797 : "flags=O_RDWR, mode=0600)\nOpen a TDB file."
798 : },
799 : { .ml_name = NULL }
800 : };
801 :
802 : #define MODULE_DOC "simple key-value database that supports multiple writers."
803 :
804 : #if PY_MAJOR_VERSION >= 3
805 : static struct PyModuleDef moduledef = {
806 : PyModuleDef_HEAD_INIT,
807 : .m_name = "tdb",
808 : .m_doc = MODULE_DOC,
809 : .m_size = -1,
810 : .m_methods = tdb_methods,
811 : };
812 : #endif
813 :
814 : PyObject* module_init(void);
815 1206 : PyObject* module_init(void)
816 : {
817 : PyObject *m;
818 :
819 1206 : if (PyType_Ready(&PyTdb) < 0)
820 0 : return NULL;
821 :
822 1206 : if (PyType_Ready(&PyTdbIterator) < 0)
823 0 : return NULL;
824 :
825 : #if PY_MAJOR_VERSION >= 3
826 1206 : m = PyModule_Create(&moduledef);
827 : #else
828 : m = Py_InitModule3("tdb", tdb_methods, MODULE_DOC);
829 : #endif
830 1206 : if (m == NULL)
831 0 : return NULL;
832 :
833 1206 : PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
834 1206 : PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
835 1206 : PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
836 :
837 1206 : PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
838 1206 : PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
839 1206 : PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
840 1206 : PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
841 1206 : PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
842 1206 : PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
843 1206 : PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
844 1206 : PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
845 1206 : PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
846 1206 : PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
847 1206 : PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
848 1206 : PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
849 1206 : PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
850 :
851 1206 : PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
852 :
853 1206 : PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
854 :
855 1206 : Py_INCREF(&PyTdb);
856 1206 : PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
857 :
858 1206 : Py_INCREF(&PyTdbIterator);
859 :
860 1206 : return m;
861 : }
862 :
863 :
864 : #if PY_MAJOR_VERSION >= 3
865 : PyMODINIT_FUNC PyInit_tdb(void);
866 1206 : PyMODINIT_FUNC PyInit_tdb(void)
867 : {
868 1206 : return module_init();
869 : }
870 : #else
871 : void inittdb(void);
872 : void inittdb(void)
873 : {
874 : module_init();
875 : }
876 : #endif
|