I *hate* global variables...
[Samba.git] / source / python / py_tdb.c
blob37f64ce7802b6732b2be03aa45b6c24fa2413ba7
1 /*
2 Python wrappers for TDB module
4 Copyright (C) Tim Potter, 2002-2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /*
22 NOTE: Since tdb is licenced under the GPL any program that uses these bindings
23 must be distributed under the GPL license terms since this is what
24 the GPL requires.
26 http://www.gnu.org/licenses/gpl-faq.html#IfInterpreterIsGPL
29 #include "includes.h"
31 /* This symbol is used in both includes.h and Python.h which causes an
32 annoying compiler warning. */
34 #ifdef HAVE_FSTAT
35 #undef HAVE_FSTAT
36 #endif
38 #include "Python.h"
40 /* Tdb exception */
42 PyObject *py_tdb_error;
44 /* tdb handle object */
46 typedef struct {
47 PyObject_HEAD
48 TDB_CONTEXT *tdb;
49 } tdb_hnd_object;
51 PyTypeObject tdb_hnd_type;
53 PyObject *new_tdb_hnd_object(TDB_CONTEXT *tdb)
55 tdb_hnd_object *obj;
57 obj = PyObject_New(tdb_hnd_object, &tdb_hnd_type);
58 obj->tdb = tdb;
60 return (PyObject *)obj;
63 PyObject *py_tdb_close(PyObject *self, PyObject *args)
65 tdb_hnd_object *obj;
67 if (!PyArg_ParseTuple(args, "O!", &tdb_hnd_type, &obj))
68 return NULL;
70 if (tdb_close(obj->tdb) == -1) {
71 obj->tdb = NULL;
72 PyErr_SetString(py_tdb_error, strerror(errno));
73 return NULL;
76 obj->tdb = NULL;
78 Py_INCREF(Py_None);
79 return Py_None;
82 PyObject *py_tdb_open(PyObject *self, PyObject *args, PyObject *kw)
84 static char *kwlist[] = { "name", "hash_size", "tdb_flags",
85 "open_flags", "mode", NULL };
86 char *name;
87 int hash_size = 0, flags = TDB_DEFAULT, open_flags = -1, open_mode = 0600;
88 TDB_CONTEXT *tdb;
90 if (!PyArg_ParseTupleAndKeywords(
91 args, kw, "s|iiii", kwlist, &name, &hash_size, &flags,
92 &open_flags, &open_mode))
93 return NULL;
95 /* Default open_flags to read/write */
97 if (open_flags == -1) {
98 if (access(name, W_OK) == -1)
99 open_flags = O_RDONLY;
100 else
101 open_flags = O_RDWR;
104 if (!(tdb = tdb_open(name, hash_size, flags, open_flags, open_mode))) {
105 PyErr_SetString(py_tdb_error, strerror(errno));
106 return NULL;
109 return new_tdb_hnd_object(tdb);
113 * Allow a tdb to act as a python mapping (dictionary)
116 static int tdb_traverse_count(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
117 void *state)
119 /* Do nothing - tdb_traverse will return the number of records
120 traversed. */
122 return 0;
125 static int tdb_hnd_length(tdb_hnd_object *obj)
127 int result;
129 result = tdb_traverse(obj->tdb, tdb_traverse_count, NULL);
131 return result;
134 static PyObject *tdb_hnd_subscript(tdb_hnd_object *obj, PyObject *key)
136 TDB_DATA drec, krec;
137 PyObject *result;
139 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize))
140 return NULL;
142 drec = tdb_fetch(obj->tdb, krec);
144 if (!drec.dptr) {
145 PyErr_SetString(PyExc_KeyError,
146 PyString_AsString(key));
147 return NULL;
150 result = PyString_FromStringAndSize(drec.dptr, drec.dsize);
151 free(drec.dptr);
153 return result;
156 static int tdb_ass_subscript(tdb_hnd_object *obj, PyObject *key, PyObject *value)
158 TDB_DATA krec, drec;
160 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize)) {
161 PyErr_SetString(PyExc_TypeError,
162 "tdb mappings have string indices only");
163 return -1;
166 if (!obj->tdb) {
167 PyErr_SetString(
168 py_tdb_error, "tdb object has been closed");
169 return -1;
172 if (!value) {
174 /* Delete value */
176 if (tdb_delete(obj->tdb, krec) == -1) {
177 PyErr_SetString(PyExc_KeyError,
178 PyString_AsString(value));
179 return -1;
182 } else {
184 /* Set value */
186 if (!PyArg_Parse(value, "s#", &drec.dptr, &drec.dsize)) {
187 PyErr_SetString(PyExc_TypeError,
188 "tdb mappings have string elements only");
189 return -1;
192 errno = 0;
194 if (tdb_store(obj->tdb, krec, drec, 0) < 0 ) {
195 if (errno != 0)
196 PyErr_SetFromErrno(py_tdb_error);
197 else
198 PyErr_SetString(
199 py_tdb_error,
200 (char *)tdb_errorstr(obj->tdb));
202 return -1;
206 return 0;
209 static PyMappingMethods tdb_mapping = {
210 (inquiry) tdb_hnd_length,
211 (binaryfunc) tdb_hnd_subscript,
212 (objobjargproc) tdb_ass_subscript
216 * Utility methods
219 /* Return non-zero if a given key exists in the tdb */
221 PyObject *py_tdb_hnd_has_key(PyObject *self, PyObject *args)
223 tdb_hnd_object *obj = (tdb_hnd_object *)self;
224 TDB_DATA key;
226 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
227 return NULL;
229 if (!obj->tdb) {
230 PyErr_SetString(
231 py_tdb_error, "tdb object has been closed");
232 return NULL;
235 return PyInt_FromLong(tdb_exists(obj->tdb, key));
238 /* Return a list of keys in the tdb */
240 static int tdb_traverse_keys(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
241 void *state)
243 PyObject *key_list = (PyObject *)state;
245 PyList_Append(key_list,
246 PyString_FromStringAndSize(key.dptr, key.dsize));
248 return 0;
251 PyObject *py_tdb_hnd_keys(PyObject *self, PyObject *args)
253 tdb_hnd_object *obj = (tdb_hnd_object *)self;
254 PyObject *key_list = PyList_New(0);
256 if (!obj->tdb) {
257 PyErr_SetString(py_tdb_error, "tdb object has been closed");
258 return NULL;
261 if (tdb_traverse(obj->tdb, tdb_traverse_keys, key_list) == -1) {
262 PyErr_SetString(py_tdb_error, "error traversing tdb");
263 Py_DECREF(key_list);
264 return NULL;
267 return key_list;
270 PyObject *py_tdb_hnd_first_key(PyObject *self, PyObject *args)
272 tdb_hnd_object *obj = (tdb_hnd_object *)self;
273 TDB_DATA key;
275 if (!obj->tdb) {
276 PyErr_SetString(py_tdb_error, "tdb object has been closed");
277 return NULL;
280 key = tdb_firstkey(obj->tdb);
282 return Py_BuildValue("s#", key.dptr, key.dsize);
285 PyObject *py_tdb_hnd_next_key(PyObject *self, PyObject *py_oldkey)
287 tdb_hnd_object *obj = (tdb_hnd_object *)self;
288 TDB_DATA key, oldkey;
290 if (!obj->tdb) {
291 PyErr_SetString(py_tdb_error, "tdb object has been closed");
292 return NULL;
295 if (!PyArg_Parse(py_oldkey, "s#", &oldkey.dptr, &oldkey.dsize))
296 return NULL;
298 key = tdb_nextkey(obj->tdb, oldkey);
300 return Py_BuildValue("s#", key.dptr, key.dsize);
304 * Locking routines
307 PyObject *py_tdb_hnd_lock_all(PyObject *self, PyObject *args)
309 tdb_hnd_object *obj = (tdb_hnd_object *)self;
310 int result;
312 if (!obj->tdb) {
313 PyErr_SetString(py_tdb_error, "tdb object has been closed");
314 return NULL;
317 result = tdb_lockall(obj->tdb);
319 return PyInt_FromLong(result != -1);
322 PyObject *py_tdb_hnd_unlock_all(PyObject *self, PyObject *args)
324 tdb_hnd_object *obj = (tdb_hnd_object *)self;
326 if (!obj->tdb) {
327 PyErr_SetString(py_tdb_error, "tdb object has been closed");
328 return NULL;
331 tdb_unlockall(obj->tdb);
333 Py_INCREF(Py_None);
334 return Py_None;
337 /* Return an array of keys from a python object which must be a string or a
338 list of strings. */
340 static BOOL make_lock_list(PyObject *py_keys, TDB_DATA **keys, int *num_keys)
342 /* Are we a list or a string? */
344 if (!PyList_Check(py_keys) && !PyString_Check(py_keys)) {
345 PyErr_SetString(PyExc_TypeError, "arg must be list of string");
346 return False;
349 if (PyList_Check(py_keys)) {
350 int i;
352 /* Turn python list into array of keys */
354 *num_keys = PyList_Size(py_keys);
355 *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA) * (*num_keys));
357 for (i = 0; i < *num_keys; i++) {
358 PyObject *key = PyList_GetItem(py_keys, i);
360 if (!PyString_Check(key)) {
361 PyErr_SetString(
362 PyExc_TypeError,
363 "list elements must be strings");
364 return False;
367 PyArg_Parse(key, "s#", &(*keys)[i].dptr,
368 &(*keys)[i].dsize);
371 } else {
373 /* Turn python string into a single key */
375 *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA));
376 *num_keys = 1;
377 PyArg_Parse(py_keys, "s#", &(*keys)->dptr, &(*keys)->dsize);
380 return True;
383 PyObject *py_tdb_hnd_lock(PyObject *self, PyObject *args)
385 tdb_hnd_object *obj = (tdb_hnd_object *)self;
386 PyObject *py_keys;
387 TDB_DATA *keys;
388 int num_keys, result;
390 if (!obj->tdb) {
391 PyErr_SetString(py_tdb_error, "tdb object has been closed");
392 return NULL;
395 if (!PyArg_ParseTuple(args, "O", &py_keys))
396 return NULL;
398 if (!make_lock_list(py_keys, &keys, &num_keys))
399 return NULL;
401 result = tdb_lockkeys(obj->tdb, num_keys, keys);
403 free(keys);
405 return PyInt_FromLong(result != -1);
408 PyObject *py_tdb_hnd_unlock(PyObject *self, PyObject *args)
410 tdb_hnd_object *obj = (tdb_hnd_object *)self;
412 if (!obj->tdb) {
413 PyErr_SetString(py_tdb_error, "tdb object has been closed");
414 return NULL;
417 if (!PyArg_ParseTuple(args, ""))
418 return NULL;
420 tdb_unlockkeys(obj->tdb);
422 Py_INCREF(Py_None);
423 return Py_None;
427 * tdb traversal
430 struct traverse_info {
431 PyObject *callback;
432 PyObject *state;
435 static int tdb_traverse_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
436 void *state)
438 struct traverse_info *info = state;
439 PyObject *arglist, *py_result;
440 int result;
442 arglist = Py_BuildValue("(s#s#O)", key.dptr, key.dsize, value.dptr,
443 value.dsize, info->state);
445 py_result = PyEval_CallObject(info->callback, arglist);
447 Py_DECREF(arglist);
449 if (!PyInt_Check(py_result)) {
450 result = 1; /* Hmm - non-integer object returned by callback */
451 goto done;
454 result = PyInt_AsLong(py_result);
456 done:
457 Py_DECREF(py_result);
458 return result;
461 PyObject *py_tdb_hnd_traverse(PyObject *self, PyObject *args, PyObject *kw)
463 tdb_hnd_object *obj = (tdb_hnd_object *)self;
464 static char *kwlist[] = { "traverse_fn", "state", NULL };
465 PyObject *state = Py_None, *callback;
466 struct traverse_info info;
467 int result;
469 if (!PyArg_ParseTupleAndKeywords(
470 args, kw, "O|O", kwlist, &callback, &state))
471 return NULL;
473 if (!PyCallable_Check(callback)) {
474 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
475 return NULL;
478 Py_INCREF(callback);
479 Py_INCREF(state);
481 info.callback = callback;
482 info.state = state;
484 result = tdb_traverse(obj->tdb, tdb_traverse_traverse, &info);
486 Py_DECREF(callback);
487 Py_DECREF(state);
489 return PyInt_FromLong(result);
492 PyObject *py_tdb_hnd_chainlock(PyObject *self, PyObject *args)
494 tdb_hnd_object *obj = (tdb_hnd_object *)self;
495 TDB_DATA key;
496 int result;
498 if (!obj->tdb) {
499 PyErr_SetString(py_tdb_error, "tdb object has been closed");
500 return NULL;
503 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
504 return NULL;
506 result = tdb_chainlock(obj->tdb, key);
508 return PyInt_FromLong(result != -1);
511 PyObject *py_tdb_hnd_chainunlock(PyObject *self, PyObject *args)
513 tdb_hnd_object *obj = (tdb_hnd_object *)self;
514 TDB_DATA key;
515 int result;
517 if (!obj->tdb) {
518 PyErr_SetString(py_tdb_error, "tdb object has been closed");
519 return NULL;
522 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
523 return NULL;
525 result = tdb_chainunlock(obj->tdb, key);
527 return PyInt_FromLong(result != -1);
530 PyObject *py_tdb_hnd_lock_bystring(PyObject *self, PyObject *args)
532 tdb_hnd_object *obj = (tdb_hnd_object *)self;
533 int result, timeout = 30;
534 char *s;
536 if (!obj->tdb) {
537 PyErr_SetString(py_tdb_error, "tdb object has been closed");
538 return NULL;
541 if (!PyArg_ParseTuple(args, "s|i", &s, &timeout))
542 return NULL;
544 result = tdb_lock_bystring(obj->tdb, s, timeout);
546 return PyInt_FromLong(result != -1);
549 PyObject *py_tdb_hnd_unlock_bystring(PyObject *self, PyObject *args)
551 tdb_hnd_object *obj = (tdb_hnd_object *)self;
552 char *s;
554 if (!obj->tdb) {
555 PyErr_SetString(py_tdb_error, "tdb object has been closed");
556 return NULL;
559 if (!PyArg_ParseTuple(args, "s", &s))
560 return NULL;
562 tdb_unlock_bystring(obj->tdb, s);
564 Py_INCREF(Py_None);
565 return Py_None;
569 * Method dispatch table for this module
572 static PyMethodDef tdb_methods[] = {
573 { "open", (PyCFunction)py_tdb_open, METH_VARARGS | METH_KEYWORDS },
574 { "close", (PyCFunction)py_tdb_close, METH_VARARGS },
575 { NULL }
579 * Methods on a tdb object
582 static PyMethodDef tdb_hnd_methods[] = {
583 { "keys", (PyCFunction)py_tdb_hnd_keys, METH_VARARGS },
584 { "has_key", (PyCFunction)py_tdb_hnd_has_key, METH_VARARGS },
585 { "first_key", (PyCFunction)py_tdb_hnd_first_key, METH_VARARGS },
586 { "next_key", (PyCFunction)py_tdb_hnd_next_key, METH_VARARGS },
587 { "lock_all", (PyCFunction)py_tdb_hnd_lock_all, METH_VARARGS },
588 { "unlock_all", (PyCFunction)py_tdb_hnd_unlock_all, METH_VARARGS },
589 { "lock", (PyCFunction)py_tdb_hnd_lock, METH_VARARGS },
590 { "unlock", (PyCFunction)py_tdb_hnd_unlock, METH_VARARGS },
591 { "traverse", (PyCFunction)py_tdb_hnd_traverse, METH_VARARGS | METH_KEYWORDS },
592 { "chainlock", (PyCFunction)py_tdb_hnd_chainlock, METH_VARARGS | METH_KEYWORDS },
593 { "chainunlock", (PyCFunction)py_tdb_hnd_chainunlock, METH_VARARGS | METH_KEYWORDS },
594 { "lock_bystring", (PyCFunction)py_tdb_hnd_lock_bystring, METH_VARARGS | METH_KEYWORDS },
595 { "unlock_bystring", (PyCFunction)py_tdb_hnd_unlock_bystring, METH_VARARGS | METH_KEYWORDS },
596 { NULL }
599 /* Deallocate a tdb handle object */
601 static void tdb_hnd_dealloc(PyObject* self)
603 tdb_hnd_object *hnd = (tdb_hnd_object *)self;
605 if (hnd->tdb) {
606 tdb_close(hnd->tdb);
607 hnd->tdb = NULL;
611 /* Return tdb handle attributes */
613 static PyObject *tdb_hnd_getattr(PyObject *self, char *attrname)
615 return Py_FindMethod(tdb_hnd_methods, self, attrname);
618 static char tdb_hnd_type_doc[] =
619 "Python wrapper for tdb.";
621 PyTypeObject tdb_hnd_type = {
622 PyObject_HEAD_INIT(NULL)
624 "tdb",
625 sizeof(tdb_hnd_object),
627 tdb_hnd_dealloc, /* tp_dealloc*/
628 0, /* tp_print*/
629 tdb_hnd_getattr, /* tp_getattr*/
630 0, /* tp_setattr*/
631 0, /* tp_compare*/
632 0, /* tp_repr*/
633 0, /* tp_as_number*/
634 0, /* tp_as_sequence*/
635 &tdb_mapping, /* tp_as_mapping*/
636 0, /* tp_hash */
637 0, /* tp_call */
638 0, /* tp_str */
639 0, /* tp_getattro */
640 0, /* tp_setattro */
641 0, /* tp_as_buffer*/
642 Py_TPFLAGS_DEFAULT, /* tp_flags */
643 tdb_hnd_type_doc, /* tp_doc */
646 /* Constants */
648 static struct const_vals {
649 char *name;
650 uint32 value;
651 } module_const_vals[] = {
653 /* Flags for tdb_open() */
655 { "TDB_DEFAULT", TDB_DEFAULT },
656 { "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST },
657 { "TDB_INTERNAL", TDB_INTERNAL },
658 { "TDB_NOLOCK", TDB_NOLOCK },
659 { "TDB_NOMMAP", TDB_NOMMAP },
660 { "TDB_CONVERT", TDB_CONVERT },
661 { "TDB_BIGENDIAN", TDB_BIGENDIAN },
663 { NULL },
666 static void const_init(PyObject *dict)
668 struct const_vals *tmp;
669 PyObject *obj;
671 for (tmp = module_const_vals; tmp->name; tmp++) {
672 obj = PyInt_FromLong(tmp->value);
673 PyDict_SetItemString(dict, tmp->name, obj);
674 Py_DECREF(obj);
678 /* Module initialisation */
680 void inittdb(void)
682 PyObject *module, *dict;
684 /* Initialise module */
686 module = Py_InitModule("tdb", tdb_methods);
687 dict = PyModule_GetDict(module);
689 py_tdb_error = PyErr_NewException("tdb.error", NULL, NULL);
690 PyDict_SetItemString(dict, "error", py_tdb_error);
692 /* Initialise policy handle object */
694 tdb_hnd_type.ob_type = &PyType_Type;
696 PyDict_SetItemString(dict, "tdb.hnd",
697 (PyObject *)&tdb_hnd_type);
699 /* Initialise constants */
701 const_init(dict);