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 : if (num_values > INT_MAX) {
387 0 : PyErr_SetFromErrno(PyExc_OverflowError);
388 0 : return NULL;
389 : }
390 2 : values = malloc(sizeof(TDB_DATA) * num_values);
391 2 : if (values == NULL) {
392 0 : PyErr_NoMemory();
393 0 : return NULL;
394 : }
395 8 : for (i=0; i<num_values; i++) {
396 6 : py_value = PyList_GetItem(py_values, i);
397 6 : value = PyBytes_AsTDB_DATA(py_value);
398 6 : if (!value.dptr) {
399 0 : free(values);
400 0 : return NULL;
401 : }
402 6 : values[i] = value;
403 : }
404 :
405 2 : ret = tdb_storev(self->ctx, key, values, (int)num_values, flag);
406 2 : free(values);
407 2 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
408 2 : Py_RETURN_NONE;
409 : }
410 :
411 4 : static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
412 : {
413 2 : unsigned flags;
414 :
415 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
416 :
417 4 : if (!PyArg_ParseTuple(args, "I", &flags))
418 0 : return NULL;
419 :
420 4 : tdb_add_flags(self->ctx, flags);
421 4 : Py_RETURN_NONE;
422 : }
423 :
424 4 : static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
425 : {
426 2 : unsigned flags;
427 :
428 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
429 :
430 4 : if (!PyArg_ParseTuple(args, "I", &flags))
431 0 : return NULL;
432 :
433 4 : tdb_remove_flags(self->ctx, flags);
434 4 : Py_RETURN_NONE;
435 : }
436 :
437 : typedef struct {
438 : PyObject_HEAD
439 : TDB_DATA current;
440 : PyTdbObject *iteratee;
441 : } PyTdbIteratorObject;
442 :
443 228 : static PyObject *tdb_iter_next(PyTdbIteratorObject *self)
444 : {
445 204 : TDB_DATA current;
446 204 : PyObject *ret;
447 228 : if (self->current.dptr == NULL && self->current.dsize == 0)
448 10 : return NULL;
449 198 : current = self->current;
450 198 : self->current = tdb_nextkey(self->iteratee->ctx, self->current);
451 198 : ret = PyBytes_FromTDB_DATA(current);
452 198 : return ret;
453 : }
454 :
455 34 : static void tdb_iter_dealloc(PyTdbIteratorObject *self)
456 : {
457 34 : Py_CLEAR(self->iteratee);
458 34 : PyObject_Del(self);
459 34 : }
460 :
461 : PyTypeObject PyTdbIterator = {
462 : .tp_name = "Iterator",
463 : .tp_basicsize = sizeof(PyTdbIteratorObject),
464 : .tp_iternext = (iternextfunc)tdb_iter_next,
465 : .tp_dealloc = (destructor)tdb_iter_dealloc,
466 : .tp_flags = Py_TPFLAGS_DEFAULT,
467 : .tp_iter = PyObject_SelfIter,
468 : };
469 :
470 34 : static PyObject *tdb_object_iter(PyTdbObject *self,
471 : PyObject *Py_UNUSED(ignored))
472 : {
473 22 : PyTdbIteratorObject *ret;
474 :
475 34 : PyErr_TDB_RAISE_IF_CLOSED(self);
476 :
477 34 : ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
478 34 : if (!ret)
479 0 : return NULL;
480 34 : ret->current = tdb_firstkey(self->ctx);
481 34 : ret->iteratee = self;
482 34 : Py_INCREF(self);
483 34 : return (PyObject *)ret;
484 : }
485 :
486 4 : static PyObject *obj_clear(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
487 : {
488 2 : int ret;
489 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
490 4 : ret = tdb_wipe_all(self->ctx);
491 4 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
492 4 : Py_RETURN_NONE;
493 : }
494 :
495 4 : static PyObject *obj_repack(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
496 : {
497 2 : int ret;
498 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
499 4 : ret = tdb_repack(self->ctx);
500 4 : PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
501 4 : Py_RETURN_NONE;
502 : }
503 :
504 2 : static PyObject *obj_enable_seqnum(PyTdbObject *self,
505 : PyObject *Py_UNUSED(ignored))
506 : {
507 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
508 2 : tdb_enable_seqnum(self->ctx);
509 2 : Py_RETURN_NONE;
510 : }
511 :
512 2 : static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self,
513 : PyObject *Py_UNUSED(ignored))
514 : {
515 2 : PyErr_TDB_RAISE_IF_CLOSED(self);
516 2 : tdb_increment_seqnum_nonblock(self->ctx);
517 2 : Py_RETURN_NONE;
518 : }
519 :
520 : static PyMethodDef tdb_object_methods[] = {
521 : { "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS,
522 : "S.transaction_cancel() -> None\n"
523 : "Cancel the currently active transaction." },
524 : { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS,
525 : "S.transaction_commit() -> None\n"
526 : "Commit the currently active transaction." },
527 : { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
528 : "S.transaction_prepare_commit() -> None\n"
529 : "Prepare to commit the currently active transaction" },
530 : { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
531 : "S.transaction_start() -> None\n"
532 : "Start a new transaction." },
533 : { "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." },
534 : { "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL },
535 : { "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL },
536 : { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL },
537 : { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL },
538 : { "close", (PyCFunction)obj_close, METH_NOARGS, NULL },
539 : { "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n"
540 : "Fetch a value." },
541 : { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n"
542 : "Append data to an existing key." },
543 : { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n"
544 : "Return the first key in this database." },
545 : { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n"
546 : "Return the next key in this database." },
547 : { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
548 : "Delete an entry." },
549 : { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
550 : "Store data." },
551 : { "storev", (PyCFunction)obj_storev, METH_VARARGS, "S.storev(key, data, flag=REPLACE) -> None"
552 : "Store several data." },
553 : { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
554 : { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
555 : { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.keys() -> iterator" },
556 : { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
557 : "Wipe the entire database." },
558 : { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
559 : "Repack the entire database." },
560 : { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
561 : "S.enable_seqnum() -> None" },
562 : { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
563 : "S.increment_seqnum_nonblock() -> None" },
564 : {0}
565 : };
566 :
567 4 : static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure)
568 : {
569 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
570 4 : return PyLong_FromLong(tdb_hash_size(self->ctx));
571 : }
572 :
573 4 : static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure)
574 : {
575 4 : PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
576 4 : if (!PyLong_Check(max_dead))
577 0 : return -1;
578 4 : tdb_set_max_dead(self->ctx, PyLong_AsLong(max_dead));
579 4 : return 0;
580 : }
581 :
582 4 : static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
583 : {
584 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
585 4 : return PyLong_FromLong(tdb_map_size(self->ctx));
586 : }
587 :
588 4 : static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
589 : {
590 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
591 4 : return PyLong_FromLong(tdb_freelist_size(self->ctx));
592 : }
593 :
594 0 : static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
595 : {
596 0 : PyErr_TDB_RAISE_IF_CLOSED(self);
597 0 : return PyLong_FromLong(tdb_get_flags(self->ctx));
598 : }
599 :
600 4 : static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
601 : {
602 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
603 4 : return PyBytes_FromString(tdb_name(self->ctx));
604 : }
605 :
606 4 : static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
607 : {
608 4 : PyErr_TDB_RAISE_IF_CLOSED(self);
609 4 : return PyLong_FromLong(tdb_get_seqnum(self->ctx));
610 : }
611 :
612 94 : static PyObject *obj_get_text(PyTdbObject *self, void *closure)
613 : {
614 47 : PyObject *mod, *cls, *inst;
615 94 : mod = PyImport_ImportModule("_tdb_text");
616 94 : if (mod == NULL)
617 0 : return NULL;
618 94 : cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
619 94 : if (cls == NULL) {
620 0 : Py_DECREF(mod);
621 0 : return NULL;
622 : }
623 94 : inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
624 94 : Py_DECREF(mod);
625 94 : Py_DECREF(cls);
626 47 : return inst;
627 : }
628 :
629 : static PyGetSetDef tdb_object_getsetters[] = {
630 : {
631 : .name = discard_const_p(char, "hash_size"),
632 : .get = (getter)obj_get_hash_size,
633 : },
634 : {
635 : .name = discard_const_p(char, "map_size"),
636 : .get = (getter)obj_get_map_size,
637 : },
638 : {
639 : .name = discard_const_p(char, "freelist_size"),
640 : .get = (getter)obj_get_freelist_size,
641 : },
642 : {
643 : .name = discard_const_p(char, "flags"),
644 : .get = (getter)obj_get_flags,
645 : },
646 : {
647 : .name = discard_const_p(char, "max_dead"),
648 : .set = (setter)obj_set_max_dead,
649 : },
650 : {
651 : .name = discard_const_p(char, "filename"),
652 : .get = (getter)obj_get_filename,
653 : .doc = discard_const_p(char, "The filename of this TDB file."),
654 : },
655 : {
656 : .name = discard_const_p(char, "seqnum"),
657 : .get = (getter)obj_get_seqnum,
658 : },
659 : {
660 : .name = discard_const_p(char, "text"),
661 : .get = (getter)obj_get_text,
662 : },
663 : { .name = NULL }
664 : };
665 :
666 6 : static PyObject *tdb_object_repr(PyTdbObject *self)
667 : {
668 6 : PyErr_TDB_RAISE_IF_CLOSED(self);
669 6 : if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
670 2 : return PyUnicode_FromString("Tdb(<internal>)");
671 : } else {
672 4 : return PyUnicode_FromFormat("Tdb('%s')", tdb_name(self->ctx));
673 : }
674 : }
675 :
676 286 : static void tdb_object_dealloc(PyTdbObject *self)
677 : {
678 286 : if (!self->closed)
679 109 : tdb_close(self->ctx);
680 286 : Py_TYPE(self)->tp_free(self);
681 286 : }
682 :
683 48 : static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
684 : {
685 33 : TDB_DATA tkey, val;
686 48 : PyErr_TDB_RAISE_IF_CLOSED(self);
687 46 : if (!PyBytes_Check(key)) {
688 0 : PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
689 0 : return NULL;
690 : }
691 :
692 46 : tkey.dptr = (unsigned char *)PyBytes_AsString(key);
693 46 : tkey.dsize = PyBytes_Size(key);
694 :
695 46 : val = tdb_fetch(self->ctx, tkey);
696 46 : if (val.dptr == NULL) {
697 : /*
698 : * if the key doesn't exist raise KeyError(key) to be
699 : * consistent with python dict
700 : */
701 8 : PyErr_SetObject(PyExc_KeyError, key);
702 8 : return NULL;
703 : } else {
704 38 : return PyBytes_FromTDB_DATA(val);
705 : }
706 : }
707 :
708 84 : static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value)
709 : {
710 42 : TDB_DATA tkey, tval;
711 42 : int ret;
712 84 : PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
713 84 : if (!PyBytes_Check(key)) {
714 0 : PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
715 0 : return -1;
716 : }
717 :
718 84 : tkey = PyBytes_AsTDB_DATA(key);
719 :
720 84 : if (value == NULL) {
721 8 : ret = tdb_delete(self->ctx, tkey);
722 : } else {
723 76 : if (!PyBytes_Check(value)) {
724 0 : PyErr_SetString(PyExc_TypeError, "Expected string as value");
725 0 : return -1;
726 : }
727 :
728 76 : tval = PyBytes_AsTDB_DATA(value);
729 :
730 76 : ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
731 : }
732 :
733 84 : if (ret != 0) {
734 0 : PyErr_SetTDBError(self->ctx);
735 0 : return -1;
736 : }
737 :
738 42 : return ret;
739 : }
740 :
741 : static PyMappingMethods tdb_object_mapping = {
742 : .mp_subscript = (binaryfunc)obj_getitem,
743 : .mp_ass_subscript = (objobjargproc)obj_setitem,
744 : };
745 : static PySequenceMethods tdb_object_seq = {
746 : .sq_contains = (objobjproc)obj_contains,
747 : };
748 : static PyTypeObject PyTdb = {
749 : .tp_name = "tdb.Tdb",
750 : .tp_basicsize = sizeof(PyTdbObject),
751 : .tp_methods = tdb_object_methods,
752 : .tp_getset = tdb_object_getsetters,
753 : .tp_new = py_tdb_open,
754 : .tp_doc = "A TDB file",
755 : .tp_repr = (reprfunc)tdb_object_repr,
756 : .tp_dealloc = (destructor)tdb_object_dealloc,
757 : .tp_as_mapping = &tdb_object_mapping,
758 : .tp_as_sequence = &tdb_object_seq,
759 : .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
760 : .tp_iter = PY_DISCARD_FUNC_SIG(getiterfunc,tdb_object_iter),
761 : };
762 :
763 : static PyMethodDef tdb_methods[] = {
764 : {
765 : .ml_name = "open",
766 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, py_tdb_open),
767 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
768 : .ml_doc = "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, "
769 : "flags=O_RDWR, mode=0600)\nOpen a TDB file."
770 : },
771 : { .ml_name = NULL }
772 : };
773 :
774 : #define MODULE_DOC "simple key-value database that supports multiple writers."
775 :
776 : static struct PyModuleDef moduledef = {
777 : PyModuleDef_HEAD_INIT,
778 : .m_name = "tdb",
779 : .m_doc = MODULE_DOC,
780 : .m_size = -1,
781 : .m_methods = tdb_methods,
782 : };
783 :
784 : PyObject* module_init(void);
785 1900 : PyObject* module_init(void)
786 : {
787 52 : PyObject *m;
788 :
789 1900 : if (PyType_Ready(&PyTdb) < 0)
790 0 : return NULL;
791 :
792 1900 : if (PyType_Ready(&PyTdbIterator) < 0)
793 0 : return NULL;
794 :
795 1900 : m = PyModule_Create(&moduledef);
796 1900 : if (m == NULL)
797 0 : return NULL;
798 :
799 1900 : PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
800 1900 : PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
801 1900 : PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
802 :
803 1900 : PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
804 1900 : PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
805 1900 : PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
806 1900 : PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
807 1900 : PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
808 1900 : PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
809 1900 : PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
810 1900 : PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
811 1900 : PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
812 1900 : PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
813 1900 : PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
814 1900 : PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
815 1900 : PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
816 :
817 1900 : PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
818 :
819 1900 : PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
820 :
821 1562 : Py_INCREF(&PyTdb);
822 1900 : PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
823 :
824 1562 : Py_INCREF(&PyTdbIterator);
825 :
826 1900 : return m;
827 : }
828 :
829 :
830 : PyMODINIT_FUNC PyInit_tdb(void);
831 1900 : PyMODINIT_FUNC PyInit_tdb(void)
832 : {
833 1900 : return module_init();
834 : }
|