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